summaryrefslogtreecommitdiff
path: root/igen/sux-igen
diff options
context:
space:
mode:
authormrb0nk500 <b0nk@b0nk.xyz>2022-02-13 20:20:59 -0400
committermrb0nk500 <b0nk@b0nk.xyz>2022-02-13 20:20:59 -0400
commitf478e6c1223cc8370fa51d44b9244ec25be99788 (patch)
tree4abe8889888c0b098ea99ee020c446254822a923 /igen/sux-igen
parent6833f6bc2a5730169084c74d8e8fc0b76666b2a0 (diff)
igen: Start work on writing an instruction handler
generator. This will make it easier in the long run to modify instructions, add new instructions, and move the opcode tables around.
Diffstat (limited to 'igen/sux-igen')
-rw-r--r--igen/sux-igen/addr-modes.igen91
-rw-r--r--igen/sux-igen/inst.igen245
-rw-r--r--igen/sux-igen/utils.igen50
3 files changed, 386 insertions, 0 deletions
diff --git a/igen/sux-igen/addr-modes.igen b/igen/sux-igen/addr-modes.igen
new file mode 100644
index 0000000..3780ed2
--- /dev/null
+++ b/igen/sux-igen/addr-modes.igen
@@ -0,0 +1,91 @@
+#include "utils.igen"
+
+%%
+
+/*
+am((abs|zm)[xy]?) {
+ if (am == zmx || am == absx) {
+ idx = cpu->x;
+ } else if (am == zmy || am == absy) {
+ idx = cpu->y;
+ }
+
+ if (am == abs || am == absx || am == absy) {
+ is_abs = 1;
+ }
+
+ size = ((prefix & 0xC) >> 1) | is_abs;
+ addr = read(cpu->pc, size) + idx;
+ value = read(addr, rs);
+}
+
+am((a)?ind([xy])?) {
+ if (am == indx || am == aindx) {
+ idx = cpu->x;
+ pre_idx = 1;
+ } else if (am == indy || am == aindy) {
+ idx = cpu->y;
+ }
+
+ if (am == aind || am == aindx || am == aindy) {
+ is_abs = 1;
+ }
+
+ size = ((prefix & 0xC) >> 1) | is_abs;
+
+ if (pre_idx) {
+ addr = read(read(cpu->pc + idx, size), 7);
+ } else {
+ addr = read(read(cpu->pc, size), 7) + idx;
+ }
+
+ value = read(addr, rs);
+}
+
+am(eind) {
+ addr = cpu->e;
+ value = read(addr, rs);
+}
+*/
+
+am(abs|zm([xy])?) {
+ if (am == abs) {
+ mem_type = ABS;
+ } else {
+ if (am == zmx) {
+ idx = cpu->x;
+ } else if (am == zmy) {
+ idx = cpu->y;
+ }
+ mem_type = ZM;
+ }
+ addr = read_addr(prefix, mem_type) + idx;
+ value = read(addr, rs);
+}
+
+am(ind([xy])?) {
+ if (am == indx) {
+ idx = cpu->x;
+ pre_idx = 1;
+ } else if (am == indy) {
+ idx = cpu->y;
+ }
+ mem_type = ZM;
+ addr = ind_idx_addr(prefix, mem_type, idx, pre_idx);
+ value = read(addr, rs);
+}
+
+am(rel) {
+ addr = rel_addr(prefix);
+}
+
+am(imm) {
+ value = read(cpu->pc, rs);
+ cpu->pc += rs+1;
+}
+
+am(breg) {
+ value = cpu->b;
+}
+
+%%
diff --git a/igen/sux-igen/inst.igen b/igen/sux-igen/inst.igen
new file mode 100644
index 0000000..791ad2c
--- /dev/null
+++ b/igen/sux-igen/inst.igen
@@ -0,0 +1,245 @@
+#include "utils.igen"
+#include "addr-modes.igen"
+
+%%
+
+(ad|sb|breg(in|de))c, and, (or|st|ld|t[bxy]|p[hl])a, xor, (ls|ro)[lr], mul, div, asr, cmp {
+ reg = &cpu->a;
+}
+
+(ld|st|cp|in|de|ta|p[hl])b {
+ reg = &cpu->b;
+}
+
+(ld|st|cp|in|de|t[ays]|p[hl])x {
+ reg = &cpu->x;
+}
+
+(ld|st|cp|in|de|t[ax]|p[hl])y {
+ reg = &cpu->y;
+}
+
+txs {
+ reg = &cpu->sp;
+}
+
+cps, (cl|se)[cio], clv, b(po|n[ge]|[cv][sc]|eq|r[ak]), p[hl]p {
+ reg = &cpu->ps;
+}
+
+ta[bxy] {
+ reg2 = &cpu->a;
+}
+
+tba, ~breg(div) {
+ reg2 = &cpu->b;
+}
+
+tx[ay], breg(div) {
+ reg2 = &cpu->x;
+}
+
+ty[ax] {
+ reg2 = &cpu->y;
+}
+
+tsx {
+ reg2 = &cpu->sp;
+}
+
+ld[abxy] {
+ *reg = value;
+ update_flags_nz(value);
+}
+
+st[abxy] {
+ value = *reg;
+ write(value, addr, rs);
+}
+
+(in|de)[cbxy] {
+ if (addr_mode == impl) {
+ value = *reg;
+ }
+ if (inst.match[0] == in) {
+ ++value;
+ } else if (inst.match[0] == de) {
+ --value;
+ }
+ if (addr_mode != impl) {
+ msb = rs*8;
+ write(value, addr, rs);
+ } else {
+ *reg = value;
+ }
+ update_flags_nz(value);
+}
+
+ph[abxyp] {
+ if (inst == php) {
+ rs = 0;
+ }
+ push(*reg, rs);
+}
+
+pl[abxyp] {
+ if (inst == plp) {
+ rs = 0;
+ }
+ *reg = pull(rs);
+}
+
+/*
+ora, and, xor {
+ switch (inst) {
+ case and: sum = *reg & value; break;
+ case ora: sum = *reg | value; break;
+ case xor: sum = *reg ^ value; break;
+ }
+ *reg = sum;
+ update_flags_nz(sum);
+}
+*/
+
+ora {
+ sum = *reg | value;
+ *reg = sum;
+ update_flags_nz(sum);
+}
+
+and {
+ sum = *reg & value;
+ *reg = sum;
+ update_flags_nz(sum);
+}
+
+xor {
+ sum = *reg ^ value;
+ *reg = sum;
+ update_flags_nz(sum);
+}
+
+(se|cl)c {
+ cpu->ps.C = (inst == sec);
+}
+
+(se|cl)i {
+ cpu->ps.I = (inst == sei);
+}
+
+(se|cl)o {
+ if (ext == base && mode == base) {
+ cpu->ps.O = (inst == seo);
+ }
+}
+
+clv {
+ cpu->ps.V = 0;
+}
+
+cps {
+ cpu->ps = 0;
+}
+
+b(po|ng) {
+ cpu->pc = jump(addr, cpu->pc, get_flag(inst, bpo, cpu->ps.N));
+}
+
+bc[sc] {
+ cpu->pc = jump(addr, cpu->pc, get_flag(inst, bcs, cpu->ps.C));
+}
+
+b(ne|eq) {
+ cpu->pc = jump(addr, cpu->pc, get_flag(inst, beq, cpu->ps.Z));
+}
+
+bv[sc] {
+ cpu->pc = jump(addr, cpu->pc, get_flag(inst, bvs, cpu->ps.V));
+}
+
+bra, j(mp|sr) {
+ if (inst == jsr) {
+ push(cpu->pc, (rs) ? rs : 7);
+ }
+ cpu->pc = jump(addr, cpu->pc, 1);
+}
+
+intr(irq|nmi|reset), brk, wai {
+ if (inst == nmi) {
+ addr = 0xFFA0;
+ } else if (inst == reset) {
+ addr = 0xFFC0;
+ } else if (inst == irq) {
+ addr = 0xFFE0;
+ } else {
+ addr = 0xFFF0;
+ }
+
+ if (inst != reset) {
+ if (!cpu->is_wait) {
+ push(cpu->pc, 7);
+ push(cpu->ps, 0);
+ cpu->ps.I = 1;
+ }
+ cpu->is_wait = (inst == wai);
+ }
+ if (inst != wai) {
+ addr = read(addr, 7);
+ cpu->pc = jump(addr, cpu->pc, 1);
+ }
+}
+
+rt[si] {
+ if (inst == rti) {
+ cpu->ps = pull(0);
+ }
+ cpu->pc = pull(7);
+}
+
+(ad|sb)c {
+ if (inst == sbc) {
+ value = ~value;
+ }
+ *reg = adc(*reg, value, cpu->ps.C);
+}
+
+c(mp|p[bxy]) {
+ adc(*reg, ~value, 1);
+}
+
+(asr|ls[lr]) {
+ if (inst == lsl) {
+ sum = (value < msb) ? shift(*reg, value, 0, <<) : 0;
+ cpu->ps.C = (*reg >> (msb-(value+!value))) & 1;
+ } else {
+ if (inst == asr) {
+ sign = -(uint64_t)(*reg >> (msb-1)) << (msb-1)-value;
+ }
+ sum = (value < msb) ? shift(*reg, value, sign, >>) : 0;
+ cpu->ps.C = (*reg >> (value-(value != 0))) & 1;
+ }
+}
+
+ro[lr] {
+ if (inst == rol) {
+ rotate(sum, *reg, value, <<, >>, cpu->ps.C, cpu->ps.C << (value-1));
+ cpu->ps.C = (*reg >> (msb-(value+!value))) & 1;
+ } else {
+ rotate(sum, *reg, value, >>, <<, cpu->ps.C << (msb-1), cpu->ps.C << (msb-value));
+ cpu->ps.C = (*reg >> (value-(value != 0))) & 1;
+ }
+}
+
+mul {
+ *reg = mul(*reg, value);
+}
+
+div {
+ *reg = div(*reg, value, reg2);
+}
+
+t(a[bxy]|ba|x[ays]|y[ax]|sx) {
+ *reg = *reg2;
+ update_flags_nz(*reg);
+}
+%%
diff --git a/igen/sux-igen/utils.igen b/igen/sux-igen/utils.igen
new file mode 100644
index 0000000..7385117
--- /dev/null
+++ b/igen/sux-igen/utils.igen
@@ -0,0 +1,50 @@
+update_flags_nz(value) {
+ cpu->ps.N = bit(value, msb-1);
+ cpu->ps.Z = value == 0;
+}
+
+get_flag(name, match, flag) {
+ if (name == match) {
+ return flag;
+ } else {
+ return !flag;
+ }
+}
+
+jump(addr, fallback, flag) {
+ if (flag) {
+ return addr;
+ } else {
+ return fallback;
+ }
+}
+
+read(addr, size) {
+ return read_value(addr, size);
+}
+
+write(value, addr, size) {
+ write_value(value, addr, size);
+}
+
+adc(a, b, carry) {
+ sum = a + b + carry;
+ update_flags_nz(sum);
+ cpu->ps.C = sum < b;
+ cpu->ps.V = bit(a^b, msb-1) && bit(a^sum, msb-1);
+ return sum;
+}
+
+mul(a, b) {
+ sum = a * b;
+ update_flags_nz(sum);
+ cpu->ps.V = bit(a^b, msb-1) && bit(a^sum, msb-1);
+ return sum;
+}
+
+div(a, b, *rem) {
+ sum = a / b;
+ *rem = a % b;
+ update_flags_nz(sum);
+ return sum;
+}