diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 10 | ||||
-rwxr-xr-x | asm.py | 40 | ||||
-rw-r--r-- | cpu.ha | 130 | ||||
-rwxr-xr-x | disasm.py | 29 | ||||
-rwxr-xr-x | mnems.py | 45 | ||||
-rw-r--r-- | opc_impl.ha | 134 | ||||
-rw-r--r-- | r1b.txt | 14 |
8 files changed, 327 insertions, 78 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cba89c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +opcodes.ha +*.py[cod] + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..23120d0 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +.POSIX: +.SUFFIXES: + +run: opcodes.ha + hare run + +opcodes.ha: mnems.py + ./mnems.py >opcodes.ha + +.PHONY: run @@ -1,39 +1,6 @@ #!/usr/bin/env python3 -mnems = """ -nop -rot -nrt -dup -swp -ovr -drp -tck -nip -equ -neq -add -sub -mul -div -neg -slt -ult -sle -ule -lod -sto -psh -pop -""".split() -mnems.extend(['???']*(64-len(mnems))) -def opws(kw): - for k in range(16): - mnems.append(kw + str(k)) -opws("mark") # who is mark -opws("loc") -opws("ret") -opws("lit") +from mnems import mnems # print(mnems) import sys @@ -81,7 +48,7 @@ def assemble_line(args, lineno): opc2 = mnems.index(i2) emit_instrs(opc1, opc2) case ["l", val]: - emit_lit(int(val)) + emit_lit(int(val,16)) case [':', label]: if label in labels: @@ -145,9 +112,6 @@ def jump_instr(target, origin): rel = target - origin + 2048 return (rel&0b111111111111)|0b0100000000000000 - - - import sys def main(): for ix, line in enumerate(sys.stdin): @@ -0,0 +1,130 @@ +use endian; +use io; +use os; +use fs; +use fmt; + +type stack_overflow = !void; +type stack_underflow = !void; + +type cpu = struct { + sp: u8, + rp: u8, + pc: u16, + mem: []u8, + halted: bool, +}; + +fn cpu_new() cpu = cpu { + sp = 0, + rp = 0, + pc = 0x0200, + mem = alloc([0...], 65536): []u8, + halted = false, +}; + +fn rmem(mem: []u8, addr: u16) u16 = + endian::begetu16(mem[addr..addr+2]); +fn wmem(mem: []u8, addr: u16, w: u16) void = + endian::beputu16(mem[addr..addr+2], w); + +// stacks grow up, for a change +fn push(cpu: *cpu, val: u16) void = { + wmem(cpu.mem, 0 + cpu.sp, val); + cpu.sp += 2; +}; +fn pop(cpu: *cpu) u16 = { + cpu.sp -= 2; + return rmem(cpu.mem, 0 + cpu.sp); +}; +fn peek(cpu: *cpu, n: u16 = 0) u16 = + rmem(cpu.mem, 0 + cpu.sp - 2 + n); + + +fn rpush(cpu: *cpu, val: u16) void = { + wmem(cpu.mem, 0x100 + cpu.rp:u16, val); + cpu.rp += 2; +}; +fn rpop(cpu: *cpu) u16 = { + cpu.rp -= 2; + return rmem(cpu.mem, 0x100 + cpu.rp:u16); +}; + + + +def MASK_CALL: u16 = 0b1000000000000000; +def MASK_LIT : u16 = 0b0110000000000000; +def MASK_JMP : u16 = 0b0100000000000000; +fn maskeq(x: u16, m: u16) bool = + // still must be called in the right order + (x&m) == m; + +fn do_word(cpu: *cpu, word: u16) void = { + if (maskeq(word, MASK_CALL)) { + const addr = word & 0b0111111111111111; + const addr = addr << 1; + do_call(cpu, addr); + } else if (maskeq(word, MASK_LIT)) { + const lval = word & 0b0001111111111111; + push(cpu, lval); + } else if (maskeq(word, MASK_JMP)) { + const is_cond = (word & 0b0001000000000000) != 0; + const rel: u16 = word & 0b0000111111111111; + const rel: i16 = rel:i16 - 2048i16; + const target: i16 = rel + cpu.pc:i16 - 2i16; + const target: u16 = target:u16; + if (is_cond) + do_0branch(cpu, target) + else + do_jmp(cpu, target); + } else { + const opc1: u8 = ((word & 0b0011111110000000) >> 7):u8; + const opc2: u8 = (word & 0b0000000001111111):u8; + do_opc(cpu, opc1); + do_opc(cpu, opc2); + }; +}; + +fn do_call(cpu: *cpu, addr: u16) void = { + rpush(cpu, cpu.pc); + cpu.pc = addr; +}; + +fn do_jmp(cpu: *cpu, addr: u16) void = { + cpu.pc = addr; +}; + +fn do_0branch(cpu: *cpu, addr: u16) void = { + const val = pop(cpu); + if (val == 0) { + cpu.pc = addr; + }; +}; + +fn mainloop(cpu: *cpu) void = { + for (! cpu.halted) { + const word = rmem(cpu.mem, cpu.pc); + cpu.pc += 2; + do_word(cpu, word); + }; +}; + +export fn main() void = { + const cpu = cpu_new(); + const fp = match (os::open("sys0.r1b")) { + case let i: io::file => yield i; + case let e: fs::error => fmt::fatalf("MISSING BOOT SECTOR: {}", + fs::strerror(e)); + }; + + match (io::readall(fp, cpu.mem[0x0200..0x0300])) { + case let e: io::error => fmt::fatalf("BOOT SECTOR READ ERROR: {}", io::strerror(e)); + case => yield; + }; + + mainloop(&cpu); +}; + + + + @@ -1,33 +1,8 @@ #!/usr/bin/env python3 import sys -mnems = """ -nop -rot -nrt -dup -swp -ovr -drp -tck -nip -equ -neq -add -sub -mul -div -neg -slt -ult -sle -ule -lod -sto -psh -pop -""".split() -mnems.extend(['???']*(64-len(mnems))) +from mnems import mnems + def opws(kw): for k in range(16): mnems.append(kw + str(k)) diff --git a/mnems.py b/mnems.py new file mode 100755 index 0000000..db00fbc --- /dev/null +++ b/mnems.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 + +mnems = """ +nop +rot +nrt +dup +swp +ovr +drp +tck +nip +equ +neq +add +sub +mul +div +neg +slt +ult +sle +ule +lod +sto +psh +pop +hlt +put +""".split() +mnems.extend(['???']*(64-len(mnems))) +def opws(kw): + for k in range(16): + mnems.append(kw + str(k)) +opws("mark") # who is mark +opws("loc") +opws("ret") +opws("lit") + +if __name__ == "__main__": + print("type op = enum u8 {") + for opc,mnem in enumerate(mnems): + if mnem != "???": + print(f"\t{mnem.upper()} = {opc},") + print("};") diff --git a/opc_impl.ha b/opc_impl.ha new file mode 100644 index 0000000..f85be5f --- /dev/null +++ b/opc_impl.ha @@ -0,0 +1,134 @@ +use fmt; + +fn do_opc(cpu: *cpu, opc: u8) void = + if (0 <= opc && opc < op::MARK0) do_opr(cpu, opc) + else if (op::MARK0 <= opc && opc <= op::MARK15) + // who is mark + do_op_mark(cpu, opc-op::MARK0) + else if (op::LOC0 <= opc && opc <= op::LOC15) + do_op_loc(cpu, opc-op::LOC0) + else if (op::RET0 <= opc && opc <= op::RET15) + do_op_ret(cpu, opc-op::RET0) + else if (op::LIT0 <= opc && opc <= op::LIT15) + do_op_lit(cpu, opc-op::LIT0) + else abort("what???"); + +fn do_op_mark(cpu: *cpu, p: u8) void = + cpu.rp += p*2; + +fn do_op_loc(cpu: *cpu, p: u8) void = + push(cpu, 0x100 + cpu.rp:u16 - (p-1)*2); + +fn do_op_ret(cpu: *cpu, p: u8) void = { + cpu.rp -= p*2; + const rval = rpop(cpu); + cpu.pc = rval; +}; + +fn do_op_lit(cpu: *cpu, p: u8) void = { + push(cpu, p: u16); +}; + +fn do_opr(cpu: *cpu, op: u8) void = switch (op) { + case op::NOP => yield; + case op::ROT => + const a = pop(cpu); + const b = pop(cpu); + const c = pop(cpu); + push(cpu, b); + push(cpu, a); + push(cpu, c); + case op::NRT => + const a = pop(cpu); + const b = pop(cpu); + const c = pop(cpu); + push(cpu, a); + push(cpu, c); + push(cpu, b); + case op::DUP => + push(cpu, peek(cpu)); + case op::SWP => + const a = pop(cpu); + const b = pop(cpu); + push(cpu, a); + push(cpu, b); + case op::OVR => + const x = peek(cpu, 1); + push(cpu, x); + case op::DRP => + pop(cpu); + case op::TCK => + const y = pop(cpu); + const x = pop(cpu); + push(cpu, y); + push(cpu, x); + push(cpu, y); + case op::NIP => + const y = pop(cpu); + pop(cpu); + push(cpu, y); + case op::EQU => + const x = pop(cpu); + const y = pop(cpu); + push(cpu, if (x == y) 1 else 0); + case op::NEQ => + const x = pop(cpu); + const y = pop(cpu); + push(cpu, if (x != y) 1 else 0); + case op::ADD => + const x = pop(cpu); + const y = pop(cpu); + push(cpu, x + y); + case op::SUB => + const x = pop(cpu); + const y = pop(cpu); + push(cpu, x - y); + case op::MUL => + // TODO: better handling mul div + const x = pop(cpu); + const y = pop(cpu); + push(cpu, x * y); + case op::DIV => + const x = pop(cpu); + const y = pop(cpu); + push(cpu, x / y); + case op::NEG => + push(cpu, - pop(cpu)); + case op::SLT => + const x = pop(cpu): i16; + const y = pop(cpu): i16; + push(cpu, if (y < x) 1 else 0); + case op::SLE => + const x = pop(cpu): i16; + const y = pop(cpu): i16; + push(cpu, if (y <= x) 1 else 0); + case op::ULT => + const x = pop(cpu): u16; + const y = pop(cpu): u16; + push(cpu, if (y < x) 1 else 0); + case op::ULE => + const x = pop(cpu): u16; + const y = pop(cpu): u16; + push(cpu, if (y <= x) 1 else 0); + case op::LOD => + // TODO lod and sto for bytes + const addr = pop(cpu); + push(cpu, rmem(cpu.mem, addr)); + case op::STO => + const addr = pop(cpu); + const val = pop(cpu); + wmem(cpu.mem, addr, val); + case op::PSH => + rpush(cpu, pop(cpu)); + case op::POP => + push(cpu, rpop(cpu)); + case op::HLT => + cpu.halted = true; + case op::PUT => + fmt::printfln("{:_04x}",pop(cpu))!; + case => abort("wrong opr"); +}; + + + + @@ -24,15 +24,6 @@ sto (da-) push pop - - -what abotu either - -1[addr:15] : call -0 -01 literal - - want: calls (15 bits) j, cj, relative addr, 8 bits @@ -53,6 +44,7 @@ regular op (7 bits) OPW:7: 1 T:2 arg:4 OPR:7: 0 opcode:6 +that is, 00 - 3f regular opcodes (64 of them) 4x mark x 5x loc x @@ -64,7 +56,3 @@ J: 0 1 0 cond? raddr:12 L: 0 1 1 value:13 C: 1 addr:15 - - - - |