Files
uart/rtl/apb4_uart.sv
T

225 lines
7.3 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 Beijing Institute of Open Source Chip
// 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 "register.sv"
`include "fifo.sv"
`include "uart_define.sv"
module apb4_uart #(
parameter int FIFO_DEPTH = 64,
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 [1:0] s_bit_wls, s_bit_ps, s_bit_rx_trg_levl;
logic s_clr_int, s_parity_err;
logic s_tx_push_valid, s_tx_push_ready, s_tx_pop_valid, s_tx_pop_ready;
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_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_uart_lcr_en = s_apb4_wr_hdshk && s_apb4_addr == `UART_LCR;
assign s_uart_lcr_d = s_uart_lcr_en ? apb4.pwdata[`UART_LCR_WIDTH-1:0] : s_uart_lcr_q;
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 = s_uart_div_en ? apb4.pwdata[`UART_DIV_WIDTH-1:0] : s_uart_div_q;
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;
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 = s_uart_fcr_en ? apb4.pwdata[`UART_FCR_WIDTH-1:0] : s_uart_fcr_q;
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);
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
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 (),
.dat_i (s_tx_push_data),
.pop_i (s_tx_pop_ready),
.empty_o(s_tx_pop_valid),
.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)
);
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_push_ready),
.dat_i ({s_parity_err, s_rx_push_data}),
.pop_i (s_rx_pop_ready),
.empty_o(s_rx_pop_valid),
.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_uart_lcr_q[2:0]),
.thre_i (s_uart_lsr_q[5]),
.cti_i (1'b0),
.pe_i (s_uart_lsr_q[4]),
.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