From 5b1830d85cd06020f50290b5e5b8e9e5e7049dae Mon Sep 17 00:00:00 2001
From: Michel Pollet <buserror@gmail.com>
Date: Tue, 15 Mar 2011 13:33:54 +0000
Subject: [PATCH] uart: Added logic to regulate data rate

Now uses a data rate thst is proportional to speed.
Could be made a bit better by using the cycle clock count directly,
but this method is a bit clearer

Signed-off-by: Michel Pollet <buserror@gmail.com>
---
 simavr/sim/avr_uart.c | 24 ++++++++++++++++++------
 simavr/sim/avr_uart.h |  4 ++++
 2 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/simavr/sim/avr_uart.c b/simavr/sim/avr_uart.c
index f6000e6..7cb019a 100644
--- a/simavr/sim/avr_uart.c
+++ b/simavr/sim/avr_uart.c
@@ -97,8 +97,9 @@ static uint8_t avr_uart_read(struct avr_t * avr, avr_io_addr_t addr, void * para
 	// made to trigger potential watchpoints
 	v = avr_core_watch_read(avr, addr);
 
-	if (!uart_fifo_isempty(&p->input))
-		avr_cycle_timer_register_usec(avr, 100, avr_uart_rxc_raise, p); // should be uart speed dependent
+	// should always trigger that timer
+//	if (!uart_fifo_isempty(&p->input))
+	avr_cycle_timer_register_usec(avr, p->usec_per_byte, avr_uart_rxc_raise, p);
 
 	return v;
 }
@@ -113,7 +114,17 @@ static void avr_uart_baud_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t
 		baud /= 8;
 	else
 		baud /= 16;
-	printf("UART-%c configured to %04x = %d baud\n", p->name, val, baud);
+
+	const int databits[] = { 5,6,7,8,  /* 'reserved', assume 8 */8,8,8, 9 };
+	int db = databits[avr_regbit_get(avr, p->ucsz) | (avr_regbit_get(avr, p->ucsz2) << 2)];
+	int sb = 1 + avr_regbit_get(avr, p->usbs);
+	int word_size = 1 /* start */ + db /* data bits */ + 1 /* parity */ + sb /* stops */;
+
+	printf("UART-%c configured to %04x = %d bps, %d data %d stop\n",
+			p->name, val, baud, db, sb);
+	// TODO: Use the divider value and calculate the straight number of cycles
+	p->usec_per_byte = 1000000 / (baud / word_size);
+	printf("Roughtly %d usec per bytes\n", (int)p->usec_per_byte);
 }
 
 static void avr_uart_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
@@ -124,7 +135,8 @@ static void avr_uart_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, vo
 		avr_core_watch_write(avr, addr, v);
 
 		avr_regbit_clear(avr, p->udrc.raised);
-		avr_cycle_timer_register_usec(avr, 100, avr_uart_txc_raise, p); // should be uart speed dependent
+		avr_cycle_timer_register_usec(avr,
+				p->usec_per_byte, avr_uart_txc_raise, p); // should be uart speed dependent
 
 		if (p->flags & AVR_UART_FLAG_STDIO) {
 			static char buf[128];
@@ -180,7 +192,7 @@ static void avr_uart_irq_input(struct avr_irq_t * irq, uint32_t value, void * pa
 		return;
 
 	if (uart_fifo_isempty(&p->input))
-		avr_cycle_timer_register_usec(avr, 100, avr_uart_rxc_raise, p); // should be uart speed dependent
+		avr_cycle_timer_register_usec(avr, p->usec_per_byte, avr_uart_rxc_raise, p); // should be uart speed dependent
 	uart_fifo_write(&p->input, value); // add to fifo
 
 //	printf("UART IRQ in %02x (%d/%d) %s\n", value, p->input.read, p->input.write, uart_fifo_isfull(&p->input) ? "FULL!!" : "");
@@ -201,7 +213,7 @@ void avr_uart_reset(struct avr_io_t *io)
 
 	// DEBUG allow printf without fidding with enabling the uart
 	avr_regbit_set(avr, p->txen);
-
+	p->usec_per_byte = 100;
 }
 
 static int avr_uart_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param)
diff --git a/simavr/sim/avr_uart.h b/simavr/sim/avr_uart.h
index 4764e72..dc9e805 100644
--- a/simavr/sim/avr_uart.h
+++ b/simavr/sim/avr_uart.h
@@ -92,6 +92,9 @@ typedef struct avr_uart_t {
 	avr_regbit_t	rxen;		// receive enabled
 	avr_regbit_t	txen;		// transmit enable
 	avr_regbit_t	u2x;		// double UART speed
+	avr_regbit_t	usbs;		// stop bits
+	avr_regbit_t	ucsz;		// data bits
+	avr_regbit_t	ucsz2;		// data bits, continued
 
 	avr_io_addr_t r_ubrrl,r_ubrrh;
 
@@ -102,6 +105,7 @@ typedef struct avr_uart_t {
 	uart_fifo_t	input;
 
 	uint32_t		flags;
+	avr_cycle_count_t usec_per_byte;
 } avr_uart_t;
 
 /* takes a uint32_t* as parameter */
-- 
2.39.5