mirror of
https://github.com/retroSoC/uart.git
synced 2026-11-04 22:32:39 +00:00
238 lines
7.7 KiB
Systemverilog
238 lines
7.7 KiB
Systemverilog
// Copyright 2017 ETH Zurich and University of Bologna.
|
|
// Copyright and related rights are licensed under the Solderpad Hardware
|
|
// License, Version 0.51 (the “License”); you may not use this file except in
|
|
// compliance with the License. You may obtain a copy of the License at
|
|
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
|
// or agreed to in writing, software, hardware and materials distributed under
|
|
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
|
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations under the License.
|
|
//
|
|
// -- Adaptable modifications are redistributed under compatible License --
|
|
//
|
|
// Copyright (c) 2023-2024 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
|
// uart is licensed under Mulan PSL v2.
|
|
// You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
// You may obtain a copy of Mulan PSL v2 at:
|
|
// http://license.coscl.org.cn/MulanPSL2
|
|
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
// See the Mulan PSL v2 for more details.
|
|
|
|
`include "uart_define.svh"
|
|
|
|
module apb4_uart #(
|
|
parameter int FIFO_DEPTH = 32,
|
|
parameter int LOG_FIFO_DEPTH = $clog2(FIFO_DEPTH)
|
|
) (
|
|
apb4_if.slave apb4,
|
|
uart_if.dut uart
|
|
);
|
|
|
|
logic [3:0] s_apb4_addr;
|
|
logic s_apb4_wr_hdshk, s_apb4_rd_hdshk;
|
|
logic [`UART_LCR_WIDTH-1:0] s_uart_lcr_d, s_uart_lcr_q;
|
|
logic s_uart_lcr_en;
|
|
logic [`UART_DIV_WIDTH-1:0] s_uart_div_d, s_uart_div_q;
|
|
logic s_uart_div_en;
|
|
logic [`UART_FCR_WIDTH-1:0] s_uart_fcr_d, s_uart_fcr_q;
|
|
logic s_uart_fcr_en;
|
|
logic [`UART_LSR_WIDTH-1:0] s_uart_lsr_d, s_uart_lsr_q;
|
|
logic s_bit_stb, s_bit_pen, s_bit_rf_clr, s_bit_tf_clr;
|
|
logic s_bit_pe, s_bit_thre;
|
|
logic [1:0] s_bit_wls, s_bit_ps, s_bit_rx_trg_levl;
|
|
logic [2:0] s_bit_ie;
|
|
logic s_clr_int, s_parity_err;
|
|
logic s_tx_push_valid, s_tx_push_ready, s_tx_empty, s_tx_full;
|
|
logic s_tx_pop_valid, s_tx_pop_ready;
|
|
logic s_rx_push_valid, s_rx_push_ready, s_rx_empty, s_rx_full;
|
|
logic s_rx_pop_valid, s_rx_pop_ready;
|
|
logic [2:0] s_lsr_ip;
|
|
logic [7:0] s_tx_push_data, s_tx_pop_data, s_rx_push_data;
|
|
logic [8:0] s_rx_pop_data;
|
|
logic [LOG_FIFO_DEPTH:0] s_tx_elem, s_rx_elem;
|
|
|
|
assign s_apb4_addr = apb4.paddr[5:2];
|
|
assign s_apb4_wr_hdshk = apb4.psel && apb4.penable && apb4.pwrite;
|
|
assign s_apb4_rd_hdshk = apb4.psel && apb4.penable && (~apb4.pwrite);
|
|
assign apb4.pready = 1'b1;
|
|
assign apb4.pslverr = 1'b0;
|
|
|
|
assign s_bit_ie = s_uart_lcr_q[2:0];
|
|
assign s_bit_wls = s_uart_lcr_q[4:3];
|
|
assign s_bit_stb = s_uart_lcr_q[5];
|
|
assign s_bit_pen = s_uart_lcr_q[6];
|
|
assign s_bit_ps = s_uart_lcr_q[8:7];
|
|
|
|
assign s_bit_rf_clr = s_uart_fcr_q[0];
|
|
assign s_bit_tf_clr = s_uart_fcr_q[1];
|
|
assign s_bit_rx_trg_levl = s_uart_fcr_q[3:2];
|
|
|
|
assign s_bit_pe = s_uart_lsr_q[4];
|
|
assign s_bit_thre = s_uart_lsr_q[5];
|
|
|
|
assign s_uart_lcr_en = s_apb4_wr_hdshk && s_apb4_addr == `UART_LCR;
|
|
assign s_uart_lcr_d = apb4.pwdata[`UART_LCR_WIDTH-1:0];
|
|
dffer #(`UART_LCR_WIDTH) u_uart_lcr_dffer (
|
|
apb4.pclk,
|
|
apb4.presetn,
|
|
s_uart_lcr_en,
|
|
s_uart_lcr_d,
|
|
s_uart_lcr_q
|
|
);
|
|
|
|
assign s_uart_div_en = s_apb4_wr_hdshk && s_apb4_addr == `UART_DIV;
|
|
assign s_uart_div_d = apb4.pwdata[`UART_DIV_WIDTH-1:0];
|
|
dfferc #(`UART_DIV_WIDTH, `UART_DIV_MIN_VAL) u_uart_div_dfferc (
|
|
apb4.pclk,
|
|
apb4.presetn,
|
|
s_uart_div_en,
|
|
s_uart_div_d,
|
|
s_uart_div_q
|
|
);
|
|
|
|
always_comb begin
|
|
s_tx_push_valid = 1'b0;
|
|
s_tx_push_data = '0;
|
|
if (s_apb4_wr_hdshk && s_apb4_addr == `UART_TRX) begin
|
|
s_tx_push_valid = 1'b1;
|
|
s_tx_push_data = apb4.pwdata[`UART_TRX_WIDTH-1:0];
|
|
end
|
|
end
|
|
|
|
assign s_uart_fcr_en = s_apb4_wr_hdshk && s_apb4_addr == `UART_FCR;
|
|
assign s_uart_fcr_d = apb4.pwdata[`UART_FCR_WIDTH-1:0];
|
|
dffer #(`UART_FCR_WIDTH) u_uart_fcr_dffer (
|
|
apb4.pclk,
|
|
apb4.presetn,
|
|
s_uart_fcr_en,
|
|
s_uart_fcr_d,
|
|
s_uart_fcr_q
|
|
);
|
|
|
|
always_comb begin
|
|
s_uart_lsr_d[2:0] = s_lsr_ip;
|
|
s_uart_lsr_d[3] = s_rx_pop_valid;
|
|
s_uart_lsr_d[4] = s_rx_pop_data[8];
|
|
s_uart_lsr_d[5] = ~(|s_tx_elem);
|
|
s_uart_lsr_d[6] = s_tx_pop_ready & ~(|s_tx_elem);
|
|
s_uart_lsr_d[7] = s_rx_empty;
|
|
s_uart_lsr_d[8] = s_tx_full;
|
|
end
|
|
dffrc #(`UART_LSR_WIDTH, `UART_LSR_RESET_VAL) u_uart_lsr_dffrc (
|
|
apb4.pclk,
|
|
apb4.presetn,
|
|
s_uart_lsr_d,
|
|
s_uart_lsr_q
|
|
);
|
|
|
|
always_comb begin
|
|
apb4.prdata = '0;
|
|
s_rx_pop_ready = 1'b0;
|
|
s_clr_int = 1'b0;
|
|
if (s_apb4_rd_hdshk) begin
|
|
unique case (s_apb4_addr)
|
|
`UART_LCR: apb4.prdata[`UART_LCR_WIDTH-1:0] = s_uart_lcr_q;
|
|
`UART_DIV: apb4.prdata[`UART_DIV_WIDTH-1:0] = s_uart_div_q;
|
|
`UART_TRX: begin
|
|
s_rx_pop_ready = 1'b1;
|
|
apb4.prdata[`UART_TRX_WIDTH-1:0] = s_rx_pop_data[7:0];
|
|
end
|
|
`UART_LSR: begin
|
|
s_clr_int = 1'b1;
|
|
apb4.prdata[`UART_LSR_WIDTH-1:0] = s_uart_lsr_q;
|
|
end
|
|
default: apb4.prdata = '0;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
assign s_tx_push_ready = ~s_tx_full;
|
|
assign s_tx_pop_valid = ~s_tx_empty;
|
|
fifo #(
|
|
.DATA_WIDTH (8),
|
|
.BUFFER_DEPTH(FIFO_DEPTH)
|
|
) u_tx_fifo (
|
|
.clk_i (apb4.pclk),
|
|
.rst_n_i(apb4.presetn),
|
|
.flush_i(s_bit_tf_clr),
|
|
.cnt_o (s_tx_elem),
|
|
.push_i (s_tx_push_valid),
|
|
.full_o (s_tx_full),
|
|
.dat_i (s_tx_push_data),
|
|
.pop_i (s_tx_pop_ready),
|
|
.empty_o(s_tx_empty),
|
|
.dat_o (s_tx_pop_data)
|
|
);
|
|
|
|
uart_tx u_uart_tx (
|
|
.clk_i (apb4.pclk),
|
|
.rst_n_i (apb4.presetn),
|
|
.tx_o (uart.uart_tx_o),
|
|
.busy_o (),
|
|
.cfg_en_i (1'b1),
|
|
.cfg_div_i (s_uart_div_q[`UART_DIV_WIDTH-1:0]),
|
|
.cfg_parity_en_i (s_bit_pen),
|
|
.cfg_parity_sel_i(s_bit_ps),
|
|
.cfg_bits_i (s_bit_wls),
|
|
.cfg_stop_bits_i (s_bit_stb),
|
|
.tx_data_i (s_tx_pop_data),
|
|
.tx_valid_i (s_tx_pop_valid),
|
|
.tx_ready_o (s_tx_pop_ready)
|
|
);
|
|
|
|
assign s_rx_push_ready = ~s_rx_full;
|
|
assign s_rx_pop_valid = ~s_rx_empty;
|
|
fifo #(
|
|
.DATA_WIDTH (9),
|
|
.BUFFER_DEPTH(FIFO_DEPTH)
|
|
) u_rx_fifo (
|
|
.clk_i (apb4.pclk),
|
|
.rst_n_i(apb4.presetn),
|
|
.flush_i(s_bit_rf_clr),
|
|
.cnt_o (s_rx_elem),
|
|
.push_i (s_rx_push_valid),
|
|
.full_o (s_rx_full),
|
|
.dat_i ({s_parity_err, s_rx_push_data}),
|
|
.pop_i (s_rx_pop_ready),
|
|
.empty_o(s_rx_empty),
|
|
.dat_o (s_rx_pop_data)
|
|
);
|
|
|
|
uart_rx u_uart_rx (
|
|
.clk_i (apb4.pclk),
|
|
.rst_n_i (apb4.presetn),
|
|
.rx_i (uart.uart_rx_i),
|
|
.busy_o (),
|
|
.cfg_en_i (1'b1),
|
|
.cfg_div_i (s_uart_div_q[`UART_DIV_WIDTH-1:0]),
|
|
.cfg_parity_en_i (s_bit_pen),
|
|
.cfg_parity_sel_i(s_bit_ps),
|
|
.cfg_bits_i (s_bit_wls),
|
|
.err_o (s_parity_err),
|
|
.err_clr_i (1'b1),
|
|
.rx_data_o (s_rx_push_data),
|
|
.rx_valid_o (s_rx_push_valid),
|
|
.rx_ready_i (s_rx_push_ready)
|
|
);
|
|
|
|
uart_irq #(
|
|
.FIFO_DEPTH(FIFO_DEPTH)
|
|
) u_uart_irq (
|
|
.clk_i (apb4.pclk),
|
|
.rst_n_i (apb4.presetn),
|
|
.clr_int_i (s_clr_int),
|
|
.irq_en_i (s_bit_ie),
|
|
.thre_i (s_bit_thre),
|
|
.cti_i (1'b0),
|
|
.pe_i (s_bit_pe),
|
|
.rx_elem_i (s_rx_elem),
|
|
.tx_elem_i (s_tx_elem),
|
|
.trg_level_i(s_bit_rx_trg_levl),
|
|
.ip_o (s_lsr_ip),
|
|
.irq_o (uart.irq_o)
|
|
);
|
|
endmodule
|
|
|