The unified diff between revisions [8760ae92..] and [cbddc8b3..] 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 [cbddc8b347cfe68cf634efaf314c99652ed27527]
#
# add_file "uart.c"
#  content [cd75769ab8ffb66cd0ff19a158def1fadbbbe56f]
#
============================================================
--- /dev/null	
+++ uart.c	cd75769ab8ffb66cd0ff19a158def1fadbbbe56f
@@ -0,0 +1,155 @@
+#include "uart.h"
+#include "types.h"
+#include "interrupt.h"
+
+#define UARTBASE 0xE000C000
+
+#define FP0XVAL (*((volatile unsigned int *) 0x3FFFC014))
+
+#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_BUFSIZE 128
+
+char uart_txbuf[UART_BUFSIZE];
+volatile int uart_txread;
+volatile int uart_txwrite;
+volatile bool tx_running;
+
+void __attribute__((interrupt("IRQ"))) uart_interrupt_handler(void);
+
+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;
+	tx_running = FALSE;
+	interrupt_register(UART0, uart_interrupt_handler);
+
+	UREG(IER) = 0x02; /* THRE interrupt enable */
+}
+
+void putch(char c) {
+	/* Wait for space in the buffer */
+	while (uart_txread == ((uart_txwrite+1) % UART_BUFSIZE));
+
+	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_BUFSIZE;
+
+	if (!tx_running) {
+		if (uart_txread != uart_txwrite) {
+			tx_running = TRUE;
+			uart_txread = (uart_txread + 1) % UART_BUFSIZE;
+			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 = uart_txwrite;
+	int local_txread = uart_txread;
+
+	source = UREG(IIR);
+
+	/* For now we assume that all interrupts are actually THR empty
+	 * interrupts. Actually check this when we do more things with
+	 * the UART
+	 */
+
+	if (U0THRE) {
+		for (i = 0; (i < 16) && (local_txwrite != local_txread); i++) {
+			UREG(THR) = uart_txbuf[local_txread];
+			local_txread = (local_txread + 1) % UART_BUFSIZE;
+			active = TRUE;
+		}
+	}
+
+	uart_txread = local_txread;
+
+	if (!active)
+		tx_running = FALSE;
+
+	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 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);
+}
+
+char getch(void) {
+	while (!U0DR) {
+		FP0XVAL ^= 0x04000000;
+	}
+	return UREG(RBR);
+}