diff --git a/uxn/uxn.ha b/uxn/uxn.ha index f5fd4e9..225015d 100644 --- a/uxn/uxn.ha +++ b/uxn/uxn.ha @@ -425,6 +425,54 @@ fn short_from_bytes(high: u8, low: u8) u16 = { return (high: u16) << 8 | (low: u16); }; +fn read_from_addr(short: bool, addr: u16, state: *uxn) (u8 | u16) = { + switch(short){ + case true => + const high = state.ram[addr]; + const low = state.ram[addr+1]; + return short_from_bytes(high,low); + + case false => + return state.ram[addr]; + }; +}; + +fn write_to_addr(value: (u8 | u16), addr: u16, state: *uxn) void = { + match(value){ + case let s: u16 => + let high = (s >> 8 ): u8; + let low = s: u8; + state.ram[addr] = high; + state.ram[addr+1] = low; + + case let b: u8 => + state.ram[addr] = b; + }; +}; + +fn read_from_zaddr(short: bool, zaddr: u8, state: *uxn) (u8 | u16) = { + switch(short){ + case true => + const high = state.ram[zaddr: u16]; + const low = state.ram[(zaddr+1): u16]; + return short_from_bytes(high,low); + + case false => + return state.ram[zaddr: u16]; + }; +}; +fn write_to_zaddr(value: (u8 | u16), zaddr: u8, state: *uxn) void = { + match(value){ + case let s: u16 => + let high = (s >> 8 ): u8; + let low = s: u8; + state.ram[zaddr: u16] = high; + state.ram[(zaddr+1): u16] = low; + + case let b: u8 => + state.ram[zaddr: u16] = b; + }; +}; fn push_to_stack(ret: bool, val: (u8 | u16), state: *uxn) void = { let stack = switch(ret){ @@ -448,7 +496,7 @@ fn push_to_stack(ret: bool, val: (u8 | u16), state: *uxn) void = { }; }; -// Get value from stack, offset 0 is top of stack. +// Get value from stack, offset 0 is top of stack. offset depends on short or byte fn get_stack_val(ret: bool, short: bool, off: u8, state: *uxn) (u8 | u16) = { let stack = switch(ret){ case true => @@ -467,6 +515,26 @@ fn get_stack_val(ret: bool, short: bool, off: u8, state: *uxn) (u8 | u16) = { }; }; +//peek offset is always byte offset +fn peek(ret: bool, short: bool, off: u8, state: *uxn) (u8 | u16 ) = { + let stack = switch(ret){ + case true => + yield 1; + case false => + yield 0; + }; + + if(!short){ + let val: u8 = state.stk[stack][state.ptr[stack] - 1 - off]; + return val; + } else { + let low: u8 = state.stk[stack][state.ptr[stack] - 1 - off]; + let high: u8 = state.stk[stack][state.ptr[stack] - 2 - off]; + return short_from_bytes(high,low); + }; + +}; + fn increment_stack(ret: bool, short: bool, state: *uxn) void = { let stack = switch(ret){ case true => @@ -508,6 +576,15 @@ fn pop_or_get(inst: normal_op, off: u8, state: *uxn) (u8 | u16) = { yield get_stack_val(inst.ret,inst.short, off,state); }; }; +//Offset is always byte aligned in peek +fn pop_or_peek(inst: normal_op, off: u8, state: *uxn) (u8 | u16) = { + return switch(inst.keep) { + case false => + yield pop_from_stack(false,inst.ret,inst.short,state); + case true => + yield peek(inst.ret,inst.short, off,state); + }; +}; export fn uxn_eval(new_pc: u16, state: *uxn) (done | quit | error ) = { // let a: u16 = 0, b: u16 = 0, c: u16 = 0, x: [2]u16 = [0...], y: [2]u16 = [0...], z: [2]u16 = [0...]; state.pc = new_pc; @@ -749,93 +826,36 @@ export fn uxn_step(state: *uxn) (done | error) = { push_to_stack(!sth_inst.ret, val, state); // /* LDZ */ OPC(0x10,POx(a,0),PEK(a, x, 0xff)) case let ldz_inst: LDZ => - let addr: u16 = pop_from_stack(ldz_inst.keep, ldz_inst.ret, false, state): u16 & 0x00FF; - let val = if(ldz_inst.short){ - yield short_from_bytes(state.ram[addr],state.ram[addr+1 & 0x00FF]); - } else { - yield state.ram[addr]; - }; + let addr: u8 = pop_from_stack(ldz_inst.keep, ldz_inst.ret, false, state): u8; + let val = read_from_zaddr(ldz_inst.short,addr,state); push_to_stack(ldz_inst.ret, val, state); // /* STZ */ OPC(0x11,POx(a,0) GOT(y),POK(a, y, 0xff)) case let stz_inst: STZ => - let addr: u16 = pop_or_get(normal_op{short = false, keep = stz_inst.keep, ret = stz_inst.ret}, 0, state): u16 & 0x00FF; - let val = if(stz_inst.short){ - let low = pop_or_get(normal_op{short = false, keep = stz_inst.keep, ret = stz_inst.ret}, 1, state): u8; - let high = pop_or_get(normal_op{short = false, keep = stz_inst.keep, ret = stz_inst.ret}, 2, state): u8; - yield short_from_bytes(high,low); - - }else{ - yield pop_or_get(stz_inst, 1, state): u8; - }; - match (val) { - case let b: u8 => - state.ram[addr] = b; - case let s: u16 => - let high = (s >> 8 ): u8; - let low = s: u8; - state.ram[addr] = high; - state.ram[addr+1 & 0x00FF] = low; - //TODO verify correct endianness - }; + let addr: u8 = pop_or_peek(normal_op{short = false, keep = stz_inst.keep, ret = stz_inst.ret}, 0, state): u8; + let val = pop_or_peek(stz_inst,1,state); + write_to_zaddr(val,addr,state); // /* LDR */ OPC(0x12,POx(a,0),PEK(pc + (Sint8)a, x, 0xffff)) case let ldr_inst: LDR => let reladdr = (pop_from_stack(ldr_inst.keep, ldr_inst.ret, false, state): u16): i8; let addr: u16 = (state.pc: u32: i32 + reladdr): u16; - let val = if(ldr_inst.short){ - yield short_from_bytes(state.ram[addr],state.ram[addr+1]); - } else { - yield state.ram[addr]; - }; + let val = read_from_addr(ldr_inst.short,addr,state); push_to_stack(ldr_inst.ret, val, state); // /* STR */ OPC(0x13,POx(a,0) GOT(y),POK(pc + (Sint8)a, y, 0xffff)) case let str_inst: STR => - let reladdr = (pop_or_get(normal_op{short = false, keep = str_inst.keep, ret = str_inst.ret}, 0, state): u16 & 0x00FF): u8: i8; + let reladdr = (pop_or_peek(normal_op{short = false, keep = str_inst.keep, ret = str_inst.ret}, 0, state): u16 & 0x00FF): u8: i8; let addr: u16 = (state.pc: u32: i32 + reladdr): u16; - let val = if(str_inst.short){ - let low = pop_or_get(normal_op{short = false, keep = str_inst.keep, ret = str_inst.ret}, 1, state): u8; - let high = pop_or_get(normal_op{short = false, keep = str_inst.keep, ret = str_inst.ret}, 2, state): u8; - yield short_from_bytes(high,low); - - }else{ - yield pop_or_get(str_inst, 1, state): u8; - }; - match (val) { - case let b: u8 => - state.ram[addr] = b; - case let s: u16 => - let high = (s >> 8 ): u8; - let low = s: u8; - state.ram[addr] = high; - state.ram[addr+1] = low; - //TODO verify correct endianness - }; + let val = pop_or_peek(str_inst,1,state); + write_to_addr(val,addr,state); // /* LDA */ OPC(0x14,POx(a,1),PEK(a, x, 0xffff)) case let lda_inst: LDA => let addr: u16 = pop_from_stack(lda_inst.keep, lda_inst.ret, true, state): u16; - let val = if(lda_inst.short){ - yield short_from_bytes(state.ram[addr],state.ram[addr+1]); - } else { - yield state.ram[addr]; - }; + let val = read_from_addr(lda_inst.short,addr,state); push_to_stack(lda_inst.ret, val, state); // /* STA */ OPC(0x15,POx(a,1) GOT(y),POK(a, y, 0xffff)) case let sta_inst: STA => - let addr: u16 = pop_or_get(normal_op{short = true, keep = sta_inst.keep, ret = sta_inst.ret}, 0, state): u16 ; - let val = if(sta_inst.short){ - yield pop_or_get(sta_inst, 1, state): u16; - }else{ - yield pop_or_get(sta_inst, 2, state): u8; - }; - match (val) { - case let b: u8 => - state.ram[addr] = b; - case let s: u16 => - let high = (s >> 8 ): u8; - let low = s: u8; - state.ram[addr] = high; - state.ram[addr+1] = low; - //TODO verify correct endianness - }; + let addr: u16 = pop_or_peek(normal_op{short = true, keep = sta_inst.keep, ret = sta_inst.ret}, 0, state): u16 ; + let val = pop_or_peek(sta_inst,2,state); + write_to_addr(val,addr,state); // /* DEI */ OPC(0x16,POx(a,0),DEI(a, x)) case let dei_inst: DEI => // fmt::println("DEI Instruction")!;