Commit eab7a03e7ab811e50497f1316f6dac1b622d007f
authorMichel Pollet <buserror@gmail.com>
Tue, 15 Dec 2009 21:35:02 +0000 (21:35 +0000)
committerMichel Pollet <buserror@gmail.com>
Tue, 15 Dec 2009 21:35:02 +0000 (21:35 +0000)
Each IO address has it's own IRQ list now, dynamicaly
allocated when needed. It allows any code to register
an IRQ callback for any change made to any register.

Even registers that have no IO drivers (yet?) can be
monitored.

As a silver lining, this means any register or register bit
can be traced in a VCD file and displayed in gtkwave.

Signed-off-by: Michel Pollet <buserror@gmail.com>
4 files changed:
simavr/sim/sim_avr.h
simavr/sim/sim_core.c
simavr/sim/sim_io.c
simavr/sim/sim_io.h

index 01a12b4d6d456ab0363abd00b6d1b5a8ba35172f..cac737fde2dfc7586010c486ba19e4c70c8adcdc 100644 (file)
@@ -107,13 +107,16 @@ typedef struct avr_t {
         * these should probably be allocated dynamically in init()..
         */
        struct {
-               void * param;
-               avr_io_read_t r;
-       } ior[MAX_IOs];
-       struct {
-               void * param;
-               avr_io_write_t w;
-       } iow[MAX_IOs];
+               struct avr_irq_t * irq; // optional, used only if asked for with avr_iomem_getirq()
+               struct {
+                       void * param;
+                       avr_io_read_t c;
+               } r;
+               struct {
+                       void * param;
+                       avr_io_write_t c;
+               } w;
+       } io[MAX_IOs];
 
        // flash memory (initialized to 0xff, and code loaded into it)
        uint8_t *       flash;
@@ -174,6 +177,12 @@ typedef struct avr_t {
        uint32_t        touched[256 / 32];      // debug
 #endif
 
+       // this is the VCD file that gets allocated if the 
+       // firmware that is loaded explicitely asks for a trace
+       // to be generated, and allocates it's own symbols
+       // using AVR_MMCU_TAG_VCD_TRACE (see avr_mcu_section.h)
+       struct avr_vcd_t * vcd;
+       
        // gdb hooking structure. Only present when gdb server is active
        struct avr_gdb_t * gdb;
        // if non-zero, the gdb server will be started when the core
index 9d0f773ebdbee5b06dd219dc922e4131fe10cb91..197b71991635877d516e136753ebe28bd44f6f19 100644 (file)
@@ -101,10 +101,15 @@ static inline void _avr_set_r(avr_t * avr, uint8_t r, uint8_t v)
        }
        if (r > 31) {
                uint8_t io = AVR_DATA_TO_IO(r);
-               if (avr->iow[io].w)
-                       avr->iow[io].w(avr, r, v, avr->iow[io].param);
+               if (avr->io[io].w.c)
+                       avr->io[io].w.c(avr, r, v, avr->io[io].w.param);
                else
                        avr->data[r] = v;
+               if (avr->io[io].irq) {
+                       avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v);
+                       for (int i = 0; i < 8; i++)
+                               avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1);                               
+               }
        } else
                avr->data[r] = v;
 }
@@ -141,8 +146,15 @@ static inline uint8_t _avr_get_ram(avr_t * avr, uint16_t addr)
 {
        if (addr > 31 && addr < 256) {
                uint8_t io = AVR_DATA_TO_IO(addr);
-               if (avr->ior[io].r)
-                       avr->data[addr] = avr->ior[io].r(avr, addr, avr->ior[io].param);
+               if (avr->io[io].r.c)
+                       avr->data[addr] = avr->io[io].r.c(avr, addr, avr->io[io].r.param);
+               
+               if (avr->io[io].irq) {
+                       uint8_t v = avr->data[addr];
+                       avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v);
+                       for (int i = 0; i < 8; i++)
+                               avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1);                               
+               }
        }
        return avr_core_watch_read(avr, addr);
 }
index 2c6ddef849ff2c0838aeebe1f605c865c1e2d0bd..63862e2be3f0cc54d9d83806b938fffcc833b34e 100644 (file)
@@ -46,14 +46,16 @@ void avr_register_io(avr_t *avr, avr_io_t * io)
 
 void avr_register_io_read(avr_t *avr, avr_io_addr_t addr, avr_io_read_t readp, void * param)
 {
-       avr->ior[AVR_DATA_TO_IO(addr)].param = param;
-       avr->ior[AVR_DATA_TO_IO(addr)].r = readp;
+       avr_io_addr_t a = AVR_DATA_TO_IO(addr);
+       avr->io[a].r.param = param;
+       avr->io[a].r.c = readp;
 }
 
 void avr_register_io_write(avr_t *avr, avr_io_addr_t addr, avr_io_write_t writep, void * param)
 {
-       avr->iow[AVR_DATA_TO_IO(addr)].param = param;
-       avr->iow[AVR_DATA_TO_IO(addr)].w = writep;
+       avr_io_addr_t a = AVR_DATA_TO_IO(addr);
+       avr->io[a].w.param = param;
+       avr->io[a].w.c = writep;
 }
 
 struct avr_irq_t * avr_io_getirq(avr_t * avr, uint32_t ctl, int index)
@@ -67,3 +69,17 @@ struct avr_irq_t * avr_io_getirq(avr_t * avr, uint32_t ctl, int index)
        return NULL;
        
 }
+
+
+avr_irq_t * avr_iomem_getirq(avr_t * avr, avr_io_addr_t addr, int index)
+{
+       avr_io_addr_t a = AVR_DATA_TO_IO(addr);
+       if (avr->io[a].irq == NULL) {
+               avr->io[a].irq = avr_alloc_irq(0, 9);
+               // mark the pin ones as filtered, so they only are raised when changing
+               for (int i = 0; i < 8; i++)
+                       avr->io[a].irq[i].flags |= IRQ_FLAG_FILTERED;
+       }
+       return index < 9 ? avr->io[a].irq + index : NULL;
+}
+
index 588cccaa59d5d592bcc0ede587e4965d261c3f99..eeb2f4887e4789e28bbfb6d6545cc931924dfacc 100644 (file)
@@ -68,4 +68,14 @@ int avr_ioctl(avr_t *avr, uint32_t ctl, void * io_param);
 // get the specific irq for a module, check AVR_IOCTL_IOPORT_GETIRQ for example
 struct avr_irq_t * avr_io_getirq(avr_t * avr, uint32_t ctl, int index);
 
+// get the IRQ for an absolute IO address
+// this allows any code to hook an IRQ in any io address, for example
+// tracing changes of values into a register
+// Note that the values do not "magicaly" change, they change only
+// when the AVR code attempt to read and write at that address
+// 
+// the "index" is a bit number, or ALL bits if index == 8
+#define AVR_IOMEM_IRQ_ALL 8
+struct avr_irq_t * avr_iomem_getirq(avr_t * avr, avr_io_addr_t addr, int index);
+
 #endif /* __SIM_IO_H__ */