diff options
author | mrb0nk500 <b0nk@b0nk.xyz> | 2022-02-13 20:20:59 -0400 |
---|---|---|
committer | mrb0nk500 <b0nk@b0nk.xyz> | 2022-02-13 20:20:59 -0400 |
commit | f478e6c1223cc8370fa51d44b9244ec25be99788 (patch) | |
tree | 4abe8889888c0b098ea99ee020c446254822a923 /igen/sux-igen | |
parent | 6833f6bc2a5730169084c74d8e8fc0b76666b2a0 (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.igen | 91 | ||||
-rw-r--r-- | igen/sux-igen/inst.igen | 245 | ||||
-rw-r--r-- | igen/sux-igen/utils.igen | 50 |
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; +} |