From 73017d0f4938145ad2837fdb9cc725c94b705d07 Mon Sep 17 00:00:00 2001 From: miezekatze Date: Fri, 11 Jul 2025 22:33:13 +0200 Subject: [PATCH 1/3] fix some examples, implement getchar/read --- libb/6502.b | 240 +++++++++++++++++++++++++++++------------ src/codegen/mos6502.rs | 2 +- src/crust.rs | 1 + src/runner/mos6502.rs | 48 +++++++-- 4 files changed, 208 insertions(+), 83 deletions(-) diff --git a/libb/6502.b b/libb/6502.b index dc19cd61..73bd7a8f 100644 --- a/libb/6502.b +++ b/libb/6502.b @@ -1,89 +1,60 @@ exit(code) { - 0(code); + (*0xFFFC)(code); } - abort() { exit(69); } - -putchar(c) { - 0xFFEF(c); -} - -/* TODO: fd not supported */ -fputc(c, fd) { - putchar(c); -} - -/* TODO: actually allocate something */ -__heap_ptr 0x0200; -malloc(size) { - extrn printf; - auto ptr; - ptr = __heap_ptr; - __heap_ptr += size; - if (__heap_ptr >= 0x1000) { - printf("Allocation reached end: %p\nTODO: allow allocating more, implement free\n", __heap_ptr); +assert(cond, msg) { + if (cond == 0) { + printf("Assertion failed: %s\n", msg); abort(); } - return (ptr); -} -/* TODO: free someting? */ -realloc(ptr, size) { - return (malloc(size)); } -/* TODO: Try to implement this function with assembly - Problem with this implementation is that it is not - mapped to the operator - We cannot call this function `div` as it conflicts - with the `divmod` test -*/ -_div(a, b) { - auto d, sign; - sign = 0; - if (a < 0) { - sign = !sign; - a = -a; - } - if (b < 0) { - sign = !sign; - b = -a; +/* not correct at all */ +usleep(n) { + auto i, j; + if (n < 0) n = 32767; + i = 0; while (i < n) { + __asm__("nop"); + i++; } +} - d = 0; while(a >= b) { - a = a - b; - d++; - } - if (sign) d = -d; - return (d); +/* IO functions */ +putchar(c) { + extrn lchar; + lchar(0xD012, 0, c); } -_udiv(a, b) { - auto d; - d = 0; while(a >= b | a < 0) { - a = a - b; - d++; - } - return (d); + +getchar() { + extrn char; + return (char(0xD010, 0)); } -/* TODO: Try to implement this function with assembly - Problem with this implementation is that it is not - mapped to the operator */ -_rem (a, b) { - auto d; - while(a >= b) { - a = a - b; +read(fd, buf, n) { + extrn lchar; + auto i, c; + + assert(fd == 0, "only fd==0 supported for read"); + i = 0; while (i < n) { + c = getchar(); + lchar(buf, i, c); + if (c == '\n') { + return (n); /* simulate terminal behaviour */ + } + if (c == 0xFF) return (i); + i++; } - return (a); + + return (n); } -_urem(a, b) { - auto d; - while(a >= b | a < 0) { - a = a - b; - } - return (a); + +/* TODO: fd not supported */ +fputc(c, fd) { + putchar(c); } +fflush(); /* nop */ printn(n, b, sign) { auto a, c, d, __div, __rem; @@ -104,6 +75,15 @@ printn(n, b, sign) { putchar(c); } +stdin 0; +stdout 1; +stderr 1; + +fprintf(fd, str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) { + assert((fd == 1) | (fd == 2), "only fd in [1,2] supported for fprintf"); + return (printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)); +} + printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) { extrn char; auto i, j, arg, c; @@ -115,7 +95,7 @@ printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) { c = char(str, i); while (c != 0) { if (c == '\n') { - putchar(0xD); // \r + putchar(0xD); /* \r */ } if(c == '%') { @@ -153,6 +133,86 @@ printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) { } } +/* Math functions */ +atoi(str) { + extrn char; + + auto i, c, n, neg; + neg = 0; + n = 0; + + if (char(str, 0) == '-') { + neg = 1; + str++; + } + + i = 0; while (1) { + c = char(str, i); + if ((c == 0) | (c < '0') | (c > '9')) goto end; + n = n * 10 + (c - '0'); + i++; + } + + end:; + if (neg) n = -n; + + return (n); +} + +/* TODO: Try to implement this function with assembly + Problem with this implementation is that it is not + mapped to the operator + We cannot call this function `div` as it conflicts + with the `divmod` test +*/ +_div(a, b) { + auto d, sign; + sign = 0; + if (a < 0) { + sign = !sign; + a = -a; + } + if (b < 0) { + sign = !sign; + b = -a; + } + + d = 0; while(a >= b) { + a = a - b; + d++; + } + if (sign) d = -d; + return (d); +} +_udiv(a, b) { + auto d; + d = 0; while(a >= b | a < 0) { + a = a - b; + d++; + } + return (d); +} + +/* TODO: Try to implement this function with assembly + Problem with this implementation is that it is not + mapped to the operator */ +_rem (a, b) { + auto d; + while(a >= b) { + a = a - b; + } + return (a); +} +_urem(a, b) { + auto d; + while(a >= b | a < 0) { + a = a - b; + } + return (a); +} + + +/* memory related functions */ strlen(s) { extrn char; auto n; @@ -167,7 +227,6 @@ toupper(c) { } -/* memory related functions */ memset(addr, val, size) { extrn lchar; auto i; @@ -177,3 +236,42 @@ memset(addr, val, size) { i += 1; } } + +memcpy(dest, src, n) { + extrn char, lchar; + auto i, rn; + rn = n; + if (n & 1) n--; + + i = 0; while (i < n) { + dest[i] = src[i]; + i++; + } + + if (rn & 1) lchar(dest, n-1, char(src, n-1)); + return (dest); +} + +/* TODO: actually allocate something */ +__heap_ptr 0x0E000; +malloc(size) { + extrn printf; + auto ptr; + ptr = __heap_ptr; + __heap_ptr += size; + if (__heap_ptr >= 0xFF00) { + printf("Allocation reached end: %p\nTODO: allow allocating more, implement free\n", __heap_ptr); + abort(); + } + return (ptr); +} +free() { + /* TODO: free someting */ +} +realloc(ptr, size) { + auto nptr; + nptr = malloc(size); + memcpy(nptr, ptr, size); + free(ptr); + return (nptr); +} diff --git a/src/codegen/mos6502.rs b/src/codegen/mos6502.rs index 4d81793d..1cce8791 100644 --- a/src/codegen/mos6502.rs +++ b/src/codegen/mos6502.rs @@ -817,7 +817,7 @@ pub unsafe fn generate_function(name: *const c_char, params_count: usize, auto_v instr8(out, LDX, IMM, 0); instr8(out, CMP, IMM, 0); - instr8(out, BNE, REL, 5); + instr8(out, BNE, REL, 6); instr(out, TYA); instr8(out, CMP, IMM, 0); diff --git a/src/crust.rs b/src/crust.rs index 1ea13edb..8d39c6f2 100644 --- a/src/crust.rs +++ b/src/crust.rs @@ -99,6 +99,7 @@ pub mod libc { pub fn strlen(s: *const c_char) -> usize; pub fn strtoull(nptr: *const c_char, endptr: *mut*mut c_char, base: c_int) -> c_ulonglong; pub fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: *mut FILE) -> usize; + pub fn getchar() -> c_int; pub fn abort() -> !; pub fn strdup(s: *const c_char) -> *mut c_char; diff --git a/src/runner/mos6502.rs b/src/runner/mos6502.rs index 95fc4b4e..78f8b145 100644 --- a/src/runner/mos6502.rs +++ b/src/runner/mos6502.rs @@ -2,7 +2,8 @@ use crate::nob::*; use crate::crust::libc::*; use core::ffi::*; -pub const DEFAULT_LOAD_OFFSET: u16 = 0x8000; +// load directly after stack page +pub const DEFAULT_LOAD_OFFSET: u16 = 0x0200; #[derive(Clone, Copy)] pub struct Config { @@ -11,9 +12,10 @@ pub struct Config { pub mod fake6502 { use core::mem::zeroed; - use crate::nob::*; + use super::*; pub static mut MEMORY: [u8; 1<<16] = unsafe { zeroed() }; + pub static mut stdout: *mut FILE = unsafe { zeroed() }; pub unsafe fn load_rom_at(rom: String_Builder, offset: u16) { for i in 0..rom.count { @@ -23,11 +25,37 @@ pub mod fake6502 { #[no_mangle] pub unsafe extern "C" fn read6502(address: u16) -> u8 { + // https://www.sbprojects.net/projects/apple1/wozmon.php + if address == 0xD011 { + // KBDCR: always set, key always available + // TODO: this is not very accurate, real Apple-1 + // progams would use this bit to check if key was + // pressed, we would have to check here if a byte + // is in stdin queue. + MEMORY[address as usize] |= 0b1000_0000; + } else if address == 0xD010 { + // TODO: if we want to be completely accurate, + // we would have to set bit 7 here and filter it + // out in B. + MEMORY[address as usize] = getchar() as i8 as u8; + } + MEMORY[address as usize] } #[no_mangle] - pub unsafe extern "C" fn write6502(address: u16, value: u8) { + pub unsafe extern "C" fn write6502(address: u16, mut value: u8) { + // https://www.sbprojects.net/projects/apple1/wozmon.php + if address == 0xD012 { // DSP + // accept immediatetely => clear bit 7 + value &= 0b0111_1111; + fprintf(stdout, c!("%c"), value as c_int); + } + + if address == 0x0206 { + printf(c!("HERE! [0x0206 := $%x], pc := %p\n"), value as c_int, pc as c_int); + } + MEMORY[address as usize] = value; } @@ -46,10 +74,11 @@ pub mod fake6502 { } -pub unsafe fn run_impl(output: *mut String_Builder, config: Config, stdout: *mut FILE) -> Option<()> { +pub unsafe fn run_impl(output: *mut String_Builder, config: Config, argv_addr: u16, stdout: *mut FILE) -> Option<()> { fake6502::load_rom_at(*output, config.load_offset); fake6502::reset(); fake6502::pc = config.load_offset; + fake6502::stdout = stdout; // set reset to $0000 to exit on reset fake6502::MEMORY[0xFFFC] = 0; @@ -60,17 +89,14 @@ pub unsafe fn run_impl(output: *mut String_Builder, config: Config, stdout: *mut let opcode = fake6502::MEMORY[fake6502::pc as usize]; fake6502::step(); + // printf(c!("pc=%p\n"), fake6502::pc as c_int); + let curr_sp = fake6502::sp & 0xFF; if opcode == 0x48 && curr_sp > prev_sp { // PHA instruction log(Log_Level::ERROR, c!("Stack overflow detected")); log(Log_Level::ERROR, c!("SP changed from $%02X to $%02X after PHA instruction"), prev_sp as c_uint, curr_sp as c_uint); return None; } - - if fake6502::pc == 0xFFEF { // Emulating wozmon ECHO routine - fprintf(stdout, c!("%c"), fake6502::a as c_uint); - fake6502::rts(); - } } // print exit code (in Y:A) let code = ((fake6502::y as c_uint) << 8) | fake6502::a as c_uint; @@ -82,7 +108,7 @@ pub unsafe fn run_impl(output: *mut String_Builder, config: Config, stdout: *mut Some(()) } -pub unsafe fn run(output: *mut String_Builder, config: Config, program_path: *const c_char, stdout_path: Option<*const c_char>) -> Option<()> { +pub unsafe fn run(output: *mut String_Builder, config: Config, program_path: *const c_char, argv_addr: Option, stdout_path: Option<*const c_char>) -> Option<()> { (*output).count = 0; read_entire_file(program_path, output)?; @@ -95,7 +121,7 @@ pub unsafe fn run(output: *mut String_Builder, config: Config, program_path: *co } else { stdout() }; - let result = run_impl(output, config, stdout); + let result = run_impl(output, config, argv_addr, stdout); if stdout_path.is_some() { fclose(stdout); } From 69a7bed95ac1564ffe3c09e648fb4dd741c40c03 Mon Sep 17 00:00:00 2001 From: miezekatze Date: Fri, 11 Jul 2025 22:33:13 +0200 Subject: [PATCH 2/3] fix some examples, implement getchar/read --- libb/6502.b | 240 +++++++++++++++++++++++++++++------------ src/codegen/mos6502.rs | 2 +- src/crust.rs | 1 + src/runner/mos6502.rs | 42 ++++++-- 4 files changed, 205 insertions(+), 80 deletions(-) diff --git a/libb/6502.b b/libb/6502.b index dc19cd61..73bd7a8f 100644 --- a/libb/6502.b +++ b/libb/6502.b @@ -1,89 +1,60 @@ exit(code) { - 0(code); + (*0xFFFC)(code); } - abort() { exit(69); } - -putchar(c) { - 0xFFEF(c); -} - -/* TODO: fd not supported */ -fputc(c, fd) { - putchar(c); -} - -/* TODO: actually allocate something */ -__heap_ptr 0x0200; -malloc(size) { - extrn printf; - auto ptr; - ptr = __heap_ptr; - __heap_ptr += size; - if (__heap_ptr >= 0x1000) { - printf("Allocation reached end: %p\nTODO: allow allocating more, implement free\n", __heap_ptr); +assert(cond, msg) { + if (cond == 0) { + printf("Assertion failed: %s\n", msg); abort(); } - return (ptr); -} -/* TODO: free someting? */ -realloc(ptr, size) { - return (malloc(size)); } -/* TODO: Try to implement this function with assembly - Problem with this implementation is that it is not - mapped to the operator - We cannot call this function `div` as it conflicts - with the `divmod` test -*/ -_div(a, b) { - auto d, sign; - sign = 0; - if (a < 0) { - sign = !sign; - a = -a; - } - if (b < 0) { - sign = !sign; - b = -a; +/* not correct at all */ +usleep(n) { + auto i, j; + if (n < 0) n = 32767; + i = 0; while (i < n) { + __asm__("nop"); + i++; } +} - d = 0; while(a >= b) { - a = a - b; - d++; - } - if (sign) d = -d; - return (d); +/* IO functions */ +putchar(c) { + extrn lchar; + lchar(0xD012, 0, c); } -_udiv(a, b) { - auto d; - d = 0; while(a >= b | a < 0) { - a = a - b; - d++; - } - return (d); + +getchar() { + extrn char; + return (char(0xD010, 0)); } -/* TODO: Try to implement this function with assembly - Problem with this implementation is that it is not - mapped to the operator */ -_rem (a, b) { - auto d; - while(a >= b) { - a = a - b; +read(fd, buf, n) { + extrn lchar; + auto i, c; + + assert(fd == 0, "only fd==0 supported for read"); + i = 0; while (i < n) { + c = getchar(); + lchar(buf, i, c); + if (c == '\n') { + return (n); /* simulate terminal behaviour */ + } + if (c == 0xFF) return (i); + i++; } - return (a); + + return (n); } -_urem(a, b) { - auto d; - while(a >= b | a < 0) { - a = a - b; - } - return (a); + +/* TODO: fd not supported */ +fputc(c, fd) { + putchar(c); } +fflush(); /* nop */ printn(n, b, sign) { auto a, c, d, __div, __rem; @@ -104,6 +75,15 @@ printn(n, b, sign) { putchar(c); } +stdin 0; +stdout 1; +stderr 1; + +fprintf(fd, str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) { + assert((fd == 1) | (fd == 2), "only fd in [1,2] supported for fprintf"); + return (printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)); +} + printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) { extrn char; auto i, j, arg, c; @@ -115,7 +95,7 @@ printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) { c = char(str, i); while (c != 0) { if (c == '\n') { - putchar(0xD); // \r + putchar(0xD); /* \r */ } if(c == '%') { @@ -153,6 +133,86 @@ printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) { } } +/* Math functions */ +atoi(str) { + extrn char; + + auto i, c, n, neg; + neg = 0; + n = 0; + + if (char(str, 0) == '-') { + neg = 1; + str++; + } + + i = 0; while (1) { + c = char(str, i); + if ((c == 0) | (c < '0') | (c > '9')) goto end; + n = n * 10 + (c - '0'); + i++; + } + + end:; + if (neg) n = -n; + + return (n); +} + +/* TODO: Try to implement this function with assembly + Problem with this implementation is that it is not + mapped to the operator + We cannot call this function `div` as it conflicts + with the `divmod` test +*/ +_div(a, b) { + auto d, sign; + sign = 0; + if (a < 0) { + sign = !sign; + a = -a; + } + if (b < 0) { + sign = !sign; + b = -a; + } + + d = 0; while(a >= b) { + a = a - b; + d++; + } + if (sign) d = -d; + return (d); +} +_udiv(a, b) { + auto d; + d = 0; while(a >= b | a < 0) { + a = a - b; + d++; + } + return (d); +} + +/* TODO: Try to implement this function with assembly + Problem with this implementation is that it is not + mapped to the operator */ +_rem (a, b) { + auto d; + while(a >= b) { + a = a - b; + } + return (a); +} +_urem(a, b) { + auto d; + while(a >= b | a < 0) { + a = a - b; + } + return (a); +} + + +/* memory related functions */ strlen(s) { extrn char; auto n; @@ -167,7 +227,6 @@ toupper(c) { } -/* memory related functions */ memset(addr, val, size) { extrn lchar; auto i; @@ -177,3 +236,42 @@ memset(addr, val, size) { i += 1; } } + +memcpy(dest, src, n) { + extrn char, lchar; + auto i, rn; + rn = n; + if (n & 1) n--; + + i = 0; while (i < n) { + dest[i] = src[i]; + i++; + } + + if (rn & 1) lchar(dest, n-1, char(src, n-1)); + return (dest); +} + +/* TODO: actually allocate something */ +__heap_ptr 0x0E000; +malloc(size) { + extrn printf; + auto ptr; + ptr = __heap_ptr; + __heap_ptr += size; + if (__heap_ptr >= 0xFF00) { + printf("Allocation reached end: %p\nTODO: allow allocating more, implement free\n", __heap_ptr); + abort(); + } + return (ptr); +} +free() { + /* TODO: free someting */ +} +realloc(ptr, size) { + auto nptr; + nptr = malloc(size); + memcpy(nptr, ptr, size); + free(ptr); + return (nptr); +} diff --git a/src/codegen/mos6502.rs b/src/codegen/mos6502.rs index 4d81793d..1cce8791 100644 --- a/src/codegen/mos6502.rs +++ b/src/codegen/mos6502.rs @@ -817,7 +817,7 @@ pub unsafe fn generate_function(name: *const c_char, params_count: usize, auto_v instr8(out, LDX, IMM, 0); instr8(out, CMP, IMM, 0); - instr8(out, BNE, REL, 5); + instr8(out, BNE, REL, 6); instr(out, TYA); instr8(out, CMP, IMM, 0); diff --git a/src/crust.rs b/src/crust.rs index 1ea13edb..8d39c6f2 100644 --- a/src/crust.rs +++ b/src/crust.rs @@ -99,6 +99,7 @@ pub mod libc { pub fn strlen(s: *const c_char) -> usize; pub fn strtoull(nptr: *const c_char, endptr: *mut*mut c_char, base: c_int) -> c_ulonglong; pub fn fwrite(ptr: *const c_void, size: usize, nmemb: usize, stream: *mut FILE) -> usize; + pub fn getchar() -> c_int; pub fn abort() -> !; pub fn strdup(s: *const c_char) -> *mut c_char; diff --git a/src/runner/mos6502.rs b/src/runner/mos6502.rs index 95fc4b4e..596c3073 100644 --- a/src/runner/mos6502.rs +++ b/src/runner/mos6502.rs @@ -2,7 +2,8 @@ use crate::nob::*; use crate::crust::libc::*; use core::ffi::*; -pub const DEFAULT_LOAD_OFFSET: u16 = 0x8000; +// load directly after stack page +pub const DEFAULT_LOAD_OFFSET: u16 = 0x0200; #[derive(Clone, Copy)] pub struct Config { @@ -11,9 +12,10 @@ pub struct Config { pub mod fake6502 { use core::mem::zeroed; - use crate::nob::*; + use super::*; pub static mut MEMORY: [u8; 1<<16] = unsafe { zeroed() }; + pub static mut stdout: *mut FILE = unsafe { zeroed() }; pub unsafe fn load_rom_at(rom: String_Builder, offset: u16) { for i in 0..rom.count { @@ -23,11 +25,37 @@ pub mod fake6502 { #[no_mangle] pub unsafe extern "C" fn read6502(address: u16) -> u8 { + // https://www.sbprojects.net/projects/apple1/wozmon.php + if address == 0xD011 { + // KBDCR: always set, key always available + // TODO: this is not very accurate, real Apple-1 + // progams would use this bit to check if key was + // pressed, we would have to check here if a byte + // is in stdin queue. + MEMORY[address as usize] |= 0b1000_0000; + } else if address == 0xD010 { + // TODO: if we want to be completely accurate, + // we would have to set bit 7 here and filter it + // out in B. + MEMORY[address as usize] = getchar() as i8 as u8; + } + MEMORY[address as usize] } #[no_mangle] - pub unsafe extern "C" fn write6502(address: u16, value: u8) { + pub unsafe extern "C" fn write6502(address: u16, mut value: u8) { + // https://www.sbprojects.net/projects/apple1/wozmon.php + if address == 0xD012 { // DSP + // accept immediatetely => clear bit 7 + value &= 0b0111_1111; + fprintf(stdout, c!("%c"), value as c_int); + } + + if address == 0x0206 { + printf(c!("HERE! [0x0206 := $%x], pc := %p\n"), value as c_int, pc as c_int); + } + MEMORY[address as usize] = value; } @@ -50,6 +78,7 @@ pub unsafe fn run_impl(output: *mut String_Builder, config: Config, stdout: *mut fake6502::load_rom_at(*output, config.load_offset); fake6502::reset(); fake6502::pc = config.load_offset; + fake6502::stdout = stdout; // set reset to $0000 to exit on reset fake6502::MEMORY[0xFFFC] = 0; @@ -60,17 +89,14 @@ pub unsafe fn run_impl(output: *mut String_Builder, config: Config, stdout: *mut let opcode = fake6502::MEMORY[fake6502::pc as usize]; fake6502::step(); + // printf(c!("pc=%p\n"), fake6502::pc as c_int); + let curr_sp = fake6502::sp & 0xFF; if opcode == 0x48 && curr_sp > prev_sp { // PHA instruction log(Log_Level::ERROR, c!("Stack overflow detected")); log(Log_Level::ERROR, c!("SP changed from $%02X to $%02X after PHA instruction"), prev_sp as c_uint, curr_sp as c_uint); return None; } - - if fake6502::pc == 0xFFEF { // Emulating wozmon ECHO routine - fprintf(stdout, c!("%c"), fake6502::a as c_uint); - fake6502::rts(); - } } // print exit code (in Y:A) let code = ((fake6502::y as c_uint) << 8) | fake6502::a as c_uint; From 583b59b75ab25120dce0df056cde184e2d2d8f81 Mon Sep 17 00:00:00 2001 From: miezekatze Date: Fri, 11 Jul 2025 22:58:59 +0200 Subject: [PATCH 3/3] implement arguments, fix other examples, change ref.b test --- libb/6502.b | 7 ++++++ src/b.rs | 3 ++- src/codegen/mos6502.rs | 53 +++++++++++++++++++++++++++++++++++++++++- src/runner/mos6502.rs | 6 ++--- tests/ref.b | 12 +++++----- 5 files changed, 70 insertions(+), 11 deletions(-) diff --git a/libb/6502.b b/libb/6502.b index 73bd7a8f..9e9157bb 100644 --- a/libb/6502.b +++ b/libb/6502.b @@ -134,6 +134,13 @@ printf(str, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) { } /* Math functions */ +_rand_seed 123456789; +rand() { + _rand_seed = 20077 * _rand_seed + 12345; + return (_rand_seed); +} + + atoi(str) { extrn char; diff --git a/src/b.rs b/src/b.rs index 5a9723f0..45af1834 100644 --- a/src/b.rs +++ b/src/b.rs @@ -1716,7 +1716,6 @@ pub unsafe fn main(mut argc: i32, mut argv: *mut*mut c_char) -> Option<()> { } Target::Mos6502 => { let config = codegen::mos6502::parse_config_from_link_flags(da_slice(*linker))?; - codegen::mos6502::generate_program(&mut output, &c, config); let effective_output_path; if (*output_path).is_null() { @@ -1727,6 +1726,8 @@ pub unsafe fn main(mut argc: i32, mut argv: *mut*mut c_char) -> Option<()> { effective_output_path = *output_path; } + codegen::mos6502::generate_program(&mut output, &c, effective_output_path, da_slice(run_args), config); + write_entire_file(effective_output_path, output.items as *const c_void, output.count)?; log(Log_Level::INFO, c!("generated %s"), effective_output_path); if *run { diff --git a/src/codegen/mos6502.rs b/src/codegen/mos6502.rs index 1cce8791..1670a991 100644 --- a/src/codegen/mos6502.rs +++ b/src/codegen/mos6502.rs @@ -1471,6 +1471,18 @@ pub unsafe fn generate_data_section(out: *mut String_Builder, data: *const [u8]) } pub unsafe fn generate_entry(out: *mut String_Builder, asm: *mut Assembler) { + instr0(out, LDA, ABS); + add_reloc(out, RelocationKind::External{name: c!("$argv_descriptor"), offset: 3, byte: Byte::Both}, asm); + instr(out, PHA); + instr0(out, LDA, ABS); + add_reloc(out, RelocationKind::External{name: c!("$argv_descriptor"), offset: 2, byte: Byte::Both}, asm); + instr(out, PHA); + + instr0(out, LDY, ABS); + add_reloc(out, RelocationKind::External{name: c!("$argv_descriptor"), offset: 1, byte: Byte::Both}, asm); + instr0(out, LDA, ABS); + add_reloc(out, RelocationKind::External{name: c!("$argv_descriptor"), offset: 0, byte: Byte::Both}, asm); + instr0(out, JSR, ABS); add_reloc(out, RelocationKind::External{name: c!("main"), offset: 0, byte: Byte::Both}, asm); @@ -1518,7 +1530,35 @@ pub unsafe fn generate_asm_funcs(out: *mut String_Builder, asm_funcs: *const [As } } -pub unsafe fn generate_program(out: *mut String_Builder, c: *const Compiler, config: Config) -> Option<()> { +pub unsafe fn generate_argv(out: *mut String_Builder, arg0: *const c_char, run_args: *const [*const c_char], asm: *mut Assembler) { + let mut arr: Array = zeroed(); + da_append(&mut arr, (*asm).code_start + (*out).count as u16); + sb_appendf(out, c!("%s"), arg0); + write_byte(out, 0); + + for i in 0..run_args.len() { + da_append(&mut arr, (*asm).code_start + (*out).count as u16); + sb_appendf(out, c!("%s"), (*run_args)[i]); + write_byte(out, 0); + } + + da_append(&mut arr, 0); + let ptr = (*asm).code_start + (*out).count as u16; + for i in 0..arr.count { + write_word(out, *arr.items.add(i)); + } + + let fun_addr = (*out).count as u16; + da_append(&mut (*asm).externals, External { + name: c!("$argv_descriptor"), + addr: fun_addr, + }); + + write_word(out, 1 + run_args.len() as u16); + write_word(out, ptr); +} + +pub unsafe fn generate_program(out: *mut String_Builder, c: *const Compiler, arg0: *const c_char, run_args: *const [*const c_char], config: Config) -> Option<()> { let mut asm: Assembler = zeroed(); generate_entry(out, &mut asm); asm.code_start = config.load_offset; @@ -1529,10 +1569,21 @@ pub unsafe fn generate_program(out: *mut String_Builder, c: *const Compiler, con let data_start = config.load_offset + (*out).count as u16; generate_data_section(out, da_slice((*c).data)); + generate_argv(out, arg0, run_args, &mut asm); + generate_globals(out, da_slice((*c).globals), &mut asm); log(Log_Level::INFO, c!("Generated size: 0x%x"), (*out).count as c_uint); apply_relocations(out, data_start, &mut asm); + // TODO: move this behind a flag, useful for debugging + let print_addresses = false; + if print_addresses { + for i in 0..asm.externals.count { + let ex = *asm.externals.items.add(i); + printf(c!("%s => $%04X\n"), ex.name, ex.addr as c_uint); + } + } + Some(()) } diff --git a/src/runner/mos6502.rs b/src/runner/mos6502.rs index 78f8b145..596c3073 100644 --- a/src/runner/mos6502.rs +++ b/src/runner/mos6502.rs @@ -74,7 +74,7 @@ pub mod fake6502 { } -pub unsafe fn run_impl(output: *mut String_Builder, config: Config, argv_addr: u16, stdout: *mut FILE) -> Option<()> { +pub unsafe fn run_impl(output: *mut String_Builder, config: Config, stdout: *mut FILE) -> Option<()> { fake6502::load_rom_at(*output, config.load_offset); fake6502::reset(); fake6502::pc = config.load_offset; @@ -108,7 +108,7 @@ pub unsafe fn run_impl(output: *mut String_Builder, config: Config, argv_addr: u Some(()) } -pub unsafe fn run(output: *mut String_Builder, config: Config, program_path: *const c_char, argv_addr: Option, stdout_path: Option<*const c_char>) -> Option<()> { +pub unsafe fn run(output: *mut String_Builder, config: Config, program_path: *const c_char, stdout_path: Option<*const c_char>) -> Option<()> { (*output).count = 0; read_entire_file(program_path, output)?; @@ -121,7 +121,7 @@ pub unsafe fn run(output: *mut String_Builder, config: Config, program_path: *co } else { stdout() }; - let result = run_impl(output, config, argv_addr, stdout); + let result = run_impl(output, config, stdout); if stdout_path.is_some() { fclose(stdout); } diff --git a/tests/ref.b b/tests/ref.b index cc4a45bc..fd1d708a 100644 --- a/tests/ref.b +++ b/tests/ref.b @@ -1,13 +1,13 @@ -write(ref, val) *ref = val; -read(ref) return (*ref); +rwrite(ref, val) *ref = val; +rread(ref) return (*ref); y; test1() { extrn printf; auto x; - write(&x, 69); - write(&y, 420); + rwrite(&x, 69); + rwrite(&y, 420); // printf("&x: %p\n", &x); // printf("&y: %p\n", &y); @@ -40,8 +40,8 @@ test3() { // check generated IR to confirm that printf( "xs: [%d, %d]\n", - read(xs + 0*8), - read(&xs[1*8]) + rread(xs + 0*8), + rread(&xs[1*8]) ); }