I was trying to create a module for using the sensors that I recently bought. My module works well in simulation , synthesis and implementation. but when I used my module inside the top leveled module, I saw that while synthesizing it, it creates some registers outside it's module. With trial and error I found out that the problem is from a sequence of arithmetic operations.
module Sensor_handle_dev1(
input logic i_clk , i_reset , i_echo,
output logic o_trg,
output logic[7:0] o_distance , sensorNum
);
assign sensorNum = 8'b1;
logic[1:0] IdleState , CatchEchoState , CountState , PackUpState;
assign IdleState = 2'b00;
assign CatchEchoState = 2'b01;
assign CountState = 2'b10;
assign PackUpState = 2'b11;
logic next_trg;
logic[1:0] curState , next_state;
logic[31:0] l_count , next_count;
logic[7:0] next_distance;
always @( posedge i_clk )
begin
if ( i_reset == 1'b1 )
begin
curState <= IdleState;
o_trg <= 0;
o_distance <= 0;
l_count <= 0;
end
else
begin
curState <= next_state;
l_count <= next_count;
o_distance <= next_distance;
o_trg <= next_trg;
end
end
always_comb
begin
next_trg = o_trg; // <-- default value is flopped value
next_distance = o_distance; // <-- default value is flopped value
next_count = l_count;
case(curState)
IdleState:
begin
next_count = 0;
next_trg = 1;
next_count = 0;
next_distance = 0;
//# trig wait
next_state = CatchEchoState;
end
CatchEchoState:
begin
next_trg = 0;
if ( i_echo == 1 )
begin
if( l_count < 32'b101101110001101100000000 )
begin
next_count = l_count + 1;
next_state = CatchEchoState;
end
else
begin
next_state = IdleState;
end
end
else
begin
next_state = CountState;
end
end
CountState:
begin
// here is the problem
//next_distance = ((l_count * 68) / 100000) + 1;
next_state = IdleState;
end
default:
next_state = IdleState;
endcase
end
endmodule
and the schematic looks like thisenter image description here
how can I implement to evade this situation ?
1 Answer 1
My guess is it requires more than one clock to calculate ((l_count * 68) / 100000) + 1
. There should be a warning about this in the synthesis/timing report.
First thing that can be done is reduce the 68/100000 to 17/25000. The synthesizer should have done the same optimization.
Then split the calculation across multiple clocks. Notice in the CatchEchoState
state when next_state = CountState;
, next_count
is not being updated. Some of the distance calculation can be move to this condition.
In the example below I moved the multiplication to the CatchEchoState
and kept the division in the CountState
. Check the timing report. If the timing can be meet for partial calc and not the final calc, then include a division of factor of 25000 (ex 40 is a factor of 25000, which then becomes next_count = (l_count * 17) / 40;
... next_distance = (l_count / 625) + 1;
). If timing still cannot be meet, consider to increment next_count
by 17 instead of 1, thereby eliminating the dedicated multiplication logic.
...
CatchEchoState:
begin
next_trg = 0;
if ( i_echo == 1 )
...
else
begin
next_count = l_count * 17; // <-- partial calc
next_state = CountState;
end
end
CountState:
begin
next_distance = (l_count / 25000) + 1; // <-- final calc
next_state = IdleState;
end
...
If there is still an issue, then it likely has to do with your top level module or your synthesis configurations.
FYI: o_distance
and next_distance
need to be at least 24-bits wide to store the maximum unsigned value (assuming max l_count
value is 11,999,999). Looks like this is what is going on in the screenshot, but it is 8-bits in the provided RTL.
-
\$\begingroup\$ @Batuhan , I'm curious what the final computational split needed to be. Can you add a comment? \$\endgroup\$Greg– Greg2019年07月31日 16:12:47 +00:00Commented Jul 31, 2019 at 16:12