litex: reorganize things, first work working version
[litex.git] / litex / soc / software / libbase / uart.c
1 #include <uart.h>
2 #include <irq.h>
3 #include <generated/csr.h>
4 #include <hw/flags.h>
5
6 /*
7 * Buffer sizes must be a power of 2 so that modulos can be computed
8 * with logical AND.
9 */
10
11 #define UART_RINGBUFFER_SIZE_RX 128
12 #define UART_RINGBUFFER_MASK_RX (UART_RINGBUFFER_SIZE_RX-1)
13
14 static char rx_buf[UART_RINGBUFFER_SIZE_RX];
15 static volatile unsigned int rx_produce;
16 static unsigned int rx_consume;
17
18 #define UART_RINGBUFFER_SIZE_TX 128
19 #define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX-1)
20
21 static char tx_buf[UART_RINGBUFFER_SIZE_TX];
22 static unsigned int tx_produce;
23 static volatile unsigned int tx_consume;
24
25 void uart_isr(void)
26 {
27 unsigned int stat, rx_produce_next;
28
29 stat = uart_ev_pending_read();
30
31 if(stat & UART_EV_RX) {
32 while(!uart_rxempty_read()) {
33 rx_produce_next = (rx_produce + 1) & UART_RINGBUFFER_MASK_RX;
34 if(rx_produce_next != rx_consume) {
35 rx_buf[rx_produce] = uart_rxtx_read();
36 rx_produce = rx_produce_next;
37 }
38 uart_ev_pending_write(UART_EV_RX);
39 }
40 }
41
42 if(stat & UART_EV_TX) {
43 uart_ev_pending_write(UART_EV_TX);
44 while((tx_consume != tx_produce) && !uart_txfull_read()) {
45 uart_rxtx_write(tx_buf[tx_consume]);
46 tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
47 }
48 }
49 }
50
51 /* Do not use in interrupt handlers! */
52 char uart_read(void)
53 {
54 char c;
55
56 if(irq_getie()) {
57 while(rx_consume == rx_produce);
58 } else if (rx_consume == rx_produce) {
59 return 0;
60 }
61
62 c = rx_buf[rx_consume];
63 rx_consume = (rx_consume + 1) & UART_RINGBUFFER_MASK_RX;
64 return c;
65 }
66
67 int uart_read_nonblock(void)
68 {
69 return (rx_consume != rx_produce);
70 }
71
72 void uart_write(char c)
73 {
74 unsigned int oldmask;
75 unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;
76
77 if(irq_getie()) {
78 while(tx_produce_next == tx_consume);
79 } else if(tx_produce_next == tx_consume) {
80 return;
81 }
82
83 oldmask = irq_getmask();
84 irq_setmask(oldmask & ~(1 << UART_INTERRUPT));
85 if((tx_consume != tx_produce) || uart_txfull_read()) {
86 tx_buf[tx_produce] = c;
87 tx_produce = tx_produce_next;
88 } else {
89 uart_rxtx_write(c);
90 }
91 irq_setmask(oldmask);
92 }
93
94 void uart_init(void)
95 {
96 rx_produce = 0;
97 rx_consume = 0;
98
99 tx_produce = 0;
100 tx_consume = 0;
101
102 uart_ev_pending_write(uart_ev_pending_read());
103 uart_ev_enable_write(UART_EV_TX | UART_EV_RX);
104 irq_setmask(irq_getmask() | (1 << UART_INTERRUPT));
105 }
106
107 void uart_sync(void)
108 {
109 while(tx_consume != tx_produce);
110 }