METech 版 (精华区)
发信人: alphame (spring是春天), 信区: METech
标 题: 可综合Verilog代码风格 zz
发信站: 哈工大紫丁香 (2003年12月29日18:10:29 星期一), 站内信件
Writing synthesizable Verilog from behavioral Verilog code
David Chinnery
What follows is a quick description of how to convert behavioral Verilog cod
e to synthesizable Verilog. It is incomplete, and I haven't tried these spec
ific examples. Please send me an email if you spot any errors, or have any c
omments and suggestions. Given the complexity of some of the changes require
d, converting behavioral Verilog code sometimes needs to be done by hand. I
would be interested in discussion of automating this.
Jump to:
wait statements
while statements
fork statements
tasks
delay statements
Notes ...
----------------------------------------------------------------------------
----
To modify a behavioural Verilog wait statement to make it synthesizable. Ori
ginal code:
command1;
wait (x != 0);
command3;
Synthesizable Verilog:
case (state)
0 : begin
command1;
if (x != 0) command3;
else state <= 1;
end
1 : if (x != 0) // wait until this is true
command3;
endcase
And you need to add the variable state, reg state. If a cycle delay between
command1 and command3 does not matter, then the following is simpler, but no
t identical to the original:
case (state)
0 : begin
command1;
state <= 1;
end
1 : if (x != 0) // wait until this is true
command3;
endcase
I have taken the latter approach in many cases for coding simplicity.
----------------------------------------------------------------------------
----
To modify a behavioural Verilog while statement to make it synthesizable. Or
iginal code:
command1;
while (x != 0)
begin
command2;
end
command3;
Synthesizable Verilog:
case (state)
0 : begin
command1;
if (x != 0)
begin
command2;
state <= 1;
end
else command3;
end
1 : if (x != 0)
begin
command2;
end
else command3;
endcase
Again, if a cycle delay between command1 and the other commands executing is
acceptable, simpler code is the following:
case (state)
0 : begin
command1;
state <= 1;
end
1 : if (x != 0)
begin
command2;
end
else command3;
endcase
----------------------------------------------------------------------------
----
To modify a behavioural Verilog fork and join statement to make it synthesiz
able. Original code:
command1;
fork
// start of fork block 1
begin
wait (y != 0);
a = y;
end
// start of fork block 2
begin
wait (z != 0);
b = z;
end
join
command2;
command2 will execute only after fork blocks 1 and 2 have finished. Here is
the synthesizable Verilog:
case (state)
0 : begin
command1;
done_fork_block_1 = 0;
done_fork_block_2 = 0;
if (y != 0)
begin
a = y;
done_fork_block_1 = 1;
end
if (z != 0)
begin
b = z;
done_fork_block_2 = 1;
end
if (done_fork_block_1 & done_fork_block_2) command2;
else state <= 1;
end
1 : begin
if ((y != 0) && !done_fork_block_1)
begin
a = y;
done_fork_block_1 = 1;
end
if ((z != 0) && !done_fork_block_2)
begin
b = z;
done_fork_block_2 = 1;
end
if (done_fork_block_1 & done_fork_block_2) command2;
// else state <= 1;
end
endcase
In some special cases, it may not be necessary to have done signals, but in
general the blocks of commands being executed in parallel by fork may finish
at different times. Again, if a cycle delay between command1 and the other
commands executing is acceptable, then this code is simpler:
case (state)
0 : begin
command1;
done_fork_block_1 = 0;
done_fork_block_2 = 0;
state <= 1;
end
1 : begin
if ((y != 0) && !done_fork_block_1)
begin
a = y;
done_fork_block_1 = 1;
end
if ((z != 0) && !done_fork_block_2)
begin
b = z;
done_fork_block_2 = 1;
end
if (done_fork_block_1 & done_fork_block_2) command2;
// else state <= 1;
end
endcase
As y or z may have different values after a clock cycle passes, care needs t
o be taken in choosing the simpler alternative, that doesn't exactly impleme
nt the behavioural code.
----------------------------------------------------------------------------
----
When implementing Verilog tasks in modules, the best approach is to group ta
sks that have the same output signals into separate modules. If different mo
dules control the same signal, then explicit arbitration logic is required t
o specify which module is controlling the signal at a given time. To put tas
ks in a separate module, you will require start and completion handshaking s
ignals.
For example, here is some behavioural Verilog:
task update_a_and_b;
begin
a = y;
wait (z != 0) b = z;
end
endtask
...
y = x + w;
update_a_and_b; // calls the task
x = a + b;
@(posedge clock);
x = b;
if (y == x) update_a_and_b;
@(posedge clock);
command1;
Care must be taken when translating this into synthesizable Verilog, to pres
erve correct timing:
module update_a_and_b(do_update_a_and_b, clock, reset, a, z, done_update_a_a
nd_b, b_temp, x_temp);
input do_update_a_and_b; // this signal should go high for only one clock
cycle
input clock;
input reset; // reset this module when reset goes high
input [7:0] a;
input [7:0] z;
output done_update_a_and_b;
output [7:0] b_temp;
output [7:0] x_temp;
reg done_update_a_and_b;
reg [7:0] b_temp;
reg [7:0] x_temp;
reg state;
always @(posedge refclk or posedge reset)
if (reset)
begin
state <= 0;
done_update_a_and_b = 0;
b_temp = 0;
x_temp = 0;
end
else if (do_update_a_and_b && (state == 0))
begin
done_update_a_and_b = 0;
if (z != 0)
begin
b_temp = z;
x_temp = a+b_temp; // x value is update inside this module, as it must
occur immediately when z != 0
done_update_a_and_b = 1;
// stay in state 0, we've finished
end
else state <= 1;
end
else
begin
case (state)
0 : done_update_a_and_b = 0; // do nothing, this is the idle state
1 : if (z != 0)
begin
b_temp = z;
x_temp = a+b_temp; // x value is update inside this module, as i
t must occur immediately when z != 0
done_update_a_and_b = 1;
state <= 0;
// stay in state 0, we've finished
end
endcase
end
endmodule
...
reg [2:0] top_state;
...
case (top_state)
0 : begin
y = x + w;
a = y; // this must happen immediately
if (z != 0) // we have to update x and b immediately if z != 0
begin
b = z;
x = a + b;
top_state <= 2;
end
else
begin
do_update_a_and_b = 1; // call the task
top_state <= 1;
end
end
1 : begin
do_update_a_and_b = 0; // stays high for only one cycle
if (done_update_a_and_b)
begin
// we assume the values of x and b weren't needed on the previous
cycle, otherwise additional circuitry is needed
// or x_temp and b_temp values need to be used on that cycle - it'
s very difficult to coordinate this correctly
// in the general case
x = x_temp;
b = b_temp;
top_state <= 2;
end
end
2 : begin
x = b;
if (y == x)
begin
a = y; // this must happen immediately
if (z != 0) // we have to update x and b immediately if z != 0
begin
b = z;
x = a + b;
top_state <= 4;
end
else
begin
do_update_a_and_b = 1; // call the task
top_state <= 3;
end
end
else top_state <= 4;
end
3 : begin
do_update_a_and_b = 0; // stays high for only one cycle
if (done_update_a_and_b)
begin
// we assume the values of x and b weren't needed on the previous
cycle, otherwise additional circuitry is needed
// or x_temp and b_temp values need to be used on that cycle - it'
s very difficult to coordinate this correctly
// in the general case
x = x_temp;
b = b_temp;
top_state <= 4;
end
end
4: command1;
endcase
Now if we didn't care about having a couple of additional cycle delays betwe
en updates (i.e. assuming nothing depends on the variable values immediately
, and nothing else is changing variable values), we could implement this in
a far simpler fashion:
module update_a_and_b(do_update_a_and_b, clock, reset, a, z, done_update_and
_b, b_temp, x_temp);
input do_update_a_and_b; // this signal should go high for only one clock
cycle
input clock;
input reset; // reset this module when reset goes high
input [7:0] a;
input [7:0] z;
output done_update_and_b;
output [7:0] b_temp;
output [7:0] x_temp;
reg done_update_and_b;
reg [7:0] b_temp;
reg [7:0] x_temp;
reg state;
always @(posedge refclk or posedge reset)
if (reset)
begin
state <= 0;
done_update_and_b = 0;
b_temp = 0;
x_temp = 0;
end
else if (do_update_a_and_b && (state == 0))
begin
state <= 1;
done_update_a_and_b = 0;
end
else
begin
case (state)
0 : done_update_and_b = 0; // do nothing, this is the idle state
1 : if (z != 0)
begin
b_temp = z;
x_temp = a+b_temp; // x value is update inside this module, as i
t must occur immediately when z != 0
done_update_and_b = 1;
state <= 0;
// stay in state 0, we've finished
end
endcase
end
endmodule
...
reg [2:0] top_state;
...
case (top_state)
0 : begin
y = x + w;
do_update_a_and_b = 1; // call the task
top_state <= 1;
end
1 : begin
do_update_a_and_b = 0; // stays high for only one cycle
if (done_update_and_b)
begin
x = x_temp;
b = b_temp;
top_state <= 2;
end
end
2 : begin
x = b;
if (y == x)
begin
do_update_a_and_b = 1; // call the task
top_state <= 3;
end
else top_state <= 4;
end
3 : begin
do_update_a_and_b = 0; // stays high for only one cycle
if (done_update_and_b)
begin
x = x_temp;
b = b_temp;
top_state <= 4;
end
end
4: command1;
endcase
----------------------------------------------------------------------------
----
Delay statements, e.g. @(posedge clock), require careful attention if there
are several in a row. If there are only delays on the positive edge of the c
lock you can implement them with a state machine:
Behavioural Verilog:
forever
begin
command1;
@(posedge clock);
command2;
@(posedge clock);
command3;
@(posedge clock);
end
Could be implemented with the following synthesizable Verilog:
always @(posedge clock or posedge reset)
if (reset) // reset the state machine when reset is high
begin
state <= 0;
end
else
begin
case (state)
0 : begin
command1;
state <= 1;
end
1 : begin
command2;
state <= 2;
end
2 : begin
command3;
state <= 0;
end
endcase
end
If both clock edges are present, then you could implement it in synthesizabl
e Verilog with a state machine changing values on both clock edges:
Behavioural Verilog:
forever
begin
command1;
@(posedge clock);
command2;
@(negedge clock);
command3;
@(posedge clock);
@(posedge clock);
command4;
@(negedge clock);
end
Could be implemented with the following synthesizable Verilog:
always @(posedge clock or negedge clock or posedge reset)
if (reset) // reset the state machine when reset is high
begin
state <= 0;
end
else
begin
case (state)
0 : begin
command1;
state <= 1;
end
1 : if (clock == 1) // wait for the positive edge
begin
command2;
state <= 2;
end
2 : begin // this will definitely begin at the negative edge as stat
e 1 precedes it
command3;
state <= 0;
end
3 : state <= 4; // we arrive at the positive edge of the clock, but
need to wait a clock cycle
4 : if (clock == 1) // wait for the positive edge
begin
command4;
state <= 0;
end // we'll get back to state 0 at the negative clock edge, the
right time for command1
endcase
end
As you can see, multiple clock edges requires care to implement in synthesiz
able Verilog.
----------------------------------------------------------------------------
----
Note: in general commandi refers to a block of commands. I've assumed there
is an appropriate clock for the case statement state machines. Care is requi
red in setting appropriate reset states, initialization, and completion of u
se of a state machine:
Is there a signal to tell the state machine to begin?
Does a done signal go high, signalling the state machine has finished?
When it is not in operation, does the state machine idle correctly? Does it
change signal values shared with other code? Does it set outputs from it to
appropriate idling values?
Is the state machine reset to the idle state by a reset signal?
Ensure that you initialize all registers.
Ensure that your state register has the correct bit width - if it is too sma
ll, assigning a larger state value will just return it to an earlier state.
--
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 218.104.33.3]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:207.846毫秒