uart.v (5145B)
1 /* 2 * Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free 3 * soft-/hardware under the GNU GPL v3 license or any later 4 * version. See COPYING in the root directory for details. 5 */ 6 7 `ifndef uart_v 8 `define uart_v 9 10 // In order to send a byte, din is set to the byte to be send and 11 // write is set to 1. While transmitting, bit 0 of the status register 12 // is 1. 13 // 14 // In order to receive a byte, the receive buffer must be cleared by 15 // writing to the status register. Once the byte is received, bit 1 of 16 // the status register is set to 1. 17 18 module uart(input clk, // 12 Mhz system clock 19 // Data to be send via the serial line is read from din. 20 input [7:0] din, 21 // When reg_select is set to 0 (see below), dout carries 22 // the last byte received via the serial line. 23 // When reg_select is set to 1, dout carries the current bits: 24 // Bit 0: The UART is in the process of sending the byte at din 25 // Bit 1: The UART received a byte. 26 output [7:0] dout, 27 // When reg_select is set to 0 (see below), setting write to 1 28 // starts serial transmission of din. 29 // When reg_select is set to 1, setting write to 1 clears 30 // the receive buffer. 31 input write, 32 // 0: Data Register 33 // 1: Status register 34 input reg_select, 35 // Connections to hardware lines 36 output reg tx, 37 input rx); 38 39 reg [9:0] tx_buffer; // Internal transmit buffer (start bit, data, stop bit) 40 reg [7:0] rx_buffer; // Internal receive buffer 41 reg [7:0] received_byte; // Last complete byte received 42 reg [7:0] bit_time_tx; // Clock ticks until bit transmitted 43 reg [3:0] curr_bit_tx; // Index of bit currently transmitted 44 reg rx_busy; 45 reg tx_busy; 46 wire recv_buffer_full; 47 48 parameter ticks_per_bit = 104; // Clock ticks per bit for 115200 bps @ 12 Mhz 49 50 assign dout = reg_select ? {6'b000000, recv_buffer_full, tx_busy} : received_byte; 51 52 initial 53 begin 54 tx_busy <= 0; 55 tx <= 1; 56 curr_bit_tx <= 0; 57 rx_busy <= 0; 58 end 59 60 /* 61 * Transmitter 62 * 63 */ 64 65 always @(posedge(clk)) 66 begin 67 // Begin of transmission 68 if (write && !reg_select && !tx_busy) 69 // Transmissions starts on write operation to data register: 70 // Fill the internal transmit buffer, and get busy. 71 begin 72 tx_buffer <= {1'b1, din, 1'b0}; 73 curr_bit_tx <= 0; 74 bit_time_tx <= ticks_per_bit; 75 tx_busy <= 1; 76 end 77 // End of transmission 78 if (curr_bit_tx == 10) 79 begin 80 // Keep tx high will not transmitting. 81 tx <= 1; 82 // If the CPU clock is significangtly slower than the 83 // system clock, write may still be high. In order to 84 // avoid sending the same byte again, we only set tx_busy 85 // to low when write is low as well. 86 if(!write) 87 begin 88 tx_busy <= 0; 89 curr_bit_tx <= 0; 90 end 91 end // if (curr_bit_tx == 10) 92 else 93 // In transmission 94 begin 95 if (tx_busy) 96 // Output current bit 97 begin 98 tx <= tx_buffer[curr_bit_tx]; 99 bit_time_tx <= bit_time_tx - 1; 100 end 101 if (bit_time_tx == 0) 102 // Switch to next bit 103 begin 104 curr_bit_tx <= curr_bit_tx + 1; 105 bit_time_tx <= ticks_per_bit; 106 end 107 end 108 end // always @ (posedge(clk)) 109 110 /* 111 * Receiver 112 * 113 */ 114 115 reg [7:0] bit_time_rx; // Clock ticks until bit received 116 reg [3:0] curr_bit_rx; // Index of bit currently received 117 118 assign recv_buffer_full = (curr_bit_rx == 9); 119 always @(posedge(clk)) 120 begin 121 if (write && reg_select) 122 curr_bit_rx <= 0; 123 else 124 begin 125 if (!rx_busy && !rx) 126 begin 127 // Start receving once we get the start bit 128 rx_busy <= 1; 129 curr_bit_rx <= 0; 130 // bit_time_rx hits 0 in the middle 131 // of the first data bit 132 bit_time_rx <= ticks_per_bit * 1.5; 133 end 134 else if ((curr_bit_rx == 9) && rx) 135 begin 136 // If this is the stop bit, we are done 137 rx_busy <= 0; 138 received_byte <= rx_buffer; 139 end 140 else if ((rx_busy) && (bit_time_rx == 0)) 141 // We are in the middle of the next bit. 142 begin 143 // Read it 144 rx_buffer[curr_bit_rx] <= rx; 145 curr_bit_rx <= curr_bit_rx + 1; 146 bit_time_rx <= ticks_per_bit; 147 end 148 else 149 bit_time_rx <= bit_time_rx - 1; 150 end 151 end // always @ (posedge(clk)) 152 153 endmodule 154 155 `endif