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
|