summary refs log tree commit diff
path: root/src/6522.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/6522.c')
-rw-r--r--src/6522.c187
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;
+}