Skip to content

Instantly share code, notes, and snippets.

@miyo
Last active May 29, 2020
Embed
What would you like to do?
ACRiブログ "FPGA をもっと活用するために IP コアを使ってみよう (5)" のコードスニペット
`default_nettype none
module bram_to_fifo
(
input wire CLK,
input wire RST,
output logic WE,
output logic [7:0] DATA_IN,
output logic [13:0] A,
input wire [7:0] Q
);
typedef enum {
STATE_IDLE,
STATE_WAIT,
STATE_SEND_PRE_0,
STATE_SEND_PRE_1,
STATE_SEND,
STATE_SEND_CR,
STATE_SEND_LF
} state_type;
state_type state, n_state;
logic [3:0] x_count, n_x_count;
logic [3:0] y_count, n_y_count;
logic [31:0] wait_counter, n_wait_counter;
logic [0:0] n_we;
logic [13:0] n_a;
logic [7:0] n_data_in;
always_comb begin
n_state = state;
n_x_count = x_count;
n_y_count = y_count;
n_wait_counter = wait_counter;
n_we = 1'b0;
n_a = A;
n_data_in = DATA_IN;
case(state)
STATE_IDLE: begin
n_state = STATE_SEND_PRE_0;
n_a = 0;
end
// メモリのリードレインテンシを考慮した調整
STATE_SEND_PRE_0: begin
n_a = A + 1;
n_state = STATE_SEND_PRE_1;
end
// メモリのリードレインテンシを考慮した調整
STATE_SEND_PRE_1: begin
n_a = A + 1;
n_state = STATE_SEND;
end
// bram_to_uartでは serial_send の状況を見てSTATE_SEND_WAITに遷移していたが,
// 間にFIFOがあることで serial_send を考慮せず,連続でデータを読み出して出力できる
STATE_SEND: begin
n_we = 1'b1;
n_data_in = Q == 0 ? 8'h5f : Q; // replace NULL to '_'
n_a = (x_count >= 6) ? A : (A == 8*8-1) ? 0 : A + 1;
n_state = (x_count == 7) ? STATE_SEND_CR : STATE_SEND;
n_x_count = (x_count == 7) ? 0 : x_count + 1;
end
// bram_to_uartでは CR の出力の後,serial_send の状況を見て待つ必要があったが,
// 間にFIFOがあることで serial_send を考慮せず,すぐにLFの出力ができる
STATE_SEND_CR: begin
n_we = 1'b1;
n_a = (A == 8*8-1) ? 0 : A + 1;
n_data_in = 8'h0d; // CR
n_state = STATE_SEND_LF;
end
// bram_to_uartでは LF の出力の後,serial_send の状況を見て待つ必要があったが,
// 間にFIFOがあることで serial_send を考慮せず,すぐに次の状態に遷移できる
STATE_SEND_LF: begin
n_we = 1'b1;
n_a = (A == 8*8-1) ? 0 : A + 1;
n_data_in = 8'h0a; // LF
n_state = (y_count == 7) ? STATE_WAIT : STATE_SEND;
n_y_count = (y_count == 7) ? 0 : y_count + 1;
end
STATE_WAIT: begin
n_a = 0;
if(wait_counter < 100000000) begin
n_wait_counter <= wait_counter + 1;
end else begin
n_wait_counter <= 0;
n_state <= STATE_SEND_PRE_0;
end
end
endcase // case (state)
end
always_ff @ (posedge CLK) begin
if (RST) begin
state <= STATE_IDLE;
x_count <= 0;
y_count <= 0;
A <= 0;
WE <= 0;
wait_counter <= 0;
end else begin
state <= n_state;
x_count <= n_x_count;
y_count <= n_y_count;
wait_counter <= n_wait_counter;
A <= n_a;
WE <= n_we;
DATA_IN <= n_data_in;
end
end // always_ff @ (posedge CLK)
endmodule // bram_to_uart
`default_nettype wire
`default_nettype none
module fifo_example_top (
input wire CLK,
input wire RST,
output logic DATA_OUT
);
logic [7:0] DATA_IN;
logic WE;
logic BUSY;
serial_send serial_send_i(.CLK(CLK),
.RST(RST),
.DATA_IN(DATA_IN),
.WE(WE),
.DATA_OUT(DATA_OUT),
.BUSY(BUSY)
);
(* MARK_DEBUG *) logic [13:0] A;
(* MARK_DEBUG *) logic [7:0] Q;
bram_example_vio bram_example_i (.CLKA(CLK),
.CLKB(CLK),
.RST(RST),
.A(A),
.Q(Q)
);
(* MARK_DEBUG *) logic [7:0] fifo_ft_din;
(* MARK_DEBUG *) logic fifo_ft_wr_en;
(* MARK_DEBUG *) logic fifo_ft_rd_en;
(* MARK_DEBUG *) logic [7:0] fifo_ft_dout;
logic system_ready = ~(RST | fifo_ft_wr_rst_busy | fifo_ft_rd_rst_busy);
bram_to_fifo bram_to_uart_i(.CLK(CLK),
.RST(~system_ready),
.DATA_IN(fifo_ft_din),
.WE(fifo_ft_wr_en),
.A(A),
.Q(Q));
always_ff @(posedge CLK) begin
if(system_ready == 1 && WE == 0 && BUSY == 0 && fifo_ft_valid == 1) begin
WE <= 1;
fifo_ft_rd_en <= 1;
DATA_IN <= fifo_ft_dout;
end else begin
WE <= 0;
fifo_ft_rd_en <= 0;
end
end
logic fifo_ft_full;
logic fifo_ft_almost_full;
logic fifo_ft_wr_ack;
logic fifo_ft_overflow;
logic fifo_ft_empty;
logic fifo_ft_almost_empty;
logic fifo_ft_valid;
logic fifo_ft_underflow;
logic fifo_ft_rd_data_count;
logic fifo_ft_wr_data_count;
logic fifo_ft_wr_rst_busy;
logic fifo_ft_rd_rst_busy;
fifo_generator_0_ft fifo_generator_0_ft_i
(
.rst(RST),
.wr_clk(CLK),
.rd_clk(CLK),
.din(fifo_ft_din),
.wr_en(fifo_ft_wr_en),
.rd_en(fifo_ft_rd_en),
.dout(fifo_ft_dout),
.full(fifo_ft_full),
.almost_full(fifo_ft_almost_full),
.wr_ack(fifo_ft_wr_ack),
.overflow(fifo_ft_overflow),
.empty(fifo_ft_empty),
.almost_empty(fifo_ft_almost_empty),
.valid(fifo_ft_valid),
.underflow(fifo_ft_underflow),
.rd_data_count(fifo_ft_rd_data_count),
.wr_data_count(fifo_ft_wr_data_count),
.wr_rst_busy(fifo_ft_wr_rst_busy),
.rd_rst_busy(fifo_ft_rd_rst_busy)
);
endmodule // bram_example_top
`default_nettype wire
`timescale 1ns / 100ps
`default_nettype none
module fifo_tb();
logic fifo_rst;
logic fifo_wr_clk;
logic fifo_rd_clk;
logic [7:0] fifo_din;
logic fifo_wr_en;
logic fifo_rd_en;
logic [7:0] fifo_dout;
logic fifo_full;
logic fifo_almost_full;
logic fifo_wr_ack;
logic fifo_overflow;
logic fifo_empty;
logic fifo_almost_empty;
logic fifo_valid;
logic fifo_underflow;
logic [9:0] fifo_rd_data_count;
logic [9:0] fifo_wr_data_count;
logic fifo_wr_rst_busy;
logic fifo_rd_rst_busy;
logic fifo_ft_rst;
logic fifo_ft_wr_clk;
logic fifo_ft_rd_clk;
logic [7:0] fifo_ft_din;
logic fifo_ft_wr_en;
logic fifo_ft_rd_en;
logic [7:0] fifo_ft_dout;
logic fifo_ft_full;
logic fifo_ft_almost_full;
logic fifo_ft_wr_ack;
logic fifo_ft_overflow;
logic fifo_ft_empty;
logic fifo_ft_almost_empty;
logic fifo_ft_valid;
logic fifo_ft_underflow;
logic [10:0] fifo_ft_rd_data_count;
logic [10:0] fifo_ft_wr_data_count;
logic fifo_ft_wr_rst_busy;
logic fifo_ft_rd_rst_busy;
fifo_generator_0 fifo_generator_0_i
(
.rst(fifo_rst),
.wr_clk(fifo_wr_clk),
.rd_clk(fifo_rd_clk),
.din(fifo_din),
.wr_en(fifo_wr_en),
.rd_en(fifo_rd_en),
.dout(fifo_dout),
.full(fifo_full),
.almost_full(fifo_almost_full),
.wr_ack(fifo_wr_ack),
.overflow(fifo_overflow),
.empty(fifo_empty),
.almost_empty(fifo_almost_empty),
.valid(fifo_valid),
.underflow(fifo_underflow),
.rd_data_count(fifo_rd_data_count),
.wr_data_count(fifo_wr_data_count),
.wr_rst_busy(fifo_wr_rst_busy),
.rd_rst_busy(fifo_rd_rst_busy)
);
fifo_generator_0_ft fifo_generator_0_ft_i
(
.rst(fifo_ft_rst),
.wr_clk(fifo_ft_wr_clk),
.rd_clk(fifo_ft_rd_clk),
.din(fifo_ft_din),
.wr_en(fifo_ft_wr_en),
.rd_en(fifo_ft_rd_en),
.dout(fifo_ft_dout),
.full(fifo_ft_full),
.almost_full(fifo_ft_almost_full),
.wr_ack(fifo_ft_wr_ack),
.overflow(fifo_ft_overflow),
.empty(fifo_ft_empty),
.almost_empty(fifo_ft_almost_empty),
.valid(fifo_ft_valid),
.underflow(fifo_ft_underflow),
.rd_data_count(fifo_ft_rd_data_count),
.wr_data_count(fifo_ft_wr_data_count),
.wr_rst_busy(fifo_ft_wr_rst_busy),
.rd_rst_busy(fifo_ft_rd_rst_busy)
);
// 書き込み側のクロックを生成 (100MHz)
always begin
fifo_wr_clk <= 1'b0;
fifo_ft_wr_clk <= 1'b0;
#5;
fifo_wr_clk <= 1'b1;
fifo_ft_wr_clk <= 1'b1;
#5;
end
// 読み出し側のクロックを生成 (33MHz)
always begin
fifo_rd_clk <= 1'b0;
fifo_ft_rd_clk <= 1'b0;
#15;
fifo_rd_clk <= 1'b1;
fifo_ft_rd_clk <= 1'b1;
#15;
end
// リセット制御
initial begin
fifo_rst <= 1'b1; // リセット
fifo_ft_rst <= 1'b1;
#40; // 40ns間 リセットを保持
fifo_rst <= 1'b0; // リセット解除
fifo_ft_rst <= 1'b0;
end
integer i;
logic [7:0] d;
initial begin
fifo_din <= 8'h00;
fifo_wr_en <= 1'b0;
fifo_ft_din <= 8'h00;
fifo_ft_wr_en <= 1'b0;
d <= 8'h61;
#473; // リセット解除を適当に待つ.本来なら fifo_wr_rst_busy を見るべき.
// 2048回 'a'から'z'をFIFOに書き込む
for (i = 0; i < 2048; i = i + 1) begin
// fifo_generator_0用
fifo_din <= d;
fifo_wr_en <= 1'b1;
// fifo_generator_0_ft用(同じデータを同じタイミングで書く)
fifo_ft_din <= d;
fifo_ft_wr_en <= 1'b1;
d <= d == 8'h7a ? 8'h61 : d + 1; // 'a'〜'z'を用意
#10; // 10n秒待って,次の書き込みを実行
end
fifo_wr_en <= 1'b0;
fifo_ft_wr_en <= 1'b0;
#1000;
$finish;
end
integer j;
initial begin
fifo_rd_en <= 1'b0;
fifo_ft_rd_en <= 1'b0;
d <= 8'h61;
#723; // リセット解除を適当に待つ.本来なら fifo_rd_rst_busy を見るべき.
// 1024回 FIFOからデータを読見出す
for (j = 0; j < 1024; j = j + 1) begin
fifo_rd_en <= 1'b1;
fifo_ft_rd_en <= 1'b1;
#30; // 30n秒待って,次の読み出しを実行
end
fifo_rd_en <= 1'b0;
fifo_ft_rd_en <= 1'b0;
end
endmodule // fifo_tb
`default_nettype wire
module serial_send (
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};
BUSY = 1'b1; // WEを受け取った直後にBUSYをたてたいので、ここでフラグを立てる
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 // serial_send
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment