CPU+コンパイラ自作キャンプ/Verilogの練習
6ビットのLEDを好きなビットパターンで光らせる
assign onboard_led = 6'b111001;
Tang Nano 9KのオンボードLEDは、0で点灯、1で消灯
WSL上で make sim するとシミュレーションが動く
code:実行例
$ make sim
iverilog -g2012 -o sim.exe main_tb.sv main.sv
./sim.exe
0 led=001010
2行目はIcarus Verilogを起動してsim.exeをビルドしている。
3行目はsim.exeを実行している。
4行目以降がシミュレーション結果。
最初の「0」は時刻
次の「led=001010」はLEDへの出力信号
この回路は信号が変化しないので時刻=0の行だけが表示されている。
makeはMakefileの指示にしたがって動く
1秒間隔で点滅させる
2通りのやり方を説明
1. LEDへの出力信号をレジスタとして、0.5秒ごとにレジスタの値を反転させる。
カウンタを作る logic [23:0] counter;
27M/2=13.5Mをカウントするためには、24ビット(最大値は約16.8M)で足りる。
クロックの立ち上がりでカウンタをインクリメントし、13.5M(0.5秒)に達したら0に戻す
カウンタが一周したら onboard_led のビットを反転させる
2. LEDへの出力信号を配線として、カウンタが下半分のときと上半分のときに出力値を変える。
カウンタを作る logic [24:0] counter;
1の方法の2倍を数える必要があるので、1ビット大きくする。
クロックの立ち上がりでカウンタをインクリメントし、27M(1秒)に達したら0に戻す
カウンタが13.5M(0.5秒)未満か以上かで onboard_led のビットを反転させる
脱線ネタ:PWMを使って滑らかに明るさを変えて明滅させる 余裕があれば挑戦してみよう
ボタンを押すたびに1ビットずつ乱数を生成する
logic [15:0] lfsr;
6ビットのLEDを1ビットずらし、空いた1ビットに乱数を入れる
10ms程度の間隔でボタンを読み取る方法は簡単で効果が高い
Verilogの書き方
いろんな書き方ができる
FPGAは理論的にはどんな論理回路も作れる
ちゃんと動く回路、見通しが良いコードという観点で「良い書き方」というのがある
基本方針1:クロック同期回路としてすべてを設計する
code:alwaysのひな形.sv
always @(posedge sys_clk, negedge rst_n) begin
if (~rst_n)
信号 <= 初期値;
else
信号 <= 意味のある値;
end
posedgeは立ち上がりエッジ(positive edge)、negedgeは立ち下がりエッジ(negative edge)に反応
https://gyazo.com/c05309f6e03bb8eaa06a63e324467e6b
レジスタへの信号代入は、すべて上記のひな形を守る
当然だが、else ではなく else if を使うといった応用は必要に応じてやる
守ること:
alwaysのセンシティビティリストはクロックとリセットのみを指定
他の信号は入れない
alwaysの2行目は必ずリセット信号を判定するif文とする
基本方針2:assignは信号線に使い、alwaysはレジスタに使う
code:assignとalwaysの使い分け.sv
always @(posedge sys_clk, negedge rst_n) begin
if (~rst_n)
counter <= 0;
else if (counter >= 27_000_000 - 1)
counter <= 0;
else
counter <= counter + 25'd1;
end
// 出力を配線(継続代入)で行う
assign onboard_led = counter < 13_500_000 ? 6'b101001 : 6'b010110;
onboard_ledは配線名となり、値を記憶したりはしない
配線なので当然だが、右辺の値が変化すればすぐにonboard_ledの値も変化する
counterはジレスタとなり、値を記憶する