diff options
author | ubq323 <ubq323@ubq323.website> | 2023-05-03 21:59:43 +0100 |
---|---|---|
committer | ubq323 <ubq323@ubq323.website> | 2023-05-03 22:15:14 +0100 |
commit | b6f756f2019cee700d070df312b4995e35e67d9d (patch) | |
tree | d6a107f8b5448114731ec1e5b1fe041671cf9893 | |
parent | ca7a393005ae1b8834bc15366106aca155b0f4d0 (diff) |
-rw-r--r-- | .b.r1a.kak.4uCRcR | 6 | ||||
-rw-r--r-- | asm.ha | 19 | ||||
-rw-r--r-- | bee.r1 | 1 | ||||
-rw-r--r-- | disasm.ha | 8 | ||||
-rw-r--r-- | main.ha | 15 | ||||
-rw-r--r-- | r1-better.txt | 1 | ||||
-rw-r--r-- | r1.ha | 150 | ||||
-rw-r--r-- | u.r1a | 10 |
8 files changed, 167 insertions, 43 deletions
diff --git a/.b.r1a.kak.4uCRcR b/.b.r1a.kak.4uCRcR deleted file mode 100644 index 57cc788..0000000 --- a/.b.r1a.kak.4uCRcR +++ /dev/null @@ -1,6 +0,0 @@ -i dup drp swp -i psh pop psh -j 1234 -: penis - -? 142345 @@ -12,8 +12,8 @@ type state = struct { here: size, }; -export fn run_asm() void = { - let file = os::open("u.r1a")!; +export fn run_asm(filename: str) void = { + let file = os::open(filename)!; let scanner = bufio::newscanner(file, 4096); let s = state { ... }; for (true) match (bufio::scan_line(&scanner)!) { @@ -57,17 +57,18 @@ fn literal_instr(s: *state, tok: strings::tokenizer) void = { fn arith_instr(s: *state, tok: strings::tokenizer) void = { let instr = 0u16; - for (let i=0z; i<3; i+=1) match (strings::next_token(&tok)) { - case void => fmt::fatal("expected 3 opcodes"); - case let word: str => { + for (let i=0z; i<3; i+=1) { instr <<= 5; - let op = match (opcodefromstr(word)) { - case invalid_opcode => fmt::fatalf("unknown opcode {}",word); - case let o: uint => yield o; + let op = match (strings::next_token(&tok)) { + case void => yield 0; // nop + case let word: str => yield match (opcodefromstr(word)) { + case invalid_opcode => fmt::fatalf("unknown opcode {}",word); + case let o: uint => yield o; }; + }; + instr |= (op:u16); }; - }; set_mem(&s.mem, s.here, instr&0x7fff); s.here += 2; @@ -1 +0,0 @@ - @@ -2,8 +2,12 @@ use io; use fmt; fn pr_instr(instr: u16, pos: (void|u16)) (void|io::error) = { - if (pos is u16) - fmt::printf("{:04x}: ",pos as u16)!; + if (pos is u16) { + fmt::printf(" [{:04x}]:",pos as u16)!; + } else { + fmt::print(" ")!; + }; + fmt::printf("{:04x} ",instr)?; if (instr & 0x8000 == 0) { pr_instr_arith(instr)?; @@ -0,0 +1,15 @@ +use os; +use fmt; + + + +export fn main() void = { + if (len(os::args) < 2) + fmt::fatal("usage: {} <asm|disasm|run> FILENAME"); + switch(os::args[1]) { + case "asm" => run_asm(os::args[2]); + case "disasm" => run_disasm(os::args[2]); + case "run" => run_run(os::args[2]); + case => fmt::fatal("what do you want me to do"); + }; +}; diff --git a/r1-better.txt b/r1-better.txt index ffc5426..6c56b13 100644 --- a/r1-better.txt +++ b/r1-better.txt @@ -62,6 +62,7 @@ sys op: 2 clear selected flags (c2-) 3 pop flags (f3-) 4 halt (4-) +5 debug print (x5-) %get-flags { zero sys } %set-flags (f-) { one sys } @@ -21,6 +21,23 @@ fn pop(s: *stack) u16 = { return s.d[s.p]; }; +fn peek(s: *stack) u16 = { + assert(s.p > 0, "stack underflow"); + return s.d[s.p-1]; +}; + +fn checkstack(s: *stack, depth: size) void = { + assert(s.p >= depth, "stack not deep enough"); +}; + +fn readmem(mem: []u8, where: u16) u16 = { + if (where <= len(mem) - 2) { + return endian::begetu16(mem[where..]); + } else { + return 0; + }; +}; + fn pr_stack(s: *stack) (void | io::error) = { fmt::print(" stack:")?; for (let i = 0z; i < s.p; i = i+1) @@ -30,33 +47,128 @@ fn pr_stack(s: *stack) (void | io::error) = { type cpu = struct { pc: u16, - ostack: stack, + dstack: stack, rstack: stack, + mem: []u8, + stopped: bool, +}; + + +fn do_instr(cpu: *cpu, instr: u16) void = { + if (instr & 0x8000 == 0) { + do_instr_arith(cpu,instr); + } else { + do_instr_jmp(cpu,instr); + }; }; +fn do_instr_arith(cpu: *cpu,instr: u16) void = { + let opa = (instr&(0x1f<<10)) >> 10; + let opb = (instr&(0x1f<< 5)) >> 5; + let opc = instr&(0x1f ) ; + do_opcode(cpu,opa); + do_opcode(cpu,opb); + do_opcode(cpu,opc); +}; + +fn do_instr_jmp(cpu: *cpu,instr: u16) void = { + let ty = (instr&0x6000)>>13; + let addr = (instr&0x1fff)<<1; + switch (ty) { + case 0 => // jmp + cpu.pc = addr; + case 1 => { // cjmp + let val = pop(&cpu.dstack); + if (val != 0) cpu.pc = addr; + }; + case 2 => { // call + push(&cpu.rstack,cpu.pc); + cpu.pc = addr; + }; + }; +}; -export fn run_disasm() void = { - let rom = io::drain(os::open("bee.r1")!)!; +fn do_opcode(cpu: *cpu,opc: u16) void = { + switch (opc) { + case opcode::nop => yield; + case opcode::psh => push(&cpu.rstack,pop(&cpu.dstack)); + case opcode::pop => push(&cpu.dstack,pop(&cpu.rstack)); + case opcode::dup => push(&cpu.dstack,peek(&cpu.dstack)); + case opcode::swp => { + let a = pop(&cpu.dstack); + let b = pop(&cpu.dstack); + push(&cpu.dstack, a); + push(&cpu.dstack, b); + }; + case opcode::ovr => { + checkstack(&cpu.dstack,2); + push(&cpu.dstack, cpu.dstack.d[cpu.dstack.p-2]); + }; + case opcode::drp => pop(&cpu.dstack); + case opcode::one => push(&cpu.dstack,1); + case opcode::zro => push(&cpu.dstack,0); + case opcode::ret => cpu.pc = pop(&cpu.rstack); + case opcode::eql => { + let a = pop(&cpu.dstack); + let b = pop(&cpu.dstack); + push(&cpu.dstack, if (a==b) { yield 1; } else { yield 0; }); + }; + case opcode::sys => { + let callno = pop(&cpu.dstack); + switch (callno) { + case 4 => cpu.stopped=true; + case 5 => fmt::printfln("{:04x}",pop(&cpu.dstack))!; + case => fmt::fatalf("unknown syscall {:04x}",callno); + }; + }; + case opcode::lit => { + push(&cpu.dstack, readmem(cpu.mem, cpu.pc)); + cpu.pc += 2; + }; + case opcode::meh => fmt::printfln("{:04x}",pop(&cpu.dstack))!; + case opcode::add => { + let a = pop(&cpu.dstack); + let b = pop(&cpu.dstack); + push(&cpu.dstack, a+b); + }; + case opcode::sub=> { + let a = pop(&cpu.dstack); + let b = pop(&cpu.dstack); + push(&cpu.dstack, a-b); + }; + + + case => fmt::fatalf("unimplemented opcode {}",opcodestr(opc: opcode)!); + }; +}; + +export fn run_run(filename: str) void = { + let rom = io::drain(os::open(filename)!)!; defer free(rom); assert(len(rom)&1 == 0, "rom length must be even"); + let cpu = cpu { mem=rom, ... }; + for (!cpu.stopped) { + let instr = readmem(cpu.mem, cpu.pc); + // pr_instr(instr, cpu.pc)!; - let cpu = cpu { ... }; - - for (true) { - let instr = endian::begetu16(rom[cpu.pc..]); - pr_instr(instr, cpu.pc)!; cpu.pc += 2; - // if (instr == 0) - // break - // else if (instr & 0x8000 == 0) { - // push(&cpu.ostack, instr); - // fmt::printfln(" push {:04x}",instr)!; - // } else { - // let v = pop(&cpu.ostack); - // fmt::printfln(" pop {:04x}", v)!; - // }; - - // pr_stack(&cpu.ostack)!; + do_instr(&cpu, instr); + // pr_stack(&cpu.dstack)!; + }; +}; + + +export fn run_disasm(filename: str) void = { + let rom = io::drain(os::open("u.r1b")!)!; + defer free(rom); + assert(len(rom)&1 == 0, "rom length must be even"); + + let here = 0u16; + + for (here < len(rom)) { + let instr = endian::begetu16(rom[here..]); + pr_instr(instr, here)!; + here += 2; }; }; @@ -1,6 +1,4 @@ -# print 2+2 -i nop lit nop -i dup add meh -l 1234 -i dup pop pop -call 2016 +i lit dup add +l 2 +i meh lit sys +l 4 |