From 889efa7fdf48a0b4fce32021d7d3e0fe91ea20df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 25 Dec 2025 13:40:58 +0100 Subject: [PATCH 01/36] Archival commit, works well enough to almost print the title screen of ZORK I --- config.py | 4 + src/arch/nano6502/build.py | 4 +- third_party/z65/build.py | 9 + third_party/z65/z65.c | 1201 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1217 insertions(+), 1 deletion(-) create mode 100644 third_party/z65/build.py create mode 100644 third_party/z65/z65.c diff --git a/config.py b/config.py index cc288d11..7c9f3fa5 100644 --- a/config.py +++ b/config.py @@ -71,6 +71,10 @@ "0:triangle.frt": "cpmfs+triangle_frt_cpm", } +ZM_APPS = { + "0:z65.com": "third_party/z65", +} + SERIAL_APPS = { "0:xrecv.com": "apps+xrecv", "0:xsend.com": "apps+xsend", diff --git a/src/arch/nano6502/build.py b/src/arch/nano6502/build.py index 9268b00a..9f3da7b4 100644 --- a/src/arch/nano6502/build.py +++ b/src/arch/nano6502/build.py @@ -12,6 +12,7 @@ SERIAL_APPS, SERIAL_SCREEN_APPS, FORTH_APPS, + ZM_APPS, ) llvmrawprogram( @@ -40,7 +41,8 @@ | PASCAL_APPS | SERIAL_APPS | SERIAL_SCREEN_APPS - | FORTH_APPS, + | FORTH_APPS + | ZM_APPS, ) mkcpmfs( diff --git a/third_party/z65/build.py b/third_party/z65/build.py new file mode 100644 index 00000000..8d395fe3 --- /dev/null +++ b/third_party/z65/build.py @@ -0,0 +1,9 @@ +from build.ab import Rule, Target, Targets, simplerule +from build.llvm import llvmprogram +from tools.build import unixtocpm + +llvmprogram( + name="z65", + srcs=["./z65.c"], + deps=["lib+cpm65"], +) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c new file mode 100644 index 00000000..4b6a1222 --- /dev/null +++ b/third_party/z65/z65.c @@ -0,0 +1,1201 @@ +/* Z-machine v1–v3 interpreter for CP/M-65 + * Step 2: complete 1OP instruction set + */ + +#include +//#include +#include +#include "lib/printi.h" +/* ============================================================ + * Opcode definitions + * ============================================================ + */ + +/* 2OP */ +#define OP2_JE 0x01 +#define OP2_JL 0x02 +#define OP2_JG 0x03 +#define OP2_DEC_CHK 0x04 +#define OP2_INC_CHK 0x05 +#define OP2_TEST 0x07 +#define OP2_OR 0x08 +#define OP2_AND 0x09 +#define OP2_STORE 0x0D +#define OP2_LOADW 0x0F +#define OP2_LOADB 0x10 +#define OP2_ADD 0x14 +#define OP2_SUB 0x15 +#define OP2_MUL 0x16 +#define OP2_DIV 0x17 +#define OP2_MOD 0x18 +#define OP2_TEST_ATTR 0x0A +#define OP2_SET_ATTR 0x0B +#define OP2_CLEAR_ATTR 0x0C +#define OP2_INSERT_OBJ 0x0E +#define OP2_GET_PROP 0x11 +#define OP2_GET_PROP_ADDR 0x12 +#define OP2_GET_NEXT_PROP 0x13 + +/* 1OP */ +/*#define OP1_RTRUE 0x00 +#define OP1_RFALSE 0x01 +#define OP1_PRINT 0x02 +#define OP1_JUMP 0x03 +#define OP1_PRINT_ADDR 0x04 +#define OP1_VALUE 0x05 +#define OP1_INC 0x06 +#define OP1_DEC 0x07 +#define OP1_PRINT_PADDR 0x08 +#define OP1_REMOVE_OBJ 0x09 +#define OP1_PRINT_OBJ 0x0A +#define OP1_RET 0x0B +#define OP1_JZ 0x0C +#define OP1_JZ 0x00 +#define OP1_INC 0x05 +#define OP1_DEC 0x06 +#define OP1_PRINT_ADDR 0x07 +#define OP1_PRINT_PADDR 0x0D +#define OP1_REMOVE_OBJ 0x09 +#define OP1_PRINT_OBJ 0x0A +#define OP1_JUMP 0x0C +#define OP1_RET 0x0B*/ + +/* 1OP opcodes (v1–v3) */ +#define OP1_JZ 0x00 +#define OP1_GET_SIBLING 0x01 +#define OP1_GET_CHILD 0x02 +#define OP1_GET_PARENT 0x03 +#define OP1_GET_PROP_LEN 0x04 +#define OP1_INC 0x05 +#define OP1_DEC 0x06 +#define OP1_PRINT_ADDR 0x07 +#define OP1_CALL_1S 0x08 +#define OP1_REMOVE_OBJ 0x09 +#define OP1_PRINT_OBJ 0x0A +#define OP1_RET 0x0B +#define OP1_JUMP 0x0C +#define OP1_PRINT_PADDR 0x0D +#define OP1_LOAD 0x0E +#define OP1_CALL_1N 0x0F + +/* 0OP */ +#define OP0_RTRUE 0x00 +#define OP0_RFALSE 0x01 +#define OP0_PRINT 0x02 +#define OP0_PRINT_RET 0x03 +#define OP0_NOP 0x04 +#define OP0_SAVE 0x05 +#define OP0_RESTORE 0x06 +#define OP0_RESTART 0x07 +#define OP0_RET_POPPED 0x08 +#define OP0_POP 0x09 +#define OP0_QUIT 0x0A +#define OP0_NEW_LINE 0x0B + +/* VAR */ +#define OPV_CALL 0x00 +#define OPV_STOREW 0x01 +#define OPV_STOREB 0x02 +#define OPV_PUT_PROP 0x03 +#define OPV_SREAD 0x04 +#define OPV_PRINT_CHAR 0x05 +#define OPV_PRINT_NUM 0x06 +#define OPV_PUSH 0x08 +#define OPV_PULL 0x09 + +/* ============================================================ + * BDOS + * ============================================================ + */ + +//extern uint8_t bdos(uint8_t fn, void *arg); + +//#define BDOS_OPEN_R 15 +//bin#define BDOS_READ_SEQ 20 +//#define BDOS_READ_RAND 33 +//#define BDOS_CONOUT 2 + +/*typedef struct { + uint8_t drive; + char name[8]; + char ext[3]; + uint8_t ex,s1,s2,rc; + uint8_t d[16]; + uint8_t cr; + uint8_t r0,r1,r2; +} FCB; +*/ + +/* ============================================================ + * Configuration + * ============================================================ + */ + +#define PAGE_SIZE 512 +#define NUM_PAGES 8 +#define DYNAMIC_MEM_MAX 16384 + +#define STACK_SIZE 256 +#define MAX_FRAMES 16 +#define MAX_LOCALS 8 +#define MAX_OPERANDS 8 + +#define INPUT_MAX 80 +#define MAX_TOKENS 16 + +/* ============================================================ + * Structures + * ============================================================ + */ + +typedef struct { + uint16_t return_pc; + uint8_t store_var; + uint8_t num_locals; + uint16_t locals[MAX_LOCALS]; +} CallFrame; + +typedef struct { + uint16_t page; + uint8_t data[PAGE_SIZE]; + uint8_t valid; +} Page; + +/* ============================================================ + * Globals + * ============================================================ + */ + +//static FCB story_fcb; + +static uint8_t dynamic_mem[DYNAMIC_MEM_MAX]; +static uint16_t dynamic_size; + +static Page page_cache[NUM_PAGES]; +static uint8_t next_victim; + +static uint16_t pc; +static uint16_t initial_pc; +static int16_t stack[STACK_SIZE]; +static uint16_t sp; + +static CallFrame frames[MAX_FRAMES]; +static uint8_t fp; + +static uint8_t dma[128]; +static uint8_t hdr[128]; + +static uint16_t dict_addr; +static uint8_t dict_sep_count; +static uint8_t dict_seps[32]; +static uint8_t dict_entry_len; +static uint16_t dict_entry_count; + +static uint16_t object_table; + +static uint8_t alphabet; +static uint8_t alphabet_reset; +static uint8_t alphabet_prev; + +static uint8_t abbrev_print; +static uint8_t abbrev_table; +static uint16_t abbrev_base; +/* ============================================================ + * Console + * ============================================================ + */ + +static inline void putc(char c){ + //bdos(BDOS_CONOUT,(void *)(uintptr_t)c); + cpm_conout(c); +} + +static void crlf(void) +{ + cpm_printstring("\r\n"); +} + +static void spc(void) +{ + cpm_conout(' '); +} + + +static void print_hex(uint16_t val) +{ + cpm_printstring("0x"); + for(uint8_t i = 4; i>0; i--) { + uint8_t nibble = (val >> ((i-1) << 2)) & 0xf; + + if(nibble < 10) cpm_conout(nibble + '0'); + else cpm_conout(nibble-10 + 'A'); + } +} + +static void printx(const char *s) +{ + cpm_printstring(s); + crlf(); +} + +static void fatal(const char *s) +{ + printx(s); + cpm_warmboot(); +} + + +static uint8_t read_line(char *buf){ + uint8_t len=0; + for(;;){ + char c=cpm_conin(); + if(c=='\r'||c=='\n'){ + crlf(); + buf[len]=0; + return len; + } + if(c==8 && len){ + len--; + putc(8); putc(' '); putc(8); + continue; + } + if(len>8; + //story_fcb.r2=0; + //cmp_set_dma(dma); + //crlf(); + for(uint8_t i=0;i<4;i++){ + //bdos(BDOS_READ_RAND,&story_fcb); + cpm_set_dma(&dma); + cpm_read_random(&cpm_fcb); + for(uint8_t j=0;j<128;j++) { + p->data[(i<<7)+j]=dma[j]; + } + //crlf(); + //crlf(); + record++; + cpm_fcb.r = record; + } + p->page=page; + p->valid=1; +} + +static Page *get_page(uint16_t page){ + //cpm_printstring("Page "); + //printi(page); + //cpm_printstring(" requested"); + //crlf(); + for(uint8_t i=0;i>9); + //printi(p->data[a&0x1FF]); + //crlf(); + //cpm_printstring("Read "); + //print_hex(p->data[a&0x1FF]); + //cpm_printstring(" from address "); + //print_hex(a); + //crlf(); + return p->data[a&0x1FF]; +} + +static uint16_t zm_read16(uint16_t a){ + return ((uint16_t)zm_read8(a)<<8)|zm_read8(a+1); +} + +static inline void zm_write8(uint16_t a,uint8_t v){ + if(a>=dynamic_size) { + crlf(); + print_hex(a); + fatal(" Illegal write address"); + + } + dynamic_mem[a]=v; +} + +/* ============================================================ + * Stack & variables + * ============================================================ + */ + +static inline void push(int16_t v){stack[sp++]=v;} +static inline int16_t pop(void){return stack[--sp];} + +static uint16_t get_var(uint8_t v){ + //cpm_printstring("get_var - v:"); + //print_hex(v); + // crlf(); + if(v==0) { + uint16_t stack; + stack = pop(); + // cpm_printstring("stack: "); + // print_hex(stack); + // crlf(); + return stack; + } + if(v<16) { + // cpm_printstring("local: "); + // print_hex(frames[fp-1].locals[v-1]); + // crlf(); + return frames[fp-1].locals[v-1]; + } + //uint16_t a=zm_read16(0x0C)+2*(v-16); + uint16_t a = (hdr[0x0c]<<8) + hdr[0x0d] + 2*(v-16); + //cpm_printstring("get_var - a:"); + //print_hex(a); + //crlf(); + uint16_t ret_data = zm_read16(a); + //cpm_printstring("global: "); + //print_hex(ret_data); + //crlf(); + return ret_data; +} + +static void set_var(uint8_t v,uint16_t val){ + if(v==0) push(val); + else if(v<16) frames[fp-1].locals[v-1]=val; + else{ + //uint16_t a=zm_read16(0x0C)+2*(v-16); + uint16_t a = (hdr[0x0c]<<8) + hdr[0x0d] + 2*(v-16); + //cpm_printstring("Setvar "); + //printi(a); + //spc(); + //printi(val); + //spc(); + //printi(v); + zm_write8(a,val>>8); + zm_write8(a+1,val&0xFF); + } +} + +/* ============================================================ + * Operand decoding + * ============================================================ + */ + +enum{OP_LARGE,OP_SMALL,OP_VAR,OP_OMIT}; + +static uint16_t operands[MAX_OPERANDS]; +static uint8_t operand_count; + +static uint16_t read_operand(uint8_t t){ + if(t==OP_LARGE){pc+=2;return zm_read16(pc-2);} + if(t==OP_SMALL)return zm_read8(pc++); + if(t==OP_VAR)return get_var(zm_read8(pc++)); + return 0; +} + + +static void decode_operands(uint8_t spec){ + operand_count=0; + for(int s=6;s>=0;s-=2){ + uint8_t t=(spec>>s)&3; + if(t==OP_OMIT) break; + operands[operand_count++]=read_operand(t); + } +} + + +/* ============================================================ + * Branching + * ============================================================ + */ + +static void branch(uint8_t cond){ + uint8_t b=zm_read8(pc++); + uint8_t sense=b&0x80; + int16_t off; + + if(b&0x40) off=b&0x3F; + else{ + off=((b&0x3F)<<8)|zm_read8(pc++); + if(off&0x2000) off|=0xC000; + } + + if((cond!=0)==(sense!=0)){ + if(off==0) push(0),pc=frames[--fp].return_pc; + else if(off==1) push(1),pc=frames[--fp].return_pc; + else pc+=off-2; + } +} + +/* ============================================================ + * ZSCII output (minimal) + * ============================================================ + */ + +static void print_zstring(uint16_t addr){ + uint8_t base; + while(1){ + uint16_t w=zm_read16(addr); + addr+=2; + //cpm_printstring("zstring decode - word: "); + //print_hex(w); + //spc(); + + for(int i=10;i>=0;i-=5){ + uint8_t c=(w>>i)&0x1F; + //print_hex(c); + //spc(); + //printi(alphabet); + //spc(); + if(alphabet == 0) base = 'a'-6; + else if(alphabet == 1) base = 'A'-6; + else if(alphabet == 2) base = '0'-8; + else base = 'a' - 6; + + if(alphabet_reset) { + alphabet = alphabet_prev; + alphabet_reset = 0; + } + + + if(abbrev_print == 1) { + uint16_t string_addr; + string_addr = zm_read16(abbrev_base+(((abbrev_table<<5)+c)<<1)); + abbrev_print = 0; + print_zstring(string_addr<<1); + } + else if(c>=6) { + //crlf(); + putc(base+c); + //crlf(); + } + else if(c==4) { + alphabet_prev = alphabet; + alphabet = (alphabet + 1) % 3; + alphabet_reset = 1; + } + else if(c==5) { + alphabet_prev = alphabet; + if(alphabet == 0) alphabet = 2; + else alphabet--; + alphabet_reset = 1; + } + else if((c>0) && (c<4)) { + abbrev_print = 1; + abbrev_table = c-1; + } + else if(c==0) putc(' '); + + } + //crlf(); + if(w&0x8000) break; + } +} + +static void print_num(int16_t v){ + char buf[6]; + uint8_t i=0; + + if(v<0){ putc('-'); v=-v; } + do{ + buf[i++]='0'+(v%10); + v/=10; + }while(v); + while(i--) putc(buf[i]); +} + +// Dictionary +static void dict_init(void){ + dict_addr = zm_read16(0x08); + + dict_sep_count = zm_read8(dict_addr++); + for(uint8_t i=0;i>8); + zm_write8(entry+1, dict); + zm_write8(entry+2, len); + zm_write8(entry+3, start+1); + + count++; + } + + zm_write8(parse_buf+1,count); + return count; +} + + +// Objects + +static inline uint16_t obj_addr(uint8_t obj) +{ + return object_table + 62 + (obj - 1) * 9; +} + +static uint8_t obj_test_attr(uint8_t obj, uint8_t attr){ + uint16_t a = obj_addr(obj) + (attr >> 3); + return zm_read8(a) & (0x80 >> (attr & 7)); +} + +static void obj_set_attr(uint8_t obj, uint8_t attr){ + uint16_t a = obj_addr(obj) + (attr >> 3); + zm_write8(a, zm_read8(a) | (0x80 >> (attr & 7))); +} + +static void obj_clear_attr(uint8_t obj, uint8_t attr){ + uint16_t a = obj_addr(obj) + (attr >> 3); + zm_write8(a, zm_read8(a) & ~(0x80 >> (attr & 7))); +} + +static uint8_t obj_parent(uint8_t obj){ + return zm_read8(obj_addr(obj) + 4); +} + +static uint8_t obj_sibling(uint8_t obj){ + return zm_read8(obj_addr(obj) + 5); +} + +static uint8_t obj_child(uint8_t obj){ + return zm_read8(obj_addr(obj) + 6); +} + +static void obj_remove(uint8_t obj){ + uint8_t parent = obj_parent(obj); + if (!parent) return; + + uint16_t paddr = obj_addr(parent) + 6; + uint8_t cur = zm_read8(paddr); + + if (cur == obj) { + zm_write8(paddr, obj_sibling(obj)); + } else { + while (cur) { + uint16_t caddr = obj_addr(cur) + 5; + uint8_t sib = zm_read8(caddr); + if (sib == obj) { + zm_write8(caddr, obj_sibling(obj)); + break; + } + cur = sib; + } + } + + zm_write8(obj_addr(obj) + 4, 0); + zm_write8(obj_addr(obj) + 5, 0); +} + +static void obj_insert(uint8_t obj, uint8_t dest){ + obj_remove(obj); + + uint16_t daddr = obj_addr(dest) + 6; + zm_write8(obj_addr(obj) + 4, dest); + zm_write8(obj_addr(obj) + 5, zm_read8(daddr)); + zm_write8(daddr, obj); +} + + +static uint16_t obj_prop_table(uint8_t obj){ + return zm_read16(obj_addr(obj) + 7); +} + +static uint16_t obj_prop_start(uint8_t obj){ + uint16_t p = obj_prop_table(obj); + return p + 1 + 2 * zm_read8(p); +} + +static uint16_t obj_find_prop(uint8_t obj, uint8_t prop){ + uint16_t p = obj_prop_start(obj); + + while (1) { + uint8_t h = zm_read8(p++); + if (!h) return 0; + + uint8_t num = h & 0x1F; + uint8_t len = (h >> 5) + 1; + + if (num == prop) return p; + p += len; + } +} + +static uint16_t obj_get_prop(uint8_t obj, uint8_t prop){ + uint16_t p = obj_find_prop(obj, prop); + if (!p) { + return zm_read16(object_table + (prop - 1) * 2); + } + + uint8_t len = ((zm_read8(p - 1) >> 5) & 7) + 1; + if (len == 1) return zm_read8(p); + return zm_read16(p); +} + +static uint8_t obj_get_prop_len(uint16_t addr){ + if (!addr) return 0; + return ((zm_read8(addr - 1) >> 5) & 7) + 1; +} + +static void obj_put_prop(uint8_t obj, uint8_t prop, uint16_t val){ + cpm_printstring("obj_put_prop - obj: "); + print_hex(obj); + cpm_printstring(" prop: "); + print_hex(prop); + cpm_printstring(" val: "); + print_hex(val); + + uint16_t p = obj_find_prop(obj, prop); + + cpm_printstring(" p: "); + print_hex(p); + crlf(); + + if (!p) { + // property must exist + return; + } + + uint8_t len = ((zm_read8(p - 1) >> 5) & 7) + 1; + + if (len == 1) { + zm_write8(p, (uint8_t)val); + } else { + zm_write8(p, val >> 8); + zm_write8(p + 1, val & 0xFF); + } +} + + +/* ============================================================ + * Execution + * ============================================================ + */ + +static void z_ret(uint16_t v){ + CallFrame *f=&frames[--fp]; + pc=f->return_pc; + set_var(f->store_var,v); +} + +static void store_result(uint16_t v){ + uint8_t var=zm_read8(pc++); + //cpm_printstring("Store "); + //printi(v); + //cpm_printstring(" in variable "); + //printi(var); + //crlf(); + set_var(var,v); +} + +static void restart(void) +{ + pc = initial_pc; + sp = fp = 0; +} + +static inline uint16_t unpack_routine(uint16_t p) +{ + // v1-v3 - only version supported for now + return p << 1; +} + +static void step(void){ + uint8_t op=zm_read8(pc++); + cpm_printstring("OP: "); + print_hex(op); + cpm_printstring(" PC: "); + print_hex(pc); + crlf(); + /* -------- 2OP -------- */ + if(op<0x80){ + uint8_t t1=(op&0x40)?OP_VAR:OP_SMALL; + uint8_t t2=(op&0x20)?OP_VAR:OP_SMALL; + operands[0]=read_operand(t1); + operands[1]=read_operand(t2); + + //cpm_printstring("2OP - "); + //print_hex(operands[0]); + //spc(); + //print_hex(operands[1]); + //crlf(); + + switch(op&0x1F){ + case OP2_JE: + cpm_printstring("JE "); + printi(operands[0]); + spc(); + printi(operands[1]); + crlf(); + branch(operands[0]==operands[1]); + break; + case OP2_JL: + branch((int16_t)operands[0]<(int16_t)operands[1]); + break; + case OP2_JG: + branch((int16_t)operands[0]>(int16_t)operands[1]); + break; + case OP2_DEC_CHK: + operands[0]--; + set_var(operands[0],operands[0]); + branch((int16_t)operands[0]<(int16_t)operands[1]); + break; + case OP2_INC_CHK: + operands[0]++; + set_var(operands[0],operands[0]); + branch((int16_t)operands[0]>(int16_t)operands[1]); + break; + case OP2_TEST: + branch((operands[0]&operands[1])==operands[1]); + break; + case OP2_OR: + store_result(operands[0]|operands[1]); + break; + case OP2_AND: + store_result(operands[0]&operands[1]); + break; + case OP2_STORE: + set_var(operands[0],operands[1]); + break; + case OP2_LOADW: + store_result(zm_read16(operands[0]+2*operands[1])); + break; + case OP2_LOADB: + store_result(zm_read8(operands[0]+operands[1])); + break; + case OP2_ADD: + store_result((int16_t)operands[0]+(int16_t)operands[1]); + break; + case OP2_SUB: + store_result((int16_t)operands[0]-(int16_t)operands[1]); + break; + case OP2_MUL: + store_result((int16_t)operands[0]*(int16_t)operands[1]); + break; + case OP2_DIV: + store_result((int16_t)operands[0]/(int16_t)operands[1]); + break; + case OP2_MOD: + store_result((int16_t)operands[0]%(int16_t)operands[1]); + break; + case OP2_TEST_ATTR: + branch(obj_test_attr(operands[0], operands[1])); + break; + + case OP2_SET_ATTR: + obj_set_attr(operands[0], operands[1]); + break; + + case OP2_CLEAR_ATTR: + obj_clear_attr(operands[0], operands[1]); + break; + + case OP2_INSERT_OBJ: + obj_insert(operands[0], operands[1]); + break; + + case OP2_GET_PROP: + store_result(obj_get_prop(operands[0], operands[1])); + break; + + case OP2_GET_PROP_ADDR: { + uint16_t p = obj_find_prop(operands[0], operands[1]); + store_result(p); + break; + } + + case OP2_GET_NEXT_PROP: { + uint16_t p = obj_find_prop(operands[0], operands[1]); + if (!p) { + store_result(0); + } else { + uint8_t h = zm_read8(p - 1); + store_result(h & 0x1F); + } + break; + } + + default: + printi(op); + fatal(" - Non-implemented opcode!!!"); + } + return; + } + + /* -------- 1OP -------- */ + if(op<0xB0){ + uint8_t type=(op>>4)&3; + uint8_t oc=op&0x0F; + if(type!=OP_OMIT) operands[0]=read_operand(type); + cpm_printstring("Type: "); + printi(type); + cpm_printstring(" Operand 1: "); + printi(operands[0]); + crlf(); + switch(oc){ + /*case OP1_RTRUE: + z_ret(1); + break; + case OP1_RFALSE: + z_ret(0); + break;*/ + /*case OP1_PRINT: + print_zstring(pc); + while(!(zm_read16(pc)&0x8000)) pc+=2; + pc+=2; + break;*/ + case OP1_JUMP: + cpm_printstring("Performing jump with offset"); + printi(operands[0]-2); + crlf(); + pc+=(int16_t)operands[0]-2; + break; + case OP1_PRINT_ADDR: + print_zstring(operands[0]); + break; + case OP1_RET: + //case OP1_VALUE: + z_ret(operands[0]); + break; + case OP1_INC: + operands[0]++; + set_var(zm_read8(pc-1),operands[0]); + break; + case OP1_DEC: + operands[0]--; + set_var(zm_read8(pc-1),operands[0]); + break; + //case OP1_RET: + // z_ret(operands[0]); + // break; + case OP1_JZ: + branch(operands[0]==0); + break; + default: + printi(op); + fatal(" - Non-implemented opcode!!!"); + } + return; + } + /* 0OP */ + if(op<0xC0) { + switch(op&0x0F){ + case OP0_RTRUE: + z_ret(1); + break; + case OP0_RFALSE: + z_ret(0); + break; + case OP0_PRINT: + print_zstring(pc); + while(!(zm_read16(pc)&0x8000)) pc+=2; + pc+=2; + break; + case OP0_PRINT_RET: + print_zstring(pc); + while(!(zm_read16(pc)&0x8000)) pc+=2; + pc+=2; + putc('\n'); + z_ret(1); + break; + + case OP0_NOP: + break; + + case OP0_SAVE: + case OP0_RESTORE: + branch(0); /* always fail */ + break; + + case OP0_RESTART: + restart(); + break; + + case OP0_RET_POPPED: + z_ret(pop()); + break; + + case OP0_POP: + pop(); + break; + + case OP0_NEW_LINE: + crlf(); + break; + + case OP0_QUIT: + cpm_warmboot(); + default: + printi(op); + fatal(" - Non-implemented opcode!!!"); + } + return; + } + /* -------- VAR -------- */ + decode_operands(zm_read8(pc++)); + switch(op&0x1F){ + /*case OPV_CALL: + cpm_printstring("Call - "); + if(operands[0]==0) { + uint8_t sv=zm_read8(pc++); + set_var(sv,0); + return; + } else { + CallFrame *f=&frames[fp++]; + f->return_pc=pc+1; + f->store_var=zm_read8(pc++); + uint16_t addr=unpack_routine(operands[0]); + cpm_printstring("Addr: "); + printi(addr); + f->num_locals=zm_read8(addr++); + cpm_printstring("Num lcls: "); + printi(f->num_locals); + for(uint8_t i=0;inum_locals;i++) + f->locals[i]=zm_read16(addr+2*i); + pc=addr+2*f->num_locals; + cpm_printstring(" New PC: "); + printi(pc); + crlf(); + } + break;*/ + case OPV_CALL: { + if (operands[0] == 0) { + uint8_t sv = zm_read8(pc++); + set_var(sv, 0); + return; + } + + CallFrame *f = &frames[fp++]; + + uint8_t sv = zm_read8(pc++); + f->store_var = sv; + f->return_pc = pc; + + uint16_t addr = unpack_routine(operands[0]); + cpm_printstring("CALL to address "); + print_hex(addr); + crlf(); + f->num_locals = zm_read8(addr++); + + for (uint8_t i = 0; i < f->num_locals; i++) + f->locals[i] = zm_read16(addr + 2*i); + + /* overwrite locals with arguments */ + uint8_t argc = operand_count - 1; + if (argc > f->num_locals) + argc = f->num_locals; + + for (uint8_t i = 0; i < argc; i++) + f->locals[i] = operands[i + 1]; + + pc = addr + 2 * f->num_locals; + break; + } + + case OPV_STOREW: + cpm_printstring("STOREW: "); + printi(operands[0]); + spc(); + printi(operands[1]); + spc(); + printi(operands[2]); + crlf(); + zm_write8(operands[0]+2*operands[1],operands[2]>>8); + zm_write8(operands[0]+2*operands[1]+1,operands[2]); + break; + + case OPV_STOREB: + zm_write8(operands[0]+operands[1],operands[2]); + break; + + case OPV_PRINT_CHAR: + putc((char)operands[0]); + break; + + case OPV_PRINT_NUM: + print_num((int16_t)operands[0]); + break; + + case OPV_PUSH: + push(operands[0]); + break; + + case OPV_PULL: + set_var(operands[0],pop()); + break; + case OPV_SREAD: { + uint16_t text = operands[0]; + uint16_t parse = operands[1]; + + char line[INPUT_MAX]; + uint8_t len = read_line(line); + + uint8_t max = zm_read8(text); + if(len>max) len=max; + + zm_write8(text+1,len); + for(uint8_t i=0;iDYNAMIC_MEM_MAX) while(1); + + for(uint16_t i=0; i<128; i++) + dynamic_mem[i] = hdr[i]; + + for(uint16_t i=128;i Date: Thu, 25 Dec 2025 15:10:39 +0100 Subject: [PATCH 02/36] It now makes it to West of house... --- third_party/z65/z65.c | 85 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 17 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 4b6a1222..fcac7a4a 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -17,6 +17,7 @@ #define OP2_JG 0x03 #define OP2_DEC_CHK 0x04 #define OP2_INC_CHK 0x05 +#define OP2_JIN 0x06 #define OP2_TEST 0x07 #define OP2_OR 0x08 #define OP2_AND 0x09 @@ -94,14 +95,20 @@ /* VAR */ #define OPV_CALL 0x00 -#define OPV_STOREW 0x01 -#define OPV_STOREB 0x02 -#define OPV_PUT_PROP 0x03 -#define OPV_SREAD 0x04 -#define OPV_PRINT_CHAR 0x05 -#define OPV_PRINT_NUM 0x06 -#define OPV_PUSH 0x08 -#define OPV_PULL 0x09 +#define OPV_STOREW 0x21 +#define OPV_STOREB 0x22 +#define OPV_PUT_PROP 0x23 +#define OPV_SREAD 0x24 +#define OPV_PRINT_CHAR 0x25 +#define OPV_PRINT_NUM 0x26 +#define OPV_AND 0x09 +#define OPV_OR 0x0A +#define OPV_NOT 0x0B +#define OPV_CALL_EXT 0x20 +#define OPV_PUSH 0x28 +#define OPV_PULL 0x29 + + /* ============================================================ * BDOS @@ -365,9 +372,9 @@ static inline void push(int16_t v){stack[sp++]=v;} static inline int16_t pop(void){return stack[--sp];} static uint16_t get_var(uint8_t v){ - //cpm_printstring("get_var - v:"); - //print_hex(v); - // crlf(); + cpm_printstring("get_var - v:"); + print_hex(v); + crlf(); if(v==0) { uint16_t stack; stack = pop(); @@ -377,9 +384,9 @@ static uint16_t get_var(uint8_t v){ return stack; } if(v<16) { - // cpm_printstring("local: "); - // print_hex(frames[fp-1].locals[v-1]); - // crlf(); + cpm_printstring("local: "); + print_hex(frames[fp-1].locals[v-1]); + crlf(); return frames[fp-1].locals[v-1]; } //uint16_t a=zm_read16(0x0C)+2*(v-16); @@ -395,6 +402,11 @@ static uint16_t get_var(uint8_t v){ } static void set_var(uint8_t v,uint16_t val){ + cpm_printstring("Setvar - var: "); + print_hex(v); + cpm_printstring(" val: "); + print_hex(val); + crlf(); if(v==0) push(val); else if(v<16) frames[fp-1].locals[v-1]=val; else{ @@ -790,6 +802,8 @@ static void step(void){ if(op<0x80){ uint8_t t1=(op&0x40)?OP_VAR:OP_SMALL; uint8_t t2=(op&0x20)?OP_VAR:OP_SMALL; + if(op == 0x05 || op ==0x04) t1=OP_VAR; + uint8_t var_num = zm_read8(pc); operands[0]=read_operand(t1); operands[1]=read_operand(t2); @@ -814,14 +828,27 @@ static void step(void){ case OP2_JG: branch((int16_t)operands[0]>(int16_t)operands[1]); break; + case OP2_JIN: { + uint8_t parent; + parent = obj_parent(operands[0]); + branch(parent == operands[1]); + break; + } case OP2_DEC_CHK: operands[0]--; - set_var(operands[0],operands[0]); + set_var(var_num,operands[0]); branch((int16_t)operands[0]<(int16_t)operands[1]); break; case OP2_INC_CHK: + cpm_printstring("OP2_INC_CHK entry - OP1: "); + print_hex(operands[0]); + cpm_printstring(" OP2: "); + print_hex(operands[1]); + cpm_printstring(" Var: "); + print_hex(var_num); + crlf(); operands[0]++; - set_var(operands[0],operands[0]); + set_var(var_num,operands[0]); branch((int16_t)operands[0]>(int16_t)operands[1]); break; case OP2_TEST: @@ -932,6 +959,18 @@ static void step(void){ case OP1_PRINT_ADDR: print_zstring(operands[0]); break; + case OP1_PRINT_OBJ: { + uint16_t obj = operands[0]; + + if(obj==0) break; + + uint16_t entry = obj_addr(obj); + uint16_t prop_table = zm_read16(entry + 7); + uint8_t name_len = zm_read8(prop_table); + if(name_len==0) break; + print_zstring(prop_table+1); + break; + } case OP1_RET: //case OP1_VALUE: z_ret(operands[0]); @@ -1012,7 +1051,12 @@ static void step(void){ } /* -------- VAR -------- */ decode_operands(zm_read8(pc++)); - switch(op&0x1F){ + uint8_t var_opcode = op & 0x1f; + if((op & 0xE0)==0xE0) var_opcode += 0x20; + cpm_printstring("Var opcode: "); + print_hex(var_opcode); + crlf(); + switch(var_opcode) { /*case OPV_CALL: cpm_printstring("Call - "); if(operands[0]==0) { @@ -1037,6 +1081,7 @@ static void step(void){ crlf(); } break;*/ + case OPV_CALL_EXT: case OPV_CALL: { if (operands[0] == 0) { uint8_t sv = zm_read8(pc++); @@ -1129,6 +1174,12 @@ static void step(void){ obj_put_prop((uint8_t)operands[0],(uint8_t)operands[1], operands[2]); break; + case OPV_OR: + store_result(operands[0] | operands[1]); + break; + case OPV_AND: + store_result(operands[0] & operands[1]); + break; default: printi(op); fatal(" - Non-implemented opcode!!!"); From 8cbd3dce1d807d0cbea6ec2aa9119eb1c9730f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 25 Dec 2025 15:42:21 +0100 Subject: [PATCH 03/36] Gets a bit longer, but get_sibling does not decode correctly --- third_party/z65/z65.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index fcac7a4a..57938d99 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -95,6 +95,7 @@ /* VAR */ #define OPV_CALL 0x00 +#define OPV_JE 0x01 #define OPV_STOREW 0x21 #define OPV_STOREB 0x22 #define OPV_PUT_PROP 0x23 @@ -971,6 +972,31 @@ static void step(void){ print_zstring(prop_table+1); break; } + case OP1_GET_CHILD: { + uint8_t result; + if(operands[0]==0) result = 0; + else result = obj_child(operands[0]); + store_result(result); + branch(result!=0); + break; + } + case OP1_GET_SIBLING: { + uint8_t result; + if(operands[0]==0) result = 0; + else result = obj_sibling(operands[0]); + store_result(result); + branch(result!=0); + break; + } + + + case OP1_GET_PARENT: { + uint8_t result; + if(operands[0]==0) result = 0; + else result = obj_parent(operands[0]); + store_result(result); + break; + } case OP1_RET: //case OP1_VALUE: z_ret(operands[0]); @@ -1115,7 +1141,9 @@ static void step(void){ pc = addr + 2 * f->num_locals; break; } - + case OPV_JE: + branch(operands[0] == operands[1]); + break; case OPV_STOREW: cpm_printstring("STOREW: "); printi(operands[0]); From 8c876f9164294df23056bc40694c6722ea1ba1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 25 Dec 2025 19:43:54 +0100 Subject: [PATCH 04/36] It doesnt crash anymore, but it cant read the input correctly and priniting is wonky --- third_party/z65/z65.c | 108 ++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 46 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 57938d99..ae29eb7c 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -96,6 +96,8 @@ /* VAR */ #define OPV_CALL 0x00 #define OPV_JE 0x01 +#define OPV_JL 0x02 +#define OPV_JG 0x03 #define OPV_STOREW 0x21 #define OPV_STOREB 0x22 #define OPV_PUT_PROP 0x23 @@ -373,9 +375,9 @@ static inline void push(int16_t v){stack[sp++]=v;} static inline int16_t pop(void){return stack[--sp];} static uint16_t get_var(uint8_t v){ - cpm_printstring("get_var - v:"); - print_hex(v); - crlf(); +// cpm_printstring("get_var - v:"); +// print_hex(v); +// crlf(); if(v==0) { uint16_t stack; stack = pop(); @@ -385,9 +387,9 @@ static uint16_t get_var(uint8_t v){ return stack; } if(v<16) { - cpm_printstring("local: "); - print_hex(frames[fp-1].locals[v-1]); - crlf(); + // cpm_printstring("local: "); + // print_hex(frames[fp-1].locals[v-1]); + // crlf(); return frames[fp-1].locals[v-1]; } //uint16_t a=zm_read16(0x0C)+2*(v-16); @@ -403,11 +405,11 @@ static uint16_t get_var(uint8_t v){ } static void set_var(uint8_t v,uint16_t val){ - cpm_printstring("Setvar - var: "); - print_hex(v); - cpm_printstring(" val: "); - print_hex(val); - crlf(); +// cpm_printstring("Setvar - var: "); +// print_hex(v); +// cpm_printstring(" val: "); +// print_hex(val); +// crlf(); if(v==0) push(val); else if(v<16) frames[fp-1].locals[v-1]=val; else{ @@ -794,11 +796,11 @@ static inline uint16_t unpack_routine(uint16_t p) static void step(void){ uint8_t op=zm_read8(pc++); - cpm_printstring("OP: "); - print_hex(op); - cpm_printstring(" PC: "); - print_hex(pc); - crlf(); + //cpm_printstring("OP: "); + //print_hex(op); + //cpm_printstring(" PC: "); + //print_hex(pc); + //crlf(); /* -------- 2OP -------- */ if(op<0x80){ uint8_t t1=(op&0x40)?OP_VAR:OP_SMALL; @@ -816,11 +818,11 @@ static void step(void){ switch(op&0x1F){ case OP2_JE: - cpm_printstring("JE "); - printi(operands[0]); - spc(); - printi(operands[1]); - crlf(); + //cpm_printstring("JE "); + //printi(operands[0]); + //spc(); + //printi(operands[1]); + //crlf(); branch(operands[0]==operands[1]); break; case OP2_JL: @@ -841,13 +843,13 @@ static void step(void){ branch((int16_t)operands[0]<(int16_t)operands[1]); break; case OP2_INC_CHK: - cpm_printstring("OP2_INC_CHK entry - OP1: "); - print_hex(operands[0]); - cpm_printstring(" OP2: "); - print_hex(operands[1]); - cpm_printstring(" Var: "); - print_hex(var_num); - crlf(); + //cpm_printstring("OP2_INC_CHK entry - OP1: "); + //print_hex(operands[0]); + //cpm_printstring(" OP2: "); + //print_hex(operands[1]); + //cpm_printstring(" Var: "); + //print_hex(var_num); + //crlf(); operands[0]++; set_var(var_num,operands[0]); branch((int16_t)operands[0]>(int16_t)operands[1]); @@ -934,11 +936,13 @@ static void step(void){ uint8_t type=(op>>4)&3; uint8_t oc=op&0x0F; if(type!=OP_OMIT) operands[0]=read_operand(type); - cpm_printstring("Type: "); - printi(type); - cpm_printstring(" Operand 1: "); - printi(operands[0]); - crlf(); + //cpm_printstring("Type: "); + //printi(type); + //cpm_printstring(" Operand 1: "); + //printi(operands[0]); + //cpm_printstring(" oc: "); + //print_hex(oc); + //crlf(); switch(oc){ /*case OP1_RTRUE: z_ret(1); @@ -952,9 +956,9 @@ static void step(void){ pc+=2; break;*/ case OP1_JUMP: - cpm_printstring("Performing jump with offset"); - printi(operands[0]-2); - crlf(); + //cpm_printstring("Performing jump with offset"); + //printi(operands[0]-2); + //crlf(); pc+=(int16_t)operands[0]-2; break; case OP1_PRINT_ADDR: @@ -1015,6 +1019,11 @@ static void step(void){ case OP1_JZ: branch(operands[0]==0); break; + case OP1_PRINT_PADDR: { + uint16_t addr = unpack_routine(operands[0]); + print_zstring(addr); + break; + } default: printi(op); fatal(" - Non-implemented opcode!!!"); @@ -1122,9 +1131,9 @@ static void step(void){ f->return_pc = pc; uint16_t addr = unpack_routine(operands[0]); - cpm_printstring("CALL to address "); - print_hex(addr); - crlf(); + //cpm_printstring("CALL to address "); + //print_hex(addr); + //crlf(); f->num_locals = zm_read8(addr++); for (uint8_t i = 0; i < f->num_locals; i++) @@ -1144,14 +1153,21 @@ static void step(void){ case OPV_JE: branch(operands[0] == operands[1]); break; + case OPV_JL: + branch((int16_t)operands[0] < (int16_t)operands[1]); + break; + case OPV_JG: + branch((int16_t)operands[0] > (int16_t)operands[1]); + break; + case OPV_STOREW: - cpm_printstring("STOREW: "); - printi(operands[0]); - spc(); - printi(operands[1]); - spc(); - printi(operands[2]); - crlf(); + //cpm_printstring("STOREW: "); + //printi(operands[0]); + //spc(); + //printi(operands[1]); + //spc(); + //printi(operands[2]); + //crlf(); zm_write8(operands[0]+2*operands[1],operands[2]>>8); zm_write8(operands[0]+2*operands[1]+1,operands[2]); break; From 12a936c3deae7883fa3458ae0f51a458daf09a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 25 Dec 2025 19:56:51 +0100 Subject: [PATCH 05/36] Archival commit, debugging input parsing --- third_party/z65/z65.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index ae29eb7c..75db6fae 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -557,8 +557,11 @@ static void print_num(int16_t v){ // Dictionary static void dict_init(void){ dict_addr = zm_read16(0x08); - + cpm_printstring("Dict addr "); + print_hex(dict_addr); dict_sep_count = zm_read8(dict_addr++); + cpm_printstring(" Dict sep cnt "); + printi(dict_sep_count); for(uint8_t i=0;i Date: Fri, 2 Jan 2026 09:13:44 +0100 Subject: [PATCH 06/36] Fixed z-string decoding --- third_party/z65/z65.c | 147 ++++++++++++++++++++++++++++++++---------- 1 file changed, 112 insertions(+), 35 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 75db6fae..839c2983 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -206,6 +206,16 @@ static uint16_t object_table; static uint8_t alphabet; static uint8_t alphabet_reset; static uint8_t alphabet_prev; +static uint8_t zalph[3][26] = {{'a','b','c','d','e','f','g','h','i','j','k', + 'l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z'}, + {'A','B','C','D','E','F','G','H','I','J','K', + 'L','M','N','O','P','Q','R','S','T','U','V', + 'W','X','Y','Z'}, + {' ','\n','0','1','2','3','4','5','6','7','8', + '9','.',',','!','?','_','#','\'','\"','/', + '\\','-',':','(',')'}}; + static uint8_t abbrev_print; static uint8_t abbrev_table; @@ -356,7 +366,7 @@ static uint16_t zm_read16(uint16_t a){ return ((uint16_t)zm_read8(a)<<8)|zm_read8(a+1); } -static inline void zm_write8(uint16_t a,uint8_t v){ +static void zm_write8(uint16_t a,uint8_t v){ if(a>=dynamic_size) { crlf(); print_hex(a); @@ -371,8 +381,8 @@ static inline void zm_write8(uint16_t a,uint8_t v){ * ============================================================ */ -static inline void push(int16_t v){stack[sp++]=v;} -static inline int16_t pop(void){return stack[--sp];} +static void push(int16_t v){stack[sp++]=v;} +static int16_t pop(void){return stack[--sp];} static uint16_t get_var(uint8_t v){ // cpm_printstring("get_var - v:"); @@ -487,49 +497,39 @@ static void print_zstring(uint16_t addr){ while(1){ uint16_t w=zm_read16(addr); addr+=2; - //cpm_printstring("zstring decode - word: "); - //print_hex(w); - //spc(); - + for(int i=10;i>=0;i-=5){ uint8_t c=(w>>i)&0x1F; - //print_hex(c); - //spc(); - //printi(alphabet); - //spc(); - if(alphabet == 0) base = 'a'-6; - else if(alphabet == 1) base = 'A'-6; - else if(alphabet == 2) base = '0'-8; - else base = 'a' - 6; - - if(alphabet_reset) { - alphabet = alphabet_prev; - alphabet_reset = 0; - } - - + if(abbrev_print == 1) { uint16_t string_addr; + alphabet = 0; + alphabet_prev = 0; string_addr = zm_read16(abbrev_base+(((abbrev_table<<5)+c)<<1)); abbrev_print = 0; print_zstring(string_addr<<1); + alphabet = 0; + alphabet_prev = 0; } else if(c>=6) { - //crlf(); - putc(base+c); - //crlf(); + putc(zalph[alphabet][c-6]); + if(alphabet_reset) { + alphabet = alphabet_prev; + alphabet_reset = 0; + + } } else if(c==4) { alphabet_prev = alphabet; alphabet = (alphabet + 1) % 3; alphabet_reset = 1; - } + } else if(c==5) { alphabet_prev = alphabet; if(alphabet == 0) alphabet = 2; else alphabet--; alphabet_reset = 1; - } + } else if((c>0) && (c<4)) { abbrev_print = 1; abbrev_table = c-1; @@ -537,8 +537,10 @@ static void print_zstring(uint16_t addr){ else if(c==0) putc(' '); } - //crlf(); - if(w&0x8000) break; + if(w&0x8000) { + alphabet = alphabet_prev = 0; + break; + } } } @@ -570,7 +572,7 @@ static void dict_init(void){ } -static uint16_t dict_lookup(const char *w,uint8_t len){ +/*static uint16_t dict_lookup(const char *w,uint8_t len){ uint16_t base = dict_addr + 2; for(uint16_t i=0;i= 'A' && c <= 'Z') + c = c - 'A' + 'a'; + + if (c >= 'a' && c <= 'z') { + zchars[zi++] = (c - 'a') + 6; + } + else { + /* shift to A2 */ + if (zi < 6) + zchars[zi++] = 5; + if (zi < 6) + zchars[zi++] = encode_a2(c); + } + } + + /* pad with spaces (A2 space = shift 5 + 0, but Inform pads with 5) */ + while (zi < 6) + zchars[zi++] = 5; +} + +uint16_t dict_lookup(const char *word) +{ + uint8_t zchars[6]; + encode_zchars(word, zchars); + + uint16_t w0 = (zchars[0] << 10) | (zchars[1] << 5) | zchars[2]; + uint16_t w1 = (zchars[3] << 10) | (zchars[4] << 5) | zchars[5] | 0x8000; + cpm_printstring("dict lookup "); + print_hex(w0); + spc(); + print_hex(w1); + crlf(); + uint16_t dict = dict_addr; + uint8_t sep = zm_read8(dict++); + dict += sep; + + uint8_t entry_len = zm_read8(dict++); + uint16_t count = zm_read16(dict); + dict += 2; + cpm_printstring("sep: "); + printi(sep); + cpm_printstring(" entry_len: "); + printi(entry_len); + cpm_printstring(" count: "); + printi(count); + crlf(); + for (uint16_t i = 0; i < count; i++) { + uint16_t e = dict + i * entry_len; + if (zm_read16(e) == w0 && zm_read16(e + 2) == w1) + return e; + } + return 0; } + // Tokenization static uint8_t is_sep(char c){ @@ -612,7 +689,7 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) while(in[i] && !is_sep(in[i]) && len<6) word[len++]=in[i++]; - uint16_t dict = dict_lookup(word,len); + uint16_t dict = dict_lookup(word); uint16_t entry = parse_buf + 2 + count*4; zm_write8(entry, dict>>8); @@ -630,7 +707,7 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) // Objects -static inline uint16_t obj_addr(uint8_t obj) +static uint16_t obj_addr(uint8_t obj) { return object_table + 62 + (obj - 1) * 9; } @@ -1094,9 +1171,9 @@ static void step(void){ decode_operands(zm_read8(pc++)); uint8_t var_opcode = op & 0x1f; if((op & 0xE0)==0xE0) var_opcode += 0x20; - cpm_printstring("Var opcode: "); - print_hex(var_opcode); - crlf(); + //cpm_printstring("Var opcode: "); + //print_hex(var_opcode); + //crlf(); switch(var_opcode) { /*case OPV_CALL: cpm_printstring("Call - "); From 313713ef694af5ada643df1d1430ef39f07bcbe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Fri, 2 Jan 2026 10:30:26 +0100 Subject: [PATCH 07/36] Dictionary lookup seems to work --- third_party/z65/z65.c | 90 +++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 839c2983..b871a78d 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -204,8 +204,6 @@ static uint16_t dict_entry_count; static uint16_t object_table; static uint8_t alphabet; -static uint8_t alphabet_reset; -static uint8_t alphabet_prev; static uint8_t zalph[3][26] = {{'a','b','c','d','e','f','g','h','i','j','k', 'l','m','n','o','p','q','r','s','t','u','v', 'w','x','y','z'}, @@ -493,7 +491,6 @@ static void branch(uint8_t cond){ */ static void print_zstring(uint16_t addr){ - uint8_t base; while(1){ uint16_t w=zm_read16(addr); addr+=2; @@ -504,32 +501,21 @@ static void print_zstring(uint16_t addr){ if(abbrev_print == 1) { uint16_t string_addr; alphabet = 0; - alphabet_prev = 0; string_addr = zm_read16(abbrev_base+(((abbrev_table<<5)+c)<<1)); abbrev_print = 0; print_zstring(string_addr<<1); alphabet = 0; - alphabet_prev = 0; } else if(c>=6) { putc(zalph[alphabet][c-6]); - if(alphabet_reset) { - alphabet = alphabet_prev; - alphabet_reset = 0; - - } + alphabet = 0; } else if(c==4) { - alphabet_prev = alphabet; - alphabet = (alphabet + 1) % 3; - alphabet_reset = 1; - } + alphabet = 1; + } else if(c==5) { - alphabet_prev = alphabet; - if(alphabet == 0) alphabet = 2; - else alphabet--; - alphabet_reset = 1; - } + alphabet = 2; + } else if((c>0) && (c<4)) { abbrev_print = 1; abbrev_table = c-1; @@ -538,7 +524,7 @@ static void print_zstring(uint16_t addr){ } if(w&0x8000) { - alphabet = alphabet_prev = 0; + alphabet = 0; break; } } @@ -558,34 +544,31 @@ static void print_num(int16_t v){ // Dictionary static void dict_init(void){ - dict_addr = zm_read16(0x08); + dict_addr = hdr[0x08]<<8 | hdr[0x09]; cpm_printstring("Dict addr "); print_hex(dict_addr); dict_sep_count = zm_read8(dict_addr++); cpm_printstring(" Dict sep cnt "); printi(dict_sep_count); - for(uint8_t i=0;i Date: Fri, 2 Jan 2026 13:23:10 +0100 Subject: [PATCH 08/36] Now also prints strings at addresses above 0xffff. PC etc. also needs to be modified to support larger addresses --- third_party/z65/z65.c | 159 +++++++++++++++++++++++++++++++++++------- 1 file changed, 132 insertions(+), 27 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index b871a78d..46856c8e 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -104,9 +104,11 @@ #define OPV_SREAD 0x24 #define OPV_PRINT_CHAR 0x25 #define OPV_PRINT_NUM 0x26 +#define OPV_RANDOM 0x27 #define OPV_AND 0x09 #define OPV_OR 0x0A #define OPV_NOT 0x0B +#define OPV_STORE 0x0D #define OPV_CALL_EXT 0x20 #define OPV_PUSH 0x28 #define OPV_PULL 0x29 @@ -218,6 +220,10 @@ static uint8_t zalph[3][26] = {{'a','b','c','d','e','f','g','h','i','j','k', static uint8_t abbrev_print; static uint8_t abbrev_table; static uint16_t abbrev_base; + +static uint16_t rng_state = 1; +static uint8_t rng_enabled = 1; + /* ============================================================ * Console * ============================================================ @@ -250,6 +256,18 @@ static void print_hex(uint16_t val) } } +static void print_hex_32(uint32_t val) +{ + cpm_printstring("0x"); + for(uint8_t i = 8; i>0; i--) { + uint8_t nibble = (val >> ((i-1) << 2)) & 0xf; + + if(nibble < 10) cpm_conout(nibble + '0'); + else cpm_conout(nibble-10 + 'A'); + } +} + + static void printx(const char *s) { cpm_printstring(s); @@ -335,7 +353,7 @@ static Page *get_page(uint16_t page){ * ============================================================ */ -static uint8_t zm_read8(uint16_t a){ +static uint8_t zm_read8(uint32_t a){ //cpm_printstring("read 8 addr "); //printi(a); //cpm_printstring(" data "); @@ -360,11 +378,11 @@ static uint8_t zm_read8(uint16_t a){ return p->data[a&0x1FF]; } -static uint16_t zm_read16(uint16_t a){ +static uint16_t zm_read16(uint32_t a){ return ((uint16_t)zm_read8(a)<<8)|zm_read8(a+1); } -static void zm_write8(uint16_t a,uint8_t v){ +static void zm_write8(uint32_t a,uint8_t v){ if(a>=dynamic_size) { crlf(); print_hex(a); @@ -379,8 +397,22 @@ static void zm_write8(uint16_t a,uint8_t v){ * ============================================================ */ -static void push(int16_t v){stack[sp++]=v;} -static int16_t pop(void){return stack[--sp];} +static void push(int16_t v){ + /*crlf(); + cpm_printstring("Stack push - "); + print_hex(v); + crlf();*/ + stack[sp++]=v; +} +static uint16_t pop(void) { + uint16_t val; + val = stack[--sp]; + /*crlf(); + cpm_printstring("Stack pop - "); + print_hex(val); + crlf();*/ + return val; +} static uint16_t get_var(uint8_t v){ // cpm_printstring("get_var - v:"); @@ -389,9 +421,10 @@ static uint16_t get_var(uint8_t v){ if(v==0) { uint16_t stack; stack = pop(); - // cpm_printstring("stack: "); - // print_hex(stack); - // crlf(); + //crlf(); + //cpm_printstring("stack: "); + //print_hex(stack); + //crlf(); return stack; } if(v<16) { @@ -490,11 +523,11 @@ static void branch(uint8_t cond){ * ============================================================ */ -static void print_zstring(uint16_t addr){ +static void print_zstring(uint32_t addr){ while(1){ uint16_t w=zm_read16(addr); addr+=2; - + //print_hex(w); for(int i=10;i>=0;i-=5){ uint8_t c=(w>>i)&0x1F; @@ -672,6 +705,11 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) uint8_t count=0; uint8_t i=0; + uint8_t max_text = zm_read8(parse_buf); + cpm_printstring("Max test: "); + print_hex(max_text); + crlf(); + while(in[i] && count>8); + spc(); + print_hex(dict & 0xff); + spc(); + print_hex(len); + spc(); + print_hex(start+1); zm_write8(entry, dict>>8); - zm_write8(entry+1, dict); + zm_write8(entry+1, dict & 0xff); zm_write8(entry+2, len); zm_write8(entry+3, start+1); @@ -695,6 +745,14 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) } zm_write8(parse_buf+1,count); + + uint8_t x; + crlf(); + for(x=0; x<(count<<2)+2; x++) { + print_hex(zm_read8(parse_buf+x)); + crlf(); + } + return count; } @@ -871,13 +929,26 @@ static inline uint16_t unpack_routine(uint16_t p) return p << 1; } +static uint16_t rng_next(void) +{ + uint16_t x = rng_state; + + x ^= x << 7; + x ^= x >> 9; + x ^= x << 8; + + rng_state = x & 0x7fff; + + return rng_state; +} + static void step(void){ uint8_t op=zm_read8(pc++); - //cpm_printstring("OP: "); - //print_hex(op); - //cpm_printstring(" PC: "); - //print_hex(pc); - //crlf(); + cpm_printstring("OP: "); + print_hex(op); + cpm_printstring(" PC: "); + print_hex(pc); + crlf(); /* -------- 2OP -------- */ if(op<0x80){ uint8_t t1=(op&0x40)?OP_VAR:OP_SMALL; @@ -886,13 +957,13 @@ static void step(void){ uint8_t var_num = zm_read8(pc); operands[0]=read_operand(t1); operands[1]=read_operand(t2); - - //cpm_printstring("2OP - "); - //print_hex(operands[0]); - //spc(); - //print_hex(operands[1]); - //crlf(); - + /* + cpm_printstring("2OP - "); + print_hex(operands[0]); + spc(); + print_hex(operands[1]); + crlf(); + */ switch(op&0x1F){ case OP2_JE: //cpm_printstring("JE "); @@ -1004,6 +1075,9 @@ static void step(void){ default: crlf(); printi(op); + spc(); + print_hex(pc); + spc(); fatal(" - Non-implemented opcode!!!"); } return; @@ -1098,7 +1172,12 @@ static void step(void){ branch(operands[0]==0); break; case OP1_PRINT_PADDR: { - uint16_t addr = unpack_routine(operands[0]); + uint32_t addr = (uint32_t)operands[0] << 1; + //print_hex_32(addr); + //crlf(); + //cpm_printstring("OP1 PRINT_PADDR - "); + //print_hex(addr); + //crlf(); print_zstring(addr); break; } @@ -1256,6 +1335,10 @@ static void step(void){ zm_write8(operands[0]+operands[1],operands[2]); break; + case OPV_STORE: + set_var(operands[0],operands[1]); + break; + case OPV_PRINT_CHAR: putc((char)operands[0]); break; @@ -1275,7 +1358,7 @@ static void step(void){ uint16_t text = operands[0]; uint16_t parse = operands[1]; - char line[INPUT_MAX]; + char line[INPUT_MAX]={0}; uint8_t len = read_line(line); uint8_t max = zm_read8(text); @@ -1304,6 +1387,28 @@ static void step(void){ case OPV_AND: store_result(operands[0] & operands[1]); break; + case OPV_RANDOM: { + crlf(); + cpm_printstring("Random called with argument "); + print_hex(operands[0]); + crlf(); + int16_t range = (int16_t)operands[0]; + if(range == 0) { + rng_state = (uint16_t)pc; + store_result(0); + break; + } + if(range < 0) { + rng_state = (uint16_t)(-range); + store_result(0); + break; + } + + uint16_t r = rng_next(); + uint16_t result = (r % range) + 1; + store_result(result); + break; + } default: crlf(); printi(op); From 2d997d23198dcb08268115ea03f3ed1777ac1075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Fri, 2 Jan 2026 13:49:23 +0100 Subject: [PATCH 09/36] Fixed ZSCII escape printing --- third_party/z65/z65.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 46856c8e..2e9a3e45 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -206,6 +206,8 @@ static uint16_t dict_entry_count; static uint16_t object_table; static uint8_t alphabet; +static uint8_t zscii_esc=0; +static uint8_t zscii_high; static uint8_t zalph[3][26] = {{'a','b','c','d','e','f','g','h','i','j','k', 'l','m','n','o','p','q','r','s','t','u','v', 'w','x','y','z'}, @@ -539,6 +541,19 @@ static void print_zstring(uint32_t addr){ print_zstring(string_addr<<1); alphabet = 0; } + else if(zscii_esc == 1) { + zscii_high = c; + zscii_esc = 2; + } + else if(zscii_esc == 2) { + putc((zscii_high << 5) | c); + zscii_esc = 0; + } + else if(alphabet == 2 && c==6) { + // ZSCII escape + zscii_esc = 1; + alphabet = 0; + } else if(c>=6) { putc(zalph[alphabet][c-6]); alphabet = 0; @@ -944,11 +959,11 @@ static uint16_t rng_next(void) static void step(void){ uint8_t op=zm_read8(pc++); - cpm_printstring("OP: "); + /*cpm_printstring("OP: "); print_hex(op); cpm_printstring(" PC: "); print_hex(pc); - crlf(); + crlf();*/ /* -------- 2OP -------- */ if(op<0x80){ uint8_t t1=(op&0x40)?OP_VAR:OP_SMALL; From 3427b491be216fde2d98b198831effc50f52e1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Tue, 6 Jan 2026 19:43:46 +0100 Subject: [PATCH 10/36] Archival commit, full of debugging trace prints --- third_party/z65/z65.c | 194 ++++++++++++++++++++++++++---------------- 1 file changed, 121 insertions(+), 73 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 2e9a3e45..21fb619a 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -186,8 +186,8 @@ static uint16_t dynamic_size; static Page page_cache[NUM_PAGES]; static uint8_t next_victim; -static uint16_t pc; -static uint16_t initial_pc; +static uint32_t pc; +static uint32_t initial_pc; static int16_t stack[STACK_SIZE]; static uint16_t sp; @@ -430,9 +430,11 @@ static uint16_t get_var(uint8_t v){ return stack; } if(v<16) { - // cpm_printstring("local: "); - // print_hex(frames[fp-1].locals[v-1]); - // crlf(); + cpm_printstring("local "); + printi(v); + cpm_printstring(": "); + print_hex(frames[fp-1].locals[v-1]); + crlf(); return frames[fp-1].locals[v-1]; } //uint16_t a=zm_read16(0x0C)+2*(v-16); @@ -454,7 +456,14 @@ static void set_var(uint8_t v,uint16_t val){ // print_hex(val); // crlf(); if(v==0) push(val); - else if(v<16) frames[fp-1].locals[v-1]=val; + else if(v<16) { + cpm_printstring("Setvar local "); + printi(v); + spc(); + print_hex(val); + crlf(); + frames[fp-1].locals[v-1]=val; + } else{ //uint16_t a=zm_read16(0x0C)+2*(v-16); uint16_t a = (hdr[0x0c]<<8) + hdr[0x0d] + 2*(v-16); @@ -493,6 +502,8 @@ static void decode_operands(uint8_t spec){ uint8_t t=(spec>>s)&3; if(t==OP_OMIT) break; operands[operand_count++]=read_operand(t); + cpm_printstring("Operand "); + printi(operand_count); } } @@ -504,16 +515,36 @@ static void decode_operands(uint8_t spec){ static void branch(uint8_t cond){ uint8_t b=zm_read8(pc++); - uint8_t sense=b&0x80; + //uint8_t sense=b&0x80; int16_t off; if(b&0x40) off=b&0x3F; else{ off=((b&0x3F)<<8)|zm_read8(pc++); + // Sign extension for 14-bit long offset if(off&0x2000) off|=0xC000; } - if((cond!=0)==(sense!=0)){ + uint8_t take_branch = 0; + + if(b & 0x80) { + if(cond) take_branch = 1; + } + else { + if(!cond) take_branch = 1; + } + + cpm_printstring("Branch cond: "); + print_hex(cond); + cpm_printstring(" sense: "); + print_hex(b & 0x80); + cpm_printstring(" take_branch: "); + print_hex(take_branch); + cpm_printstring(" offset: "); + print_hex(off); + crlf(); + + if(take_branch) { if(off==0) push(0),pc=frames[--fp].return_pc; else if(off==1) push(1),pc=frames[--fp].return_pc; else pc+=off-2; @@ -593,27 +624,28 @@ static void print_num(int16_t v){ // Dictionary static void dict_init(void){ dict_addr = hdr[0x08]<<8 | hdr[0x09]; - cpm_printstring("Dict addr "); - print_hex(dict_addr); +// cpm_printstring("Dict addr "); +// print_hex(dict_addr); dict_sep_count = zm_read8(dict_addr++); - cpm_printstring(" Dict sep cnt "); - printi(dict_sep_count); +// cpm_printstring(" Dict sep cnt "); +// printi(dict_sep_count); for(uint8_t i=0;i(int16_t)operands[1]); @@ -1144,18 +1175,28 @@ static void step(void){ break; } case OP1_GET_CHILD: { + cpm_printstring("GET_CHILD for object "); + print_hex(operands[0]); uint8_t result; if(operands[0]==0) result = 0; else result = obj_child(operands[0]); store_result(result); + cpm_printstring(" CHILD: "); + print_hex(result); + crlf(); branch(result!=0); break; } case OP1_GET_SIBLING: { + cpm_printstring("GET_SIBLING for object "); + print_hex(operands[0]); + uint8_t result; if(operands[0]==0) result = 0; else result = obj_sibling(operands[0]); store_result(result); + cpm_printstring(" SIBLING "); + print_hex(result); branch(result!=0); break; } @@ -1184,6 +1225,8 @@ static void step(void){ // z_ret(operands[0]); // break; case OP1_JZ: + cpm_printstring("JZ - arg "); + print_hex(operands[0]); branch(operands[0]==0); break; case OP1_PRINT_PADDR: { @@ -1304,24 +1347,34 @@ static void step(void){ f->store_var = sv; f->return_pc = pc; - uint16_t addr = unpack_routine(operands[0]); + uint32_t addr = unpack_routine(operands[0]); //cpm_printstring("CALL to address "); //print_hex(addr); //crlf(); f->num_locals = zm_read8(addr++); - for (uint8_t i = 0; i < f->num_locals; i++) - f->locals[i] = zm_read16(addr + 2*i); + for (uint8_t i = 0; i < f->num_locals; i++) { + f->locals[i] = zm_read16(addr); + addr += 2; + } /* overwrite locals with arguments */ uint8_t argc = operand_count - 1; if (argc > f->num_locals) argc = f->num_locals; + cpm_printstring("Argc: "); + printi(argc); + for (uint8_t i = 0; i < argc; i++){ + //f->locals[i] = operands[i + 1]; + f->locals[i] = operands[i + 1]; + cpm_printstring("locals "); + printi(i); + spc(); + print_hex(f->locals[i]); + crlf(); + } - for (uint8_t i = 0; i < argc; i++) - f->locals[i] = operands[i + 1]; - - pc = addr + 2 * f->num_locals; + pc = addr; // + 2 * f->num_locals; break; } case OPV_JE: @@ -1386,13 +1439,13 @@ static void step(void){ tokenize(line,parse,text); break; } case OPV_PUT_PROP: - cpm_printstring("Putprop - "); + /*cpm_printstring("Putprop - "); print_hex(operands[0]); spc(); print_hex(operands[1]); spc(); print_hex(operands[2]); - crlf(); + crlf();*/ obj_put_prop((uint8_t)operands[0],(uint8_t)operands[1], operands[2]); break; @@ -1439,16 +1492,11 @@ static void step(void){ */ int main(int agrv, char **argv){ - /* - story_fcb.drive=0; - story_fcb.name[0]='S';story_fcb.name[1]='T';story_fcb.name[2]='O'; - story_fcb.name[3]='R';story_fcb.name[4]='Y';story_fcb.name[5]=' '; - story_fcb.name[6]=' ';story_fcb.name[7]=' '; - story_fcb.ext[0]='Z';story_fcb.ext[1]='3';story_fcb.ext[2]=' '; - */ + cpm_printstring("z65 - Z-machine v3 interpreter"); + crlf(); + crlf(); + // Get story filename from commandline - - //cpm_fcb.cr = 0; if(cpm_open_file(&cpm_fcb)) fatal("Could not open input file!"); @@ -1456,15 +1504,15 @@ int main(int agrv, char **argv){ //bdos(BDOS_READ_SEQ,&story_fcb); cpm_read_sequential(&cpm_fcb); //uint8_t *hdr=dma; - + dynamic_size=(hdr[0x0e]<<8)|hdr[0x0f]; - cpm_printstring("Dynamic size: "); + //cpm_printstring("Dynamic size: "); for(uint16_t i=0; iDYNAMIC_MEM_MAX) while(1); for(uint16_t i=0; i<128; i++) @@ -1490,8 +1538,8 @@ int main(int agrv, char **argv){ abbrev_table = 0; abbrev_base = (hdr[0x18]<<8)|hdr[0x19]; - cpm_printstring("PC: "); - print_hex(pc); - crlf(); + //cpm_printstring("PC: "); + //print_hex(pc); + //crlf(); for(;;) step(); } From 7ed40c74aef8059875042aaf742ef234026fa7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Wed, 7 Jan 2026 13:22:58 +0100 Subject: [PATCH 11/36] Multiple fixes, now prints Zork I intro correctly --- third_party/z65/z65.c | 221 +++++++++++++++++++++++++++++++----------- 1 file changed, 167 insertions(+), 54 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 21fb619a..26765c7d 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -77,7 +77,7 @@ #define OP1_JUMP 0x0C #define OP1_PRINT_PADDR 0x0D #define OP1_LOAD 0x0E -#define OP1_CALL_1N 0x0F +#define OP1_NOT 0x0F /* 0OP */ #define OP0_RTRUE 0x00 @@ -108,11 +108,13 @@ #define OPV_AND 0x09 #define OPV_OR 0x0A #define OPV_NOT 0x0B +#define OPV_LOADW 0x0F #define OPV_STORE 0x0D #define OPV_CALL_EXT 0x20 #define OPV_PUSH 0x28 #define OPV_PULL 0x29 - +#define OPV_LOADB 0x50 +#define OPV_MUL 0x56 /* ============================================================ @@ -161,10 +163,11 @@ */ typedef struct { - uint16_t return_pc; + uint32_t return_pc; uint8_t store_var; uint8_t num_locals; uint16_t locals[MAX_LOCALS]; + uint16_t saved_sp; } CallFrame; typedef struct { @@ -226,6 +229,9 @@ static uint16_t abbrev_base; static uint16_t rng_state = 1; static uint8_t rng_enabled = 1; +static void z_ret(uint16_t v); + + /* ============================================================ * Console * ============================================================ @@ -424,8 +430,10 @@ static uint16_t get_var(uint8_t v){ uint16_t stack; stack = pop(); //crlf(); - //cpm_printstring("stack: "); + //cpm_printstring("stack pop: "); //print_hex(stack); + //cpm_printstring(" SP: "); + //print_hex(sp); //crlf(); return stack; } @@ -455,7 +463,14 @@ static void set_var(uint8_t v,uint16_t val){ // cpm_printstring(" val: "); // print_hex(val); // crlf(); - if(v==0) push(val); + if(v==0) { + push(val); + //cpm_printstring("stack push: "); + //print_hex(val); + //cpm_printstring(" SP: "); + //print_hex(sp); + //crlf(); + } else if(v<16) { cpm_printstring("Setvar local "); printi(v); @@ -489,10 +504,16 @@ static uint16_t operands[MAX_OPERANDS]; static uint8_t operand_count; static uint16_t read_operand(uint8_t t){ - if(t==OP_LARGE){pc+=2;return zm_read16(pc-2);} - if(t==OP_SMALL)return zm_read8(pc++); - if(t==OP_VAR)return get_var(zm_read8(pc++)); - return 0; + uint16_t value=0; + if(t==OP_LARGE){pc+=2;value = zm_read16(pc-2);} + if(t==OP_SMALL)value = zm_read8(pc++); + if(t==OP_VAR) value = get_var(zm_read8(pc++)); + /*cpm_printstring(" type: "); + print_hex(t); + cpm_printstring(" value: "); + print_hex(value); + crlf();*/ + return value; } @@ -501,9 +522,9 @@ static void decode_operands(uint8_t spec){ for(int s=6;s>=0;s-=2){ uint8_t t=(spec>>s)&3; if(t==OP_OMIT) break; + /*cpm_printstring("Operand "); + printi(operand_count);*/ operands[operand_count++]=read_operand(t); - cpm_printstring("Operand "); - printi(operand_count); } } @@ -534,7 +555,7 @@ static void branch(uint8_t cond){ if(!cond) take_branch = 1; } - cpm_printstring("Branch cond: "); + /*cpm_printstring("Branch cond: "); print_hex(cond); cpm_printstring(" sense: "); print_hex(b & 0x80); @@ -543,10 +564,20 @@ static void branch(uint8_t cond){ cpm_printstring(" offset: "); print_hex(off); crlf(); - + */ if(take_branch) { - if(off==0) push(0),pc=frames[--fp].return_pc; - else if(off==1) push(1),pc=frames[--fp].return_pc; + if(off==0) { + //push(0); + //pc=frames[--fp].return_pc; + //sp=frames[--fp].saved_sp; + z_ret(0); + } + else if(off==1) { + //push(1); + //pc=frames[--fp].return_pc; + //sp=frames[--fp].saved_sp; + z_ret(1); + } else pc+=off-2; } } @@ -748,9 +779,9 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) uint8_t i=0; uint8_t max_text = zm_read8(parse_buf); - cpm_printstring("Max test: "); - print_hex(max_text); - crlf(); + //cpm_printstring("Max test: "); + //print_hex(max_text); + //crlf(); while(in[i] && count>8); zm_write8(entry+1, dict & 0xff); zm_write8(entry+2, len); - zm_write8(entry+3, start+1); + zm_write8(entry+3, start+2);//1); count++; } @@ -813,7 +844,7 @@ static uint8_t obj_test_attr(uint8_t obj, uint8_t attr){ static void obj_set_attr(uint8_t obj, uint8_t attr){ uint16_t a = obj_addr(obj) + (attr >> 3); - zm_write8(a, zm_read8(a) | (0x80 >> (attr & 7))); + if(obj != 0) zm_write8(a, zm_read8(a) | (0x80 >> (attr & 7))); } static void obj_clear_attr(uint8_t obj, uint8_t attr){ @@ -834,6 +865,7 @@ static uint8_t obj_child(uint8_t obj){ } static void obj_remove(uint8_t obj){ + if(!obj) return; uint8_t parent = obj_parent(obj); if (!parent) return; @@ -859,6 +891,7 @@ static void obj_remove(uint8_t obj){ } static void obj_insert(uint8_t obj, uint8_t dest){ + if(obj == 0 || dest == 0) return; obj_remove(obj); uint16_t daddr = obj_addr(dest) + 6; @@ -944,8 +977,11 @@ static void obj_put_prop(uint8_t obj, uint8_t prop, uint16_t val){ */ static void z_ret(uint16_t v){ - CallFrame *f=&frames[--fp]; + CallFrame *f=&frames[fp-1]; + fp--; pc=f->return_pc; + sp=f->saved_sp; + /*if(f->store_var != 0)*/ set_var(f->store_var,v); } @@ -989,7 +1025,7 @@ static void step(void){ cpm_printstring("OP: "); print_hex(op); cpm_printstring(" PC: "); - print_hex(pc); + print_hex_32(pc); crlf(); /* -------- 2OP -------- */ if(op<0x80){ @@ -1108,13 +1144,38 @@ static void step(void){ } case OP2_GET_NEXT_PROP: { - uint16_t p = obj_find_prop(operands[0], operands[1]); + cpm_printstring("GET_NEXT_PROP - op1: "); + print_hex(operands[0]); + cpm_printstring(" op2: "); + print_hex(operands[1]); + crlf(); + uint8_t obj = (uint8_t)operands[0]; + uint8_t prop = (uint8_t)operands[1]; + uint16_t addr; + + if (prop==0) { + addr = obj_prop_start(obj); + } else { + addr = obj_find_prop(obj, prop); + if(!addr) { + store_result(0); + break; + } + addr+=obj_get_prop_len(addr); + } + + uint8_t next_header = zm_read8(addr); + + if(next_header == 0) store_result(0); + else store_result(next_header & 0x1F); + + /*uint16_t p = obj_find_prop(operands[0], operands[1]); if (!p) { store_result(0); } else { uint8_t h = zm_read8(p - 1); store_result(h & 0x1F); - } + }*/ break; } @@ -1174,29 +1235,32 @@ static void step(void){ print_zstring(prop_table+1); break; } + case OP1_REMOVE_OBJ: + obj_remove(operands[0]); + break; case OP1_GET_CHILD: { - cpm_printstring("GET_CHILD for object "); - print_hex(operands[0]); + //cpm_printstring("GET_CHILD for object "); + //print_hex(operands[0]); uint8_t result; if(operands[0]==0) result = 0; else result = obj_child(operands[0]); store_result(result); - cpm_printstring(" CHILD: "); - print_hex(result); - crlf(); + //cpm_printstring(" CHILD: "); + //print_hex(result); + //crlf(); branch(result!=0); break; } case OP1_GET_SIBLING: { - cpm_printstring("GET_SIBLING for object "); - print_hex(operands[0]); + //cpm_printstring("GET_SIBLING for object "); + //print_hex(operands[0]); uint8_t result; if(operands[0]==0) result = 0; else result = obj_sibling(operands[0]); store_result(result); - cpm_printstring(" SIBLING "); - print_hex(result); + //cpm_printstring(" SIBLING "); + //print_hex(result); branch(result!=0); break; } @@ -1209,18 +1273,42 @@ static void step(void){ store_result(result); break; } + case OP1_GET_PROP_LEN: { + uint8_t result; + if(operands[0]==0) result = 0; + else result = obj_get_prop_len(operands[0]); + store_result(result); + break; + } + case OP1_LOAD: { + uint8_t result; + result = get_var(operands[0]); + store_result(result); + } + case OP1_NOT: { + uint8_t result; + result = ~operands[0]; + store_result(result); + } case OP1_RET: //case OP1_VALUE: z_ret(operands[0]); break; - case OP1_INC: - operands[0]++; - set_var(zm_read8(pc-1),operands[0]); + case OP1_INC: { + //cpm_printstring("OP1_INC - operand: "); + //print_hex(operands[0]); + //crlf(); + uint8_t value = get_var(operands[0]); + value++; + set_var(operands[0], value); break; - case OP1_DEC: - operands[0]--; - set_var(zm_read8(pc-1),operands[0]); + } + case OP1_DEC: { + uint8_t value = get_var(operands[0]); + value--; + set_var(operands[0], value); break; + } //case OP1_RET: // z_ret(operands[0]); // break; @@ -1241,7 +1329,9 @@ static void step(void){ } default: crlf(); - printi(op); + printi(op); + spc(); + print_hex(pc); fatal(" - Non-implemented opcode!!!"); } return; @@ -1305,6 +1395,7 @@ static void step(void){ decode_operands(zm_read8(pc++)); uint8_t var_opcode = op & 0x1f; if((op & 0xE0)==0xE0) var_opcode += 0x20; + if((op & 0xD0)==0xD0) var_opcode += 0x40; //cpm_printstring("Var opcode: "); //print_hex(var_opcode); //crlf(); @@ -1340,17 +1431,20 @@ static void step(void){ set_var(sv, 0); return; } - + CallFrame *f = &frames[fp++]; uint8_t sv = zm_read8(pc++); f->store_var = sv; f->return_pc = pc; - - uint32_t addr = unpack_routine(operands[0]); - //cpm_printstring("CALL to address "); - //print_hex(addr); - //crlf(); + f->saved_sp = sp; + + uint32_t addr = (uint32_t)operands[0]<<1; + /*cpm_printstring("CALL to address "); + print_hex_32(addr); + spc(); + print_hex(operands[0]); + crlf()*/; f->num_locals = zm_read8(addr++); for (uint8_t i = 0; i < f->num_locals; i++) { @@ -1362,23 +1456,33 @@ static void step(void){ uint8_t argc = operand_count - 1; if (argc > f->num_locals) argc = f->num_locals; - cpm_printstring("Argc: "); - printi(argc); + //cpm_printstring("Argc: "); + //printi(argc); for (uint8_t i = 0; i < argc; i++){ //f->locals[i] = operands[i + 1]; f->locals[i] = operands[i + 1]; - cpm_printstring("locals "); - printi(i); - spc(); - print_hex(f->locals[i]); - crlf(); + //cpm_printstring("locals "); + //printi(i); + //spc(); + //print_hex(f->locals[i]); + //crlf(); } pc = addr; // + 2 * f->num_locals; break; } case OPV_JE: - branch(operands[0] == operands[1]); + cpm_printstring("JE VAR - operand count: "); + print_hex(operand_count); + if(operand_count == 2) + branch(operands[0] == operands[1]); + else if(operand_count == 3) + branch(operands[0] == operands[1] || + operands[0] == operands[2]); + else if(operand_count == 4) + branch(operands[0] == operands[1] || + operands[0] == operands[2] || + operands[0] == operands[3]); break; case OPV_JL: branch((int16_t)operands[0] < (int16_t)operands[1]); @@ -1477,6 +1581,15 @@ static void step(void){ store_result(result); break; } + case OPV_LOADW: + store_result(zm_read16(operands[0]+2*operands[1])); + break; + case OPV_LOADB: + store_result(zm_read8(operands[0]+operands[1])); + break; + case OPV_MUL: + store_result((int16_t)operands[0]*(int16_t)operands[1]); + break; default: crlf(); printi(op); From 20f9c3a872591c07501110d33569194fef46922b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Wed, 7 Jan 2026 14:28:51 +0100 Subject: [PATCH 12/36] czech.z3 now runs without crashing, but many tests fail --- third_party/z65/z65.c | 99 ++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 26765c7d..609da8cc 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -92,12 +92,15 @@ #define OP0_POP 0x09 #define OP0_QUIT 0x0A #define OP0_NEW_LINE 0x0B +#define OP0_VERIFY 0x0D /* VAR */ #define OPV_CALL 0x00 #define OPV_JE 0x01 #define OPV_JL 0x02 #define OPV_JG 0x03 +#define OPV_INC_CHK 0x05 +#define OPV_TEST 0x07 #define OPV_STOREW 0x21 #define OPV_STOREB 0x22 #define OPV_PUT_PROP 0x23 @@ -438,11 +441,11 @@ static uint16_t get_var(uint8_t v){ return stack; } if(v<16) { - cpm_printstring("local "); - printi(v); - cpm_printstring(": "); - print_hex(frames[fp-1].locals[v-1]); - crlf(); + //cpm_printstring("local "); + //printi(v); + //cpm_printstring(": "); + //print_hex(frames[fp-1].locals[v-1]); + //crlf(); return frames[fp-1].locals[v-1]; } //uint16_t a=zm_read16(0x0C)+2*(v-16); @@ -472,11 +475,11 @@ static void set_var(uint8_t v,uint16_t val){ //crlf(); } else if(v<16) { - cpm_printstring("Setvar local "); - printi(v); - spc(); - print_hex(val); - crlf(); + //cpm_printstring("Setvar local "); + //printi(v); + //spc(); + //print_hex(val); + //crlf(); frames[fp-1].locals[v-1]=val; } else{ @@ -745,7 +748,7 @@ uint16_t dict_lookup(const char *word) //cpm_printstring("Starting search at address "); //print_hex(e); - crlf(); + //crlf(); for (uint16_t i = 0; i < dict_entry_count; i++) { //uint16_t e = dict + i * entry_len; e += dict_entry_len; @@ -765,9 +768,9 @@ uint16_t dict_lookup(const char *word) // Tokenization static uint8_t is_sep(char c){ - cpm_printstring("is_sep: "); - cpm_conout(c); - crlf(); + //cpm_printstring("is_sep: "); + //cpm_conout(c); + //crlf(); for(uint8_t i=0;i>8); - spc(); - print_hex(dict & 0xff); - spc(); - print_hex(len); - spc(); - print_hex(start+1); + //crlf(); + //cpm_printstring("Writing entry to parse_buf - "); + //print_hex(dict>>8); + //spc(); + //print_hex(dict & 0xff); + //spc(); + //print_hex(len); + //spc(); + //print_hex(start+1); zm_write8(entry, dict>>8); zm_write8(entry+1, dict & 0xff); zm_write8(entry+2, len); @@ -821,10 +824,10 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) uint8_t x; crlf(); - for(x=0; x<(count<<2)+2; x++) { - print_hex(zm_read8(parse_buf+x)); - crlf(); - } + //for(x=0; x<(count<<2)+2; x++) { + // print_hex(zm_read8(parse_buf+x)); + // crlf(); + //} return count; } @@ -1022,11 +1025,11 @@ static uint16_t rng_next(void) static void step(void){ uint8_t op=zm_read8(pc++); - cpm_printstring("OP: "); - print_hex(op); - cpm_printstring(" PC: "); - print_hex_32(pc); - crlf(); + //cpm_printstring("OP: "); + //print_hex(op); + //cpm_printstring(" PC: "); + //print_hex_32(pc); + //crlf(); /* -------- 2OP -------- */ if(op<0x80){ uint8_t t1=(op&0x40)?OP_VAR:OP_SMALL; @@ -1064,8 +1067,8 @@ static void step(void){ break; } case OP2_DEC_CHK: - cpm_printstring("DEC_CHK"); - crlf(); + //cpm_printstring("DEC_CHK"); + //crlf(); operands[0]--; set_var(var_num,operands[0]); branch((int16_t)operands[0]<(int16_t)operands[1]); @@ -1078,8 +1081,11 @@ static void step(void){ //cpm_printstring(" Var: "); //print_hex(var_num); //crlf(); - cpm_printstring("INC_CHK"); - crlf(); + //cpm_printstring("INC_CHK op1: "); + //print_hex(operands[0]); + //cpm_printstring("Var num: "); + //print_hex(var_num); + //crlf(); operands[0]++; set_var(var_num,operands[0]); branch((int16_t)operands[0]>(int16_t)operands[1]); @@ -1144,11 +1150,11 @@ static void step(void){ } case OP2_GET_NEXT_PROP: { - cpm_printstring("GET_NEXT_PROP - op1: "); - print_hex(operands[0]); - cpm_printstring(" op2: "); - print_hex(operands[1]); - crlf(); + //cpm_printstring("GET_NEXT_PROP - op1: "); + //print_hex(operands[0]); + //cpm_printstring(" op2: "); + //print_hex(operands[1]); + //crlf(); uint8_t obj = (uint8_t)operands[0]; uint8_t prop = (uint8_t)operands[1]; uint16_t addr; @@ -1313,7 +1319,7 @@ static void step(void){ // z_ret(operands[0]); // break; case OP1_JZ: - cpm_printstring("JZ - arg "); + //cpm_printstring("JZ - arg "); print_hex(operands[0]); branch(operands[0]==0); break; @@ -1384,6 +1390,11 @@ static void step(void){ case OP0_QUIT: cpm_warmboot(); + break; + case OP0_VERIFY: + // Not supported + pc++; + break; default: crlf(); printi(op); @@ -1490,7 +1501,9 @@ static void step(void){ case OPV_JG: branch((int16_t)operands[0] > (int16_t)operands[1]); break; - + case OPV_TEST: + branch((operands[0] & operands[1]) == operands[1]); + break; case OPV_STOREW: //cpm_printstring("STOREW: "); //printi(operands[0]); From d60f4c35a0da3692e358a1819e75b9a94fb11967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Fri, 9 Jan 2026 11:18:33 +0100 Subject: [PATCH 13/36] Now passes all czech-tests! Needs massive cleanup --- third_party/z65/z65.c | 318 +++++++++++++++++++++++++++--------------- 1 file changed, 205 insertions(+), 113 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 609da8cc..015ee3c9 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -153,8 +153,8 @@ #define DYNAMIC_MEM_MAX 16384 #define STACK_SIZE 256 -#define MAX_FRAMES 16 -#define MAX_LOCALS 8 +#define MAX_FRAMES 8 +#define MAX_LOCALS 16 #define MAX_OPERANDS 8 #define INPUT_MAX 80 @@ -409,43 +409,65 @@ static void zm_write8(uint32_t a,uint8_t v){ */ static void push(int16_t v){ - /*crlf(); + crlf(); cpm_printstring("Stack push - "); print_hex(v); - crlf();*/ stack[sp++]=v; + cpm_printstring(" SP: "); + print_hex(sp); + crlf(); + cpm_printstring("Stack ["); + for(uint8_t i=0; i 0) ? stack[sp - 1] : 0; + else + val = pop(); //crlf(); //cpm_printstring("stack pop: "); //print_hex(stack); //cpm_printstring(" SP: "); //print_hex(sp); //crlf(); - return stack; + return val; } if(v<16) { - //cpm_printstring("local "); - //printi(v); - //cpm_printstring(": "); - //print_hex(frames[fp-1].locals[v-1]); - //crlf(); + cpm_printstring("local "); + printi(v); + cpm_printstring(": "); + print_hex(frames[fp-1].locals[v-1]); + cpm_printstring(" fp: "); + printi(fp-1); + crlf(); return frames[fp-1].locals[v-1]; } //uint16_t a=zm_read16(0x0C)+2*(v-16); @@ -460,14 +482,22 @@ static uint16_t get_var(uint8_t v){ return ret_data; } -static void set_var(uint8_t v,uint16_t val){ +static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { // cpm_printstring("Setvar - var: "); // print_hex(v); // cpm_printstring(" val: "); // print_hex(val); // crlf(); if(v==0) { - push(val); + if(indirect) { + if(sp > 0) stack[sp - 1] = val; + else push(val); + } else { + push(val); + } + + //push(val); + //cpm_printstring("stack push: "); //print_hex(val); //cpm_printstring(" SP: "); @@ -475,11 +505,13 @@ static void set_var(uint8_t v,uint16_t val){ //crlf(); } else if(v<16) { - //cpm_printstring("Setvar local "); - //printi(v); - //spc(); - //print_hex(val); - //crlf(); + cpm_printstring("Setvar local "); + printi(v); + spc(); + print_hex(val); + cpm_printstring(" fp: "); + printi(fp-1); + crlf(); frames[fp-1].locals[v-1]=val; } else{ @@ -506,28 +538,32 @@ enum{OP_LARGE,OP_SMALL,OP_VAR,OP_OMIT}; static uint16_t operands[MAX_OPERANDS]; static uint8_t operand_count; -static uint16_t read_operand(uint8_t t){ +static uint16_t read_operand(uint8_t t, uint8_t indirect){ uint16_t value=0; if(t==OP_LARGE){pc+=2;value = zm_read16(pc-2);} if(t==OP_SMALL)value = zm_read8(pc++); - if(t==OP_VAR) value = get_var(zm_read8(pc++)); - /*cpm_printstring(" type: "); + if(t==OP_VAR) { + uint8_t var_num = zm_read8(pc++); + if(indirect) value = var_num; + else value = get_var(var_num, 0); + } + cpm_printstring(" type: "); print_hex(t); cpm_printstring(" value: "); print_hex(value); - crlf();*/ + crlf(); return value; } -static void decode_operands(uint8_t spec){ +static void decode_operands(uint8_t spec, uint8_t indirect){ operand_count=0; for(int s=6;s>=0;s-=2){ uint8_t t=(spec>>s)&3; if(t==OP_OMIT) break; /*cpm_printstring("Operand "); printi(operand_count);*/ - operands[operand_count++]=read_operand(t); + operands[operand_count++]=read_operand(t, indirect); } } @@ -980,22 +1016,24 @@ static void obj_put_prop(uint8_t obj, uint8_t prop, uint16_t val){ */ static void z_ret(uint16_t v){ - CallFrame *f=&frames[fp-1]; - fp--; + CallFrame *f=&frames[--fp]; pc=f->return_pc; sp=f->saved_sp; /*if(f->store_var != 0)*/ - set_var(f->store_var,v); + if(f->store_var==0) { + push(v); + } + else set_var(f->store_var,v, 0); } -static void store_result(uint16_t v){ +static void store_result(uint16_t v, uint8_t indirect){ uint8_t var=zm_read8(pc++); //cpm_printstring("Store "); //printi(v); //cpm_printstring(" in variable "); //printi(var); //crlf(); - set_var(var,v); + set_var(var, v, indirect); } static void restart(void) @@ -1025,19 +1063,26 @@ static uint16_t rng_next(void) static void step(void){ uint8_t op=zm_read8(pc++); - //cpm_printstring("OP: "); - //print_hex(op); - //cpm_printstring(" PC: "); - //print_hex_32(pc); - //crlf(); + + cpm_printstring("OP: "); + print_hex(op); + cpm_printstring(" PC: "); + print_hex_32(pc); + crlf(); + /* -------- 2OP -------- */ if(op<0x80){ uint8_t t1=(op&0x40)?OP_VAR:OP_SMALL; uint8_t t2=(op&0x20)?OP_VAR:OP_SMALL; - if(op == 0x05 || op ==0x04) t1=OP_VAR; + uint8_t oc = op & 0x1f; + if(oc == OP2_INC_CHK || oc == OP2_DEC_CHK) t1=OP_VAR; uint8_t var_num = zm_read8(pc); - operands[0]=read_operand(t1); - operands[1]=read_operand(t2); + uint8_t indirect = ((oc == OP2_INC_CHK && t1 == OP_VAR)|| + (oc == OP2_DEC_CHK && t1 == OP_VAR)); + uint8_t d_indirect = !(op == 0x45 || op == 0x65 || + op == 0x44 || op == 0x64); + operands[0]=read_operand(t1, indirect & d_indirect); + operands[1]=read_operand(t2, 0); /* cpm_printstring("2OP - "); print_hex(operands[0]); @@ -1045,7 +1090,7 @@ static void step(void){ print_hex(operands[1]); crlf(); */ - switch(op&0x1F){ + switch(oc){ case OP2_JE: //cpm_printstring("JE "); //printi(operands[0]); @@ -1066,62 +1111,85 @@ static void step(void){ branch(parent == operands[1]); break; } - case OP2_DEC_CHK: + case OP2_DEC_CHK: { //cpm_printstring("DEC_CHK"); //crlf(); - operands[0]--; - set_var(var_num,operands[0]); - branch((int16_t)operands[0]<(int16_t)operands[1]); + + //operands[0]--; + //set_var(var_num,operands[0]); + //branch((int16_t)operands[0]<(int16_t)operands[1]); + int16_t value = (int16_t)get_var(operands[0],1); + value--; + set_var(operands[0],(uint16_t)value,1); + branch(value>(int16_t)operands[1]); break; - case OP2_INC_CHK: - //cpm_printstring("OP2_INC_CHK entry - OP1: "); - //print_hex(operands[0]); - //cpm_printstring(" OP2: "); - //print_hex(operands[1]); - //cpm_printstring(" Var: "); - //print_hex(var_num); - //crlf(); + } + case OP2_INC_CHK: { + /*cpm_printstring("OP2_INC_CHK entry - OP1: "); + print_hex(operands[0]); + cpm_printstring(" OP2: "); + print_hex(operands[1]); + cpm_printstring(" Var: "); + print_hex(var_num); + crlf(); */ //cpm_printstring("INC_CHK op1: "); //print_hex(operands[0]); //cpm_printstring("Var num: "); //print_hex(var_num); //crlf(); - operands[0]++; - set_var(var_num,operands[0]); - branch((int16_t)operands[0]>(int16_t)operands[1]); + //uint8_t v_idx = zm_read8(pc - 2); + //int16_t val = (int16_t)get_var(v_idx, indirect) + 1; + ///set_var(v_idx, (uint16_t)val, indirect); + //branch(val > (int16_t)operands[1]); + //operands[0]++; + int16_t value = (int16_t)get_var(operands[0],1); + value++; + set_var(operands[0],(uint16_t)value,1); + branch(value>(int16_t)operands[1]); break; + } case OP2_TEST: branch((operands[0]&operands[1])==operands[1]); break; case OP2_OR: - store_result(operands[0]|operands[1]); + store_result(operands[0]|operands[1],indirect); break; case OP2_AND: - store_result(operands[0]&operands[1]); + store_result(operands[0]&operands[1],indirect); break; - case OP2_STORE: - set_var(operands[0],operands[1]); + case OP2_STORE: + cpm_printstring("OP2_STORE - op1: "); + print_hex(operands[0]); + cpm_printstring(" op2: "); + print_hex(operands[1]); + crlf(); + set_var(operands[0],operands[1], 1); break; case OP2_LOADW: - store_result(zm_read16(operands[0]+2*operands[1])); + store_result(zm_read16(operands[0]+2*operands[1]), indirect); break; case OP2_LOADB: - store_result(zm_read8(operands[0]+operands[1])); + store_result(zm_read8(operands[0]+operands[1]), indirect); break; case OP2_ADD: - store_result((int16_t)operands[0]+(int16_t)operands[1]); + store_result((int16_t)operands[0]+(int16_t)operands[1], + indirect); break; case OP2_SUB: - store_result((int16_t)operands[0]-(int16_t)operands[1]); + store_result((int16_t)operands[0]-(int16_t)operands[1], + indirect); break; case OP2_MUL: - store_result((int16_t)operands[0]*(int16_t)operands[1]); + store_result((int16_t)operands[0]*(int16_t)operands[1], + indirect); break; case OP2_DIV: - store_result((int16_t)operands[0]/(int16_t)operands[1]); + store_result((int16_t)operands[0]/(int16_t)operands[1], + indirect); break; case OP2_MOD: - store_result((int16_t)operands[0]%(int16_t)operands[1]); + store_result((int16_t)operands[0]%(int16_t)operands[1], + indirect); break; case OP2_TEST_ATTR: branch(obj_test_attr(operands[0], operands[1])); @@ -1140,12 +1208,12 @@ static void step(void){ break; case OP2_GET_PROP: - store_result(obj_get_prop(operands[0], operands[1])); + store_result(obj_get_prop(operands[0], operands[1]), indirect); break; case OP2_GET_PROP_ADDR: { uint16_t p = obj_find_prop(operands[0], operands[1]); - store_result(p); + store_result(p, indirect); break; } @@ -1164,7 +1232,7 @@ static void step(void){ } else { addr = obj_find_prop(obj, prop); if(!addr) { - store_result(0); + store_result(0, indirect); break; } addr+=obj_get_prop_len(addr); @@ -1172,8 +1240,8 @@ static void step(void){ uint8_t next_header = zm_read8(addr); - if(next_header == 0) store_result(0); - else store_result(next_header & 0x1F); + if(next_header == 0) store_result(0, indirect); + else store_result(next_header & 0x1F, indirect); /*uint16_t p = obj_find_prop(operands[0], operands[1]); if (!p) { @@ -1200,7 +1268,8 @@ static void step(void){ if(op<0xB0){ uint8_t type=(op>>4)&3; uint8_t oc=op&0x0F; - if(type!=OP_OMIT) operands[0]=read_operand(type); + uint8_t indirect = (oc == OP1_LOAD); + if(type!=OP_OMIT) operands[0]=read_operand(type, indirect); //cpm_printstring("Type: "); //printi(type); //cpm_printstring(" Operand 1: "); @@ -1250,7 +1319,7 @@ static void step(void){ uint8_t result; if(operands[0]==0) result = 0; else result = obj_child(operands[0]); - store_result(result); + store_result(result, indirect); //cpm_printstring(" CHILD: "); //print_hex(result); //crlf(); @@ -1264,7 +1333,7 @@ static void step(void){ uint8_t result; if(operands[0]==0) result = 0; else result = obj_sibling(operands[0]); - store_result(result); + store_result(result, indirect); //cpm_printstring(" SIBLING "); //print_hex(result); branch(result!=0); @@ -1276,43 +1345,40 @@ static void step(void){ uint8_t result; if(operands[0]==0) result = 0; else result = obj_parent(operands[0]); - store_result(result); + store_result(result, indirect); break; } case OP1_GET_PROP_LEN: { uint8_t result; if(operands[0]==0) result = 0; else result = obj_get_prop_len(operands[0]); - store_result(result); + store_result(result, indirect); break; } case OP1_LOAD: { uint8_t result; - result = get_var(operands[0]); - store_result(result); + result = get_var(operands[0], indirect); + store_result(result, 0); } case OP1_NOT: { uint8_t result; result = ~operands[0]; - store_result(result); + store_result(result, indirect); } case OP1_RET: //case OP1_VALUE: z_ret(operands[0]); break; case OP1_INC: { - //cpm_printstring("OP1_INC - operand: "); - //print_hex(operands[0]); - //crlf(); - uint8_t value = get_var(operands[0]); + uint8_t value = get_var(operands[0], indirect); value++; - set_var(operands[0], value); + set_var(operands[0], value, indirect); break; } case OP1_DEC: { - uint8_t value = get_var(operands[0]); + uint8_t value = get_var(operands[0], indirect); value--; - set_var(operands[0], value); + set_var(operands[0], value, indirect); break; } //case OP1_RET: @@ -1320,7 +1386,7 @@ static void step(void){ // break; case OP1_JZ: //cpm_printstring("JZ - arg "); - print_hex(operands[0]); + //print_hex(operands[0]); branch(operands[0]==0); break; case OP1_PRINT_PADDR: { @@ -1392,8 +1458,8 @@ static void step(void){ cpm_warmboot(); break; case OP0_VERIFY: - // Not supported - pc++; + // Not supported, just assume it's OK + branch(1); break; default: crlf(); @@ -1403,10 +1469,14 @@ static void step(void){ return; } /* -------- VAR -------- */ - decode_operands(zm_read8(pc++)); uint8_t var_opcode = op & 0x1f; + uint8_t indirect = (var_opcode == OPV_PULL); + + decode_operands(zm_read8(pc++), indirect); if((op & 0xE0)==0xE0) var_opcode += 0x20; if((op & 0xD0)==0xD0) var_opcode += 0x40; + //if(var_opcode != OPV_PULL) + // decode_operands(zm_read8(pc++)); //cpm_printstring("Var opcode: "); //print_hex(var_opcode); //crlf(); @@ -1439,7 +1509,7 @@ static void step(void){ case OPV_CALL: { if (operands[0] == 0) { uint8_t sv = zm_read8(pc++); - set_var(sv, 0); + set_var(sv, 0, indirect); return; } @@ -1451,11 +1521,11 @@ static void step(void){ f->saved_sp = sp; uint32_t addr = (uint32_t)operands[0]<<1; - /*cpm_printstring("CALL to address "); + cpm_printstring("CALL to address "); print_hex_32(addr); spc(); print_hex(operands[0]); - crlf()*/; + crlf(); f->num_locals = zm_read8(addr++); for (uint8_t i = 0; i < f->num_locals; i++) { @@ -1472,19 +1542,19 @@ static void step(void){ for (uint8_t i = 0; i < argc; i++){ //f->locals[i] = operands[i + 1]; f->locals[i] = operands[i + 1]; - //cpm_printstring("locals "); - //printi(i); - //spc(); - //print_hex(f->locals[i]); - //crlf(); + cpm_printstring("locals "); + printi(i); + spc(); + print_hex(f->locals[i]); + crlf(); } pc = addr; // + 2 * f->num_locals; break; } case OPV_JE: - cpm_printstring("JE VAR - operand count: "); - print_hex(operand_count); + //cpm_printstring("JE VAR - operand count: "); + //print_hex(operand_count); if(operand_count == 2) branch(operands[0] == operands[1]); else if(operand_count == 3) @@ -1521,7 +1591,7 @@ static void step(void){ break; case OPV_STORE: - set_var(operands[0],operands[1]); + set_var(operands[0],operands[1], 0); break; case OPV_PRINT_CHAR: @@ -1536,9 +1606,31 @@ static void step(void){ push(operands[0]); break; - case OPV_PULL: - set_var(operands[0],pop()); + case OPV_PULL: { + cpm_printstring("OPV_PULL "); + print_hex(operands[0]); + crlf(); + + //if(operands[0] != 0) set_var(operands[0],pop()); + //else pop(); + //pc++; + //uint8_t dest_var = zm_read8(pc++); + + //cpm_printstring(" dest_var: "); + //print_hex(dest_var); + + uint16_t value = pop(); + + + //cpm_printstring(" value: "); + //print_hex(value); + //crlf(); + + //if(operands[1] != 0) + set_var(operands[0], value, 1); + break; + } case OPV_SREAD: { uint16_t text = operands[0]; uint16_t parse = operands[1]; @@ -1567,10 +1659,10 @@ static void step(void){ operands[2]); break; case OPV_OR: - store_result(operands[0] | operands[1]); + store_result(operands[0] | operands[1], indirect); break; case OPV_AND: - store_result(operands[0] & operands[1]); + store_result(operands[0] & operands[1], indirect); break; case OPV_RANDOM: { crlf(); @@ -1580,28 +1672,28 @@ static void step(void){ int16_t range = (int16_t)operands[0]; if(range == 0) { rng_state = (uint16_t)pc; - store_result(0); + store_result(0, indirect); break; } if(range < 0) { rng_state = (uint16_t)(-range); - store_result(0); + store_result(0, indirect); break; } uint16_t r = rng_next(); uint16_t result = (r % range) + 1; - store_result(result); + store_result(result, indirect); break; } case OPV_LOADW: - store_result(zm_read16(operands[0]+2*operands[1])); + store_result(zm_read16(operands[0]+2*operands[1]), indirect); break; case OPV_LOADB: - store_result(zm_read8(operands[0]+operands[1])); + store_result(zm_read8(operands[0]+operands[1]), indirect); break; case OPV_MUL: - store_result((int16_t)operands[0]*(int16_t)operands[1]); + store_result((int16_t)operands[0]*(int16_t)operands[1], indirect); break; default: crlf(); From 1fe61a4efc90911e9e9f1ab69a28e73f7e5c628e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Fri, 9 Jan 2026 12:09:41 +0100 Subject: [PATCH 14/36] Some cleanup --- third_party/z65/z65.c | 413 ++---------------------------------------- 1 file changed, 20 insertions(+), 393 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 015ee3c9..f71ce75c 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -3,7 +3,6 @@ */ #include -//#include #include #include "lib/printi.h" /* ============================================================ @@ -37,30 +36,6 @@ #define OP2_GET_PROP_ADDR 0x12 #define OP2_GET_NEXT_PROP 0x13 -/* 1OP */ -/*#define OP1_RTRUE 0x00 -#define OP1_RFALSE 0x01 -#define OP1_PRINT 0x02 -#define OP1_JUMP 0x03 -#define OP1_PRINT_ADDR 0x04 -#define OP1_VALUE 0x05 -#define OP1_INC 0x06 -#define OP1_DEC 0x07 -#define OP1_PRINT_PADDR 0x08 -#define OP1_REMOVE_OBJ 0x09 -#define OP1_PRINT_OBJ 0x0A -#define OP1_RET 0x0B -#define OP1_JZ 0x0C -#define OP1_JZ 0x00 -#define OP1_INC 0x05 -#define OP1_DEC 0x06 -#define OP1_PRINT_ADDR 0x07 -#define OP1_PRINT_PADDR 0x0D -#define OP1_REMOVE_OBJ 0x09 -#define OP1_PRINT_OBJ 0x0A -#define OP1_JUMP 0x0C -#define OP1_RET 0x0B*/ - /* 1OP opcodes (v1–v3) */ #define OP1_JZ 0x00 #define OP1_GET_SIBLING 0x01 @@ -120,29 +95,6 @@ #define OPV_MUL 0x56 -/* ============================================================ - * BDOS - * ============================================================ - */ - -//extern uint8_t bdos(uint8_t fn, void *arg); - -//#define BDOS_OPEN_R 15 -//bin#define BDOS_READ_SEQ 20 -//#define BDOS_READ_RAND 33 -//#define BDOS_CONOUT 2 - -/*typedef struct { - uint8_t drive; - char name[8]; - char ext[3]; - uint8_t ex,s1,s2,rc; - uint8_t d[16]; - uint8_t cr; - uint8_t r0,r1,r2; -} FCB; -*/ - /* ============================================================ * Configuration * ============================================================ @@ -160,6 +112,8 @@ #define INPUT_MAX 80 #define MAX_TOKENS 16 +//#define DEBUG + /* ============================================================ * Structures * ============================================================ @@ -184,8 +138,6 @@ typedef struct { * ============================================================ */ -//static FCB story_fcb; - static uint8_t dynamic_mem[DYNAMIC_MEM_MAX]; static uint16_t dynamic_size; @@ -241,7 +193,6 @@ static void z_ret(uint16_t v); */ static inline void putc(char c){ - //bdos(BDOS_CONOUT,(void *)(uintptr_t)c); cpm_conout(c); } @@ -299,6 +250,14 @@ static uint8_t read_line(char *buf){ if(c=='\r'||c=='\n'){ crlf(); buf[len]=0; + /*cpm_printstring("Read line: "); + crlf(); + for(uint8_t i=0; i<=len; i++) { + print_hex(buf[i]); + crlf(); + } + cpm_printstring("---END---"); + crlf();*/ return len; } if(c==8 && len){ @@ -320,24 +279,13 @@ static uint8_t read_line(char *buf){ static void load_page(Page *p,uint16_t page){ uint16_t record=page<<2; - //cpm_printstring("Load page from record "); - //printi(record); - //crlf(); cpm_fcb.r = record; - //story_fcb.r0=record&0xFF; - //story_fcb.r1=record>>8; - //story_fcb.r2=0; - //cmp_set_dma(dma); - //crlf(); for(uint8_t i=0;i<4;i++){ - //bdos(BDOS_READ_RAND,&story_fcb); cpm_set_dma(&dma); cpm_read_random(&cpm_fcb); for(uint8_t j=0;j<128;j++) { p->data[(i<<7)+j]=dma[j]; } - //crlf(); - //crlf(); record++; cpm_fcb.r = record; } @@ -346,10 +294,6 @@ static void load_page(Page *p,uint16_t page){ } static Page *get_page(uint16_t page){ - //cpm_printstring("Page "); - //printi(page); - //cpm_printstring(" requested"); - //crlf(); for(uint8_t i=0;i>9); - //printi(p->data[a&0x1FF]); - //crlf(); - //cpm_printstring("Read "); - //print_hex(p->data[a&0x1FF]); - //cpm_printstring(" from address "); - //print_hex(a); - //crlf(); return p->data[a&0x1FF]; } @@ -409,86 +337,33 @@ static void zm_write8(uint32_t a,uint8_t v){ */ static void push(int16_t v){ - crlf(); - cpm_printstring("Stack push - "); - print_hex(v); stack[sp++]=v; - cpm_printstring(" SP: "); - print_hex(sp); - crlf(); - cpm_printstring("Stack ["); - for(uint8_t i=0; i 0) ? stack[sp - 1] : 0; else val = pop(); - //crlf(); - //cpm_printstring("stack pop: "); - //print_hex(stack); - //cpm_printstring(" SP: "); - //print_hex(sp); - //crlf(); return val; } if(v<16) { - cpm_printstring("local "); - printi(v); - cpm_printstring(": "); - print_hex(frames[fp-1].locals[v-1]); - cpm_printstring(" fp: "); - printi(fp-1); - crlf(); return frames[fp-1].locals[v-1]; } - //uint16_t a=zm_read16(0x0C)+2*(v-16); uint16_t a = (hdr[0x0c]<<8) + hdr[0x0d] + 2*(v-16); - //cpm_printstring("get_var - a:"); - //print_hex(a); - //crlf(); uint16_t ret_data = zm_read16(a); - //cpm_printstring("global: "); - //print_hex(ret_data); - //crlf(); return ret_data; } static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { -// cpm_printstring("Setvar - var: "); -// print_hex(v); -// cpm_printstring(" val: "); -// print_hex(val); -// crlf(); - if(v==0) { + if(v==0) { if(indirect) { if(sp > 0) stack[sp - 1] = val; else push(val); @@ -496,33 +371,12 @@ static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { push(val); } - //push(val); - - //cpm_printstring("stack push: "); - //print_hex(val); - //cpm_printstring(" SP: "); - //print_hex(sp); - //crlf(); - } + } else if(v<16) { - cpm_printstring("Setvar local "); - printi(v); - spc(); - print_hex(val); - cpm_printstring(" fp: "); - printi(fp-1); - crlf(); - frames[fp-1].locals[v-1]=val; + frames[fp-1].locals[v-1]=val; } else{ - //uint16_t a=zm_read16(0x0C)+2*(v-16); uint16_t a = (hdr[0x0c]<<8) + hdr[0x0d] + 2*(v-16); - //cpm_printstring("Setvar "); - //printi(a); - //spc(); - //printi(val); - //spc(); - //printi(v); zm_write8(a,val>>8); zm_write8(a+1,val&0xFF); } @@ -547,12 +401,7 @@ static uint16_t read_operand(uint8_t t, uint8_t indirect){ if(indirect) value = var_num; else value = get_var(var_num, 0); } - cpm_printstring(" type: "); - print_hex(t); - cpm_printstring(" value: "); - print_hex(value); - crlf(); - return value; + return value; } @@ -561,8 +410,6 @@ static void decode_operands(uint8_t spec, uint8_t indirect){ for(int s=6;s>=0;s-=2){ uint8_t t=(spec>>s)&3; if(t==OP_OMIT) break; - /*cpm_printstring("Operand "); - printi(operand_count);*/ operands[operand_count++]=read_operand(t, indirect); } } @@ -575,7 +422,6 @@ static void decode_operands(uint8_t spec, uint8_t indirect){ static void branch(uint8_t cond){ uint8_t b=zm_read8(pc++); - //uint8_t sense=b&0x80; int16_t off; if(b&0x40) off=b&0x3F; @@ -594,27 +440,11 @@ static void branch(uint8_t cond){ if(!cond) take_branch = 1; } - /*cpm_printstring("Branch cond: "); - print_hex(cond); - cpm_printstring(" sense: "); - print_hex(b & 0x80); - cpm_printstring(" take_branch: "); - print_hex(take_branch); - cpm_printstring(" offset: "); - print_hex(off); - crlf(); - */ if(take_branch) { if(off==0) { - //push(0); - //pc=frames[--fp].return_pc; - //sp=frames[--fp].saved_sp; z_ret(0); } else if(off==1) { - //push(1); - //pc=frames[--fp].return_pc; - //sp=frames[--fp].saved_sp; z_ret(1); } else pc+=off-2; @@ -851,7 +681,7 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) zm_write8(entry, dict>>8); zm_write8(entry+1, dict & 0xff); zm_write8(entry+2, len); - zm_write8(entry+3, start+2);//1); + zm_write8(entry+3, start+1);//1); count++; } @@ -981,19 +811,8 @@ static uint8_t obj_get_prop_len(uint16_t addr){ } static void obj_put_prop(uint8_t obj, uint8_t prop, uint16_t val){ - /*cpm_printstring("obj_put_prop - obj: "); - print_hex(obj); - cpm_printstring(" prop: "); - print_hex(prop); - cpm_printstring(" val: "); - print_hex(val); - */ uint16_t p = obj_find_prop(obj, prop); - //cpm_printstring(" p: "); - //print_hex(p); - //crlf(); - if (!p) { // property must exist return; @@ -1019,7 +838,6 @@ static void z_ret(uint16_t v){ CallFrame *f=&frames[--fp]; pc=f->return_pc; sp=f->saved_sp; - /*if(f->store_var != 0)*/ if(f->store_var==0) { push(v); } @@ -1028,11 +846,6 @@ static void z_ret(uint16_t v){ static void store_result(uint16_t v, uint8_t indirect){ uint8_t var=zm_read8(pc++); - //cpm_printstring("Store "); - //printi(v); - //cpm_printstring(" in variable "); - //printi(var); - //crlf(); set_var(var, v, indirect); } @@ -1042,12 +855,6 @@ static void restart(void) sp = fp = 0; } -static inline uint32_t unpack_routine(uint16_t p) -{ - // v1-v3 - only version supported for now - return p << 1; -} - static uint16_t rng_next(void) { uint16_t x = rng_state; @@ -1064,11 +871,13 @@ static uint16_t rng_next(void) static void step(void){ uint8_t op=zm_read8(pc++); +#ifdef DEBUG cpm_printstring("OP: "); print_hex(op); cpm_printstring(" PC: "); print_hex_32(pc); crlf(); +#endif /* -------- 2OP -------- */ if(op<0x80){ @@ -1083,20 +892,8 @@ static void step(void){ op == 0x44 || op == 0x64); operands[0]=read_operand(t1, indirect & d_indirect); operands[1]=read_operand(t2, 0); - /* - cpm_printstring("2OP - "); - print_hex(operands[0]); - spc(); - print_hex(operands[1]); - crlf(); - */ switch(oc){ case OP2_JE: - //cpm_printstring("JE "); - //printi(operands[0]); - //spc(); - //printi(operands[1]); - //crlf(); branch(operands[0]==operands[1]); break; case OP2_JL: @@ -1112,12 +909,6 @@ static void step(void){ break; } case OP2_DEC_CHK: { - //cpm_printstring("DEC_CHK"); - //crlf(); - - //operands[0]--; - //set_var(var_num,operands[0]); - //branch((int16_t)operands[0]<(int16_t)operands[1]); int16_t value = (int16_t)get_var(operands[0],1); value--; set_var(operands[0],(uint16_t)value,1); @@ -1125,23 +916,6 @@ static void step(void){ break; } case OP2_INC_CHK: { - /*cpm_printstring("OP2_INC_CHK entry - OP1: "); - print_hex(operands[0]); - cpm_printstring(" OP2: "); - print_hex(operands[1]); - cpm_printstring(" Var: "); - print_hex(var_num); - crlf(); */ - //cpm_printstring("INC_CHK op1: "); - //print_hex(operands[0]); - //cpm_printstring("Var num: "); - //print_hex(var_num); - //crlf(); - //uint8_t v_idx = zm_read8(pc - 2); - //int16_t val = (int16_t)get_var(v_idx, indirect) + 1; - ///set_var(v_idx, (uint16_t)val, indirect); - //branch(val > (int16_t)operands[1]); - //operands[0]++; int16_t value = (int16_t)get_var(operands[0],1); value++; set_var(operands[0],(uint16_t)value,1); @@ -1158,11 +932,6 @@ static void step(void){ store_result(operands[0]&operands[1],indirect); break; case OP2_STORE: - cpm_printstring("OP2_STORE - op1: "); - print_hex(operands[0]); - cpm_printstring(" op2: "); - print_hex(operands[1]); - crlf(); set_var(operands[0],operands[1], 1); break; case OP2_LOADW: @@ -1218,11 +987,6 @@ static void step(void){ } case OP2_GET_NEXT_PROP: { - //cpm_printstring("GET_NEXT_PROP - op1: "); - //print_hex(operands[0]); - //cpm_printstring(" op2: "); - //print_hex(operands[1]); - //crlf(); uint8_t obj = (uint8_t)operands[0]; uint8_t prop = (uint8_t)operands[1]; uint16_t addr; @@ -1243,13 +1007,6 @@ static void step(void){ if(next_header == 0) store_result(0, indirect); else store_result(next_header & 0x1F, indirect); - /*uint16_t p = obj_find_prop(operands[0], operands[1]); - if (!p) { - store_result(0); - } else { - uint8_t h = zm_read8(p - 1); - store_result(h & 0x1F); - }*/ break; } @@ -1270,29 +1027,8 @@ static void step(void){ uint8_t oc=op&0x0F; uint8_t indirect = (oc == OP1_LOAD); if(type!=OP_OMIT) operands[0]=read_operand(type, indirect); - //cpm_printstring("Type: "); - //printi(type); - //cpm_printstring(" Operand 1: "); - //printi(operands[0]); - //cpm_printstring(" oc: "); - //print_hex(oc); - //crlf(); switch(oc){ - /*case OP1_RTRUE: - z_ret(1); - break; - case OP1_RFALSE: - z_ret(0); - break;*/ - /*case OP1_PRINT: - print_zstring(pc); - while(!(zm_read16(pc)&0x8000)) pc+=2; - pc+=2; - break;*/ case OP1_JUMP: - //cpm_printstring("Performing jump with offset"); - //printi(operands[0]-2); - //crlf(); pc+=(int16_t)operands[0]-2; break; case OP1_PRINT_ADDR: @@ -1314,28 +1050,18 @@ static void step(void){ obj_remove(operands[0]); break; case OP1_GET_CHILD: { - //cpm_printstring("GET_CHILD for object "); - //print_hex(operands[0]); uint8_t result; if(operands[0]==0) result = 0; else result = obj_child(operands[0]); store_result(result, indirect); - //cpm_printstring(" CHILD: "); - //print_hex(result); - //crlf(); branch(result!=0); break; } case OP1_GET_SIBLING: { - //cpm_printstring("GET_SIBLING for object "); - //print_hex(operands[0]); - uint8_t result; if(operands[0]==0) result = 0; else result = obj_sibling(operands[0]); store_result(result, indirect); - //cpm_printstring(" SIBLING "); - //print_hex(result); branch(result!=0); break; } @@ -1366,7 +1092,6 @@ static void step(void){ store_result(result, indirect); } case OP1_RET: - //case OP1_VALUE: z_ret(operands[0]); break; case OP1_INC: { @@ -1381,21 +1106,11 @@ static void step(void){ set_var(operands[0], value, indirect); break; } - //case OP1_RET: - // z_ret(operands[0]); - // break; case OP1_JZ: - //cpm_printstring("JZ - arg "); - //print_hex(operands[0]); branch(operands[0]==0); break; case OP1_PRINT_PADDR: { uint32_t addr = (uint32_t)operands[0] << 1; - //print_hex_32(addr); - //crlf(); - //cpm_printstring("OP1 PRINT_PADDR - "); - //print_hex(addr); - //crlf(); print_zstring(addr); break; } @@ -1475,36 +1190,7 @@ static void step(void){ decode_operands(zm_read8(pc++), indirect); if((op & 0xE0)==0xE0) var_opcode += 0x20; if((op & 0xD0)==0xD0) var_opcode += 0x40; - //if(var_opcode != OPV_PULL) - // decode_operands(zm_read8(pc++)); - //cpm_printstring("Var opcode: "); - //print_hex(var_opcode); - //crlf(); switch(var_opcode) { - /*case OPV_CALL: - cpm_printstring("Call - "); - if(operands[0]==0) { - uint8_t sv=zm_read8(pc++); - set_var(sv,0); - return; - } else { - CallFrame *f=&frames[fp++]; - f->return_pc=pc+1; - f->store_var=zm_read8(pc++); - uint16_t addr=unpack_routine(operands[0]); - cpm_printstring("Addr: "); - printi(addr); - f->num_locals=zm_read8(addr++); - cpm_printstring("Num lcls: "); - printi(f->num_locals); - for(uint8_t i=0;inum_locals;i++) - f->locals[i]=zm_read16(addr+2*i); - pc=addr+2*f->num_locals; - cpm_printstring(" New PC: "); - printi(pc); - crlf(); - } - break;*/ case OPV_CALL_EXT: case OPV_CALL: { if (operands[0] == 0) { @@ -1521,11 +1207,6 @@ static void step(void){ f->saved_sp = sp; uint32_t addr = (uint32_t)operands[0]<<1; - cpm_printstring("CALL to address "); - print_hex_32(addr); - spc(); - print_hex(operands[0]); - crlf(); f->num_locals = zm_read8(addr++); for (uint8_t i = 0; i < f->num_locals; i++) { @@ -1537,24 +1218,14 @@ static void step(void){ uint8_t argc = operand_count - 1; if (argc > f->num_locals) argc = f->num_locals; - //cpm_printstring("Argc: "); - //printi(argc); for (uint8_t i = 0; i < argc; i++){ - //f->locals[i] = operands[i + 1]; f->locals[i] = operands[i + 1]; - cpm_printstring("locals "); - printi(i); - spc(); - print_hex(f->locals[i]); - crlf(); } pc = addr; // + 2 * f->num_locals; break; } case OPV_JE: - //cpm_printstring("JE VAR - operand count: "); - //print_hex(operand_count); if(operand_count == 2) branch(operands[0] == operands[1]); else if(operand_count == 3) @@ -1575,13 +1246,6 @@ static void step(void){ branch((operands[0] & operands[1]) == operands[1]); break; case OPV_STOREW: - //cpm_printstring("STOREW: "); - //printi(operands[0]); - //spc(); - //printi(operands[1]); - //spc(); - //printi(operands[2]); - //crlf(); zm_write8(operands[0]+2*operands[1],operands[2]>>8); zm_write8(operands[0]+2*operands[1]+1,operands[2]); break; @@ -1607,26 +1271,8 @@ static void step(void){ break; case OPV_PULL: { - cpm_printstring("OPV_PULL "); - print_hex(operands[0]); - crlf(); - - //if(operands[0] != 0) set_var(operands[0],pop()); - //else pop(); - //pc++; - //uint8_t dest_var = zm_read8(pc++); - - //cpm_printstring(" dest_var: "); - //print_hex(dest_var); - uint16_t value = pop(); - - //cpm_printstring(" value: "); - //print_hex(value); - //crlf(); - - //if(operands[1] != 0) set_var(operands[0], value, 1); break; @@ -1648,15 +1294,8 @@ static void step(void){ tokenize(line,parse,text); break; } case OPV_PUT_PROP: - /*cpm_printstring("Putprop - "); - print_hex(operands[0]); - spc(); - print_hex(operands[1]); - spc(); - print_hex(operands[2]); - crlf();*/ - obj_put_prop((uint8_t)operands[0],(uint8_t)operands[1], - operands[2]); + obj_put_prop((uint8_t)operands[0],(uint8_t)operands[1], + operands[2]); break; case OPV_OR: store_result(operands[0] | operands[1], indirect); @@ -1665,10 +1304,6 @@ static void step(void){ store_result(operands[0] & operands[1], indirect); break; case OPV_RANDOM: { - crlf(); - cpm_printstring("Random called with argument "); - print_hex(operands[0]); - crlf(); int16_t range = (int16_t)operands[0]; if(range == 0) { rng_state = (uint16_t)pc; @@ -1719,18 +1354,13 @@ int main(int agrv, char **argv){ fatal("Could not open input file!"); cpm_set_dma(&hdr); - //bdos(BDOS_READ_SEQ,&story_fcb); cpm_read_sequential(&cpm_fcb); - //uint8_t *hdr=dma; dynamic_size=(hdr[0x0e]<<8)|hdr[0x0f]; - //cpm_printstring("Dynamic size: "); for(uint16_t i=0; iDYNAMIC_MEM_MAX) while(1); for(uint16_t i=0; i<128; i++) @@ -1739,7 +1369,7 @@ int main(int agrv, char **argv){ for(uint16_t i=128;i Date: Fri, 9 Jan 2026 19:19:22 +0100 Subject: [PATCH 15/36] Multiple small fixes. Zork I is now semi-playable! --- third_party/z65/z65.c | 171 +++++++++++++++++++++++++++++++----------- 1 file changed, 129 insertions(+), 42 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index f71ce75c..84204b7c 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -84,7 +84,7 @@ #define OPV_PRINT_NUM 0x26 #define OPV_RANDOM 0x27 #define OPV_AND 0x09 -#define OPV_OR 0x0A +#define OPV_OR 0x08 #define OPV_NOT 0x0B #define OPV_LOADW 0x0F #define OPV_STORE 0x0D @@ -309,12 +309,29 @@ static Page *get_page(uint16_t page){ */ static uint8_t zm_read8(uint32_t a){ - + + uint8_t data; if(a>9); + data = p->data[a&0x1FF]; + } +/* if(a>0x4687 && a<0x468f) { + cpm_printstring("Read addr: "); + print_hex(a); + cpm_printstring(" data: "); + print_hex(data); + crlf(); } - Page *p=get_page(a>>9); - return p->data[a&0x1FF]; + if(a>0x2550 && a<0x2641) { + cpm_printstring("Read from parse buffer "); + print_hex(a); + spc(); + print_hex(data); + crlf(); + }*/ + return data; } static uint16_t zm_read16(uint32_t a){ @@ -359,11 +376,20 @@ static uint16_t get_var(uint8_t v, uint8_t indirect){ } uint16_t a = (hdr[0x0c]<<8) + hdr[0x0d] + 2*(v-16); uint16_t ret_data = zm_read16(a); +#ifdef DEBUG + cpm_printstring("Read global variable "); + print_hex(v); + cpm_printstring(" data: "); + print_hex(ret_data); + cpm_printstring(" address: "); + print_hex(a); + crlf(); +#endif return ret_data; } static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { - if(v==0) { + if(v==0) { if(indirect) { if(sp > 0) stack[sp - 1] = val; else push(val); @@ -371,17 +397,30 @@ static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { push(val); } - } + } else if(v<16) { - frames[fp-1].locals[v-1]=val; + frames[fp-1].locals[v-1]=val; } else{ uint16_t a = (hdr[0x0c]<<8) + hdr[0x0d] + 2*(v-16); zm_write8(a,val>>8); zm_write8(a+1,val&0xFF); + + /*cpm_printstring("Write global variable "); + print_hex(v); + spc(); + print_hex(val); + spc(); + print_hex(a); + crlf(); + */ + } + + } + /* ============================================================ * Operand decoding * ============================================================ @@ -600,8 +639,8 @@ uint16_t dict_lookup(const char *word) print_hex(w0); spc(); print_hex(w1); - crlf();*/ - + crlf(); + */ //cpm_printstring("sep: "); //printi(sep); //cpm_printstring(" entry_len: "); @@ -617,13 +656,14 @@ uint16_t dict_lookup(const char *word) //crlf(); for (uint16_t i = 0; i < dict_entry_count; i++) { //uint16_t e = dict + i * entry_len; - e += dict_entry_len; if (zm_read16(e) == w0 && zm_read16(e + 2) == w1) { //cpm_printstring("Found match at address"); //print_hex(e); return e; } + + e += dict_entry_len; } return 0; @@ -647,54 +687,67 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) uint8_t count=0; uint8_t i=0; - uint8_t max_text = zm_read8(parse_buf); - //cpm_printstring("Max test: "); - //print_hex(max_text); - //crlf(); + uint8_t max_tok = zm_read8(parse_buf); - while(in[i] && count MAX_TOKENS) max_tok = MAX_TOKENS; + + // Clear buffer + for(uint8_t i=0; i>8); - //spc(); - //print_hex(dict & 0xff); - //spc(); - //print_hex(len); - //spc(); - //print_hex(start+1); + uint16_t entry = parse_buf + 2 + (count<<2); zm_write8(entry, dict>>8); zm_write8(entry+1, dict & 0xff); - zm_write8(entry+2, len); + zm_write8(entry+2, word_len); zm_write8(entry+3, start+1);//1); count++; } zm_write8(parse_buf+1,count); - - uint8_t x; + //uint8_t x; + //crlf(); + /* cpm_printstring("Parse buffer: "); crlf(); - //for(x=0; x<(count<<2)+2; x++) { - // print_hex(zm_read8(parse_buf+x)); - // crlf(); - //} - + for(x=0; x<(count<<2)+2; x++) { + print_hex(zm_read8(parse_buf+x)); + crlf(); + }*/ + /* + cpm_printstring("Text buffer: "); + crlf(); + x=0; + while(1) { + uint8_t a = zm_read8(text_buf+x); + x++; + print_hex(a); + crlf(); + if(!a) break; + } +*/ return count; } @@ -912,7 +965,7 @@ static void step(void){ int16_t value = (int16_t)get_var(operands[0],1); value--; set_var(operands[0],(uint16_t)value,1); - branch(value>(int16_t)operands[1]); + branch(value<(int16_t)operands[1]); break; } case OP2_INC_CHK: { @@ -935,9 +988,25 @@ static void step(void){ set_var(operands[0],operands[1], 1); break; case OP2_LOADW: + /*cpm_printstring("OP2_LOADW address: "); + print_hex(operands[0]+2*operands[1]); + cpm_printstring(" data: "); + print_hex(zm_read16(operands[0]+2*operands[1])); + cpm_printstring("Operands: "); + print_hex(operands[0]); + spc(); + print_hex(operands[1]); + crlf();*/ + + store_result(zm_read16(operands[0]+2*operands[1]), indirect); break; - case OP2_LOADB: + case OP2_LOADB: + /*cpm_printstring("OP2_LOADB address: "); + print_hex(operands[0]+operands[1]); + cpm_printstring(" data: "); + print_hex(zm_read8(operands[0]+operands[1])); + crlf()*/; store_result(zm_read8(operands[0]+operands[1]), indirect); break; case OP2_ADD: @@ -1280,18 +1349,29 @@ static void step(void){ case OPV_SREAD: { uint16_t text = operands[0]; uint16_t parse = operands[1]; - + //cpm_printstring("Text addr: "); + //print_hex(text); + //cpm_printstring(" Parse addr: "); + //print_hex(parse); + //crlf(); char line[INPUT_MAX]={0}; uint8_t len = read_line(line); uint8_t max = zm_read8(text); if(len>max) len=max; - zm_write8(text+1,len); + //zm_write8(text+1,len); for(uint8_t i=0;i(int16_t)operands[1]); + break; + } default: crlf(); printi(op); From fbe8f9a7c33b9e90401820adccb92d14b00b7434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Fri, 9 Jan 2026 20:42:34 +0100 Subject: [PATCH 16/36] Zork I now runs on actual CP/M-65! But not great... --- config.py | 1 + src/arch/atari800/build.py | 4 +++- third_party/z65/z65.c | 36 +++++++++++++++++++++++++----------- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/config.py b/config.py index 7c9f3fa5..f188de13 100644 --- a/config.py +++ b/config.py @@ -73,6 +73,7 @@ ZM_APPS = { "0:z65.com": "third_party/z65", + "0:zork1.z3": "third_party/z65/zork1.z3", } SERIAL_APPS = { diff --git a/src/arch/atari800/build.py b/src/arch/atari800/build.py index 90a8ff96..8fb929d9 100644 --- a/src/arch/atari800/build.py +++ b/src/arch/atari800/build.py @@ -11,6 +11,7 @@ BIG_SCREEN_APPS, PASCAL_APPS, FORTH_APPS, + ZM_APPS, ) llvmclibrary(name="headers", hdrs={"atari800.inc": "./atari800.inc"}) @@ -172,7 +173,8 @@ | SCREEN_APPS_SRCS | BIG_SCREEN_APPS | PASCAL_APPS - | FORTH_APPS, + | FORTH_APPS + | ZM_APPS, ) simplerule( diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 84204b7c..535ad990 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -101,8 +101,8 @@ */ #define PAGE_SIZE 512 -#define NUM_PAGES 8 -#define DYNAMIC_MEM_MAX 16384 +#define NUM_PAGES 4 +#define DYNAMIC_MEM_MAX 12000 #define STACK_SIZE 256 #define MAX_FRAMES 8 @@ -138,6 +138,7 @@ typedef struct { * ============================================================ */ + static uint8_t dynamic_mem[DYNAMIC_MEM_MAX]; static uint16_t dynamic_size; @@ -152,6 +153,7 @@ static uint16_t sp; static CallFrame frames[MAX_FRAMES]; static uint8_t fp; +static FCB storyFile; static uint8_t dma[128]; static uint8_t hdr[128]; @@ -262,12 +264,12 @@ static uint8_t read_line(char *buf){ } if(c==8 && len){ len--; - putc(8); putc(' '); putc(8); + //putc(8); putc(' '); putc(8); continue; } if(lendata[(i<<7)+j]=dma[j]; } record++; - cpm_fcb.r = record; + storyFile.r = record; } p->page=page; p->valid=1; @@ -1437,14 +1439,26 @@ int main(int agrv, char **argv){ crlf(); // Get story filename from commandline - if(cpm_open_file(&cpm_fcb)) + for(uint8_t i=0; i<11; i++) + storyFile.f[i]=cpm_fcb.f[i]; + storyFile.dr = cpm_fcb.dr; + + if(cpm_open_file(&storyFile)) fatal("Could not open input file!"); + //cpm_fcb.r = 0; cpm_set_dma(&hdr); - cpm_read_sequential(&cpm_fcb); + cpm_read_sequential(&storyFile); dynamic_size=(hdr[0x0e]<<8)|hdr[0x0f]; - + //cpm_printstring("Dynamic size: "); + //printi(dynamic_size); + //crlf(); + // cpm_printstring("Header: "); + // for(uint8_t i=0; i<16; i++) { + // print_hex(hdr[i]); + // spc(); + // } for(uint16_t i=0; i Date: Sat, 10 Jan 2026 20:22:26 +0100 Subject: [PATCH 17/36] Added defines for header data locations --- third_party/z65/z65.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 535ad990..535c7958 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -1,6 +1,4 @@ -/* Z-machine v1–v3 interpreter for CP/M-65 - * Step 2: complete 1OP instruction set - */ +/* Z-machine v1–v3 interpreter for CP/M-65 */ #include #include @@ -94,6 +92,18 @@ #define OPV_LOADB 0x50 #define OPV_MUL 0x56 +/* ============================================================ + * Header definitions + * ============================================================ + */ + +#define HDR_VERSION 0x00 +#define HDR_PC 0x06 +#define HDR_DICT 0x08 +#define HDR_OBJ 0x0A +#define HDR_GLB 0x0C +#define HDR_STAT 0x0E +#define HDR_ABBR 0x18 /* ============================================================ * Configuration @@ -376,7 +386,7 @@ static uint16_t get_var(uint8_t v, uint8_t indirect){ if(v<16) { return frames[fp-1].locals[v-1]; } - uint16_t a = (hdr[0x0c]<<8) + hdr[0x0d] + 2*(v-16); + uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); uint16_t ret_data = zm_read16(a); #ifdef DEBUG cpm_printstring("Read global variable "); @@ -404,7 +414,7 @@ static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { frames[fp-1].locals[v-1]=val; } else{ - uint16_t a = (hdr[0x0c]<<8) + hdr[0x0d] + 2*(v-16); + uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); zm_write8(a,val>>8); zm_write8(a+1,val&0xFF); @@ -564,7 +574,7 @@ static void print_num(int16_t v){ // Dictionary static void dict_init(void){ - dict_addr = hdr[0x08]<<8 | hdr[0x09]; + dict_addr = hdr[HDR_DICT]<<8 | hdr[HDR_DICT+1]; // cpm_printstring("Dict addr "); // print_hex(dict_addr); dict_sep_count = zm_read8(dict_addr++); @@ -1450,7 +1460,7 @@ int main(int agrv, char **argv){ cpm_set_dma(&hdr); cpm_read_sequential(&storyFile); - dynamic_size=(hdr[0x0e]<<8)|hdr[0x0f]; + dynamic_size=(hdr[HDR_STAT]<<8)|hdr[HDR_STAT+1]; //cpm_printstring("Dynamic size: "); //printi(dynamic_size); //crlf(); @@ -1475,17 +1485,17 @@ int main(int agrv, char **argv){ dynamic_mem[i]=dma[i&0x7f]; } - pc=initial_pc=(hdr[0x06]<<8)|hdr[0x07]; + pc=initial_pc=(hdr[HDR_PC]<<8)|hdr[HDR_PC+1]; sp=fp=next_victim=0; for(uint8_t i=0;i Date: Sun, 11 Jan 2026 20:34:10 +0100 Subject: [PATCH 18/36] Fixed various bugs, Zork I now seems fully playable but Mini-Zork cannot parse input --- third_party/z65/z65.c | 56 ++++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 535c7958..7549a383 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -111,11 +111,11 @@ */ #define PAGE_SIZE 512 -#define NUM_PAGES 4 +#define NUM_PAGES 2 #define DYNAMIC_MEM_MAX 12000 -#define STACK_SIZE 256 -#define MAX_FRAMES 8 +#define STACK_SIZE 512 +#define MAX_FRAMES 12 #define MAX_LOCALS 16 #define MAX_OPERANDS 8 @@ -384,6 +384,13 @@ static uint16_t get_var(uint8_t v, uint8_t indirect){ return val; } if(v<16) { +/* cpm_printstring("Local "); + printi(v-1); + cpm_printstring(" read as "); + print_hex(frames[fp-1].locals[v-1]); + cpm_printstring(" fp: "); + printi(fp); + crlf();*/ return frames[fp-1].locals[v-1]; } uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); @@ -412,6 +419,13 @@ static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { } else if(v<16) { frames[fp-1].locals[v-1]=val; + /*cpm_printstring("Local "); + printi(v-1); + cpm_printstring(" set to "); + print_hex(val); + cpm_printstring(" sp: "); + printi(fp); + crlf();*/ } else{ uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); @@ -646,13 +660,13 @@ uint16_t dict_lookup(const char *word) uint16_t w0 = (zchars[0] << 10) | (zchars[1] << 5) | zchars[2]; uint16_t w1 = (zchars[3] << 10) | (zchars[4] << 5) | zchars[5] | 0x8000; - /*cpm_printstring("dict lookup "); - cpm_printstring(word); - print_hex(w0); - spc(); - print_hex(w1); - crlf(); - */ + //cpm_printstring("dict lookup "); + //cpm_printstring(word); + //print_hex(w0); + //spc(); + //print_hex(w1); + //crlf(); + //cpm_printstring("sep: "); //printi(sep); //cpm_printstring(" entry_len: "); @@ -671,6 +685,7 @@ uint16_t dict_lookup(const char *word) if (zm_read16(e) == w0 && zm_read16(e + 2) == w1) { //cpm_printstring("Found match at address"); //print_hex(e); + //crlf(); return e; } @@ -983,8 +998,8 @@ static void step(void){ case OP2_INC_CHK: { int16_t value = (int16_t)get_var(operands[0],1); value++; - set_var(operands[0],(uint16_t)value,1); - branch(value>(int16_t)operands[1]); + set_var(operands[0],value,1); + branch((int16_t)value>(int16_t)operands[1]); break; } case OP2_TEST: @@ -1010,7 +1025,7 @@ static void step(void){ print_hex(operands[1]); crlf();*/ - + store_result(zm_read16(operands[0]+2*operands[1]), indirect); break; case OP2_LOADB: @@ -1166,11 +1181,13 @@ static void step(void){ uint8_t result; result = get_var(operands[0], indirect); store_result(result, 0); + break; } case OP1_NOT: { uint8_t result; result = ~operands[0]; store_result(result, indirect); + break; } case OP1_RET: z_ret(operands[0]); @@ -1456,19 +1473,14 @@ int main(int agrv, char **argv){ if(cpm_open_file(&storyFile)) fatal("Could not open input file!"); - //cpm_fcb.r = 0; cpm_set_dma(&hdr); cpm_read_sequential(&storyFile); + if(hdr[HDR_VERSION] != 3) + fatal("Only v3 files are supported!"); + dynamic_size=(hdr[HDR_STAT]<<8)|hdr[HDR_STAT+1]; - //cpm_printstring("Dynamic size: "); - //printi(dynamic_size); - //crlf(); - // cpm_printstring("Header: "); - // for(uint8_t i=0; i<16; i++) { - // print_hex(hdr[i]); - // spc(); - // } + for(uint16_t i=0; i Date: Sun, 11 Jan 2026 21:36:07 +0100 Subject: [PATCH 19/36] Fixed bug where variables were treaded as 8 bit in some opcodes. Minizork now mostly runs --- third_party/z65/z65.c | 53 ++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 7549a383..997caa79 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -197,7 +197,10 @@ static uint16_t rng_state = 1; static uint8_t rng_enabled = 1; static void z_ret(uint16_t v); - + +#ifdef DEBUG +static long int opcnt = 0; +#endif /* ============================================================ * Console @@ -423,7 +426,7 @@ static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { printi(v-1); cpm_printstring(" set to "); print_hex(val); - cpm_printstring(" sp: "); + cpm_printstring(" fp: "); printi(fp); crlf();*/ } @@ -432,14 +435,14 @@ static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { zm_write8(a,val>>8); zm_write8(a+1,val&0xFF); - /*cpm_printstring("Write global variable "); - print_hex(v); - spc(); - print_hex(val); - spc(); - print_hex(a); - crlf(); - */ + //cpm_printstring("Write global variable "); + //print_hex(v); + //spc(); + //print_hex(val); + //spc(); + //print_hex(a); + //crlf(); + } @@ -952,10 +955,18 @@ static void step(void){ uint8_t op=zm_read8(pc++); #ifdef DEBUG + printi(opcnt++); + spc(); cpm_printstring("OP: "); print_hex(op); cpm_printstring(" PC: "); print_hex_32(pc); + cpm_printstring(" SP: "); + print_hex(sp); + cpm_printstring(" FP: "); + print_hex(fp); + cpm_printstring(" [SP]: "); + print_hex(stack[sp-1]); crlf(); #endif @@ -979,7 +990,12 @@ static void step(void){ case OP2_JL: branch((int16_t)operands[0]<(int16_t)operands[1]); break; - case OP2_JG: + case OP2_JG: + //cpm_printstring("OP2_JG - op1: "); + //print_hex(operands[0]); + //cpm_printstring(" op2: "); + //print_hex(operands[1]); + //crlf(); branch((int16_t)operands[0]>(int16_t)operands[1]); break; case OP2_JIN: { @@ -1048,7 +1064,12 @@ static void step(void){ store_result((int16_t)operands[0]*(int16_t)operands[1], indirect); break; - case OP2_DIV: + case OP2_DIV: + //cpm_printstring("OP2_DIV - op1: "); + //print_hex(operands[0]); + //cpm_printstring(" op2: "); + //print_hex(operands[1]); + //crlf(); store_result((int16_t)operands[0]/(int16_t)operands[1], indirect); break; @@ -1178,13 +1199,13 @@ static void step(void){ break; } case OP1_LOAD: { - uint8_t result; + uint16_t result; result = get_var(operands[0], indirect); store_result(result, 0); break; } case OP1_NOT: { - uint8_t result; + uint16_t result; result = ~operands[0]; store_result(result, indirect); break; @@ -1193,13 +1214,13 @@ static void step(void){ z_ret(operands[0]); break; case OP1_INC: { - uint8_t value = get_var(operands[0], indirect); + uint16_t value = get_var(operands[0], indirect); value++; set_var(operands[0], value, indirect); break; } case OP1_DEC: { - uint8_t value = get_var(operands[0], indirect); + uint16_t value = get_var(operands[0], indirect); value--; set_var(operands[0], value, indirect); break; From 860d2cbe52c672010e7ccfd322ea8e85f38ca6ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Mon, 12 Jan 2026 20:14:01 +0100 Subject: [PATCH 20/36] Some bugfixes. Zork I and Minizork plays without issue not and czech passes all tests --- third_party/z65/z65.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 997caa79..4973d11e 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -72,6 +72,7 @@ #define OPV_JE 0x01 #define OPV_JL 0x02 #define OPV_JG 0x03 +#define OPV_DEC_CHK 0x04 #define OPV_INC_CHK 0x05 #define OPV_TEST 0x07 #define OPV_STOREW 0x21 @@ -115,7 +116,7 @@ #define DYNAMIC_MEM_MAX 12000 #define STACK_SIZE 512 -#define MAX_FRAMES 12 +#define MAX_FRAMES 16 #define MAX_LOCALS 16 #define MAX_OPERANDS 8 @@ -262,6 +263,12 @@ static uint8_t read_line(char *buf){ uint8_t len=0; for(;;){ char c=cpm_conin(); + + /* force lowercase */ + if (c >= 'A' && c <= 'Z') + c = c - 'A' + 'a'; + + if(c=='\r'||c=='\n'){ crlf(); buf[len]=0; @@ -620,9 +627,9 @@ static void dict_init(void){ static uint8_t encode_a2(char c) { /* A2 table for v1–v3 */ - const char *a2 = " \n0123456789.,!?_#'\"/\\-:()"; - for (uint8_t i = 0; a2[i]; i++) { - if (a2[i] == c) + //const char *a2 = " \n0123456789.,!?_#'\"/\\-:()"; + for (uint8_t i = 0; zalph[2][i]; i++) { + if (zalph[2][i] == c) return i; } return 0; /* space */ @@ -636,8 +643,8 @@ void encode_zchars(const char *s, uint8_t zchars[6]) char c = *s++; /* force lowercase */ - if (c >= 'A' && c <= 'Z') - c = c - 'A' + 'a'; + //if (c >= 'A' && c <= 'Z') + // c = c - 'A' + 'a'; if (c >= 'a' && c <= 'z') { zchars[zi++] = (c - 'a') + 6; @@ -651,7 +658,7 @@ void encode_zchars(const char *s, uint8_t zchars[6]) } } - /* pad with spaces (A2 space = shift 5 + 0, but Inform pads with 5) */ + /* pad with 5 */ while (zi < 6) zchars[zi++] = 5; } @@ -1143,7 +1150,7 @@ static void step(void){ uint8_t type=(op>>4)&3; uint8_t oc=op&0x0F; uint8_t indirect = (oc == OP1_LOAD); - if(type!=OP_OMIT) operands[0]=read_operand(type, indirect); + if(type!=OP_OMIT) operands[0]=read_operand(type, 0); switch(oc){ case OP1_JUMP: pc+=(int16_t)operands[0]-2; @@ -1467,6 +1474,13 @@ static void step(void){ branch(value>(int16_t)operands[1]); break; } + case OPV_DEC_CHK:{ + int16_t value = (int16_t)get_var(operands[0],1); + value--; + set_var(operands[0],(uint16_t)value,1); + branch(value<(int16_t)operands[1]); + break; + } default: crlf(); printi(op); From 98a6636d3684b5343fde191a634e393d0b6b7b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Tue, 13 Jan 2026 08:24:34 +0100 Subject: [PATCH 21/36] Avoid clearing the parse buffer in case games give illegal lengths... --- third_party/z65/z65.c | 64 +++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 4973d11e..3abb0143 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -85,12 +85,15 @@ #define OPV_AND 0x09 #define OPV_OR 0x08 #define OPV_NOT 0x0B +#define OPV_INSERT_OBJ 0x0E #define OPV_LOADW 0x0F #define OPV_STORE 0x0D #define OPV_CALL_EXT 0x20 #define OPV_PUSH 0x28 #define OPV_PULL 0x29 #define OPV_LOADB 0x50 +#define OPV_ADD 0x54 +#define OPV_SUB 0x55 #define OPV_MUL 0x56 /* ============================================================ @@ -164,7 +167,7 @@ static uint16_t sp; static CallFrame frames[MAX_FRAMES]; static uint8_t fp; -static FCB storyFile; +//static FCB storyFile; static uint8_t dma[128]; static uint8_t hdr[128]; @@ -301,15 +304,15 @@ static uint8_t read_line(char *buf){ static void load_page(Page *p,uint16_t page){ uint16_t record=page<<2; - storyFile.r = record; + cpm_fcb.r = record; for(uint8_t i=0;i<4;i++){ cpm_set_dma(&dma); - cpm_read_random(&storyFile); + cpm_read_random(&cpm_fcb); for(uint8_t j=0;j<128;j++) { p->data[(i<<7)+j]=dma[j]; } record++; - storyFile.r = record; + cpm_fcb.r = record; } p->page=page; p->valid=1; @@ -725,18 +728,21 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) uint8_t i=0; uint8_t max_tok = zm_read8(parse_buf); - + if (max_tok > MAX_TOKENS) max_tok = MAX_TOKENS; - // Clear buffer - for(uint8_t i=0; imax) len=max; - + //zm_write8(text+1,len); for(uint8_t i=0;i Date: Tue, 13 Jan 2026 17:02:59 +0100 Subject: [PATCH 22/36] Added save functionality, no load yet --- third_party/z65/z65.c | 122 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 3abb0143..567bb890 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -202,6 +202,8 @@ static uint8_t rng_enabled = 1; static void z_ret(uint16_t v); +static uint8_t w_addr; + #ifdef DEBUG static long int opcnt = 0; #endif @@ -924,6 +926,123 @@ static void obj_put_prop(uint8_t obj, uint8_t prop, uint16_t val){ } } +void write_save_sector(FCB *fcb, void *dmaptr) { + cpm_set_dma(dmaptr); + cpm_write_sequential(fcb); +} + +void add_save_byte(FCB *fcb, uint8_t *writeSector, uint8_t data) { + writeSector[w_addr++] = data; + if(w_addr == 0x80) { + write_save_sector(fcb, writeSector); + w_addr = 0; + } +} + +void write_zero_block(FCB *fcb, uint8_t *writeSector, uint8_t zero_cnt) { + add_save_byte(fcb, writeSector, 0x00); + add_save_byte(fcb, writeSector, zero_cnt); +} +// Saving and loading +uint8_t save_game(void) { + FCB saveFile; + char filename_input[14]; + + filename_input[0]=13; + filename_input[1]=0; + + cpm_printstring("Enter filename: "); + cpm_readline((uint8_t *)filename_input); + crlf(); + + cpm_set_dma(&saveFile); + if(!cpm_parse_filename(&filename_input[2])) { + return 0; + } + + if(cpm_make_file(&saveFile)) { + return 0; + } + + // Write delta of dynamic ram to file + uint16_t cmp_addr = 0; + cpm_fcb.r = 0; + uint8_t writeSector[128]; + w_addr=0; + uint8_t zero_cnt=0; + while(cmp_addr < dynamic_size) { + // Read a sector from file + uint8_t checkSector[128]; + cpm_set_dma(&checkSector); + cpm_read_random(&cpm_fcb); + cpm_fcb.r++; + // Compare byte by byte with ram + for(uint8_t i=0; i<128; i++) { + uint8_t diff = dynamic_mem[cmp_addr] ^ checkSector[i]; + if(diff) { + if(zero_cnt != 0) { + write_zero_block(&saveFile, writeSector, zero_cnt); + zero_cnt = 0; + } + add_save_byte(&saveFile, writeSector, diff); + + cpm_printstring("Difference found at addr "); + print_hex(cmp_addr); + cpm_printstring(" dyn: "); + print_hex(dynamic_mem[cmp_addr]); + cpm_printstring(" file: "); + print_hex(checkSector[i]); + crlf(); + } else { + zero_cnt++; + if(zero_cnt == 0x80) { + write_zero_block(&saveFile, writeSector, zero_cnt); + zero_cnt = 0; + } + } + cmp_addr++; + } + } + // Write trailing zeroes + if(zero_cnt != 0) { + write_zero_block(&saveFile, writeSector, zero_cnt); + } + + // Write frames + add_save_byte(&saveFile, writeSector, fp); + for(uint8_t i = 0; i> 24)); + add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 16)); + add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 8)); + add_save_byte(&saveFile, writeSector, (frames[i].return_pc & 0xFF)); + + add_save_byte(&saveFile, writeSector, frames[i].store_var ); + + add_save_byte(&saveFile, writeSector, frames[i].num_locals); + for(uint8_t j = 0; j< MAX_LOCALS; j++) { + add_save_byte(&saveFile, writeSector, (frames[i].locals[j] >> 8)); + add_save_byte(&saveFile, writeSector, (frames[i].locals[j] & 0xFF)); + } + + add_save_byte(&saveFile, writeSector, (frames[i].saved_sp >> 8)); + add_save_byte(&saveFile, writeSector, (frames[i].saved_sp & 0xFF)); + + } + // Write stack + add_save_byte(&saveFile, writeSector, (sp>>8)); + add_save_byte(&saveFile, writeSector, (sp & 0xFF)); + for(uint16_t i = 0; i> 8)); + add_save_byte(&saveFile, writeSector, (stack[i] & 0xFF)); + } + // Perform a final write if necessary + if(w_addr != 0) { + write_save_sector(&saveFile, writeSector); + } + cpm_close_file(&saveFile); + + return 1; +} /* ============================================================ * Execution @@ -1281,6 +1400,9 @@ static void step(void){ break; case OP0_SAVE: + branch(save_game()); + break; + case OP0_RESTORE: branch(0); /* always fail */ break; From 7665d0143e2eb2891f23f8bf1a87d1613bb4fddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 15 Jan 2026 21:00:32 +0100 Subject: [PATCH 23/36] Save/Restore implemented and almost working, crashes on first command after restore for unknown reason --- third_party/z65/z65.c | 186 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 181 insertions(+), 5 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 567bb890..ab000f66 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -964,6 +964,8 @@ uint8_t save_game(void) { return 0; } + uint16_t enc = 0; + // Write delta of dynamic ram to file uint16_t cmp_addr = 0; cpm_fcb.r = 0; @@ -977,15 +979,16 @@ uint8_t save_game(void) { cpm_read_random(&cpm_fcb); cpm_fcb.r++; // Compare byte by byte with ram - for(uint8_t i=0; i<128; i++) { + for(uint8_t i=0; i<((dynamic_size-cmp_addr)>128?128:(dynamic_size-cmp_addr)); i++) { uint8_t diff = dynamic_mem[cmp_addr] ^ checkSector[i]; if(diff) { if(zero_cnt != 0) { write_zero_block(&saveFile, writeSector, zero_cnt); + enc += zero_cnt; zero_cnt = 0; } add_save_byte(&saveFile, writeSector, diff); - + enc++; cpm_printstring("Difference found at addr "); print_hex(cmp_addr); cpm_printstring(" dyn: "); @@ -997,6 +1000,7 @@ uint8_t save_game(void) { zero_cnt++; if(zero_cnt == 0x80) { write_zero_block(&saveFile, writeSector, zero_cnt); + enc+=zero_cnt; zero_cnt = 0; } } @@ -1006,10 +1010,23 @@ uint8_t save_game(void) { // Write trailing zeroes if(zero_cnt != 0) { write_zero_block(&saveFile, writeSector, zero_cnt); + enc+=zero_cnt; } - + /*cpm_printstring("Encoded bytes: "); + printi(enc); + crlf(); + cpm_printstring("Address: "); + printi(cmp_addr); + crlf(); + cpm_printstring("Dynamic size: "); + printi(dynamic_size); + crlf();*/ + // Write frames add_save_byte(&saveFile, writeSector, fp); + cpm_printstring("Save fp: "); + print_hex(fp); + crlf(); for(uint8_t i = 0; i> 24)); add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 16)); @@ -1031,19 +1048,178 @@ uint8_t save_game(void) { // Write stack add_save_byte(&saveFile, writeSector, (sp>>8)); add_save_byte(&saveFile, writeSector, (sp & 0xFF)); + cpm_printstring("Save sp: "); + print_hex(sp); + crlf(); for(uint16_t i = 0; i> 8)); add_save_byte(&saveFile, writeSector, (stack[i] & 0xFF)); } + + // Save PC + add_save_byte(&saveFile, writeSector, (pc >> 24)); + add_save_byte(&saveFile, writeSector, (pc >> 16)); + add_save_byte(&saveFile, writeSector, (pc >> 8)); + add_save_byte(&saveFile, writeSector, (pc & 0xFF)); + // Perform a final write if necessary + if(w_addr != 0) { write_save_sector(&saveFile, writeSector); - } + } + cpm_close_file(&saveFile); return 1; } +uint8_t read_save_byte(FCB *fcb, uint8_t *restoreSector) { + uint8_t data; + // Refill buffer if out of data + if(w_addr == 0x80) { + cpm_set_dma(restoreSector); + cpm_read_random(fcb); + fcb->r++; + w_addr = 0; +// cpm_printstring("Save file read performed"); + } + + data = restoreSector[w_addr++]; + cpm_printstring("Read save byte: "); + print_hex(data); + crlf(); + return data; +} + +uint8_t read_game_byte(uint8_t *r_addr) { + uint8_t data; + // Refill buffer if out of data + if((*r_addr) == 0x80) { + cpm_set_dma(&dma); + cpm_read_random(&cpm_fcb); + cpm_fcb.r++; + (*r_addr) = 0; + //cpm_printstring("Game file read performed"); + //crlf(); + } + + data = dma[(*r_addr)]; + (*r_addr) = (*r_addr) + 1; + //cpm_printstring("Read game byte: "); + //print_hex(data); + //crlf(); + return data; +} + + +uint8_t restore_game(void) { + FCB saveFile; + char filename_input[14]; + + filename_input[0]=13; + filename_input[1]=0; + + cpm_printstring("Enter filename: "); + cpm_readline((uint8_t *)filename_input); + crlf(); + + cpm_set_dma(&saveFile); + if(!cpm_parse_filename(&filename_input[2])) { + return 0; + } + + saveFile.cr = 0; + if(cpm_open_file(&saveFile)) { + return 0; + } + saveFile.r = 0; + + // Restore dynamic ram from file + uint16_t cmp_addr = 0; + + cpm_fcb.r = 0; + uint8_t restoreSector[128]; + uint8_t gameFileSector[128]; + //uint8_t zero_cnt; + + w_addr = 0x80; // trigger sector read + uint8_t r_addr = 0x80; + uint8_t gameFileAddr = 0x80; + + // Restore dynamic memory + while(cmp_addr < dynamic_size) { + + uint8_t data = read_save_byte(&saveFile, restoreSector); + + if(data == 0x00) { + uint8_t zero_cnt = read_save_byte(&saveFile, restoreSector); + + for(uint8_t i=0; i Date: Tue, 20 Jan 2026 19:50:31 +0100 Subject: [PATCH 24/36] Saving and loading seems to work! Needs massive cleanup --- third_party/z65/z65.c | 69 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index ab000f66..792ae566 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -126,7 +126,7 @@ #define INPUT_MAX 80 #define MAX_TOKENS 16 -//#define DEBUG +#define DEBUG /* ============================================================ * Structures @@ -399,13 +399,13 @@ static uint16_t get_var(uint8_t v, uint8_t indirect){ return val; } if(v<16) { -/* cpm_printstring("Local "); + cpm_printstring("Local "); printi(v-1); cpm_printstring(" read as "); print_hex(frames[fp-1].locals[v-1]); cpm_printstring(" fp: "); printi(fp); - crlf();*/ + crlf(); return frames[fp-1].locals[v-1]; } uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); @@ -434,13 +434,13 @@ static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { } else if(v<16) { frames[fp-1].locals[v-1]=val; - /*cpm_printstring("Local "); + cpm_printstring("Local "); printi(v-1); cpm_printstring(" set to "); print_hex(val); cpm_printstring(" fp: "); printi(fp); - crlf();*/ + crlf(); } else{ uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); @@ -965,21 +965,29 @@ uint8_t save_game(void) { } uint16_t enc = 0; - + // Write delta of dynamic ram to file uint16_t cmp_addr = 0; cpm_fcb.r = 0; uint8_t writeSector[128]; w_addr=0; uint8_t zero_cnt=0; + + uint16_t file_pos = 0; while(cmp_addr < dynamic_size) { // Read a sector from file uint8_t checkSector[128]; cpm_set_dma(&checkSector); cpm_read_random(&cpm_fcb); cpm_fcb.r++; + file_pos +=128; // Compare byte by byte with ram - for(uint8_t i=0; i<((dynamic_size-cmp_addr)>128?128:(dynamic_size-cmp_addr)); i++) { + uint8_t next_len = (dynamic_size-cmp_addr)>128?128: + (dynamic_size-cmp_addr); + cpm_printstring("Next: "); + print_hex(next_len); + crlf(); + for(uint8_t i=0; i> 24)); add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 16)); add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 8)); @@ -1039,6 +1054,13 @@ uint8_t save_game(void) { for(uint8_t j = 0; j< MAX_LOCALS; j++) { add_save_byte(&saveFile, writeSector, (frames[i].locals[j] >> 8)); add_save_byte(&saveFile, writeSector, (frames[i].locals[j] & 0xFF)); + cpm_printstring("Local "); + printi(i); + spc(); + printi(j); + spc(); + print_hex(frames[i].locals[j]); + crlf(); } add_save_byte(&saveFile, writeSector, (frames[i].saved_sp >> 8)); @@ -1051,11 +1073,14 @@ uint8_t save_game(void) { cpm_printstring("Save sp: "); print_hex(sp); crlf(); + cpm_printstring("Stack: "); for(uint16_t i = 0; i> 8)); add_save_byte(&saveFile, writeSector, (stack[i] & 0xFF)); + print_hex(stack[i]); + spc(); } - + crlf(); // Save PC add_save_byte(&saveFile, writeSector, (pc >> 24)); add_save_byte(&saveFile, writeSector, (pc >> 16)); @@ -1178,7 +1203,7 @@ uint8_t restore_game(void) { cpm_printstring("fp: "); print_hex(fp); crlf(); - for(uint8_t i=0; inum_locals; i++) { f->locals[i] = zm_read16(addr); addr += 2; + cpm_printstring("CALL local "); + printi(i); + spc(); + print_hex(f->locals[i]); + crlf(); } /* overwrite locals with arguments */ From cf734d6700ef742377fd55c0c940612aa874a840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Tue, 20 Jan 2026 19:59:10 +0100 Subject: [PATCH 25/36] Cleaned up debug tracing --- third_party/z65/z65.c | 110 ++++-------------------------------------- 1 file changed, 9 insertions(+), 101 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 792ae566..c04442f0 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -126,7 +126,7 @@ #define INPUT_MAX 80 #define MAX_TOKENS 16 -#define DEBUG +//#define DEBUG /* ============================================================ * Structures @@ -399,13 +399,13 @@ static uint16_t get_var(uint8_t v, uint8_t indirect){ return val; } if(v<16) { - cpm_printstring("Local "); +/* cpm_printstring("Local "); printi(v-1); cpm_printstring(" read as "); print_hex(frames[fp-1].locals[v-1]); cpm_printstring(" fp: "); printi(fp); - crlf(); + crlf();*/ return frames[fp-1].locals[v-1]; } uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); @@ -434,13 +434,13 @@ static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { } else if(v<16) { frames[fp-1].locals[v-1]=val; - cpm_printstring("Local "); + /*cpm_printstring("Local "); printi(v-1); cpm_printstring(" set to "); print_hex(val); cpm_printstring(" fp: "); printi(fp); - crlf(); + crlf();*/ } else{ uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); @@ -973,20 +973,15 @@ uint8_t save_game(void) { w_addr=0; uint8_t zero_cnt=0; - uint16_t file_pos = 0; while(cmp_addr < dynamic_size) { // Read a sector from file uint8_t checkSector[128]; cpm_set_dma(&checkSector); cpm_read_random(&cpm_fcb); cpm_fcb.r++; - file_pos +=128; // Compare byte by byte with ram uint8_t next_len = (dynamic_size-cmp_addr)>128?128: (dynamic_size-cmp_addr); - cpm_printstring("Next: "); - print_hex(next_len); - crlf(); for(uint8_t i=0; i> 24)); add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 16)); @@ -1054,13 +1023,6 @@ uint8_t save_game(void) { for(uint8_t j = 0; j< MAX_LOCALS; j++) { add_save_byte(&saveFile, writeSector, (frames[i].locals[j] >> 8)); add_save_byte(&saveFile, writeSector, (frames[i].locals[j] & 0xFF)); - cpm_printstring("Local "); - printi(i); - spc(); - printi(j); - spc(); - print_hex(frames[i].locals[j]); - crlf(); } add_save_byte(&saveFile, writeSector, (frames[i].saved_sp >> 8)); @@ -1070,15 +1032,10 @@ uint8_t save_game(void) { // Write stack add_save_byte(&saveFile, writeSector, (sp>>8)); add_save_byte(&saveFile, writeSector, (sp & 0xFF)); - cpm_printstring("Save sp: "); - print_hex(sp); - crlf(); - cpm_printstring("Stack: "); + for(uint16_t i = 0; i> 8)); add_save_byte(&saveFile, writeSector, (stack[i] & 0xFF)); - print_hex(stack[i]); - spc(); } crlf(); // Save PC @@ -1106,13 +1063,9 @@ uint8_t read_save_byte(FCB *fcb, uint8_t *restoreSector) { cpm_read_random(fcb); fcb->r++; w_addr = 0; -// cpm_printstring("Save file read performed"); } data = restoreSector[w_addr++]; - cpm_printstring("Read save byte: "); - print_hex(data); - crlf(); return data; } @@ -1124,15 +1077,10 @@ uint8_t read_game_byte(uint8_t *r_addr) { cpm_read_random(&cpm_fcb); cpm_fcb.r++; (*r_addr) = 0; - //cpm_printstring("Game file read performed"); - //crlf(); } data = dma[(*r_addr)]; (*r_addr) = (*r_addr) + 1; - //cpm_printstring("Read game byte: "); - //print_hex(data); - //crlf(); return data; } @@ -1181,28 +1129,14 @@ uint8_t restore_game(void) { for(uint8_t i=0; inum_locals; i++) { f->locals[i] = zm_read16(addr); addr += 2; - cpm_printstring("CALL local "); - printi(i); - spc(); - print_hex(f->locals[i]); - crlf(); } /* overwrite locals with arguments */ @@ -1875,9 +1783,9 @@ int main(int agrv, char **argv){ fatal("Only v3 files are supported!"); dynamic_size=(hdr[HDR_STAT]<<8)|hdr[HDR_STAT+1]; - cpm_printstring("Dynamic size: "); - print_hex(dynamic_size); - crlf(); + //cpm_printstring("Dynamic size: "); + //print_hex(dynamic_size); + //crlf(); for(uint16_t i=0; i Date: Tue, 20 Jan 2026 20:15:13 +0100 Subject: [PATCH 26/36] More cleanup of tracing code --- third_party/z65/z65.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index c04442f0..b89ca13f 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -227,7 +227,7 @@ static void spc(void) cpm_conout(' '); } - +#ifdef DEBUG static void print_hex(uint16_t val) { cpm_printstring("0x"); @@ -249,17 +249,12 @@ static void print_hex_32(uint32_t val) else cpm_conout(nibble-10 + 'A'); } } +#endif - -static void printx(const char *s) +static void fatal(const char *s) { cpm_printstring(s); crlf(); -} - -static void fatal(const char *s) -{ - printx(s); cpm_warmboot(); } @@ -368,7 +363,7 @@ static uint16_t zm_read16(uint32_t a){ static void zm_write8(uint32_t a,uint8_t v){ if(a>=dynamic_size) { crlf(); - print_hex(a); + //print_hex(a); fatal(" Illegal write address"); } @@ -1387,11 +1382,13 @@ static void step(void){ } default: + #ifdef DEBUG crlf(); printi(op); spc(); print_hex(pc); spc(); + #endif fatal(" - Non-implemented opcode!!!"); } return; @@ -1493,10 +1490,12 @@ static void step(void){ break; } default: + #ifdef DEBUG crlf(); printi(op); spc(); - print_hex(pc); + print_hex(pc); + #endif fatal(" - Non-implemented opcode!!!"); } return; @@ -1558,8 +1557,10 @@ static void step(void){ branch(1); break; default: + #ifdef DEBUG crlf(); printi(op); + #endif fatal(" - Non-implemented opcode!!!"); } return; From 6bf9743208792155dfe19ab2b6b2c1310d81b933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Tue, 20 Jan 2026 20:29:42 +0100 Subject: [PATCH 27/36] Formatting --- third_party/z65/z65.c | 2239 +++++++++++++++++++++-------------------- 1 file changed, 1145 insertions(+), 1094 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index b89ca13f..68b4818a 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -9,105 +9,105 @@ */ /* 2OP */ -#define OP2_JE 0x01 -#define OP2_JL 0x02 -#define OP2_JG 0x03 -#define OP2_DEC_CHK 0x04 -#define OP2_INC_CHK 0x05 -#define OP2_JIN 0x06 -#define OP2_TEST 0x07 -#define OP2_OR 0x08 -#define OP2_AND 0x09 -#define OP2_STORE 0x0D -#define OP2_LOADW 0x0F -#define OP2_LOADB 0x10 -#define OP2_ADD 0x14 -#define OP2_SUB 0x15 -#define OP2_MUL 0x16 -#define OP2_DIV 0x17 -#define OP2_MOD 0x18 -#define OP2_TEST_ATTR 0x0A -#define OP2_SET_ATTR 0x0B -#define OP2_CLEAR_ATTR 0x0C -#define OP2_INSERT_OBJ 0x0E -#define OP2_GET_PROP 0x11 -#define OP2_GET_PROP_ADDR 0x12 -#define OP2_GET_NEXT_PROP 0x13 +#define OP2_JE 0x01 +#define OP2_JL 0x02 +#define OP2_JG 0x03 +#define OP2_DEC_CHK 0x04 +#define OP2_INC_CHK 0x05 +#define OP2_JIN 0x06 +#define OP2_TEST 0x07 +#define OP2_OR 0x08 +#define OP2_AND 0x09 +#define OP2_STORE 0x0D +#define OP2_LOADW 0x0F +#define OP2_LOADB 0x10 +#define OP2_ADD 0x14 +#define OP2_SUB 0x15 +#define OP2_MUL 0x16 +#define OP2_DIV 0x17 +#define OP2_MOD 0x18 +#define OP2_TEST_ATTR 0x0A +#define OP2_SET_ATTR 0x0B +#define OP2_CLEAR_ATTR 0x0C +#define OP2_INSERT_OBJ 0x0E +#define OP2_GET_PROP 0x11 +#define OP2_GET_PROP_ADDR 0x12 +#define OP2_GET_NEXT_PROP 0x13 /* 1OP opcodes (v1–v3) */ -#define OP1_JZ 0x00 -#define OP1_GET_SIBLING 0x01 -#define OP1_GET_CHILD 0x02 -#define OP1_GET_PARENT 0x03 -#define OP1_GET_PROP_LEN 0x04 -#define OP1_INC 0x05 -#define OP1_DEC 0x06 -#define OP1_PRINT_ADDR 0x07 -#define OP1_CALL_1S 0x08 -#define OP1_REMOVE_OBJ 0x09 -#define OP1_PRINT_OBJ 0x0A -#define OP1_RET 0x0B -#define OP1_JUMP 0x0C -#define OP1_PRINT_PADDR 0x0D -#define OP1_LOAD 0x0E -#define OP1_NOT 0x0F +#define OP1_JZ 0x00 +#define OP1_GET_SIBLING 0x01 +#define OP1_GET_CHILD 0x02 +#define OP1_GET_PARENT 0x03 +#define OP1_GET_PROP_LEN 0x04 +#define OP1_INC 0x05 +#define OP1_DEC 0x06 +#define OP1_PRINT_ADDR 0x07 +#define OP1_CALL_1S 0x08 +#define OP1_REMOVE_OBJ 0x09 +#define OP1_PRINT_OBJ 0x0A +#define OP1_RET 0x0B +#define OP1_JUMP 0x0C +#define OP1_PRINT_PADDR 0x0D +#define OP1_LOAD 0x0E +#define OP1_NOT 0x0F /* 0OP */ -#define OP0_RTRUE 0x00 -#define OP0_RFALSE 0x01 -#define OP0_PRINT 0x02 -#define OP0_PRINT_RET 0x03 -#define OP0_NOP 0x04 -#define OP0_SAVE 0x05 -#define OP0_RESTORE 0x06 -#define OP0_RESTART 0x07 -#define OP0_RET_POPPED 0x08 -#define OP0_POP 0x09 -#define OP0_QUIT 0x0A -#define OP0_NEW_LINE 0x0B -#define OP0_VERIFY 0x0D +#define OP0_RTRUE 0x00 +#define OP0_RFALSE 0x01 +#define OP0_PRINT 0x02 +#define OP0_PRINT_RET 0x03 +#define OP0_NOP 0x04 +#define OP0_SAVE 0x05 +#define OP0_RESTORE 0x06 +#define OP0_RESTART 0x07 +#define OP0_RET_POPPED 0x08 +#define OP0_POP 0x09 +#define OP0_QUIT 0x0A +#define OP0_NEW_LINE 0x0B +#define OP0_VERIFY 0x0D /* VAR */ -#define OPV_CALL 0x00 -#define OPV_JE 0x01 -#define OPV_JL 0x02 -#define OPV_JG 0x03 -#define OPV_DEC_CHK 0x04 -#define OPV_INC_CHK 0x05 -#define OPV_TEST 0x07 -#define OPV_STOREW 0x21 -#define OPV_STOREB 0x22 -#define OPV_PUT_PROP 0x23 -#define OPV_SREAD 0x24 -#define OPV_PRINT_CHAR 0x25 -#define OPV_PRINT_NUM 0x26 -#define OPV_RANDOM 0x27 -#define OPV_AND 0x09 -#define OPV_OR 0x08 -#define OPV_NOT 0x0B -#define OPV_INSERT_OBJ 0x0E -#define OPV_LOADW 0x0F -#define OPV_STORE 0x0D -#define OPV_CALL_EXT 0x20 -#define OPV_PUSH 0x28 -#define OPV_PULL 0x29 -#define OPV_LOADB 0x50 -#define OPV_ADD 0x54 -#define OPV_SUB 0x55 -#define OPV_MUL 0x56 +#define OPV_CALL 0x00 +#define OPV_JE 0x01 +#define OPV_JL 0x02 +#define OPV_JG 0x03 +#define OPV_DEC_CHK 0x04 +#define OPV_INC_CHK 0x05 +#define OPV_TEST 0x07 +#define OPV_STOREW 0x21 +#define OPV_STOREB 0x22 +#define OPV_PUT_PROP 0x23 +#define OPV_SREAD 0x24 +#define OPV_PRINT_CHAR 0x25 +#define OPV_PRINT_NUM 0x26 +#define OPV_RANDOM 0x27 +#define OPV_AND 0x09 +#define OPV_OR 0x08 +#define OPV_NOT 0x0B +#define OPV_INSERT_OBJ 0x0E +#define OPV_LOADW 0x0F +#define OPV_STORE 0x0D +#define OPV_CALL_EXT 0x20 +#define OPV_PUSH 0x28 +#define OPV_PULL 0x29 +#define OPV_LOADB 0x50 +#define OPV_ADD 0x54 +#define OPV_SUB 0x55 +#define OPV_MUL 0x56 /* ============================================================ * Header definitions * ============================================================ */ -#define HDR_VERSION 0x00 -#define HDR_PC 0x06 -#define HDR_DICT 0x08 -#define HDR_OBJ 0x0A -#define HDR_GLB 0x0C -#define HDR_STAT 0x0E -#define HDR_ABBR 0x18 +#define HDR_VERSION 0x00 +#define HDR_PC 0x06 +#define HDR_DICT 0x08 +#define HDR_OBJ 0x0A +#define HDR_GLB 0x0C +#define HDR_STAT 0x0E +#define HDR_ABBR 0x18 /* ============================================================ * Configuration @@ -152,7 +152,6 @@ typedef struct { * ============================================================ */ - static uint8_t dynamic_mem[DYNAMIC_MEM_MAX]; static uint16_t dynamic_size; @@ -180,18 +179,16 @@ static uint16_t dict_entry_count; static uint16_t object_table; static uint8_t alphabet; -static uint8_t zscii_esc=0; +static uint8_t zscii_esc = 0; static uint8_t zscii_high; -static uint8_t zalph[3][26] = {{'a','b','c','d','e','f','g','h','i','j','k', - 'l','m','n','o','p','q','r','s','t','u','v', - 'w','x','y','z'}, - {'A','B','C','D','E','F','G','H','I','J','K', - 'L','M','N','O','P','Q','R','S','T','U','V', - 'W','X','Y','Z'}, - {' ','\n','0','1','2','3','4','5','6','7','8', - '9','.',',','!','?','_','#','\'','\"','/', - '\\','-',':','(',')'}}; - +static uint8_t zalph[3][26] = { + { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }, + { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }, + { ' ', '\n', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', + ',', '!', '?', '_', '#', '\'', '\"', '/', '\\', '-', ':', '(', ')' } +}; static uint8_t abbrev_print; static uint8_t abbrev_table; @@ -213,7 +210,8 @@ static long int opcnt = 0; * ============================================================ */ -static inline void putc(char c){ +static inline void putc(char c) +{ cpm_conout(c); } @@ -222,7 +220,7 @@ static void crlf(void) cpm_printstring("\r\n"); } -static void spc(void) +static void spc(void) { cpm_conout(' '); } @@ -231,22 +229,26 @@ static void spc(void) static void print_hex(uint16_t val) { cpm_printstring("0x"); - for(uint8_t i = 4; i>0; i--) { - uint8_t nibble = (val >> ((i-1) << 2)) & 0xf; + for (uint8_t i = 4; i > 0; i--) { + uint8_t nibble = (val >> ((i - 1) << 2)) & 0xf; - if(nibble < 10) cpm_conout(nibble + '0'); - else cpm_conout(nibble-10 + 'A'); + if (nibble < 10) + cpm_conout(nibble + '0'); + else + cpm_conout(nibble - 10 + 'A'); } } static void print_hex_32(uint32_t val) { cpm_printstring("0x"); - for(uint8_t i = 8; i>0; i--) { - uint8_t nibble = (val >> ((i-1) << 2)) & 0xf; + for (uint8_t i = 8; i > 0; i--) { + uint8_t nibble = (val >> ((i - 1) << 2)) & 0xf; - if(nibble < 10) cpm_conout(nibble + '0'); - else cpm_conout(nibble-10 + 'A'); + if (nibble < 10) + cpm_conout(nibble + '0'); + else + cpm_conout(nibble - 10 + 'A'); } } #endif @@ -258,21 +260,20 @@ static void fatal(const char *s) cpm_warmboot(); } - -static uint8_t read_line(char *buf){ - uint8_t len=0; - for(;;){ - char c=cpm_conin(); - - /* force lowercase */ - if (c >= 'A' && c <= 'Z') - c = c - 'A' + 'a'; - - - if(c=='\r'||c=='\n'){ - crlf(); - buf[len]=0; - /*cpm_printstring("Read line: "); +static uint8_t read_line(char *buf) +{ + uint8_t len = 0; + for (;;) { + char c = cpm_conin(); + + /* force lowercase */ + if (c >= 'A' && c <= 'Z') + c = c - 'A' + 'a'; + + if (c == '\r' || c == '\n') { + crlf(); + buf[len] = 0; + /*cpm_printstring("Read line: "); crlf(); for(uint8_t i=0; i<=len; i++) { print_hex(buf[i]); @@ -280,17 +281,17 @@ static uint8_t read_line(char *buf){ } cpm_printstring("---END---"); crlf();*/ - return len; - } - if(c==8 && len){ - len--; - //putc(8); putc(' '); putc(8); - continue; - } - if(lendata[(i<<7)+j]=dma[j]; - } - record++; - cpm_fcb.r = record; + for (uint8_t i = 0; i < 4; i++) { + cpm_set_dma(&dma); + cpm_read_random(&cpm_fcb); + for (uint8_t j = 0; j < 128; j++) { + p->data[(i << 7) + j] = dma[j]; + } + record++; + cpm_fcb.r = record; } - p->page=page; - p->valid=1; + p->page = page; + p->valid = 1; } -static Page *get_page(uint16_t page){ - for(uint8_t i=0;i>9); - data = p->data[a&0x1FF]; +static uint8_t zm_read8(uint32_t a) +{ + uint8_t data; + if (a < dynamic_size) { + data = dynamic_mem[a]; + } else { + Page *p = get_page(a >> 9); + data = p->data[a & 0x1FF]; } -/* if(a>0x4687 && a<0x468f) { + /* if(a>0x4687 && a<0x468f) { cpm_printstring("Read addr: "); print_hex(a); cpm_printstring(" data: "); @@ -356,18 +359,19 @@ static uint8_t zm_read8(uint32_t a){ return data; } -static uint16_t zm_read16(uint32_t a){ - return ((uint16_t)zm_read8(a)<<8)|zm_read8(a+1); +static uint16_t zm_read16(uint32_t a) +{ + return ((uint16_t)zm_read8(a) << 8) | zm_read8(a + 1); } -static void zm_write8(uint32_t a,uint8_t v){ - if(a>=dynamic_size) { - crlf(); - //print_hex(a); - fatal(" Illegal write address"); - +static void zm_write8(uint32_t a, uint8_t v) +{ + if (a >= dynamic_size) { + crlf(); + //print_hex(a); + fatal(" Illegal write address"); } - dynamic_mem[a]=v; + dynamic_mem[a] = v; } /* ============================================================ @@ -375,35 +379,38 @@ static void zm_write8(uint32_t a,uint8_t v){ * ============================================================ */ -static void push(int16_t v){ - stack[sp++]=v; +static void push(int16_t v) +{ + stack[sp++] = v; } -static uint16_t pop(void) { +static uint16_t pop(void) +{ uint16_t val; val = stack[--sp]; return val; } -static uint16_t get_var(uint8_t v, uint8_t indirect){ - if(v==0) { - uint16_t val; - if(indirect) - val = (sp > 0) ? stack[sp - 1] : 0; - else - val = pop(); - return val; +static uint16_t get_var(uint8_t v, uint8_t indirect) +{ + if (v == 0) { + uint16_t val; + if (indirect) + val = (sp > 0) ? stack[sp - 1] : 0; + else + val = pop(); + return val; } - if(v<16) { -/* cpm_printstring("Local "); + if (v < 16) { + /* cpm_printstring("Local "); printi(v-1); cpm_printstring(" read as "); print_hex(frames[fp-1].locals[v-1]); cpm_printstring(" fp: "); printi(fp); crlf();*/ - return frames[fp-1].locals[v-1]; + return frames[fp - 1].locals[v - 1]; } - uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); + uint16_t a = (hdr[HDR_GLB] << 8) + hdr[HDR_GLB + 1] + 2 * (v - 16); uint16_t ret_data = zm_read16(a); #ifdef DEBUG cpm_printstring("Read global variable "); @@ -413,116 +420,122 @@ static uint16_t get_var(uint8_t v, uint8_t indirect){ cpm_printstring(" address: "); print_hex(a); crlf(); -#endif +#endif return ret_data; } -static void set_var(uint8_t v,uint16_t val, uint8_t indirect) { - if(v==0) { - if(indirect) { - if(sp > 0) stack[sp - 1] = val; - else push(val); - } else { - push(val); - } - - } - else if(v<16) { - frames[fp-1].locals[v-1]=val; - /*cpm_printstring("Local "); +static void set_var(uint8_t v, uint16_t val, uint8_t indirect) +{ + if (v == 0) { + if (indirect) { + if (sp > 0) + stack[sp - 1] = val; + else + push(val); + } else { + push(val); + } + + } else if (v < 16) { + frames[fp - 1].locals[v - 1] = val; + /*cpm_printstring("Local "); printi(v-1); cpm_printstring(" set to "); print_hex(val); cpm_printstring(" fp: "); printi(fp); crlf();*/ + } else { + uint16_t a = (hdr[HDR_GLB] << 8) + hdr[HDR_GLB + 1] + 2 * (v - 16); + zm_write8(a, val >> 8); + zm_write8(a + 1, val & 0xFF); + + //cpm_printstring("Write global variable "); + //print_hex(v); + //spc(); + //print_hex(val); + //spc(); + //print_hex(a); + //crlf(); } - else{ - uint16_t a = (hdr[HDR_GLB]<<8) + hdr[HDR_GLB+1] + 2*(v-16); - zm_write8(a,val>>8); - zm_write8(a+1,val&0xFF); - - //cpm_printstring("Write global variable "); - //print_hex(v); - //spc(); - //print_hex(val); - //spc(); - //print_hex(a); - //crlf(); - - - } - - } - /* ============================================================ * Operand decoding * ============================================================ */ -enum{OP_LARGE,OP_SMALL,OP_VAR,OP_OMIT}; +enum { OP_LARGE, OP_SMALL, OP_VAR, OP_OMIT }; static uint16_t operands[MAX_OPERANDS]; static uint8_t operand_count; -static uint16_t read_operand(uint8_t t, uint8_t indirect){ - uint16_t value=0; - if(t==OP_LARGE){pc+=2;value = zm_read16(pc-2);} - if(t==OP_SMALL)value = zm_read8(pc++); - if(t==OP_VAR) { - uint8_t var_num = zm_read8(pc++); - if(indirect) value = var_num; - else value = get_var(var_num, 0); - } - return value; +static uint16_t read_operand(uint8_t t, uint8_t indirect) +{ + uint16_t value = 0; + if (t == OP_LARGE) { + pc += 2; + value = zm_read16(pc - 2); + } + if (t == OP_SMALL) + value = zm_read8(pc++); + if (t == OP_VAR) { + uint8_t var_num = zm_read8(pc++); + if (indirect) + value = var_num; + else + value = get_var(var_num, 0); + } + return value; } - -static void decode_operands(uint8_t spec, uint8_t indirect){ - operand_count=0; - for(int s=6;s>=0;s-=2){ - uint8_t t=(spec>>s)&3; - if(t==OP_OMIT) break; - operands[operand_count++]=read_operand(t, indirect); +static void decode_operands(uint8_t spec, uint8_t indirect) +{ + operand_count = 0; + for (int s = 6; s >= 0; s -= 2) { + uint8_t t = (spec >> s) & 3; + if (t == OP_OMIT) + break; + operands[operand_count++] = read_operand(t, indirect); } } - /* ============================================================ * Branching * ============================================================ */ -static void branch(uint8_t cond){ - uint8_t b=zm_read8(pc++); +static void branch(uint8_t cond) +{ + uint8_t b = zm_read8(pc++); int16_t off; - if(b&0x40) off=b&0x3F; - else{ - off=((b&0x3F)<<8)|zm_read8(pc++); - // Sign extension for 14-bit long offset - if(off&0x2000) off|=0xC000; + if (b & 0x40) + off = b & 0x3F; + else { + off = ((b & 0x3F) << 8) | zm_read8(pc++); + // Sign extension for 14-bit long offset + if (off & 0x2000) + off |= 0xC000; } uint8_t take_branch = 0; - if(b & 0x80) { - if(cond) take_branch = 1; - } - else { - if(!cond) take_branch = 1; + if (b & 0x80) { + if (cond) + take_branch = 1; + } else { + if (!cond) + take_branch = 1; } - if(take_branch) { - if(off==0) { - z_ret(0); - } - else if(off==1) { - z_ret(1); - } - else pc+=off-2; + if (take_branch) { + if (off == 0) { + z_ret(0); + } else if (off == 1) { + z_ret(1); + } else + pc += off - 2; } } @@ -531,106 +544,105 @@ static void branch(uint8_t cond){ * ============================================================ */ -static void print_zstring(uint32_t addr){ - while(1){ - uint16_t w=zm_read16(addr); - addr+=2; - //print_hex(w); - for(int i=10;i>=0;i-=5){ - uint8_t c=(w>>i)&0x1F; - - if(abbrev_print == 1) { - uint16_t string_addr; - alphabet = 0; - string_addr = zm_read16(abbrev_base+(((abbrev_table<<5)+c)<<1)); - abbrev_print = 0; - print_zstring(string_addr<<1); - alphabet = 0; - } - else if(zscii_esc == 1) { - zscii_high = c; - zscii_esc = 2; - } - else if(zscii_esc == 2) { - putc((zscii_high << 5) | c); - zscii_esc = 0; - } - else if(alphabet == 2 && c==6) { - // ZSCII escape - zscii_esc = 1; - alphabet = 0; - } - else if(c>=6) { - putc(zalph[alphabet][c-6]); - alphabet = 0; - } - else if(c==4) { - alphabet = 1; - } - else if(c==5) { - alphabet = 2; - } - else if((c>0) && (c<4)) { - abbrev_print = 1; - abbrev_table = c-1; - } - else if(c==0) putc(' '); - - } - if(w&0x8000) { - alphabet = 0; - break; - } +static void print_zstring(uint32_t addr) +{ + while (1) { + uint16_t w = zm_read16(addr); + addr += 2; + //print_hex(w); + for (int i = 10; i >= 0; i -= 5) { + uint8_t c = (w >> i) & 0x1F; + + if (abbrev_print == 1) { + uint16_t string_addr; + alphabet = 0; + string_addr = zm_read16(abbrev_base + + (((abbrev_table << 5) + c) << 1)); + abbrev_print = 0; + print_zstring(string_addr << 1); + alphabet = 0; + } else if (zscii_esc == 1) { + zscii_high = c; + zscii_esc = 2; + } else if (zscii_esc == 2) { + putc((zscii_high << 5) | c); + zscii_esc = 0; + } else if (alphabet == 2 && c == 6) { + // ZSCII escape + zscii_esc = 1; + alphabet = 0; + } else if (c >= 6) { + putc(zalph[alphabet][c - 6]); + alphabet = 0; + } else if (c == 4) { + alphabet = 1; + } else if (c == 5) { + alphabet = 2; + } else if ((c > 0) && (c < 4)) { + abbrev_print = 1; + abbrev_table = c - 1; + } else if (c == 0) + putc(' '); + } + if (w & 0x8000) { + alphabet = 0; + break; + } } } -static void print_num(int16_t v){ +static void print_num(int16_t v) +{ char buf[6]; - uint8_t i=0; - - if(v<0){ putc('-'); v=-v; } - do{ - buf[i++]='0'+(v%10); - v/=10; - }while(v); - while(i--) putc(buf[i]); + uint8_t i = 0; + + if (v < 0) { + putc('-'); + v = -v; + } + do { + buf[i++] = '0' + (v % 10); + v /= 10; + } while (v); + while (i--) + putc(buf[i]); } // Dictionary -static void dict_init(void){ - dict_addr = hdr[HDR_DICT]<<8 | hdr[HDR_DICT+1]; -// cpm_printstring("Dict addr "); -// print_hex(dict_addr); +static void dict_init(void) +{ + dict_addr = hdr[HDR_DICT] << 8 | hdr[HDR_DICT + 1]; + // cpm_printstring("Dict addr "); + // print_hex(dict_addr); dict_sep_count = zm_read8(dict_addr++); -// cpm_printstring(" Dict sep cnt "); -// printi(dict_sep_count); - for(uint8_t i=0;i= 'A' && c <= 'Z') - // c = c - 'A' + 'a'; - - if (c >= 'a' && c <= 'z') { - zchars[zi++] = (c - 'a') + 6; - } - else { - /* shift to A2 */ - if (zi < 6) - zchars[zi++] = 5; - if (zi < 6) - zchars[zi++] = encode_a2(c); - } + char c = *s++; + + /* force lowercase */ + //if (c >= 'A' && c <= 'Z') + // c = c - 'A' + 'a'; + + if (c >= 'a' && c <= 'z') { + zchars[zi++] = (c - 'a') + 6; + } else { + /* shift to A2 */ + if (zi < 6) + zchars[zi++] = 5; + if (zi < 6) + zchars[zi++] = encode_a2(c); + } } /* pad with 5 */ while (zi < 6) - zchars[zi++] = 5; + zchars[zi++] = 5; } uint16_t dict_lookup(const char *word) @@ -676,7 +687,7 @@ uint16_t dict_lookup(const char *word) //spc(); //print_hex(w1); //crlf(); - + //cpm_printstring("sep: "); //printi(sep); //cpm_printstring(" entry_len: "); @@ -684,49 +695,49 @@ uint16_t dict_lookup(const char *word) //cpm_printstring(" count: "); //printi(count); //crlf(); - - uint16_t e = dict_addr+2; + + uint16_t e = dict_addr + 2; //cpm_printstring("Starting search at address "); //print_hex(e); //crlf(); for (uint16_t i = 0; i < dict_entry_count; i++) { - //uint16_t e = dict + i * entry_len; - if (zm_read16(e) == w0 && zm_read16(e + 2) == w1) { - //cpm_printstring("Found match at address"); - //print_hex(e); - //crlf(); - return e; - - } - - e += dict_entry_len; + //uint16_t e = dict + i * entry_len; + if (zm_read16(e) == w0 && zm_read16(e + 2) == w1) { + //cpm_printstring("Found match at address"); + //print_hex(e); + //crlf(); + return e; + } + + e += dict_entry_len; } return 0; } - - // Tokenization -static uint8_t is_sep(char c){ +static uint8_t is_sep(char c) +{ //cpm_printstring("is_sep: "); //cpm_conout(c); //crlf(); - for(uint8_t i=0;i MAX_TOKENS) max_tok = MAX_TOKENS; + + if (max_tok > MAX_TOKENS) + max_tok = MAX_TOKENS; /*for(uint8_t i=0; i>8); - zm_write8(entry+1, dict & 0xff); - zm_write8(entry+2, word_len); - zm_write8(entry+3, start+1);//1); - - count++; + while (in[i] && count < max_tok) { + while (is_sep(in[i])) + i++; + if (!in[i]) + break; + + uint8_t start = i; + char word[10] = { 0 }; + uint8_t dict_len = 0; + uint8_t word_len = 0; + + while (in[i] && !is_sep(in[i])) { + if (dict_len < 7) + word[dict_len++] = in[i]; + word_len++; + i++; + } + + uint16_t dict = dict_lookup(word); + + uint16_t entry = parse_buf + 2 + (count << 2); + zm_write8(entry, dict >> 8); + zm_write8(entry + 1, dict & 0xff); + zm_write8(entry + 2, word_len); + zm_write8(entry + 3, start + 1); //1); + + count++; } - zm_write8(parse_buf+1,count); + zm_write8(parse_buf + 1, count); //uint8_t x; //crlf(); - /* cpm_printstring("Parse buffer: "); + /* cpm_printstring("Parse buffer: "); crlf(); for(x=0; x<(count<<2)+2; x++) { print_hex(zm_read8(parse_buf+x)); crlf(); }*/ - /* + /* cpm_printstring("Text buffer: "); crlf(); x=0; @@ -791,7 +804,6 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) return count; } - // Objects static uint16_t obj_addr(uint8_t obj) @@ -799,61 +811,73 @@ static uint16_t obj_addr(uint8_t obj) return object_table + 62 + (obj - 1) * 9; } -static uint8_t obj_test_attr(uint8_t obj, uint8_t attr){ +static uint8_t obj_test_attr(uint8_t obj, uint8_t attr) +{ uint16_t a = obj_addr(obj) + (attr >> 3); return zm_read8(a) & (0x80 >> (attr & 7)); } -static void obj_set_attr(uint8_t obj, uint8_t attr){ +static void obj_set_attr(uint8_t obj, uint8_t attr) +{ uint16_t a = obj_addr(obj) + (attr >> 3); - if(obj != 0) zm_write8(a, zm_read8(a) | (0x80 >> (attr & 7))); + if (obj != 0) + zm_write8(a, zm_read8(a) | (0x80 >> (attr & 7))); } -static void obj_clear_attr(uint8_t obj, uint8_t attr){ +static void obj_clear_attr(uint8_t obj, uint8_t attr) +{ uint16_t a = obj_addr(obj) + (attr >> 3); zm_write8(a, zm_read8(a) & ~(0x80 >> (attr & 7))); } -static uint8_t obj_parent(uint8_t obj){ +static uint8_t obj_parent(uint8_t obj) +{ return zm_read8(obj_addr(obj) + 4); } -static uint8_t obj_sibling(uint8_t obj){ +static uint8_t obj_sibling(uint8_t obj) +{ return zm_read8(obj_addr(obj) + 5); } -static uint8_t obj_child(uint8_t obj){ +static uint8_t obj_child(uint8_t obj) +{ return zm_read8(obj_addr(obj) + 6); } -static void obj_remove(uint8_t obj){ - if(!obj) return; +static void obj_remove(uint8_t obj) +{ + if (!obj) + return; uint8_t parent = obj_parent(obj); - if (!parent) return; + if (!parent) + return; uint16_t paddr = obj_addr(parent) + 6; uint8_t cur = zm_read8(paddr); if (cur == obj) { - zm_write8(paddr, obj_sibling(obj)); + zm_write8(paddr, obj_sibling(obj)); } else { - while (cur) { - uint16_t caddr = obj_addr(cur) + 5; - uint8_t sib = zm_read8(caddr); - if (sib == obj) { - zm_write8(caddr, obj_sibling(obj)); - break; - } - cur = sib; - } + while (cur) { + uint16_t caddr = obj_addr(cur) + 5; + uint8_t sib = zm_read8(caddr); + if (sib == obj) { + zm_write8(caddr, obj_sibling(obj)); + break; + } + cur = sib; + } } zm_write8(obj_addr(obj) + 4, 0); zm_write8(obj_addr(obj) + 5, 0); } -static void obj_insert(uint8_t obj, uint8_t dest){ - if(obj == 0 || dest == 0) return; +static void obj_insert(uint8_t obj, uint8_t dest) +{ + if (obj == 0 || dest == 0) + return; obj_remove(obj); uint16_t daddr = obj_addr(dest) + 6; @@ -862,175 +886,188 @@ static void obj_insert(uint8_t obj, uint8_t dest){ zm_write8(daddr, obj); } - -static uint16_t obj_prop_table(uint8_t obj){ +static uint16_t obj_prop_table(uint8_t obj) +{ return zm_read16(obj_addr(obj) + 7); } -static uint16_t obj_prop_start(uint8_t obj){ +static uint16_t obj_prop_start(uint8_t obj) +{ uint16_t p = obj_prop_table(obj); return p + 1 + 2 * zm_read8(p); } -static uint16_t obj_find_prop(uint8_t obj, uint8_t prop){ +static uint16_t obj_find_prop(uint8_t obj, uint8_t prop) +{ uint16_t p = obj_prop_start(obj); while (1) { - uint8_t h = zm_read8(p++); - if (!h) return 0; + uint8_t h = zm_read8(p++); + if (!h) + return 0; - uint8_t num = h & 0x1F; - uint8_t len = (h >> 5) + 1; + uint8_t num = h & 0x1F; + uint8_t len = (h >> 5) + 1; - if (num == prop) return p; - p += len; + if (num == prop) + return p; + p += len; } } -static uint16_t obj_get_prop(uint8_t obj, uint8_t prop){ +static uint16_t obj_get_prop(uint8_t obj, uint8_t prop) +{ uint16_t p = obj_find_prop(obj, prop); if (!p) { - return zm_read16(object_table + (prop - 1) * 2); + return zm_read16(object_table + (prop - 1) * 2); } uint8_t len = ((zm_read8(p - 1) >> 5) & 7) + 1; - if (len == 1) return zm_read8(p); + if (len == 1) + return zm_read8(p); return zm_read16(p); } -static uint8_t obj_get_prop_len(uint16_t addr){ - if (!addr) return 0; +static uint8_t obj_get_prop_len(uint16_t addr) +{ + if (!addr) + return 0; return ((zm_read8(addr - 1) >> 5) & 7) + 1; } -static void obj_put_prop(uint8_t obj, uint8_t prop, uint16_t val){ +static void obj_put_prop(uint8_t obj, uint8_t prop, uint16_t val) +{ uint16_t p = obj_find_prop(obj, prop); - + if (!p) { - // property must exist - return; + // property must exist + return; } uint8_t len = ((zm_read8(p - 1) >> 5) & 7) + 1; if (len == 1) { - zm_write8(p, (uint8_t)val); + zm_write8(p, (uint8_t)val); } else { - zm_write8(p, val >> 8); - zm_write8(p + 1, val & 0xFF); + zm_write8(p, val >> 8); + zm_write8(p + 1, val & 0xFF); } } -void write_save_sector(FCB *fcb, void *dmaptr) { +void write_save_sector(FCB *fcb, void *dmaptr) +{ cpm_set_dma(dmaptr); cpm_write_sequential(fcb); } -void add_save_byte(FCB *fcb, uint8_t *writeSector, uint8_t data) { +void add_save_byte(FCB *fcb, uint8_t *writeSector, uint8_t data) +{ writeSector[w_addr++] = data; - if(w_addr == 0x80) { - write_save_sector(fcb, writeSector); - w_addr = 0; + if (w_addr == 0x80) { + write_save_sector(fcb, writeSector); + w_addr = 0; } } -void write_zero_block(FCB *fcb, uint8_t *writeSector, uint8_t zero_cnt) { +void write_zero_block(FCB *fcb, uint8_t *writeSector, uint8_t zero_cnt) +{ add_save_byte(fcb, writeSector, 0x00); add_save_byte(fcb, writeSector, zero_cnt); } // Saving and loading -uint8_t save_game(void) { +uint8_t save_game(void) +{ FCB saveFile; char filename_input[14]; - - filename_input[0]=13; - filename_input[1]=0; + + filename_input[0] = 13; + filename_input[1] = 0; cpm_printstring("Enter filename: "); cpm_readline((uint8_t *)filename_input); crlf(); cpm_set_dma(&saveFile); - if(!cpm_parse_filename(&filename_input[2])) { - return 0; + if (!cpm_parse_filename(&filename_input[2])) { + return 0; } - if(cpm_make_file(&saveFile)) { - return 0; + if (cpm_make_file(&saveFile)) { + return 0; } uint16_t enc = 0; - + // Write delta of dynamic ram to file uint16_t cmp_addr = 0; cpm_fcb.r = 0; uint8_t writeSector[128]; - w_addr=0; - uint8_t zero_cnt=0; - - while(cmp_addr < dynamic_size) { - // Read a sector from file - uint8_t checkSector[128]; - cpm_set_dma(&checkSector); - cpm_read_random(&cpm_fcb); - cpm_fcb.r++; - // Compare byte by byte with ram - uint8_t next_len = (dynamic_size-cmp_addr)>128?128: - (dynamic_size-cmp_addr); - for(uint8_t i=0; i 128 ? + 128 : + (dynamic_size - cmp_addr); + for (uint8_t i = 0; i < next_len; i++) { + uint8_t diff = dynamic_mem[cmp_addr] ^ checkSector[i]; + if (diff) { + if (zero_cnt != 0) { + write_zero_block(&saveFile, writeSector, zero_cnt); + enc += zero_cnt; + zero_cnt = 0; + } + add_save_byte(&saveFile, writeSector, diff); + enc++; + } else { + zero_cnt++; + if (zero_cnt == 0x80) { + write_zero_block(&saveFile, writeSector, zero_cnt); + enc += zero_cnt; + zero_cnt = 0; + } + } + cmp_addr++; + } } // Write trailing zeroes - if(zero_cnt != 0) { - write_zero_block(&saveFile, writeSector, zero_cnt); - enc+=zero_cnt; + if (zero_cnt != 0) { + write_zero_block(&saveFile, writeSector, zero_cnt); + enc += zero_cnt; } - + // Write frames add_save_byte(&saveFile, writeSector, fp); - for(uint8_t i = 0; i> 24)); - add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 16)); - add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 8)); - add_save_byte(&saveFile, writeSector, (frames[i].return_pc & 0xFF)); - - add_save_byte(&saveFile, writeSector, frames[i].store_var ); - - add_save_byte(&saveFile, writeSector, frames[i].num_locals); - for(uint8_t j = 0; j< MAX_LOCALS; j++) { - add_save_byte(&saveFile, writeSector, (frames[i].locals[j] >> 8)); - add_save_byte(&saveFile, writeSector, (frames[i].locals[j] & 0xFF)); - } - - add_save_byte(&saveFile, writeSector, (frames[i].saved_sp >> 8)); - add_save_byte(&saveFile, writeSector, (frames[i].saved_sp & 0xFF)); - + for (uint8_t i = 0; i < fp + 2; i++) { + add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 24)); + add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 16)); + add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 8)); + add_save_byte(&saveFile, writeSector, (frames[i].return_pc & 0xFF)); + + add_save_byte(&saveFile, writeSector, frames[i].store_var); + + add_save_byte(&saveFile, writeSector, frames[i].num_locals); + for (uint8_t j = 0; j < MAX_LOCALS; j++) { + add_save_byte(&saveFile, writeSector, (frames[i].locals[j] >> 8)); + add_save_byte(&saveFile, writeSector, (frames[i].locals[j] & 0xFF)); + } + + add_save_byte(&saveFile, writeSector, (frames[i].saved_sp >> 8)); + add_save_byte(&saveFile, writeSector, (frames[i].saved_sp & 0xFF)); } // Write stack - add_save_byte(&saveFile, writeSector, (sp>>8)); + add_save_byte(&saveFile, writeSector, (sp >> 8)); add_save_byte(&saveFile, writeSector, (sp & 0xFF)); - - for(uint16_t i = 0; i> 8)); - add_save_byte(&saveFile, writeSector, (stack[i] & 0xFF)); + + for (uint16_t i = 0; i < sp; i++) { + add_save_byte(&saveFile, writeSector, (stack[i] >> 8)); + add_save_byte(&saveFile, writeSector, (stack[i] & 0xFF)); } crlf(); // Save PC @@ -1040,71 +1077,73 @@ uint8_t save_game(void) { add_save_byte(&saveFile, writeSector, (pc & 0xFF)); // Perform a final write if necessary - - if(w_addr != 0) { - write_save_sector(&saveFile, writeSector); + + if (w_addr != 0) { + write_save_sector(&saveFile, writeSector); } - + cpm_close_file(&saveFile); return 1; } -uint8_t read_save_byte(FCB *fcb, uint8_t *restoreSector) { +uint8_t read_save_byte(FCB *fcb, uint8_t *restoreSector) +{ uint8_t data; // Refill buffer if out of data - if(w_addr == 0x80) { - cpm_set_dma(restoreSector); - cpm_read_random(fcb); - fcb->r++; - w_addr = 0; + if (w_addr == 0x80) { + cpm_set_dma(restoreSector); + cpm_read_random(fcb); + fcb->r++; + w_addr = 0; } - + data = restoreSector[w_addr++]; return data; } -uint8_t read_game_byte(uint8_t *r_addr) { +uint8_t read_game_byte(uint8_t *r_addr) +{ uint8_t data; // Refill buffer if out of data - if((*r_addr) == 0x80) { - cpm_set_dma(&dma); - cpm_read_random(&cpm_fcb); - cpm_fcb.r++; - (*r_addr) = 0; + if ((*r_addr) == 0x80) { + cpm_set_dma(&dma); + cpm_read_random(&cpm_fcb); + cpm_fcb.r++; + (*r_addr) = 0; } - + data = dma[(*r_addr)]; (*r_addr) = (*r_addr) + 1; return data; } - -uint8_t restore_game(void) { +uint8_t restore_game(void) +{ FCB saveFile; char filename_input[14]; - - filename_input[0]=13; - filename_input[1]=0; + + filename_input[0] = 13; + filename_input[1] = 0; cpm_printstring("Enter filename: "); cpm_readline((uint8_t *)filename_input); crlf(); cpm_set_dma(&saveFile); - if(!cpm_parse_filename(&filename_input[2])) { - return 0; + if (!cpm_parse_filename(&filename_input[2])) { + return 0; } saveFile.cr = 0; - if(cpm_open_file(&saveFile)) { - return 0; + if (cpm_open_file(&saveFile)) { + return 0; } saveFile.r = 0; // Restore dynamic ram from file uint16_t cmp_addr = 0; - + cpm_fcb.r = 0; uint8_t restoreSector[128]; uint8_t gameFileSector[128]; @@ -1113,55 +1152,53 @@ uint8_t restore_game(void) { w_addr = 0x80; // trigger sector read uint8_t r_addr = 0x80; uint8_t gameFileAddr = 0x80; - + // Restore dynamic memory - while(cmp_addr < dynamic_size) { - - uint8_t data = read_save_byte(&saveFile, restoreSector); - - if(data == 0x00) { - uint8_t zero_cnt = read_save_byte(&saveFile, restoreSector); - - for(uint8_t i=0; ireturn_pc; - sp=f->saved_sp; - if(f->store_var==0) { - push(v); - } - else set_var(f->store_var,v, 0); +static void z_ret(uint16_t v) +{ + CallFrame *f = &frames[--fp]; + pc = f->return_pc; + sp = f->saved_sp; + if (f->store_var == 0) { + push(v); + } else + set_var(f->store_var, v, 0); } -static void store_result(uint16_t v, uint8_t indirect){ - uint8_t var=zm_read8(pc++); +static void store_result(uint16_t v, uint8_t indirect) +{ + uint8_t var = zm_read8(pc++); set_var(var, v, indirect); } @@ -1201,13 +1240,14 @@ static uint16_t rng_next(void) x ^= x << 8; rng_state = x & 0x7fff; - + return rng_state; } -static void step(void){ - uint8_t op=zm_read8(pc++); - +static void step(void) +{ + uint8_t op = zm_read8(pc++); + #ifdef DEBUG printi(opcnt++); spc(); @@ -1220,72 +1260,73 @@ static void step(void){ cpm_printstring(" FP: "); print_hex(fp); cpm_printstring(" [SP]: "); - print_hex(stack[sp-1]); + print_hex(stack[sp - 1]); crlf(); #endif - + /* -------- 2OP -------- */ - if(op<0x80){ - uint8_t t1=(op&0x40)?OP_VAR:OP_SMALL; - uint8_t t2=(op&0x20)?OP_VAR:OP_SMALL; - uint8_t oc = op & 0x1f; - if(oc == OP2_INC_CHK || oc == OP2_DEC_CHK) t1=OP_VAR; - uint8_t var_num = zm_read8(pc); - uint8_t indirect = ((oc == OP2_INC_CHK && t1 == OP_VAR)|| - (oc == OP2_DEC_CHK && t1 == OP_VAR)); - uint8_t d_indirect = !(op == 0x45 || op == 0x65 || - op == 0x44 || op == 0x64); - operands[0]=read_operand(t1, indirect & d_indirect); - operands[1]=read_operand(t2, 0); - switch(oc){ - case OP2_JE: - branch(operands[0]==operands[1]); - break; - case OP2_JL: - branch((int16_t)operands[0]<(int16_t)operands[1]); - break; - case OP2_JG: - //cpm_printstring("OP2_JG - op1: "); - //print_hex(operands[0]); - //cpm_printstring(" op2: "); - //print_hex(operands[1]); - //crlf(); - branch((int16_t)operands[0]>(int16_t)operands[1]); - break; - case OP2_JIN: { - uint8_t parent; - parent = obj_parent(operands[0]); - branch(parent == operands[1]); - break; - } - case OP2_DEC_CHK: { - int16_t value = (int16_t)get_var(operands[0],1); - value--; - set_var(operands[0],(uint16_t)value,1); - branch(value<(int16_t)operands[1]); - break; - } - case OP2_INC_CHK: { - int16_t value = (int16_t)get_var(operands[0],1); - value++; - set_var(operands[0],value,1); - branch((int16_t)value>(int16_t)operands[1]); - break; - } - case OP2_TEST: - branch((operands[0]&operands[1])==operands[1]); - break; - case OP2_OR: - store_result(operands[0]|operands[1],indirect); - break; - case OP2_AND: - store_result(operands[0]&operands[1],indirect); - break; - case OP2_STORE: - set_var(operands[0],operands[1], 1); - break; - case OP2_LOADW: - /*cpm_printstring("OP2_LOADW address: "); + if (op < 0x80) { + uint8_t t1 = (op & 0x40) ? OP_VAR : OP_SMALL; + uint8_t t2 = (op & 0x20) ? OP_VAR : OP_SMALL; + uint8_t oc = op & 0x1f; + if (oc == OP2_INC_CHK || oc == OP2_DEC_CHK) + t1 = OP_VAR; + uint8_t var_num = zm_read8(pc); + uint8_t indirect = ((oc == OP2_INC_CHK && t1 == OP_VAR) || + (oc == OP2_DEC_CHK && t1 == OP_VAR)); + uint8_t d_indirect = + !(op == 0x45 || op == 0x65 || op == 0x44 || op == 0x64); + operands[0] = read_operand(t1, indirect & d_indirect); + operands[1] = read_operand(t2, 0); + switch (oc) { + case OP2_JE: + branch(operands[0] == operands[1]); + break; + case OP2_JL: + branch((int16_t)operands[0] < (int16_t)operands[1]); + break; + case OP2_JG: + //cpm_printstring("OP2_JG - op1: "); + //print_hex(operands[0]); + //cpm_printstring(" op2: "); + //print_hex(operands[1]); + //crlf(); + branch((int16_t)operands[0] > (int16_t)operands[1]); + break; + case OP2_JIN: { + uint8_t parent; + parent = obj_parent(operands[0]); + branch(parent == operands[1]); + break; + } + case OP2_DEC_CHK: { + int16_t value = (int16_t)get_var(operands[0], 1); + value--; + set_var(operands[0], (uint16_t)value, 1); + branch(value < (int16_t)operands[1]); + break; + } + case OP2_INC_CHK: { + int16_t value = (int16_t)get_var(operands[0], 1); + value++; + set_var(operands[0], value, 1); + branch((int16_t)value > (int16_t)operands[1]); + break; + } + case OP2_TEST: + branch((operands[0] & operands[1]) == operands[1]); + break; + case OP2_OR: + store_result(operands[0] | operands[1], indirect); + break; + case OP2_AND: + store_result(operands[0] & operands[1], indirect); + break; + case OP2_STORE: + set_var(operands[0], operands[1], 1); + break; + case OP2_LOADW: + /*cpm_printstring("OP2_LOADW address: "); print_hex(operands[0]+2*operands[1]); cpm_printstring(" data: "); print_hex(zm_read16(operands[0]+2*operands[1])); @@ -1293,469 +1334,474 @@ static void step(void){ print_hex(operands[0]); spc(); print_hex(operands[1]); - crlf();*/ + crlf();*/ - - store_result(zm_read16(operands[0]+2*operands[1]), indirect); - break; - case OP2_LOADB: - /*cpm_printstring("OP2_LOADB address: "); + store_result(zm_read16(operands[0] + 2 * operands[1]), indirect); + break; + case OP2_LOADB: + /*cpm_printstring("OP2_LOADB address: "); print_hex(operands[0]+operands[1]); cpm_printstring(" data: "); print_hex(zm_read8(operands[0]+operands[1])); - crlf()*/; - store_result(zm_read8(operands[0]+operands[1]), indirect); - break; - case OP2_ADD: - store_result((int16_t)operands[0]+(int16_t)operands[1], - indirect); - break; - case OP2_SUB: - store_result((int16_t)operands[0]-(int16_t)operands[1], - indirect); - break; - case OP2_MUL: - store_result((int16_t)operands[0]*(int16_t)operands[1], - indirect); - break; - case OP2_DIV: - //cpm_printstring("OP2_DIV - op1: "); - //print_hex(operands[0]); - //cpm_printstring(" op2: "); - //print_hex(operands[1]); - //crlf(); - store_result((int16_t)operands[0]/(int16_t)operands[1], - indirect); - break; - case OP2_MOD: - store_result((int16_t)operands[0]%(int16_t)operands[1], - indirect); - break; - case OP2_TEST_ATTR: - branch(obj_test_attr(operands[0], operands[1])); - break; - - case OP2_SET_ATTR: - obj_set_attr(operands[0], operands[1]); - break; - - case OP2_CLEAR_ATTR: - obj_clear_attr(operands[0], operands[1]); - break; - - case OP2_INSERT_OBJ: - obj_insert(operands[0], operands[1]); - break; - - case OP2_GET_PROP: - store_result(obj_get_prop(operands[0], operands[1]), indirect); - break; - - case OP2_GET_PROP_ADDR: { - uint16_t p = obj_find_prop(operands[0], operands[1]); - store_result(p, indirect); - break; - } - - case OP2_GET_NEXT_PROP: { - uint8_t obj = (uint8_t)operands[0]; - uint8_t prop = (uint8_t)operands[1]; - uint16_t addr; - - if (prop==0) { - addr = obj_prop_start(obj); - } else { - addr = obj_find_prop(obj, prop); - if(!addr) { - store_result(0, indirect); - break; - } - addr+=obj_get_prop_len(addr); - } - - uint8_t next_header = zm_read8(addr); - - if(next_header == 0) store_result(0, indirect); - else store_result(next_header & 0x1F, indirect); - - break; - } - - default: - #ifdef DEBUG - crlf(); - printi(op); - spc(); - print_hex(pc); - spc(); - #endif - fatal(" - Non-implemented opcode!!!"); - } - return; + crlf()*/ + ; + store_result(zm_read8(operands[0] + operands[1]), indirect); + break; + case OP2_ADD: + store_result((int16_t)operands[0] + (int16_t)operands[1], indirect); + break; + case OP2_SUB: + store_result((int16_t)operands[0] - (int16_t)operands[1], indirect); + break; + case OP2_MUL: + store_result((int16_t)operands[0] * (int16_t)operands[1], indirect); + break; + case OP2_DIV: + //cpm_printstring("OP2_DIV - op1: "); + //print_hex(operands[0]); + //cpm_printstring(" op2: "); + //print_hex(operands[1]); + //crlf(); + store_result((int16_t)operands[0] / (int16_t)operands[1], indirect); + break; + case OP2_MOD: + store_result((int16_t)operands[0] % (int16_t)operands[1], indirect); + break; + case OP2_TEST_ATTR: + branch(obj_test_attr(operands[0], operands[1])); + break; + + case OP2_SET_ATTR: + obj_set_attr(operands[0], operands[1]); + break; + + case OP2_CLEAR_ATTR: + obj_clear_attr(operands[0], operands[1]); + break; + + case OP2_INSERT_OBJ: + obj_insert(operands[0], operands[1]); + break; + + case OP2_GET_PROP: + store_result(obj_get_prop(operands[0], operands[1]), indirect); + break; + + case OP2_GET_PROP_ADDR: { + uint16_t p = obj_find_prop(operands[0], operands[1]); + store_result(p, indirect); + break; + } + + case OP2_GET_NEXT_PROP: { + uint8_t obj = (uint8_t)operands[0]; + uint8_t prop = (uint8_t)operands[1]; + uint16_t addr; + + if (prop == 0) { + addr = obj_prop_start(obj); + } else { + addr = obj_find_prop(obj, prop); + if (!addr) { + store_result(0, indirect); + break; + } + addr += obj_get_prop_len(addr); + } + + uint8_t next_header = zm_read8(addr); + + if (next_header == 0) + store_result(0, indirect); + else + store_result(next_header & 0x1F, indirect); + + break; + } + + default: +#ifdef DEBUG + crlf(); + printi(op); + spc(); + print_hex(pc); + spc(); +#endif + fatal(" - Non-implemented opcode!!!"); + } + return; } /* -------- 1OP -------- */ - if(op<0xB0){ - uint8_t type=(op>>4)&3; - uint8_t oc=op&0x0F; - uint8_t indirect = (oc == OP1_LOAD); - if(type!=OP_OMIT) operands[0]=read_operand(type, 0); - switch(oc){ - case OP1_JUMP: - pc+=(int16_t)operands[0]-2; - break; - case OP1_PRINT_ADDR: - print_zstring(operands[0]); - break; - case OP1_PRINT_OBJ: { - uint16_t obj = operands[0]; - - if(obj==0) break; - - uint16_t entry = obj_addr(obj); - uint16_t prop_table = zm_read16(entry + 7); - uint8_t name_len = zm_read8(prop_table); - if(name_len==0) break; - print_zstring(prop_table+1); - break; - } - case OP1_REMOVE_OBJ: - obj_remove(operands[0]); - break; - case OP1_GET_CHILD: { - uint8_t result; - if(operands[0]==0) result = 0; - else result = obj_child(operands[0]); - store_result(result, indirect); - branch(result!=0); - break; - } - case OP1_GET_SIBLING: { - uint8_t result; - if(operands[0]==0) result = 0; - else result = obj_sibling(operands[0]); - store_result(result, indirect); - branch(result!=0); - break; - } - - - case OP1_GET_PARENT: { - uint8_t result; - if(operands[0]==0) result = 0; - else result = obj_parent(operands[0]); - store_result(result, indirect); - break; - } - case OP1_GET_PROP_LEN: { - uint8_t result; - if(operands[0]==0) result = 0; - else result = obj_get_prop_len(operands[0]); - store_result(result, indirect); - break; - } - case OP1_LOAD: { - uint16_t result; - result = get_var(operands[0], indirect); - store_result(result, 0); - break; - } - case OP1_NOT: { - uint16_t result; - result = ~operands[0]; - store_result(result, indirect); - break; - } - case OP1_RET: - z_ret(operands[0]); - break; - case OP1_INC: { - uint16_t value = get_var(operands[0], indirect); - value++; - set_var(operands[0], value, indirect); - break; - } - case OP1_DEC: { - uint16_t value = get_var(operands[0], indirect); - value--; - set_var(operands[0], value, indirect); - break; - } - case OP1_JZ: - branch(operands[0]==0); - break; - case OP1_PRINT_PADDR: { - uint32_t addr = (uint32_t)operands[0] << 1; - print_zstring(addr); - break; - } - default: - #ifdef DEBUG - crlf(); - printi(op); - spc(); - print_hex(pc); - #endif - fatal(" - Non-implemented opcode!!!"); - } - return; + if (op < 0xB0) { + uint8_t type = (op >> 4) & 3; + uint8_t oc = op & 0x0F; + uint8_t indirect = (oc == OP1_LOAD); + if (type != OP_OMIT) + operands[0] = read_operand(type, 0); + switch (oc) { + case OP1_JUMP: + pc += (int16_t)operands[0] - 2; + break; + case OP1_PRINT_ADDR: + print_zstring(operands[0]); + break; + case OP1_PRINT_OBJ: { + uint16_t obj = operands[0]; + + if (obj == 0) + break; + + uint16_t entry = obj_addr(obj); + uint16_t prop_table = zm_read16(entry + 7); + uint8_t name_len = zm_read8(prop_table); + if (name_len == 0) + break; + print_zstring(prop_table + 1); + break; + } + case OP1_REMOVE_OBJ: + obj_remove(operands[0]); + break; + case OP1_GET_CHILD: { + uint8_t result; + if (operands[0] == 0) + result = 0; + else + result = obj_child(operands[0]); + store_result(result, indirect); + branch(result != 0); + break; + } + case OP1_GET_SIBLING: { + uint8_t result; + if (operands[0] == 0) + result = 0; + else + result = obj_sibling(operands[0]); + store_result(result, indirect); + branch(result != 0); + break; + } + + case OP1_GET_PARENT: { + uint8_t result; + if (operands[0] == 0) + result = 0; + else + result = obj_parent(operands[0]); + store_result(result, indirect); + break; + } + case OP1_GET_PROP_LEN: { + uint8_t result; + if (operands[0] == 0) + result = 0; + else + result = obj_get_prop_len(operands[0]); + store_result(result, indirect); + break; + } + case OP1_LOAD: { + uint16_t result; + result = get_var(operands[0], indirect); + store_result(result, 0); + break; + } + case OP1_NOT: { + uint16_t result; + result = ~operands[0]; + store_result(result, indirect); + break; + } + case OP1_RET: + z_ret(operands[0]); + break; + case OP1_INC: { + uint16_t value = get_var(operands[0], indirect); + value++; + set_var(operands[0], value, indirect); + break; + } + case OP1_DEC: { + uint16_t value = get_var(operands[0], indirect); + value--; + set_var(operands[0], value, indirect); + break; + } + case OP1_JZ: + branch(operands[0] == 0); + break; + case OP1_PRINT_PADDR: { + uint32_t addr = (uint32_t)operands[0] << 1; + print_zstring(addr); + break; + } + default: +#ifdef DEBUG + crlf(); + printi(op); + spc(); + print_hex(pc); +#endif + fatal(" - Non-implemented opcode!!!"); + } + return; } /* 0OP */ - if(op<0xC0) { - switch(op&0x0F){ - case OP0_RTRUE: - z_ret(1); - break; - case OP0_RFALSE: - z_ret(0); - break; - case OP0_PRINT: - print_zstring(pc); - while(!(zm_read16(pc)&0x8000)) pc+=2; - pc+=2; - break; - case OP0_PRINT_RET: - print_zstring(pc); - while(!(zm_read16(pc)&0x8000)) pc+=2; - pc+=2; - crlf(); - z_ret(1); - break; - - case OP0_NOP: - break; - - case OP0_SAVE: - branch(save_game()); - break; - - case OP0_RESTORE: - branch(restore_game()); - break; - - case OP0_RESTART: - restart(); - break; - - case OP0_RET_POPPED: - z_ret(pop()); - break; - - case OP0_POP: - pop(); - break; - - case OP0_NEW_LINE: - crlf(); - break; - - case OP0_QUIT: - cpm_warmboot(); - break; - case OP0_VERIFY: - // Not supported, just assume it's OK - branch(1); - break; - default: - #ifdef DEBUG - crlf(); - printi(op); - #endif - fatal(" - Non-implemented opcode!!!"); - } - return; + if (op < 0xC0) { + switch (op & 0x0F) { + case OP0_RTRUE: + z_ret(1); + break; + case OP0_RFALSE: + z_ret(0); + break; + case OP0_PRINT: + print_zstring(pc); + while (!(zm_read16(pc) & 0x8000)) + pc += 2; + pc += 2; + break; + case OP0_PRINT_RET: + print_zstring(pc); + while (!(zm_read16(pc) & 0x8000)) + pc += 2; + pc += 2; + crlf(); + z_ret(1); + break; + + case OP0_NOP: + break; + + case OP0_SAVE: + branch(save_game()); + break; + + case OP0_RESTORE: + branch(restore_game()); + break; + + case OP0_RESTART: + restart(); + break; + + case OP0_RET_POPPED: + z_ret(pop()); + break; + + case OP0_POP: + pop(); + break; + + case OP0_NEW_LINE: + crlf(); + break; + + case OP0_QUIT: + cpm_warmboot(); + break; + case OP0_VERIFY: + // Not supported, just assume it's OK + branch(1); + break; + default: +#ifdef DEBUG + crlf(); + printi(op); +#endif + fatal(" - Non-implemented opcode!!!"); + } + return; } /* -------- VAR -------- */ uint8_t var_opcode = op & 0x1f; uint8_t indirect = (var_opcode == OPV_PULL); - + decode_operands(zm_read8(pc++), indirect); - if((op & 0xE0)==0xE0) var_opcode += 0x20; - if((op & 0xD0)==0xD0) var_opcode += 0x40; - switch(var_opcode) { + if ((op & 0xE0) == 0xE0) + var_opcode += 0x20; + if ((op & 0xD0) == 0xD0) + var_opcode += 0x40; + switch (var_opcode) { case OPV_CALL_EXT: case OPV_CALL: { - if (operands[0] == 0) { - uint8_t sv = zm_read8(pc++); - set_var(sv, 0, indirect); - return; - } - - CallFrame *f = &frames[fp++]; - - uint8_t sv = zm_read8(pc++); - f->store_var = sv; - f->return_pc = pc; - f->saved_sp = sp; - - uint32_t addr = (uint32_t)operands[0]<<1; - f->num_locals = zm_read8(addr++); - - for (uint8_t i = 0; i < f->num_locals; i++) { - f->locals[i] = zm_read16(addr); - addr += 2; - } - - /* overwrite locals with arguments */ - uint8_t argc = operand_count - 1; - if (argc > f->num_locals) - argc = f->num_locals; - for (uint8_t i = 0; i < argc; i++){ - f->locals[i] = operands[i + 1]; - } - - pc = addr; // + 2 * f->num_locals; - break; + if (operands[0] == 0) { + uint8_t sv = zm_read8(pc++); + set_var(sv, 0, indirect); + return; + } + + CallFrame *f = &frames[fp++]; + + uint8_t sv = zm_read8(pc++); + f->store_var = sv; + f->return_pc = pc; + f->saved_sp = sp; + + uint32_t addr = (uint32_t)operands[0] << 1; + f->num_locals = zm_read8(addr++); + + for (uint8_t i = 0; i < f->num_locals; i++) { + f->locals[i] = zm_read16(addr); + addr += 2; + } + + /* overwrite locals with arguments */ + uint8_t argc = operand_count - 1; + if (argc > f->num_locals) + argc = f->num_locals; + for (uint8_t i = 0; i < argc; i++) { + f->locals[i] = operands[i + 1]; + } + + pc = addr; // + 2 * f->num_locals; + break; } case OPV_JE: - if(operand_count == 2) - branch(operands[0] == operands[1]); - else if(operand_count == 3) - branch(operands[0] == operands[1] || - operands[0] == operands[2]); - else if(operand_count == 4) - branch(operands[0] == operands[1] || - operands[0] == operands[2] || - operands[0] == operands[3]); - break; + if (operand_count == 2) + branch(operands[0] == operands[1]); + else if (operand_count == 3) + branch(operands[0] == operands[1] || operands[0] == operands[2]); + else if (operand_count == 4) + branch(operands[0] == operands[1] || operands[0] == operands[2] || + operands[0] == operands[3]); + break; case OPV_JL: - branch((int16_t)operands[0] < (int16_t)operands[1]); - break; + branch((int16_t)operands[0] < (int16_t)operands[1]); + break; case OPV_JG: - branch((int16_t)operands[0] > (int16_t)operands[1]); - break; + branch((int16_t)operands[0] > (int16_t)operands[1]); + break; case OPV_TEST: - branch((operands[0] & operands[1]) == operands[1]); - break; + branch((operands[0] & operands[1]) == operands[1]); + break; case OPV_STOREW: - zm_write8(operands[0]+2*operands[1],operands[2]>>8); - zm_write8(operands[0]+2*operands[1]+1,operands[2]); - break; + zm_write8(operands[0] + 2 * operands[1], operands[2] >> 8); + zm_write8(operands[0] + 2 * operands[1] + 1, operands[2]); + break; case OPV_STOREB: - zm_write8(operands[0]+operands[1],operands[2]); - break; + zm_write8(operands[0] + operands[1], operands[2]); + break; case OPV_STORE: - set_var(operands[0],operands[1], 0); - break; + set_var(operands[0], operands[1], 0); + break; case OPV_PRINT_CHAR: - putc((char)operands[0]); - break; + putc((char)operands[0]); + break; case OPV_PRINT_NUM: - print_num((int16_t)operands[0]); - break; + print_num((int16_t)operands[0]); + break; case OPV_PUSH: - push(operands[0]); - break; + push(operands[0]); + break; case OPV_PULL: { - uint16_t value = pop(); + uint16_t value = pop(); - set_var(operands[0], value, 1); + set_var(operands[0], value, 1); - break; + break; } case OPV_SREAD: { - uint16_t text = operands[0]; - uint16_t parse = operands[1]; - /*cpm_printstring("Text addr: "); + uint16_t text = operands[0]; + uint16_t parse = operands[1]; + /*cpm_printstring("Text addr: "); print_hex(text); cpm_printstring(" Parse addr: "); print_hex(parse); crlf();*/ - char line[INPUT_MAX]={0}; - uint8_t len = read_line(line); - uint8_t max = zm_read8(text); - if(len>max) len=max; - - //zm_write8(text+1,len); - for(uint8_t i=0;i max) + len = max; + + //zm_write8(text+1,len); + for (uint8_t i = 0; i < len; i++) + zm_write8(text + 1 + i, line[i]); + + zm_write8(text + 1 + len, 0); + + tokenize(line, parse, text); + /*cpm_printstring("RAW PARSE: "); for(uint8_t i=0; i<6; i++) { print_hex(zm_read8(parse+i)); spc(); }*/ - break; } + break; + } case OPV_PUT_PROP: - obj_put_prop((uint8_t)operands[0],(uint8_t)operands[1], - operands[2]); - break; + obj_put_prop((uint8_t)operands[0], (uint8_t)operands[1], operands[2]); + break; case OPV_OR: - store_result(operands[0] | operands[1], indirect); - break; + store_result(operands[0] | operands[1], indirect); + break; case OPV_AND: - store_result(operands[0] & operands[1], indirect); - break; + store_result(operands[0] & operands[1], indirect); + break; case OPV_RANDOM: { - int16_t range = (int16_t)operands[0]; - if(range == 0) { - rng_state = (uint16_t)pc; - store_result(0, indirect); - break; - } - if(range < 0) { - rng_state = (uint16_t)(-range); - store_result(0, indirect); - break; - } - - uint16_t r = rng_next(); - uint16_t result = (r % range) + 1; - store_result(result, indirect); - break; - } + int16_t range = (int16_t)operands[0]; + if (range == 0) { + rng_state = (uint16_t)pc; + store_result(0, indirect); + break; + } + if (range < 0) { + rng_state = (uint16_t)(-range); + store_result(0, indirect); + break; + } + + uint16_t r = rng_next(); + uint16_t result = (r % range) + 1; + store_result(result, indirect); + break; + } case OPV_LOADW: - store_result(zm_read16(operands[0]+2*operands[1]), indirect); - break; + store_result(zm_read16(operands[0] + 2 * operands[1]), indirect); + break; case OPV_LOADB: - store_result(zm_read8(operands[0]+operands[1]), indirect); - break; + store_result(zm_read8(operands[0] + operands[1]), indirect); + break; case OPV_MUL: - store_result((int16_t)operands[0]*(int16_t)operands[1], indirect); - break; - case OPV_ADD: - store_result((int16_t)operands[0]+(int16_t)operands[1], - indirect); - break; - case OPV_SUB: - store_result((int16_t)operands[0]-(int16_t)operands[1], - indirect); - break; - case OPV_INC_CHK:{ - int16_t value = (int16_t)get_var(operands[0],1); - value++; - set_var(operands[0],(uint16_t)value,1); - branch(value>(int16_t)operands[1]); - break; + store_result((int16_t)operands[0] * (int16_t)operands[1], indirect); + break; + case OPV_ADD: + store_result((int16_t)operands[0] + (int16_t)operands[1], indirect); + break; + case OPV_SUB: + store_result((int16_t)operands[0] - (int16_t)operands[1], indirect); + break; + case OPV_INC_CHK: { + int16_t value = (int16_t)get_var(operands[0], 1); + value++; + set_var(operands[0], (uint16_t)value, 1); + branch(value > (int16_t)operands[1]); + break; } - case OPV_DEC_CHK:{ - int16_t value = (int16_t)get_var(operands[0],1); - value--; - set_var(operands[0],(uint16_t)value,1); - branch(value<(int16_t)operands[1]); - break; + case OPV_DEC_CHK: { + int16_t value = (int16_t)get_var(operands[0], 1); + value--; + set_var(operands[0], (uint16_t)value, 1); + branch(value < (int16_t)operands[1]); + break; } case OP2_INSERT_OBJ: - obj_insert(operands[0], operands[1]); - break; - + obj_insert(operands[0], operands[1]); + break; default: - crlf(); - printi(op); - fatal(" - Non-implemented opcode!!!"); - + crlf(); + printi(op); + fatal(" - Non-implemented opcode!!!"); } - } /* ============================================================ @@ -1763,58 +1809,63 @@ static void step(void){ * ============================================================ */ -int main(int agrv, char **argv){ +int main(int agrv, char **argv) +{ cpm_printstring("z65 - Z-machine v3 interpreter"); crlf(); crlf(); - + // Get story filename from commandline //for(uint8_t i=0; i<11; i++) // storyFile.f[i]=cpm_fcb.f[i]; //storyFile.dr = cpm_fcb.dr; cpm_fcb.cr = 0; - if(cpm_open_file(&cpm_fcb)) - fatal("Could not open input file!"); + if (cpm_open_file(&cpm_fcb)) + fatal("Could not open input file!"); cpm_set_dma(&hdr); cpm_read_sequential(&cpm_fcb); - - if(hdr[HDR_VERSION] != 3) - fatal("Only v3 files are supported!"); - dynamic_size=(hdr[HDR_STAT]<<8)|hdr[HDR_STAT+1]; + if (hdr[HDR_VERSION] != 3) + fatal("Only v3 files are supported!"); + + dynamic_size = (hdr[HDR_STAT] << 8) | hdr[HDR_STAT + 1]; //cpm_printstring("Dynamic size: "); //print_hex(dynamic_size); //crlf(); - for(uint16_t i=0; iDYNAMIC_MEM_MAX) while(1); + if (dynamic_size > DYNAMIC_MEM_MAX) + while (1) + ; - for(uint16_t i=0; i<128; i++) - dynamic_mem[i] = hdr[i]; + for (uint16_t i = 0; i < 128; i++) + dynamic_mem[i] = hdr[i]; - for(uint16_t i=128;i Date: Thu, 22 Jan 2026 07:47:45 +0100 Subject: [PATCH 28/36] Updates to reduce binary size --- third_party/z65/z65.c | 289 ++++++++++++++++++++---------------------- 1 file changed, 137 insertions(+), 152 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 68b4818a..a8468323 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -597,15 +597,16 @@ static void print_num(int16_t v) uint8_t i = 0; if (v < 0) { - putc('-'); - v = -v; + putc('-'); + v = -v; } - do { + printi(v); + /* do { buf[i++] = '0' + (v % 10); v /= 10; } while (v); while (i--) - putc(buf[i]); + putc(buf[i]);*/ } // Dictionary @@ -1244,6 +1245,17 @@ static uint16_t rng_next(void) return rng_state; } +static void unimplemented(uint8_t opcode) { +#ifdef DEBUG + crlf(); + printi(op); + spc(); + print_hex(pc); + spc(); +#endif + fatal("Non-implemented opcode"); +} + static void step(void) { uint8_t op = zm_read8(pc++); @@ -1538,14 +1550,8 @@ static void step(void) break; } default: -#ifdef DEBUG - crlf(); - printi(op); - spc(); - print_hex(pc); -#endif - fatal(" - Non-implemented opcode!!!"); - } + unimplemented(op); + } return; } /* 0OP */ @@ -1607,12 +1613,8 @@ static void step(void) branch(1); break; default: -#ifdef DEBUG - crlf(); - printi(op); -#endif - fatal(" - Non-implemented opcode!!!"); - } + unimplemented(op); + } return; } /* -------- VAR -------- */ @@ -1627,180 +1629,163 @@ static void step(void) switch (var_opcode) { case OPV_CALL_EXT: case OPV_CALL: { - if (operands[0] == 0) { - uint8_t sv = zm_read8(pc++); - set_var(sv, 0, indirect); - return; - } + if (operands[0] == 0) { + uint8_t sv = zm_read8(pc++); + set_var(sv, 0, indirect); + return; + } - CallFrame *f = &frames[fp++]; + CallFrame *f = &frames[fp++]; - uint8_t sv = zm_read8(pc++); - f->store_var = sv; - f->return_pc = pc; - f->saved_sp = sp; + uint8_t sv = zm_read8(pc++); + f->store_var = sv; + f->return_pc = pc; + f->saved_sp = sp; - uint32_t addr = (uint32_t)operands[0] << 1; - f->num_locals = zm_read8(addr++); + uint32_t addr = (uint32_t)operands[0] << 1; + f->num_locals = zm_read8(addr++); - for (uint8_t i = 0; i < f->num_locals; i++) { - f->locals[i] = zm_read16(addr); - addr += 2; - } + for (uint8_t i = 0; i < f->num_locals; i++) { + f->locals[i] = zm_read16(addr); + addr += 2; + } - /* overwrite locals with arguments */ - uint8_t argc = operand_count - 1; - if (argc > f->num_locals) - argc = f->num_locals; - for (uint8_t i = 0; i < argc; i++) { - f->locals[i] = operands[i + 1]; - } + /* overwrite locals with arguments */ + uint8_t argc = operand_count - 1; + if (argc > f->num_locals) + argc = f->num_locals; + for (uint8_t i = 0; i < argc; i++) { + f->locals[i] = operands[i + 1]; + } - pc = addr; // + 2 * f->num_locals; - break; + pc = addr; // + 2 * f->num_locals; + break; } case OPV_JE: - if (operand_count == 2) - branch(operands[0] == operands[1]); - else if (operand_count == 3) - branch(operands[0] == operands[1] || operands[0] == operands[2]); - else if (operand_count == 4) - branch(operands[0] == operands[1] || operands[0] == operands[2] || - operands[0] == operands[3]); - break; + if (operand_count == 2) + branch(operands[0] == operands[1]); + else if (operand_count == 3) + branch(operands[0] == operands[1] || + operands[0] == operands[2]); + else if (operand_count == 4) + branch(operands[0] == operands[1] || + operands[0] == operands[2] || + operands[0] == operands[3]); + break; case OPV_JL: - branch((int16_t)operands[0] < (int16_t)operands[1]); - break; + branch((int16_t)operands[0] < (int16_t)operands[1]); + break; case OPV_JG: - branch((int16_t)operands[0] > (int16_t)operands[1]); - break; + branch((int16_t)operands[0] > (int16_t)operands[1]); + break; case OPV_TEST: - branch((operands[0] & operands[1]) == operands[1]); - break; + branch((operands[0] & operands[1]) == operands[1]); + break; case OPV_STOREW: - zm_write8(operands[0] + 2 * operands[1], operands[2] >> 8); - zm_write8(operands[0] + 2 * operands[1] + 1, operands[2]); + zm_write8(operands[0] + 2 * operands[1], operands[2] >> 8); + zm_write8(operands[0] + 2 * operands[1] + 1, operands[2]); break; - case OPV_STOREB: - zm_write8(operands[0] + operands[1], operands[2]); - break; - + zm_write8(operands[0] + operands[1], operands[2]); + break; case OPV_STORE: - set_var(operands[0], operands[1], 0); - break; - + set_var(operands[0], operands[1], 0); + break; case OPV_PRINT_CHAR: - putc((char)operands[0]); - break; - + putc((char)operands[0]); + break; case OPV_PRINT_NUM: - print_num((int16_t)operands[0]); - break; - + print_num((int16_t)operands[0]); + break; case OPV_PUSH: - push(operands[0]); - break; - + push(operands[0]); + break; case OPV_PULL: { - uint16_t value = pop(); - - set_var(operands[0], value, 1); - - break; + uint16_t value = pop(); + set_var(operands[0], value, 1); + break; } case OPV_SREAD: { - uint16_t text = operands[0]; - uint16_t parse = operands[1]; - /*cpm_printstring("Text addr: "); - print_hex(text); - cpm_printstring(" Parse addr: "); - print_hex(parse); - crlf();*/ - char line[INPUT_MAX] = { 0 }; - uint8_t len = read_line(line); - uint8_t max = zm_read8(text); - if (len > max) - len = max; - - //zm_write8(text+1,len); - for (uint8_t i = 0; i < len; i++) - zm_write8(text + 1 + i, line[i]); - - zm_write8(text + 1 + len, 0); - - tokenize(line, parse, text); - /*cpm_printstring("RAW PARSE: "); - for(uint8_t i=0; i<6; i++) { - print_hex(zm_read8(parse+i)); - spc(); - }*/ - break; + uint16_t text = operands[0]; + uint16_t parse = operands[1]; + char line[INPUT_MAX] = { 0 }; + uint8_t len = read_line(line); + uint8_t max = zm_read8(text); + if (len > max) + len = max; + + //zm_write8(text+1,len); + for (uint8_t i = 0; i < len; i++) + zm_write8(text + 1 + i, line[i]); + + zm_write8(text + 1 + len, 0); + + tokenize(line, parse, text); + break; } case OPV_PUT_PROP: - obj_put_prop((uint8_t)operands[0], (uint8_t)operands[1], operands[2]); - break; + obj_put_prop((uint8_t)operands[0], ( + uint8_t)operands[1], operands[2]); + break; case OPV_OR: - store_result(operands[0] | operands[1], indirect); - break; - case OPV_AND: - store_result(operands[0] & operands[1], indirect); - break; - case OPV_RANDOM: { - int16_t range = (int16_t)operands[0]; - if (range == 0) { - rng_state = (uint16_t)pc; - store_result(0, indirect); + store_result(operands[0] | operands[1], indirect); break; - } - if (range < 0) { - rng_state = (uint16_t)(-range); - store_result(0, indirect); + case OPV_AND: + store_result(operands[0] & operands[1], indirect); break; - } + case OPV_RANDOM: { + int16_t range = (int16_t)operands[0]; + if (range == 0) { + rng_state = (uint16_t)pc; + store_result(0, indirect); + break; + } + if (range < 0) { + rng_state = (uint16_t)(-range); + store_result(0, indirect); + break; + } - uint16_t r = rng_next(); - uint16_t result = (r % range) + 1; - store_result(result, indirect); - break; + uint16_t r = rng_next(); + uint16_t result = (r % range) + 1; + store_result(result, indirect); + break; } case OPV_LOADW: - store_result(zm_read16(operands[0] + 2 * operands[1]), indirect); - break; + store_result(zm_read16(operands[0] + 2 * operands[1]), indirect); + break; case OPV_LOADB: - store_result(zm_read8(operands[0] + operands[1]), indirect); - break; + store_result(zm_read8(operands[0] + operands[1]), indirect); + break; case OPV_MUL: - store_result((int16_t)operands[0] * (int16_t)operands[1], indirect); - break; + store_result((int16_t)operands[0] * (int16_t)operands[1], indirect); + break; case OPV_ADD: - store_result((int16_t)operands[0] + (int16_t)operands[1], indirect); - break; + store_result((int16_t)operands[0] + (int16_t)operands[1], indirect); + break; case OPV_SUB: - store_result((int16_t)operands[0] - (int16_t)operands[1], indirect); - break; + store_result((int16_t)operands[0] - (int16_t)operands[1], indirect); + break; case OPV_INC_CHK: { - int16_t value = (int16_t)get_var(operands[0], 1); - value++; - set_var(operands[0], (uint16_t)value, 1); - branch(value > (int16_t)operands[1]); - break; + int16_t value = (int16_t)get_var(operands[0], 1); + value++; + set_var(operands[0], (uint16_t)value, 1); + branch(value > (int16_t)operands[1]); + break; } case OPV_DEC_CHK: { - int16_t value = (int16_t)get_var(operands[0], 1); - value--; - set_var(operands[0], (uint16_t)value, 1); - branch(value < (int16_t)operands[1]); - break; + int16_t value = (int16_t)get_var(operands[0], 1); + value--; + set_var(operands[0], (uint16_t)value, 1); + branch(value < (int16_t)operands[1]); + break; } case OP2_INSERT_OBJ: - obj_insert(operands[0], operands[1]); - break; + obj_insert(operands[0], operands[1]); + break; default: - crlf(); - printi(op); - fatal(" - Non-implemented opcode!!!"); + unimplemented(op); } } From 2f7322f4282a6fdf914cb87f9a046cea5679d6db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 22 Jan 2026 08:19:06 +0100 Subject: [PATCH 29/36] Dynamic allocation of memory using zmalloc. Fixed formatting --- third_party/z65/build.py | 3 +- third_party/z65/z65.c | 2478 +++++++++++++++++++------------------- 2 files changed, 1244 insertions(+), 1237 deletions(-) diff --git a/third_party/z65/build.py b/third_party/z65/build.py index 8d395fe3..d78b6d4b 100644 --- a/third_party/z65/build.py +++ b/third_party/z65/build.py @@ -4,6 +4,7 @@ llvmprogram( name="z65", + cflags=["-Ithird_party/zmalloc"], srcs=["./z65.c"], - deps=["lib+cpm65"], + deps=["lib+cpm65", "third_party/zmalloc+zmalloc"], ) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index a8468323..0f8d0e35 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -1,8 +1,10 @@ -/* Z-machine v1–v3 interpreter for CP/M-65 */ +/* Z-machine v3 interpreter for CP/M-65 */ #include #include #include "lib/printi.h" +#include "zmalloc.h" + /* ============================================================ * Opcode definitions * ============================================================ @@ -126,7 +128,7 @@ #define INPUT_MAX 80 #define MAX_TOKENS 16 -//#define DEBUG +// #define DEBUG /* ============================================================ * Structures @@ -134,17 +136,17 @@ */ typedef struct { - uint32_t return_pc; - uint8_t store_var; - uint8_t num_locals; - uint16_t locals[MAX_LOCALS]; - uint16_t saved_sp; + uint32_t return_pc; + uint8_t store_var; + uint8_t num_locals; + uint16_t locals[MAX_LOCALS]; + uint16_t saved_sp; } CallFrame; typedef struct { - uint16_t page; - uint8_t data[PAGE_SIZE]; - uint8_t valid; + uint16_t page; + uint8_t data[PAGE_SIZE]; + uint8_t valid; } Page; /* ============================================================ @@ -152,7 +154,8 @@ typedef struct { * ============================================================ */ -static uint8_t dynamic_mem[DYNAMIC_MEM_MAX]; +// static uint8_t dynamic_mem[DYNAMIC_MEM_MAX]; +static uint8_t *dynamic_mem; static uint16_t dynamic_size; static Page page_cache[NUM_PAGES]; @@ -166,7 +169,7 @@ static uint16_t sp; static CallFrame frames[MAX_FRAMES]; static uint8_t fp; -//static FCB storyFile; +// static FCB storyFile; static uint8_t dma[128]; static uint8_t hdr[128]; @@ -182,12 +185,12 @@ static uint8_t alphabet; static uint8_t zscii_esc = 0; static uint8_t zscii_high; static uint8_t zalph[3][26] = { - { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }, - { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }, - { ' ', '\n', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', - ',', '!', '?', '_', '#', '\'', '\"', '/', '\\', '-', ':', '(', ')' } + { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }, + { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }, + { ' ', '\n', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', + ',', '!', '?', '_', '#', '\'', '\"', '/', '\\', '-', ':', '(', ')' } }; static uint8_t abbrev_print; @@ -212,68 +215,68 @@ static long int opcnt = 0; static inline void putc(char c) { - cpm_conout(c); + cpm_conout(c); } static void crlf(void) { - cpm_printstring("\r\n"); + cpm_printstring("\r\n"); } static void spc(void) { - cpm_conout(' '); + cpm_conout(' '); } #ifdef DEBUG static void print_hex(uint16_t val) { - cpm_printstring("0x"); - for (uint8_t i = 4; i > 0; i--) { - uint8_t nibble = (val >> ((i - 1) << 2)) & 0xf; - - if (nibble < 10) - cpm_conout(nibble + '0'); - else - cpm_conout(nibble - 10 + 'A'); - } + cpm_printstring("0x"); + for (uint8_t i = 4; i > 0; i--) { + uint8_t nibble = (val >> ((i - 1) << 2)) & 0xf; + + if (nibble < 10) + cpm_conout(nibble + '0'); + else + cpm_conout(nibble - 10 + 'A'); + } } static void print_hex_32(uint32_t val) { - cpm_printstring("0x"); - for (uint8_t i = 8; i > 0; i--) { - uint8_t nibble = (val >> ((i - 1) << 2)) & 0xf; - - if (nibble < 10) - cpm_conout(nibble + '0'); - else - cpm_conout(nibble - 10 + 'A'); - } + cpm_printstring("0x"); + for (uint8_t i = 8; i > 0; i--) { + uint8_t nibble = (val >> ((i - 1) << 2)) & 0xf; + + if (nibble < 10) + cpm_conout(nibble + '0'); + else + cpm_conout(nibble - 10 + 'A'); + } } #endif static void fatal(const char *s) { - cpm_printstring(s); - crlf(); - cpm_warmboot(); + cpm_printstring(s); + crlf(); + cpm_warmboot(); } static uint8_t read_line(char *buf) { - uint8_t len = 0; - for (;;) { - char c = cpm_conin(); - - /* force lowercase */ - if (c >= 'A' && c <= 'Z') - c = c - 'A' + 'a'; - - if (c == '\r' || c == '\n') { - crlf(); - buf[len] = 0; - /*cpm_printstring("Read line: "); + uint8_t len = 0; + for (;;) { + char c = cpm_conin(); + + /* force lowercase */ + if (c >= 'A' && c <= 'Z') + c = c - 'A' + 'a'; + + if (c == '\r' || c == '\n') { + crlf(); + buf[len] = 0; + /*cpm_printstring("Read line: "); crlf(); for(uint8_t i=0; i<=len; i++) { print_hex(buf[i]); @@ -281,18 +284,18 @@ static uint8_t read_line(char *buf) } cpm_printstring("---END---"); crlf();*/ - return len; - } - if (c == 8 && len) { - len--; - //putc(8); putc(' '); putc(8); - continue; - } - if (len < INPUT_MAX - 1) { - buf[len++] = c; - //putc(c); + return len; + } + if (c == 8 && len) { + len--; + // putc(8); putc(' '); putc(8); + continue; + } + if (len < INPUT_MAX - 1) { + buf[len++] = c; + // putc(c); + } } - } } /* ============================================================ @@ -302,30 +305,30 @@ static uint8_t read_line(char *buf) static void load_page(Page *p, uint16_t page) { - uint16_t record = page << 2; - cpm_fcb.r = record; - for (uint8_t i = 0; i < 4; i++) { - cpm_set_dma(&dma); - cpm_read_random(&cpm_fcb); - for (uint8_t j = 0; j < 128; j++) { - p->data[(i << 7) + j] = dma[j]; - } - record++; + uint16_t record = page << 2; cpm_fcb.r = record; - } - p->page = page; - p->valid = 1; + for (uint8_t i = 0; i < 4; i++) { + cpm_set_dma(&dma); + cpm_read_random(&cpm_fcb); + for (uint8_t j = 0; j < 128; j++) { + p->data[(i << 7) + j] = dma[j]; + } + record++; + cpm_fcb.r = record; + } + p->page = page; + p->valid = 1; } static Page *get_page(uint16_t page) { - for (uint8_t i = 0; i < NUM_PAGES; i++) - if (page_cache[i].valid && page_cache[i].page == page) - return &page_cache[i]; - Page *p = &page_cache[next_victim]; - next_victim = (next_victim + 1) % NUM_PAGES; - load_page(p, page); - return p; + for (uint8_t i = 0; i < NUM_PAGES; i++) + if (page_cache[i].valid && page_cache[i].page == page) + return &page_cache[i]; + Page *p = &page_cache[next_victim]; + next_victim = (next_victim + 1) % NUM_PAGES; + load_page(p, page); + return p; } /* ============================================================ @@ -335,14 +338,14 @@ static Page *get_page(uint16_t page) static uint8_t zm_read8(uint32_t a) { - uint8_t data; - if (a < dynamic_size) { - data = dynamic_mem[a]; - } else { - Page *p = get_page(a >> 9); - data = p->data[a & 0x1FF]; - } - /* if(a>0x4687 && a<0x468f) { + uint8_t data; + if (a < dynamic_size) { + data = dynamic_mem[a]; + } else { + Page *p = get_page(a >> 9); + data = p->data[a & 0x1FF]; + } + /* if(a>0x4687 && a<0x468f) { cpm_printstring("Read addr: "); print_hex(a); cpm_printstring(" data: "); @@ -356,22 +359,22 @@ static uint8_t zm_read8(uint32_t a) print_hex(data); crlf(); }*/ - return data; + return data; } static uint16_t zm_read16(uint32_t a) { - return ((uint16_t)zm_read8(a) << 8) | zm_read8(a + 1); + return ((uint16_t)zm_read8(a) << 8) | zm_read8(a + 1); } static void zm_write8(uint32_t a, uint8_t v) { - if (a >= dynamic_size) { - crlf(); - //print_hex(a); - fatal(" Illegal write address"); - } - dynamic_mem[a] = v; + if (a >= dynamic_size) { + crlf(); + // print_hex(a); + fatal(" Illegal write address"); + } + dynamic_mem[a] = v; } /* ============================================================ @@ -381,83 +384,82 @@ static void zm_write8(uint32_t a, uint8_t v) static void push(int16_t v) { - stack[sp++] = v; + stack[sp++] = v; } static uint16_t pop(void) { - uint16_t val; - val = stack[--sp]; - return val; + uint16_t val; + val = stack[--sp]; + return val; } static uint16_t get_var(uint8_t v, uint8_t indirect) { - if (v == 0) { - uint16_t val; - if (indirect) - val = (sp > 0) ? stack[sp - 1] : 0; - else - val = pop(); - return val; - } - if (v < 16) { - /* cpm_printstring("Local "); + if (v == 0) { + uint16_t val; + if (indirect) + val = (sp > 0) ? stack[sp - 1] : 0; + else + val = pop(); + return val; + } + if (v < 16) { + /* cpm_printstring("Local "); printi(v-1); cpm_printstring(" read as "); print_hex(frames[fp-1].locals[v-1]); cpm_printstring(" fp: "); printi(fp); crlf();*/ - return frames[fp - 1].locals[v - 1]; - } - uint16_t a = (hdr[HDR_GLB] << 8) + hdr[HDR_GLB + 1] + 2 * (v - 16); - uint16_t ret_data = zm_read16(a); + return frames[fp - 1].locals[v - 1]; + } + uint16_t a = (hdr[HDR_GLB] << 8) + hdr[HDR_GLB + 1] + 2 * (v - 16); + uint16_t ret_data = zm_read16(a); #ifdef DEBUG - cpm_printstring("Read global variable "); - print_hex(v); - cpm_printstring(" data: "); - print_hex(ret_data); - cpm_printstring(" address: "); - print_hex(a); - crlf(); + cpm_printstring("Read global variable "); + print_hex(v); + cpm_printstring(" data: "); + print_hex(ret_data); + cpm_printstring(" address: "); + print_hex(a); + crlf(); #endif - return ret_data; + return ret_data; } static void set_var(uint8_t v, uint16_t val, uint8_t indirect) { - if (v == 0) { - if (indirect) { - if (sp > 0) - stack[sp - 1] = val; - else - push(val); - } else { - push(val); - } - - } else if (v < 16) { - frames[fp - 1].locals[v - 1] = val; - /*cpm_printstring("Local "); + if (v == 0) { + if (indirect) { + if (sp > 0) + stack[sp - 1] = val; + else + push(val); + } else { + push(val); + } + } else if (v < 16) { + frames[fp - 1].locals[v - 1] = val; + /*cpm_printstring("Local "); printi(v-1); cpm_printstring(" set to "); print_hex(val); cpm_printstring(" fp: "); printi(fp); crlf();*/ - } else { - uint16_t a = (hdr[HDR_GLB] << 8) + hdr[HDR_GLB + 1] + 2 * (v - 16); - zm_write8(a, val >> 8); - zm_write8(a + 1, val & 0xFF); - - //cpm_printstring("Write global variable "); - //print_hex(v); - //spc(); - //print_hex(val); - //spc(); - //print_hex(a); - //crlf(); - } + } else { + uint16_t a = (hdr[HDR_GLB] << 8) + hdr[HDR_GLB + 1] + 2 * (v - 16); + zm_write8(a, val >> 8); + zm_write8(a + 1, val & 0xFF); + + // cpm_printstring("Write global variable "); + // print_hex(v); + // spc(); + // print_hex(val); + // spc(); + // print_hex(a); + // crlf(); + } } /* ============================================================ @@ -472,32 +474,32 @@ static uint8_t operand_count; static uint16_t read_operand(uint8_t t, uint8_t indirect) { - uint16_t value = 0; - if (t == OP_LARGE) { - pc += 2; - value = zm_read16(pc - 2); - } - if (t == OP_SMALL) - value = zm_read8(pc++); - if (t == OP_VAR) { - uint8_t var_num = zm_read8(pc++); - if (indirect) - value = var_num; - else - value = get_var(var_num, 0); - } - return value; + uint16_t value = 0; + if (t == OP_LARGE) { + pc += 2; + value = zm_read16(pc - 2); + } + if (t == OP_SMALL) + value = zm_read8(pc++); + if (t == OP_VAR) { + uint8_t var_num = zm_read8(pc++); + if (indirect) + value = var_num; + else + value = get_var(var_num, 0); + } + return value; } static void decode_operands(uint8_t spec, uint8_t indirect) { - operand_count = 0; - for (int s = 6; s >= 0; s -= 2) { - uint8_t t = (spec >> s) & 3; - if (t == OP_OMIT) - break; - operands[operand_count++] = read_operand(t, indirect); - } + operand_count = 0; + for (int s = 6; s >= 0; s -= 2) { + uint8_t t = (spec >> s) & 3; + if (t == OP_OMIT) + break; + operands[operand_count++] = read_operand(t, indirect); + } } /* ============================================================ @@ -507,36 +509,36 @@ static void decode_operands(uint8_t spec, uint8_t indirect) static void branch(uint8_t cond) { - uint8_t b = zm_read8(pc++); - int16_t off; - - if (b & 0x40) - off = b & 0x3F; - else { - off = ((b & 0x3F) << 8) | zm_read8(pc++); - // Sign extension for 14-bit long offset - if (off & 0x2000) - off |= 0xC000; - } + uint8_t b = zm_read8(pc++); + int16_t off; + + if (b & 0x40) + off = b & 0x3F; + else { + off = ((b & 0x3F) << 8) | zm_read8(pc++); + // Sign extension for 14-bit long offset + if (off & 0x2000) + off |= 0xC000; + } - uint8_t take_branch = 0; + uint8_t take_branch = 0; - if (b & 0x80) { - if (cond) - take_branch = 1; - } else { - if (!cond) - take_branch = 1; - } + if (b & 0x80) { + if (cond) + take_branch = 1; + } else { + if (!cond) + take_branch = 1; + } - if (take_branch) { - if (off == 0) { - z_ret(0); - } else if (off == 1) { - z_ret(1); - } else - pc += off - 2; - } + if (take_branch) { + if (off == 0) { + z_ret(0); + } else if (off == 1) { + z_ret(1); + } else + pc += off - 2; + } } /* ============================================================ @@ -546,201 +548,201 @@ static void branch(uint8_t cond) static void print_zstring(uint32_t addr) { - while (1) { - uint16_t w = zm_read16(addr); - addr += 2; - //print_hex(w); - for (int i = 10; i >= 0; i -= 5) { - uint8_t c = (w >> i) & 0x1F; - - if (abbrev_print == 1) { - uint16_t string_addr; - alphabet = 0; - string_addr = zm_read16(abbrev_base + - (((abbrev_table << 5) + c) << 1)); - abbrev_print = 0; - print_zstring(string_addr << 1); - alphabet = 0; - } else if (zscii_esc == 1) { - zscii_high = c; - zscii_esc = 2; - } else if (zscii_esc == 2) { - putc((zscii_high << 5) | c); - zscii_esc = 0; - } else if (alphabet == 2 && c == 6) { - // ZSCII escape - zscii_esc = 1; - alphabet = 0; - } else if (c >= 6) { - putc(zalph[alphabet][c - 6]); - alphabet = 0; - } else if (c == 4) { - alphabet = 1; - } else if (c == 5) { - alphabet = 2; - } else if ((c > 0) && (c < 4)) { - abbrev_print = 1; - abbrev_table = c - 1; - } else if (c == 0) - putc(' '); - } - if (w & 0x8000) { - alphabet = 0; - break; + while (1) { + uint16_t w = zm_read16(addr); + addr += 2; + // print_hex(w); + for (int i = 10; i >= 0; i -= 5) { + uint8_t c = (w >> i) & 0x1F; + + if (abbrev_print == 1) { + uint16_t string_addr; + alphabet = 0; + string_addr = + zm_read16(abbrev_base + (((abbrev_table << 5) + c) << 1)); + abbrev_print = 0; + print_zstring(string_addr << 1); + alphabet = 0; + } else if (zscii_esc == 1) { + zscii_high = c; + zscii_esc = 2; + } else if (zscii_esc == 2) { + putc((zscii_high << 5) | c); + zscii_esc = 0; + } else if (alphabet == 2 && c == 6) { + // ZSCII escape + zscii_esc = 1; + alphabet = 0; + } else if (c >= 6) { + putc(zalph[alphabet][c - 6]); + alphabet = 0; + } else if (c == 4) { + alphabet = 1; + } else if (c == 5) { + alphabet = 2; + } else if ((c > 0) && (c < 4)) { + abbrev_print = 1; + abbrev_table = c - 1; + } else if (c == 0) + putc(' '); + } + if (w & 0x8000) { + alphabet = 0; + break; + } } - } } static void print_num(int16_t v) { - char buf[6]; - uint8_t i = 0; + char buf[6]; + uint8_t i = 0; - if (v < 0) { - putc('-'); - v = -v; - } - printi(v); - /* do { - buf[i++] = '0' + (v % 10); - v /= 10; - } while (v); - while (i--) - putc(buf[i]);*/ + if (v < 0) { + putc('-'); + v = -v; + } + printi(v); + /* do { + buf[i++] = '0' + (v % 10); + v /= 10; + } while (v); + while (i--) + putc(buf[i]);*/ } // Dictionary static void dict_init(void) { - dict_addr = hdr[HDR_DICT] << 8 | hdr[HDR_DICT + 1]; - // cpm_printstring("Dict addr "); - // print_hex(dict_addr); - dict_sep_count = zm_read8(dict_addr++); - // cpm_printstring(" Dict sep cnt "); - // printi(dict_sep_count); - for (uint8_t i = 0; i < dict_sep_count; i++) { - dict_seps[i] = zm_read8(dict_addr++); - //spc(); - //putc(dict_seps[i]); - //spc(); - } + dict_addr = hdr[HDR_DICT] << 8 | hdr[HDR_DICT + 1]; + // cpm_printstring("Dict addr "); + // print_hex(dict_addr); + dict_sep_count = zm_read8(dict_addr++); + // cpm_printstring(" Dict sep cnt "); + // printi(dict_sep_count); + for (uint8_t i = 0; i < dict_sep_count; i++) { + dict_seps[i] = zm_read8(dict_addr++); + // spc(); + // putc(dict_seps[i]); + // spc(); + } - dict_entry_len = zm_read8(dict_addr++); - //crlf(); - //cpm_printstring("Dict entry length: "); - //print_hex(dict_entry_len); - //crlf(); + dict_entry_len = zm_read8(dict_addr++); + // crlf(); + // cpm_printstring("Dict entry length: "); + // print_hex(dict_entry_len); + // crlf(); - dict_entry_count = zm_read16(dict_addr); - //cpm_printstring("Dict entry count:" ); - //print_hex(dict_entry_count); - //crlf(); + dict_entry_count = zm_read16(dict_addr); + // cpm_printstring("Dict entry count:" ); + // print_hex(dict_entry_count); + // crlf(); } static uint8_t encode_a2(char c) { - /* A2 table for v1–v3 */ - //const char *a2 = " \n0123456789.,!?_#'\"/\\-:()"; - for (uint8_t i = 0; zalph[2][i]; i++) { - if (zalph[2][i] == c) - return i; - } - return 0; /* space */ + /* A2 table for v1–v3 */ + // const char *a2 = " \n0123456789.,!?_#'\"/\\-:()"; + for (uint8_t i = 0; zalph[2][i]; i++) { + if (zalph[2][i] == c) + return i; + } + return 0; /* space */ } void encode_zchars(const char *s, uint8_t zchars[6]) { - uint8_t zi = 0; - - while (*s && zi < 6) { - char c = *s++; - - /* force lowercase */ - //if (c >= 'A' && c <= 'Z') - // c = c - 'A' + 'a'; - - if (c >= 'a' && c <= 'z') { - zchars[zi++] = (c - 'a') + 6; - } else { - /* shift to A2 */ - if (zi < 6) - zchars[zi++] = 5; - if (zi < 6) - zchars[zi++] = encode_a2(c); + uint8_t zi = 0; + + while (*s && zi < 6) { + char c = *s++; + + /* force lowercase */ + // if (c >= 'A' && c <= 'Z') + // c = c - 'A' + 'a'; + + if (c >= 'a' && c <= 'z') { + zchars[zi++] = (c - 'a') + 6; + } else { + /* shift to A2 */ + if (zi < 6) + zchars[zi++] = 5; + if (zi < 6) + zchars[zi++] = encode_a2(c); + } } - } - /* pad with 5 */ - while (zi < 6) - zchars[zi++] = 5; + /* pad with 5 */ + while (zi < 6) + zchars[zi++] = 5; } uint16_t dict_lookup(const char *word) { - uint8_t zchars[6]; - encode_zchars(word, zchars); - - uint16_t w0 = (zchars[0] << 10) | (zchars[1] << 5) | zchars[2]; - uint16_t w1 = (zchars[3] << 10) | (zchars[4] << 5) | zchars[5] | 0x8000; - //cpm_printstring("dict lookup "); - //cpm_printstring(word); - //print_hex(w0); - //spc(); - //print_hex(w1); - //crlf(); - - //cpm_printstring("sep: "); - //printi(sep); - //cpm_printstring(" entry_len: "); - //printi(entry_len); - //cpm_printstring(" count: "); - //printi(count); - //crlf(); - - uint16_t e = dict_addr + 2; - - //cpm_printstring("Starting search at address "); - //print_hex(e); - //crlf(); - for (uint16_t i = 0; i < dict_entry_count; i++) { - //uint16_t e = dict + i * entry_len; - if (zm_read16(e) == w0 && zm_read16(e + 2) == w1) { - //cpm_printstring("Found match at address"); - //print_hex(e); - //crlf(); - return e; - } + uint8_t zchars[6]; + encode_zchars(word, zchars); + + uint16_t w0 = (zchars[0] << 10) | (zchars[1] << 5) | zchars[2]; + uint16_t w1 = (zchars[3] << 10) | (zchars[4] << 5) | zchars[5] | 0x8000; + // cpm_printstring("dict lookup "); + // cpm_printstring(word); + // print_hex(w0); + // spc(); + // print_hex(w1); + // crlf(); + + // cpm_printstring("sep: "); + // printi(sep); + // cpm_printstring(" entry_len: "); + // printi(entry_len); + // cpm_printstring(" count: "); + // printi(count); + // crlf(); + + uint16_t e = dict_addr + 2; + + // cpm_printstring("Starting search at address "); + // print_hex(e); + // crlf(); + for (uint16_t i = 0; i < dict_entry_count; i++) { + // uint16_t e = dict + i * entry_len; + if (zm_read16(e) == w0 && zm_read16(e + 2) == w1) { + // cpm_printstring("Found match at address"); + // print_hex(e); + // crlf(); + return e; + } - e += dict_entry_len; - } + e += dict_entry_len; + } - return 0; + return 0; } // Tokenization static uint8_t is_sep(char c) { - //cpm_printstring("is_sep: "); - //cpm_conout(c); - //crlf(); - for (uint8_t i = 0; i < dict_sep_count; i++) - if (c == dict_seps[i]) - return 1; - return c == ' '; + // cpm_printstring("is_sep: "); + // cpm_conout(c); + // crlf(); + for (uint8_t i = 0; i < dict_sep_count; i++) + if (c == dict_seps[i]) + return 1; + return c == ' '; } static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) { - uint8_t count = 0; - uint8_t i = 0; + uint8_t count = 0; + uint8_t i = 0; - uint8_t max_tok = zm_read8(parse_buf); + uint8_t max_tok = zm_read8(parse_buf); - if (max_tok > MAX_TOKENS) - max_tok = MAX_TOKENS; + if (max_tok > MAX_TOKENS) + max_tok = MAX_TOKENS; - /*for(uint8_t i=0; i> 8); - zm_write8(entry + 1, dict & 0xff); - zm_write8(entry + 2, word_len); - zm_write8(entry + 3, start + 1); //1); + uint16_t entry = parse_buf + 2 + (count << 2); + zm_write8(entry, dict >> 8); + zm_write8(entry + 1, dict & 0xff); + zm_write8(entry + 2, word_len); + zm_write8(entry + 3, start + 1); // 1); - count++; - } + count++; + } - zm_write8(parse_buf + 1, count); - //uint8_t x; - //crlf(); - /* cpm_printstring("Parse buffer: "); + zm_write8(parse_buf + 1, count); + // uint8_t x; + // crlf(); + /* cpm_printstring("Parse buffer: "); crlf(); for(x=0; x<(count<<2)+2; x++) { print_hex(zm_read8(parse_buf+x)); crlf(); }*/ - /* + /* cpm_printstring("Text buffer: "); crlf(); x=0; @@ -802,407 +804,406 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) if(!a) break; } */ - return count; + return count; } // Objects static uint16_t obj_addr(uint8_t obj) { - return object_table + 62 + (obj - 1) * 9; + return object_table + 62 + (obj - 1) * 9; } static uint8_t obj_test_attr(uint8_t obj, uint8_t attr) { - uint16_t a = obj_addr(obj) + (attr >> 3); - return zm_read8(a) & (0x80 >> (attr & 7)); + uint16_t a = obj_addr(obj) + (attr >> 3); + return zm_read8(a) & (0x80 >> (attr & 7)); } static void obj_set_attr(uint8_t obj, uint8_t attr) { - uint16_t a = obj_addr(obj) + (attr >> 3); - if (obj != 0) - zm_write8(a, zm_read8(a) | (0x80 >> (attr & 7))); + uint16_t a = obj_addr(obj) + (attr >> 3); + if (obj != 0) + zm_write8(a, zm_read8(a) | (0x80 >> (attr & 7))); } static void obj_clear_attr(uint8_t obj, uint8_t attr) { - uint16_t a = obj_addr(obj) + (attr >> 3); - zm_write8(a, zm_read8(a) & ~(0x80 >> (attr & 7))); + uint16_t a = obj_addr(obj) + (attr >> 3); + zm_write8(a, zm_read8(a) & ~(0x80 >> (attr & 7))); } static uint8_t obj_parent(uint8_t obj) { - return zm_read8(obj_addr(obj) + 4); + return zm_read8(obj_addr(obj) + 4); } static uint8_t obj_sibling(uint8_t obj) { - return zm_read8(obj_addr(obj) + 5); + return zm_read8(obj_addr(obj) + 5); } static uint8_t obj_child(uint8_t obj) { - return zm_read8(obj_addr(obj) + 6); + return zm_read8(obj_addr(obj) + 6); } static void obj_remove(uint8_t obj) { - if (!obj) - return; - uint8_t parent = obj_parent(obj); - if (!parent) - return; - - uint16_t paddr = obj_addr(parent) + 6; - uint8_t cur = zm_read8(paddr); - - if (cur == obj) { - zm_write8(paddr, obj_sibling(obj)); - } else { - while (cur) { - uint16_t caddr = obj_addr(cur) + 5; - uint8_t sib = zm_read8(caddr); - if (sib == obj) { - zm_write8(caddr, obj_sibling(obj)); - break; - } - cur = sib; + if (!obj) + return; + uint8_t parent = obj_parent(obj); + if (!parent) + return; + + uint16_t paddr = obj_addr(parent) + 6; + uint8_t cur = zm_read8(paddr); + + if (cur == obj) { + zm_write8(paddr, obj_sibling(obj)); + } else { + while (cur) { + uint16_t caddr = obj_addr(cur) + 5; + uint8_t sib = zm_read8(caddr); + if (sib == obj) { + zm_write8(caddr, obj_sibling(obj)); + break; + } + cur = sib; + } } - } - zm_write8(obj_addr(obj) + 4, 0); - zm_write8(obj_addr(obj) + 5, 0); + zm_write8(obj_addr(obj) + 4, 0); + zm_write8(obj_addr(obj) + 5, 0); } static void obj_insert(uint8_t obj, uint8_t dest) { - if (obj == 0 || dest == 0) - return; - obj_remove(obj); - - uint16_t daddr = obj_addr(dest) + 6; - zm_write8(obj_addr(obj) + 4, dest); - zm_write8(obj_addr(obj) + 5, zm_read8(daddr)); - zm_write8(daddr, obj); + if (obj == 0 || dest == 0) + return; + obj_remove(obj); + + uint16_t daddr = obj_addr(dest) + 6; + zm_write8(obj_addr(obj) + 4, dest); + zm_write8(obj_addr(obj) + 5, zm_read8(daddr)); + zm_write8(daddr, obj); } static uint16_t obj_prop_table(uint8_t obj) { - return zm_read16(obj_addr(obj) + 7); + return zm_read16(obj_addr(obj) + 7); } static uint16_t obj_prop_start(uint8_t obj) { - uint16_t p = obj_prop_table(obj); - return p + 1 + 2 * zm_read8(p); + uint16_t p = obj_prop_table(obj); + return p + 1 + 2 * zm_read8(p); } static uint16_t obj_find_prop(uint8_t obj, uint8_t prop) { - uint16_t p = obj_prop_start(obj); + uint16_t p = obj_prop_start(obj); - while (1) { - uint8_t h = zm_read8(p++); - if (!h) - return 0; + while (1) { + uint8_t h = zm_read8(p++); + if (!h) + return 0; - uint8_t num = h & 0x1F; - uint8_t len = (h >> 5) + 1; + uint8_t num = h & 0x1F; + uint8_t len = (h >> 5) + 1; - if (num == prop) - return p; - p += len; - } + if (num == prop) + return p; + p += len; + } } static uint16_t obj_get_prop(uint8_t obj, uint8_t prop) { - uint16_t p = obj_find_prop(obj, prop); - if (!p) { - return zm_read16(object_table + (prop - 1) * 2); - } + uint16_t p = obj_find_prop(obj, prop); + if (!p) { + return zm_read16(object_table + (prop - 1) * 2); + } - uint8_t len = ((zm_read8(p - 1) >> 5) & 7) + 1; - if (len == 1) - return zm_read8(p); - return zm_read16(p); + uint8_t len = ((zm_read8(p - 1) >> 5) & 7) + 1; + if (len == 1) + return zm_read8(p); + return zm_read16(p); } static uint8_t obj_get_prop_len(uint16_t addr) { - if (!addr) - return 0; - return ((zm_read8(addr - 1) >> 5) & 7) + 1; + if (!addr) + return 0; + return ((zm_read8(addr - 1) >> 5) & 7) + 1; } static void obj_put_prop(uint8_t obj, uint8_t prop, uint16_t val) { - uint16_t p = obj_find_prop(obj, prop); + uint16_t p = obj_find_prop(obj, prop); - if (!p) { - // property must exist - return; - } + if (!p) { + // property must exist + return; + } - uint8_t len = ((zm_read8(p - 1) >> 5) & 7) + 1; + uint8_t len = ((zm_read8(p - 1) >> 5) & 7) + 1; - if (len == 1) { - zm_write8(p, (uint8_t)val); - } else { - zm_write8(p, val >> 8); - zm_write8(p + 1, val & 0xFF); - } + if (len == 1) { + zm_write8(p, (uint8_t)val); + } else { + zm_write8(p, val >> 8); + zm_write8(p + 1, val & 0xFF); + } } void write_save_sector(FCB *fcb, void *dmaptr) { - cpm_set_dma(dmaptr); - cpm_write_sequential(fcb); + cpm_set_dma(dmaptr); + cpm_write_sequential(fcb); } void add_save_byte(FCB *fcb, uint8_t *writeSector, uint8_t data) { - writeSector[w_addr++] = data; - if (w_addr == 0x80) { - write_save_sector(fcb, writeSector); - w_addr = 0; - } + writeSector[w_addr++] = data; + if (w_addr == 0x80) { + write_save_sector(fcb, writeSector); + w_addr = 0; + } } void write_zero_block(FCB *fcb, uint8_t *writeSector, uint8_t zero_cnt) { - add_save_byte(fcb, writeSector, 0x00); - add_save_byte(fcb, writeSector, zero_cnt); + add_save_byte(fcb, writeSector, 0x00); + add_save_byte(fcb, writeSector, zero_cnt); } // Saving and loading uint8_t save_game(void) { - FCB saveFile; - char filename_input[14]; + FCB saveFile; + char filename_input[14]; - filename_input[0] = 13; - filename_input[1] = 0; + filename_input[0] = 13; + filename_input[1] = 0; - cpm_printstring("Enter filename: "); - cpm_readline((uint8_t *)filename_input); - crlf(); + cpm_printstring("Enter filename: "); + cpm_readline((uint8_t *)filename_input); + crlf(); - cpm_set_dma(&saveFile); - if (!cpm_parse_filename(&filename_input[2])) { - return 0; - } + cpm_set_dma(&saveFile); + if (!cpm_parse_filename(&filename_input[2])) { + return 0; + } - if (cpm_make_file(&saveFile)) { - return 0; - } + if (cpm_make_file(&saveFile)) { + return 0; + } - uint16_t enc = 0; - - // Write delta of dynamic ram to file - uint16_t cmp_addr = 0; - cpm_fcb.r = 0; - uint8_t writeSector[128]; - w_addr = 0; - uint8_t zero_cnt = 0; - - while (cmp_addr < dynamic_size) { - // Read a sector from file - uint8_t checkSector[128]; - cpm_set_dma(&checkSector); - cpm_read_random(&cpm_fcb); - cpm_fcb.r++; - // Compare byte by byte with ram - uint8_t next_len = (dynamic_size - cmp_addr) > 128 ? - 128 : - (dynamic_size - cmp_addr); - for (uint8_t i = 0; i < next_len; i++) { - uint8_t diff = dynamic_mem[cmp_addr] ^ checkSector[i]; - if (diff) { - if (zero_cnt != 0) { - write_zero_block(&saveFile, writeSector, zero_cnt); - enc += zero_cnt; - zero_cnt = 0; - } - add_save_byte(&saveFile, writeSector, diff); - enc++; - } else { - zero_cnt++; - if (zero_cnt == 0x80) { - write_zero_block(&saveFile, writeSector, zero_cnt); - enc += zero_cnt; - zero_cnt = 0; + uint16_t enc = 0; + + // Write delta of dynamic ram to file + uint16_t cmp_addr = 0; + cpm_fcb.r = 0; + uint8_t writeSector[128]; + w_addr = 0; + uint8_t zero_cnt = 0; + + while (cmp_addr < dynamic_size) { + // Read a sector from file + uint8_t checkSector[128]; + cpm_set_dma(&checkSector); + cpm_read_random(&cpm_fcb); + cpm_fcb.r++; + // Compare byte by byte with ram + uint8_t next_len = + (dynamic_size - cmp_addr) > 128 ? 128 : (dynamic_size - cmp_addr); + for (uint8_t i = 0; i < next_len; i++) { + uint8_t diff = dynamic_mem[cmp_addr] ^ checkSector[i]; + if (diff) { + if (zero_cnt != 0) { + write_zero_block(&saveFile, writeSector, zero_cnt); + enc += zero_cnt; + zero_cnt = 0; + } + add_save_byte(&saveFile, writeSector, diff); + enc++; + } else { + zero_cnt++; + if (zero_cnt == 0x80) { + write_zero_block(&saveFile, writeSector, zero_cnt); + enc += zero_cnt; + zero_cnt = 0; + } + } + cmp_addr++; } - } - cmp_addr++; } - } - // Write trailing zeroes - if (zero_cnt != 0) { - write_zero_block(&saveFile, writeSector, zero_cnt); - enc += zero_cnt; - } + // Write trailing zeroes + if (zero_cnt != 0) { + write_zero_block(&saveFile, writeSector, zero_cnt); + enc += zero_cnt; + } - // Write frames - add_save_byte(&saveFile, writeSector, fp); - for (uint8_t i = 0; i < fp + 2; i++) { - add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 24)); - add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 16)); - add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 8)); - add_save_byte(&saveFile, writeSector, (frames[i].return_pc & 0xFF)); + // Write frames + add_save_byte(&saveFile, writeSector, fp); + for (uint8_t i = 0; i < fp + 2; i++) { + add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 24)); + add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 16)); + add_save_byte(&saveFile, writeSector, (frames[i].return_pc >> 8)); + add_save_byte(&saveFile, writeSector, (frames[i].return_pc & 0xFF)); - add_save_byte(&saveFile, writeSector, frames[i].store_var); + add_save_byte(&saveFile, writeSector, frames[i].store_var); - add_save_byte(&saveFile, writeSector, frames[i].num_locals); - for (uint8_t j = 0; j < MAX_LOCALS; j++) { - add_save_byte(&saveFile, writeSector, (frames[i].locals[j] >> 8)); - add_save_byte(&saveFile, writeSector, (frames[i].locals[j] & 0xFF)); - } + add_save_byte(&saveFile, writeSector, frames[i].num_locals); + for (uint8_t j = 0; j < MAX_LOCALS; j++) { + add_save_byte(&saveFile, writeSector, (frames[i].locals[j] >> 8)); + add_save_byte(&saveFile, writeSector, (frames[i].locals[j] & 0xFF)); + } - add_save_byte(&saveFile, writeSector, (frames[i].saved_sp >> 8)); - add_save_byte(&saveFile, writeSector, (frames[i].saved_sp & 0xFF)); - } - // Write stack - add_save_byte(&saveFile, writeSector, (sp >> 8)); - add_save_byte(&saveFile, writeSector, (sp & 0xFF)); + add_save_byte(&saveFile, writeSector, (frames[i].saved_sp >> 8)); + add_save_byte(&saveFile, writeSector, (frames[i].saved_sp & 0xFF)); + } + // Write stack + add_save_byte(&saveFile, writeSector, (sp >> 8)); + add_save_byte(&saveFile, writeSector, (sp & 0xFF)); - for (uint16_t i = 0; i < sp; i++) { - add_save_byte(&saveFile, writeSector, (stack[i] >> 8)); - add_save_byte(&saveFile, writeSector, (stack[i] & 0xFF)); - } - crlf(); - // Save PC - add_save_byte(&saveFile, writeSector, (pc >> 24)); - add_save_byte(&saveFile, writeSector, (pc >> 16)); - add_save_byte(&saveFile, writeSector, (pc >> 8)); - add_save_byte(&saveFile, writeSector, (pc & 0xFF)); + for (uint16_t i = 0; i < sp; i++) { + add_save_byte(&saveFile, writeSector, (stack[i] >> 8)); + add_save_byte(&saveFile, writeSector, (stack[i] & 0xFF)); + } + crlf(); + // Save PC + add_save_byte(&saveFile, writeSector, (pc >> 24)); + add_save_byte(&saveFile, writeSector, (pc >> 16)); + add_save_byte(&saveFile, writeSector, (pc >> 8)); + add_save_byte(&saveFile, writeSector, (pc & 0xFF)); - // Perform a final write if necessary + // Perform a final write if necessary - if (w_addr != 0) { - write_save_sector(&saveFile, writeSector); - } + if (w_addr != 0) { + write_save_sector(&saveFile, writeSector); + } - cpm_close_file(&saveFile); + cpm_close_file(&saveFile); - return 1; + return 1; } uint8_t read_save_byte(FCB *fcb, uint8_t *restoreSector) { - uint8_t data; - // Refill buffer if out of data - if (w_addr == 0x80) { - cpm_set_dma(restoreSector); - cpm_read_random(fcb); - fcb->r++; - w_addr = 0; - } + uint8_t data; + // Refill buffer if out of data + if (w_addr == 0x80) { + cpm_set_dma(restoreSector); + cpm_read_random(fcb); + fcb->r++; + w_addr = 0; + } - data = restoreSector[w_addr++]; - return data; + data = restoreSector[w_addr++]; + return data; } uint8_t read_game_byte(uint8_t *r_addr) { - uint8_t data; - // Refill buffer if out of data - if ((*r_addr) == 0x80) { - cpm_set_dma(&dma); - cpm_read_random(&cpm_fcb); - cpm_fcb.r++; - (*r_addr) = 0; - } + uint8_t data; + // Refill buffer if out of data + if ((*r_addr) == 0x80) { + cpm_set_dma(&dma); + cpm_read_random(&cpm_fcb); + cpm_fcb.r++; + (*r_addr) = 0; + } - data = dma[(*r_addr)]; - (*r_addr) = (*r_addr) + 1; - return data; + data = dma[(*r_addr)]; + (*r_addr) = (*r_addr) + 1; + return data; } uint8_t restore_game(void) { - FCB saveFile; - char filename_input[14]; + FCB saveFile; + char filename_input[14]; - filename_input[0] = 13; - filename_input[1] = 0; + filename_input[0] = 13; + filename_input[1] = 0; - cpm_printstring("Enter filename: "); - cpm_readline((uint8_t *)filename_input); - crlf(); + cpm_printstring("Enter filename: "); + cpm_readline((uint8_t *)filename_input); + crlf(); - cpm_set_dma(&saveFile); - if (!cpm_parse_filename(&filename_input[2])) { - return 0; - } + cpm_set_dma(&saveFile); + if (!cpm_parse_filename(&filename_input[2])) { + return 0; + } - saveFile.cr = 0; - if (cpm_open_file(&saveFile)) { - return 0; - } - saveFile.r = 0; + saveFile.cr = 0; + if (cpm_open_file(&saveFile)) { + return 0; + } + saveFile.r = 0; - // Restore dynamic ram from file - uint16_t cmp_addr = 0; + // Restore dynamic ram from file + uint16_t cmp_addr = 0; - cpm_fcb.r = 0; - uint8_t restoreSector[128]; - uint8_t gameFileSector[128]; - //uint8_t zero_cnt; + cpm_fcb.r = 0; + uint8_t restoreSector[128]; + uint8_t gameFileSector[128]; + // uint8_t zero_cnt; - w_addr = 0x80; // trigger sector read - uint8_t r_addr = 0x80; - uint8_t gameFileAddr = 0x80; + w_addr = 0x80; // trigger sector read + uint8_t r_addr = 0x80; + uint8_t gameFileAddr = 0x80; - // Restore dynamic memory - while (cmp_addr < dynamic_size) { - uint8_t data = read_save_byte(&saveFile, restoreSector); + // Restore dynamic memory + while (cmp_addr < dynamic_size) { + uint8_t data = read_save_byte(&saveFile, restoreSector); - if (data == 0x00) { - uint8_t zero_cnt = read_save_byte(&saveFile, restoreSector); + if (data == 0x00) { + uint8_t zero_cnt = read_save_byte(&saveFile, restoreSector); - for (uint8_t i = 0; i < zero_cnt; i++) { - dynamic_mem[cmp_addr++] = read_game_byte(&gameFileAddr); - } - } else { - dynamic_mem[cmp_addr++] = read_game_byte(&gameFileAddr) ^ data; + for (uint8_t i = 0; i < zero_cnt; i++) { + dynamic_mem[cmp_addr++] = read_game_byte(&gameFileAddr); + } + } else { + dynamic_mem[cmp_addr++] = read_game_byte(&gameFileAddr) ^ data; + } } - } - // Restore frames - fp = read_save_byte(&saveFile, restoreSector); // Frame pointer - for (uint8_t i = 0; i < fp + 2; i++) { - frames[i].return_pc = - ((uint32_t)read_save_byte(&saveFile, restoreSector) << 24) | - ((uint32_t)read_save_byte(&saveFile, restoreSector) << 16) | - ((uint32_t)read_save_byte(&saveFile, restoreSector) << 8) | - (uint32_t)read_save_byte(&saveFile, restoreSector); - frames[i].store_var = read_save_byte(&saveFile, restoreSector); - frames[i].num_locals = read_save_byte(&saveFile, restoreSector); - for (uint8_t j = 0; j < MAX_LOCALS; j++) { - frames[i].locals[j] = - (read_save_byte(&saveFile, restoreSector) << 8) | - read_save_byte(&saveFile, restoreSector); + // Restore frames + fp = read_save_byte(&saveFile, restoreSector); // Frame pointer + for (uint8_t i = 0; i < fp + 2; i++) { + frames[i].return_pc = + ((uint32_t)read_save_byte(&saveFile, restoreSector) << 24) | + ((uint32_t)read_save_byte(&saveFile, restoreSector) << 16) | + ((uint32_t)read_save_byte(&saveFile, restoreSector) << 8) | + (uint32_t)read_save_byte(&saveFile, restoreSector); + frames[i].store_var = read_save_byte(&saveFile, restoreSector); + frames[i].num_locals = read_save_byte(&saveFile, restoreSector); + for (uint8_t j = 0; j < MAX_LOCALS; j++) { + frames[i].locals[j] = + (read_save_byte(&saveFile, restoreSector) << 8) | + read_save_byte(&saveFile, restoreSector); + } + frames[i].saved_sp = (read_save_byte(&saveFile, restoreSector) << 8) | + read_save_byte(&saveFile, restoreSector); + crlf(); } - frames[i].saved_sp = (read_save_byte(&saveFile, restoreSector) << 8) | - read_save_byte(&saveFile, restoreSector); - crlf(); - } - // Restore stack - sp = (read_save_byte(&saveFile, restoreSector) << 8) | - read_save_byte(&saveFile, restoreSector); - for (uint16_t i = 0; i < sp; i++) { - stack[i] = (read_save_byte(&saveFile, restoreSector) << 8) | - read_save_byte(&saveFile, restoreSector); - } - // Restore PC - pc = ((uint32_t)read_save_byte(&saveFile, restoreSector) << 24) | - ((uint32_t)read_save_byte(&saveFile, restoreSector) << 16) | - ((uint32_t)read_save_byte(&saveFile, restoreSector) << 8) | - (uint32_t)read_save_byte(&saveFile, restoreSector); - - cpm_close_file(&saveFile); - return 1; + // Restore stack + sp = (read_save_byte(&saveFile, restoreSector) << 8) | + read_save_byte(&saveFile, restoreSector); + for (uint16_t i = 0; i < sp; i++) { + stack[i] = (read_save_byte(&saveFile, restoreSector) << 8) | + read_save_byte(&saveFile, restoreSector); + } + // Restore PC + pc = ((uint32_t)read_save_byte(&saveFile, restoreSector) << 24) | + ((uint32_t)read_save_byte(&saveFile, restoreSector) << 16) | + ((uint32_t)read_save_byte(&saveFile, restoreSector) << 8) | + (uint32_t)read_save_byte(&saveFile, restoreSector); + + cpm_close_file(&saveFile); + return 1; } /* ============================================================ * Execution @@ -1211,582 +1212,589 @@ uint8_t restore_game(void) static void z_ret(uint16_t v) { - CallFrame *f = &frames[--fp]; - pc = f->return_pc; - sp = f->saved_sp; - if (f->store_var == 0) { - push(v); - } else - set_var(f->store_var, v, 0); + CallFrame *f = &frames[--fp]; + pc = f->return_pc; + sp = f->saved_sp; + if (f->store_var == 0) { + push(v); + } else + set_var(f->store_var, v, 0); } static void store_result(uint16_t v, uint8_t indirect) { - uint8_t var = zm_read8(pc++); - set_var(var, v, indirect); + uint8_t var = zm_read8(pc++); + set_var(var, v, indirect); } static void restart(void) { - pc = initial_pc; - sp = fp = 0; + pc = initial_pc; + sp = fp = 0; } static uint16_t rng_next(void) { - uint16_t x = rng_state; + uint16_t x = rng_state; - x ^= x << 7; - x ^= x >> 9; - x ^= x << 8; + x ^= x << 7; + x ^= x >> 9; + x ^= x << 8; - rng_state = x & 0x7fff; + rng_state = x & 0x7fff; - return rng_state; + return rng_state; } -static void unimplemented(uint8_t opcode) { +static void unimplemented(uint8_t opcode) +{ #ifdef DEBUG - crlf(); - printi(op); - spc(); - print_hex(pc); - spc(); + crlf(); + printi(op); + spc(); + print_hex(pc); + spc(); #endif - fatal("Non-implemented opcode"); + fatal("Non-implemented opcode"); } static void step(void) { - uint8_t op = zm_read8(pc++); + uint8_t op = zm_read8(pc++); #ifdef DEBUG - printi(opcnt++); - spc(); - cpm_printstring("OP: "); - print_hex(op); - cpm_printstring(" PC: "); - print_hex_32(pc); - cpm_printstring(" SP: "); - print_hex(sp); - cpm_printstring(" FP: "); - print_hex(fp); - cpm_printstring(" [SP]: "); - print_hex(stack[sp - 1]); - crlf(); + printi(opcnt++); + spc(); + cpm_printstring("OP: "); + print_hex(op); + cpm_printstring(" PC: "); + print_hex_32(pc); + cpm_printstring(" SP: "); + print_hex(sp); + cpm_printstring(" FP: "); + print_hex(fp); + cpm_printstring(" [SP]: "); + print_hex(stack[sp - 1]); + crlf(); #endif - /* -------- 2OP -------- */ - if (op < 0x80) { - uint8_t t1 = (op & 0x40) ? OP_VAR : OP_SMALL; - uint8_t t2 = (op & 0x20) ? OP_VAR : OP_SMALL; - uint8_t oc = op & 0x1f; - if (oc == OP2_INC_CHK || oc == OP2_DEC_CHK) - t1 = OP_VAR; - uint8_t var_num = zm_read8(pc); - uint8_t indirect = ((oc == OP2_INC_CHK && t1 == OP_VAR) || - (oc == OP2_DEC_CHK && t1 == OP_VAR)); - uint8_t d_indirect = - !(op == 0x45 || op == 0x65 || op == 0x44 || op == 0x64); - operands[0] = read_operand(t1, indirect & d_indirect); - operands[1] = read_operand(t2, 0); - switch (oc) { - case OP2_JE: - branch(operands[0] == operands[1]); - break; - case OP2_JL: - branch((int16_t)operands[0] < (int16_t)operands[1]); - break; - case OP2_JG: - //cpm_printstring("OP2_JG - op1: "); - //print_hex(operands[0]); - //cpm_printstring(" op2: "); - //print_hex(operands[1]); - //crlf(); - branch((int16_t)operands[0] > (int16_t)operands[1]); - break; - case OP2_JIN: { - uint8_t parent; - parent = obj_parent(operands[0]); - branch(parent == operands[1]); - break; - } - case OP2_DEC_CHK: { - int16_t value = (int16_t)get_var(operands[0], 1); - value--; - set_var(operands[0], (uint16_t)value, 1); - branch(value < (int16_t)operands[1]); - break; - } - case OP2_INC_CHK: { - int16_t value = (int16_t)get_var(operands[0], 1); - value++; - set_var(operands[0], value, 1); - branch((int16_t)value > (int16_t)operands[1]); - break; - } - case OP2_TEST: - branch((operands[0] & operands[1]) == operands[1]); - break; - case OP2_OR: - store_result(operands[0] | operands[1], indirect); - break; - case OP2_AND: - store_result(operands[0] & operands[1], indirect); - break; - case OP2_STORE: - set_var(operands[0], operands[1], 1); - break; - case OP2_LOADW: - /*cpm_printstring("OP2_LOADW address: "); - print_hex(operands[0]+2*operands[1]); - cpm_printstring(" data: "); - print_hex(zm_read16(operands[0]+2*operands[1])); - cpm_printstring("Operands: "); - print_hex(operands[0]); - spc(); - print_hex(operands[1]); - crlf();*/ - - store_result(zm_read16(operands[0] + 2 * operands[1]), indirect); - break; - case OP2_LOADB: - /*cpm_printstring("OP2_LOADB address: "); + /* -------- 2OP -------- */ + if (op < 0x80) { + uint8_t t1 = (op & 0x40) ? OP_VAR : OP_SMALL; + uint8_t t2 = (op & 0x20) ? OP_VAR : OP_SMALL; + uint8_t oc = op & 0x1f; + if (oc == OP2_INC_CHK || oc == OP2_DEC_CHK) + t1 = OP_VAR; + uint8_t var_num = zm_read8(pc); + uint8_t indirect = ((oc == OP2_INC_CHK && t1 == OP_VAR) || + (oc == OP2_DEC_CHK && t1 == OP_VAR)); + uint8_t d_indirect = + !(op == 0x45 || op == 0x65 || op == 0x44 || op == 0x64); + operands[0] = read_operand(t1, indirect & d_indirect); + operands[1] = read_operand(t2, 0); + switch (oc) { + case OP2_JE: + branch(operands[0] == operands[1]); + break; + case OP2_JL: + branch((int16_t)operands[0] < (int16_t)operands[1]); + break; + case OP2_JG: + // cpm_printstring("OP2_JG - op1: "); + // print_hex(operands[0]); + // cpm_printstring(" op2: "); + // print_hex(operands[1]); + // crlf(); + branch((int16_t)operands[0] > (int16_t)operands[1]); + break; + case OP2_JIN: { + uint8_t parent; + parent = obj_parent(operands[0]); + branch(parent == operands[1]); + break; + } + case OP2_DEC_CHK: { + int16_t value = (int16_t)get_var(operands[0], 1); + value--; + set_var(operands[0], (uint16_t)value, 1); + branch(value < (int16_t)operands[1]); + break; + } + case OP2_INC_CHK: { + int16_t value = (int16_t)get_var(operands[0], 1); + value++; + set_var(operands[0], value, 1); + branch((int16_t)value > (int16_t)operands[1]); + break; + } + case OP2_TEST: + branch((operands[0] & operands[1]) == operands[1]); + break; + case OP2_OR: + store_result(operands[0] | operands[1], indirect); + break; + case OP2_AND: + store_result(operands[0] & operands[1], indirect); + break; + case OP2_STORE: + set_var(operands[0], operands[1], 1); + break; + case OP2_LOADW: + /*cpm_printstring("OP2_LOADW address: "); + print_hex(operands[0]+2*operands[1]); + cpm_printstring(" data: "); + print_hex(zm_read16(operands[0]+2*operands[1])); + cpm_printstring("Operands: "); + print_hex(operands[0]); + spc(); + print_hex(operands[1]); + crlf();*/ + + store_result(zm_read16(operands[0] + 2 * operands[1]), + indirect); + break; + case OP2_LOADB: + /*cpm_printstring("OP2_LOADB address: "); print_hex(operands[0]+operands[1]); cpm_printstring(" data: "); print_hex(zm_read8(operands[0]+operands[1])); crlf()*/ - ; - store_result(zm_read8(operands[0] + operands[1]), indirect); - break; - case OP2_ADD: - store_result((int16_t)operands[0] + (int16_t)operands[1], indirect); - break; - case OP2_SUB: - store_result((int16_t)operands[0] - (int16_t)operands[1], indirect); - break; - case OP2_MUL: - store_result((int16_t)operands[0] * (int16_t)operands[1], indirect); - break; - case OP2_DIV: - //cpm_printstring("OP2_DIV - op1: "); - //print_hex(operands[0]); - //cpm_printstring(" op2: "); - //print_hex(operands[1]); - //crlf(); - store_result((int16_t)operands[0] / (int16_t)operands[1], indirect); - break; - case OP2_MOD: - store_result((int16_t)operands[0] % (int16_t)operands[1], indirect); - break; - case OP2_TEST_ATTR: - branch(obj_test_attr(operands[0], operands[1])); - break; - - case OP2_SET_ATTR: - obj_set_attr(operands[0], operands[1]); - break; - - case OP2_CLEAR_ATTR: - obj_clear_attr(operands[0], operands[1]); - break; - - case OP2_INSERT_OBJ: - obj_insert(operands[0], operands[1]); - break; - - case OP2_GET_PROP: - store_result(obj_get_prop(operands[0], operands[1]), indirect); - break; - - case OP2_GET_PROP_ADDR: { - uint16_t p = obj_find_prop(operands[0], operands[1]); - store_result(p, indirect); - break; - } - - case OP2_GET_NEXT_PROP: { - uint8_t obj = (uint8_t)operands[0]; - uint8_t prop = (uint8_t)operands[1]; - uint16_t addr; - - if (prop == 0) { - addr = obj_prop_start(obj); - } else { - addr = obj_find_prop(obj, prop); - if (!addr) { - store_result(0, indirect); - break; - } - addr += obj_get_prop_len(addr); - } - - uint8_t next_header = zm_read8(addr); - - if (next_header == 0) - store_result(0, indirect); - else - store_result(next_header & 0x1F, indirect); - - break; - } - - default: + ; + store_result(zm_read8(operands[0] + operands[1]), indirect); + break; + case OP2_ADD: + store_result((int16_t)operands[0] + (int16_t)operands[1], + indirect); + break; + case OP2_SUB: + store_result((int16_t)operands[0] - (int16_t)operands[1], + indirect); + break; + case OP2_MUL: + store_result((int16_t)operands[0] * (int16_t)operands[1], + indirect); + break; + case OP2_DIV: + // cpm_printstring("OP2_DIV - op1: "); + // print_hex(operands[0]); + // cpm_printstring(" op2: "); + // print_hex(operands[1]); + // crlf(); + store_result((int16_t)operands[0] / (int16_t)operands[1], + indirect); + break; + case OP2_MOD: + store_result((int16_t)operands[0] % (int16_t)operands[1], + indirect); + break; + case OP2_TEST_ATTR: + branch(obj_test_attr(operands[0], operands[1])); + break; + + case OP2_SET_ATTR: + obj_set_attr(operands[0], operands[1]); + break; + + case OP2_CLEAR_ATTR: + obj_clear_attr(operands[0], operands[1]); + break; + + case OP2_INSERT_OBJ: + obj_insert(operands[0], operands[1]); + break; + + case OP2_GET_PROP: + store_result(obj_get_prop(operands[0], operands[1]), indirect); + break; + + case OP2_GET_PROP_ADDR: { + uint16_t p = obj_find_prop(operands[0], operands[1]); + store_result(p, indirect); + break; + } + + case OP2_GET_NEXT_PROP: { + uint8_t obj = (uint8_t)operands[0]; + uint8_t prop = (uint8_t)operands[1]; + uint16_t addr; + + if (prop == 0) { + addr = obj_prop_start(obj); + } else { + addr = obj_find_prop(obj, prop); + if (!addr) { + store_result(0, indirect); + break; + } + addr += obj_get_prop_len(addr); + } + + uint8_t next_header = zm_read8(addr); + + if (next_header == 0) + store_result(0, indirect); + else + store_result(next_header & 0x1F, indirect); + + break; + } + + default: #ifdef DEBUG - crlf(); - printi(op); - spc(); - print_hex(pc); - spc(); + crlf(); + printi(op); + spc(); + print_hex(pc); + spc(); #endif - fatal(" - Non-implemented opcode!!!"); + fatal(" - Non-implemented opcode!!!"); + } + return; } - return; - } - /* -------- 1OP -------- */ - if (op < 0xB0) { - uint8_t type = (op >> 4) & 3; - uint8_t oc = op & 0x0F; - uint8_t indirect = (oc == OP1_LOAD); - if (type != OP_OMIT) - operands[0] = read_operand(type, 0); - switch (oc) { - case OP1_JUMP: - pc += (int16_t)operands[0] - 2; - break; - case OP1_PRINT_ADDR: - print_zstring(operands[0]); - break; - case OP1_PRINT_OBJ: { - uint16_t obj = operands[0]; - - if (obj == 0) - break; - - uint16_t entry = obj_addr(obj); - uint16_t prop_table = zm_read16(entry + 7); - uint8_t name_len = zm_read8(prop_table); - if (name_len == 0) - break; - print_zstring(prop_table + 1); - break; - } - case OP1_REMOVE_OBJ: - obj_remove(operands[0]); - break; - case OP1_GET_CHILD: { - uint8_t result; - if (operands[0] == 0) - result = 0; - else - result = obj_child(operands[0]); - store_result(result, indirect); - branch(result != 0); - break; + /* -------- 1OP -------- */ + if (op < 0xB0) { + uint8_t type = (op >> 4) & 3; + uint8_t oc = op & 0x0F; + uint8_t indirect = (oc == OP1_LOAD); + if (type != OP_OMIT) + operands[0] = read_operand(type, 0); + switch (oc) { + case OP1_JUMP: + pc += (int16_t)operands[0] - 2; + break; + case OP1_PRINT_ADDR: + print_zstring(operands[0]); + break; + case OP1_PRINT_OBJ: { + uint16_t obj = operands[0]; + + if (obj == 0) + break; + + uint16_t entry = obj_addr(obj); + uint16_t prop_table = zm_read16(entry + 7); + uint8_t name_len = zm_read8(prop_table); + if (name_len == 0) + break; + print_zstring(prop_table + 1); + break; + } + case OP1_REMOVE_OBJ: + obj_remove(operands[0]); + break; + case OP1_GET_CHILD: { + uint8_t result; + if (operands[0] == 0) + result = 0; + else + result = obj_child(operands[0]); + store_result(result, indirect); + branch(result != 0); + break; + } + case OP1_GET_SIBLING: { + uint8_t result; + if (operands[0] == 0) + result = 0; + else + result = obj_sibling(operands[0]); + store_result(result, indirect); + branch(result != 0); + break; + } + + case OP1_GET_PARENT: { + uint8_t result; + if (operands[0] == 0) + result = 0; + else + result = obj_parent(operands[0]); + store_result(result, indirect); + break; + } + case OP1_GET_PROP_LEN: { + uint8_t result; + if (operands[0] == 0) + result = 0; + else + result = obj_get_prop_len(operands[0]); + store_result(result, indirect); + break; + } + case OP1_LOAD: { + uint16_t result; + result = get_var(operands[0], indirect); + store_result(result, 0); + break; + } + case OP1_NOT: { + uint16_t result; + result = ~operands[0]; + store_result(result, indirect); + break; + } + case OP1_RET: + z_ret(operands[0]); + break; + case OP1_INC: { + uint16_t value = get_var(operands[0], indirect); + value++; + set_var(operands[0], value, indirect); + break; + } + case OP1_DEC: { + uint16_t value = get_var(operands[0], indirect); + value--; + set_var(operands[0], value, indirect); + break; + } + case OP1_JZ: + branch(operands[0] == 0); + break; + case OP1_PRINT_PADDR: { + uint32_t addr = (uint32_t)operands[0] << 1; + print_zstring(addr); + break; + } + default: + unimplemented(op); + } + return; } - case OP1_GET_SIBLING: { - uint8_t result; - if (operands[0] == 0) - result = 0; - else - result = obj_sibling(operands[0]); - store_result(result, indirect); - branch(result != 0); - break; + /* 0OP */ + if (op < 0xC0) { + switch (op & 0x0F) { + case OP0_RTRUE: + z_ret(1); + break; + case OP0_RFALSE: + z_ret(0); + break; + case OP0_PRINT: + print_zstring(pc); + while (!(zm_read16(pc) & 0x8000)) + pc += 2; + pc += 2; + break; + case OP0_PRINT_RET: + print_zstring(pc); + while (!(zm_read16(pc) & 0x8000)) + pc += 2; + pc += 2; + crlf(); + z_ret(1); + break; + + case OP0_NOP: + break; + + case OP0_SAVE: + branch(save_game()); + break; + + case OP0_RESTORE: + branch(restore_game()); + break; + + case OP0_RESTART: + restart(); + break; + + case OP0_RET_POPPED: + z_ret(pop()); + break; + + case OP0_POP: + pop(); + break; + + case OP0_NEW_LINE: + crlf(); + break; + + case OP0_QUIT: + cpm_warmboot(); + break; + case OP0_VERIFY: + // Not supported, just assume it's OK + branch(1); + break; + default: + unimplemented(op); + } + return; } + /* -------- VAR -------- */ + uint8_t var_opcode = op & 0x1f; + uint8_t indirect = (var_opcode == OPV_PULL); + + decode_operands(zm_read8(pc++), indirect); + if ((op & 0xE0) == 0xE0) + var_opcode += 0x20; + if ((op & 0xD0) == 0xD0) + var_opcode += 0x40; + switch (var_opcode) { + case OPV_CALL_EXT: + case OPV_CALL: { + if (operands[0] == 0) { + uint8_t sv = zm_read8(pc++); + set_var(sv, 0, indirect); + return; + } + + CallFrame *f = &frames[fp++]; + + uint8_t sv = zm_read8(pc++); + f->store_var = sv; + f->return_pc = pc; + f->saved_sp = sp; + + uint32_t addr = (uint32_t)operands[0] << 1; + f->num_locals = zm_read8(addr++); + + for (uint8_t i = 0; i < f->num_locals; i++) { + f->locals[i] = zm_read16(addr); + addr += 2; + } + + /* overwrite locals with arguments */ + uint8_t argc = operand_count - 1; + if (argc > f->num_locals) + argc = f->num_locals; + for (uint8_t i = 0; i < argc; i++) { + f->locals[i] = operands[i + 1]; + } + + pc = addr; // + 2 * f->num_locals; + break; + } + case OPV_JE: + if (operand_count == 2) + branch(operands[0] == operands[1]); + else if (operand_count == 3) + branch(operands[0] == operands[1] || + operands[0] == operands[2]); + else if (operand_count == 4) + branch(operands[0] == operands[1] || + operands[0] == operands[2] || + operands[0] == operands[3]); + break; + case OPV_JL: + branch((int16_t)operands[0] < (int16_t)operands[1]); + break; + case OPV_JG: + branch((int16_t)operands[0] > (int16_t)operands[1]); + break; + case OPV_TEST: + branch((operands[0] & operands[1]) == operands[1]); + break; + case OPV_STOREW: + zm_write8(operands[0] + 2 * operands[1], operands[2] >> 8); + zm_write8(operands[0] + 2 * operands[1] + 1, operands[2]); + break; + case OPV_STOREB: + zm_write8(operands[0] + operands[1], operands[2]); + break; + case OPV_STORE: + set_var(operands[0], operands[1], 0); + break; + case OPV_PRINT_CHAR: + putc((char)operands[0]); + break; + case OPV_PRINT_NUM: + print_num((int16_t)operands[0]); + break; + case OPV_PUSH: + push(operands[0]); + break; + case OPV_PULL: { + uint16_t value = pop(); + set_var(operands[0], value, 1); + break; + } + case OPV_SREAD: { + uint16_t text = operands[0]; + uint16_t parse = operands[1]; + char line[INPUT_MAX] = { 0 }; + uint8_t len = read_line(line); + uint8_t max = zm_read8(text); + if (len > max) + len = max; + + // zm_write8(text+1,len); + for (uint8_t i = 0; i < len; i++) + zm_write8(text + 1 + i, line[i]); + + zm_write8(text + 1 + len, 0); + + tokenize(line, parse, text); + break; + } + case OPV_PUT_PROP: + obj_put_prop((uint8_t)operands[0], (uint8_t)operands[1], + operands[2]); + break; + case OPV_OR: + store_result(operands[0] | operands[1], indirect); + break; + case OPV_AND: + store_result(operands[0] & operands[1], indirect); + break; + case OPV_RANDOM: { + int16_t range = (int16_t)operands[0]; + if (range == 0) { + rng_state = (uint16_t)pc; + store_result(0, indirect); + break; + } + if (range < 0) { + rng_state = (uint16_t)(-range); + store_result(0, indirect); + break; + } + + uint16_t r = rng_next(); + uint16_t result = (r % range) + 1; + store_result(result, indirect); + break; + } + case OPV_LOADW: + store_result(zm_read16(operands[0] + 2 * operands[1]), indirect); + break; + case OPV_LOADB: + store_result(zm_read8(operands[0] + operands[1]), indirect); + break; + case OPV_MUL: + store_result((int16_t)operands[0] * (int16_t)operands[1], indirect); + break; + case OPV_ADD: + store_result((int16_t)operands[0] + (int16_t)operands[1], indirect); + break; + case OPV_SUB: + store_result((int16_t)operands[0] - (int16_t)operands[1], indirect); + break; + case OPV_INC_CHK: { + int16_t value = (int16_t)get_var(operands[0], 1); + value++; + set_var(operands[0], (uint16_t)value, 1); + branch(value > (int16_t)operands[1]); + break; + } + case OPV_DEC_CHK: { + int16_t value = (int16_t)get_var(operands[0], 1); + value--; + set_var(operands[0], (uint16_t)value, 1); + branch(value < (int16_t)operands[1]); + break; + } + case OP2_INSERT_OBJ: + obj_insert(operands[0], operands[1]); + break; - case OP1_GET_PARENT: { - uint8_t result; - if (operands[0] == 0) - result = 0; - else - result = obj_parent(operands[0]); - store_result(result, indirect); - break; - } - case OP1_GET_PROP_LEN: { - uint8_t result; - if (operands[0] == 0) - result = 0; - else - result = obj_get_prop_len(operands[0]); - store_result(result, indirect); - break; - } - case OP1_LOAD: { - uint16_t result; - result = get_var(operands[0], indirect); - store_result(result, 0); - break; + default: + unimplemented(op); } - case OP1_NOT: { - uint16_t result; - result = ~operands[0]; - store_result(result, indirect); - break; - } - case OP1_RET: - z_ret(operands[0]); - break; - case OP1_INC: { - uint16_t value = get_var(operands[0], indirect); - value++; - set_var(operands[0], value, indirect); - break; - } - case OP1_DEC: { - uint16_t value = get_var(operands[0], indirect); - value--; - set_var(operands[0], value, indirect); - break; - } - case OP1_JZ: - branch(operands[0] == 0); - break; - case OP1_PRINT_PADDR: { - uint32_t addr = (uint32_t)operands[0] << 1; - print_zstring(addr); - break; - } - default: - unimplemented(op); - } - return; - } - /* 0OP */ - if (op < 0xC0) { - switch (op & 0x0F) { - case OP0_RTRUE: - z_ret(1); - break; - case OP0_RFALSE: - z_ret(0); - break; - case OP0_PRINT: - print_zstring(pc); - while (!(zm_read16(pc) & 0x8000)) - pc += 2; - pc += 2; - break; - case OP0_PRINT_RET: - print_zstring(pc); - while (!(zm_read16(pc) & 0x8000)) - pc += 2; - pc += 2; - crlf(); - z_ret(1); - break; - - case OP0_NOP: - break; - - case OP0_SAVE: - branch(save_game()); - break; - - case OP0_RESTORE: - branch(restore_game()); - break; - - case OP0_RESTART: - restart(); - break; - - case OP0_RET_POPPED: - z_ret(pop()); - break; - - case OP0_POP: - pop(); - break; - - case OP0_NEW_LINE: - crlf(); - break; - - case OP0_QUIT: - cpm_warmboot(); - break; - case OP0_VERIFY: - // Not supported, just assume it's OK - branch(1); - break; - default: - unimplemented(op); - } - return; - } - /* -------- VAR -------- */ - uint8_t var_opcode = op & 0x1f; - uint8_t indirect = (var_opcode == OPV_PULL); - - decode_operands(zm_read8(pc++), indirect); - if ((op & 0xE0) == 0xE0) - var_opcode += 0x20; - if ((op & 0xD0) == 0xD0) - var_opcode += 0x40; - switch (var_opcode) { - case OPV_CALL_EXT: - case OPV_CALL: { - if (operands[0] == 0) { - uint8_t sv = zm_read8(pc++); - set_var(sv, 0, indirect); - return; - } - - CallFrame *f = &frames[fp++]; - - uint8_t sv = zm_read8(pc++); - f->store_var = sv; - f->return_pc = pc; - f->saved_sp = sp; - - uint32_t addr = (uint32_t)operands[0] << 1; - f->num_locals = zm_read8(addr++); - - for (uint8_t i = 0; i < f->num_locals; i++) { - f->locals[i] = zm_read16(addr); - addr += 2; - } - - /* overwrite locals with arguments */ - uint8_t argc = operand_count - 1; - if (argc > f->num_locals) - argc = f->num_locals; - for (uint8_t i = 0; i < argc; i++) { - f->locals[i] = operands[i + 1]; - } - - pc = addr; // + 2 * f->num_locals; - break; - } - case OPV_JE: - if (operand_count == 2) - branch(operands[0] == operands[1]); - else if (operand_count == 3) - branch(operands[0] == operands[1] || - operands[0] == operands[2]); - else if (operand_count == 4) - branch(operands[0] == operands[1] || - operands[0] == operands[2] || - operands[0] == operands[3]); - break; - case OPV_JL: - branch((int16_t)operands[0] < (int16_t)operands[1]); - break; - case OPV_JG: - branch((int16_t)operands[0] > (int16_t)operands[1]); - break; - case OPV_TEST: - branch((operands[0] & operands[1]) == operands[1]); - break; - case OPV_STOREW: - zm_write8(operands[0] + 2 * operands[1], operands[2] >> 8); - zm_write8(operands[0] + 2 * operands[1] + 1, operands[2]); - break; - case OPV_STOREB: - zm_write8(operands[0] + operands[1], operands[2]); - break; - case OPV_STORE: - set_var(operands[0], operands[1], 0); - break; - case OPV_PRINT_CHAR: - putc((char)operands[0]); - break; - case OPV_PRINT_NUM: - print_num((int16_t)operands[0]); - break; - case OPV_PUSH: - push(operands[0]); - break; - case OPV_PULL: { - uint16_t value = pop(); - set_var(operands[0], value, 1); - break; - } - case OPV_SREAD: { - uint16_t text = operands[0]; - uint16_t parse = operands[1]; - char line[INPUT_MAX] = { 0 }; - uint8_t len = read_line(line); - uint8_t max = zm_read8(text); - if (len > max) - len = max; - - //zm_write8(text+1,len); - for (uint8_t i = 0; i < len; i++) - zm_write8(text + 1 + i, line[i]); - - zm_write8(text + 1 + len, 0); - - tokenize(line, parse, text); - break; - } - case OPV_PUT_PROP: - obj_put_prop((uint8_t)operands[0], ( - uint8_t)operands[1], operands[2]); - break; - case OPV_OR: - store_result(operands[0] | operands[1], indirect); - break; - case OPV_AND: - store_result(operands[0] & operands[1], indirect); - break; - case OPV_RANDOM: { - int16_t range = (int16_t)operands[0]; - if (range == 0) { - rng_state = (uint16_t)pc; - store_result(0, indirect); - break; - } - if (range < 0) { - rng_state = (uint16_t)(-range); - store_result(0, indirect); - break; - } - - uint16_t r = rng_next(); - uint16_t result = (r % range) + 1; - store_result(result, indirect); - break; - } - case OPV_LOADW: - store_result(zm_read16(operands[0] + 2 * operands[1]), indirect); - break; - case OPV_LOADB: - store_result(zm_read8(operands[0] + operands[1]), indirect); - break; - case OPV_MUL: - store_result((int16_t)operands[0] * (int16_t)operands[1], indirect); - break; - case OPV_ADD: - store_result((int16_t)operands[0] + (int16_t)operands[1], indirect); - break; - case OPV_SUB: - store_result((int16_t)operands[0] - (int16_t)operands[1], indirect); - break; - case OPV_INC_CHK: { - int16_t value = (int16_t)get_var(operands[0], 1); - value++; - set_var(operands[0], (uint16_t)value, 1); - branch(value > (int16_t)operands[1]); - break; - } - case OPV_DEC_CHK: { - int16_t value = (int16_t)get_var(operands[0], 1); - value--; - set_var(operands[0], (uint16_t)value, 1); - branch(value < (int16_t)operands[1]); - break; - } - case OP2_INSERT_OBJ: - obj_insert(operands[0], operands[1]); - break; - - default: - unimplemented(op); - } } /* ============================================================ @@ -1796,61 +1804,59 @@ static void step(void) int main(int agrv, char **argv) { - cpm_printstring("z65 - Z-machine v3 interpreter"); - crlf(); - crlf(); - - // Get story filename from commandline - //for(uint8_t i=0; i<11; i++) - // storyFile.f[i]=cpm_fcb.f[i]; - //storyFile.dr = cpm_fcb.dr; + cpm_printstring("z65 - Z-machine v3 interpreter"); + crlf(); + crlf(); - cpm_fcb.cr = 0; - if (cpm_open_file(&cpm_fcb)) - fatal("Could not open input file!"); + // Read story file (filename from commandline) + cpm_fcb.cr = 0; + if (cpm_open_file(&cpm_fcb)) + fatal("Could not open input file!"); - cpm_set_dma(&hdr); - cpm_read_sequential(&cpm_fcb); + cpm_set_dma(&hdr); + cpm_read_sequential(&cpm_fcb); - if (hdr[HDR_VERSION] != 3) - fatal("Only v3 files are supported!"); + if (hdr[HDR_VERSION] != 3) + fatal("Only v3 files are supported!"); - dynamic_size = (hdr[HDR_STAT] << 8) | hdr[HDR_STAT + 1]; - //cpm_printstring("Dynamic size: "); - //print_hex(dynamic_size); - //crlf(); + // Allocate dynamic memory + dynamic_size = (hdr[HDR_STAT] << 8) | hdr[HDR_STAT + 1]; - for (uint16_t i = 0; i < DYNAMIC_MEM_MAX; i++) - dynamic_mem[i] = 0; + uint16_t tpa = cpm_bios_gettpa(); + uint8_t *top = (uint8_t *)(tpa & 0xff00); + zmalloc_init(cpm_ram, top - cpm_ram); + dynamic_mem = zmalloc(dynamic_size); - if (dynamic_size > DYNAMIC_MEM_MAX) - while (1) - ; + // Fail if dynamic memory does not fit in RAM + if (!dynamic_mem) + fatal("Out of memory"); - for (uint16_t i = 0; i < 128; i++) - dynamic_mem[i] = hdr[i]; + // Read dynamic memory + for (uint16_t i = 0; i < 128; i++) + dynamic_mem[i] = hdr[i]; - for (uint16_t i = 128; i < dynamic_size; i++) { - if ((i & 0x7f) == 0) { - cpm_set_dma(&dma); - cpm_read_sequential(&cpm_fcb); + for (uint16_t i = 128; i < dynamic_size; i++) { + if ((i & 0x7f) == 0) { + cpm_set_dma(&dma); + cpm_read_sequential(&cpm_fcb); + } + dynamic_mem[i] = dma[i & 0x7f]; } - dynamic_mem[i] = dma[i & 0x7f]; - } - pc = initial_pc = (hdr[HDR_PC] << 8) | hdr[HDR_PC + 1]; - sp = fp = next_victim = 0; - for (uint8_t i = 0; i < NUM_PAGES; i++) - page_cache[i].valid = 0; + // Initiate Z-machine + pc = initial_pc = (hdr[HDR_PC] << 8) | hdr[HDR_PC + 1]; + sp = fp = next_victim = 0; + for (uint8_t i = 0; i < NUM_PAGES; i++) + page_cache[i].valid = 0; - dict_init(); - object_table = (hdr[HDR_OBJ] << 8) | hdr[HDR_OBJ + 1]; + dict_init(); + object_table = (hdr[HDR_OBJ] << 8) | hdr[HDR_OBJ + 1]; - alphabet = 0; - abbrev_print = 0; - abbrev_table = 0; - abbrev_base = (hdr[HDR_ABBR] << 8) | hdr[HDR_ABBR + 1]; + alphabet = 0; + abbrev_print = 0; + abbrev_table = 0; + abbrev_base = (hdr[HDR_ABBR] << 8) | hdr[HDR_ABBR + 1]; - for (;;) - step(); + for (;;) + step(); } From d2bb79786ea6a1781f510c716e65d626b3ef2ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 22 Jan 2026 08:26:28 +0100 Subject: [PATCH 30/36] Fixed backspace check to inlude 127. Removed a bunch of old commented out code --- third_party/z65/z65.c | 175 +++--------------------------------------- 1 file changed, 10 insertions(+), 165 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 0f8d0e35..6683d640 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -276,24 +276,14 @@ static uint8_t read_line(char *buf) if (c == '\r' || c == '\n') { crlf(); buf[len] = 0; - /*cpm_printstring("Read line: "); - crlf(); - for(uint8_t i=0; i<=len; i++) { - print_hex(buf[i]); - crlf(); - } - cpm_printstring("---END---"); - crlf();*/ - return len; + return len; } - if (c == 8 && len) { + if ((c == 8 || c == 127) && len) { len--; - // putc(8); putc(' '); putc(8); continue; } if (len < INPUT_MAX - 1) { buf[len++] = c; - // putc(c); } } } @@ -345,20 +335,6 @@ static uint8_t zm_read8(uint32_t a) Page *p = get_page(a >> 9); data = p->data[a & 0x1FF]; } - /* if(a>0x4687 && a<0x468f) { - cpm_printstring("Read addr: "); - print_hex(a); - cpm_printstring(" data: "); - print_hex(data); - crlf(); - } - if(a>0x2550 && a<0x2641) { - cpm_printstring("Read from parse buffer "); - print_hex(a); - spc(); - print_hex(data); - crlf(); - }*/ return data; } @@ -371,7 +347,6 @@ static void zm_write8(uint32_t a, uint8_t v) { if (a >= dynamic_size) { crlf(); - // print_hex(a); fatal(" Illegal write address"); } dynamic_mem[a] = v; @@ -404,14 +379,7 @@ static uint16_t get_var(uint8_t v, uint8_t indirect) return val; } if (v < 16) { - /* cpm_printstring("Local "); - printi(v-1); - cpm_printstring(" read as "); - print_hex(frames[fp-1].locals[v-1]); - cpm_printstring(" fp: "); - printi(fp); - crlf();*/ - return frames[fp - 1].locals[v - 1]; + return frames[fp - 1].locals[v - 1]; } uint16_t a = (hdr[HDR_GLB] << 8) + hdr[HDR_GLB + 1] + 2 * (v - 16); uint16_t ret_data = zm_read16(a); @@ -440,25 +408,10 @@ static void set_var(uint8_t v, uint16_t val, uint8_t indirect) } } else if (v < 16) { frames[fp - 1].locals[v - 1] = val; - /*cpm_printstring("Local "); - printi(v-1); - cpm_printstring(" set to "); - print_hex(val); - cpm_printstring(" fp: "); - printi(fp); - crlf();*/ } else { uint16_t a = (hdr[HDR_GLB] << 8) + hdr[HDR_GLB + 1] + 2 * (v - 16); zm_write8(a, val >> 8); zm_write8(a + 1, val & 0xFF); - - // cpm_printstring("Write global variable "); - // print_hex(v); - // spc(); - // print_hex(val); - // spc(); - // print_hex(a); - // crlf(); } } @@ -603,51 +556,29 @@ static void print_num(int16_t v) v = -v; } printi(v); - /* do { - buf[i++] = '0' + (v % 10); - v /= 10; - } while (v); - while (i--) - putc(buf[i]);*/ } // Dictionary static void dict_init(void) { dict_addr = hdr[HDR_DICT] << 8 | hdr[HDR_DICT + 1]; - // cpm_printstring("Dict addr "); - // print_hex(dict_addr); dict_sep_count = zm_read8(dict_addr++); - // cpm_printstring(" Dict sep cnt "); - // printi(dict_sep_count); for (uint8_t i = 0; i < dict_sep_count; i++) { dict_seps[i] = zm_read8(dict_addr++); - // spc(); - // putc(dict_seps[i]); - // spc(); } dict_entry_len = zm_read8(dict_addr++); - // crlf(); - // cpm_printstring("Dict entry length: "); - // print_hex(dict_entry_len); - // crlf(); dict_entry_count = zm_read16(dict_addr); - // cpm_printstring("Dict entry count:" ); - // print_hex(dict_entry_count); - // crlf(); } static uint8_t encode_a2(char c) { - /* A2 table for v1–v3 */ - // const char *a2 = " \n0123456789.,!?_#'\"/\\-:()"; for (uint8_t i = 0; zalph[2][i]; i++) { if (zalph[2][i] == c) return i; } - return 0; /* space */ + return 0; } void encode_zchars(const char *s, uint8_t zchars[6]) @@ -657,14 +588,10 @@ void encode_zchars(const char *s, uint8_t zchars[6]) while (*s && zi < 6) { char c = *s++; - /* force lowercase */ - // if (c >= 'A' && c <= 'Z') - // c = c - 'A' + 'a'; - if (c >= 'a' && c <= 'z') { zchars[zi++] = (c - 'a') + 6; } else { - /* shift to A2 */ + // shift to A2 if (zi < 6) zchars[zi++] = 5; if (zi < 6) @@ -672,7 +599,7 @@ void encode_zchars(const char *s, uint8_t zchars[6]) } } - /* pad with 5 */ + // pad with 5 while (zi < 6) zchars[zi++] = 5; } @@ -684,32 +611,10 @@ uint16_t dict_lookup(const char *word) uint16_t w0 = (zchars[0] << 10) | (zchars[1] << 5) | zchars[2]; uint16_t w1 = (zchars[3] << 10) | (zchars[4] << 5) | zchars[5] | 0x8000; - // cpm_printstring("dict lookup "); - // cpm_printstring(word); - // print_hex(w0); - // spc(); - // print_hex(w1); - // crlf(); - - // cpm_printstring("sep: "); - // printi(sep); - // cpm_printstring(" entry_len: "); - // printi(entry_len); - // cpm_printstring(" count: "); - // printi(count); - // crlf(); - uint16_t e = dict_addr + 2; - // cpm_printstring("Starting search at address "); - // print_hex(e); - // crlf(); for (uint16_t i = 0; i < dict_entry_count; i++) { - // uint16_t e = dict + i * entry_len; if (zm_read16(e) == w0 && zm_read16(e + 2) == w1) { - // cpm_printstring("Found match at address"); - // print_hex(e); - // crlf(); return e; } @@ -723,9 +628,6 @@ uint16_t dict_lookup(const char *word) static uint8_t is_sep(char c) { - // cpm_printstring("is_sep: "); - // cpm_conout(c); - // crlf(); for (uint8_t i = 0; i < dict_sep_count; i++) if (c == dict_seps[i]) return 1; @@ -742,18 +644,6 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) if (max_tok > MAX_TOKENS) max_tok = MAX_TOKENS; - /*for(uint8_t i=0; i (int16_t)operands[1]); break; case OP2_JIN: { @@ -1340,26 +1207,10 @@ static void step(void) set_var(operands[0], operands[1], 1); break; case OP2_LOADW: - /*cpm_printstring("OP2_LOADW address: "); - print_hex(operands[0]+2*operands[1]); - cpm_printstring(" data: "); - print_hex(zm_read16(operands[0]+2*operands[1])); - cpm_printstring("Operands: "); - print_hex(operands[0]); - spc(); - print_hex(operands[1]); - crlf();*/ - store_result(zm_read16(operands[0] + 2 * operands[1]), indirect); break; case OP2_LOADB: - /*cpm_printstring("OP2_LOADB address: "); - print_hex(operands[0]+operands[1]); - cpm_printstring(" data: "); - print_hex(zm_read8(operands[0]+operands[1])); - crlf()*/ - ; store_result(zm_read8(operands[0] + operands[1]), indirect); break; case OP2_ADD: @@ -1375,11 +1226,6 @@ static void step(void) indirect); break; case OP2_DIV: - // cpm_printstring("OP2_DIV - op1: "); - // print_hex(operands[0]); - // cpm_printstring(" op2: "); - // print_hex(operands[1]); - // crlf(); store_result((int16_t)operands[0] / (int16_t)operands[1], indirect); break; @@ -1666,7 +1512,7 @@ static void step(void) f->locals[i] = operands[i + 1]; } - pc = addr; // + 2 * f->num_locals; + pc = addr; break; } case OPV_JE: @@ -1722,7 +1568,6 @@ static void step(void) if (len > max) len = max; - // zm_write8(text+1,len); for (uint8_t i = 0; i < len; i++) zm_write8(text + 1 + i, line[i]); From 90d720e5c3b5ab8c15c2a111377b46bd6b5406e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 22 Jan 2026 09:02:46 +0100 Subject: [PATCH 31/36] Added header, cleaned up comments --- third_party/z65/z65.c | 54 +++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 6683d640..4058242e 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -1,4 +1,10 @@ -/* Z-machine v3 interpreter for CP/M-65 */ +/* z65 - Z-machine v3 interpreter for CP/M-65 + * + * Copyright (C) 2026 by Henrik Löfgren + * + * BSD-2 License. See LICENSE file in root directory. + * + */ #include #include @@ -10,7 +16,7 @@ * ============================================================ */ -/* 2OP */ +// 2OP #define OP2_JE 0x01 #define OP2_JL 0x02 #define OP2_JG 0x03 @@ -36,7 +42,7 @@ #define OP2_GET_PROP_ADDR 0x12 #define OP2_GET_NEXT_PROP 0x13 -/* 1OP opcodes (v1–v3) */ +// 1OP #define OP1_JZ 0x00 #define OP1_GET_SIBLING 0x01 #define OP1_GET_CHILD 0x02 @@ -54,7 +60,7 @@ #define OP1_LOAD 0x0E #define OP1_NOT 0x0F -/* 0OP */ +// 0OP #define OP0_RTRUE 0x00 #define OP0_RFALSE 0x01 #define OP0_PRINT 0x02 @@ -69,7 +75,7 @@ #define OP0_NEW_LINE 0x0B #define OP0_VERIFY 0x0D -/* VAR */ +// VAR #define OPV_CALL 0x00 #define OPV_JE 0x01 #define OPV_JL 0x02 @@ -154,7 +160,6 @@ typedef struct { * ============================================================ */ -// static uint8_t dynamic_mem[DYNAMIC_MEM_MAX]; static uint8_t *dynamic_mem; static uint16_t dynamic_size; @@ -169,7 +174,6 @@ static uint16_t sp; static CallFrame frames[MAX_FRAMES]; static uint8_t fp; -// static FCB storyFile; static uint8_t dma[128]; static uint8_t hdr[128]; @@ -495,7 +499,7 @@ static void branch(uint8_t cond) } /* ============================================================ - * ZSCII output (minimal) + * ZSCII output * ============================================================ */ @@ -558,7 +562,12 @@ static void print_num(int16_t v) printi(v); } -// Dictionary +/* ============================================================ + * Dictionary + * ============================================================ + */ + + static void dict_init(void) { dict_addr = hdr[HDR_DICT] << 8 | hdr[HDR_DICT + 1]; @@ -624,7 +633,10 @@ uint16_t dict_lookup(const char *word) return 0; } -// Tokenization +/* ============================================================ + * Tokenization + * ============================================================ + */ static uint8_t is_sep(char c) { @@ -677,7 +689,10 @@ static uint8_t tokenize(char *in, uint16_t parse_buf, uint16_t text_buf) return count; } -// Objects +/* ============================================================ + * Objects + * ============================================================ + */ static uint16_t obj_addr(uint8_t obj) { @@ -827,7 +842,10 @@ static void obj_put_prop(uint8_t obj, uint8_t prop, uint16_t val) } } -// Saving and loading +/* ============================================================ + * Saving and Restoring + * ============================================================ + */ void write_save_sector(FCB *fcb, void *dmaptr) { @@ -1077,6 +1095,7 @@ uint8_t restore_game(void) cpm_close_file(&saveFile); return 1; } + /* ============================================================ * Execution * ============================================================ @@ -1150,7 +1169,7 @@ static void step(void) crlf(); #endif - /* -------- 2OP -------- */ + // -------- 2OP -------- if (op < 0x80) { uint8_t t1 = (op & 0x40) ? OP_VAR : OP_SMALL; uint8_t t2 = (op & 0x20) ? OP_VAR : OP_SMALL; @@ -1298,7 +1317,7 @@ static void step(void) return; } - /* -------- 1OP -------- */ + // -------- 1OP -------- if (op < 0xB0) { uint8_t type = (op >> 4) & 3; uint8_t oc = op & 0x0F; @@ -1408,7 +1427,7 @@ static void step(void) } return; } - /* 0OP */ + // -------- 0OP -------- if (op < 0xC0) { switch (op & 0x0F) { case OP0_RTRUE: @@ -1471,7 +1490,7 @@ static void step(void) } return; } - /* -------- VAR -------- */ + // -------- VAR -------- uint8_t var_opcode = op & 0x1f; uint8_t indirect = (var_opcode == OPV_PULL); @@ -1643,7 +1662,7 @@ static void step(void) } /* ============================================================ - * Entry + * Main * ============================================================ */ @@ -1702,6 +1721,7 @@ int main(int agrv, char **argv) abbrev_table = 0; abbrev_base = (hdr[HDR_ABBR] << 8) | hdr[HDR_ABBR + 1]; + // Start game execution for (;;) step(); } From 2ec94e5c7ef54aa7f1bdcf281f96b60328d32a85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 22 Jan 2026 10:54:05 +0100 Subject: [PATCH 32/36] Fixed so that carriage return is also printed with newline --- third_party/z65/z65.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index 4058242e..d47de488 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -532,7 +532,10 @@ static void print_zstring(uint32_t addr) alphabet = 0; } else if (c >= 6) { putc(zalph[alphabet][c - 6]); - alphabet = 0; + // Also print \r when \n is printed + if(alphabet == 2 && c == 7) + putc('\r'); + alphabet = 0; } else if (c == 4) { alphabet = 1; } else if (c == 5) { From 78f20faabf94399973221644ce1344bc9278a213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 22 Jan 2026 10:54:41 +0100 Subject: [PATCH 33/36] Added freeware 10k adventure Moonglow --- third_party/z65/moonglow.z3 | Bin 0 -> 10239 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 third_party/z65/moonglow.z3 diff --git a/third_party/z65/moonglow.z3 b/third_party/z65/moonglow.z3 new file mode 100644 index 0000000000000000000000000000000000000000..77a47f3e7c00be52a9c1b28bc34c6b62e2fa2bf2 GIT binary patch literal 10239 zcmeHtYj{*uvS_WfyF2~b{m4#8Cp^-5blx2v1`(o=PSSZ1^6U_l1iOhXf1;0f7Vtn9*Z{fDUtqt4DnBkbP_IP6Bi1JNJC| z-1&KTK6TZ3{UUV$c)-OvsoxVd6w$60TfX1OLfGPO^#n z(&CZeyUa?=S*x(a4gZaEqjJ>)!rS=t{ z=<6AL_(D;@Fu8h%n9%X57zpY6_)KM9M~^ru<7;u_*@Dk^h?^VV-LOgfmq_Qa4{T?u zx1?+;0_*?dUk12gITS)R+z(Gd6FdV8Aq!T*ba)PmpcEFtESLig@Gy9w1RjK+Lo2L+ zXW>yuhH|KYW_TWELk{>L1)c^MIN@=43DRL1%!T=o2{kYoehH7jB=`lq0BMj2Hdp`; zKn%n}96Sl!y(W|Jxpy4wOOo-Z@fZNkHT?bTJrM4hp#isYxU*rn^UiQ*zfbOka37(} zpi%>OLhfjQ`%La=f%}Wx(E)cu?&v`gB6k23;XZ{-uZWWyFe>tp4H!(InCr7*2XPhz zr$QA^qjA72fZ`=aWex+yZy1glao!E$j8g1lkZ^>Y4ni!703dQiBq**i@(7%|#X9&X zm2v}Pl;I3AdMqg881m?GpuA7+AdVx5V^z*%kmwjtKFW}zacW_3Do(kCL1N=U+3sT< zoO&}jm7wfoQ?^7<_Q)NaI!4Xr&6eOi;u7FOfB8_sC2<5o5psQD`f=w7gab~9tR3vU zi=zOgc}2mhiY4>b^i=~F`DDFVN;WY^3q%&H4nOF(n_?CWF?ayRGMdre_RXP6nMv`)jQToI1i&{?FoMfDCB3 zPm(49jF+Tz<4Kz&#YK2MpI5A86B0Ko$#?y&lPSEcL(k901Kk(@7+RuQrd*k)L z_h^^v44^Pwnddfd>2szVzfFYj1T-<1JKzc*j7-;m6a>7bOVO>>O$2V-bw{PI-lqS9 zNB5!jMv%>=ARCo=(EaELE7PP@h)99x1at;kANMC^y#6mSy7R!9wRs7jis`1ADd-gB z<(29B@8k7%Vsvdlwrq^&BVx2K1LrBIeb`qL&yV-$-q)=J&UCXx%ZS#bpu3FB-aj;3 zU#V{li1GYGF}eWm(izXsj?tm(3sv=TbHQ{q;rf6x-SlxPE=XMm|5;4uTVr%fQR9Q# z-bgq7#iP&AJqIeYwlt-Nmc2T){B1GaoSBGfAg?$lm|spezY@>C8G|@fo7HwX-TbF` ze%D*t4f;&oHBhi!hi-TSnRYQ0($*KxAM$8_qx}PrU#+~4|8_!XTsr@GTnLTP{tVE$ z(3zOu!c1Wvb0=YquvSo)ZwuRnUBbIUr?6XiPxzhiuS0J44{d}; z1-DQqc!kG=Mq#1wq|hUr5C(+B!ZSjvuta!4SSt90UkJ;EmBKHDmxVTAwNUjB_&X$g zC>$30g`>i8;k57v;hgYC;Zxyr;ezl56i_)j7E;`35&L243O@gPI|Tl3HN(9ATg3mL z=pU&8>wm@UzeM=Y7-$+aPimgkEYqygtkG=J?9%Mfe5UzcBWX?Am|+J9AtdN!l#pPW zRu4~U$WTu^+`)4je1-udGYTb0cYeZ29k#cF?X8|JPvAR70=#a!zDZYYxX%z~$TUpR<>_A2Vfh9NrKU$WdgojkA0Mxy!)rlr&oAg`1`pg9s2JnZF3!4d5*V__$89AIQOH{&S z2~DgC~%hNpq^9s-kZ&-!G%Ys1rH9N0%b}_#aUMpvEgXAmrQb!RlXNd z$R=fSh%1?B_=)Nqjp}fdQZvy%vBIuN$q5PhaGj=3liJ6oLiW_46wWp%!{!s**5lv_ zfxb4#YJ&$nDXDW2+%L;G9z`apWy%o14nSuhHH0G}YCZ#oc6jHgUyY1H)+M(|KU>GO zNkxuHii&P?hW4T*GUNOx=Nn=hXu8e>!UB+;-V!SpF zt$6^rYz}(-oO69@XYXn*(UiN3vn#kZs6kYpEt~qlT7^V1{$zd%2^^TrIXF_lQ`&}V zqRe91)YNakkK(|twAod*KuSo}SQF)j8Tz?=ev(3F+@iAETqzVT>>{98m(tl4jF`aN zflmW_I-`AtP)=$|x7++_&ULmfM;a+S5v|Dr*xPNoN?o;Cbvt8@PF41Ae>Kt6IZV%i zfATSY3Pt(QKODWg#u7R+FrNQuEE@*KhrCZD_Dj)wQMvw%BRJYjq)xjnJuqH93VXv| zZKoM_ZoFN}a7ffuK?G!w(-}xq_Y*;C1KuI23O!`Jlb=BB88pa^^m>SCraz+~5FPTq zO4>po`_IdWpB%?UjuPoDLJs`U8I1iSD|gkWClmz|L%tS9vNP|u+bs+i>oCxr|i zPNem=VcAgT><8%ass|{bUmPWHS6=^phdS%1y|8~iww}fd`dDqwcq^AOtA^wy6Qs3K>^wj~W8n-VWI3?686(^qJl;EMz zyH43Aeba>u8FSLRg6Lej-{)>tAd51>j=K+6@7Wbhu?&a$X-^qdkV2wnGi6i-dxM%i zUP`qErFein1oBJqeD8Hp1&Vl0p4i1IX8Dmr4%FL#dDm>4EEZX3Llqeba-Tihra(zK z?j!;@I5}Q@4G2=h2wna<+pCf!Yhy1;J{#q9p;Iw@fYS^ghT%cjURJ5gPaxG8hI`2Y zS`}J6p8rF$A!&G6JYmDI36<5jD zsU63&>LY}bXCegB&8h;7V$TQ>r2DGa4R?Ivl>?+Z?BMn7Lnnw2=g&lw1Zm6{m3$a9 z@VAuwO(musiP|HCMd7BcCUlJcttL~O^!=9b;gdL%D2oZmC(%LaM}ZmI*QG$T)_^WL z3SRIC5uZ3LBp)+csf27UL}(^pBEerG|6;_#K5pBn%GXSg_!!`0fgcALm?pqDJ{owd z+$SWPkbVZG(bf0LQK9*;%;x39Y?xu`maT*Vp-*haHs8N^{IN{*O115%?Xj05z(K4(H>p2-bjHzUp zBRKM?3qpo{A=ug#(RQWPt{TV8A5HC6&K^VUv7CJzo_ARYupL}Ij=-aLWnuP=R@h?{ zcB|4JtF(_(b^Sd^j*RQV_zcP?qPv7_Hc1#Oo-u_>D7b&rp-wc}4b;S;&JiQ|#uX9e z8MIUp(UhECjcZ3q>h_6&@!DUo$Q_*N>t5x%2jV9M z-6b3M)ONCn)*XD^(OE&lQ7J(l;jEN!>?AV1&nWh_8$};LUpx9|=v8Olg)Ad-KC&7( z39cM~Zr{K0Bs7~?N+uxq@&Q;!+NA&JjtH0s^{=h)n&3g{@&U;N4+Wd)!Da?)P}Fu~ z-~LY6ZFDF2yxT5yqr|wW>?5l)F|zn!0CPnV(H~*3HtG5Nbq<|>dnP@yn#v3Y|CT`;jQu}wz~E}ZPciYaqa?1OHz zYTg~4cwNaX9k6M?24=pF%jjUYkp{h8Hy;@~*ccp`q#O^D-rYjnY;Qll{9=CUi3vYE zKPJ2YPt7sdTNI-{Toj|7wL7$>A-v*-<(nPdSbU7Q(UEnOIm|80*DxG5B72QA~IjY>mN$Xv*JhED3aP4TnWB?9|<}zIjT;d&xGGU?h5P4JYL>8U>4e z3Y3##n${=~;8)B7FvF8xKiB8SV9iPj zv(#0D7JLxjR2(j%s-q)($}zFYL6$8fA9AX~l1qhfOj1LNV9XYUQ@e@&jp!ItnozGJ za&M9A5hVM#nCjo6^uSGw?;}88EiUe>L=||jomoWHzPy=Kzm6-S%30;q7!3ZtNh96U zY}*L;1LLgo>r!c8r|_la!DKpdK1Yhvb?y~R#U z9y0n|IpLAt5m_fZ#zX$5WFL(u6N*f_Q!`DvB9o@bB`5_~q%uiwqKh|>?cV_Un@JH{JcsZ&Cjob<4F$P?8Ubhj{JtZ46YPs-aLzLBW z@n2bBX^oL~uXi#&G011wGjQ$Q_=Z+d+4!l5{$dDW{>!e6!G0I(m+m%ZKLzSKlSRv~ zcVblTHucnGw;JZHr3poTya;xG91Q~3*KX48_K8SAs}GNdap52Hqe#2SvcI$46sr@s zE~G?mMFFEO4Z@{PnRoea<8;!&RY5b!Sd7O5af)tnAGMq2GqNT7Wh@Ttj#!~WXW@1m ztr}k@l)M4X^-h0me!FS;{?6Tkoqwl%j`m`BB{|Ooblgz5K8c2?h}}#Rb+4t`b$Cc{ z?J5M+&S~IG%bMSHW>wTL3A@yNuT-Olq$&(V>(V0F0C_1P4Y!kM0&9R68Xyr0iS$Y7 zSV%-+48DeE+)L$Gt=;V=k%=o)Ob=2d^sY8REbiuAtaXCKMT~eHBp!{1c&^>_I}|^( zW!%fHlwaPoRG&3}rK|(3l{^^;T3mv`kK5qAS-xp)3%33pbZjZ zQR?>4_&}WDsarDBs@>+DB&@mGt(*6n@wCRT@9P)aL+@j|)5df8?V&SdEp~zYhta$X zc$49awc&=)vi8s#OgfNY4X;2Am9&Q*3QB`k}qtas|HT)PmpzY}ku?LzAQd#H!GbQ=rNt!_sxku!7f0HOCA zq3MbB&V)qM+-_I`E!>I;1shE$dvUvv!3z!O^__Uqz+ti#1tKtaBuHo#FSEu-1RJVU zFKku-H*#ZtT{o>5b918i1*(~NuA4_ zwO08#C@Ylgii6d#Dv7WnsRxmk0i0cpX`YrVIS#2S*V8h5(bj^@U3fRZi;s)rWOi9H zyQl85L+TmB)OUFrLCHCkwDf+A_KZsvCbqq^l?HHeFR)h*z%EGR@onA&%=xpIekg2_J4=pjZCvH?Ea%*i8FQgB4O?poeM zXiir)-srL^9O}f*5$rhe{&i$EStfDJRFVSU-{f>6Y{Xx%LPNoQQwupC>fyvX!b-M6 zn4xHc&_XT?Vf{Sb4eN5AE7E8g?uyB-fOe;|p8`W9rLrd7l zyO+4-FL)XCDyzK?xXz?l4Ix+WKs^t|z8E_bkf0gbPiX2(H3YwiB8g)7nt1~=`v_gxWK zE>ncs8$yz&RJ_LaPhIosTIgd2H(EO?yTxz}tA&CyXdxeu-vTlr;mTrn zMg8-6r;&qo5b}(Fef$;h8eg1N|9pvUBKk}&c*Cx_m({&Ge>!+{er--uE9Ai-sdWvy zYdCG~$L_GS?YxDv^E;w$CD8|a7W}GyI{t5kd1{|JF2jp5tf~05&L5lMDR2FGrd2)Q z=B6G+yN5L<)A>&x8=V5VVKX)kC{Px~T?!#4q6G!$7lMJ-ft zh6QSFe=^!(yYPV3k#&BEl! z{GNH6X4%Hp##CXQv$QU!I5O!hZH)TjXO*^U_oHab?G|0CulZ~$q`p_Fjeo&t)uL_n zu`OIKjhYj7QSX5trnaNJi_{SH-n^IC{lat(L*<#-*CTo3HqNd)n4LZg&m#U$k0z9} zm5WUAPpd=ccqvX z$okS{)lW$p(D`*ou_icVp`bQoc|WKu&cM3E7@IT*Ev#bD`Df+T+(Elo4L+;^eR*pq zRtMn*E2{~~d~2=o(Ce~Cvr@#3k>#O5R<}0RJ%*f^&b(WeyfkY~tGYH1W8j!fyYU-K zVdeZ>KIzEnmFAuBu-mfWR3;DeCZD5?O_s)bp80{*ba0WoJ}w{lEhbvPSt9Sh>e=J8 z8mvuExT!vCy;H8ovhb{iJy~sNg@?Jw#-~}yX@t=$TvXrV-8Uw9~7G zx|W~ojz&frKd|K1jC#C3dpb08_6G_KZte2Nw#Q!a_;Z`p-$GUm7xsb?Cg;V|hc2qQ zsR@hScxtqAjH5QE)xp23iJI3K|8xCoI=|)|^YhAAo~$;aW;4-0j%%6i;mA|T)?h5s%hq9)^8Ai`P}j#VD>#ESTQlSqTf9~3Z_#Ul zzR6iMnOqi^yHuOyJh}kVuNP1n(2E7z@e;`MzQt=fdnSaI6xXo)cyfDK@6(mpEsNcw zr`CS7FeR+_NAcL=c3W-E+oEmG{Odo8wH1+ruZpqjeiZ#r&%SoTHv3v>T+RDYKWy%c zT^p0vR~Wmt;gjRlZG96fQ?7g{=B?^2EZY2z?c}ThuSYwp`bW_d_E}+l!sY%a&t;~( zEiT^RXx_MT_Vt&&V{_IxBk}8E@pBP5uRj-fZpU*?*t5JZp8e{%x1WnlHe8;o9@sf; zk@xV2C`s(K>hu9GYu|K6-Pqe`9c*~Ndu3_Go7GAE8SgKsJ|j*A^Xz%l_DFrd z=p9IU{}tt$j?jz&r4V;o6!@r%d&JOv7ew>&uSJY0^}Ce#g{?01>gi`g|G3{~o-!bs g2mgm?u8k@=?le!?yi!=viKEQ;fiJPt`oDet7lN Date: Thu, 22 Jan 2026 10:56:29 +0100 Subject: [PATCH 34/36] Added to build files for all systems where it fits on the disk --- config.py | 4 ++-- src/arch/apple2e/build.py | 3 ++- src/arch/atari800/build.py | 7 ++++--- src/arch/kim-1/build.py | 10 +++++++--- src/arch/nano6502/build.py | 4 ++-- src/arch/neo6502/build.py | 2 ++ src/arch/oric/build.py | 4 +++- src/arch/osi/build.py | 10 +++++++--- src/arch/snes/build.py | 4 +++- src/arch/sorbus/build.py | 4 +++- src/arch/x16/build.py | 4 +++- 11 files changed, 38 insertions(+), 18 deletions(-) diff --git a/config.py b/config.py index f188de13..0f25fa7d 100644 --- a/config.py +++ b/config.py @@ -71,9 +71,9 @@ "0:triangle.frt": "cpmfs+triangle_frt_cpm", } -ZM_APPS = { +Z65_APPS = { "0:z65.com": "third_party/z65", - "0:zork1.z3": "third_party/z65/zork1.z3", + "0:moonglow.z3": "third_party/z65/moonglow.z3", } SERIAL_APPS = { diff --git a/src/arch/apple2e/build.py b/src/arch/apple2e/build.py index 20ea94fa..9b8b6ed4 100644 --- a/src/arch/apple2e/build.py +++ b/src/arch/apple2e/build.py @@ -10,6 +10,7 @@ BIG_SCREEN_APPS, PASCAL_APPS, FORTH_APPS, + Z65_APPS, ) llvmcfile( @@ -73,7 +74,7 @@ bootimage=".+bios_shuffled", size=143360, items={} | SCREEN_APPS | SCREEN_APPS_SRCS | BIG_SCREEN_APPS | PASCAL_APPS - | FORTH_APPS, + | FORTH_APPS | Z65_APPS, ) diff --git a/src/arch/atari800/build.py b/src/arch/atari800/build.py index 8fb929d9..ccde3e18 100644 --- a/src/arch/atari800/build.py +++ b/src/arch/atari800/build.py @@ -11,7 +11,7 @@ BIG_SCREEN_APPS, PASCAL_APPS, FORTH_APPS, - ZM_APPS, + Z65_APPS, ) llvmclibrary(name="headers", hdrs={"atari800.inc": "./atari800.inc"}) @@ -123,7 +123,8 @@ | SCREEN_APPS_SRCS | BIG_SCREEN_APPS | PASCAL_APPS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) simplerule( @@ -174,7 +175,7 @@ | BIG_SCREEN_APPS | PASCAL_APPS | FORTH_APPS - | ZM_APPS, + | Z65_APPS, ) simplerule( diff --git a/src/arch/kim-1/build.py b/src/arch/kim-1/build.py index bd6e8aac..8c3729be 100644 --- a/src/arch/kim-1/build.py +++ b/src/arch/kim-1/build.py @@ -11,6 +11,7 @@ BIG_SCREEN_APPS, PASCAL_APPS, FORTH_APPS, + Z65_APPS, ) COMMODORE_ITEMS = ( @@ -128,7 +129,8 @@ | SCREEN_APPS | BIG_SCREEN_APPS | PASCAL_APPS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) mkcpmfs( @@ -149,7 +151,8 @@ | SCREEN_APPS | BIG_SCREEN_APPS | PASCAL_APPS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) mkcpmfs( @@ -173,7 +176,8 @@ | SCREEN_APPS | BIG_SCREEN_APPS | PASCAL_APPS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) mkimd(name="diskimage-k1013", src=".+rawdiskimage-k1013") diff --git a/src/arch/nano6502/build.py b/src/arch/nano6502/build.py index 9f3da7b4..5a79aebd 100644 --- a/src/arch/nano6502/build.py +++ b/src/arch/nano6502/build.py @@ -12,7 +12,7 @@ SERIAL_APPS, SERIAL_SCREEN_APPS, FORTH_APPS, - ZM_APPS, + Z65_APPS, ) llvmrawprogram( @@ -42,7 +42,7 @@ | SERIAL_APPS | SERIAL_SCREEN_APPS | FORTH_APPS - | ZM_APPS, + | Z65_APPS, ) mkcpmfs( diff --git a/src/arch/neo6502/build.py b/src/arch/neo6502/build.py index b105ea8c..1778ee27 100644 --- a/src/arch/neo6502/build.py +++ b/src/arch/neo6502/build.py @@ -12,6 +12,7 @@ BIG_SCREEN_APPS, PASCAL_APPS, FORTH_APPS, + Z65_APPS, ) import re @@ -80,6 +81,7 @@ | BIG_SCREEN_APPS | PASCAL_APPS | FORTH_APPS + | Z65_APPS ).items() }, ) diff --git a/src/arch/oric/build.py b/src/arch/oric/build.py index 15f10b5c..84042b58 100644 --- a/src/arch/oric/build.py +++ b/src/arch/oric/build.py @@ -10,6 +10,7 @@ BIG_SCREEN_APPS, PASCAL_APPS, FORTH_APPS, + Z65_APPS, ) llvmcfile( @@ -55,7 +56,8 @@ | SCREEN_APPS_SRCS | BIG_SCREEN_APPS | PASCAL_APPS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) mkoricdsk(name="diskimage", src=".+cpmfs") diff --git a/src/arch/osi/build.py b/src/arch/osi/build.py index 825c9795..0c29c21f 100644 --- a/src/arch/osi/build.py +++ b/src/arch/osi/build.py @@ -10,6 +10,7 @@ BIG_SCREEN_APPS, PASCAL_APPS, FORTH_APPS, + Z65_APPS, ) # ---------------------------------------------------------------------------- @@ -207,7 +208,8 @@ | PASCAL_APPS | MINIMAL_APPS_SRCS | BIG_APPS_SRCS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) mkcpmfs( @@ -246,7 +248,8 @@ | PASCAL_APPS | MINIMAL_APPS_SRCS | BIG_APPS_SRCS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) mkcpmfs(name="osif-b_rawdiskimage", format="osi8", size=128 * 1848, items={}) @@ -358,7 +361,8 @@ | BIG_APPS_SRCS | SCREEN_APPS_SRCS | BIG_SCREEN_APPS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) mkcpmfs( diff --git a/src/arch/snes/build.py b/src/arch/snes/build.py index 5b991ca8..d498c9d6 100644 --- a/src/arch/snes/build.py +++ b/src/arch/snes/build.py @@ -11,6 +11,7 @@ BIG_SCREEN_APPS, PASCAL_APPS, FORTH_APPS, + Z65_APPS, ) llvmrawprogram( @@ -38,7 +39,8 @@ | SCREEN_APPS | BIG_SCREEN_APPS | PASCAL_APPS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) simplerule( diff --git a/src/arch/sorbus/build.py b/src/arch/sorbus/build.py index c0ad69fb..22a727fe 100644 --- a/src/arch/sorbus/build.py +++ b/src/arch/sorbus/build.py @@ -10,6 +10,7 @@ PASCAL_APPS, SERIAL_APPS, FORTH_APPS, + Z65_APPS, ) llvmrawprogram( @@ -29,7 +30,8 @@ | BIG_APPS_SRCS | PASCAL_APPS | SERIAL_APPS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) zip( diff --git a/src/arch/x16/build.py b/src/arch/x16/build.py index 03beb81b..50bd998a 100644 --- a/src/arch/x16/build.py +++ b/src/arch/x16/build.py @@ -9,6 +9,7 @@ BIG_APPS_SRCS, PASCAL_APPS, FORTH_APPS, + Z65_APPS, ) llvmrawprogram( @@ -27,7 +28,8 @@ | BIG_APPS | BIG_APPS_SRCS | PASCAL_APPS - | FORTH_APPS, + | FORTH_APPS + | Z65_APPS, ) zip( From 345eabcd532983bb35d4afcb087f4726dea4a142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 22 Jan 2026 16:01:13 +0100 Subject: [PATCH 35/36] Removed some stray newlines --- third_party/z65/z65.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/third_party/z65/z65.c b/third_party/z65/z65.c index d47de488..fc10672b 100644 --- a/third_party/z65/z65.c +++ b/third_party/z65/z65.c @@ -350,7 +350,6 @@ static uint16_t zm_read16(uint32_t a) static void zm_write8(uint32_t a, uint8_t v) { if (a >= dynamic_size) { - crlf(); fatal(" Illegal write address"); } dynamic_mem[a] = v; @@ -881,7 +880,6 @@ uint8_t save_game(void) cpm_printstring("Enter filename: "); cpm_readline((uint8_t *)filename_input); - crlf(); cpm_set_dma(&saveFile); if (!cpm_parse_filename(&filename_input[2])) { @@ -964,7 +962,6 @@ uint8_t save_game(void) add_save_byte(&saveFile, writeSector, (stack[i] >> 8)); add_save_byte(&saveFile, writeSector, (stack[i] & 0xFF)); } - crlf(); // Save PC add_save_byte(&saveFile, writeSector, (pc >> 24)); add_save_byte(&saveFile, writeSector, (pc >> 16)); @@ -1023,7 +1020,6 @@ uint8_t restore_game(void) cpm_printstring("Enter filename: "); cpm_readline((uint8_t *)filename_input); - crlf(); cpm_set_dma(&saveFile); if (!cpm_parse_filename(&filename_input[2])) { @@ -1080,7 +1076,6 @@ uint8_t restore_game(void) } frames[i].saved_sp = (read_save_byte(&saveFile, restoreSector) << 8) | read_save_byte(&saveFile, restoreSector); - crlf(); } // Restore stack sp = (read_save_byte(&saveFile, restoreSector) << 8) | From 52fcce6e0f3db3ac489478224af4d53e6d498590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20L=C3=B6fgren?= Date: Thu, 22 Jan 2026 16:28:59 +0100 Subject: [PATCH 36/36] Added some info about z65 to the readme --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index d80e2f0c..37d867ca 100644 --- a/README.md +++ b/README.md @@ -622,6 +622,17 @@ END OF FILE OK ``` +### The Z-machine interpreter + +z65 is Z-machine interpeter for version 3 Z-machine adventures, written from scratch for CP/M-65. The freeware adventure moonglow is supplied with it to have something to run, but is has been tested with many of the classic version 3 Infocom games (Zork I-III, Mini-Zork, Planetfall, Hollywood Hijinx etc.). It has however not been extensively tested and almost certainly has a lot of bugs, so please report any issues you find. + +Saving and restoring games is supported if the games implement support for it. No check is made to ensure that the file being restored is for the correct game. + +Usage: Run it with the game file you want to run as a command line argument: +``` +A> Z65 MOONGLOW.Z3 +``` + ### Utilities `bin/cpmemu` contains a basic CP/M-65 user mode emulator and debugger. It'll run