9.ステートメント
ステートメントは、initial_statementや、always_statementのなかで使われる手続き構文です。
<statement>
::=<blocking_assignment> ;
||= <non_blocking_assignment> ;
||= if ( <expression> ) <statement_or_null>
||= if ( <expression> ) <statement_or_null> else <statement_or_null>
||= case ( <expression> ) <case_item>+ endcase
||= casez ( <expression> ) <case_item>+ endcase
||= casex ( <expression> ) <case_item>+ endcase
||= forever <statement>
||= repeat ( <expression> ) <statement>
||= while ( <expression> ) <statement>
||= for ( <assignment> ; <expression> ; <assignment> ) <statement>
||= <delay_or_event_control> <statement_or_null>
||= wait ( <expression> ) <statement_or_null>
||= -> <name_of_event> ;
||= <seq_block>
||= <par_block>
||= <task_enable>
||= <system_task_enable>
||= disable <name_of_task> ;
||= disable <name_of_block> ;
||= assign <assignment> ;
||= deassign <lvalue> ;
||= force <assignment> ;
||= release <lvalue> ;
9.7 implicit event expression list(Verilog2001)
Verilog2001になって、最も恩恵があるのは、この機能でしょう。具体的には、
event_control ::= @event_identifier |@(event_expression ) |@* |@(*) |
で、@* や、@(*)が追加されました。どちらも同じ意味で、いちいちSensitibity Listを書かなくてもよいのです。たくさん ある Sensitibity Listの一つを忘れて、意図回路と合成回路が違うという、誰でも一度は犯しただろうバグを回避できます。(なんと、その効用は、LRMにも書いてあります。?)
下の例は、YACC ALUです。 @*を使って、簡単に記述することができます。
module alu (a,b,alu_func,alu_out); parameter [3:0] ALU_NOTHING =4'b0000, ALU_ADD =4'b0001, ALU_SUBTRACT =4'b0010, ALU_LESS_THAN_UNSIGNED =4'b0101, //Jul.5.2004 ALU_LESS_THAN_SIGNED =4'b0100, //Jul.5.2004 ALU_OR =4'b0011, ALU_AND =4'b0110, ALU_XOR =4'b0111, ALU_NOR =4'b1000; input [31:0] a,b; output [31:0] alu_out; input [3:0] alu_func; reg [31:0] alu_out; reg [32:0] sum; always @* begin //Jan.20.2005 @(a , b ,alu_func,sum) begin case (alu_func) ALU_NOTHING : alu_out=32'h0000; ALU_ADD : alu_out=a+b; ALU_SUBTRACT : alu_out=a+~b+1'b1;//a-b; ALU_OR : alu_out=a | b; ALU_AND : alu_out=a & b; ALU_XOR : alu_out=a ^ b; ALU_NOR : alu_out=~(a | b); ALU_LESS_THAN_UNSIGNED : alu_out=a < b;//Jun.29.2004 ALU_LESS_THAN_SIGNED: begin sum={a[31],a}+~{b[31],b}+1'b1;//a-b $signed(a) > $signed(b); alu_out={31'h0000_0000,sum[32]}; end default : alu_out=32'h0000_0000; endcase end endmodule |
次の例はマルチプレクサです。
module MPX_17 (address,R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15,R16,Y); input [4:0] address; input [7:0] R0,R1,R2,R3,R4,R5,R6,R7 ; input [7:0] R8,R9,R10,R11,R12,R13,R14,R15,R16 ; output [7:0] Y; wire [7:0] R0,R1,R2,R3,R4,R5,R6,R7 ; wire [7:0] R8,R9,R10,R11,R12,R13,R14,R15,R16 ; reg [7:0] Y; always @* //@(address or R0 or R1 or R2 or R3 or R4 or R5 or R6 or R7 or // R8 or R9 or R10 or R11 or R12 or R13 or R14 or R15 or R16 ) case(address) 5'b00000: Y=R0; 5'b00001: Y=R1; 5'b00010: Y=R2; 5'b00011: Y=R3; 5'b00100: Y=R4; 5'b00101: Y=R5; 5'b00110: Y=R6; 5'b00111: Y=R7; 5'b01000: Y=R8; 5'b01001: Y=R9; 5'b01010: Y=R10; 5'b01011: Y=R11; 5'b01100: Y=R12; 5'b01101: Y=R13; 5'b01110: Y=R14; 5'b01111: Y=R15; 5'b10000: Y=R16; 5'b10001: Y=R16; 5'b10010: Y=R16; 5'b10011: Y=R16; 5'b10100: Y=R16; 5'b10101: Y=R16; 5'b10110: Y=R16; 5'b10111: Y=R16; 5'b11000: Y=R16; 5'b11001: Y=R16; 5'b11010: Y=R16; 5'b11011: Y=R16; 5'b11100: Y=R16; 5'b11101: Y=R16; 5'b11110: Y=R16; 5'b11111: Y=R16; endcase endmodule |
イベントリストのショートカットみたいなものです。(実際、シミュレータの中では、@*以下の全てのステートメントをScanして内部イベントリストを作っています。その後のシミュレータの内部動作としては、ショートカットであろうがなかろうが、なんら変わりません。)
便利な記述ですが、気をつけることがあります。それは、HW合成する際は、その性質上、組み合わせ回路に限られるということです。
always @ (posedge clock , posedge async reset) => always @*.. |
なんてしてしまったら、全く意図しない回路になってしまいます。
右辺に現れる信号は、全て内部Sensitibity Listに加えられます。functionや、taskのパラメータも加えられます。
つまり、
always @* begin if (mode==3) begin a<=b; $display(" triggered m=%d k=%d mem=%b",m,k,mem[m][k]); end end |
の場合、mode, b,m,kが、内部Sensitibity Listに加えられます。また、
次のLHSのインデックス a もenに加えて、内部Sensitibity Listに加えられます。
always @* begin // same as @(a or en) y = 8'hff; y[a] = !en; end |
ただし、Event文のSensitibity Listは加えられません。
always @* begin // equivalent to @(b) @(j) dik = b; // j is not added to @* end |