The unified diff between revisions [8760ae92..] and [24d5b9f4..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'uart.c'

#
# old_revision [8760ae9232295422550b79f09e55122390704b3c]
# new_revision [24d5b9f4dff9135787b198fe1127d9c1e3326b9c]
#
# add_file "uart.c"
#  content [7a38c486dc1280695e1e62c6d3a76d6c9f849f67]
#
============================================================
--- /dev/null	
+++ uart.c	7a38c486dc1280695e1e62c6d3a76d6c9f849f67
@@ -0,0 +1,210 @@
+#include "uart.h"
+#include "types.h"
+#include "interrupt.h"
+#include "event.h"
+
+#define UARTBASE 0xE000C000
+
+#define RBR 0x00
+#define THR 0x00
+#define DLL 0x00
+#define DLM 0x04
+#define IER 0x04
+#define IIR 0x08
+#define FCR 0x08
+
+#define LCR 0x0c
+#define LSR 0x14
+#define SCR 0x1c
+#define ACR 0x20
+#define FDR 0x28
+#define TER 0x30
+
+#define UREG(x) (((volatile unsigned char *)UARTBASE)[x])
+
+#define U0THRE ((UREG(LSR) & (1<<5))) /* UART0 transmitter holding register is empty */
+#define U0DR ((UREG(LSR) & (1<<0))) /* UART0 data ready */
+
+#define UART_TXBUFSIZE 128
+#define UART_RXBUFSIZE 128
+
+char uart_txbuf[UART_TXBUFSIZE];
+char uart_rxbuf[UART_RXBUFSIZE];
+volatile int uart_txread;
+volatile int uart_txwrite;
+volatile int uart_rxread;
+volatile int uart_rxwrite;
+volatile bool tx_running;
+
+void __attribute__((interrupt("IRQ"))) uart_interrupt_handler(void);
+
+#ifdef USE_UART
+
+void init_uart(void)
+{
+	UREG(FDR) = 0x10; /* DivAddVal = 0, MulVal = 1 */
+
+	UREG(LCR) = 0x80;
+	UREG(DLM) = 0x00;
+	UREG(DLL) = 0x08; /* 14745600 / (16*115200) */
+	UREG(LCR) = 0x13;
+	UREG(FCR) = 0x07;
+
+	uart_txread = 0;
+	uart_txwrite = 0;
+	uart_rxread = 0;
+	uart_rxwrite = 0;
+	tx_running = FALSE;
+	interrupt_register(UART0, uart_interrupt_handler);
+
+	UREG(IER) = 0x03; /* RBR and THRE interrupt enable */
+}
+
+void putch(char c) {
+	/* Wait for space in the buffer */
+	while (uart_txread == ((uart_txwrite+1) % UART_TXBUFSIZE));
+
+	if (uart_txread == uart_txwrite) {
+		if (U0THRE) {
+			tx_running = TRUE;
+			UREG(THR) = c;
+			return;
+		}
+	}
+
+	uart_txbuf[uart_txwrite] = c;
+	uart_txwrite = (uart_txwrite + 1) % UART_TXBUFSIZE;
+
+	if (!tx_running) {
+		if (uart_txread != uart_txwrite) {
+			tx_running = TRUE;
+			uart_txread = (uart_txread + 1) % UART_TXBUFSIZE;
+			UREG(THR) = c;
+		}
+	}
+}
+
+void __attribute__((interrupt("IRQ"))) uart_interrupt_handler(void)
+{
+	bool active = FALSE;
+	int source;
+	int i;
+	/* uart_txread and uart_txwrite are volatile. We don't need
+	 * to treat them as such in this handler, so let the compiler
+	 * have an easier time.
+	 */
+	int local_txwrite;
+	int local_txread;
+	int local_rxwrite;
+	int local_rxread;
+
+	source = UREG(IIR);
+
+	switch (source & 0x0e) {
+	case 0x4: /* Receive Data Available */
+	case 0xc: /* Character Time-out Indicator */
+		local_rxwrite = uart_rxwrite;
+		local_rxread = uart_rxread;
+		while (U0DR) {
+			unsigned char c = UREG(RBR);
+			if (local_rxread !=
+			    ((local_rxwrite+1) % UART_RXBUFSIZE)) {
+				uart_rxbuf[local_rxwrite] = c;
+				local_rxwrite = (local_rxwrite + 1) %
+				    UART_RXBUFSIZE;
+			}
+		}
+		uart_rxwrite = local_rxwrite;
+		event_set(EVENT_UART_INPUT);
+		break;
+
+	case 0x2: /* THRE interrupt */
+		local_txwrite = uart_txwrite;
+		local_txread = uart_txread;
+		for (i = 0; (i < 16) && (local_txwrite != local_txread); i++) {
+			UREG(THR) = uart_txbuf[local_txread];
+			local_txread = (local_txread + 1) % UART_TXBUFSIZE;
+			active = TRUE;
+		}
+		uart_txread = local_txread;
+		if (!active)
+			tx_running = FALSE;
+		break;
+
+	case 0x6: /* Receive Line Status */
+	default: /* Anything else */
+		break;
+	}
+
+	interrupt_clear();
+}
+
+void putstr(char *s) {
+	while (*s) putch(*s++);
+}
+
+void putint(unsigned int n) {
+	char s[11];
+	int i;
+
+	i = 10;
+	s[i] = '\0';
+
+	do {
+		s[--i] = n % 10 + '0';
+	} while ((n /= 10) > 0);
+
+	putstr(s+i);
+}
+
+void putint_s(int n) {
+	char s[12];
+	int i;
+	int neg;
+
+	/* OK, technically, this might not work properly for the most
+	 * negative possible number. Oh well.
+	 */
+	neg = (n < 0);
+	if (neg)
+		n = -n;
+
+	i = 11;
+	s[i] = '\0';
+
+	do {
+		s[--i] = n % 10 + '0';
+	} while ((n /= 10) > 0);
+
+	if (neg)
+		s[--i] = '-';
+
+	putstr(s+i);
+}
+
+void puthex(unsigned int n) {
+	char s[9];
+	int i;
+
+	i = 8;
+	s[i] = '\0';
+
+	do {
+		int x = n % 16;
+		if (x > 9)
+			x += 'A' - '0' - 10;
+		s[--i] = x + '0';
+	} while ((n /= 16) > 0);
+
+	putstr(s+i);
+}
+
+bool getch(char *c) {
+	if (uart_rxread == uart_rxwrite)
+		return FALSE;
+
+	*c = uart_rxbuf[uart_rxread];
+	uart_rxread = (uart_rxread + 1) % UART_RXBUFSIZE;
+	return TRUE;
+}
+#endif