├── src_files.yml ├── README.md ├── uart_interrupt.sv ├── io_generic_fifo.sv ├── uart_tx.sv ├── uart_rx.sv ├── LICENSE ├── apb_uart.sv └── apb_uart_sv.sv /src_files.yml: -------------------------------------------------------------------------------- 1 | apb_uart_sv: 2 | files: [ 3 | apb_uart_sv.sv, 4 | uart_rx.sv, 5 | uart_tx.sv, 6 | io_generic_fifo.sv, 7 | uart_interrupt.sv, 8 | ] 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # APB UART (SystemVerilog) 2 | 3 | This module implements the basic interface you would expect from a standard TI 16550 UART. It exists because of current incompatibility of Verilator to understand our VHDL based UART. This UART will likely vanish with the release of our uDMA based peripherals. -------------------------------------------------------------------------------- /uart_interrupt.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2017 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the “License”); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | module uart_interrupt 12 | #( 13 | parameter TX_FIFO_DEPTH = 32, 14 | parameter RX_FIFO_DEPTH = 32 15 | ) 16 | ( 17 | input logic clk_i, 18 | input logic rstn_i, 19 | 20 | // registers 21 | input logic [2:0] IER_i, // interrupt enable register 22 | input logic RDA_i, // receiver data available 23 | input logic CTI_i, // character timeout indication 24 | 25 | // control logic 26 | input logic error_i, 27 | input logic [$clog2(RX_FIFO_DEPTH):0] rx_elements_i, 28 | input logic [$clog2(TX_FIFO_DEPTH):0] tx_elements_i, 29 | input logic [1:0] trigger_level_i, 30 | 31 | input logic [3:0] clr_int_i, // one hot 32 | 33 | output logic interrupt_o, 34 | output logic [3:0] IIR_o 35 | ); 36 | 37 | logic [3:0] iir_n, iir_q; 38 | logic trigger_level_reached; 39 | 40 | always_comb 41 | begin 42 | trigger_level_reached = 1'b0; 43 | case (trigger_level_i) 44 | 2'b00: 45 | if ($unsigned(rx_elements_i) == 1) 46 | trigger_level_reached = 1'b1; 47 | 2'b01: 48 | if ($unsigned(rx_elements_i) == 4) 49 | trigger_level_reached = 1'b1; 50 | 2'b10: 51 | if ($unsigned(rx_elements_i) == 8) 52 | trigger_level_reached = 1'b1; 53 | 2'b11: 54 | if ($unsigned(rx_elements_i) == 14) 55 | trigger_level_reached = 1'b1; 56 | default : /* default */; 57 | endcase 58 | end 59 | 60 | always_comb 61 | begin 62 | 63 | if (clr_int_i == 4'b0) 64 | iir_n = iir_q; 65 | else 66 | iir_n = iir_q & ~(clr_int_i); 67 | 68 | // Receiver line status interrupt on: Overrun error, parity error, framing error or break interrupt 69 | if (IER_i[2] & error_i) 70 | iir_n = 4'b1100; 71 | // Received data available or trigger level reached in FIFO mode 72 | else if (IER_i[0] & (trigger_level_reached | RDA_i)) 73 | iir_n = 4'b1000; 74 | // Character timeout indication 75 | else if (IER_i[0] & CTI_i) 76 | iir_n = 4'b1000; 77 | // Transmitter holding register empty 78 | else if (IER_i[1] & tx_elements_i == 0) 79 | iir_n = 4'b0100; 80 | end 81 | 82 | 83 | always_ff @(posedge clk_i, negedge rstn_i) 84 | begin 85 | if (~rstn_i) 86 | begin 87 | iir_q <= 4'b0001; 88 | end 89 | else 90 | begin 91 | iir_q <= iir_n; 92 | end 93 | end 94 | 95 | assign IIR_o = iir_q; 96 | assign interrupt_o = ~iir_q[0]; 97 | 98 | endmodule 99 | 100 | -------------------------------------------------------------------------------- /io_generic_fifo.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2017 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the “License”); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | module io_generic_fifo 12 | #( 13 | parameter DATA_WIDTH = 32, 14 | parameter BUFFER_DEPTH = 2, 15 | parameter LOG_BUFFER_DEPTH = $clog2(BUFFER_DEPTH) 16 | ) 17 | ( 18 | input logic clk_i, 19 | input logic rstn_i, 20 | 21 | input logic clr_i, 22 | 23 | output logic [LOG_BUFFER_DEPTH:0] elements_o, 24 | 25 | output logic [DATA_WIDTH-1 : 0] data_o, 26 | output logic valid_o, 27 | input logic ready_i, 28 | 29 | input logic valid_i, 30 | input logic [DATA_WIDTH-1 : 0] data_i, 31 | output logic ready_o 32 | ); 33 | 34 | // Internal data structures 35 | /* verilator lint_off WIDTH */ 36 | logic [LOG_BUFFER_DEPTH-1:0] pointer_in; // location to which we last wrote 37 | logic [LOG_BUFFER_DEPTH-1:0] pointer_out; // location from which we last sent 38 | /* lint_off */ 39 | logic [LOG_BUFFER_DEPTH:0] elements; // number of elements in the buffer 40 | logic [DATA_WIDTH-1:0] buffer [BUFFER_DEPTH - 1 : 0]; 41 | 42 | logic full; 43 | 44 | int unsigned loop1; 45 | 46 | assign full = (elements == BUFFER_DEPTH); 47 | assign elements_o = elements; 48 | 49 | always_ff @(posedge clk_i, negedge rstn_i) 50 | begin: elements_sequential 51 | if (rstn_i == 1'b0) 52 | elements <= 0; 53 | else 54 | begin 55 | if (clr_i) 56 | elements <= 0; 57 | else 58 | begin 59 | // ------------------ 60 | // Are we filling up? 61 | // ------------------ 62 | // One out, none in 63 | if (ready_i && valid_o && (!valid_i || full)) 64 | elements <= elements - 1; 65 | // None out, one in 66 | else if ((!valid_o || !ready_i) && valid_i && !full) 67 | elements <= elements + 1; 68 | // Else, either one out and one in, or none out and none in - stays unchanged 69 | end 70 | end 71 | end 72 | 73 | always_ff @(posedge clk_i, negedge rstn_i) 74 | begin: buffers_sequential 75 | if (rstn_i == 1'b0) 76 | begin 77 | for (loop1 = 0 ; loop1 < BUFFER_DEPTH ; loop1 = loop1 + 1) 78 | buffer[loop1] <= 0; 79 | end 80 | else 81 | begin 82 | // Update the memory 83 | if (valid_i && !full) 84 | buffer[pointer_in] <= data_i; 85 | end 86 | end 87 | 88 | always_ff @(posedge clk_i, negedge rstn_i) 89 | begin: sequential 90 | if (rstn_i == 1'b0) 91 | begin 92 | pointer_out <= 0; 93 | pointer_in <= 0; 94 | end 95 | else 96 | begin 97 | if(clr_i) 98 | begin 99 | pointer_out <= 0; 100 | pointer_in <= 0; 101 | end 102 | else 103 | begin 104 | // ------------------------------------ 105 | // Check what to do with the input side 106 | // ------------------------------------ 107 | // We have some input, increase by 1 the input pointer 108 | if (valid_i && !full) 109 | begin 110 | if (pointer_in == $unsigned(BUFFER_DEPTH - 1)) 111 | pointer_in <= 0; 112 | else 113 | pointer_in <= pointer_in + 1; 114 | end 115 | // Else we don't have any input, the input pointer stays the same 116 | 117 | // ------------------------------------- 118 | // Check what to do with the output side 119 | // ------------------------------------- 120 | // We had pushed one flit out, we can try to go for the next one 121 | if (ready_i && valid_o) 122 | begin 123 | if (pointer_out == $unsigned(BUFFER_DEPTH - 1)) 124 | pointer_out <= 0; 125 | else 126 | pointer_out <= pointer_out + 1; 127 | end 128 | // Else stay on the same output location 129 | end 130 | end 131 | end 132 | 133 | // Update output ports 134 | assign data_o = buffer[pointer_out]; 135 | assign valid_o = (elements != 0); 136 | 137 | assign ready_o = ~full; 138 | 139 | endmodule -------------------------------------------------------------------------------- /uart_tx.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2017 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the “License”); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | module uart_tx ( 12 | input logic clk_i, 13 | input logic rstn_i, 14 | output logic tx_o, 15 | output logic busy_o, 16 | input logic cfg_en_i, 17 | input logic [15:0] cfg_div_i, 18 | input logic cfg_parity_en_i, 19 | input logic [1:0] cfg_bits_i, 20 | input logic cfg_stop_bits_i, 21 | input logic [7:0] tx_data_i, 22 | input logic tx_valid_i, 23 | output logic tx_ready_o 24 | ); 25 | 26 | enum logic [2:0] {IDLE,START_BIT,DATA,PARITY,STOP_BIT_FIRST,STOP_BIT_LAST} CS,NS; 27 | 28 | logic [7:0] reg_data; 29 | logic [7:0] reg_data_next; 30 | 31 | 32 | logic [2:0] reg_bit_count; 33 | logic [2:0] reg_bit_count_next; 34 | 35 | logic [2:0] s_target_bits; 36 | 37 | logic parity_bit; 38 | logic parity_bit_next; 39 | 40 | logic sampleData; 41 | 42 | logic [15:0] baud_cnt; 43 | logic baudgen_en; 44 | logic bit_done; 45 | 46 | assign busy_o = (CS != IDLE); 47 | 48 | always_comb 49 | begin 50 | case(cfg_bits_i) 51 | 2'b00: 52 | s_target_bits = 3'h4; 53 | 2'b01: 54 | s_target_bits = 3'h5; 55 | 2'b10: 56 | s_target_bits = 3'h6; 57 | 2'b11: 58 | s_target_bits = 3'h7; 59 | endcase 60 | end 61 | 62 | always_comb 63 | begin 64 | NS = CS; 65 | tx_o = 1'b1; 66 | sampleData = 1'b0; 67 | reg_bit_count_next = reg_bit_count; 68 | reg_data_next = {1'b1,reg_data[7:1]}; 69 | tx_ready_o = 1'b0; 70 | baudgen_en = 1'b0; 71 | parity_bit_next = parity_bit; 72 | case(CS) 73 | IDLE: 74 | begin 75 | if (cfg_en_i) 76 | tx_ready_o = 1'b1; 77 | if (tx_valid_i) 78 | begin 79 | NS = START_BIT; 80 | sampleData = 1'b1; 81 | reg_data_next = tx_data_i; 82 | end 83 | end 84 | 85 | START_BIT: 86 | begin 87 | tx_o = 1'b0; 88 | parity_bit_next = 1'b0; 89 | baudgen_en = 1'b1; 90 | if (bit_done) 91 | NS = DATA; 92 | end 93 | 94 | DATA: 95 | begin 96 | tx_o = reg_data[0]; 97 | baudgen_en = 1'b1; 98 | parity_bit_next = parity_bit ^ reg_data[0]; 99 | if (bit_done) 100 | begin 101 | if (reg_bit_count == s_target_bits) 102 | begin 103 | reg_bit_count_next = 'h0; 104 | if (cfg_parity_en_i) 105 | begin 106 | NS = PARITY; 107 | end 108 | else 109 | begin 110 | NS = STOP_BIT_FIRST; 111 | end 112 | end 113 | else 114 | begin 115 | reg_bit_count_next = reg_bit_count + 1; 116 | sampleData = 1'b1; 117 | end 118 | end 119 | end 120 | 121 | PARITY: 122 | begin 123 | tx_o = parity_bit; 124 | baudgen_en = 1'b1; 125 | if (bit_done) 126 | NS = STOP_BIT_FIRST; 127 | end 128 | STOP_BIT_FIRST: 129 | begin 130 | tx_o = 1'b1; 131 | baudgen_en = 1'b1; 132 | if (bit_done) 133 | begin 134 | if (cfg_stop_bits_i) 135 | NS = STOP_BIT_LAST; 136 | else 137 | NS = IDLE; 138 | end 139 | end 140 | STOP_BIT_LAST: 141 | begin 142 | tx_o = 1'b1; 143 | baudgen_en = 1'b1; 144 | if (bit_done) 145 | begin 146 | NS = IDLE; 147 | end 148 | end 149 | default: 150 | NS = IDLE; 151 | endcase 152 | end 153 | 154 | always_ff @(posedge clk_i or negedge rstn_i) 155 | begin 156 | if (rstn_i == 1'b0) 157 | begin 158 | CS <= IDLE; 159 | reg_data <= 8'hFF; 160 | reg_bit_count <= 'h0; 161 | parity_bit <= 1'b0; 162 | end 163 | else 164 | begin 165 | if(bit_done) 166 | begin 167 | parity_bit <= parity_bit_next; 168 | end 169 | 170 | if(sampleData) 171 | begin 172 | reg_data <= reg_data_next; 173 | end 174 | 175 | reg_bit_count <= reg_bit_count_next; 176 | if(cfg_en_i) 177 | CS <= NS; 178 | else 179 | CS <= IDLE; 180 | end 181 | end 182 | 183 | always_ff @(posedge clk_i or negedge rstn_i) 184 | begin 185 | if (rstn_i == 1'b0) 186 | begin 187 | baud_cnt <= 'h0; 188 | bit_done <= 1'b0; 189 | end 190 | else 191 | begin 192 | if(baudgen_en) 193 | begin 194 | if(baud_cnt == cfg_div_i) 195 | begin 196 | baud_cnt <= 'h0; 197 | bit_done <= 1'b1; 198 | end 199 | else 200 | begin 201 | baud_cnt <= baud_cnt + 1; 202 | bit_done <= 1'b0; 203 | end 204 | end 205 | else 206 | begin 207 | baud_cnt <= 'h0; 208 | bit_done <= 1'b0; 209 | end 210 | end 211 | end 212 | 213 | endmodule -------------------------------------------------------------------------------- /uart_rx.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2017 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the “License”); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | module uart_rx ( 12 | input logic clk_i, 13 | input logic rstn_i, 14 | input logic rx_i, 15 | input logic [15:0] cfg_div_i, 16 | input logic cfg_en_i, 17 | input logic cfg_parity_en_i, 18 | input logic [1:0] cfg_bits_i, 19 | // input logic cfg_stop_bits_i, 20 | output logic busy_o, 21 | output logic err_o, 22 | input logic err_clr_i, 23 | output logic [7:0] rx_data_o, 24 | output logic rx_valid_o, 25 | input logic rx_ready_i 26 | ); 27 | 28 | enum logic [2:0] {IDLE,START_BIT,DATA,SAVE_DATA,PARITY,STOP_BIT} CS, NS; 29 | 30 | logic [7:0] reg_data; 31 | logic [7:0] reg_data_next; 32 | 33 | logic [2:0] reg_rx_sync; 34 | 35 | 36 | logic [2:0] reg_bit_count; 37 | logic [2:0] reg_bit_count_next; 38 | 39 | logic [2:0] s_target_bits; 40 | 41 | logic parity_bit; 42 | logic parity_bit_next; 43 | 44 | logic sampleData; 45 | 46 | logic [15:0] baud_cnt; 47 | logic baudgen_en; 48 | logic bit_done; 49 | 50 | logic start_bit; 51 | logic set_error; 52 | logic s_rx_fall; 53 | 54 | 55 | assign busy_o = (CS != IDLE); 56 | 57 | always_comb 58 | begin 59 | case(cfg_bits_i) 60 | 2'b00: 61 | s_target_bits = 3'h4; 62 | 2'b01: 63 | s_target_bits = 3'h5; 64 | 2'b10: 65 | s_target_bits = 3'h6; 66 | 2'b11: 67 | s_target_bits = 3'h7; 68 | endcase 69 | end 70 | 71 | always_comb 72 | begin 73 | NS = CS; 74 | sampleData = 1'b0; 75 | reg_bit_count_next = reg_bit_count; 76 | reg_data_next = reg_data; 77 | rx_valid_o = 1'b0; 78 | baudgen_en = 1'b0; 79 | start_bit = 1'b0; 80 | parity_bit_next = parity_bit; 81 | set_error = 1'b0; 82 | 83 | case(CS) 84 | IDLE: 85 | begin 86 | if (s_rx_fall) 87 | begin 88 | NS = START_BIT; 89 | baudgen_en = 1'b1; 90 | start_bit = 1'b1; 91 | end 92 | end 93 | 94 | START_BIT: 95 | begin 96 | parity_bit_next = 1'b0; 97 | baudgen_en = 1'b1; 98 | start_bit = 1'b1; 99 | if (bit_done) 100 | NS = DATA; 101 | end 102 | 103 | DATA: 104 | begin 105 | baudgen_en = 1'b1; 106 | parity_bit_next = parity_bit ^ reg_rx_sync[2]; 107 | case(cfg_bits_i) 108 | 2'b00: 109 | reg_data_next = {3'b000,reg_rx_sync[2],reg_data[4:1]}; 110 | 2'b01: 111 | reg_data_next = {2'b00,reg_rx_sync[2],reg_data[5:1]}; 112 | 2'b10: 113 | reg_data_next = {1'b0,reg_rx_sync[2],reg_data[6:1]}; 114 | 2'b11: 115 | reg_data_next = {reg_rx_sync[2],reg_data[7:1]}; 116 | endcase 117 | 118 | if (bit_done) 119 | begin 120 | sampleData = 1'b1; 121 | if (reg_bit_count == s_target_bits) 122 | begin 123 | reg_bit_count_next = 'h0; 124 | NS = SAVE_DATA; 125 | end 126 | else 127 | begin 128 | reg_bit_count_next = reg_bit_count + 1; 129 | end 130 | end 131 | end 132 | SAVE_DATA: 133 | begin 134 | baudgen_en = 1'b1; 135 | rx_valid_o = 1'b1; 136 | if(rx_ready_i) 137 | if (cfg_parity_en_i) 138 | NS = PARITY; 139 | else 140 | NS = STOP_BIT; 141 | end 142 | PARITY: 143 | begin 144 | baudgen_en = 1'b1; 145 | if (bit_done) 146 | begin 147 | if(parity_bit != reg_rx_sync[2]) 148 | set_error = 1'b1; 149 | NS = STOP_BIT; 150 | end 151 | end 152 | STOP_BIT: 153 | begin 154 | baudgen_en = 1'b1; 155 | if (bit_done) 156 | begin 157 | NS = IDLE; 158 | end 159 | end 160 | default: 161 | NS = IDLE; 162 | endcase 163 | end 164 | 165 | always_ff @(posedge clk_i or negedge rstn_i) 166 | begin 167 | if (rstn_i == 1'b0) 168 | begin 169 | CS <= IDLE; 170 | reg_data <= 8'hFF; 171 | reg_bit_count <= 'h0; 172 | parity_bit <= 1'b0; 173 | end 174 | else 175 | begin 176 | if(bit_done) 177 | parity_bit <= parity_bit_next; 178 | if(sampleData) 179 | reg_data <= reg_data_next; 180 | 181 | reg_bit_count <= reg_bit_count_next; 182 | if(cfg_en_i) 183 | CS <= NS; 184 | else 185 | CS <= IDLE; 186 | end 187 | end 188 | 189 | assign s_rx_fall = ~reg_rx_sync[1] & reg_rx_sync[2]; 190 | always_ff @(posedge clk_i or negedge rstn_i) 191 | begin 192 | if (rstn_i == 1'b0) 193 | reg_rx_sync <= 3'b111; 194 | else 195 | begin 196 | if (cfg_en_i) 197 | reg_rx_sync <= {reg_rx_sync[1:0],rx_i}; 198 | else 199 | reg_rx_sync <= 3'b111; 200 | end 201 | end 202 | 203 | always_ff @(posedge clk_i or negedge rstn_i) 204 | begin 205 | if (rstn_i == 1'b0) 206 | begin 207 | baud_cnt <= 'h0; 208 | bit_done <= 1'b0; 209 | end 210 | else 211 | begin 212 | if(baudgen_en) 213 | begin 214 | if(!start_bit && (baud_cnt == cfg_div_i)) 215 | begin 216 | baud_cnt <= 'h0; 217 | bit_done <= 1'b1; 218 | end 219 | else if(start_bit && (baud_cnt == {1'b0,cfg_div_i[15:1]})) 220 | begin 221 | baud_cnt <= 'h0; 222 | bit_done <= 1'b1; 223 | end 224 | else 225 | begin 226 | baud_cnt <= baud_cnt + 1; 227 | bit_done <= 1'b0; 228 | end 229 | end 230 | else 231 | begin 232 | baud_cnt <= 'h0; 233 | bit_done <= 1'b0; 234 | end 235 | end 236 | end 237 | 238 | always_ff @(posedge clk_i or negedge rstn_i) 239 | begin 240 | if (rstn_i == 1'b0) 241 | begin 242 | err_o <= 1'b0; 243 | end 244 | else 245 | begin 246 | if(err_clr_i) 247 | begin 248 | err_o <= 1'b0; 249 | end 250 | else 251 | begin 252 | if(set_error) 253 | err_o <= 1'b1; 254 | end 255 | end 256 | end 257 | 258 | assign rx_data_o = reg_data; 259 | 260 | endmodule -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | SOLDERPAD HARDWARE LICENSE version 0.51 2 | 3 | This license is based closely on the Apache License Version 2.0, but is not 4 | approved or endorsed by the Apache Foundation. A copy of the non-modified 5 | Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0. 6 | 7 | As this license is not currently OSI or FSF approved, the Licensor permits any 8 | Work licensed under this License, at the option of the Licensee, to be treated 9 | as licensed under the Apache License Version 2.0 (which is so approved). 10 | 11 | This License is licensed under the terms of this License and in particular 12 | clause 7 below (Disclaimer of Warranties) applies in relation to its use. 13 | 14 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 15 | 16 | 1. Definitions. 17 | 18 | “License” shall mean the terms and conditions for use, reproduction, and 19 | distribution as defined by Sections 1 through 9 of this document. 20 | 21 | “Licensor” shall mean the Rights owner or entity authorized by the Rights owner 22 | that is granting the License. 23 | 24 | “Legal Entity” shall mean the union of the acting entity and all other entities 25 | that control, are controlled by, or are under common control with that entity. 26 | For the purposes of this definition, “control” means (i) the power, direct or 27 | indirect, to cause the direction or management of such entity, whether by 28 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 29 | outstanding shares, or (iii) beneficial ownership of such entity. 30 | 31 | “You” (or “Your”) shall mean an individual or Legal Entity exercising 32 | permissions granted by this License. 33 | 34 | “Rights” means copyright and any similar right including design right (whether 35 | registered or unregistered), semiconductor topography (mask) rights and 36 | database rights (but excluding Patents and Trademarks). 37 | 38 | “Source” form shall mean the preferred form for making modifications, including 39 | but not limited to source code, net lists, board layouts, CAD files, 40 | documentation source, and configuration files. 41 | 42 | “Object” form shall mean any form resulting from mechanical transformation or 43 | translation of a Source form, including but not limited to compiled object 44 | code, generated documentation, the instantiation of a hardware design and 45 | conversions to other media types, including intermediate forms such as 46 | bytecodes, FPGA bitstreams, artwork and semiconductor topographies (mask 47 | works). 48 | 49 | “Work” shall mean the work of authorship, whether in Source form or other 50 | Object form, made available under the License, as indicated by a Rights notice 51 | that is included in or attached to the work (an example is provided in the 52 | Appendix below). 53 | 54 | “Derivative Works” shall mean any work, whether in Source or Object form, that 55 | is based on (or derived from) the Work and for which the editorial revisions, 56 | annotations, elaborations, or other modifications represent, as a whole, an 57 | original work of authorship. For the purposes of this License, Derivative Works 58 | shall not include works that remain separable from, or merely link (or bind by 59 | name) or physically connect to or interoperate with the interfaces of, the Work 60 | and Derivative Works thereof. 61 | 62 | “Contribution” shall mean any design or work of authorship, including the 63 | original version of the Work and any modifications or additions to that Work or 64 | Derivative Works thereof, that is intentionally submitted to Licensor for 65 | inclusion in the Work by the Rights owner or by an individual or Legal Entity 66 | authorized to submit on behalf of the Rights owner. For the purposes of this 67 | definition, “submitted” means any form of electronic, verbal, or written 68 | communication sent to the Licensor or its representatives, including but not 69 | limited to communication on electronic mailing lists, source code control 70 | systems, and issue tracking systems that are managed by, or on behalf of, the 71 | Licensor for the purpose of discussing and improving the Work, but excluding 72 | communication that is conspicuously marked or otherwise designated in writing 73 | by the Rights owner as “Not a Contribution.” 74 | 75 | “Contributor” shall mean Licensor and any individual or Legal Entity on behalf 76 | of whom a Contribution has been received by Licensor and subsequently 77 | incorporated within the Work. 78 | 79 | 2. Grant of License. Subject to the terms and conditions of this License, each 80 | Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 81 | no-charge, royalty-free, irrevocable license under the Rights to reproduce, 82 | prepare Derivative Works of, publicly display, publicly perform, sublicense, 83 | and distribute the Work and such Derivative Works in Source or Object form and 84 | do anything in relation to the Work as if the Rights did not exist. 85 | 86 | 3. Grant of Patent License. Subject to the terms and conditions of this 87 | License, each Contributor hereby grants to You a perpetual, worldwide, 88 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this 89 | section) patent license to make, have made, use, offer to sell, sell, import, 90 | and otherwise transfer the Work, where such license applies only to those 91 | patent claims licensable by such Contributor that are necessarily infringed by 92 | their Contribution(s) alone or by combination of their Contribution(s) with the 93 | Work to which such Contribution(s) was submitted. If You institute patent 94 | litigation against any entity (including a cross-claim or counterclaim in a 95 | lawsuit) alleging that the Work or a Contribution incorporated within the Work 96 | constitutes direct or contributory patent infringement, then any patent 97 | licenses granted to You under this License for that Work shall terminate as of 98 | the date such litigation is filed. 99 | 100 | 4. Redistribution. You may reproduce and distribute copies of the Work or 101 | Derivative Works thereof in any medium, with or without modifications, and in 102 | Source or Object form, provided that You meet the following conditions: 103 | 104 | You must give any other recipients of the Work or Derivative Works a copy 105 | of this License; and 106 | 107 | You must cause any modified files to carry prominent notices stating that 108 | You changed the files; and 109 | 110 | You must retain, in the Source form of any Derivative Works that You 111 | distribute, all copyright, patent, trademark, and attribution notices from 112 | the Source form of the Work, excluding those notices that do not pertain to 113 | any part of the Derivative Works; and 114 | 115 | If the Work includes a “NOTICE” text file as part of its distribution, then 116 | any Derivative Works that You distribute must include a readable copy of 117 | the attribution notices contained within such NOTICE file, excluding those 118 | notices that do not pertain to any part of the Derivative Works, in at 119 | least one of the following places: within a NOTICE text file distributed as 120 | part of the Derivative Works; within the Source form or documentation, if 121 | provided along with the Derivative Works; or, within a display generated by 122 | the Derivative Works, if and wherever such third-party notices normally 123 | appear. The contents of the NOTICE file are for informational purposes only 124 | and do not modify the License. You may add Your own attribution notices 125 | within Derivative Works that You distribute, alongside or as an addendum to 126 | the NOTICE text from the Work, provided that such additional attribution 127 | notices cannot be construed as modifying the License. You may add Your own 128 | copyright statement to Your modifications and may provide additional or 129 | different license terms and conditions for use, reproduction, or 130 | distribution of Your modifications, or for any such Derivative Works as a 131 | whole, provided Your use, reproduction, and distribution of the Work 132 | otherwise complies with the conditions stated in this License. 133 | 134 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 135 | Contribution intentionally submitted for inclusion in the Work by You to the 136 | Licensor shall be under the terms and conditions of this License, without any 137 | additional terms or conditions. Notwithstanding the above, nothing herein shall 138 | supersede or modify the terms of any separate license agreement you may have 139 | executed with Licensor regarding such Contributions. 140 | 141 | 6. Trademarks. This License does not grant permission to use the trade names, 142 | trademarks, service marks, or product names of the Licensor, except as required 143 | for reasonable and customary use in describing the origin of the Work and 144 | reproducing the content of the NOTICE file. 145 | 146 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in 147 | writing, Licensor provides the Work (and each Contributor provides its 148 | Contributions) on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 149 | KIND, either express or implied, including, without limitation, any warranties 150 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any risks 153 | associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, whether in 156 | tort (including negligence), contract, or otherwise, unless required by 157 | applicable law (such as deliberate and grossly negligent acts) or agreed to in 158 | writing, shall any Contributor be liable to You for damages, including any 159 | direct, indirect, special, incidental, or consequential damages of any 160 | character arising as a result of this License or out of the use or inability to 161 | use the Work (including but not limited to damages for loss of goodwill, work 162 | stoppage, computer failure or malfunction, or any and all other commercial 163 | damages or losses), even if such Contributor has been advised of the 164 | possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or 167 | Derivative Works thereof, You may choose to offer, and charge a fee for, 168 | acceptance of support, warranty, indemnity, or other liability obligations 169 | and/or rights consistent with this License. However, in accepting such 170 | obligations, You may act only on Your own behalf and on Your sole 171 | responsibility, not on behalf of any other Contributor, and only if You agree 172 | to indemnify, defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason of your 174 | accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /apb_uart.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2017 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the “License”); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | module apb_uart_sv 12 | #( 13 | parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default 14 | ) 15 | ( 16 | input logic CLK, 17 | input logic RSTN, 18 | /* verilator lint_off UNUSED */ 19 | input logic [APB_ADDR_WIDTH-1:0] PADDR, 20 | /* lint_on */ 21 | input logic [31:0] PWDATA, 22 | input logic PWRITE, 23 | input logic PSEL, 24 | input logic PENABLE, 25 | output logic [31:0] PRDATA, 26 | output logic PREADY, 27 | output logic PSLVERR, 28 | 29 | input logic rx_i, // Receiver input 30 | output logic tx_o, // Transmitter output 31 | 32 | output logic event_o // interrupt/event output 33 | ); 34 | // register addresses 35 | parameter RBR = 3'h0, THR = 3'h0, DLL = 3'h0, IER = 3'h1, DLM = 3'h1, IIR = 3'h2, 36 | FCR = 3'h2, LCR = 3'h3, MCR = 3'h4, LSR = 3'h5, MSR = 3'h6, SCR = 3'h7; 37 | 38 | parameter TX_FIFO_DEPTH = 16; // in bytes 39 | parameter RX_FIFO_DEPTH = 16; // in bytes 40 | 41 | logic [2:0] register_adr; 42 | logic [9:0][7:0] regs_q, regs_n; 43 | logic [1:0] trigger_level_n, trigger_level_q; 44 | 45 | // receive buffer register, read only 46 | logic [7:0] rx_data; 47 | // parity error 48 | logic parity_error; 49 | logic [3:0] IIR_o; 50 | logic [3:0] clr_int; 51 | 52 | /* verilator lint_off UNOPTFLAT */ 53 | // tx flow control 54 | logic tx_ready; 55 | /* lint_on */ 56 | 57 | // rx flow control 58 | logic apb_rx_ready; 59 | logic rx_valid; 60 | 61 | logic tx_fifo_clr_n, tx_fifo_clr_q; 62 | logic rx_fifo_clr_n, rx_fifo_clr_q; 63 | 64 | logic fifo_tx_valid; 65 | logic tx_valid; 66 | logic fifo_rx_valid; 67 | logic fifo_rx_ready; 68 | logic rx_ready; 69 | 70 | logic [7:0] fifo_tx_data; 71 | logic [8:0] fifo_rx_data; 72 | 73 | logic [7:0] tx_data; 74 | logic [$clog2(TX_FIFO_DEPTH):0] tx_elements; 75 | logic [$clog2(RX_FIFO_DEPTH):0] rx_elements; 76 | 77 | // TODO: check that stop bits are really not necessary here 78 | uart_rx uart_rx_i 79 | ( 80 | .clk_i ( CLK ), 81 | .rstn_i ( RSTN ), 82 | .rx_i ( rx_i ), 83 | .cfg_en_i ( 1'b1 ), 84 | .cfg_div_i ( {regs_q[DLM + 'd8], regs_q[DLL + 'd8]} ), 85 | .cfg_parity_en_i ( regs_q[LCR][3] ), 86 | .cfg_bits_i ( regs_q[LCR][1:0] ), 87 | // .cfg_stop_bits_i ( regs_q[LCR][2] ), 88 | /* verilator lint_off PINCONNECTEMPTY */ 89 | .busy_o ( ), 90 | /* lint_on */ 91 | .err_o ( parity_error ), 92 | .err_clr_i ( 1'b1 ), 93 | .rx_data_o ( rx_data ), 94 | .rx_valid_o ( rx_valid ), 95 | .rx_ready_i ( rx_ready ) 96 | ); 97 | 98 | uart_tx uart_tx_i 99 | ( 100 | .clk_i ( CLK ), 101 | .rstn_i ( RSTN ), 102 | .tx_o ( tx_o ), 103 | /* verilator lint_off PINCONNECTEMPTY */ 104 | .busy_o ( ), 105 | /* lint_on */ 106 | .cfg_en_i ( 1'b1 ), 107 | .cfg_div_i ( {regs_q[DLM + 'd8], regs_q[DLL + 'd8]} ), 108 | .cfg_parity_en_i ( regs_q[LCR][3] ), 109 | .cfg_bits_i ( regs_q[LCR][1:0] ), 110 | .cfg_stop_bits_i ( regs_q[LCR][2] ), 111 | 112 | .tx_data_i ( tx_data ), 113 | .tx_valid_i ( tx_valid ), 114 | .tx_ready_o ( tx_ready ) 115 | ); 116 | 117 | io_generic_fifo 118 | #( 119 | .DATA_WIDTH ( 9 ), 120 | .BUFFER_DEPTH ( RX_FIFO_DEPTH ) 121 | ) 122 | uart_rx_fifo_i 123 | ( 124 | .clk_i ( CLK ), 125 | .rstn_i ( RSTN ), 126 | 127 | .clr_i ( rx_fifo_clr_q ), 128 | 129 | .elements_o ( rx_elements ), 130 | 131 | .data_o ( fifo_rx_data ), 132 | .valid_o ( fifo_rx_valid ), 133 | .ready_i ( fifo_rx_ready ), 134 | 135 | .valid_i ( rx_valid ), 136 | .data_i ( { parity_error, rx_data } ), 137 | .ready_o ( rx_ready ) 138 | ); 139 | 140 | io_generic_fifo 141 | #( 142 | .DATA_WIDTH ( 8 ), 143 | .BUFFER_DEPTH ( TX_FIFO_DEPTH ) 144 | ) 145 | uart_tx_fifo_i 146 | ( 147 | .clk_i ( CLK ), 148 | .rstn_i ( RSTN ), 149 | 150 | .clr_i ( tx_fifo_clr_q ), 151 | 152 | .elements_o ( tx_elements ), 153 | 154 | .data_o ( tx_data ), 155 | .valid_o ( tx_valid ), 156 | .ready_i ( tx_ready ), 157 | 158 | .valid_i ( fifo_tx_valid ), 159 | .data_i ( fifo_tx_data ), 160 | // not needed since we are getting the status via the fifo population 161 | .ready_o ( ) 162 | ); 163 | 164 | uart_interrupt 165 | #( 166 | .TX_FIFO_DEPTH (TX_FIFO_DEPTH), 167 | .RX_FIFO_DEPTH (RX_FIFO_DEPTH) 168 | ) 169 | uart_interrupt_i 170 | ( 171 | .clk_i ( CLK ), 172 | .rstn_i ( RSTN ), 173 | 174 | 175 | .IER_i ( regs_q[IER][2:0] ), // interrupt enable register 176 | .RDA_i ( regs_n[LSR][5] ), // receiver data available 177 | .CTI_i ( 1'b0 ), // character timeout indication 178 | 179 | 180 | .error_i ( regs_n[LSR][2] ), 181 | .rx_elements_i ( rx_elements ), 182 | .tx_elements_i ( tx_elements ), 183 | .trigger_level_i ( trigger_level_q ), 184 | 185 | .clr_int_i ( clr_int ), // one hot 186 | 187 | .interrupt_o ( event_o ), 188 | .IIR_o ( IIR_o ) 189 | 190 | ); 191 | 192 | // UART Registers 193 | 194 | // register write and update logic 195 | always_comb 196 | begin 197 | regs_n = regs_q; 198 | trigger_level_n = trigger_level_q; 199 | 200 | fifo_tx_valid = 1'b0; 201 | tx_fifo_clr_n = 1'b0; // self clearing 202 | rx_fifo_clr_n = 1'b0; // self clearing 203 | 204 | // rx status 205 | regs_n[LSR][0] = fifo_rx_valid; // fifo is empty 206 | 207 | // parity error on receiving part has occured 208 | regs_n[LSR][2] = fifo_rx_data[8]; // parity error is detected when element is retrieved 209 | 210 | // tx status register 211 | regs_n[LSR][5] = ~ (|tx_elements); // fifo is empty 212 | regs_n[LSR][6] = tx_ready & ~ (|tx_elements); // shift register and fifo are empty 213 | 214 | if (PSEL && PENABLE && PWRITE) 215 | begin 216 | case (register_adr) 217 | 218 | THR: // either THR or DLL 219 | begin 220 | if (regs_q[LCR][7]) // Divisor Latch Access Bit (DLAB) 221 | begin 222 | regs_n[DLL + 'd8] = PWDATA[7:0]; 223 | end 224 | else 225 | begin 226 | fifo_tx_data = PWDATA[7:0]; 227 | fifo_tx_valid = 1'b1; 228 | end 229 | end 230 | 231 | IER: // either IER or DLM 232 | begin 233 | if (regs_q[LCR][7]) // Divisor Latch Access Bit (DLAB) 234 | regs_n[DLM + 'd8] = PWDATA[7:0]; 235 | else 236 | regs_n[IER] = PWDATA[7:0]; 237 | end 238 | 239 | LCR: 240 | regs_n[LCR] = PWDATA[7:0]; 241 | 242 | FCR: // write only register, fifo control register 243 | begin 244 | rx_fifo_clr_n = PWDATA[1]; 245 | tx_fifo_clr_n = PWDATA[2]; 246 | trigger_level_n = PWDATA[7:6]; 247 | end 248 | 249 | default: ; 250 | endcase 251 | 252 | end 253 | 254 | end 255 | 256 | // register read logic 257 | always_comb 258 | begin 259 | PRDATA = 'b0; 260 | apb_rx_ready = 1'b0; 261 | fifo_rx_ready = 1'b0; 262 | clr_int = 4'b0; 263 | 264 | if (PSEL && PENABLE && !PWRITE) 265 | begin 266 | case (register_adr) 267 | RBR: // either RBR or DLL 268 | begin 269 | if (regs_q[LCR][7]) // Divisor Latch Access Bit (DLAB) 270 | PRDATA = {24'b0, regs_q[DLL + 'd8]}; 271 | else 272 | begin 273 | 274 | fifo_rx_ready = 1'b1; 275 | 276 | PRDATA = {24'b0, fifo_rx_data[7:0]}; 277 | 278 | clr_int = 4'b1000; // clear Received Data Available interrupt 279 | end 280 | end 281 | 282 | LSR: // Line Status Register 283 | begin 284 | PRDATA = {24'b0, regs_q[LSR]}; 285 | clr_int = 4'b1100; // clear parrity interrupt error 286 | end 287 | 288 | LCR: // Line Control Register 289 | PRDATA = {24'b0, regs_q[LCR]}; 290 | 291 | IER: // either IER or DLM 292 | begin 293 | if (regs_q[LCR][7]) // Divisor Latch Access Bit (DLAB) 294 | PRDATA = {24'b0, regs_q[DLM + 'd8]}; 295 | else 296 | PRDATA = {24'b0, regs_q[IER]}; 297 | end 298 | 299 | IIR: // interrupt identification register read only 300 | begin 301 | PRDATA = {24'b0, 1'b1, 1'b1, 2'b0, IIR_o}; 302 | clr_int = 4'b0100; // clear Transmitter Holding Register Empty 303 | end 304 | 305 | default: ; 306 | endcase 307 | end 308 | end 309 | 310 | // synchronouse part 311 | always_ff @(posedge CLK, negedge RSTN) 312 | begin 313 | if(~RSTN) 314 | begin 315 | 316 | regs_q[IER] <= 8'h0; 317 | regs_q[IIR] <= 8'h1; 318 | regs_q[LCR] <= 8'h0; 319 | regs_q[MCR] <= 8'h0; 320 | regs_q[LSR] <= 8'h60; 321 | regs_q[MSR] <= 8'h0; 322 | regs_q[SCR] <= 8'h0; 323 | regs_q[DLM + 'd8] <= 8'h0; 324 | regs_q[DLL + 'd8] <= 8'h0; 325 | 326 | trigger_level_q <= 2'b00; 327 | tx_fifo_clr_q <= 1'b0; 328 | rx_fifo_clr_q <= 1'b0; 329 | 330 | end 331 | else 332 | begin 333 | regs_q <= regs_n; 334 | 335 | trigger_level_q <= trigger_level_n; 336 | tx_fifo_clr_q <= tx_fifo_clr_n; 337 | rx_fifo_clr_q <= rx_fifo_clr_n; 338 | 339 | end 340 | end 341 | 342 | assign register_adr = {PADDR[2:0]}; 343 | // APB logic: we are always ready to capture the data into our regs 344 | // not supporting transfare failure 345 | assign PREADY = 1'b1; 346 | assign PSLVERR = 1'b0; 347 | endmodule 348 | -------------------------------------------------------------------------------- /apb_uart_sv.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2017 ETH Zurich and University of Bologna. 2 | // Copyright and related rights are licensed under the Solderpad Hardware 3 | // License, Version 0.51 (the “License”); you may not use this file except in 4 | // compliance with the License. You may obtain a copy of the License at 5 | // http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law 6 | // or agreed to in writing, software, hardware and materials distributed under 7 | // this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR 8 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 9 | // specific language governing permissions and limitations under the License. 10 | 11 | module apb_uart_sv 12 | #( 13 | parameter APB_ADDR_WIDTH = 12 //APB slaves are 4KB by default 14 | ) 15 | ( 16 | input logic CLK, 17 | input logic RSTN, 18 | /* verilator lint_off UNUSED */ 19 | input logic [APB_ADDR_WIDTH-1:0] PADDR, 20 | /* lint_on */ 21 | input logic [31:0] PWDATA, 22 | input logic PWRITE, 23 | input logic PSEL, 24 | input logic PENABLE, 25 | output logic [31:0] PRDATA, 26 | output logic PREADY, 27 | output logic PSLVERR, 28 | 29 | input logic rx_i, // Receiver input 30 | output logic tx_o, // Transmitter output 31 | 32 | output logic event_o // interrupt/event output 33 | ); 34 | // register addresses 35 | parameter RBR = 3'h0, THR = 3'h0, DLL = 3'h0, IER = 3'h1, DLM = 3'h1, IIR = 3'h2, 36 | FCR = 3'h2, LCR = 3'h3, MCR = 3'h4, LSR = 3'h5, MSR = 3'h6, SCR = 3'h7; 37 | 38 | parameter TX_FIFO_DEPTH = 16; // in bytes 39 | parameter RX_FIFO_DEPTH = 16; // in bytes 40 | 41 | logic [2:0] register_adr; 42 | logic [9:0][7:0] regs_q, regs_n; 43 | logic [1:0] trigger_level_n, trigger_level_q; 44 | 45 | // receive buffer register, read only 46 | logic [7:0] rx_data; 47 | // parity error 48 | logic parity_error; 49 | logic [3:0] IIR_o; 50 | logic [3:0] clr_int; 51 | 52 | /* verilator lint_off UNOPTFLAT */ 53 | // tx flow control 54 | logic tx_ready; 55 | /* lint_on */ 56 | 57 | // rx flow control 58 | logic apb_rx_ready; 59 | logic rx_valid; 60 | 61 | logic tx_fifo_clr_n, tx_fifo_clr_q; 62 | logic rx_fifo_clr_n, rx_fifo_clr_q; 63 | 64 | logic fifo_tx_valid; 65 | logic tx_valid; 66 | logic fifo_rx_valid; 67 | logic fifo_rx_ready; 68 | logic rx_ready; 69 | 70 | logic [7:0] fifo_tx_data; 71 | logic [8:0] fifo_rx_data; 72 | 73 | logic [7:0] tx_data; 74 | logic [$clog2(TX_FIFO_DEPTH):0] tx_elements; 75 | logic [$clog2(RX_FIFO_DEPTH):0] rx_elements; 76 | 77 | // TODO: check that stop bits are really not necessary here 78 | uart_rx uart_rx_i 79 | ( 80 | .clk_i ( CLK ), 81 | .rstn_i ( RSTN ), 82 | .rx_i ( rx_i ), 83 | .cfg_en_i ( 1'b1 ), 84 | .cfg_div_i ( {regs_q[DLM + 'd8], regs_q[DLL + 'd8]} ), 85 | .cfg_parity_en_i ( regs_q[LCR][3] ), 86 | .cfg_bits_i ( regs_q[LCR][1:0] ), 87 | // .cfg_stop_bits_i ( regs_q[LCR][2] ), 88 | /* verilator lint_off PINCONNECTEMPTY */ 89 | .busy_o ( ), 90 | /* lint_on */ 91 | .err_o ( parity_error ), 92 | .err_clr_i ( 1'b1 ), 93 | .rx_data_o ( rx_data ), 94 | .rx_valid_o ( rx_valid ), 95 | .rx_ready_i ( rx_ready ) 96 | ); 97 | 98 | uart_tx uart_tx_i 99 | ( 100 | .clk_i ( CLK ), 101 | .rstn_i ( RSTN ), 102 | .tx_o ( tx_o ), 103 | /* verilator lint_off PINCONNECTEMPTY */ 104 | .busy_o ( ), 105 | /* lint_on */ 106 | .cfg_en_i ( 1'b1 ), 107 | .cfg_div_i ( {regs_q[DLM + 'd8], regs_q[DLL + 'd8]} ), 108 | .cfg_parity_en_i ( regs_q[LCR][3] ), 109 | .cfg_bits_i ( regs_q[LCR][1:0] ), 110 | .cfg_stop_bits_i ( regs_q[LCR][2] ), 111 | 112 | .tx_data_i ( tx_data ), 113 | .tx_valid_i ( tx_valid ), 114 | .tx_ready_o ( tx_ready ) 115 | ); 116 | 117 | io_generic_fifo 118 | #( 119 | .DATA_WIDTH ( 9 ), 120 | .BUFFER_DEPTH ( RX_FIFO_DEPTH ) 121 | ) 122 | uart_rx_fifo_i 123 | ( 124 | .clk_i ( CLK ), 125 | .rstn_i ( RSTN ), 126 | 127 | .clr_i ( rx_fifo_clr_q ), 128 | 129 | .elements_o ( rx_elements ), 130 | 131 | .data_o ( fifo_rx_data ), 132 | .valid_o ( fifo_rx_valid ), 133 | .ready_i ( fifo_rx_ready ), 134 | 135 | .valid_i ( rx_valid ), 136 | .data_i ( { parity_error, rx_data } ), 137 | .ready_o ( rx_ready ) 138 | ); 139 | 140 | io_generic_fifo 141 | #( 142 | .DATA_WIDTH ( 8 ), 143 | .BUFFER_DEPTH ( TX_FIFO_DEPTH ) 144 | ) 145 | uart_tx_fifo_i 146 | ( 147 | .clk_i ( CLK ), 148 | .rstn_i ( RSTN ), 149 | 150 | .clr_i ( tx_fifo_clr_q ), 151 | 152 | .elements_o ( tx_elements ), 153 | 154 | .data_o ( tx_data ), 155 | .valid_o ( tx_valid ), 156 | .ready_i ( tx_ready ), 157 | 158 | .valid_i ( fifo_tx_valid ), 159 | .data_i ( fifo_tx_data ), 160 | // not needed since we are getting the status via the fifo population 161 | .ready_o ( ) 162 | ); 163 | 164 | uart_interrupt 165 | #( 166 | .TX_FIFO_DEPTH (TX_FIFO_DEPTH), 167 | .RX_FIFO_DEPTH (RX_FIFO_DEPTH) 168 | ) 169 | uart_interrupt_i 170 | ( 171 | .clk_i ( CLK ), 172 | .rstn_i ( RSTN ), 173 | 174 | 175 | .IER_i ( regs_q[IER][2:0] ), // interrupt enable register 176 | .RDA_i ( regs_n[LSR][5] ), // receiver data available 177 | .CTI_i ( 1'b0 ), // character timeout indication 178 | 179 | 180 | .error_i ( regs_n[LSR][2] ), 181 | .rx_elements_i ( rx_elements ), 182 | .tx_elements_i ( tx_elements ), 183 | .trigger_level_i ( trigger_level_q ), 184 | 185 | .clr_int_i ( clr_int ), // one hot 186 | 187 | .interrupt_o ( event_o ), 188 | .IIR_o ( IIR_o ) 189 | 190 | ); 191 | 192 | // UART Registers 193 | 194 | // register write and update logic 195 | always_comb 196 | begin 197 | regs_n = regs_q; 198 | trigger_level_n = trigger_level_q; 199 | 200 | fifo_tx_valid = 1'b0; 201 | tx_fifo_clr_n = 1'b0; // self clearing 202 | rx_fifo_clr_n = 1'b0; // self clearing 203 | 204 | // rx status 205 | regs_n[LSR][0] = fifo_rx_valid; // fifo is empty 206 | 207 | // parity error on receiving part has occured 208 | regs_n[LSR][2] = fifo_rx_data[8]; // parity error is detected when element is retrieved 209 | 210 | // tx status register 211 | regs_n[LSR][5] = ~ (|tx_elements); // fifo is empty 212 | regs_n[LSR][6] = tx_ready & ~ (|tx_elements); // shift register and fifo are empty 213 | 214 | if (PSEL && PENABLE && PWRITE) 215 | begin 216 | case (register_adr) 217 | 218 | THR: // either THR or DLL 219 | begin 220 | if (regs_q[LCR][7]) // Divisor Latch Access Bit (DLAB) 221 | begin 222 | regs_n[DLL + 'd8] = PWDATA[7:0]; 223 | end 224 | else 225 | begin 226 | fifo_tx_data = PWDATA[7:0]; 227 | fifo_tx_valid = 1'b1; 228 | end 229 | end 230 | 231 | IER: // either IER or DLM 232 | begin 233 | if (regs_q[LCR][7]) // Divisor Latch Access Bit (DLAB) 234 | regs_n[DLM + 'd8] = PWDATA[7:0]; 235 | else 236 | regs_n[IER] = PWDATA[7:0]; 237 | end 238 | 239 | LCR: 240 | regs_n[LCR] = PWDATA[7:0]; 241 | 242 | FCR: // write only register, fifo control register 243 | begin 244 | rx_fifo_clr_n = PWDATA[1]; 245 | tx_fifo_clr_n = PWDATA[2]; 246 | trigger_level_n = PWDATA[7:6]; 247 | end 248 | 249 | default: ; 250 | endcase 251 | 252 | end 253 | 254 | end 255 | 256 | // register read logic 257 | always_comb 258 | begin 259 | PRDATA = 'b0; 260 | apb_rx_ready = 1'b0; 261 | fifo_rx_ready = 1'b0; 262 | clr_int = 4'b0; 263 | 264 | if (PSEL && PENABLE && !PWRITE) 265 | begin 266 | case (register_adr) 267 | RBR: // either RBR or DLL 268 | begin 269 | if (regs_q[LCR][7]) // Divisor Latch Access Bit (DLAB) 270 | PRDATA = {24'b0, regs_q[DLL + 'd8]}; 271 | else 272 | begin 273 | 274 | fifo_rx_ready = 1'b1; 275 | 276 | PRDATA = {24'b0, fifo_rx_data[7:0]}; 277 | 278 | clr_int = 4'b1000; // clear Received Data Available interrupt 279 | end 280 | end 281 | 282 | LSR: // Line Status Register 283 | begin 284 | PRDATA = {24'b0, regs_q[LSR]}; 285 | clr_int = 4'b1100; // clear parrity interrupt error 286 | end 287 | 288 | LCR: // Line Control Register 289 | PRDATA = {24'b0, regs_q[LCR]}; 290 | 291 | IER: // either IER or DLM 292 | begin 293 | if (regs_q[LCR][7]) // Divisor Latch Access Bit (DLAB) 294 | PRDATA = {24'b0, regs_q[DLM + 'd8]}; 295 | else 296 | PRDATA = {24'b0, regs_q[IER]}; 297 | end 298 | 299 | IIR: // interrupt identification register read only 300 | begin 301 | PRDATA = {24'b0, 1'b1, 1'b1, 2'b0, IIR_o}; 302 | clr_int = 4'b0100; // clear Transmitter Holding Register Empty 303 | end 304 | 305 | default: ; 306 | endcase 307 | end 308 | end 309 | 310 | // synchronouse part 311 | always_ff @(posedge CLK, negedge RSTN) 312 | begin 313 | if(~RSTN) 314 | begin 315 | 316 | regs_q[IER] <= 8'h0; 317 | regs_q[IIR] <= 8'h1; 318 | regs_q[LCR] <= 8'h0; 319 | regs_q[MCR] <= 8'h0; 320 | regs_q[LSR] <= 8'h60; 321 | regs_q[MSR] <= 8'h0; 322 | regs_q[SCR] <= 8'h0; 323 | regs_q[DLM + 'd8] <= 8'h0; 324 | regs_q[DLL + 'd8] <= 8'h0; 325 | 326 | trigger_level_q <= 2'b00; 327 | tx_fifo_clr_q <= 1'b0; 328 | rx_fifo_clr_q <= 1'b0; 329 | 330 | end 331 | else 332 | begin 333 | regs_q <= regs_n; 334 | 335 | trigger_level_q <= trigger_level_n; 336 | tx_fifo_clr_q <= tx_fifo_clr_n; 337 | rx_fifo_clr_q <= rx_fifo_clr_n; 338 | 339 | end 340 | end 341 | 342 | assign register_adr = {PADDR[2:0]}; 343 | // APB logic: we are always ready to capture the data into our regs 344 | // not supporting transfare failure 345 | assign PREADY = 1'b1; 346 | assign PSLVERR = 1'b0; 347 | endmodule 348 | --------------------------------------------------------------------------------