试用Verilog中的=, <=和assign
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.