progress towards working screen device
This commit is contained in:
@@ -10,7 +10,7 @@ HARE_SOURCES != find . -name '*.ha'
|
||||
build: build/meadow
|
||||
|
||||
run: build
|
||||
build/meadow factor.rom
|
||||
build/meadow pixel.rom
|
||||
|
||||
build/meadow: $(HARE_SOURCES)
|
||||
hare build $(LIBS) -o build/meadow src/
|
||||
|
||||
+116
-19
@@ -2,6 +2,10 @@ use sdl3;
|
||||
use sdl3::image;
|
||||
use sdl3::ttf;
|
||||
use types::c;
|
||||
use os;
|
||||
use io;
|
||||
use fmt;
|
||||
use strings;
|
||||
use uxn;
|
||||
|
||||
def WIDTH = 640;
|
||||
@@ -23,20 +27,6 @@ export fn main() void = {
|
||||
const img = image::LoadTexture(render, c::nulstr("./assets/mascot.jpg\0"))!;
|
||||
defer sdl3::DestroyTexture(img);
|
||||
|
||||
ttf::Init()!;
|
||||
defer ttf::Quit();
|
||||
|
||||
let font = ttf::OpenFontIO(
|
||||
sdl3::IOFromConstMem(&tiny_ttf, len(tiny_ttf))!, true, 18.0)!;
|
||||
defer ttf::CloseFont(font);
|
||||
|
||||
let text_color = sdl3::Color { r = 0, g = 255, b = 0, a = 255 };
|
||||
let text = ttf::RenderText_Blended(font, c::nulstr("Hello World!\0"),
|
||||
0, text_color)!;
|
||||
let text_texture = sdl3::CreateTextureFromSurface(render, text)!;
|
||||
sdl3::DestroySurface(text);
|
||||
defer sdl3::DestroyTexture(text_texture);
|
||||
|
||||
let w = 0.0f32, h = 0.0f32;
|
||||
sdl3::GetTextureSize(img, &w, &h)!;
|
||||
sdl3::get_error()!;
|
||||
@@ -45,10 +35,119 @@ export fn main() void = {
|
||||
let x = 0, y = 0;
|
||||
let xd = 1, yd = 1;
|
||||
|
||||
|
||||
const screen_w = WIDTH;
|
||||
const screen_h = HEIGHT;
|
||||
//Create blank texture for screen
|
||||
const meadow_texture = sdl3::CreateTexture(render,
|
||||
sdl3::PixelFormat::XRGB8888,
|
||||
sdl3::TextureAccess::STATIC,
|
||||
screen_w,
|
||||
screen_h)!;
|
||||
defer sdl3::DestroyTexture(meadow_texture);
|
||||
// const pixeldata: [WIDTH * HEIGHT]u32 = [0...];
|
||||
let pixeldata: *[uxn::MAXWIDTH * uxn::MAXHEIGHT]u32 = alloc([0...])!; //TODO figure out actual size
|
||||
|
||||
let run = true;
|
||||
let ev = sdl3::Event { ... };
|
||||
uxn::uxnrun();
|
||||
if(len(os::args) < 2){
|
||||
fmt::printf("usage: %s file.rom [args..]\n")!;
|
||||
return;
|
||||
};
|
||||
let path = os::args[1];
|
||||
let state: *uxn::uxn = uxn::uxn_init(path)!;
|
||||
uxn::uxn_reset(state);
|
||||
for (run) {
|
||||
//UXN stuff
|
||||
if(state.running){
|
||||
// fmt::printf("Next Step!\n")!;
|
||||
uxn::uxn_step(state)!;
|
||||
}else{
|
||||
// fmt::printf("Not Running!\n")!;
|
||||
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 (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
|
||||
};
|
||||
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 (uxn::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 (uxn::console_input('\n',4,state)) { //TODO should this run?
|
||||
case done =>
|
||||
yield done;
|
||||
case let val: u8 =>
|
||||
fmt::fatalf("Unhandled Opcode: {:x}", val);
|
||||
};
|
||||
};
|
||||
};
|
||||
if(state.screen_size_changed){
|
||||
let dims = uxn::get_window_size(state);
|
||||
fmt::printfln("Setting window to width: {:x} height: {:x}", dims.width, dims.height)!;
|
||||
if((dims.width != 0) && (dims.height !=0)){
|
||||
//TODO, check current dims
|
||||
|
||||
sdl3::SetWindowSize(win,dims.width: int,dims.height: int)!;
|
||||
};
|
||||
|
||||
|
||||
state.screen_size_changed = false;
|
||||
};
|
||||
|
||||
if(state.screen_update){
|
||||
let pcount = 0;
|
||||
for(let x: u16 = 0; x < screen_w: u16; x+=1 ){
|
||||
for(let y: u16 = 0; y < screen_h: u16; y+=1 ){
|
||||
const colshort = uxn::get_color(x,y,state);
|
||||
//take 16-bit color and transform to 32-bit number
|
||||
//XRGB -> XXRXGXBX
|
||||
const r = (colshort & 0x0F00): u32 << (3*4);
|
||||
const g = (colshort & 0x00F0): u32 << (2*4);
|
||||
const b = (colshort & 0x000F): u32 << (1*4);
|
||||
const color: u32 = r | g | b;
|
||||
// const data = pixeldata: *[*]u32; //
|
||||
pixeldata[pcount] = color;
|
||||
pcount +=1;
|
||||
};
|
||||
};
|
||||
state.screen_update = false;
|
||||
};
|
||||
|
||||
|
||||
//Render stuff
|
||||
for (sdl3::PollEvent(&ev)) {
|
||||
if (ev.event_type == sdl3::EventType::QUIT) {
|
||||
run = false;
|
||||
@@ -64,10 +163,8 @@ export fn main() void = {
|
||||
h = h: f32,
|
||||
})!;
|
||||
|
||||
let dst = sdl3::FRect { y = y: f32, ... };
|
||||
sdl3::GetTextureSize(text_texture, &dst.w, &dst.h)!;
|
||||
dst.x = x: f32 + (w: f32 - dst.w) / 2.0;
|
||||
sdl3::RenderTexture(render, text_texture, null, &dst)!;
|
||||
sdl3::UpdateTexture(meadow_texture, null, pixeldata: *opaque, 32)!;
|
||||
sdl3::RenderTexture(render, meadow_texture, null, null)!;
|
||||
|
||||
sdl3::RenderPresent(render)!;
|
||||
sdl3::Delay(1000 / 60);
|
||||
|
||||
+475
-364
@@ -10,26 +10,59 @@ use strings;
|
||||
// let ptr: [2] u8 = [0...];
|
||||
// let stk: [2][0x100] u8 = [[0...],[0...]];
|
||||
|
||||
type uxn = struct {
|
||||
|
||||
export type uxn = struct {
|
||||
pc: u16,
|
||||
console_vector: u16,
|
||||
screen_vector: u16,
|
||||
ram: [0x10000] u8,
|
||||
dev: [0x100] u8,
|
||||
ptr: [2] u8,
|
||||
stk: [2][0x100] u8,
|
||||
running: bool,
|
||||
screen_size_changed: bool,
|
||||
screen_update: bool,
|
||||
screen: uxn_screen,
|
||||
palette: [4] u16,
|
||||
};
|
||||
|
||||
//TODO find a way to use these below
|
||||
export def MAXWIDTH = 4096;
|
||||
export def MAXHEIGHT = 2160;
|
||||
//Screen consists of two layers of 2-bit pixels
|
||||
export type uxn_screen = ([MAXWIDTH][MAXHEIGHT]u8, [MAXWIDTH][MAXHEIGHT]u8);
|
||||
|
||||
const reset_vector: u16 = 0x0100;
|
||||
|
||||
fn initialize_uxn_mem() *uxn = {
|
||||
return alloc(uxn{
|
||||
pc = 0x0100,
|
||||
pc = reset_vector,
|
||||
console_vector = 0,
|
||||
screen_vector = 0,
|
||||
ram = [0...],
|
||||
dev = [0...],
|
||||
ptr = [0...],
|
||||
stk = [[0...],[0...]]
|
||||
stk = [[0...],[0...]],
|
||||
running = false,
|
||||
screen_size_changed = false,
|
||||
screen_update = false,
|
||||
screen = ([[0...]...],[[0...]...]),
|
||||
palette = [0...],
|
||||
})!;
|
||||
};
|
||||
|
||||
|
||||
export fn get_window_size(state: *uxn) struct{width: u16, height: u16} = {
|
||||
let width_high = state.dev[0x22];
|
||||
let width_low = state.dev[0x23];
|
||||
let height_high = state.dev[0x24];
|
||||
let height_low = state.dev[0x25];
|
||||
|
||||
let result = struct {width: u16 = short_from_bytes(width_high,width_low),
|
||||
height: u16 = short_from_bytes(height_high,height_low) };
|
||||
return result;
|
||||
};
|
||||
|
||||
fn emu_dei(port: u8, state: *uxn) u8 = {
|
||||
let val = state.dev[port];
|
||||
// fmt::printfln("Read {:x} from port {:x}", val, port)!;
|
||||
@@ -46,23 +79,73 @@ fn emu_deo(port: u8, value: u8, state: *uxn) void = {
|
||||
let low = value;
|
||||
state.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 0x21 =>
|
||||
let high = state.dev[0x20];
|
||||
let low = value;
|
||||
state.screen_vector = short_from_bytes(high,low);
|
||||
case 0x2e =>
|
||||
draw_pixel(value,state);
|
||||
case 0x2f =>
|
||||
yield;
|
||||
case =>
|
||||
return;
|
||||
if( port == 0x22 ||
|
||||
port == 0x23 ||
|
||||
port == 0x24 ||
|
||||
port == 0x25 ) {
|
||||
state.screen_size_changed = true;
|
||||
}else if( port == 0x09 || //TODO maybe also trigger on high bytes
|
||||
port == 0x0b ||
|
||||
port == 0x0d ){
|
||||
regenerate_palettes(state);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
fn regenerate_palettes(state: *uxn) void = {
|
||||
const r = short_from_bytes(state.dev[0x08],state.dev[0x09]);
|
||||
const g = short_from_bytes(state.dev[0x0a],state.dev[0x0b]);
|
||||
const b = short_from_bytes(state.dev[0x0c],state.dev[0x0d]);
|
||||
|
||||
type evalerror = !void;
|
||||
type unhandled = !u8;
|
||||
|
||||
type error = !(evalerror | unhandled);
|
||||
state.palette[0] = ((r & 0xf000) >> 4) | ((g & 0xf000) >> 8) | ((b & 0xf000) >> 12);
|
||||
state.palette[1] = ((r & 0x0f00) >> 0) | ((g & 0x0f00) >> 4) | ((b & 0x0f00) >> 8);
|
||||
state.palette[2] = ((r & 0x00f0) << 4) | ((g & 0x00f0) >> 0) | ((b & 0x00f0) >> 4);
|
||||
state.palette[3] = ((r & 0x000f) << 8) | ((g & 0x000f) << 4) | ((b & 0x000f) >> 0);
|
||||
};
|
||||
|
||||
|
||||
fn draw_pixel(value: u8, state: *uxn) void = {
|
||||
//TODO handle fill
|
||||
const color = value & 0b00000011;
|
||||
const x = short_from_bytes(state.dev[0x28],state.dev[0x29]);
|
||||
const y = short_from_bytes(state.dev[0x2a],state.dev[0x2b]);
|
||||
if((value & 0b01000000) == 0){
|
||||
state.screen.0[x][y] = color;
|
||||
} else {
|
||||
state.screen.1[x][y] = color;
|
||||
};
|
||||
state.screen_update = true;
|
||||
};
|
||||
|
||||
export fn get_color(x: u16, y: u16, state: *uxn) u16 = {
|
||||
// check layer 1
|
||||
let color = state.screen.1[x][y] & 0b00000011;
|
||||
if(color == 0){
|
||||
color = state.screen.0[x][y];
|
||||
};
|
||||
return state.palette[color];
|
||||
};
|
||||
|
||||
export type evalerror = !void;
|
||||
export type unhandled = !u8;
|
||||
|
||||
export type error = !(evalerror | unhandled);
|
||||
|
||||
type simple_op = void;
|
||||
type literal_op = struct { short: bool, ret: bool};
|
||||
@@ -295,169 +378,165 @@ fn pop_or_get(inst: normal_op, off: u8, state: *uxn) (u8 | u16) = {
|
||||
fn uxn_eval(new_pc: u16, state: *uxn) (done | 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;
|
||||
for(true){
|
||||
// fmt::printfln("Starting eval with pc: {:x}", pc)!;
|
||||
let readval = state.ram[state.pc];
|
||||
let inst: instruction = get_instruction(readval)?;
|
||||
state.pc += 1; //TODO verify all pc changes
|
||||
state.running = true;
|
||||
for(state.running){
|
||||
uxn_step(state)?;
|
||||
};
|
||||
return done;
|
||||
};
|
||||
|
||||
match(inst) {
|
||||
// /* BRK */ case 0x00: return 1;
|
||||
case BRK =>
|
||||
// fmt::println("Break!")!;
|
||||
return done;
|
||||
// /* JCI */ case 0x20: if(DEC(0)) { IMM state.pc += a; } else pc += 2; break;
|
||||
case JCI =>
|
||||
let val: u8 = pop_from_stack(false, false, false, state): u8;
|
||||
if(val != 0) {
|
||||
state.pc += 2 + short_from_bytes(state.ram[state.pc],state.ram[state.pc+1]); //TODO, is this signed?
|
||||
}else{
|
||||
state.pc += 2;
|
||||
};
|
||||
// /* JMI */ case 0x40: IMM pc += a; break;
|
||||
case JMI =>
|
||||
state.pc = state.pc + 2 + short_from_bytes(state.ram[state.pc],state.ram[state.pc+1]); //TODO is this signed?
|
||||
// /* JSI */ case 0x60: IMM PUx(pc, 1, 1) pc += a; break;
|
||||
case JSI =>
|
||||
push_to_stack(true, state.pc + 2, state);
|
||||
state.pc = state.pc + 2 + short_from_bytes(state.ram[state.pc],state.ram[state.pc+1]); //TODO is this signed?
|
||||
export fn uxn_step(state: *uxn) (done | error) = {
|
||||
// fmt::printfln("Starting eval with pc: {:x}", pc)!;
|
||||
let readval = state.ram[state.pc];
|
||||
let inst: instruction = get_instruction(readval)?;
|
||||
state.pc += 1; //TODO verify all pc changes
|
||||
|
||||
// /* LIT */ case 0x80: INC(0) = ram[pc++]; break;
|
||||
case let lit_inst: LIT =>
|
||||
push_to_stack(lit_inst.ret, state.ram[state.pc], state);
|
||||
match(inst) {
|
||||
// /* BRK */ case 0x00: return 1;
|
||||
case BRK =>
|
||||
// fmt::println("Break!")!;
|
||||
state.running = false;
|
||||
return done;
|
||||
// /* JCI */ case 0x20: if(DEC(0)) { IMM state.pc += a; } else pc += 2; break;
|
||||
case JCI =>
|
||||
let val: u8 = pop_from_stack(false, false, false, state): u8;
|
||||
if(val != 0) {
|
||||
state.pc += 2 + short_from_bytes(state.ram[state.pc],state.ram[state.pc+1]); //TODO, is this signed?
|
||||
}else{
|
||||
state.pc += 2;
|
||||
};
|
||||
// /* JMI */ case 0x40: IMM pc += a; break;
|
||||
case JMI =>
|
||||
state.pc = state.pc + 2 + short_from_bytes(state.ram[state.pc],state.ram[state.pc+1]); //TODO is this signed?
|
||||
// /* JSI */ case 0x60: IMM PUx(pc, 1, 1) pc += a; break;
|
||||
case JSI =>
|
||||
push_to_stack(true, state.pc + 2, state);
|
||||
state.pc = state.pc + 2 + short_from_bytes(state.ram[state.pc],state.ram[state.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, state.ram[state.pc], state);
|
||||
state.pc = state.pc + 1;
|
||||
if(lit_inst.short) {
|
||||
push_to_stack(lit_inst.ret, state.ram[state.pc],state);
|
||||
state.pc = state.pc + 1;
|
||||
if(lit_inst.short) {
|
||||
push_to_stack(lit_inst.ret, state.ram[state.pc],state);
|
||||
state.pc = state.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,state)) {
|
||||
//TODO this whole match statement seems unnecessary
|
||||
case let byte: u8 =>
|
||||
yield byte + 1;
|
||||
case let short: u16 =>
|
||||
yield short + 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,state)) {
|
||||
//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,state);
|
||||
// /* 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,state);
|
||||
};
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(nip_inst,1,state);
|
||||
push_to_stack(nip_inst.ret, top, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(swp_inst,1,state);
|
||||
push_to_stack(inc_inst.ret,val,state);
|
||||
// /* 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,state);
|
||||
};
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(nip_inst,1,state);
|
||||
push_to_stack(nip_inst.ret, top, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(swp_inst,1,state);
|
||||
|
||||
push_to_stack(swp_inst.ret, top, state);
|
||||
push_to_stack(swp_inst.ret, bot, state);
|
||||
// /* 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,state);
|
||||
let mid = pop_or_get(rot_inst,1,state);
|
||||
let bot = pop_or_get(rot_inst,2,state);
|
||||
push_to_stack(swp_inst.ret, top, state);
|
||||
push_to_stack(swp_inst.ret, bot, state);
|
||||
// /* 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,state);
|
||||
let mid = pop_or_get(rot_inst,1,state);
|
||||
let bot = pop_or_get(rot_inst,2,state);
|
||||
|
||||
push_to_stack(rot_inst.ret, mid, state);
|
||||
push_to_stack(rot_inst.ret, top, state);
|
||||
push_to_stack(rot_inst.ret, bot, state);
|
||||
// /* 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, state);
|
||||
push_to_stack(dup_inst.ret, val, state);
|
||||
push_to_stack(dup_inst.ret, val, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(ovr_inst,1,state);
|
||||
push_to_stack(rot_inst.ret, mid, state);
|
||||
push_to_stack(rot_inst.ret, top, state);
|
||||
push_to_stack(rot_inst.ret, bot, state);
|
||||
// /* 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, state);
|
||||
push_to_stack(dup_inst.ret, val, state);
|
||||
push_to_stack(dup_inst.ret, val, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(ovr_inst,1,state);
|
||||
|
||||
push_to_stack(ovr_inst.ret, bot, state);
|
||||
push_to_stack(ovr_inst.ret, top, state);
|
||||
push_to_stack(ovr_inst.ret, bot, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(equ_inst,1,state);
|
||||
push_to_stack(ovr_inst.ret, bot, state);
|
||||
push_to_stack(ovr_inst.ret, top, state);
|
||||
push_to_stack(ovr_inst.ret, bot, state);
|
||||
// /* 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,state);
|
||||
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;
|
||||
};
|
||||
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 =>
|
||||
let top = pop_or_get(neq_inst,0,state);
|
||||
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;
|
||||
};
|
||||
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 =>
|
||||
let top = pop_or_get(neq_inst,0,state);
|
||||
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;
|
||||
};
|
||||
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 =>
|
||||
let top = pop_or_get(gth_inst,0,state);
|
||||
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(top: u16 != bot: 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 =>
|
||||
let top = pop_or_get(gth_inst,0,state);
|
||||
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;
|
||||
};
|
||||
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 =>
|
||||
let top = pop_or_get(lth_inst,0,state);
|
||||
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;
|
||||
};
|
||||
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 =>
|
||||
let top = pop_or_get(lth_inst,0,state);
|
||||
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;
|
||||
};
|
||||
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
|
||||
case let s: u16 =>
|
||||
state.pc = s;
|
||||
};
|
||||
//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, 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
|
||||
case let s: u16 =>
|
||||
state.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,state);
|
||||
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; }, state ): u8;
|
||||
if( cond != 0) {
|
||||
match(addr) {
|
||||
case let b: u8 =>
|
||||
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;
|
||||
};
|
||||
};
|
||||
// /* JSR */ OPC(0x0e,POx(a,d),PUx(pc,1,!r) MOV)
|
||||
case let jsr_inst: JSR =>
|
||||
let addr = pop_or_get(jsr_inst,0,state);
|
||||
push_to_stack(true, state.pc, state);
|
||||
// /* 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,state);
|
||||
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; }, state ): u8;
|
||||
if( cond != 0) {
|
||||
match(addr) {
|
||||
case let b: u8 =>
|
||||
let off = b: i8: i32;
|
||||
@@ -465,216 +544,225 @@ fn uxn_eval(new_pc: u16, state: *uxn) (done | error ) = {
|
||||
case let s: u16 =>
|
||||
state.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,state);
|
||||
push_to_stack(true, state.pc, state);
|
||||
match(addr) {
|
||||
case let b: u8 =>
|
||||
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;
|
||||
};
|
||||
|
||||
// /* STH */ OPC(0x0f,GOT(x),PUT(x,!r))
|
||||
case let sth_inst: STH =>
|
||||
let val = pop_or_get(sth_inst,0,state);
|
||||
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];
|
||||
};
|
||||
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);
|
||||
// /* STH */ OPC(0x0f,GOT(x),PUT(x,!r))
|
||||
case let sth_inst: STH =>
|
||||
let val = pop_or_get(sth_inst,0,state);
|
||||
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];
|
||||
};
|
||||
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
|
||||
};
|
||||
// /* 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];
|
||||
};
|
||||
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_from_stack(str_inst.keep, str_inst.ret, false, state): u16): i8;
|
||||
let addr: u16 = (state.pc: u32: i32 + reladdr): u16;
|
||||
let val = pop_from_stack(str_inst.keep, str_inst.ret, str_inst.short, state);
|
||||
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
|
||||
};
|
||||
// /* 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];
|
||||
};
|
||||
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_from_stack(sta_inst.keep, sta_inst.ret, true, state): u16;
|
||||
let val = pop_from_stack(sta_inst.keep, sta_inst.ret, sta_inst.short, state);
|
||||
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
|
||||
};
|
||||
// /* 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, state): u8;
|
||||
let val = if(dei_inst.short){
|
||||
yield short_from_bytes(emu_dei(port,state),emu_dei(port+1,state));
|
||||
}else{
|
||||
yield emu_dei(port,state);
|
||||
};
|
||||
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);
|
||||
};
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(add_inst,1,state);
|
||||
let res = if(!add_inst.short){
|
||||
yield (top: u8 + bot: u8);
|
||||
} else {
|
||||
yield (top: u16 + bot: u16);
|
||||
};
|
||||
push_to_stack(add_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(sub_inst,1,state);
|
||||
let res = if(!sub_inst.short){
|
||||
yield (bot: u8 - top: u8);
|
||||
} else {
|
||||
yield (bot: u16 - top: u16);
|
||||
};
|
||||
push_to_stack(sub_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(mul_inst,1,state);
|
||||
let res = if(!mul_inst.short){
|
||||
yield (bot: u8 * top: u8);
|
||||
} else {
|
||||
yield (bot: u16 * top: u16);
|
||||
};
|
||||
push_to_stack(mul_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(div_inst,1,state);
|
||||
}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
|
||||
};
|
||||
// /* 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];
|
||||
};
|
||||
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_from_stack(str_inst.keep, str_inst.ret, false, state): u16): i8;
|
||||
let addr: u16 = (state.pc: u32: i32 + reladdr): u16;
|
||||
let val = pop_from_stack(str_inst.keep, str_inst.ret, str_inst.short, state);
|
||||
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
|
||||
};
|
||||
// /* 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];
|
||||
};
|
||||
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_from_stack(sta_inst.keep, sta_inst.ret, true, state): u16;
|
||||
let val = pop_from_stack(sta_inst.keep, sta_inst.ret, sta_inst.short, state);
|
||||
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
|
||||
};
|
||||
// /* 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, state): u8;
|
||||
let val = if(dei_inst.short){
|
||||
yield short_from_bytes(emu_dei(port,state),emu_dei(port+1,state));
|
||||
}else{
|
||||
yield emu_dei(port,state);
|
||||
};
|
||||
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);
|
||||
};
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(add_inst,1,state);
|
||||
let res = if(!add_inst.short){
|
||||
yield (top: u8 + bot: u8);
|
||||
} else {
|
||||
yield (top: u16 + bot: u16);
|
||||
};
|
||||
push_to_stack(add_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(sub_inst,1,state);
|
||||
let res = if(!sub_inst.short){
|
||||
yield (bot: u8 - top: u8);
|
||||
} else {
|
||||
yield (bot: u16 - top: u16);
|
||||
};
|
||||
push_to_stack(sub_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(mul_inst,1,state);
|
||||
let res = if(!mul_inst.short){
|
||||
yield (bot: u8 * top: u8);
|
||||
} else {
|
||||
yield (bot: u16 * top: u16);
|
||||
};
|
||||
push_to_stack(mul_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(div_inst,1,state);
|
||||
|
||||
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, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(and_inst,1,state);
|
||||
let res = if(!and_inst.short){
|
||||
yield (bot: u8 & top: u8);
|
||||
} else {
|
||||
yield (bot: u16 & top: u16);
|
||||
};
|
||||
push_to_stack(and_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(ora_inst,1,state);
|
||||
let res = if(!ora_inst.short){
|
||||
yield (bot: u8 | top: u8);
|
||||
} else {
|
||||
yield (bot: u16 | top: u16);
|
||||
};
|
||||
push_to_stack(ora_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(eor_inst,1,state);
|
||||
let res = if(!eor_inst.short){
|
||||
yield (bot: u8 ^ top: u8);
|
||||
} else {
|
||||
yield (bot: u16 ^ top: u16);
|
||||
};
|
||||
push_to_stack(eor_inst.ret, res, state);
|
||||
// /* 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, state): 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, state): u8;
|
||||
let high = pop_or_get(normal_op{short = false, keep = sft_inst.keep, ret = sft_inst.ret}, 2, state): u8;
|
||||
let val = short_from_bytes(high,low);
|
||||
let res = (val >> rightshifts ) << leftshifts;
|
||||
push_to_stack(sft_inst.ret, res, state);
|
||||
}else{
|
||||
let val = pop_or_get(sft_inst, 1, state): u8;
|
||||
let res = (val >> rightshifts ) << leftshifts;
|
||||
push_to_stack(sft_inst.ret, res, state);
|
||||
};
|
||||
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, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(and_inst,1,state);
|
||||
let res = if(!and_inst.short){
|
||||
yield (bot: u8 & top: u8);
|
||||
} else {
|
||||
yield (bot: u16 & top: u16);
|
||||
};
|
||||
push_to_stack(and_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(ora_inst,1,state);
|
||||
let res = if(!ora_inst.short){
|
||||
yield (bot: u8 | top: u8);
|
||||
} else {
|
||||
yield (bot: u16 | top: u16);
|
||||
};
|
||||
push_to_stack(ora_inst.ret, res, state);
|
||||
// /* 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,state);
|
||||
let bot = pop_or_get(eor_inst,1,state);
|
||||
let res = if(!eor_inst.short){
|
||||
yield (bot: u8 ^ top: u8);
|
||||
} else {
|
||||
yield (bot: u16 ^ top: u16);
|
||||
};
|
||||
push_to_stack(eor_inst.ret, res, state);
|
||||
// /* 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, state): 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, state): u8;
|
||||
let high = pop_or_get(normal_op{short = false, keep = sft_inst.keep, ret = sft_inst.ret}, 2, state): u8;
|
||||
let val = short_from_bytes(high,low);
|
||||
let res = (val >> rightshifts ) << leftshifts;
|
||||
push_to_stack(sft_inst.ret, res, state);
|
||||
}else{
|
||||
let val = pop_or_get(sft_inst, 1, state): u8;
|
||||
let res = (val >> rightshifts ) << leftshifts;
|
||||
push_to_stack(sft_inst.ret, res, state);
|
||||
};
|
||||
|
||||
|
||||
case =>
|
||||
return readval: unhandled;
|
||||
};
|
||||
case =>
|
||||
return readval: unhandled;
|
||||
};
|
||||
|
||||
|
||||
// return evalerror;
|
||||
return done;
|
||||
};
|
||||
|
||||
fn console_input(c: u8, ctype: u8, state: *uxn) (done | error) = {
|
||||
export fn console_input(c: u8, ctype: u8, state: *uxn) (done | error) = {
|
||||
state.dev[0x12] = c;
|
||||
state.dev[0x17] = ctype;
|
||||
if(state.console_vector != 0){
|
||||
@@ -697,7 +785,30 @@ fn strerror(err: error) str = {
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export fn uxn_init(path: str) ( *uxn | error ) = {
|
||||
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?
|
||||
return state;
|
||||
};
|
||||
export fn uxn_reset(state: *uxn) void = {
|
||||
state.pc = reset_vector;
|
||||
state.running = true;
|
||||
};
|
||||
export fn uxnrun() void = {
|
||||
if(len(os::args) < 2){
|
||||
fmt::printf("usage: %s file.rom [args..]\n")!;
|
||||
|
||||
Reference in New Issue
Block a user