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); if (a >= MAX_IOs) { AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_write(): IO address 0x%04x out of range (max 0x%04x).\n", a, MAX_IOs); abort(); } /* * 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) { 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) { AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_write(): Too many shared IO registers.\n"); abort(); } AVR_LOG(avr, LOG_TRACE, "IO: 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*)(intptr_t)no; avr->io[a].w.c = _avr_io_mux_write; } int no = (intptr_t)avr->io[a].w.param; int d = avr->io_shared_io[no].used++; if (avr->io_shared_io[no].used > 4) { AVR_LOG(avr, LOG_ERROR, "IO: 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; return; } } avr->io[a].w.param = param; avr->io[a].w.c = writep; }
void avr_register_io_read( avr_t *avr, avr_io_addr_t addr, avr_io_read_t readp, void * param) { avr_io_addr_t a = AVR_DATA_TO_IO(addr); if (avr->io[a].r.param || avr->io[a].r.c) { if (avr->io[a].r.param != param || avr->io[a].r.c != readp) { AVR_LOG(avr, LOG_ERROR, "IO: avr_register_io_read(): Already registered, refusing to override.\n"); AVR_LOG(avr, LOG_ERROR, "IO: 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; }
avr_irq_t * avr_iomem_getirq( avr_t * avr, avr_io_addr_t addr, const char * name, int index) { if (index > 8) return NULL; avr_io_addr_t a = AVR_DATA_TO_IO(addr); if (avr->io[a].irq == NULL) { /* * Prepare an array of names for the io IRQs. Ideally we'd love to have * a proper name for these, but it's not possible at this time. */ char names[9 * 20]; char * d = names; const char * namep[9]; for (int ni = 0; ni < 9; ni++) { if (ni < 8) sprintf(d, "=avr.io%04x.%d", addr, ni); else sprintf(d, "8=avr.io%04x.all", addr); namep[ni] = d; d += strlen(d) + 1; } avr->io[a].irq = avr_alloc_irq(&avr->irq_pool, 0, 9, namep); // 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; } // if given a name, replace the default one... if (name) { int l = strlen(name); char n[l + 10]; sprintf(n, "avr.io.%s", name); free((void*)avr->io[a].irq[index].name); avr->io[a].irq[index].name = strdup(n); } return avr->io[a].irq + index; }
/* * Set a register (r < 256) * if it's an IO register (> 31) also (try to) call any callback that was * registered to track changes to that register. */ static inline void _avr_set_r(avr_t * avr, uint8_t r, uint8_t v) { REG_TOUCH(avr, r); if (r == R_SREG) { avr->data[R_SREG] = v; // unsplit the SREG SET_SREG_FROM(avr, v); SREG(); } if (r > 31) { uint8_t io = AVR_DATA_TO_IO(r); 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); }