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

This commit is contained in:
Niels Moseley 2017-10-24 19:40:56 +02:00
parent 22b3443358
commit 31163effd9
3 changed files with 226 additions and 146 deletions

View File

@ -50,15 +50,19 @@ module FILTER (
reg signed [15:0] state2 [0:5]; // state 2 memory / shift register reg signed [15:0] state2 [0:5]; // state 2 memory / shift register
reg signed [15:0] accu; // accumulator reg signed [15:0] accu; // accumulator
reg mul_start; reg mul_start; // if 1, trigger start of multiplier
reg state_sel; reg state_sel; // if 1, input to multiplier is state2, else state1
reg accu_sel; reg accu_sel; // if 1, input to accumulator is accu, else sig_in
reg do_accu; reg do_accu; // if 1, the accumulator is updated
reg double_mode; reg double_mode; // if 1, the input to the accumulator is x2
reg update_states; reg update_states; // shift the state registers
reg update_coeffs; reg clear_states; // zero all states
reg [3:0] cur_state; reg update_coeffs; // shift the coefficient registers
reg unsigned [2:0] section; 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 mul_done;
wire signed [15:0] mul_result, accu_in, mul_in; wire signed [15:0] mul_result, accu_in, mul_in;
@ -103,17 +107,8 @@ module FILTER (
// accumulator // accumulator
accu <= 0; accu <= 0;
accu_sel <= 0; cur_state <= 4'b0000;
state_sel <= 0; section <= 0;
do_accu <= 0;
double_mode <= 0;
update_states <= 0;
update_coeffs <= 0;
mul_start <= 0;
cur_state <= 4'b0000;
done <= 0;
section <= 0;
end end
else else
begin begin
@ -122,6 +117,16 @@ module FILTER (
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// update the filter states if necessary // 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) if (update_states == 1)
begin begin
state1[0] <= accu; state1[0] <= accu;
@ -132,8 +137,10 @@ module FILTER (
state1[i] <= state1[i-1]; state1[i] <= state1[i-1];
state2[i] <= state2[i-1]; state2[i] <= state2[i-1];
end 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 // update the coefficients if necessary
if ((update_coeffs) || (coef_load)) if ((update_coeffs) || (coef_load))
@ -162,126 +169,160 @@ module FILTER (
accu <= accu_in + mul_result; accu <= accu_in + mul_result;
end end
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // handle section counter
// control state machine here .. if (clear_section == 1)
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! begin
section <= 0;
end
else if (inc_section == 1)
begin
section <= section + 1;
end
// defaults // update FSM state
done <= 0; cur_state <= next_state;
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
end end
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 endmodule

View File

@ -10,9 +10,11 @@ module FILTER_TB;
reg signed [15:0] sig_in; reg signed [15:0] sig_in;
reg signed [9:0] coef_in; reg signed [9:0] coef_in;
reg [3:0] reg_sel; reg [3:0] reg_sel;
wire signed [15:0] sig_out; wire signed [15:0] sig_out;
wire done; wire done;
parameter load_simple = 1;
defparam u_filter.DEBUG = 1; defparam u_filter.DEBUG = 1;
FILTER u_filter ( FILTER u_filter (
@ -45,6 +47,42 @@ module FILTER_TB;
rst_an = 1; rst_an = 1;
// load all the coefficients // 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 #10
coef_load = 1; coef_load = 1;
// section 1 // section 1
@ -76,7 +114,8 @@ module FILTER_TB;
coef_in = 10'h000; coef_in = 10'h000;
#10 #10
coef_in = 10'h000; coef_in = 10'h000;
#10 end
#10
coef_load = 0; coef_load = 0;
start = 1; start = 1;
#10000; #10000;

View File

@ -33,10 +33,10 @@ module SPMUL (
output reg done; output reg done;
//////////// internal signals ////////// //////////// internal signals //////////
reg signed [24:0] accumulator; reg signed [24:0] accumulator;
reg signed [9:0] coefreg; reg signed [9:0] coefreg;
reg signed [15:0] sigreg; reg signed [15:0] sigreg;
reg [3:0] state; // state machine state reg [3:0] state; // state machine state
wire signed [15:0] bmul; wire signed [15:0] bmul;
reg domul,accu_clr; reg domul,accu_clr;
@ -53,7 +53,7 @@ module SPMUL (
// note: leave coefreg[9] untouched // note: leave coefreg[9] untouched
// as this is the sign bit... // as this is the sign bit...
if (coefreg[8] == 1'b1) if (coefreg[8] == 1'b1)
accumulator <= {accumulator[23:0], 1'b0} + sigreg; accumulator <= $signed({accumulator[23:0], 1'b0}) + sigreg;
else else
accumulator <= {accumulator[23:0], 1'b0}; accumulator <= {accumulator[23:0], 1'b0};
@ -143,9 +143,9 @@ module SPMUL (
done <= 1; done <= 1;
// correct for the coeff sign bit // correct for the coeff sign bit
if (coefreg[9] == 0) if (coefreg[9] == 0)
result_out <= {1'b0, accumulator[23:9]}; result_out <= accumulator[24:9];
else else
result_out <= {1'b1, ~accumulator[23:9]} + 1; result_out <= $signed(~accumulator[24:9]) + 1;
state <= 0; state <= 0;
end end
default: default: