Forum Discussion
Thanks, but I believe I have tried that too. I still get violations related to the calculations
Is there something fundamental I have misunderstood about FSMs? or maybe Quartus TA?
My FSM now looks like this:
-----------------------------------------------------------------------------
-- Filter statemachine
--
-- Avoid start filtering in the "middle" of tvalid, if reset is released at a
-- bad time => need both negative edge and a positive edge on the next tvalid
-- in order to start filtering.
-----------------------------------------------------------------------------
p_filter_fsm : process (clk) is
begin
if rising_edge(clk) then
if (rst = '1') then
current_state <= IDLE;
else
current_state <= next_state;
end if;
end if;
end process p_filter_fsm;
-----------------------------------------------------------------------------
-- Counters for handling accRAM-accesses during filtering
-----------------------------------------------------------------------------
p_filter_fsm_counters : process (clk) is
begin
if rising_edge(clk) then
if (rst = '1') then
accRAM_addr_in <= i_config_q_factor_reg(accRAM_addr_in'range) - 1;
accRAM_addr_out <= i_config_q_factor_reg(accRAM_addr_out'range) - 1;
prev_accRAM_addr_in <= i_config_q_factor_reg(accRAM_addr_in'range) - 1;
prev_accRAM_addr_out <= i_config_q_factor_reg(accRAM_addr_out'range) - 1;
coef_addr_cnt <= i_config_filterlength_reg(coef_addr_cnt'range) - 1;
filtered_accRAM_addr_out <= (others => '0');
decimation_cnt <= (others => '0');
run_filter_cnt <= (others => '0');
sample_in <= (others => '0');
else
-- Defaults
run_filter_cnt <= (others => '0');
case current_state is
when IDLE =>
prev_accRAM_addr_in <= i_config_q_factor_reg(accRAM_addr_in'range) - 1;
prev_accRAM_addr_out <= i_config_q_factor_reg(accRAM_addr_out'range) - 1;
accRAM_addr_in <= i_config_q_factor_reg(accRAM_addr_in'range) - 1;
accRAM_addr_out <= i_config_q_factor_reg(accRAM_addr_out'range) - 1;
coef_addr_cnt <= i_config_filterlength_reg(coef_addr_cnt'range) - 1;
decimation_cnt <= (others => '0');
-------------------------------------------------------------------
when NEXT_SAMPLE =>
accRAM_addr_in <= prev_accRAM_addr_in;
accRAM_addr_out <= prev_accRAM_addr_out;
if (sample_tvalid_posedge = '1' or sample_tvalid_negedge = '1') then
sample_in <= sample_s1.tdata(GC_CH_DATA_WIDTH-1 downto 0);
coef_addr_cnt <= coef_addr_cnt - to_integer(i_config_d_factor_reg);
decimation_cnt <= decimation_cnt + 1;
end if;
-------------------------------------------------------------------
when FILTERING =>
-- Counter for controlling length of Filtering-state
run_filter_cnt <= run_filter_cnt + 1;
-- Update address-counter for coef-RAM, until last overlap is reached
if (run_filter_cnt < i_config_q_factor_reg-1) then
if (coef_addr_cnt < i_config_d_factor_reg) then
coef_addr_cnt <= i_config_filterlength_reg(coef_addr_cnt'range) - 1;
else
coef_addr_cnt <= coef_addr_cnt - to_integer(i_config_d_factor_reg);
end if;
end if;
-- Control length of FILTERING-state
if (run_filter_cnt = i_config_q_factor_reg+8) then
if (decimation_cnt < i_config_d_factor_reg) then
coef_addr_cnt <= i_config_filterlength_reg(coef_addr_cnt'range) -1 -decimation_cnt; -- coef in first overlap
end if;
end if;
-- Read previous sum from accRAM
if (run_filter_cnt > i_config_q_factor_reg-1) then
accRAM_addr_out <= filtered_accRAM_addr_out;
elsif (run_filter_cnt > 0) then
-- Rotating accRAM-address counter for reading from accRAM
if (accRAM_addr_out = 0) then
accRAM_addr_out <= i_config_q_factor_reg(accRAM_addr_out'range) - 1;
else
accRAM_addr_out <= accRAM_addr_out - 1;
end if;
end if;
if (run_filter_cnt > C_START_WRITING_NEW_SUM+1 and
run_filter_cnt < C_START_WRITING_NEW_SUM+i_config_q_factor_reg+1) then
if (accRAM_addr_in = 0 and we_accRAM = '1') then
accRAM_addr_in <= i_config_q_factor_reg(accRAM_addr_in'range) - 1;
else
accRAM_addr_in <= accRAM_addr_in - 1;
end if;
end if;
-------------------------------------------------------------------
when FILTER_OUTPUT =>
-- Flush cell which is read, in accRAM
accRAM_addr_in <= filtered_accRAM_addr_out;
if (i_config_q_factor_reg = 1) then
filtered_accRAM_addr_out <= (others => '0');
elsif (filtered_accRAM_addr_out > i_config_q_factor_reg-2) then
filtered_accRAM_addr_out <= (others => '0');
else
filtered_accRAM_addr_out <= filtered_accRAM_addr_out + 1;
end if;
-- Update coefficient for next sample
coef_addr_cnt <= i_config_filterlength_reg(coef_addr_cnt'range) - 1;
-- Reset decimation counter
decimation_cnt <= (others => '0');
-- Store accRAM-address value for next round of filtering before
-- changing state
prev_accRAM_addr_in <= accRAM_addr_in;
prev_accRAM_addr_out <= accRAM_addr_out;
when others => null;
end case;
end if;
end if;
end process p_filter_fsm_counters;
-----------------------------------------------------------------------------
-- Asynchronous FSM outputs
-----------------------------------------------------------------------------
p_filter_fsm_outputs : process (all) is
begin
-- Defaults
next_state <= current_state;
case current_state is
when IDLE =>
next_state <= NEXT_SAMPLE;
-------------------------------------------------------------------
when NEXT_SAMPLE =>
if (sample_tvalid_posedge = '1' or sample_tvalid_negedge = '1') then
next_state <= FILTERING;
else
next_state <= NEXT_SAMPLE;
end if;
-------------------------------------------------------------------
when FILTERING =>
-- Control length of FILTERING-state
if (run_filter_cnt = i_config_q_factor_reg+8) then
if (decimation_cnt < i_config_d_factor_reg) then
next_state <= NEXT_SAMPLE;
elsif (decimation_cnt = i_config_d_factor_reg) then
next_state <= FILTER_OUTPUT;
end if;
else
next_state <= FILTERING;
end if;
-------------------------------------------------------------------
when FILTER_OUTPUT =>
next_state <= NEXT_SAMPLE;
when others => next_state <= NEXT_SAMPLE;
end case;
end process p_filter_fsm_outputs;
-----------------------------------------------------------------------------
-- FSM pipeline stage
-----------------------------------------------------------------------------
p_fsm_pipelining : process (clk) is
begin
if rising_edge(clk) then
if (rst = '1') then
accRAM_Re_out_add <= (others => '0');
accRAM_Im_out_add <= (others => '0');
we_accRAM <= '0';
o_filtered_sample.tdata(4*GC_CH_DATA_WIDTH-1 downto 0) <= (others => '0');
o_filtered_sample.tvalid <= '0';
o_filtered_sample.tlast <= '0';
else
-- Defaults
accRAM_Re_out_add <= accRAM_Re_out;
accRAM_Im_out_add <= accRAM_Im_out;
we_accRAM <= '0';
o_filtered_sample.tdata(4*GC_CH_DATA_WIDTH-1 downto 0) <= (others => '0');
o_filtered_sample.tvalid <= '0';
o_filtered_sample.tlast <= '0';
case current_state is
when IDLE =>
accRAM_Re_out_add <= (others => '0');
accRAM_Im_out_add <= (others => '0');
o_filtered_sample.tvalid <= '0';
o_filtered_sample.tlast <= '0';
-------------------------------------------------------------------
when FILTERING =>
-- Add new sum and store in accRAM
if (run_filter_cnt > C_START_WRITING_NEW_SUM+i_config_q_factor_reg) then
we_accRAM <= '0';
elsif (run_filter_cnt > C_START_WRITING_NEW_SUM) then
we_accRAM <= '1';
end if;
-------------------------------------------------------------------
when FILTER_OUTPUT =>
we_accRAM <= '1';
o_filtered_sample.tdata <= accRAM_Re_Out & accRAM_Im_out;
o_filtered_sample.tvalid <= '1';
o_filtered_sample.tlast <= '0';
when others => null;
end case;
end if;
end if;
end process p_fsm_pipelining;
-----------------------------------------------------------------------------
-- Filter-calculations, synchronous
-----------------------------------------------------------------------------
p_filter_calculations : process (clk) is
begin
if rising_edge(clk) then
-- Multiplication of input sample with coefficients
mult_Re <= std_logic_vector(resize(signed(sample_in) * signed(i_coef_data(2*GC_COEF_DATA_WIDTH-1 downto GC_COEF_DATA_WIDTH)), mult_Re'length));
mult_Im <= std_logic_vector(resize(signed(sample_in) * signed(i_coef_data(GC_COEF_DATA_WIDTH-1 downto 0)), mult_Im'length));
-- Resizing of vectors
mult_Re_ext <= std_logic_vector(resize(signed(mult_Re), mult_Re_ext'length));
mult_Im_ext <= std_logic_vector(resize(signed(mult_Im), mult_Im_ext'length));
-- Truncate number of bits defined in 'config_lsb_prod_reg'
case i_config_lsb_prod_reg(2 downto 0) is
when b"001" =>
add_Re_in <= mult_Re_ext(GC_ADDER_WIDTH downto 1); -- (36:1)
add_Im_in <= mult_Im_ext(GC_ADDER_WIDTH downto 1);
when b"010" =>
add_Re_in <= mult_Re_ext(GC_ADDER_WIDTH+1 downto 2); -- (37:2)
add_Im_in <= mult_Im_ext(GC_ADDER_WIDTH+1 downto 2);
when b"011" =>
add_Re_in <= mult_Re_ext(GC_ADDER_WIDTH+2 downto 3); -- (38:3)
add_Im_in <= mult_Im_ext(GC_ADDER_WIDTH+2 downto 3);
when b"100" =>
add_Re_in <= mult_Re_ext(GC_ADDER_WIDTH+3 downto 4); -- (39:4)
add_Im_in <= mult_Im_ext(GC_ADDER_WIDTH+3 downto 4);
when others =>
add_Re_in <= mult_Re_ext(GC_ADDER_WIDTH-1 downto 0); -- same as (b"000")
add_Im_in <= mult_Im_ext(GC_ADDER_WIDTH-1 downto 0);
end case;
-- Add new sum and store in accRAM
if (run_filter_cnt > C_START_WRITING_NEW_SUM and
run_filter_cnt < C_START_WRITING_NEW_SUM+i_config_q_factor_reg+1) then
accRAM_Re_in <= std_logic_vector(signed(add_Re_in) + signed(accRAM_Re_out_add));
accRAM_Im_in <= std_logic_vector(signed(add_Im_in) + signed(accRAM_Im_out_add));
elsif (next_state = FILTER_OUTPUT) then
accRAM_Re_in <= (others => '0');
accRAM_Im_in <= (others => '0');
end if;
end if;
end process p_filter_calculations;
- ShengN_altera1 month ago
Super Contributor
Could you try retime stage report and fast forward timing closure report for the path that need register check below:
- cjak12 days ago
Occasional Contributor
I use Quartus Prime Lite Edition. I suspect I do not have access to the reports mentioned?
- ShengN_altera29 days ago
Super Contributor
Does your problem resolved? Do you need further help? If yes, possible provide your project file?
- cjak21 days ago
Occasional Contributor
No, I have not achieved timing closure, and the redesigned filter seem to achieve a lower fmax than the original implementation. Unfortunately I cannot share the design.
- ShengN_altera21 days ago
Super Contributor
I believe the violation at the filter right. Could you provide the filter full file? What frequency does the filter run at?