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




