最初に書いたLチカは色を変えながらずっとループするものだった。その後、すぐにUARTを書こうとして文字の出力が止まらなくなった。今日は少し反省したので、謙虚にLEDを0から3まで順番に点灯させていって最後はすべて消して止まる、という回路を書こうと思う。文字の出力が止まらなくなったので一歩下がってわかりやすい例でちゃんと止まるものを書くべきだと思ったのだ。もっと毎日がっつり時間をかけないとものにならないのでは?
とりあえず以下のようなコードを書いた。これは、2Hzで以下のように動作する。
- LED0を点ける
- LED1を点ける
- LED2を点ける
- LED3を点ける
- すべて消して終了
それだけだ。これは動いた。これに関してはさほど苦労しなかった。ただし、いくつかの軽微なエラーにでくわした。
例えば、「multiple driver nets」というのにでくわした。これは、同じシグナルに複数のalways
文から入力してしまっているということらしい。教科書を流し読みしただけだったので、これが禁止されていることを理解していなかった。
理解しないと覚えづらいたちなのでこれが禁止されている理由について考えてみたい。上のリンクで回答している人も説明してくれればいいのに……。それとも何かの背景知識があると自明なはずなのだろうか。Verilogでは回路の繋ぎ方を書いている、と思っていいのなら、このエラーは複数の順序回路の出力が一つのレジスタに入っているということを意味している。これは……片方が1でもう片方が0の時に不定になる? というかそもそもレジスタへの入力は一つなので繋ぐことができないのかな。本の索引でalways
が乗ってるページを前からしらみつぶしに見ていたところ、真ん中の方のコラムに「二つのalwaysブロックを書いた結果レジスタが二つ生成されてそれらがセレクタを通して出力されてシミュレータでは動いたが実機では動かなかい」例が載っていた。一つしか宣言していなくてもalways
文の数だけ生成されて、あとでセレクタがそれを繋ぐようになるということ? これは合成結果の回路を見ればわかるのかな。これっぽいけど、合成自体がエラーで落ちたんだよな。本が出てから後でこういう場合はエラーで落とすようになったということだろうか。
どうも電子工作の経験が皆無なことがハンデになっている気がしなくもない。あまりちゃんと理解できている感触がない。
ところで、以下のコードでalways @(...)
でコメントアウトしている部分を使ったところ正しく動かなかった(リセット後3回に2回は何も起きない、残りは2秒ほどすべてのLEDが点いて消える)のだけど、これは何でだろう。どうも、挙動を完全に理解できていないまま動かしていると前に進んでいる感があまりないな……。
module blink_for_a_while( input wire CLK100MHZ, input wire reset, output wire[2:0] led0, output wire[2:0] led1, output wire[2:0] led2, output wire[2:0] led3 ); localparam CLK_PER_BLINK = 50000000; localparam CLK_COUNTER_W = 1+$clog2(CLK_PER_BLINK); reg[CLK_COUNTER_W-1:0] clock_counter = {CLK_COUNTER_W{1'b0}}; reg turn_led = 1'b0; reg[2:0] led_addr = 3'b0; reg[2:0] led0_state = 3'b000; reg[2:0] led1_state = 3'b000; reg[2:0] led2_state = 3'b000; reg[2:0] led3_state = 3'b000; assign led0 = led0_state; assign led1 = led1_state; assign led2 = led2_state; assign led3 = led3_state; always @(posedge CLK100MHZ) begin turn_led <= 1'b0; if (reset) begin clock_counter <= {CLK_COUNTER_W{1'd0}}; end else if (clock_counter == CLK_PER_BLINK) begin clock_counter <= {CLK_COUNTER_W{1'd0}}; turn_led <= 1'b1; end else begin clock_counter <= clock_counter + 1'b1; end end // always @(turn_led or reset) begin always @(posedge CLK100MHZ) begin if (reset) begin led_addr <= 3'd0; led0_state <= 3'b000; led1_state <= 3'b000; led2_state <= 3'b000; led3_state <= 3'b000; end else if (turn_led == 1'b1) begin if (led_addr != 4) begin led_addr <= led_addr + 1; case (led_addr) 2'd0: led0_state <= 3'b111; 2'd1: led1_state <= 3'b111; 2'd2: led2_state <= 3'b111; 2'd3: led3_state <= 3'b111; endcase end else begin led0_state <= 3'b000; led1_state <= 3'b000; led2_state <= 3'b000; led3_state <= 3'b000; end end end endmodule
## This file is a general .xdc for the Arty A7-35 Rev. D ## To use it in a project: ## - uncomment the lines corresponding to used pins ## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project ## Clock signal set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { CLK100MHZ }]; #IO_L12P_T1_MRCC_35 Sch=gclk[100] create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports { CLK100MHZ }]; ## RGB LEDs set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { led0[2] }]; #IO_L18N_T2_35 Sch=led0_b set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { led0[1] }]; #IO_L19N_T3_VREF_35 Sch=led0_g set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { led0[0] }]; #IO_L19P_T3_35 Sch=led0_r set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { led1[2] }]; #IO_L20P_T3_35 Sch=led1_b set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { led1[1] }]; #IO_L21P_T3_DQS_35 Sch=led1_g set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { led1[0] }]; #IO_L20N_T3_35 Sch=led1_r set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { led2[2] }]; #IO_L21N_T3_DQS_35 Sch=led2_b set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { led2[1] }]; #IO_L22N_T3_35 Sch=led2_g set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { led2[0] }]; #IO_L22P_T3_35 Sch=led2_r set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { led3[2] }]; #IO_L23P_T3_35 Sch=led3_b set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { led3[1] }]; #IO_L24P_T3_35 Sch=led3_g set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { led3[0] }]; #IO_L23N_T3_35 Sch=led3_r ## Buttons set_property -dict { PACKAGE_PIN D9 IOSTANDARD LVCMOS33 } [get_ports { reset }]; #IO_L6N_T0_VREF_16 Sch=btn[0]