SDL Errors don't always crash the emulator. Fixed JMP relative address handling.

This commit is contained in:
JJ Bliss
2026-05-05 10:27:47 -04:00
parent fcf42a5b4a
commit f5b5f76979
2 changed files with 109 additions and 166 deletions
+11 -1
View File
@@ -285,6 +285,11 @@ export fn main() void = {
const mods = ev.key.mod;
const sym = sdl3::GetKeyFromScancode(scancode,mods,false);
uxn::set_key_down(sym: u8,state);
// Handle Debug
if(key == sdl3::K_F2){
fmt::println("Debug Print:")!;
uxn::print_stack_debug(state);
};
//Handle keyboard controller keys
// Ctrl -> A 0x01
if(key == sdl3::K_LCTRL || key == sdl3::K_RCTRL){
@@ -407,6 +412,11 @@ export fn main() void = {
// sdl3::Delay(1000 / 60);
sdl3::get_error()!;
match(sdl3::get_error()){
case void =>
yield;
case let err: sdl3::error =>
fmt::printfln("SDL Error: {}", sdl3::strerror(err))!;
};
};
};
+98 -165
View File
@@ -421,6 +421,27 @@ fn get_instruction(byte: u8) (instruction | error) = {
};
};
export fn print_stack_debug(state: *uxn) void = {
fmt::println("Working Stack:")!;
print_stack(false,state);
fmt::println("Return Stack:")!;
print_stack(true,state);
};
fn print_stack(ret: bool, state: *uxn) void = {
const p = switch(ret){
case true =>
yield 1;
case false =>
yield 0;
};
for(let i = state.ptr[p] - 8; i != state.ptr[p]; i+=1){
fmt::printf("{:x} ",state.stk[p][i])!;
};
fmt::printf("\n")!;
};
fn short_from_bytes(high: u8, low: u8) u16 = {
return (high: u16) << 8 | (low: u16);
};
@@ -688,24 +709,24 @@ export fn uxn_step(state: *uxn) (done | error) = {
let bot = pop_or_get(equ_inst,1,state);
//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;
// };
let val: u8 = if(!equ_inst.short){
yield if(bot: u8 == top: u8){
yield 1;
} else {
yield 0;
};
let val: u8 = if(top: u16 == bot: u16){
yield 1;
} else {
yield if(bot: u16 == top: u16){
yield 1;
} else {
yield 0;
};
yield 0;
};
// let val: u8 = if(!equ_inst.short){
// yield if(bot: u8 == top: u8){
// yield 1;
// } else {
// yield 0;
// };
// } else {
// yield if(bot: u16 == top: u16){
// yield 1;
// } else {
// yield 0;
// };
// };
push_to_stack(equ_inst.ret, val, state);
// /* NEQ */ OPC(0x09,POx(a,d) POx(b,d),PUx(b != a,0,r))
case let neq_inst: NEQ =>
@@ -713,24 +734,24 @@ export fn uxn_step(state: *uxn) (done | error) = {
let bot = pop_or_get(neq_inst,1,state);
//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;
// };
let val: u8 = if(!neq_inst.short){
yield if(bot: u8 != top: u8){
yield 1;
} else {
yield 0;
};
let val: u8 = if(top: u16 != bot: u16){
yield 1;
} else {
yield if(bot: u16 != top: u16){
yield 1;
} else {
yield 0;
};
yield 0;
};
// let val: u8 = if(!neq_inst.short){
// yield if(bot: u8 != top: u8){
// yield 1;
// } else {
// yield 0;
// };
// } else {
// yield if(bot: u16 != top: u16){
// yield 1;
// } else {
// yield 0;
// };
// };
push_to_stack(neq_inst.ret, val, state);
// /* GTH */ OPC(0x0a,POx(a,d) POx(b,d),PUx(b > a,0,r))
case let gth_inst: GTH =>
@@ -738,24 +759,24 @@ export fn uxn_step(state: *uxn) (done | error) = {
let bot = pop_or_get(gth_inst,1,state);
//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;
// };
let val: u8 = if(!gth_inst.short){
yield if(bot: u8 > top: u8){
yield 1;
} else {
yield 0;
};
let val: u8 = if(bot: u16 > top: u16){
yield 1;
} else {
yield if(bot: u16 > top: u16){
yield 1;
} else {
yield 0;
};
yield 0;
};
// let val: u8 = if(!gth_inst.short){
// yield if(bot: u8 > top: u8){
// yield 1;
// } else {
// yield 0;
// };
// } else {
// yield if(bot: u16 > top: u16){
// yield 1;
// } else {
// yield 0;
// };
// };
push_to_stack(gth_inst.ret, val, state);
// /* LTH */ OPC(0x0b,POx(a,d) POx(b,d),PUx(b < a,0,r))
case let lth_inst: LTH =>
@@ -763,31 +784,33 @@ export fn uxn_step(state: *uxn) (done | error) = {
let bot = pop_or_get(lth_inst,1,state);
//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;
// };
let val: u8 = if(!lth_inst.short){
yield if(bot: u8 < top: u8){
yield 1;
} else {
yield 0;
};
let val: u8 = if(bot: u16 < top: u16){
yield 1;
} else {
yield if(bot: u16 < top: u16){
yield 1;
} else {
yield 0;
};
yield 0;
};
// let val: u8 = if(!lth_inst.short){
// yield if(bot: u8 < top: u8){
// yield 1;
// } else {
// yield 0;
// };
// } else {
// yield if(bot: u16 < top: u16){
// yield 1;
// } else {
// yield 0;
// };
// };
push_to_stack(lth_inst.ret, val, state);
// /* JMP */ OPC(0x0c,POx(a,d),MOV)
case let jmp_inst: JMP =>
let addr = pop_or_get(jmp_inst,0,state);
match(addr) {
case let b: u8 =>
state.pc = state.pc + b: u16; //TODO verify if pc changes are right
let off = b: i8: i32;
state.pc = (state.pc: i32 + off): u16; //TODO verify if pc changes are right
case let s: u16 =>
state.pc = s;
};
@@ -868,15 +891,16 @@ export fn uxn_step(state: *uxn) (done | error) = {
push_to_stack(dei_inst.ret,val,state);
// /* 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, state): u8;
if(deo_inst.short){
let low = pop_or_get(normal_op{short = false, keep = deo_inst.keep, ret = deo_inst.ret}, 1, state): u8;
let high = pop_or_get(normal_op{short = false, keep = deo_inst.keep, ret = deo_inst.ret}, 2, state): u8;
emu_deo(port,high,state);
emu_deo(port+1,low,state);
}else{
let val = pop_or_get(deo_inst, 1, state): u8;
emu_deo(port,val,state);
const port: u8 = pop_or_get(normal_op{short = false, keep = deo_inst.keep, ret = deo_inst.ret}, 0, state): u8;
const val = pop_or_peek(deo_inst,1,state);
match(val){
case let s: u16 =>
const high: u8 = (s >> 8): u8;
const low: u8 = s: u8;
emu_deo(port,high,state);
emu_deo(port+1,low,state);
case let b: u8 =>
emu_deo(port,b,state);
};
// /* ADD */ OPC(0x18,POx(a,d) POx(b,d),PUx(b + a, d,r))
case let add_inst: ADD =>
@@ -1026,94 +1050,3 @@ export fn uxn_reset(state: *uxn) void = {
state.running = true;
uxn_eval(reset_vector,state)!;
};
// export fn uxnrun() void = {
// 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));
// };
// let state: *uxn = initialize_uxn_mem();
// //Copy rom into ram
// let bytesread = match (io::read(romfile,state.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){
// state.dev[0x17] = 1;
// };
// // dev[0x17] = argc > 2;
// let eval = match (uxn_eval(0x100, state)) {
// 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(state.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,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 (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
// };
// for( state.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,state)) {
// 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,state)) { //TODO should this run?
// // case done =>
// // yield done;
// // case let val: u8 =>
// // fmt::fatalf("Unhandled Opcode: {:x}", val);
// // };
// };
// fmt::println("Done with uxn")!;
// return;
// };