From: Michel Pollet <buserror@gmail.com>
Date: Tue, 22 Feb 2011 12:50:51 +0000 (+0000)
Subject: core: Add a muxer for IO writes
X-Git-Tag: v1.0a7~26
X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=0fa2d31cec6d8d64fc5dd22bb6e6c8cab538562f;p=sx%2Fsimavr.git

core: Add a muxer for IO writes

It turns out that some core (tiny85 at the very least) are competing
for IO writes on some register.
This patch introduces a muxer callback that can call multiple clients
without impacting performance for the rest of the cores.

The system could be extended for IO read if it proves necessary.

Signed-off-by: Michel Pollet <buserror@gmail.com>
---

diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h
index ae1a3ab..cdaf598 100644
--- a/simavr/sim/sim_avr.h
+++ b/simavr/sim/sim_avr.h
@@ -159,6 +159,24 @@ typedef struct avr_t {
 		} w;
 	} io[MAX_IOs];
 
+	/*
+	 * This block allows sharing of the IO write/read on addresses between
+	 * multiple callbacks. In 99% of case it's not needed, however on the tiny*
+	 * (tiny85 at last) some registers have bits that are used by different
+	 * IO modules.
+	 * If this case is detected, a special "dispatch" callback is installed that
+	 * will handle this particular case, without impacting the performance of the
+	 * other, normal cases...
+	 */
+	int	io_shared_io_count;
+	struct {
+		int used;
+		struct {
+			void * param;
+			void * c;
+		} io[4];
+	} io_shared_io[4];
+
 	// flash memory (initialized to 0xff, and code loaded into it)
 	uint8_t *	flash;
 	// this is the general purpose registers, IO registers, and SRAM
diff --git a/simavr/sim/sim_io.c b/simavr/sim/sim_io.c
index 3ef9d35..e85d0b2 100644
--- a/simavr/sim/sim_io.c
+++ b/simavr/sim/sim_io.c
@@ -48,20 +48,69 @@ void avr_register_io_read(avr_t *avr, avr_io_addr_t addr, avr_io_read_t readp, v
 {
 	avr_io_addr_t a = AVR_DATA_TO_IO(addr);
 	if (avr->io[a].r.param || avr->io[a].r.c) {
-		fputs("Error: avr_register_io_read(): Already registered, refusing to override.\n", stderr);
-		exit(1);
+		if (avr->io[a].r.param != param || avr->io[a].r.c != readp) {
+			fprintf(stderr,
+					"Error: avr_register_io_read(): Already registered, refusing to override.\n");
+			fprintf(stderr,
+					"Error: avr_register_io_read(%04x : %p/%p): %p/%p\n", a,
+					avr->io[a].r.c, avr->io[a].r.param, readp, param);
+			abort();
+		}
 	}
 	avr->io[a].r.param = param;
 	avr->io[a].r.c = readp;
 }
 
+static void
+_avr_io_mux_write(avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
+{
+	int io = (int)param;
+	for (int i = 0; i < avr->io_shared_io[io].used; i++) {
+		avr_io_write_t c = avr->io_shared_io[io].io[i].c;
+		if (c)
+			c(avr, addr, v, avr->io_shared_io[io].io[i].param);
+	}
+}
+
 void avr_register_io_write(avr_t *avr, avr_io_addr_t addr, avr_io_write_t writep, void * param)
 {
 	avr_io_addr_t a = AVR_DATA_TO_IO(addr);
+
+	/*
+	 * Verifying that some other piece of code is not installed to watch write
+	 * on this address. If there is, this code installs a "dispatcher" callback
+	 * instead to handle multiple clients, otherwise, it continues as usual
+	 */
 	if (avr->io[a].w.param || avr->io[a].w.c) {
-		fputs("Error: avr_register_io_write(): Already registered, refusing to override.\n", stderr);
-		exit(1);
+		if (avr->io[a].w.param != param || avr->io[a].w.c != writep) {
+			// if the muxer not already installed, allocate a new slot
+			if (avr->io[a].w.c != _avr_io_mux_write) {
+				int no = avr->io_shared_io_count++;
+				if (avr->io_shared_io_count > 4) {
+					fprintf(stderr,
+							"Error: avr_register_io_write(): Too many shared IO registers.\n");
+					abort();
+				}
+				fprintf(stderr,
+						"Note: avr_register_io_write(%04x): Installing muxer on register.\n", addr);
+				avr->io_shared_io[no].used = 1;
+				avr->io_shared_io[no].io[0].param = avr->io[a].w.param;
+				avr->io_shared_io[no].io[0].c = avr->io[a].w.c;
+				avr->io[a].w.param = (void*)no;
+				avr->io[a].w.c = _avr_io_mux_write;
+			}
+			int no = (int)avr->io[a].w.param;
+			int d = avr->io_shared_io[no].used++;
+			if (avr->io_shared_io[no].used > 4) {
+				fprintf(stderr,
+						"Error: avr_register_io_write(): Too many callbacks on %04x.\n", addr);
+				abort();
+			}
+			avr->io_shared_io[no].io[d].param = param;
+			avr->io_shared_io[no].io[d].c = writep;
+		}
 	}
+
 	avr->io[a].w.param = param;
 	avr->io[a].w.c = writep;
 }