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に次のように表示されます。