| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- module uart_regs #(parameter CNT = 5, DATA_WIDTH = 8) (
- input apb_clock,
- input apb_resetn,
- input apb_psel,
- input apb_penable,
- input apb_pwrite,
- input [11:0] apb_paddr,
- input [31:0] apb_pwdata,
- output reg [31:0] apb_prdata,
- output reg apb_pready,
- output reg uart_en,
- output reg [15:0] ibrd,
- output reg [5:0] fbrd,
- output reg [CNT-1:0] tx_write,
- output reg [CNT-1:0] rx_read,
- input [DATA_WIDTH*CNT-1:0] rx_data,
- input [CNT-1:0] tx_full,
- input [CNT-1:0] tx_empty,
- input [CNT-1:0] tx_busy,
- input [CNT-1:0] tx_complete,
- input [CNT-1:0] rx_full,
- input [CNT-1:0] rx_empty,
- input [CNT-1:0] rx_idle,
- input [CNT-1:0] framing_error,
- input [CNT-1:0] parity_error,
- input [CNT-1:0] break_error,
- input [CNT-1:0] overrun_error,
- output [CNT-1:0] clear_flags,
- output reg lcr_sps, // Stick parity select
- output reg lcr_stp2, // 2 stop bits select
- output reg lcr_eps, // Even parity select
- output reg lcr_pen, // Parity enable
- output reg [CNT-1:0] rx_dma_en,
- output reg [CNT-1:0] tx_dma_en,
- output reg [CNT-1:0] interrupts
- );
- parameter ADDR_DR = (8'h00 >> 2); // Data
- parameter ADDR_SR = (8'h04 >> 2); // Status register/error clear register
- parameter ADDR_FR = (8'h18 >> 2); // Flag register
- parameter ADDR_IBRD = (8'h24 >> 2); // Integer baud rate divisor
- parameter ADDR_FBRD = (8'h28 >> 2); // Fractional baud rate divisor
- parameter ADDR_LCR = (8'h2c >> 2); // Line control
- parameter ADDR_CR = (8'h30 >> 2); // Control
- parameter ADDR_IE = (8'h38 >> 2); // Interrupt enable
- parameter ADDR_IC = (8'h44 >> 2); // Interrupt clear
- parameter ADDR_DMACR = (8'h48 >> 2); // DMA control register
- parameter CNT_BITS = $clog2(CNT);
- reg [CNT-1:0] rx_not_empty_ie;
- reg [CNT-1:0] tx_not_full_ie;
- reg [CNT-1:0] tx_complete_ie;
- reg [CNT-1:0] rx_idle_ie;
- reg [CNT-1:0] framing_error_ie;
- reg [CNT-1:0] parity_error_ie;
- reg [CNT-1:0] break_error_ie;
- reg [CNT-1:0] overrun_error_ie;
- reg [DATA_WIDTH-1:0] rx_reg;
- reg [4:0] status_reg;
- wire [5:0] reg_addr = apb_paddr[7:2];
- wire [CNT_BITS-1:0] uart_idx = apb_paddr[8+:CNT_BITS];
- wire apb_write = (apb_psel && !apb_penable && apb_pwrite);
- wire apb_read0 = (apb_psel && !apb_penable && !apb_pwrite);
- wire apb_read1 = (apb_psel && apb_penable && !apb_pwrite);
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- apb_pready <= 1'b1;
- end else begin
- apb_pready <= !apb_read0;
- end
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- ibrd <= 16'h0;
- end else if (apb_write && reg_addr == ADDR_IBRD) begin
- ibrd <= apb_pwdata[15:0];
- end
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- fbrd <= 16'h0;
- end else if (apb_write && reg_addr == ADDR_FBRD) begin
- fbrd <= apb_pwdata[5:0];
- end
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- tx_write <= {CNT{1'b0}};
- end else if (apb_write && reg_addr == ADDR_DR) begin
- tx_write <= (1'b1 << uart_idx);
- end else begin
- tx_write <= {CNT{1'b0}};
- end
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- rx_read <= {CNT{1'b0}};
- end else if (apb_read0 && reg_addr == ADDR_DR) begin
- rx_read <= (1'b1 << uart_idx);
- end else begin
- rx_read <= {CNT{1'b0}};
- end
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- lcr_sps <= 1'b0;
- lcr_stp2 <= 1'b0;
- lcr_eps <= 1'b0;
- lcr_pen <= 1'b0;
- end else if (apb_write && reg_addr == ADDR_LCR) begin
- lcr_sps <= apb_pwdata[7];
- lcr_stp2 <= apb_pwdata[3];
- lcr_eps <= apb_pwdata[2];
- lcr_pen <= apb_pwdata[1];
- end
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- uart_en <= 1'b0;
- end else if (apb_write && reg_addr == ADDR_CR) begin
- uart_en <= apb_pwdata[0];
- end
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- rx_not_empty_ie <= 0;
- tx_not_full_ie <= 0;
- tx_complete_ie <= 0;
- rx_idle_ie <= 0;
- framing_error_ie <= 0;
- parity_error_ie <= 0;
- break_error_ie <= 0;
- overrun_error_ie <= 0;
- end else if (apb_write && reg_addr == ADDR_IE) begin
- rx_not_empty_ie [uart_idx] <= apb_pwdata[4];
- tx_not_full_ie [uart_idx] <= apb_pwdata[5];
- framing_error_ie[uart_idx] <= apb_pwdata[7];
- parity_error_ie [uart_idx] <= apb_pwdata[8];
- break_error_ie [uart_idx] <= apb_pwdata[9];
- overrun_error_ie[uart_idx] <= apb_pwdata[10];
- rx_idle_ie [uart_idx] <= apb_pwdata[11];
- tx_complete_ie [uart_idx] <= apb_pwdata[12];
- end
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- rx_dma_en <= 0;
- tx_dma_en <= 0;
- end else if (apb_write && reg_addr == ADDR_DMACR) begin
- rx_dma_en[uart_idx] <= apb_pwdata[0];
- tx_dma_en[uart_idx] <= apb_pwdata[1];
- end
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- interrupts <= {CNT{1'b0}};
- end else begin
- interrupts <=
- (rx_not_empty_ie & (~rx_empty) ) |
- (tx_not_full_ie & (~tx_full) ) |
- (framing_error_ie & framing_error ) |
- (parity_error_ie & parity_error ) |
- (break_error_ie & break_error ) |
- (overrun_error_ie & overrun_error ) |
- (rx_idle_ie & rx_idle ) |
- (tx_complete_ie & tx_complete );
- end
- end
- always @(posedge apb_clock) begin
- rx_reg <= rx_data[uart_idx*DATA_WIDTH+:DATA_WIDTH];
- status_reg <= { tx_empty[uart_idx], rx_full[uart_idx], tx_full[uart_idx], rx_empty[uart_idx], tx_busy[uart_idx] };
- end
- always @(posedge apb_clock or negedge apb_resetn) begin
- if (!apb_resetn) begin
- apb_prdata <= 0;
- end else if (apb_read1) begin
- case (reg_addr)
- ADDR_DR: apb_prdata <= { {32-DATA_WIDTH{1'b0}}, rx_reg };
- ADDR_SR: apb_prdata <= { 26'h0, tx_complete[uart_idx], rx_idle[uart_idx], overrun_error[uart_idx], break_error[uart_idx], parity_error[uart_idx], framing_error[uart_idx] };
- ADDR_FR: apb_prdata <= { 24'h0, status_reg, 3'b0 };
- ADDR_IBRD: apb_prdata <= { 16'h0, ibrd };
- ADDR_FBRD: apb_prdata <= { 26'h0, fbrd };
- ADDR_LCR: apb_prdata <= { 24'b0, lcr_sps, 3'b0, lcr_stp2, lcr_eps, lcr_pen, 1'b0 };
- ADDR_CR: apb_prdata <= { 31'b0, uart_en };
- ADDR_IE: apb_prdata <= { 19'h0, tx_complete_ie[uart_idx], rx_idle_ie[uart_idx], overrun_error_ie[uart_idx], break_error_ie[uart_idx], parity_error_ie[uart_idx], framing_error_ie[uart_idx], 1'b0, tx_not_full_ie[uart_idx], rx_not_empty_ie[uart_idx], 4'h0 };
- ADDR_DMACR: apb_prdata <= { 30'h0, tx_dma_en[uart_idx], rx_dma_en[uart_idx] };
- default: apb_prdata <= 32'h0;
- endcase
- end
- end
- // A simplified approach. Any write to either SR or IC will clear all the errors and interrupts.
- assign clear_flags = (apb_write && (reg_addr == ADDR_SR || reg_addr == ADDR_IC)) ? (1'b1 << uart_idx) : 0;
- endmodule
|