USTC-RVSoC/RTL/user_uart_tx.sv
2019-02-05 16:19:46 +08:00

100 lines
2.8 KiB
Systemverilog

module user_uart_tx #(
parameter UART_TX_CLK_DIV = 434 // 50MHz/1/115200Hz=434
)(
input logic clk, rst_n,
output logic o_uart_tx,
naive_bus.slave bus
);
localparam TX_CNT = 5'd19;
logic [ 7:0] fifo_rd_pointer=8'h0, fifo_wr_pointer=8'h0, fifo_len;
logic fifo_full, fifo_empty;
logic rd_addr_valid, wr_addr_valid;
logic [31:0] cnt = 0;
logic [ 4:0] tx_cnt = 0;
logic [ 7:0] tx_shift = 8'h0;
logic [ 7:0] fifo_rd_data;
initial o_uart_tx = 1'b1;
assign rd_addr_valid = (bus.rd_addr[31:2] == 30'h0);
assign wr_addr_valid = (bus.wr_addr[31:2] == 30'h0);
assign fifo_len = fifo_wr_pointer - fifo_rd_pointer;
assign fifo_empty = (fifo_len==8'h00);
assign fifo_full = (fifo_len==8'hff);
assign bus.rd_gnt = bus.rd_req;
always @ (posedge clk or negedge rst_n)
if(~rst_n)
bus.rd_data <= 0;
else begin
if(bus.rd_req & rd_addr_valid)
bus.rd_data <= {24'h0, fifo_len};
else
bus.rd_data <= 0;
end
always_comb
if(bus.wr_req) begin
if(wr_addr_valid && bus.wr_be[0]) begin
bus.wr_gnt <= ~fifo_full;
end else begin
bus.wr_gnt <= 1'b1;
end
end else begin
bus.wr_gnt <= 1'b0;
end
always @ (posedge clk or negedge rst_n)
if(~rst_n) begin
fifo_wr_pointer <= 8'h0;
end else begin
if(bus.wr_req & wr_addr_valid & bus.wr_be[0] & ~fifo_full) begin
fifo_wr_pointer <= fifo_wr_pointer + 8'h1;
end
end
always @ (posedge clk or negedge rst_n)
if(~rst_n)
cnt <= 0;
else
cnt <= (cnt<UART_TX_CLK_DIV-1) ? cnt+1 : 0;
always @ (posedge clk or negedge rst_n)
if(~rst_n) begin
fifo_rd_pointer <= 8'h0;
o_uart_tx <= 1'b1;
tx_shift <= 8'hff;
tx_cnt <= 5'h0;
end else begin
if(tx_cnt>5'd0) begin
if(cnt==0) begin
if(tx_cnt==TX_CNT) begin
{tx_shift, o_uart_tx} <= {fifo_rd_data, 1'b0};
fifo_rd_pointer <= fifo_rd_pointer + 8'h1;
end else begin
{tx_shift, o_uart_tx} <= {1'b1, tx_shift};
end
tx_cnt <= tx_cnt - 5'd1;
end
end else begin
o_uart_tx <= 1'b1;
tx_cnt <= fifo_empty ? 5'd0 : TX_CNT;
end
end
ram ram_for_uart_tx_fifo_inst(
.clk ( clk ),
.rst_n ( rst_n ),
.i_we ( bus.wr_req & wr_addr_valid & bus.wr_be[0] & ~fifo_full ),
.i_waddr ( {2'h0,fifo_wr_pointer} ),
.i_wdata ( bus.wr_data[7:0] ),
.i_raddr ( {2'h0,fifo_rd_pointer} ),
.o_rdata ( fifo_rd_data )
);
endmodule