Commit 0fa2d31cec6d8d64fc5dd22bb6e6c8cab538562f
authorMichel Pollet <buserror@gmail.com>
Tue, 22 Feb 2011 12:50:51 +0000 (12:50 +0000)
committerMichel Pollet <buserror@gmail.com>
Tue, 22 Feb 2011 12:50:51 +0000 (12:50 +0000)
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>
2 files changed:
simavr/sim/sim_avr.h
simavr/sim/sim_io.c

index ae1a3ab5055b32e03771d5df9add21b46a53bd95..cdaf598668a40a09c7ee2e3888a5317e4afc67e6 100644 (file)
@@ -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
index 3ef9d3526e0ea2b1f636176639e201503b6bb23e..e85d0b2c655507163710cb164febed6522bf67f6 100644 (file)
@@ -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;
 }