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] 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,16 +107,7 @@ 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;
end
else
@ -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,7 +137,9 @@ 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]);
//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
@ -162,8 +169,39 @@ module FILTER (
accu <= accu_in + mul_result;
end
// handle section counter
if (clear_section == 1)
begin
section <= 0;
end
else if (inc_section == 1)
begin
section <= section + 1;
end
// 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
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// control state machine here ..
// FSM combinational stuff
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// defaults
@ -175,17 +213,21 @@ module FILTER (
double_mode <= 0;
update_states <= 0;
update_coeffs <= 0;
inc_section <= 0;
clear_section <= 0;
next_state <= cur_state;
case(cur_state)
4'b0000: // IDLE state
S_IDLE: // IDLE state
begin
done <= 1;
section <= 0;
clear_section <= 1;
if (start == 1)
begin
// state1 * coeff[0]
state_sel <= 0; // state 1 as mul input
mul_start <= 1; // trigger multiplier
cur_state <= 4'b0001;
next_state <= S_DUMMY1;
if (DEBUG == 1)
begin
@ -197,48 +239,48 @@ module FILTER (
end
end
4'b0001: // Dummy cycle to wait for mul_done
S_DUMMY1: // Dummy cycle to wait for mul_done
// to reach a valid state
begin
cur_state <= 4'b0010;
next_state <= S_WAITMUL1;
end
4'b0010: // wait for multiplier to complete
S_WAITMUL1: // 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;
do_accu <= 1; // update accu
double_mode <= 1; // a1 coefficient has double the weight
next_state <= S_UPDATEC1;
end
end
4'b0011: // update accu, 1st section only!
S_UPDATEC1: // update accu, 1st section only!
begin
cur_state <= 4'b0100;
update_coeffs <= 1; // advance to coeff[1]
next_state <= S_DOSTATE2;
end
4'b0100: // state2 * coeff[1]
S_DOSTATE2: // state2 * coeff[1]
begin
state_sel <= 1; // state 2 as mul input
mul_start <= 1; // trigger multiplier
cur_state <= 4'b0101;
next_state <= S_DUMMY2;
end
4'b0101: // dummy state to wait for mul_done
S_DUMMY2: // dummy state to wait for mul_done
// to become valid
begin
cur_state <= 4'b0110;
next_state <= S_WAITMUL2;
end
4'b0110: // wait for multiplier to complete
S_WAITMUL2: // wait for multiplier to complete
begin
if (mul_done == 1)
begin
section <= section + 4'b001; // increment section number
cur_state <= 4'b0111;
inc_section <= 1;
next_state <= S_UPDATEC2;
accu_sel <= 1; // accu = accu + mul_result
do_accu <= 1;
end
end
4'b0111: // update accumulator and filter states
S_UPDATEC2: // update accumulator and filter states
begin
update_coeffs <= 1; // advance to next section..
update_states <= 1;
@ -246,42 +288,41 @@ module FILTER (
// check if this is the last section..
if (section==4'b0110)
begin
cur_state <= 4'b0000; // one complete filter set done..
next_state <= S_IDLE; // one complete filter set done..
end
else
cur_state <= 4'b1000; // next..
next_state <= S_NEXTSEC; // next..
end
4'b1000:
S_NEXTSEC:
begin
// next section: state1 * coeff[0]
cur_state <= 4'b1001;
state_sel <= 0; // state 1 as mul input
mul_start <= 1; // trigger multiplier
next_state <= S_DOSTATE1B;
end
4'b1001: // Dummy cycle to wait for mul_done
S_DOSTATE1B: // Dummy cycle to wait for mul_done
// to reach a valid state
begin
cur_state <= 4'b1010;
next_state <= S_WAITMUL3;
end
4'b1010: // wait for multiplier to complete
S_WAITMUL3: // 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
next_state <= S_UPDATEC3;
end
end
4'b1011: // update accu, 2nd..5th section only!
S_UPDATEC3: // update accu, 2nd..5th section only!
begin
update_coeffs <= 1; // advance to coeff[1]
cur_state <= 4'b0100;
next_state <= S_DOSTATE2;
end
default:
cur_state <= 4'b0000;
next_state <= S_IDLE;
endcase
end
end
endmodule

View File

@ -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,8 @@ module FILTER_TB;
rst_an = 1;
// load all the coefficients
if (load_simple == 1)
begin
#10
coef_load = 1;
// section 1
@ -76,6 +80,41 @@ module FILTER_TB;
coef_in = 10'h000;
#10
coef_in = 10'h000;
end
else
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
#10
coef_load = 0;
start = 1;

View File

@ -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: