all repos — xyw @ 00a108b7d04201efbda539b47b58b843869108de

A minimal virtual machine and assembler for terminals.

Implementing runtime (untested).
h3rald h3rald@h3rald.com
Mon, 01 Dec 2025 14:12:47 +0100
commit

00a108b7d04201efbda539b47b58b843869108de

parent

b9e49abc0175c303241447ac90a14d3f07c3cd2c

1 files changed, 264 insertions(+), 110 deletions(-)

jump to
M xywrun.cxywrun.c

@@ -101,15 +101,8 @@ xyw_word val = mget(addr);

mset(addr, (xyw_word)(val + delta)); } -//// Mode helpers - -static int is_x() { return xyw_memory[*pc] & XYW_MODE_X; } -static int is_y() { return xyw_memory[*pc] & XYW_MODE_Y; } -static int is_w() { return xyw_memory[*pc] & XYW_MODE_W; } - //// System stack management -/* static xyw_word ss_popw() { if (*ssp < 2)

@@ -133,7 +126,6 @@ }

mset(SYSTEM_STACK_START + *ssp, val); (*ssp) += 2; } -*/ //// User stack management

@@ -173,32 +165,17 @@ us_pushw(val);

(*pc)++; } -static void PSHx() -{ - us_push(*x); -} - -static void PSHy() -{ - us_push(*y); -} - -static void PSHxw() -{ - us_pushw(*xw); -} - -static void PSHyw() -{ - us_pushw(*yw); -} +static void PSHx() { us_push(*x); } +static void PSHy() { us_push(*y); } +static void PSHxw() { us_pushw(*xw); } +static void PSHyw() { us_pushw(*yw); } static xyw_byte POP() { if (*usp < 1) { xyw_memory[SYSTEM_ERROR] = XYW_ERROR_STACK_UNDERFLOW; - return; + return -1; } xyw_byte val = user_stack[--(*usp)]; user_stack[*usp] = 0;

@@ -210,7 +187,7 @@ {

if (*usp < 2) { xyw_memory[SYSTEM_ERROR] = XYW_ERROR_STACK_UNDERFLOW; - return; + return -1; } xyw_word val = mget(USER_STACK_START + (*usp) - 2); mset(USER_STACK_START + (*usp) - 2, 0);

@@ -264,135 +241,312 @@ mset(USER_STACK_START + (*usp) - 2, 0);

(*usp) -= 2; } -static void LDRx() +static void LDRx() { us_push(xyw_memory[*x]); } +static void LDRy() { us_push(xyw_memory[*y]); } +static void LDRxw() { us_pushw(mget(*xw)); } +static void LDRyw() { us_pushw(mget(*yw)); } + +static void LDA() { us_push(xyw_memory[POPw()]); } +static void LDAw() { us_pushw(mget(POPw())); } + +static void LDP() { - *x = POP(); - us_push(xyw_memory[*x]); + xyw_byte page = xyw_memory[SYSTEM_PAGE]; + xyw_word addr = (page << 8) | POP(); + us_push(xyw_memory[addr]); +} + +static void LDPw() +{ + xyw_byte page = xyw_memory[SYSTEM_PAGE]; + xyw_word addr = (page << 8) | POPw(); + us_pushw(mget(addr)); +} + +static void STA() +{ + xyw_byte val = POP(); + xyw_word addr = POPw(); + xyw_memory[addr] = val; +} + +static void STAx() +{ + xyw_byte addr = POP(); + xyw_memory[addr] = *x; +} + +static void STAy() +{ + xyw_byte addr = POP(); + xyw_memory[addr] = *y; +} + +static void STAw() +{ + xyw_word val = POPw(); + xyw_word addr = POPw(); + mset(addr, val); +} + +static void STAxw() +{ + xyw_word addr = POPw(); + mset(addr, *xw); +} + +static void STAyw() +{ + xyw_word addr = POPw(); + mset(addr, *yw); } -static void LDRy() +static void STP() { - *y = POP(); - us_push(xyw_memory[*y]); + xyw_byte val = POP(); + xyw_byte page = xyw_memory[SYSTEM_PAGE]; + xyw_word addr = (page << 8) | POP(); + xyw_memory[addr] = val; } -static void LDRxw() +static void STPx() { - *xw = POPw(); - us_pushw(mget(*xw)); + xyw_byte page = xyw_memory[SYSTEM_PAGE]; + xyw_word addr = (page << 8) | POP(); + xyw_memory[addr] = *x; } -static void LDRyw() +static void STPy() { - *yw = POPw(); - us_pushw(mget(*yw)); + xyw_byte page = xyw_memory[SYSTEM_PAGE]; + xyw_word addr = (page << 8) | POP(); + xyw_memory[addr] = *y; } -// Example: ADD -static void ADD() +static void STPw() { - us_push(POP() + POP()); + xyw_word val = POPw(); + xyw_byte page = xyw_memory[SYSTEM_PAGE]; + xyw_word addr = (page << 8) | POPw(); + mset(addr, val); } -static void ADDw() +static void STPxw() { - us_pushw(POPw() + POPw()); + xyw_byte page = xyw_memory[SYSTEM_PAGE]; + xyw_word addr = (page << 8) | POPw(); + mset(addr, *xw); } -static void ADDx() +static void STPyw() { - us_push(*x + POP()); + xyw_byte page = xyw_memory[SYSTEM_PAGE]; + xyw_word addr = (page << 8) | POPw(); + mset(addr, *yw); } -static void ADDy() + +static void SWP(xyw_byte a, xyw_byte b) { - us_push(*y + POP()); + us_push(a); + us_push(b); } -static void ADDxw() +static void SWPw(xyw_word a, xyw_word b) { - us_pushw(*xw + POPw()); + us_pushw(a); + us_pushw(b); } -static void ADDyw() +static void DUP(xyw_byte val) { - us_pushw(*yw + POPw()); + us_push(val); + us_push(val); } -static void ADDxy() +static void DUPw(xyw_word val) { - us_push(*x + *y); + us_pushw(val); + us_pushw(val); } -static void ADDxyw() +static void OVR(xyw_byte a, xyw_byte b) { - us_pushw(*xw + *yw); + us_push(b); + us_push(a); + us_push(b); } -//// TODO: Review Macro helpers & expansions +static void OVRw(xyw_word a, xyw_word b) +{ + us_pushw(b); + us_pushw(a); + us_pushw(b); +} -// Infix operation -#define IOP(op) is_w() ? us_pushw((POPw(1) op POPw(0))) : us_push((POP(1) op POP(0))) -// Binary operation -#define BOP(op) is_w() ? us_pushw(op(POPw(1), POPw(0))) : us_push(op(POP(1), POP(0))) -// Unary operation -#define UOP(op) is_w() ? us_pushw(op(POPw(1))) : us_push(op(POP(1))) +static void ROT(xyw_byte a, xyw_byte b) +{ + us_push(b); + us_push(POP()); + us_push(a); +} + +static void ROTw(xyw_word a, xyw_word b) +{ + us_pushw(b); + us_pushw(POPw()); + us_pushw(a); +} + +static void JMP() { *pc = POPw(); } +static void JCN(xyw_byte a) +{ + if (a) + *pc = POPw(); +} +static void JCNw(xyw_word a) +{ + if (a) + *pc = POPw(); +} +static void JSR() +{ + xyw_word addr = POPw(); + ss_pushw(*pc); + *pc = addr; +} +static void RTS() +{ + *pc = ss_popw(); +} + +//// Macros for instruction implementations + +// clang-format off +#define InOP(opcode, op) \ + case opcode: us_push(POP() op POP()); break; \ + case XYW_MODE_X|opcode: us_push(*x op POP()); break; \ + case XYW_MODE_Y|opcode: us_push(*y op POP()); break; \ + case XYW_MODE_W|opcode: us_pushw(POPw() op POPw()); break; \ + case XYW_MODE_X|XYW_MODE_W|opcode: us_pushw(*xw op POPw()); break; \ + case XYW_MODE_Y|XYW_MODE_W|opcode: us_pushw(*yw op POPw()); break; \ + case XYW_MODE_X|XYW_MODE_Y|opcode: us_push(*x op *y); break; \ + case XYW_MODE_X|XYW_MODE_Y|XYW_MODE_W|opcode: us_pushw(*xw op *yw); break; + +#define UnOP(opcode, op) \ + case opcode: us_push(op(POP())); break; \ + case XYW_MODE_X|opcode: us_push(op(*x)); break; \ + case XYW_MODE_Y|opcode: us_push(op(*y)); break; \ + case XYW_MODE_W|opcode: us_pushw(op(POPw())); break; \ + case XYW_MODE_X|XYW_MODE_W|opcode: us_pushw(op(*xw)); break; \ + case XYW_MODE_Y|XYW_MODE_W|opcode: us_pushw(op(*yw)); break; + +#define PoOP(opcode, op) \ + case opcode: us_push(POP() op); break; \ + case XYW_MODE_X|opcode: us_push(*x op); break; \ + case XYW_MODE_Y|opcode: us_push(*y op); break; \ + case XYW_MODE_W|opcode: us_pushw(POPw() op); break; \ + case XYW_MODE_X|XYW_MODE_W|opcode: us_pushw(*xw op); break; \ + case XYW_MODE_Y|XYW_MODE_W|opcode: us_pushw(*yw op); break; + +#define PrOP2(opcode, op) \ + case opcode: op(POP(), POP()); break; \ + case XYW_MODE_X|opcode: op(*x, POP()); break; \ + case XYW_MODE_Y|opcode: op(*y, POP()); break; \ + case XYW_MODE_X|XYW_MODE_Y|opcode: op(*x, *y); break; \ + +#define PrOP2w(opcode, op) \ + case XYW_MODE_W|opcode: op(POPw(), POPw()); break; \ + case XYW_MODE_X|XYW_MODE_W|opcode: op(*xw, POPw()); break; \ + case XYW_MODE_Y|XYW_MODE_W|opcode: op(*yw, POPw()); break; \ + case XYW_MODE_X|XYW_MODE_Y|XYW_MODE_W|opcode: op(*xw, *yw); break; + +#define PrOP(opcode, op) \ + case opcode: op(POP()); break; \ + case XYW_MODE_X|opcode: op(*x); break; \ + case XYW_MODE_Y|opcode: op(*y); break; + +#define PrOPw(opcode, op) \ + case XYW_MODE_W|opcode: op(POPw()); break; \ + case XYW_MODE_X|XYW_MODE_W|opcode: op(*xw); break; \ + case XYW_MODE_Y|XYW_MODE_W|opcode: op(*yw); break; + +// clang-format on int run() { - xyw_word current; - while (1) + xyw_memory[SYSTEM_STATE] = 1; + while (xyw_memory[SYSTEM_STATE]) { switch (xyw_memory[*pc]) { // clang-format off /* BRK */ case 0x00: break; - /* PSH */ case 0x01: is_w() ? PSHw() : PSH(); break; - /* POP */ case 0x02: is_w() ? POPw(1) : POP(1); break; - /* NOT */ case 0x03: UOP(!); break; + /* PSH */ case 0x01: PSH(); break; + /* PSHw */ case XYW_MODE_W|0x01: PSHw(); break; + /* PSHx */ case XYW_MODE_X|0x01: PSHx(); break; + /* PSHy */ case XYW_MODE_Y|0x01: PSHy(); break; + /* PSHxw */ case XYW_MODE_X|XYW_MODE_W|0x01: PSHxw(); break; + /* PSHyw */ case XYW_MODE_Y|XYW_MODE_W|0x01: PSHyw(); break; + /* POP */ case 0x02: POP(); break; + /* POPw */ case XYW_MODE_W|0x02: POPw(); break; + /* POPx */ case XYW_MODE_X|0x02: POPx(); break; + /* POPy */ case XYW_MODE_Y|0x02: POPy(); break; + /* POPxw */ case XYW_MODE_X|XYW_MODE_W|0x02: POPxw(); break; + /* POPyw */ case XYW_MODE_Y|XYW_MODE_W|0x02: POPyw(); break; + /* LDRx */ case XYW_MODE_X|0x03: LDRx(); break; + /* LDRy */ case XYW_MODE_Y|0x03: LDRy(); break; + /* LDRxw */ case XYW_MODE_X|XYW_MODE_W|0x03: LDRxw(); break; + /* LDRyw */ case XYW_MODE_Y|XYW_MODE_W|0x03: LDRyw(); break; + /* LDA */ case 0x04: LDA(); break; + /* LDAw */ case XYW_MODE_W|0x04: LDAw(); break; + /* STA */ case 0x05: STA(); break; + /* STAx */ case XYW_MODE_X|0x05: STAx(); break; + /* STAy */ case XYW_MODE_Y|0x05: STAy(); break; + /* STAw */ case XYW_MODE_W|0x05: STAw(); break; + /* STAxw */ case XYW_MODE_X|XYW_MODE_W|0x05: STAxw(); break; + /* STAyw */ case XYW_MODE_Y|XYW_MODE_W|0x05: STAyw(); break; + /* LDP */ case 0x06: LDP(); break; + /* LDPw */ case XYW_MODE_W|0x06: LDPw(); break; + /* STP */ case 0x07: STP(); break; + /* STPx */ case XYW_MODE_X|0x07: STPx(); break; + /* STPy */ case XYW_MODE_Y|0x07: STPy(); break; + /* STPw */ case XYW_MODE_W|0x07: STPw(); break; + /* STPxw */ case XYW_MODE_X|XYW_MODE_W|0x07: STPxw(); break; + /* STPyw */ case XYW_MODE_Y|XYW_MODE_W|0x07: STPyw(); break; + /* INC */ PoOP(0x08, + 1); + /* DEC */ PoOP(0x09, - 1); + /* SHL */ InOP(0x0A, <<); + /* SHR */ InOP(0x0B, >>); + /* ADD */ InOP(0x0C, +); + /* SUB */ InOP(0x0D, -); + /* MUL */ InOP(0x0E, *); + /* DIV */ InOP(0x0F, /); + /* EQU */ InOP(0x10, ==); + /* NEQ */ InOP(0x11, !=); + /* GTH */ InOP(0x12, >); + /* LTH */ InOP(0x13, <); + /* AND */ InOP(0x14, &); + /* IOR */ InOP(0x15, |); + /* XOR */ InOP(0x16, ^); + /* NOT */ UnOP(0x17, ~); - /* LDR */ case 0x04: is_w() ? UOP(LDRw) : UOP(LDR); break; - /* STR */ case 0x05: is_w() ? STRw(POPw(1), POPw(0)) : STR(POP(1), POP(0)); break; - /* LDP */ case 0x06: is_w() ? UOP(LDPw) : UOP(LDP); break; - /* STP */ case 0x07: is_w() ? STPw(POPw(1), POPw(0)) : STP(POP(1), POP(0)); break; + /* SWP */ PrOP2(0x18, SWP); + /* SWPw */ PrOP2w(0x18, SWPw); + /* DUP */ PrOP(0x19, DUP); + /* DUPw */ PrOPw(0x19, DUPw); + /* OVR */ PrOP2(0x1A, OVR); + /* OVRw */ PrOP2w(0x1A, OVRw); + /* ROT */ PrOP2(0x1B, ROT); + /* ROTw */ PrOP2w(0x1B, ROTw); - /* ILD */ case 0x08: is_w() ? UOP(ILD) : UOP(ILDw); break; - /* LDI */ case 0x09: is_w() ? UOP(LDI) : UOP(LDIw); break; - /* DLD */ case 0x0A: is_w() ? UOP(DLD) : UOP(DLDw); break; - /* LDD */ case 0x0B: is_w() ? UOP(LDD) : UOP(LDDw); break; - - /* ADD */ case 0x0C: us_push(POP() + POP()); break; - case XYW_MODE_X|0x0C: us_push(*x + POP()); break; - case XYW_MODE_Y|0x0C: us_push(*y + POP()); break; - case XYW_MODE_W|0x0C: us_pushw(POPw() + POPw()); break; - case XYW_MODE_X|XYW_MODE_W|0x0C: us_pushw(*xw + POPw()); break; - case XYW_MODE_Y|XYW_MODE_W|0x0C: us_pushw(*yw + POPw()); break; - case XYW_MODE_X|XYW_MODE_Y|0x0C: us_push(*x + *y); break; - case XYW_MODE_X|XYW_MODE_Y|XYW_MODE_W|0x0C: us_pushw(*xw + *yw); break; - /* SUB */ case 0x0D: IOP(-); break; - /* MUL */ case 0x0E: IOP(*); break; - /* DIV */ case 0x0F: IOP(/); break; - - /* EQU */ case 0x10: IOP(==); break; - /* NEQ */ case 0x11: IOP(!=); break; - /* GTH */ case 0x12: IOP(>); break; - /* LTH */ case 0x13: IOP(<); break; - - /* AND */ case 0x14: IOP(&); break; - /* IOR */ case 0x15: IOP(|); break; - /* XOR */ case 0x16: IOP(^); break; - /* SFT */ case 0x17: break; // TODO from here - - /* SWP */ case 0x18: break; - /* DUP */ case 0x19: break; - /* OVR */ case 0x1A: break; - /* ROT */ case 0x1B: break; - - /* JMP */ case 0x1C: break; - /* JCN */ case 0x1D: break; - /* JSR */ case 0x1E: break; - /* RTS */ case 0x1F: break; + /* JMP */ case 0x1C: JMP(); break; + /* JCN */ PrOP(0x1D, JCN); + /* JCNw */ PrOPw(0x1D, JCNw); + /* JSR */ case 0x1E: JSR(); break; + /* RTS */ case 0x1F: RTS(); break; // clang-format on } + // TODO: error handling etc. (*pc)++; }