From eab7a03e7ab811e50497f1316f6dac1b622d007f Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Tue, 15 Dec 2009 21:35:02 +0000 Subject: [PATCH] Added support for IRQ triggers on any IO register 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 --- simavr/sim/sim_avr.h | 23 ++++++++++++++++------- simavr/sim/sim_core.c | 20 ++++++++++++++++---- simavr/sim/sim_io.c | 24 ++++++++++++++++++++---- simavr/sim/sim_io.h | 10 ++++++++++ 4 files changed, 62 insertions(+), 15 deletions(-) diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index 01a12b4..cac737f 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -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 diff --git a/simavr/sim/sim_core.c b/simavr/sim/sim_core.c index 9d0f773..197b719 100644 --- a/simavr/sim/sim_core.c +++ b/simavr/sim/sim_core.c @@ -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); } diff --git a/simavr/sim/sim_io.c b/simavr/sim/sim_io.c index 2c6ddef..63862e2 100644 --- a/simavr/sim/sim_io.c +++ b/simavr/sim/sim_io.c @@ -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; +} + diff --git a/simavr/sim/sim_io.h b/simavr/sim/sim_io.h index 588ccca..eeb2f48 100644 --- a/simavr/sim/sim_io.h +++ b/simavr/sim/sim_io.h @@ -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__ */ -- 2.39.5