とりあえず,最初は覚え書きからスタートです.
always @(posedge reset or posedge clk) begin if (reset==1'b1) d <= 1'b0; else d <= d + 1'b1; end
クロック同期にしていないと,思わぬところでグリッヂが発生し,誤動作を招くので.
C1 >
とかなったとき,
C1 > $finish
した後,"Ctrl-\"で終了できる.
回路はモジュール構造."module"で始まり,"endmodule"で終わる.モジュール名の後に,括弧書きで入出力ポートを記述.spiceでいうなら,".subckt"みたいな感じで,例えば
.subckt inverter in out ごにょごにょ・・・ .ends
ってやつが,
module inverter (in out); ごにょごにょ・・・ endmodule
ってのに対応すると考えれば良い(と思う).
論理否定 | ! ~ | |
加減乗除 | + - * / % | |
シフト演算 | << >> | |
比較演算 | < <= > >= | |
等号 | == !== === | |
ビット単位論理積 | & | |
ビット単位排他的論理 | ^ ^~ | |
ビット単位論理和 | | | |
論理積 | && | |
論理和 | || |
3bitの信号と5bitの信号をくっつけて8bitの信号を生成したいような場合,連接演算子{}を使えばよい.
wire [3:0] a; wire [4:0] b; wire [7:0] c = {a,b};
注意すべきなのは,信号は{}の左から順に,MSB側から連結される.つまり,a=1101,b=0011だとすると,c=11010011となる.
assign文,function文の中で使う.
if (条件) begin 式; end else if (条件) begin 式; end else 式; end
である.begin~endはC言語の{}と同じ.式が一行なら省略できる.
begin~endやfork~join内で使おう.if文と似ているが,ステートマシンとか記述するとき役立つ.case~endcaseで条件を挟む.
case (式) 条件1:文; 条件2:文; ・・・ default:文; endcase
defaultは,記述した条件に当てはまらない場合に実行される.よって,設計者のミスを防いでくれる役目もあるので,記述しておいた方が良い.
assign文とか,wire宣言文で使う.例えば,weが1なら,cにbを,そうでないならcにaを出力したい場合は
assign c = (we == 1'b1) ? b : a;
メモリを初期化したい時とか,これが使える.んで,下はその例.8bit 256wordのmemメモリを初期化.resetはネガティブタイプ.
always@(posedge clk or negedge reset) begin if (reset==1'b0) begin : init_mem integer index; for (index=0;index<=255;index=index+1) mem[index] <= 8'h00; end end
ここで,for文には複数の変数を用いることはできない.例えば,
for(i=0;i<100;j=j-1)
といった場合である.
C言語などでは,#defineを利用したりして曖昧なリテラルは避けるべきである.後々回路変更等する場合,その数値にどんな意味があるのかわからないと困るし,数値にしていると変更するときむっちゃ面倒くさいことになる.そこで,verilogでもparameterを使って同じことができる.これを使えば,module呼び出しとかでも役に立つ.
parameter 変数名=初期値;
これをmodule宣言のすぐ後に記述すればよい.例えば,
module SWITCH(in, sel, out); parameter width = 2; input [width-1:0] in; input sel; output [width-1:0] out;
といった感じ.module呼び出し時のパラメータ設定についてはここを参照.
回路ブロックはすべてmodule記述されるので,同じ回路を沢山使う場合,サブサーキットみたくmodule名を呼び出して利用できる.spiceの場合,
X1 i1 i2 out AND .subckt AND a b y ... .ends
という具合に利用するが,verilogでは
AND U1 (i1, i2, out); module AND(a, b, y); ... endmodule
という記述になる.U1がインスタンス名で,自分で設定する.次にくるのがポート名で,上記のように記述するとmoduleで定義した順番と同じ順番でネットが接続される.一方,接続されるポートを指定したい場合は
AND U1 (.a(i1), .b(i2), .y(out));
とすればよい.また,moduleでparameter宣言している場合,呼び出し時に再設定できる.
AND #(3,4) U1 (i1, i2, out); module AND(a, b, y); parameter P1 = 1; parameter P2 = 2; ... endmodule
この場合,P1=3,P2=4となる.ポート定義と同じく,パラメータ名を指定したい場合は
#defparam U1.P1 = 3; #defparam U1.P2 = 4; AND U1 (i1, i2, out);
とすればよい.
組み合わせ回路を記述したいときに使える.C言語の自作関数みたいなもん.記述の仕方はこんな感じ.
function データ幅 関数名(出力名); 入力信号名; 内部信号名; 記述; endfunction
では,2:1マルチプレクサを記述する場合を例にとってみる.関数名をMPX_2to1とし,入力はa[1:0]とb[1:0]とする.で,en信号がHighならaを,Lowならbを出力する.
function [1:0] MPX_2to1; input [1:0] a; input [1:0] b; input en; if (en == 1'b1) MPX_2to1 = a; else MPX_2to1 = b; endfunction
で,実際にこの機能を利用するには,呼び出さないといけない.
wire [1:0] in1,in2,out; assign out = MPX_2to1(a,b);
注意!function文ではwire宣言はできない.代わりに,regやintegerを使うこと.integerを使うと32bit符号付き演算として合成されるので注意.
Xilinxのデバイスのように,RAMが搭載されていれば推論して利用できる.そうじゃない場合はレジスタファイルになる.
クロックに同期して書き込み・読み込みを行うメモリ.で,メモリ本体はregで表現する.3bitデータを256個保存するようなメモリを作るには,次のような記述をする.
reg [2:0] ram [0:255];
3bitのレジスタが256個並んでるってことね.で,256個並んでるということは,アドレスは8bit必要になる.
input [7:0] address;
後は,書き込み・読み込みを制御する信号を付け加え,下記のように記述する.これをちょっとでも変更すると違うタイプのRAMになったり,レジスタファイルになるので注意(たぶん).
module spram_sr(clk, we, address, data_i, data_o); input clk; input we; input [7:0] address; input [2:0] data_i; output [2:0] data_o; reg [2:0] ram [0:255]; reg [7:0] read_a; always @(posedge clk) begin if (we) begin ram[address] <= data_i; end read_a <= address; end assign data_o = ram[read_a]; endmodule
SEO | [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送 | ||