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毫秒