Last active
May 29, 2020 07:50
-
-
Save miyo/c13277ac7140f7d39a5c7ad5cf6c21b0 to your computer and use it in GitHub Desktop.
ACRiブログ "FPGA をもっと活用するために IP コアを使ってみよう (5)" のコードスニペット
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
`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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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