试用Verilog中的=, <=和assign


  .v:

module my_circuit(output reg[7:0] c, input wire[7:0] a, b);
// Remove/change 'reg' and 'wire' to see error messages like who can't drive whom.
// reg is NOT necessarily a hardware register.
reg[7:0]    t;
// Procedural blocks are either initial or always. Initial blocks process statements one time.
// Always blocks are infinite loops which process statements repeatedly.
always @(a or b) begin // When a or b changes
//always begin // error: always process doesn't have any dealy. A runtime infinite loop will occur.
// variable = expression; Blocking procedural assignment. Expression is evaluated and assigned when 
// the statement is encountered.
    //t = a + b;
    //c = a + t;
// variable <= expression; Non-blocking procedural assignment.
// Expression is evaluated when the statement is encountered, and assignment is postponed until the
// end of the simulation time-step. In a begin-end sequential statement group, execution of the next
// statement is not blocked; and will be evaluated before the assignment is complete. In the sequence
// begin m<=n; n<=m; end, both assignments will be evaluated before m or n changes.
// Imagine: t0 = n; t1 = m; m = t0; n = t1;
    t = a;
    t <= 50;
    //t = 50;
    c <= t + a + b;
end
always @(a or b) begin
// Procedural continuous assignment. Overrides any other procedural assignments.
    //assign c = 100;
end
endmodule
module test;
wire[7:0]    c;
reg[7:0]     a, b;
initial begin
$monitor("%d %d %d\n", c, a, b);
#1 a = 2;
#1 b = 3;
#1 $finish;
end
my_circuit    x(c, a, b);
endmodule
// But it was said:
// Use always@(*) block with blocking assignments for combinational circuits.
// Use always@(posedge CLK) block with non-blocking assignments for sequential circuits.
// Do not mix blocking and non-blocking assignments.

a.out:

S_0000026b4f7c8200 .scope module, "test" "test" 2 29;
 .timescale 0 0;
v0000026b4f913460_0 .var "a", 7 0;
v0000026b4f913a00_0 .var "b", 7 0;
v0000026b4f913d20_0 .net "c", 7 0, v0000026b4f913960_0;  1 drivers
S_0000026b4f8e2a10 .scope module, "x" "my_circuit" 2 38, 2 1 0, S_0000026b4f7c8200;
 .timescale 0 0;
    .port_info 0 /OUTPUT 8 "c";
    .port_info 1 /INPUT 8 "a";
    .port_info 2 /INPUT 8 "b";
v0000026b4f8e3190_0 .net "a", 7 0, v0000026b4f913460_0;  1 drivers
v0000026b4f9135a0_0 .net "b", 7 0, v0000026b4f913a00_0;  1 drivers
v0000026b4f913960_0 .var "c", 7 0;
v0000026b4f9131e0_0 .var "t", 7 0;
E_0000026b4f7cb900 .event anyedge, v0000026b4f9135a0_0, v0000026b4f8e3190_0;
    .scope S_0000026b4f8e2a10;
T_0 ;
    %wait E_0000026b4f7cb900;
    %load/vec4 v0000026b4f8e3190_0;
    %store/vec4 v0000026b4f9131e0_0, 0, 8;
    %pushi/vec4 50, 0, 8;
    %assign/vec4 v0000026b4f9131e0_0, 0;
    %load/vec4 v0000026b4f9131e0_0;
    %load/vec4 v0000026b4f8e3190_0;
    %add;
    %load/vec4 v0000026b4f9135a0_0;
    %add;
    %assign/vec4 v0000026b4f913960_0, 0;
    %jmp T_0;
    .thread T_0, $push;
    .scope S_0000026b4f8e2a10;
T_1 ;
    %wait E_0000026b4f7cb900;
    %jmp T_1;
    .thread T_1, $push;
    .scope S_0000026b4f7c8200;
T_2 ;
    %vpi_call 2 33 "$monitor", "%d %d %d\012", v0000026b4f913d20_0, v0000026b4f913460_0, v0000026b4f913a00_0 {0 0 0};
    %delay 1, 0;
    %pushi/vec4 2, 0, 8;
    %store/vec4 v0000026b4f913460_0, 0, 8;
    %delay 1, 0;
    %pushi/vec4 3, 0, 8;
    %store/vec4 v0000026b4f913a00_0, 0, 8;
    %delay 1, 0;
    %vpi_call 2 36 "$finish" {0 0 0};
    %end;
    .thread T_2;

似乎可以把指令换成函数,如%load换load(...), %add换add()。 %jmp么,事先setjmp,jmp()里longjmp()? :-) 或者#define jmp(label) goto label? C吧,C++有点玄。

它用的是自己管理的堆栈,不是C的堆栈。

把v0000026b4f8e3190_0这样的串替换为原始变量名看起来清晰些。E_0000026b4f7cb900 .event anyedge, v0000026b4f9135a0_0, v0000026b4f8e3190_0; 如果那两个变量之一改变了,event就设为true,wait该event的语句就返回。

还可以这么玩(samples/sqrt.vl):
reg [4:0]  bitl;
wire [15:0] bit = 1 << bitl;
wire rdy = bitl[4];
iverilog处理后出现了.part和.shift:
v0000025dde3b94e0_0 .net "rdy", 0 0, L_0000025dde41e7a0;  alias, 1 drivers
L_0000025dde41e5c0 .shift/l 16, L_0000025dde41f868, v0000025dde3ba160_0;
它们之间似乎是种连动关系。 详情见vvp目录下的README.txt.

相关