diff --git a/cmd/meadow/main.ha b/cmd/meadow/main.ha index 712bcfe..1988f61 100644 --- a/cmd/meadow/main.ha +++ b/cmd/meadow/main.ha @@ -59,7 +59,7 @@ export fn main() void = { }; let path = os::args[1]; - //Setting up pollfds for uni::poll + //Setting up pollfds for unix::poll const consolefd: []unix::poll::pollfd = [unix::poll::pollfd { fd = os::stdin_file, events = unix::poll::event::POLLIN, diff --git a/cmd/meadowcli/uxnmin.ha b/cmd/meadowcli/uxnmin.ha index f39ba60..97446a9 100644 --- a/cmd/meadowcli/uxnmin.ha +++ b/cmd/meadowcli/uxnmin.ha @@ -3,764 +3,87 @@ use os; use fs; use io; use strings; +use unix; +use unix::poll; +use uxn; -let console_vector: u16 = 0; -let ram: [0x10000] u8 = [0...]; -let dev: [0x100] u8 = [0...]; -let ptr: [2] u8 = [0...]; -let stk: [2][0x100] u8 = [[0...],[0...]]; - -fn emu_dei(port: u8) u8 = { - let val = dev[port]; - // fmt::printfln("Read {:x} from port {:x}", val, port)!; - return val; -}; - - -fn emu_deo(port: u8, value: u8) void = { - // fmt::printfln("Writing {:x} to port {:x}", value, port)!; - dev[port] = value; - switch(port) { - case 0x11 => - let high = dev[0x10]; - let low = value; - console_vector = short_from_bytes(high,low); - // fmt::printfln("Setting console_vector to: {:x}", console_vector)!; - return; - case 0x18 => - fmt::print(value: rune)!; - return; - case 0x19 => - fmt::error(value)!; - return; - case => - return; - }; -}; - - -type evalerror = !void; -type unhandled = !u8; - -type error = !(evalerror | unhandled); - -type simple_op = void; -type literal_op = struct { short: bool, ret: bool}; -type normal_op = struct { short: bool, keep: bool, ret: bool}; - -type BRK = simple_op; -type JCI = simple_op; -type JMI = simple_op; -type JSI = simple_op; -type LIT = literal_op; -type INC = normal_op; -type POP = normal_op; -type NIP = normal_op; -type SWP = normal_op; -type ROT = normal_op; -type DUP = normal_op; -type OVR = normal_op; -type EQU = normal_op; -type NEQ = normal_op; -type GTH = normal_op; -type LTH = normal_op; -type JMP = normal_op; -type JCN = normal_op; -type JSR = normal_op; -type STH = normal_op; -type LDZ = normal_op; -type STZ = normal_op; -type LDR = normal_op; -type STR = normal_op; -type LDA = normal_op; -type STA = normal_op; -type DEI = normal_op; -type DEO = normal_op; -type ADD = normal_op; -type SUB = normal_op; -type MUL = normal_op; -type DIV = normal_op; -type AND = normal_op; -type ORA = normal_op; -type EOR = normal_op; -type SFT = normal_op; - -type instruction = (BRK | JCI | JMI | JSI | LIT | INC | POP | NIP | SWP | ROT | DUP | OVR | EQU | NEQ - | GTH | LTH | JMP | JCN | JSR | STH | LDZ | STZ | LDR | STR | LDA | STA | DEI - | DEO | ADD | SUB | MUL | DIV | AND | ORA | EOR | SFT); - - -fn get_instruction(byte: u8) (instruction | error) = { - let k: bool = (byte & (0b10000000) != 0 ); - let r: bool = (byte & (0b01000000) != 0 ); - let s: bool = (byte & (0b00100000) != 0 ); - let opcode: u8 = byte & (0b00011111); - switch(opcode) { - case 0x00 => - switch(byte){ - case 0x00 => - return void: BRK; - case 0x20 => - return void: JCI; - case 0x40 => - return void: JMI; - case 0x60 => - return void: JSI; - case 0x80 => // LIT - return LIT {short=false, ret=false}; - case 0xa0 => // LIT2 - return LIT {short=true, ret=false}; - case 0xc0 => // LITr - return LIT {short=false, ret=true}; - case 0xe0 => // LIT2r - return LIT {short=true, ret=true}; - case => - return byte: unhandled; - }; - case 0x01 => - return INC {short = s, keep = k, ret = r}; - case 0x02 => - return POP {short = s, keep = k, ret = r}; - case 0x03 => - return NIP {short = s, keep = k, ret = r}; - case 0x04 => - return SWP {short = s, keep = k, ret = r}; - case 0x05 => - return ROT {short = s, keep = k, ret = r}; - case 0x06 => - return DUP {short = s, keep = k, ret = r}; - case 0x07 => - return OVR {short = s, keep = k, ret = r}; - case 0x08 => - return EQU {short = s, keep = k, ret = r}; - case 0x09 => - return NEQ {short = s, keep = k, ret = r}; - case 0x0a => - return GTH {short = s, keep = k, ret = r}; - case 0x0b => - return LTH {short = s, keep = k, ret = r}; - case 0x0c => - return JMP {short = s, keep = k, ret = r}; - case 0x0d => - return JCN {short = s, keep = k, ret = r}; - case 0x0e => - return JSR {short = s, keep = k, ret = r}; - case 0x0f => - return STH {short = s, keep = k, ret = r}; - - case 0x10 => - return LDZ {short = s, keep = k, ret = r}; - case 0x11 => - return STZ {short = s, keep = k, ret = r}; - case 0x12 => - return LDR {short = s, keep = k, ret = r}; - case 0x13 => - return STR {short = s, keep = k, ret = r}; - case 0x14 => - return LDA {short = s, keep = k, ret = r}; - case 0x15 => - return STA {short = s, keep = k, ret = r}; - case 0x16 => - return DEI {short = s, keep = k, ret = r}; - case 0x17 => - return DEO {short = s, keep = k, ret = r}; - case 0x18 => - return ADD {short = s, keep = k, ret = r}; - case 0x19 => - return SUB {short = s, keep = k, ret = r}; - case 0x1a => - return MUL {short = s, keep = k, ret = r}; - case 0x1b => - return DIV {short = s, keep = k, ret = r}; - case 0x1c => - return AND {short = s, keep = k, ret = r}; - case 0x1d => - return ORA {short = s, keep = k, ret = r}; - case 0x1e => - return EOR {short = s, keep = k, ret = r}; - case 0x1f => - return SFT {short = s, keep = k, ret = r}; - case => - return byte: unhandled; - }; -}; - -fn short_from_bytes(high: u8, low: u8) u16 = { - return (high: u16) << 8 | (low: u16); -}; - - -fn push_to_stack(ret: bool, val: (u8 | u16)) void = { - let stack = switch(ret){ - case true => - yield 1; - case false => - yield 0; - }; - match(val) { - case let bval: u8 => - stk[stack][ptr[stack]] = bval; - ptr[stack] = ptr[stack] + 1; - - case let sval: u16 => - let low: u8 = (sval & 0xFF): u8; - let high: u8 = (sval >> 8): u8; - stk[stack][ptr[stack]] = high; - ptr[stack] = ptr[stack] + 1; - stk[stack][ptr[stack]] = low; - ptr[stack] = ptr[stack] + 1; - }; -}; - -// Get value from stack, offset 0 is top of stack. -fn get_stack_val(ret: bool, short: bool, off: u8) (u8 | u16) = { - let stack = switch(ret){ - case true => - yield 1; - case false => - yield 0; - }; - - if(!short){ - let val: u8 = stk[stack][ptr[stack] - 1 - off]; - return val; - } else { - let low: u8 = stk[stack][ptr[stack]-1 - (off * 2)]; - let high: u8 = stk[stack][ptr[stack]-2 - (off * 2)]; - return short_from_bytes(high,low); - }; -}; - -fn increment_stack(ret: bool, short: bool) void = { - let stack = switch(ret){ - case true => - yield 1; - case false => - yield 0; - }; - if(short){ - ptr[stack] = ptr[stack] + 2; - } else { - ptr[stack] = ptr[stack] + 1; - }; -}; -fn decrement_stack(ret: bool, short: bool) void = { - let stack = switch(ret){ - case true => - yield 1; - case false => - yield 0; - }; - if(short){ - ptr[stack] = ptr[stack] - 2; - } else { - ptr[stack] = ptr[stack] - 1; - }; -}; - -fn pop_from_stack(keep: bool, ret: bool, short: bool) (u8 | u16) = { - let val = get_stack_val(ret, short, 0); - if(!keep) decrement_stack(ret, short); - return val; -}; - -fn pop_or_get(inst: normal_op, off: u8) (u8 | u16) = { - return switch(inst.keep) { - case false => - yield pop_from_stack(false,inst.ret,inst.short); - case true => - yield get_stack_val(inst.ret,inst.short, off); - }; -}; -fn uxn_eval(pc: u16) (done | error ) = { - // let a: u16 = 0, b: u16 = 0, c: u16 = 0, x: [2]u16 = [0...], y: [2]u16 = [0...], z: [2]u16 = [0...]; - for(true){ - // fmt::printfln("Starting eval with pc: {:x}", pc)!; - let readval = ram[pc]; - let inst: instruction = get_instruction(readval)?; - pc = pc+1; //TODO verify all pc changes - - match(inst) { - // /* BRK */ case 0x00: return 1; - case BRK => - // fmt::println("Break!")!; - return done; - // /* JCI */ case 0x20: if(DEC(0)) { IMM pc += a; } else pc += 2; break; - case JCI => - let val: u8 = pop_from_stack(false, false, false): u8; - if(val != 0) { - pc = pc + 2 + short_from_bytes(ram[pc],ram[pc+1]); //TODO, is this signed? - }else{ - pc = pc + 2; - }; - // /* JMI */ case 0x40: IMM pc += a; break; - case JMI => - pc = pc + 2 + short_from_bytes(ram[pc],ram[pc+1]); //TODO is this signed? - // /* JSI */ case 0x60: IMM PUx(pc, 1, 1) pc += a; break; - case JSI => - push_to_stack(true, pc + 2); - pc = pc + 2 + short_from_bytes(ram[pc],ram[pc+1]); //TODO is this signed? - - // /* LIT */ case 0x80: INC(0) = ram[pc++]; break; - case let lit_inst: LIT => - push_to_stack(lit_inst.ret, ram[pc]); - pc = pc + 1; - if(lit_inst.short) { - push_to_stack(lit_inst.ret, ram[pc]); - pc = pc + 1; - }; - // /* INC */ OPC(0x01,POx(a,d),PUx(a + 1,d,r)) - case let inc_inst: INC => - let val = match(pop_from_stack(inc_inst.keep,inc_inst.ret,inc_inst.short)) { - //TODO this whole match statement seems unnecessary - case let byte: u8 => - yield byte + 1; - case let short: u16 => - yield short + 1; - }; - - push_to_stack(inc_inst.ret,val); - // /* POP */ OPC(0x02,ptr[r] -= 1 + d;,{}) - case let pop_inst: POP => - if(!pop_inst.keep){ - pop_from_stack(false,pop_inst.ret,pop_inst.short); - }; - // /* NIP */ OPC(0x03,GOT(x) ptr[r] -= 1 + d;,PUT(x,r)) - case let nip_inst: NIP => - let top = pop_or_get(nip_inst,0); - let bot = pop_or_get(nip_inst,1); - push_to_stack(nip_inst.ret, top); - // /* SWP */ OPC(0x04,GOT(x) GOT(y),PUT(x,r) PUT(y,r)) - case let swp_inst: SWP => - let top = pop_or_get(swp_inst,0); - let bot = pop_or_get(swp_inst,1); - - push_to_stack(swp_inst.ret, top); - push_to_stack(swp_inst.ret, bot); - // /* ROT */ OPC(0x05,GOT(x) GOT(y) GOT(z),PUT(y,r) PUT(x,r) PUT(z,r)) - case let rot_inst: ROT => - let top = pop_or_get(rot_inst,0); - let mid = pop_or_get(rot_inst,1); - let bot = pop_or_get(rot_inst,2); - - push_to_stack(rot_inst.ret, mid); - push_to_stack(rot_inst.ret, top); - push_to_stack(rot_inst.ret, bot); - // /* DUP */ OPC(0x06,GOT(x),PUT(x,r) PUT(x,r)) - case let dup_inst: DUP => - let val = pop_from_stack(dup_inst.keep, dup_inst.ret, dup_inst.short); - push_to_stack(dup_inst.ret, val); - push_to_stack(dup_inst.ret, val); - // /* OVR */ OPC(0x07,GOT(x) GOT(y),PUT(y,r) PUT(x,r) PUT(y,r)) - case let ovr_inst: OVR => - let top = pop_or_get(ovr_inst,0); - let bot = pop_or_get(ovr_inst,1); - - push_to_stack(ovr_inst.ret, bot); - push_to_stack(ovr_inst.ret, top); - push_to_stack(ovr_inst.ret, bot); - // /* EQU */ OPC(0x08,POx(a,d) POx(b,d),PUx(b == a,0,r)) - case let equ_inst: EQU => - let top = pop_or_get(equ_inst,0); - let bot = pop_or_get(equ_inst,1); - - //TODO, I think this works, but it feels unclean with the casting - let val: u8 = if(top: u16 == bot: u16){ - yield 1; - } else { - yield 0; - }; - push_to_stack(equ_inst.ret, val); - // /* NEQ */ OPC(0x09,POx(a,d) POx(b,d),PUx(b != a,0,r)) - case let neq_inst: NEQ => - let top = pop_or_get(neq_inst,0); - let bot = pop_or_get(neq_inst,1); - - //TODO, I think this works, but it feels unclean with the casting - let val: u8 = if(top: u16 != bot: u16){ - yield 1; - } else { - yield 0; - }; - push_to_stack(neq_inst.ret, val); - // /* GTH */ OPC(0x0a,POx(a,d) POx(b,d),PUx(b > a,0,r)) - case let gth_inst: GTH => - let top = pop_or_get(gth_inst,0); - let bot = pop_or_get(gth_inst,1); - - //TODO, I think this works, but it feels unclean with the casting - let val: u8 = if(bot: u16 > top: u16){ - yield 1; - } else { - yield 0; - }; - push_to_stack(gth_inst.ret, val); - // /* LTH */ OPC(0x0b,POx(a,d) POx(b,d),PUx(b < a,0,r)) - case let lth_inst: LTH => - let top = pop_or_get(lth_inst,0); - let bot = pop_or_get(lth_inst,1); - - //TODO, I think this works, but it feels unclean with the casting - let val: u8 = if(bot: u16 < top: u16){ - yield 1; - } else { - yield 0; - }; - push_to_stack(lth_inst.ret, val); - // /* JMP */ OPC(0x0c,POx(a,d),MOV) - case let jmp_inst: JMP => - let addr = pop_or_get(jmp_inst,0); - match(addr) { - case let b: u8 => - pc = pc + b: u16; //TODO verify if pc changes are right - case let s: u16 => - pc = s; - }; - - // /* JCN */ OPC(0x0d,POx(a,d) POx(b,0),if(b) MOV) - case let jcn_inst: JCN => - let addr = pop_or_get(jcn_inst,0); - let cond: u8 = pop_or_get(normal_op {keep = jcn_inst.keep, - ret = jcn_inst.ret, - short = false}, - if(jcn_inst.short){ yield 2;} else { yield 1; } ): u8; - if( cond != 0) { - match(addr) { - case let b: u8 => - let off = b: i8: i32; - pc = (pc: i32 + off): u16; //TODO verify if pc changes are right - case let s: u16 => - pc = s; - }; - }; - // /* JSR */ OPC(0x0e,POx(a,d),PUx(pc,1,!r) MOV) - case let jsr_inst: JSR => - let addr = pop_or_get(jsr_inst,0); - push_to_stack(true, pc); - match(addr) { - case let b: u8 => - let off = b: i8: i32; - pc = (pc: i32 + off): u16; //TODO verify if pc changes are right - case let s: u16 => - pc = s; - }; - - // /* STH */ OPC(0x0f,GOT(x),PUT(x,!r)) - case let sth_inst: STH => - let val = pop_or_get(sth_inst,0); - push_to_stack(!sth_inst.ret, val); - // /* 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): u16 & 0x00FF; - let val = if(ldz_inst.short){ - yield short_from_bytes(ram[addr],ram[addr+1 & 0x00FF]); - } else { - yield ram[addr]; - }; - push_to_stack(ldz_inst.ret, val); - // /* 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): 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): u8; - let high = pop_or_get(normal_op{short = false, keep = stz_inst.keep, ret = stz_inst.ret}, 2): u8; - yield short_from_bytes(high,low); - - }else{ - yield pop_or_get(stz_inst, 1): u8; - }; - match (val) { - case let b: u8 => - ram[addr] = b; - case let s: u16 => - let high = (s >> 8 ): u8; - let low = s: u8; - ram[addr] = high; - ram[addr+1 & 0x00FF] = low; - //TODO verify correct endianness - }; - // /* 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): u16): i8; - let addr: u16 = (pc: u32: i32 + reladdr): u16; - let val = if(ldr_inst.short){ - yield short_from_bytes(ram[addr],ram[addr+1]); - } else { - yield ram[addr]; - }; - push_to_stack(ldr_inst.ret, val); - // /* STR */ OPC(0x13,POx(a,0) GOT(y),POK(pc + (Sint8)a, y, 0xffff)) - case let str_inst: STR => - let reladdr = (pop_from_stack(str_inst.keep, str_inst.ret, false): u16): i8; - let addr: u16 = (pc: u32: i32 + reladdr): u16; - let val = pop_from_stack(str_inst.keep, str_inst.ret, str_inst.short); - match (val) { - case let b: u8 => - ram[addr] = b; - case let s: u16 => - let high = (s >> 8 ): u8; - let low = s: u8; - ram[addr] = high; - ram[addr+1] = low; - //TODO verify correct endianness - }; - // /* 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): u16; - let val = if(lda_inst.short){ - yield short_from_bytes(ram[addr],ram[addr+1]); - } else { - yield ram[addr]; - }; - push_to_stack(lda_inst.ret, val); - // /* STA */ OPC(0x15,POx(a,1) GOT(y),POK(a, y, 0xffff)) - case let sta_inst: STA => - let addr: u16 = pop_from_stack(sta_inst.keep, sta_inst.ret, true): u16; - let val = pop_from_stack(sta_inst.keep, sta_inst.ret, sta_inst.short); - match (val) { - case let b: u8 => - ram[addr] = b; - case let s: u16 => - let high = (s >> 8 ): u8; - let low = s: u8; - ram[addr] = high; - ram[addr+1] = low; - //TODO verify correct endianness - }; - // /* DEI */ OPC(0x16,POx(a,0),DEI(a, x)) - case let dei_inst: DEI => - // fmt::println("DEI Instruction")!; - let port: u8 = pop_from_stack(dei_inst.keep, dei_inst.ret, false): u8; - let val = if(dei_inst.short){ - yield short_from_bytes(emu_dei(port),emu_dei(port+1)); - }else{ - yield emu_dei(port); - }; - push_to_stack(dei_inst.ret,val); - // /* DEO */ OPC(0x17,POx(a,0) GOT(y),DEO(a, y)) - case let deo_inst: DEO => - let port: u8 = pop_or_get(normal_op{short = false, keep = deo_inst.keep, ret = deo_inst.ret}, 0): u8; - if(deo_inst.short){ - let low = pop_or_get(normal_op{short = false, keep = deo_inst.keep, ret = deo_inst.ret}, 1): u8; - let high = pop_or_get(normal_op{short = false, keep = deo_inst.keep, ret = deo_inst.ret}, 2): u8; - emu_deo(port,high); - emu_deo(port+1,low); - }else{ - let val = pop_or_get(deo_inst, 1): u8; - emu_deo(port,val); - }; - // /* ADD */ OPC(0x18,POx(a,d) POx(b,d),PUx(b + a, d,r)) - case let add_inst: ADD => - let top = pop_or_get(add_inst,0); - let bot = pop_or_get(add_inst,1); - let res = if(!add_inst.short){ - yield (top: u8 + bot: u8); - } else { - yield (top: u16 + bot: u16); - }; - push_to_stack(add_inst.ret, res); - // /* SUB */ OPC(0x19,POx(a,d) POx(b,d),PUx(b - a, d,r)) - case let sub_inst: SUB => - let top = pop_or_get(sub_inst,0); - let bot = pop_or_get(sub_inst,1); - let res = if(!sub_inst.short){ - yield (bot: u8 - top: u8); - } else { - yield (bot: u16 - top: u16); - }; - push_to_stack(sub_inst.ret, res); - // /* MUL */ OPC(0x1a,POx(a,d) POx(b,d),PUx(b * a, d,r)) - case let mul_inst: MUL => - let top = pop_or_get(mul_inst,0); - let bot = pop_or_get(mul_inst,1); - let res = if(!mul_inst.short){ - yield (bot: u8 * top: u8); - } else { - yield (bot: u16 * top: u16); - }; - push_to_stack(mul_inst.ret, res); - // /* DIV */ OPC(0x1b,POx(a,d) POx(b,d),PUx(a ? b / a : 0, d,r)) - case let div_inst: DIV => - let top = pop_or_get(div_inst,0); - let bot = pop_or_get(div_inst,1); - - let res = if(!div_inst.short){ - assert(bot is u8); - assert(top is u8); - if(top: u8 == 0) yield top; - yield (bot: u8 / top: u8): u8; - } else { - assert(bot is u16); - assert(top is u16); - if(top: u16 == 0) yield top; - yield (bot: u16 / top: u16): u16; - };//TODO handle rounding and edge cases with division - push_to_stack(div_inst.ret, res); - // /* AND */ OPC(0x1c,POx(a,d) POx(b,d),PUx(b & a, d,r)) - case let and_inst: AND => - let top = pop_or_get(and_inst,0); - let bot = pop_or_get(and_inst,1); - let res = if(!and_inst.short){ - yield (bot: u8 & top: u8); - } else { - yield (bot: u16 & top: u16); - }; - push_to_stack(and_inst.ret, res); - // /* ORA */ OPC(0x1d,POx(a,d) POx(b,d),PUx(b | a, d,r)) - case let ora_inst: ORA => - let top = pop_or_get(ora_inst,0); - let bot = pop_or_get(ora_inst,1); - let res = if(!ora_inst.short){ - yield (bot: u8 | top: u8); - } else { - yield (bot: u16 | top: u16); - }; - push_to_stack(ora_inst.ret, res); - // /* EOR */ OPC(0x1e,POx(a,d) POx(b,d),PUx(b ^ a, d,r)) - case let eor_inst: EOR => - let top = pop_or_get(eor_inst,0); - let bot = pop_or_get(eor_inst,1); - let res = if(!eor_inst.short){ - yield (bot: u8 ^ top: u8); - } else { - yield (bot: u16 ^ top: u16); - }; - push_to_stack(eor_inst.ret, res); - // /* SFT */ OPC(0x1f,POx(a,0) POx(b,d),PUx(b >> (a & 0xf) << (a >> 4), d,r)) - case let sft_inst: SFT => - let shifts: u8 = pop_or_get(normal_op{short = false, keep = sft_inst.keep, ret = sft_inst.ret}, 0): u8; - let rightshifts = shifts & 0b00001111; - let leftshifts = (shifts & 0b11110000) >> 4; - if(sft_inst.short){ //TODO, this seems like it can be cleaned up a bit - let low = pop_or_get(normal_op{short = false, keep = sft_inst.keep, ret = sft_inst.ret}, 1): u8; - let high = pop_or_get(normal_op{short = false, keep = sft_inst.keep, ret = sft_inst.ret}, 2): u8; - let val = short_from_bytes(high,low); - let res = (val >> rightshifts ) << leftshifts; - push_to_stack(sft_inst.ret, res); - }else{ - let val = pop_or_get(sft_inst, 1): u8; - let res = (val >> rightshifts ) << leftshifts; - push_to_stack(sft_inst.ret, res); - }; - - - case => - return readval: unhandled; - }; - }; - - - // return evalerror; -}; - -fn console_input(c: u8, ctype: u8) (done | error) = { - dev[0x12] = c; - dev[0x17] = ctype; - if(console_vector != 0){ - // fmt::println("Evaluating Console Vector")!; - uxn_eval(console_vector)?; - }; //TODO implement eval - return done; -}; - - - -// Converts an error into a user-friendly string -fn strerror(err: error) str = { - match (err) { - case evalerror => - return "Reached unexpected part of eval code"; - case let val: unhandled => - return fmt::asprintf("Unknown Opcode read: {:x}", val: u8)!; - }; -}; - +def MAX_CONSOLE_INPUT = 0x1000; export fn main() void = { + let run = true; if(len(os::args) < 2){ fmt::printf("usage: %s file.rom [args..]\n")!; return; }; let path = os::args[1]; - //Open rom file - let romfile = match (os::open(path,fs::flag::RDONLY)) { - case let file: io::file => - yield file; - case let err: fs::error => - fmt::fatalf("Error opening {}: {}", path, fs::strerror(err)); - }; - //Copy rom into ram - let bytesread = match (io::read(romfile,ram[0x100..0xff00])){ - case let bytes: size => - yield bytes; - case let eof: io::EOF => - fmt::fatalf("Empty Rom"); - case let err: io::error => - fmt::fatalf("Error reading: {}", io::strerror(err)); - }; - io::close(romfile)!; //TODO, isn't there some kind of oversized roms? - // fread(&ram[0x100], 0xff00, 1, f), fclose(f); - let hasargs = len(os::args) > 2; - if(hasargs){ - dev[0x17] = 1; - }; - // dev[0x17] = argc > 2; - let eval = match (uxn_eval(0x100)) { - case done => - yield done; - case let val: u8 => - fmt::fatalf("Unhandled Opcode: {:x}", val); - }; - //TODO see if the above needs to not run if console vector not set - if(console_vector != 0){ - let args = os::args[2..]; - let i: u8 = 0; - let argcount = len(args): u8; - for (let arg .. args){ - // fmt::println("Console input args")!; - for(let char: u8 .. strings::toutf8(arg)){ - // fmt::printfln("Console input arg char: {:x}", char)!; - match (console_input(char,2)) { - case done => - yield done; - case let val: u8 => - fmt::fatalf("Unhandled Opcode: {:x}", val); + //Setting up pollfds for unix::poll + const consolefd: []unix::poll::pollfd = [unix::poll::pollfd { + fd = os::stdin_file, + events = unix::poll::event::POLLIN, + revents = 0, + } ]; + let state: *uxn::uxn = uxn::uxn_init(path)!; + uxn::uxn_reset(state); + + + for (run) { + if(state.running){ + // fmt::printf("Next Step!\n")!; + uxn::uxn_step(state)!; + yield; + }else{ + if(state.console_vector != 0){ + // fmt::printf("Console!\n")!; + let args = os::args[2..]; + let i: u8 = 0; + let argcount = len(args): u8; + for (let arg .. args){ + // fmt::println("Console input args")!; + for(let char: u8 .. strings::toutf8(arg)){ + // fmt::printfln("Console input arg char: {:x}", char)!; + match (uxn::console_input(char,2,state)) { + case done => + yield done; + case let val: u8 => + fmt::fatalf("Unhandled Opcode: {:x}", val); + }; + }; + let ctype: u8 = if(i == (argcount - 1)){ + yield 4; + } else { + yield 3; + }; + match (uxn::console_input('\n',ctype,state)) { + case done => + yield done; + case let val: u8 => + fmt::fatalf("Unhandled Opcode: {:x}", val); + }; + i+=1; //TODO using i here seems inelegant + }; + const pollr = unix::poll::poll(consolefd, unix::poll::NONBLOCK); + if(pollr > 0){ + // fmt::println("Input!")!; + let buf: [MAX_CONSOLE_INPUT]u8 = [0...]; + io::read(os::stdin_file, buf)!; + for( let b .. buf ){ + // fmt::printfln("Input: {}",buf[0])!; + match (uxn::console_input(b,1,state)) { + case done => + yield done; + case let val: u8 => + fmt::fatalf("Unhandled Opcode: {:x}", val); + }; + // uxn::console_input(b,1,state); }; - }; - let ctype: u8 = if(i == (argcount - 1)){ - yield 4; - } else { - yield 3; - }; - match (console_input('\n',ctype)) { - case done => - yield done; - case let val: u8 => - fmt::fatalf("Unhandled Opcode: {:x}", val); }; - i+=1; //TODO using i here seems inelegant + + }; }; - for( dev[0x0f] == 0; i+=1 ){ - let buf: [1]u8 = [0]; - let count = io::read(os::stdin, buf)!; - // fmt::println("Read input")!; - if(count != 0) { - match (console_input(buf[0],1)) { - case done => - yield done; - case let val: u8 => - fmt::fatalf("Unhandled Opcode: {:x}", val); - }; - // fmt::println("Retuned from console_input")!; - }; - }; - match (console_input('\n',4)) { - case done => - yield done; - case let val: u8 => - fmt::fatalf("Unhandled Opcode: {:x}", val); - }; - }; + if(state.dev[0x0f] != 0) run = false; + + + }; };