From 31163effd99d551ce15c088d05893718631656b7 Mon Sep 17 00:00:00 2001 From: Niels Moseley Date: Tue, 24 Oct 2017 19:40:56 +0200 Subject: [PATCH] Updated filter engine FSM to have named states and separated clocked and non-clocked processes. Fixed bug in spmul which caused incorrect sign handling in final product --- verilog/filter/filter.v | 321 +++++++++++++++++++++---------------- verilog/filter/filter_tb.v | 41 ++++- verilog/spmul/spmul.v | 10 +- 3 files changed, 226 insertions(+), 146 deletions(-) diff --git a/verilog/filter/filter.v b/verilog/filter/filter.v index 9406908..1b2ff39 100644 --- a/verilog/filter/filter.v +++ b/verilog/filter/filter.v @@ -50,15 +50,19 @@ module FILTER ( reg signed [15:0] state2 [0:5]; // state 2 memory / shift register reg signed [15:0] accu; // accumulator - reg mul_start; - reg state_sel; - reg accu_sel; - reg do_accu; - reg double_mode; - reg update_states; - reg update_coeffs; - reg [3:0] cur_state; - reg unsigned [2:0] section; + reg mul_start; // if 1, trigger start of multiplier + reg state_sel; // if 1, input to multiplier is state2, else state1 + reg accu_sel; // if 1, input to accumulator is accu, else sig_in + reg do_accu; // if 1, the accumulator is updated + reg double_mode; // if 1, the input to the accumulator is x2 + reg update_states; // shift the state registers + reg clear_states; // zero all states + reg update_coeffs; // shift the coefficient registers + reg [3:0] cur_state; // current FSM state + reg [3:0] next_state; // next FSM state + + reg clear_section, inc_section; + reg unsigned [2:0] section; // current filter section being processed (0..5) wire mul_done; wire signed [15:0] mul_result, accu_in, mul_in; @@ -103,17 +107,8 @@ module FILTER ( // accumulator accu <= 0; - accu_sel <= 0; - state_sel <= 0; - do_accu <= 0; - double_mode <= 0; - - update_states <= 0; - update_coeffs <= 0; - mul_start <= 0; - cur_state <= 4'b0000; - done <= 0; - section <= 0; + cur_state <= 4'b0000; + section <= 0; end else begin @@ -122,6 +117,16 @@ module FILTER ( // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // update the filter states if necessary + if (clear_states == 1) + begin + // clear all states + for(i=0; i<6; i=i+1) + begin + state1[i] <= 0; + state2[i] <= 0; + end + end + else if (update_states == 1) begin state1[0] <= accu; @@ -132,8 +137,10 @@ module FILTER ( state1[i] <= state1[i-1]; state2[i] <= state2[i-1]; end - //$display("BOOM %d %d %d %d %d %d %d", accu, state1[0], state1[1], state1[2],state1[3],state1[4],state1[5]); - end + + //if (DEBUG == 1) + // $display("BOOM accu: %d states: %d %d %d %d %d %d", accu, state1[0], state1[1], state1[2],state1[3],state1[4],state1[5]); + end // update the coefficients if necessary if ((update_coeffs) || (coef_load)) @@ -162,126 +169,160 @@ module FILTER ( accu <= accu_in + mul_result; end - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - // control state machine here .. - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // handle section counter + if (clear_section == 1) + begin + section <= 0; + end + else if (inc_section == 1) + begin + section <= section + 1; + end - // defaults - done <= 0; - do_accu <= 0; - mul_start <= 0; - state_sel <= 0; - accu_sel <= 0; - double_mode <= 0; - update_states <= 0; - update_coeffs <= 0; - case(cur_state) - 4'b0000: // IDLE state - begin - done <= 1; - section <= 0; - if (start == 1) - begin - // state1 * coeff[0] - state_sel <= 0; // state 1 as mul input - mul_start <= 1; // trigger multiplier - cur_state <= 4'b0001; - - if (DEBUG == 1) - begin - for(i=0; i<6; i=i+1) - begin - $display("Section %d: %d %d", i, state1[i], state2[i]); - end - end - - end - end - 4'b0001: // Dummy cycle to wait for mul_done - // to reach a valid state - begin - cur_state <= 4'b0010; - end - 4'b0010: // wait for multiplier to complete - begin - if (mul_done == 1) - begin - cur_state <= 4'b0011; - accu_sel <= 0; // accu = sig_in + mul_result - do_accu <= 1; - double_mode <= 1; // a1 coefficient has double the weight - end - end - 4'b0011: // update accu, 1st section only! - begin - cur_state <= 4'b0100; - update_coeffs <= 1; // advance to coeff[1] - end - 4'b0100: // state2 * coeff[1] - begin - state_sel <= 1; // state 2 as mul input - mul_start <= 1; // trigger multiplier - cur_state <= 4'b0101; - end - 4'b0101: // dummy state to wait for mul_done - // to become valid - begin - cur_state <= 4'b0110; - end - 4'b0110: // wait for multiplier to complete - begin - if (mul_done == 1) - begin - section <= section + 4'b001; // increment section number - cur_state <= 4'b0111; - accu_sel <= 1; // accu = accu + mul_result - do_accu <= 1; - end - end - 4'b0111: // update accumulator and filter states - begin - update_coeffs <= 1; // advance to next section.. - update_states <= 1; - - // check if this is the last section.. - if (section==4'b0110) - begin - cur_state <= 4'b0000; // one complete filter set done.. - end - else - cur_state <= 4'b1000; // next.. - end - 4'b1000: - begin - // next section: state1 * coeff[0] - cur_state <= 4'b1001; - state_sel <= 0; // state 1 as mul input - mul_start <= 1; // trigger multiplier - end - 4'b1001: // Dummy cycle to wait for mul_done - // to reach a valid state - begin - cur_state <= 4'b1010; - end - 4'b1010: // wait for multiplier to complete - begin - if (mul_done == 1) - begin - cur_state <= 4'b1011; - accu_sel <= 1; // accu = accu + mul_result - do_accu <= 1; - double_mode <= 1; // a1 coefficient has double the weight - end - end - 4'b1011: // update accu, 2nd..5th section only! - begin - update_coeffs <= 1; // advance to coeff[1] - cur_state <= 4'b0100; - end - default: - cur_state <= 4'b0000; - endcase + // update FSM state + cur_state <= next_state; end end + // FSM states + parameter S_IDLE = 4'b0000, + S_DUMMY1 = 4'b0001, + S_WAITMUL1 = 4'b0010, + S_UPDATEC1 = 4'b0011, + S_DOSTATE2 = 4'b0100, + S_DUMMY2 = 4'b0101, + S_WAITMUL2 = 4'b0110, + S_UPDATEC2 = 4'b0111, + S_NEXTSEC = 4'b1000, + S_DOSTATE1B= 4'b1001, + S_WAITMUL3 = 4'b1010, + S_UPDATEC3 = 4'b1011; + + always@(*) + begin + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // FSM combinational stuff + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + // defaults + done <= 0; + do_accu <= 0; + mul_start <= 0; + state_sel <= 0; + accu_sel <= 0; + double_mode <= 0; + update_states <= 0; + update_coeffs <= 0; + inc_section <= 0; + clear_section <= 0; + next_state <= cur_state; + + case(cur_state) + S_IDLE: // IDLE state + begin + done <= 1; + clear_section <= 1; + if (start == 1) + begin + // state1 * coeff[0] + state_sel <= 0; // state 1 as mul input + mul_start <= 1; // trigger multiplier + next_state <= S_DUMMY1; + + if (DEBUG == 1) + begin + for(i=0; i<6; i=i+1) + begin + $display("Section %d: %d %d", i, state1[i], state2[i]); + end + end + + end + end + S_DUMMY1: // Dummy cycle to wait for mul_done + // to reach a valid state + begin + next_state <= S_WAITMUL1; + end + S_WAITMUL1: // wait for multiplier to complete + begin + if (mul_done == 1) + begin + accu_sel <= 0; // accu = sig_in + mul_result + do_accu <= 1; // update accu + double_mode <= 1; // a1 coefficient has double the weight + next_state <= S_UPDATEC1; + end + end + S_UPDATEC1: // update accu, 1st section only! + begin + update_coeffs <= 1; // advance to coeff[1] + next_state <= S_DOSTATE2; + end + S_DOSTATE2: // state2 * coeff[1] + begin + state_sel <= 1; // state 2 as mul input + mul_start <= 1; // trigger multiplier + next_state <= S_DUMMY2; + end + S_DUMMY2: // dummy state to wait for mul_done + // to become valid + begin + next_state <= S_WAITMUL2; + end + S_WAITMUL2: // wait for multiplier to complete + begin + if (mul_done == 1) + begin + inc_section <= 1; + next_state <= S_UPDATEC2; + accu_sel <= 1; // accu = accu + mul_result + do_accu <= 1; + end + end + S_UPDATEC2: // update accumulator and filter states + begin + update_coeffs <= 1; // advance to next section.. + update_states <= 1; + + // check if this is the last section.. + if (section==4'b0110) + begin + next_state <= S_IDLE; // one complete filter set done.. + end + else + next_state <= S_NEXTSEC; // next.. + end + S_NEXTSEC: + begin + // next section: state1 * coeff[0] + state_sel <= 0; // state 1 as mul input + mul_start <= 1; // trigger multiplier + next_state <= S_DOSTATE1B; + end + S_DOSTATE1B: // Dummy cycle to wait for mul_done + // to reach a valid state + begin + next_state <= S_WAITMUL3; + end + S_WAITMUL3: // wait for multiplier to complete + begin + if (mul_done == 1) + begin + accu_sel <= 1; // accu = accu + mul_result + do_accu <= 1; + double_mode <= 1; // a1 coefficient has double the weight + next_state <= S_UPDATEC3; + end + end + S_UPDATEC3: // update accu, 2nd..5th section only! + begin + update_coeffs <= 1; // advance to coeff[1] + next_state <= S_DOSTATE2; + end + default: + next_state <= S_IDLE; + endcase + end + endmodule diff --git a/verilog/filter/filter_tb.v b/verilog/filter/filter_tb.v index abfdf44..efed501 100644 --- a/verilog/filter/filter_tb.v +++ b/verilog/filter/filter_tb.v @@ -10,9 +10,11 @@ module FILTER_TB; reg signed [15:0] sig_in; reg signed [9:0] coef_in; reg [3:0] reg_sel; + wire signed [15:0] sig_out; wire done; + parameter load_simple = 1; defparam u_filter.DEBUG = 1; FILTER u_filter ( @@ -45,6 +47,42 @@ module FILTER_TB; rst_an = 1; // load all the coefficients + if (load_simple == 1) + begin + #10 + coef_load = 1; + // section 1 + coef_in = 10'h3C9; + #10 + coef_in = 10'h1E4; + #10 + // section 2 + coef_in = 10'h2B8; + #10 + coef_in = 10'h1CF; + #10 + // section 3 + coef_in = 10'h238; + #10 + coef_in = 10'h080; + #10 + // section 4 + coef_in = 10'h195; + #10 + coef_in = 10'h1BF; + #10 + // section 5 + coef_in = 10'h135; + #10 + coef_in = 10'h1BF; + #10 + // section 6 + coef_in = 10'h000; + #10 + coef_in = 10'h000; + end + else + begin #10 coef_load = 1; // section 1 @@ -76,7 +114,8 @@ module FILTER_TB; coef_in = 10'h000; #10 coef_in = 10'h000; - #10 + end + #10 coef_load = 0; start = 1; #10000; diff --git a/verilog/spmul/spmul.v b/verilog/spmul/spmul.v index e3e6004..12872a1 100644 --- a/verilog/spmul/spmul.v +++ b/verilog/spmul/spmul.v @@ -33,10 +33,10 @@ module SPMUL ( output reg done; //////////// internal signals ////////// - reg signed [24:0] accumulator; + reg signed [24:0] accumulator; reg signed [9:0] coefreg; reg signed [15:0] sigreg; - reg [3:0] state; // state machine state + reg [3:0] state; // state machine state wire signed [15:0] bmul; reg domul,accu_clr; @@ -53,7 +53,7 @@ module SPMUL ( // note: leave coefreg[9] untouched // as this is the sign bit... if (coefreg[8] == 1'b1) - accumulator <= {accumulator[23:0], 1'b0} + sigreg; + accumulator <= $signed({accumulator[23:0], 1'b0}) + sigreg; else accumulator <= {accumulator[23:0], 1'b0}; @@ -143,9 +143,9 @@ module SPMUL ( done <= 1; // correct for the coeff sign bit if (coefreg[9] == 0) - result_out <= {1'b0, accumulator[23:9]}; + result_out <= accumulator[24:9]; else - result_out <= {1'b1, ~accumulator[23:9]} + 1; + result_out <= $signed(~accumulator[24:9]) + 1; state <= 0; end default: