X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=simavr%2Fsim%2Favr_ioport.c;h=24a8a9bd5d6b43497e021304389edc652ad06676;hb=a367ebb0e3cb1b8325d4a0e6a8d616238852a7d4;hp=be306528ad5811ae8897fd7701661eabb7e54dae;hpb=ad7ea664f377587f9e91b6c685e8bbedd8f489d4;p=simavr diff --git a/simavr/sim/avr_ioport.c b/simavr/sim/avr_ioport.c index be30652..24a8a9b 100644 --- a/simavr/sim/avr_ioport.c +++ b/simavr/sim/avr_ioport.c @@ -38,19 +38,14 @@ static uint8_t avr_ioport_read(struct avr_t * avr, avr_io_addr_t addr, void * pa static void avr_ioport_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_ioport_t * p = (avr_ioport_t *)param; - uint8_t oldv = avr->data[addr]; avr_core_watch_write(avr, addr, v); - if (v != oldv) { - // printf("PORT%c(%02x) = %02x (was %02x)\n", p->name, addr, v, oldv); - int mask = v ^ oldv; - - // raise the internal IRQ callbacks - for (int i = 0; i < 8; i++) - if (mask & (1 << i)) - avr_raise_irq(p->io.irq + i, (v >> i) & 1); - avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v); - } + // printf("PORT%c(%02x) = %02x (was %02x)\n", p->name, addr, v, oldv); + + // raise the internal IRQ callbacks + for (int i = 0; i < 8; i++) + avr_raise_irq(p->io.irq + i, (v >> i) & 1); + avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v); } /* @@ -64,6 +59,27 @@ static void avr_ioport_pin_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t avr_ioport_write(avr, p->r_port, avr->data[p->r_port] ^ v, param); } +/* + * This is a the callback for the DDR register. There is nothing much to do here, apart + * from triggering an IRQ in case any 'client' code is interested in the information, + * and restoring all PIN bits marked as output to PORT values. + */ +static void avr_ioport_ddr_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) +{ + avr_ioport_t * p = (avr_ioport_t *)param; + + avr_raise_irq(p->io.irq + IOPORT_IRQ_DIRECTION_ALL, v); + avr_core_watch_write(avr, addr, v); + + const uint8_t oldpin = avr->data[p->r_pin]; + const uint8_t pin = (oldpin & ~v) | (avr->data[p->r_port] & v); + avr_core_watch_write(avr, p->r_pin, pin); + for (int i = 0; i < 8; i++) + if (((oldpin ^ pin) >> i) & 1) + avr_raise_irq(p->io.irq + i, (pin >> i) & 1); + avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, pin); +} + /* * this is our "main" pin change callback, it can be triggered by either the * AVR code, or any external piece of code that see fit to do it. @@ -74,7 +90,7 @@ void avr_ioport_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param) avr_ioport_t * p = (avr_ioport_t *)param; avr_t * avr = p->io.avr; - int output = value & 0x100; + int output = value & AVR_IOPORT_OUTPUT; value &= 0xff; uint8_t mask = 1 << irq->irq; // set the real PIN bit. ddr doesn't matter here as it's masked when read. @@ -116,7 +132,7 @@ static int avr_ioport_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_para if (r->bit.mask == 0xff) r->irq[o++] = &p->io.irq[IOPORT_IRQ_PIN_ALL]; else { - // otherwise fil up the ones needed + // otherwise fill up the ones needed for (int bi = 0; bi < 8; bi++) if (r->bit.mask & (1 << bi)) r->irq[o++] = &p->io.irq[r->bit.bit + bi]; @@ -147,10 +163,24 @@ static int avr_ioport_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_para return res; } +static const char * irq_names[IOPORT_IRQ_COUNT] = { + [IOPORT_IRQ_PIN0] = "=pin0", + [IOPORT_IRQ_PIN1] = "=pin1", + [IOPORT_IRQ_PIN2] = "=pin2", + [IOPORT_IRQ_PIN3] = "=pin3", + [IOPORT_IRQ_PIN4] = "=pin4", + [IOPORT_IRQ_PIN5] = "=pin5", + [IOPORT_IRQ_PIN6] = "=pin6", + [IOPORT_IRQ_PIN7] = "=pin7", + [IOPORT_IRQ_PIN_ALL] = "=all", + [IOPORT_IRQ_DIRECTION_ALL] = ">ddr", +}; + static avr_io_t _io = { - .kind = "io", + .kind = "port", .reset = avr_ioport_reset, .ioctl = avr_ioport_ioctl, + .irq_names = irq_names, }; void avr_ioport_init(avr_t * avr, avr_ioport_t * p) @@ -160,17 +190,18 @@ void avr_ioport_init(avr_t * avr, avr_ioport_t * p) // p->name, p->r_pin, // p->name, p->r_ddr, // p->name, p->r_port); - - // allocate this module's IRQ - p->io.irq_count = IOPORT_IRQ_COUNT; - p->io.irq = avr_alloc_irq(0, p->io.irq_count); - p->io.irq_ioctl_get = AVR_IOCTL_IOPORT_GETIRQ(p->name); avr_register_io(avr, &p->io); avr_register_vector(avr, &p->pcint); + // allocate this module's IRQ + avr_io_setirqs(&p->io, AVR_IOCTL_IOPORT_GETIRQ(p->name), IOPORT_IRQ_COUNT, NULL); + + for (int i = 0; i < IOPORT_IRQ_COUNT; i++) + p->io.irq[i].flags |= IRQ_FLAG_FILTERED; avr_register_io_write(avr, p->r_port, avr_ioport_write, p); avr_register_io_read(avr, p->r_pin, avr_ioport_read, p); avr_register_io_write(avr, p->r_pin, avr_ioport_pin_write, p); + avr_register_io_write(avr, p->r_ddr, avr_ioport_ddr_write, p); }