mirror of
https://github.com/trcwm/Speech256.git
synced 2025-06-07 16:48:32 +02:00
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:
parent
22b3443358
commit
31163effd9
@ -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,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,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
|
||||
|
@ -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;
|
||||
|
@ -36,7 +36,7 @@ module SPMUL (
|
||||
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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user