ls2: add support for the Nexys Video board
[ls2.git] / verilator / uart-verilator.c
1 // Copyright (C) IBM 2019, see LICENSE.CC4
2 // based on code from microwatt https://github.com/antonblanchard/microwatt
3
4 #include <signal.h>
5 #include <poll.h>
6 #include <unistd.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <termios.h>
10 #include <stdlib.h>
11
12 /* Should we exit simulation on ctrl-c or pass it through? */
13 #define EXIT_ON_CTRL_C
14
15 #define BAUD 115200
16 /* Round to nearest */
17 #define BITWIDTH ((CLK_FREQUENCY+(BAUD/2))/BAUD)
18
19 /*
20 * Our UART uses 16x oversampling, so at 50 MHz and 115200 baud
21 * each sample is: 50000000/(115200*16) = 27 clock cycles. This
22 * means each bit is off by 0.47% so for 8 bits plus a start and
23 * stop bit the errors add to be 4.7%.
24 */
25 static double error = 0.05;
26
27 enum state {
28 IDLE, START_BIT, BITS, STOP_BIT, ERROR
29 };
30
31 static enum state tx_state = IDLE;
32 static unsigned long tx_countbits;
33 static unsigned char tx_bits;
34 static unsigned char tx_byte;
35 static unsigned char tx_prev;
36
37 /*
38 * Return an error if the transition is not close enough to the start or
39 * the end of an expected bit.
40 */
41 static bool is_error(unsigned long bits)
42 {
43 double e = 1.0 * tx_countbits / BITWIDTH;
44
45 if ((e <= (1.0-error)) && (e >= error))
46 return true;
47
48 return false;
49 }
50
51 void uart_tx(unsigned char tx)
52 {
53 switch (tx_state) {
54 case IDLE:
55 if (tx == 0) {
56 tx_state = START_BIT;
57 tx_countbits = BITWIDTH;
58 tx_bits = 0;
59 tx_byte = 0;
60 }
61 break;
62
63 case START_BIT:
64 tx_countbits--;
65 if (tx == 1) {
66 if (is_error(tx_countbits)) {
67 printf("START_BIT error %ld %ld\n", BITWIDTH, tx_countbits);
68 tx_countbits = BITWIDTH*2;
69 tx_state = ERROR;
70 break;
71 }
72 }
73
74 if (tx_countbits == 0) {
75 tx_state = BITS;
76 tx_countbits = BITWIDTH;
77 }
78 break;
79
80 case BITS:
81 tx_countbits--;
82 if (tx_countbits == BITWIDTH/2) {
83 tx_byte = tx_byte | (tx << tx_bits);
84 tx_bits = tx_bits + 1;
85 }
86
87 if (tx != tx_prev) {
88 if (is_error(tx_countbits)) {
89 printf("BITS error %ld %ld\n", BITWIDTH, tx_countbits);
90 tx_countbits = BITWIDTH*2;
91 tx_state = ERROR;
92 break;
93 }
94 }
95
96 if (tx_countbits == 0) {
97 if (tx_bits == 8) {
98 tx_state = STOP_BIT;
99 }
100 tx_countbits = BITWIDTH;
101 }
102 break;
103
104 case STOP_BIT:
105 tx_countbits--;
106
107 if (tx == 0) {
108 if (is_error(tx_countbits)) {
109 printf("STOP_BIT error %ld %ld\n", BITWIDTH, tx_countbits);
110 tx_countbits = BITWIDTH*2;
111 tx_state = ERROR;
112 break;
113 }
114 /* Go straight to idle */
115 write(STDOUT_FILENO, &tx_byte, 1);
116 tx_state = IDLE;
117 }
118
119 if (tx_countbits == 0) {
120 write(STDOUT_FILENO, &tx_byte, 1);
121 tx_state = IDLE;
122 }
123 break;
124
125 case ERROR:
126 tx_countbits--;
127 if (tx_countbits == 0) {
128 tx_state = IDLE;
129 }
130
131 break;
132 }
133
134 tx_prev = tx;
135 }
136
137 static struct termios oldt;
138
139 static void disable_raw_mode(void)
140 {
141 tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
142 }
143
144 static void enable_raw_mode(void)
145 {
146 static bool initialized = false;
147
148 if (!initialized) {
149 static struct termios newt;
150
151 tcgetattr(STDIN_FILENO, &oldt);
152 newt = oldt;
153 cfmakeraw(&newt);
154 #ifdef EXIT_ON_CTRL_C
155 newt.c_lflag |= ISIG;
156 #endif
157 tcsetattr(STDIN_FILENO, TCSANOW, &newt);
158 initialized = true;
159 atexit(disable_raw_mode);
160 }
161 }
162
163 static int nonblocking_read(unsigned char *c)
164 {
165 int ret;
166 unsigned long val = 0;
167 struct pollfd fdset[1];
168
169 enable_raw_mode();
170
171 memset(fdset, 0, sizeof(fdset));
172
173 fdset[0].fd = STDIN_FILENO;
174 fdset[0].events = POLLIN;
175
176 ret = poll(fdset, 1, 0);
177 if (ret == 0)
178 return false;
179
180 ret = read(STDIN_FILENO, &val, 1);
181 if (ret != 1) {
182 fprintf(stderr, "%s: read of stdin returns %d\n", __func__, ret);
183 exit(1);
184 }
185
186 if (ret == 1) {
187 *c = val;
188 return true;
189 } else {
190 return false;
191 }
192 }
193
194 static enum state rx_state = IDLE;
195 static unsigned char rx_char;
196 static unsigned long rx_countbits;
197 static unsigned char rx_bit;
198 static unsigned char rx = 1;
199
200 /* Avoid calling poll() too much */
201 #define RX_INTERVAL 10000
202 static unsigned long rx_sometimes;
203
204 unsigned char uart_rx(void)
205 {
206 unsigned char c;
207
208 switch (rx_state) {
209 case IDLE:
210 if (rx_sometimes++ >= RX_INTERVAL) {
211 rx_sometimes = 0;
212
213 if (nonblocking_read(&c)) {
214 rx_state = START_BIT;
215 rx_char = c;
216 rx_countbits = BITWIDTH;
217 rx_bit = 0;
218 rx = 0;
219 }
220 }
221
222 break;
223
224 case START_BIT:
225 rx_countbits--;
226 if (rx_countbits == 0) {
227 rx_state = BITS;
228 rx_countbits = BITWIDTH;
229 rx = rx_char & 1;
230 }
231 break;
232
233 case BITS:
234 rx_countbits--;
235 if (rx_countbits == 0) {
236 rx_bit = rx_bit + 1;
237 if (rx_bit == 8) {
238 rx = 1;
239 rx_state = STOP_BIT;
240 } else {
241 rx = (rx_char >> rx_bit) & 1;
242 }
243 rx_countbits = BITWIDTH;
244 }
245 break;
246
247 case STOP_BIT:
248 rx_countbits--;
249 if (rx_countbits == 0) {
250 rx_state = IDLE;
251 }
252 break;
253 }
254
255 return rx;
256 }