「KV260でLEDチカ(その1)」では、KV260でLEDチカを行いましたが、今回はKV260でUARTを作成し、PCのTera Termの画面に「Hello, FPGA」を表示します。
Vivado でプロジェクト作成
「Vivado MLによるKria KV260のFPGAのプログラム作成(その1)」に従ってプロジェクトを作成します。プロジェクト名は「UARTTestt」とします。
Block Designer を利用してclock・resetを作成
「KV260でLEDチカ(その1)」に従って、Block Designer でclockを作成します。ツールアイコン「Add IP」を用いて、「Processor System Reset」を追加ます。つぎに、slowest_sync_clk にクロックをつなぎ、ext_reset_in に pl_resetn0 を接続しpheripheral_reset を引き出して次のように配線します。
SystemVerilog でプログラムの記述
「KV260でLEDチカ(その1)」に従って、次のようにSystemVerilog でUARTプログラム「uart.sv」を作成します。
uart.sv
`timescale 1ns / 1ps module uart( input logic CLK, RST, input logic [7:0] DATA_IN, input logic WE, output logic DATA_OUT, output logic BUSY ); parameter WAIT_DIV = 868; // 100 MHz / 115.2 kbps localparam WAIT_LEN = $clog2(WAIT_DIV); typedef enum { STATE_IDLE, STATE_SEND } state_type; state_type state, n_state; logic [9:0] data_reg, n_data_reg; logic [WAIT_LEN-1:0] wait_cnt, n_wait_cnt; logic [3:0] bit_cnt, n_bit_cnt; assign DATA_OUT = data_reg[0]; always_comb begin BUSY = 1'b0; n_state = state; n_wait_cnt = wait_cnt; n_bit_cnt = bit_cnt; n_data_reg = data_reg; if (state == STATE_IDLE) begin if (WE) begin n_state = STATE_SEND; n_data_reg = {1'b1, DATA_IN, 1'b0}; end end else if (state == STATE_SEND) begin BUSY = 1'b1; if (wait_cnt == WAIT_DIV - 1) begin if (bit_cnt == 4'd9) begin n_state = STATE_IDLE; n_wait_cnt = 0; n_bit_cnt = 4'd0; end else begin n_data_reg = {1'b1, data_reg[9:1]}; n_wait_cnt = 0; n_bit_cnt = bit_cnt + 1'b1; end end else begin n_wait_cnt = wait_cnt + 1'b1; end end end always_ff @ (posedge CLK) begin if (RST) begin state <= STATE_IDLE; wait_cnt <= 0; bit_cnt <= 4'd0; data_reg <= 10'h3ff; end else begin state <= n_state; wait_cnt <= n_wait_cnt; bit_cnt <= n_bit_cnt; data_reg <= n_data_reg; end end endmodule
Vivado MLによるプログラムシミュレーション
回路は Design Source(s) として、テストベンチは Simulation Source(s) として、プロジェクトにそれぞれを追加します。Simulation Source(s) として追加したファイルは、論理合成では利用されず、シミュレーションでのみ利用されます。
テストベンチ「uart_sim.sv」を次に示します。
- #(数字) はその時間だけ待つという意味になります。 Vivado シミュレータで特に指定をしなかった場合、時間の単位は ns になります。
- テストベンチでは、イベントの評価順が結果に影響するので、テストされるモジュールに渡す信号線への代入は「ノンブロッキング代入」とします。
uart_sim.sv
`timescale 1ns / 1ps module uart_sim( ); logic CLK, RST; logic [7:0] DATA_IN; logic WE; logic DATA_OUT; logic BUSY; uart # ( .WAIT_DIV(5)) ser ( .CLK(CLK), .RST(RST), .DATA_IN(DATA_IN), .WE(WE), .DATA_OUT(DATA_OUT), .BUSY(BUSY)); always begin CLK <= 1'b1; #10; CLK <= 1'b0; #10; end initial begin RST <= 1'b1; #30; RST <= 1'b0; end assign DATA_IN = 8'h41; initial begin WE <= 1'b0; #90; WE <= 1'b1; #20; WE <= 1'b0; wait (BUSY == 1'b0); #100; $finish; end endmodule
Simulation Sources の階層関係を次に示します。テストベンチ「uart_sim.sv」をトップにするには、テストベンチ「uart_sim.sv」を右クリックして「Set asT op」を選択します。
右メニューの「Run Simulation」 →「Run Behavioral Simulation 」 をクリックするとシミュレータが起動し、(記述にエラーがなければ)次のシミュレータの波形が表示されます。
トップモジュールの作成
UARTプログラム「uart.sv」にデータを渡すトップモジュール「top.sv」を作成します。
top.sv
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 2025/03/24 08:46:28 // Design Name: // Module Name: top // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module top( output logic TXD ); // PS logic RST ; // sync reset logic CLK ; // 100MHz design_1 u_design_1 ( .reset (RST ), .clk (CLK ) ); typedef enum { STATE_SEND, STATE_WAIT, STATE_FIN } state_type; state_type state, n_state; logic we; logic busy; logic [7:0] data_in; logic [3:0] byte_cnt, n_byte_cnt; uart # ( .WAIT_DIV(868)) ser ( .CLK(CLK), .RST(RST), .DATA_IN(data_in), .WE(we), .DATA_OUT(TXD), .BUSY(busy)); always_comb begin case (byte_cnt) 4'd0 : data_in = 8'h48; // H 4'd1 : data_in = 8'h65; // e 4'd2 : data_in = 8'h6c; // l 4'd3 : data_in = 8'h6c; // l 4'd4 : data_in = 8'h6f; // o 4'd5 : data_in = 8'h2c; // , 4'd6 : data_in = 8'h20; // 4'd7 : data_in = 8'h46; // F 4'd8 : data_in = 8'h50; // P 4'd9 : data_in = 8'h47; // G 4'd10: data_in = 8'h41; // A 4'd11: data_in = 8'h0a; // \n default: data_in = 8'h00; endcase end always_comb begin n_state = state; n_byte_cnt = byte_cnt; we = 1'b0; if (state == STATE_SEND) begin n_state = STATE_WAIT; we = 1'b1; end else if (state == STATE_WAIT) begin if (~ busy) begin if (byte_cnt == 4'd11) begin n_state = STATE_FIN; end else begin n_state = STATE_SEND; n_byte_cnt = byte_cnt + 1'b1; end end end end always_ff @ (posedge CLK) begin if (RST) begin state <= STATE_SEND; byte_cnt <= 4'd0; end else begin state <= n_state; byte_cnt <= n_byte_cnt; end end endmodule
制約ファイル (XDC) は、「KV260でLEDチカ(その2)」で作成したファイルを使用します。 KV260 の PMOD(J2) の1番ピンにUSBシリアル変換モジュールは「CP2102 USB to TTL」を経由して、次のように接続します。UARTのTXデータが出力されます。
作成した回路は、「KV260でLEDチカ(その2)」に従って実行します。Tera Termに次のように表示されます。