diff options
author | Maxwell Beck <max@rastertail.net> | 2024-12-24 10:54:02 -0600 |
---|---|---|
committer | Maxwell Beck <max@rastertail.net> | 2024-12-24 10:54:02 -0600 |
commit | c684c194bccdb08df75423680ba334739a945fe5 (patch) | |
tree | ea052b7f413936629421fbb784aaea1dedb8133c /src/6522.c |
Initial commit
Diffstat (limited to 'src/6522.c')
-rw-r--r-- | src/6522.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/6522.c b/src/6522.c new file mode 100644 index 0000000..89bc102 --- /dev/null +++ b/src/6522.c @@ -0,0 +1,187 @@ +#include "6522.h" + +void via_init(via_t *via) { + via->ira = 0; + via->irb = 0; + via->ora = 0; + via->orb = 0; + via->ddra = 0; + via->ddrb = 0; + via->tca = 0; + via->tcb = 0; + via->tla = 0; + via->tlb = 0; + via->acr = 0; + via->pcr = 0; + via->ifr = 0; + via->ier = 0; + + via->tav = true; + via->tbv = true; +} + +void via_read(via_t *via, uint8_t addr, uint8_t *v, uint8_t cycle) { + uint16_t tca = via->tca - cycle; + uint16_t tcb = via->tcb - cycle; + + switch (addr) { + case 0: + via_pb_read(via, cycle); + *v = (via->irb & ~via->ddrb) | (via->orb & via->ddrb); + via->ifr &= 0b11100111; + if (via->ifr == 0x80) via->ifr = 0; + break; + case 1: + via_pa_read(via, cycle); + *v = via->ira; + via->ifr &= 0b11111100; + if (via->ifr == 0x80) via->ifr = 0; + break; + case 2: + *v = via->ddrb; + break; + case 3: + *v = via->ddra; + break; + case 4: + *v = tca & 0xff; + via->ifr &= 0b10111111; + if (via->ifr == 0x80) via->ifr = 0; + break; + case 5: + *v = (tca & 0xff00) >> 8; + break; + case 6: + *v = via->tla & 0xff; + break; + case 7: + *v = (via->tla & 0xff00) >> 8; + break; + case 8: + *v = tcb & 0xff; + via->ifr &= 0b11011111; + if (via->ifr == 0x80) via->ifr = 0; + break; + case 9: + *v = (tcb & 0xff00) >> 8; + case 11: + *v = via->acr; + break; + case 12: + *v = via->pcr; + break; + case 13: + *v = via->ifr; + break; + case 14: + *v = via->ier | 0x80; + break; + default: + break; + } +} + +void via_write(via_t *via, uint8_t addr, uint8_t v, uint8_t cycle) { + switch (addr) { + case 0: + via->orb = v; + via_pb_write(via, cycle); + via->ifr &= 0b11100111; + if (via->ifr == 0x80) via->ifr = 0; + break; + case 1: + via->ora = v; + via_pa_write(via, cycle); + via->ifr &= 0b11111100; + if (via->ifr == 0x80) via->ifr = 0; + break; + case 2: + via->ddrb = v; + via_pb_write(via, cycle); + break; + case 3: + via->ddra = v; + via_pa_write(via, cycle); + break; + case 4: + via->tla = (via->tla & 0xff00) | v; + break; + case 5: + via->tla = (via->tla & 0xff) | (v << 8); + via->tca = via->tla + cycle + 1; + via->ifr &= 0b10111111; + if (via->ifr == 0x80) via->ifr = 0; + via->tav = false; + break; + case 6: + via->tla = (via->tla & 0xff00) | v; + break; + case 7: + via->tla = (via->tla & 0xff) | (v << 8); + via->ifr &= 0b10111111; + if (via->ifr == 0x80) via->ifr = 0; + break; + case 8: + via->tlb = (via->tlb & 0xff00) | v; + break; + case 9: + via->tlb = (via->tlb & 0xff) | (v << 8); + via->tcb = via->tlb + cycle + 1; + via->tbv = false; + via->ifr &= 0b11011111; + if (via->ifr == 0x80) via->ifr = 0; + break; + case 11: + via->acr = v; + break; + case 12: + via->pcr = v; + break; + case 13: + via->ifr &= ~(v & 0x7f); + if (via->ifr == 0x80) via->ifr = 0; + break; + case 14: + if (v & 0x80) { + via->ier |= v & 0x7f; + } else { + via->ier &= ~v; + } + break; + default: + break; + } +} + +void via_cycle(via_t *via, uint8_t cycles) { + if (!via->tav) { + uint16_t tca = via->tca - cycles; + + if (tca > via->tca) { + via->ifr |= 0b11000000; + if ((via->acr & 0b01000000) == 0) { + tca = via->tla; + via->tav = true; + } else { + tca = via->tla + tca + 1; + } + } + + via->tca = tca; + } + + uint16_t tcb = via->tcb - cycles; + + if (tcb > via->tcb) { + if (!via->tbv) { + via->ifr |= 0b10100000; + } + via->tbv = true; + } + + via->tcb = tcb; +} + +bool via_irq(via_t *via) { + return (via->ifr & via->ier) > 0; +} |