blob: 99690810d8ddfcf3074608479ce24d1290753398 [file] [log] [blame]
module apb_uart_sv
#(
parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default
)
(
CLK,
RSTN,
PADDR,
PWDATA,
PWRITE,
PSEL,
PENABLE,
PRDATA,
PREADY,
PSLVERR,
rx_i,
tx_o,
event_o
);
//parameter APB_ADDR_WIDTH = 12;
input wire CLK;
input wire RSTN;
input wire [APB_ADDR_WIDTH - 1:0] PADDR;
input wire [31:0] PWDATA;
input wire PWRITE;
input wire PSEL;
input wire PENABLE;
output reg [31:0] PRDATA;
output wire PREADY;
output wire PSLVERR;
input wire rx_i;
output wire tx_o;
output wire event_o;
parameter RBR = 3'h0;
parameter THR = 3'h0;
parameter DLL = 3'h0;
parameter IER = 3'h1;
parameter DLM = 3'h1;
parameter IIR = 3'h2;
parameter FCR = 3'h2;
parameter LCR = 3'h3;
parameter MCR = 3'h4;
parameter LSR = 3'h5;
parameter MSR = 3'h6;
parameter SCR = 3'h7;
parameter TX_FIFO_DEPTH = 16;
parameter RX_FIFO_DEPTH = 16;
wire [2:0] register_adr;
reg [79:0] regs_q;
reg [79:0] regs_n;
reg [1:0] trigger_level_n;
reg [1:0] trigger_level_q;
wire [7:0] rx_data;
wire parity_error;
wire [3:0] IIR_o;
reg [3:0] clr_int;
wire tx_ready;
reg apb_rx_ready;
wire rx_valid;
reg tx_fifo_clr_n;
reg tx_fifo_clr_q;
reg rx_fifo_clr_n;
reg rx_fifo_clr_q;
reg fifo_tx_valid;
wire tx_valid;
wire fifo_rx_valid;
reg fifo_rx_ready;
wire rx_ready;
reg [7:0] fifo_tx_data;
wire [8:0] fifo_rx_data;
wire [7:0] tx_data;
wire [$clog2(TX_FIFO_DEPTH):0] tx_elements;
wire [$clog2(RX_FIFO_DEPTH):0] rx_elements;
uart_rx uart_rx_i(
.clk_i(CLK),
.rstn_i(RSTN),
.rx_i(rx_i),
.cfg_en_i(1'b1),
.cfg_div_i({regs_q[(DLM + 'd8) * 8+:8], regs_q[(DLL + 'd8) * 8+:8]}),
.cfg_parity_en_i(regs_q[(LCR * 8) + 3]),
.cfg_bits_i(regs_q[(LCR * 8) + 1-:2]),
.busy_o(),
.err_o(parity_error),
.err_clr_i(1'b1),
.rx_data_o(rx_data),
.rx_valid_o(rx_valid),
.rx_ready_i(rx_ready)
);
uart_tx uart_tx_i(
.clk_i(CLK),
.rstn_i(RSTN),
.tx_o(tx_o),
.busy_o(),
.cfg_en_i(1'b1),
.cfg_div_i({regs_q[(DLM + 'd8) * 8+:8], regs_q[(DLL + 'd8) * 8+:8]}),
.cfg_parity_en_i(regs_q[(LCR * 8) + 3]),
.cfg_bits_i(regs_q[(LCR * 8) + 1-:2]),
.cfg_stop_bits_i(regs_q[(LCR * 8) + 2]),
.tx_data_i(tx_data),
.tx_valid_i(tx_valid),
.tx_ready_o(tx_ready)
);
io_generic_fifo #(
.DATA_WIDTH(9),
.BUFFER_DEPTH(RX_FIFO_DEPTH)
) uart_rx_fifo_i(
.clk_i(CLK),
.rstn_i(RSTN),
.clr_i(rx_fifo_clr_q),
.elements_o(rx_elements),
.data_o(fifo_rx_data),
.valid_o(fifo_rx_valid),
.ready_i(fifo_rx_ready),
.valid_i(rx_valid),
.data_i({parity_error, rx_data}),
.ready_o(rx_ready)
);
io_generic_fifo #(
.DATA_WIDTH(8),
.BUFFER_DEPTH(TX_FIFO_DEPTH)
) uart_tx_fifo_i(
.clk_i(CLK),
.rstn_i(RSTN),
.clr_i(tx_fifo_clr_q),
.elements_o(tx_elements),
.data_o(tx_data),
.valid_o(tx_valid),
.ready_i(tx_ready),
.valid_i(fifo_tx_valid),
.data_i(fifo_tx_data),
.ready_o()
);
uart_interrupt #(
.TX_FIFO_DEPTH(TX_FIFO_DEPTH),
.RX_FIFO_DEPTH(RX_FIFO_DEPTH)
) uart_interrupt_i(
.clk_i(CLK),
.rstn_i(RSTN),
.IER_i(regs_q[(IER * 8) + 2-:3]),
.RDA_i(regs_n[(LSR * 8) + 5]),
.CTI_i(1'b0),
.error_i(regs_n[(LSR * 8) + 2]),
.rx_elements_i(rx_elements),
.tx_elements_i(tx_elements),
.trigger_level_i(trigger_level_q),
.clr_int_i(clr_int),
.interrupt_o(event_o),
.IIR_o(IIR_o)
);
always @(*) begin
regs_n = regs_q;
trigger_level_n = trigger_level_q;
fifo_tx_valid = 1'b0;
tx_fifo_clr_n = 1'b0;
rx_fifo_clr_n = 1'b0;
regs_n[LSR * 8] = fifo_rx_valid;
regs_n[(LSR * 8) + 2] = fifo_rx_data[8];
regs_n[(LSR * 8) + 5] = ~(|tx_elements);
regs_n[(LSR * 8) + 6] = tx_ready & ~(|tx_elements);
if ((PSEL && PENABLE) && PWRITE)
case (register_adr)
THR:
if (regs_q[(LCR * 8) + 7])
regs_n[(DLL + 'd8) * 8+:8] = PWDATA[7:0];
else begin
fifo_tx_data = PWDATA[7:0];
fifo_tx_valid = 1'b1;
end
IER:
if (regs_q[(LCR * 8) + 7])
regs_n[(DLM + 'd8) * 8+:8] = PWDATA[7:0];
else
regs_n[IER * 8+:8] = PWDATA[7:0];
LCR: regs_n[LCR * 8+:8] = PWDATA[7:0];
FCR: begin
rx_fifo_clr_n = PWDATA[1];
tx_fifo_clr_n = PWDATA[2];
trigger_level_n = PWDATA[7:6];
end
default:
;
endcase
end
always @(*) begin
PRDATA = 'b0;
apb_rx_ready = 1'b0;
fifo_rx_ready = 1'b0;
clr_int = 4'b0000;
if ((PSEL && PENABLE) && !PWRITE)
case (register_adr)
RBR:
if (regs_q[(LCR * 8) + 7])
PRDATA = {24'b000000000000000000000000, regs_q[(DLL + 'd8) * 8+:8]};
else begin
fifo_rx_ready = 1'b1;
PRDATA = {24'b000000000000000000000000, fifo_rx_data[7:0]};
clr_int = 4'b1000;
end
LSR: begin
PRDATA = {24'b000000000000000000000000, regs_q[LSR * 8+:8]};
clr_int = 4'b1100;
end
LCR: PRDATA = {24'b000000000000000000000000, regs_q[LCR * 8+:8]};
IER:
if (regs_q[(LCR * 8) + 7])
PRDATA = {24'b000000000000000000000000, regs_q[(DLM + 'd8) * 8+:8]};
else
PRDATA = {24'b000000000000000000000000, regs_q[IER * 8+:8]};
IIR: begin
PRDATA = {28'b0000000000000000000000001100, IIR_o};
clr_int = 4'b0100;
end
default:
;
endcase
end
always @(posedge CLK or negedge RSTN)
if (~RSTN) begin
regs_q[IER * 8+:8] <= 8'h00;
regs_q[IIR * 8+:8] <= 8'h01;
regs_q[LCR * 8+:8] <= 8'h00;
regs_q[MCR * 8+:8] <= 8'h00;
regs_q[LSR * 8+:8] <= 8'h60;
regs_q[MSR * 8+:8] <= 8'h00;
regs_q[SCR * 8+:8] <= 8'h00;
regs_q[(DLM + 'd8) * 8+:8] <= 8'h00;
regs_q[(DLL + 'd8) * 8+:8] <= 8'h00;
trigger_level_q <= 2'b00;
tx_fifo_clr_q <= 1'b0;
rx_fifo_clr_q <= 1'b0;
end
else begin
regs_q <= regs_n;
trigger_level_q <= trigger_level_n;
tx_fifo_clr_q <= tx_fifo_clr_n;
rx_fifo_clr_q <= rx_fifo_clr_n;
end
assign register_adr = {PADDR[2:0]};
assign PREADY = 1'b1;
assign PSLVERR = 1'b0;
endmodule