Verilog Function Non Blocking Assignment

 as i learn from many refernce doc: , personnally speaking , a task shouldn't contain a non-blocking assignment.

 

 

The
 Verilog®
Golden
Reference
Guide

95页:

Rules
Names used in a task that are not declared in the task refer to names in the
calling module.
A task may have any number (including none) of input, output and inout
arguments.
Arguments (including inputs and inouts) may also be declared as registers. If
it is not declared explicitly, an argument is declared implicitly as a reg with the
same range as the corresponding argument.
When a task is enabled, the values of the argument expressions
corresponding to the task’s inputs and inouts are copied into the
corresponding argument registers. When the task completes, the values of
the inout and output argument registers are copied to the corresponding
expressions in the task enable statement.
Gotchas!
Unlike module ports, the arguments of a task are not defined in brackets after
the work task.
Tasks containing more than one statement must use a begin-end block or a
fork-join block to group the statements.
Task inputs, inouts and outputs, and any local registers are stored statically.
This means that even if a task is enabled (i.e. called) more than once, there is
only one copy of these registers. If a task is enabled a second time before the
first enable has completed, the values of the input and inout registers, and
possibly the local registers too, will be overridden.
94

The values of the outputs and inouts are only copied to the corresponding
register expressions in the task enable when the task completes. If there is a
timing control in the task after an assignment to an output or inout, the
corresponding registers in the task enable will only be updated after the timing
control delay.
Similarly, a non-blocking assignment to an output or inout may not work,
because the assignment may not have taken effect when the task returns.
Synthesis
For synthesis, a task may not contain timing controls. Task enables are
synthesized as combinational logic.
Tips
Complex RTL code is often structured by writing many always’s. Consider
instead using one always that enables several tasks.
Use tasks in test fixtures to apply repetitive sequences of stimulus. For
example, to read and write data from a memory (See Examples).
Tasks to be used in more than one module can be defined in a separate
module, containing only tasks, and referenced using a hierarchical name.
Example
This shows a simple RTL task, which can be synthesized.
task Counter;
  inout [3:0] Count;
  input Reset;
  if (Reset) // Synchronous Reset
    Count = 0; // Must use non-blocking for RTL

  else
    Count = Count + 1;
endtask

 

 

 

 

 

 

PAGE 182-*** :
 
状态机的VerilogHDL 程序见下面模块:
//------------------------------------------------------------------------------
module  machine( inc_pc, load_acc, load_pc, rd,wr, load_ir,
datactl_ena, halt, clk1, zero, ena, opcode );
 
output inc_pc, load_acc, load_pc, rd, wr, load_ir;
output datactl_ena, halt;
input clk1, zero, ena;
input [2:0] opcode;
reg inc_pc, load_acc, load_pc, rd, wr, load_ir;
reg datactl_ena, halt;
reg [2:0] state;
 
parameter   HLT  = 3 'b000,
  SKZ  = 3 'b001,
  ADD  = 3 'b010,
  ANDD = 3 'b011,
  XORR = 3 'b100,
  LDA  = 3 'b101,
  STO  = 3 'b110,
  JMP  = 3 'b111;
 
always @( negedge clk1 )
begin
if ( !ena )    //接收到复位信号RST,进行复位操作
begin

----------------------------------------------------------------------------------------------------------------------
  183
state<=3'b000;
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end
else
ctl_cycle;
end
//-----------------begin of task ctl_cycle---------
task ctl_cycle;
begin
casex(state)
    3’b000:          //load high 8bits in struction
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0001;
{wr,load_ir,datactl_ena,halt}<=4'b0100;
state<=3’b001;
end
    3’b001:    //pc increased by one then load low 8bits instruction
begin
{inc_pc,load_acc,load_pc,rd}<=4'b1001;
{wr,load_ir,datactl_ena,halt}<=4'b0100;
state<=3’b010;
end
    3’b010:    //idle
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
state<=3’b011;
end
 
    3’b011:    //next instruction address setup 分析指令从这里开始
begin
if(opcode==HLT)  //指令为暂停HLT
begin
{inc_pc,load_acc,load_pc,rd}<=4'b1000;
{wr,load_ir,datactl_ena,halt}<=4'b0001;
end  
else
begin
{inc_pc,load_acc,load_pc,rd}<=4'b1000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end  
state<=3’b100;
end
    3’b100:      //fetch oprand
begin
if(opcode==JMP)
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0010;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end
else

  184
if( opcode==ADD || opcode==ANDD || 
opcode==XORR || opcode==LDA)
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0001;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end 
else 
if(opcode==STO)
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b0010;
end  
else
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end  
state<=3’b101;
end
   3’b101:    //operation
begin
if ( opcode==ADD||opcode==ANDD||
opcode==XORR||opcode==LDA )
begin    //过一个时钟后与累加器的内容进行运算
{inc_pc,load_acc,load_pc,rd}<=4'b0101;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end  
else
if( opcode==SKZ && zero==1)
begin
{inc_pc,load_acc,load_pc,rd}<=4'b1000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end 
else
if(opcode==JMP)
begin
{inc_pc,load_acc,load_pc,rd}<=4'b1010;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end  
else
if(opcode==STO)
begin
//过一个时钟后把wr变1就可写到RAM中
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b1010;
end  
else
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end  
state<=3’b110;

end
3’b110:    //idle
begin
if ( opcode==STO )
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b0010;
end
else
if ( opcode==ADD||opcode==ANDD||
opcode==XORR||opcode==LDA)
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0001;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end
else
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end
state<=3’b111;
end
 
3’b111:    //
begin
if( opcode==SKZ && zero==1 )
begin
{inc_pc,load_acc,load_pc,rd}<=4'b1000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end
else
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
end
state<=3’b000;
end
default:
begin
{inc_pc,load_acc,load_pc,rd}<=4'b0000;
{wr,load_ir,datactl_ena,halt}<=4'b0000;
state<=3’b000;
end
endcase
end
endtask
//-----------------end of task ctl_cycle---------
 
endmodule
//------------------------------------------------------------------------------

 

 

for more:

http://www.openhw.net/bbs/article_75_62157.html

Blocking vs. Nonblocking in Verilog

The concept of Blocking vs. Nonblocking signal assignments is a unique one to hardware description languages. The main reason to use either Blocking or Nonblocking assignments is to generate either combinational or sequential logic. In software, all assignments work one at a time. So for example in the C code below:

LED_on = 0; count = count + 1; LED_on = 1;

The second line is only allowed to be executed once the first line is complete. Although you probably didn't know it, this is an example of a blocking assignment. One assignment blocks the next from executing until it is done. In a hardware description language such as Verilog there is logic that can execute concurrently or at the same time as opposed to one-line-at-a-time and there needs to be a way to tell which logic is which.

<=     Nonblocking Assignment

=      Blocking Assignment   


always @(posedge i_clock) begin r_Test_1 <= 1'b1; r_Test_2 <= r_Test_1; r_Test_3 <= r_Test_2; end

The always block in the Verilog code above uses the Nonblocking Assignment, which means that it will take 3 clock cycles for the value 1 to propagate from r_Test_1 to r_Test_3. Now consider this code:

always @(posedge i_clock) begin r_Test_1 = 1'b1; r_Test_2 = r_Test_1; r_Test_3 = r_Test_2; end

See the difference? In the always block above, the Blocking Assignment is used. In this example, the value 1 will immediately propagate to r_Test_3. The Blocking assignment immediately takes the value in the right-hand-side and assigns it to the left hand side. Here's a good rule of thumb for Verilog:

In Verilog, if you want to create sequential logic use a clocked always block with Nonblocking assignments. If you want to create combinational logic use an always block with Blocking assignments. Try not to mix the two in the same always block.

Nonblocking and Blocking Assignments can be mixed in the same always block. However you must be careful when doing this! It's actually up to the synthesis tools to determine whether a blocking assignment within a clocked always block will infer a Flip-Flop or not. If it is possible that the signal will be read before being assigned, the tools will infer sequential logic. If not, then the tools will generate combinational logic. For this reason it's best just to separate your combinational and sequential code as much as possible.

One last point: you should also understand the semantics of Verilog. When talking about Blocking and Nonblocking Assignments we are referring to Assignments that are exclusively used in Procedures (always, initial, task, function). You are only allowed to assign the reg data type in procedures. This is different from a Continuous Assignment. Continuous Assignments are everything that's not a Procedure, and only allow for updating the wire data type.



One thought on “Verilog Function Non Blocking Assignment

Leave a Reply

Your email address will not be published. Required fields are marked *