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