all repos — xyw @ b79ea909ae21b1133725d29c98f59f5dfff27ee9

A minimal virtual machine and assembler for terminals.

Refactoring macros.
h3rald h3rald@h3rald.com
Tue, 02 Dec 2025 14:54:51 +0100
commit

b79ea909ae21b1133725d29c98f59f5dfff27ee9

parent

4165133f7914b828d62c12517d5bc0166ec488a4

1 files changed, 77 insertions(+), 115 deletions(-)

jump to
M xywrun.cxywrun.c

@@ -147,7 +147,7 @@ static void PSHy() { us_push(*y); }

static void PSHxw() { us_pushw(*xw); } static void PSHyw() { us_pushw(*yw); } -static xyw_byte POP() +static xyw_byte us_pop() { if (*u < 1) {

@@ -160,7 +160,7 @@ xyw_memory[USER_STACK_START + (*u)] = 0;

return val; } -static xyw_word POPw() +static xyw_word us_popw() { if (*u < 2) {

@@ -226,113 +226,49 @@ 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 LDA() { us_push(xyw_memory[us_popw()]); } +static void LDAw() { us_pushw(mget(us_popw())); } static void LDP() { xyw_byte page = xyw_memory[SYSTEM_PAGE]; - xyw_word addr = (page << 8) | POP(); + xyw_word addr = (page << 8) | us_pop(); us_push(xyw_memory[addr]); } static void LDPw() { xyw_byte page = xyw_memory[SYSTEM_PAGE]; - xyw_word addr = (page << 8) | POPw(); + xyw_word addr = (page << 8) | us_popw(); us_pushw(mget(addr)); -} - -static void STA(xyw_byte val) -{ - xyw_word addr = POPw(); - xyw_memory[addr] = val; -} - -static void STAw(xyw_word val) -{ - xyw_word addr = POPw(); - mset(addr, val); } static void STP(xyw_byte val) { - xyw_word addr = (xyw_memory[SYSTEM_PAGE] << 8) | POP(); + xyw_word addr = (xyw_memory[SYSTEM_PAGE] << 8) | us_pop(); xyw_memory[addr] = val; } static void STPw(xyw_word val) { - xyw_word addr = (xyw_memory[SYSTEM_PAGE] << 8) | POPw(); + xyw_word addr = (xyw_memory[SYSTEM_PAGE] << 8) | us_popw(); mset(addr, val); } -static void SWP(xyw_byte a, xyw_byte b) -{ - us_push(a); - us_push(b); -} - -static void SWPw(xyw_word a, xyw_word b) -{ - us_pushw(a); - us_pushw(b); -} - -static void DUP(xyw_byte val) -{ - us_push(val); - us_push(val); -} - -static void DUPw(xyw_word val) -{ - us_pushw(val); - us_pushw(val); -} - -static void OVR(xyw_byte a, xyw_byte b) -{ - us_push(b); - us_push(a); - us_push(b); -} - -static void OVRw(xyw_word a, xyw_word b) -{ - us_pushw(b); - us_pushw(a); - us_pushw(b); -} - -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 JMP() { *pc = us_popw(); } static void JCN(xyw_byte a) { if (a) - *pc = POPw(); + *pc = us_popw(); } static void JCNw(xyw_word a) { if (a) - *pc = POPw(); + *pc = us_popw(); } static void JSR() { - xyw_word addr = POPw(); + xyw_word addr = us_popw(); ss_pushw(*pc); *pc = addr; }

@@ -342,36 +278,66 @@ *pc = ss_popw();

} // clang-format off + +// w = 0: 1-byte operation +// w = 1: 2-byte operation +// r = 0: value from stack +// r = 1: value from register + //// Operations that support all mode combinations #define OPC_XYW(opc, init, body) { \ - case opc: { const xyw_byte w = 0, a = POP(), b = POP(); init body; } break; \ - case XYW_MODE_X|opc: { const xyw_byte w = 0, a = *x, b = POP(); init body; } break; \ - case XYW_MODE_Y|opc: { const xyw_byte w = 0, a = *y, b = POP(); init body; } break; \ - case XYW_MODE_X|XYW_MODE_Y|opc: { const xyw_byte w = 0, a = *x, b = *y; init body; } break; \ - case XYW_MODE_W|opc: { const xyw_byte w = 1; xyw_word a = POPw(); xyw_word b = POPw(); init body; } break; \ - case XYW_MODE_X|XYW_MODE_W|opc: { const xyw_byte w = 1; xyw_word a = *xw; xyw_word b = POPw(); init body; } break; \ - case XYW_MODE_Y|XYW_MODE_W|opc: { const xyw_byte w = 1; xyw_word a = *yw; xyw_word b = POPw(); init body; } break; \ - case XYW_MODE_X|XYW_MODE_Y|XYW_MODE_W|opc: { const xyw_byte w = 1; xyw_word a = *xw; xyw_word b = *yw; init body; } break; \ + case opc: { const xyw_byte w = 0, r = 0, a = us_pop(), b = us_pop(); init body; } break; \ + case XYW_MODE_X|opc: { const xyw_byte w = 0, r = 1, a = *x, b = us_pop(); init body; } break; \ + case XYW_MODE_Y|opc: { const xyw_byte w = 0, r = 1, a = *y, b = us_pop(); init body; } break; \ + case XYW_MODE_X|XYW_MODE_Y|opc: { const xyw_byte w = 0, r = 1, a = *x, b = *y; init body; } break; \ + case XYW_MODE_W|opc: { const xyw_byte w = 1, r = 0; xyw_word a = us_popw(); xyw_word b = us_popw(); init body; } break; \ + case XYW_MODE_X|XYW_MODE_W|opc: { const xyw_byte w = 1, r = 1; xyw_word a = *xw; xyw_word b = us_popw(); init body; } break; \ + case XYW_MODE_Y|XYW_MODE_W|opc: { const xyw_byte w = 1, r = 1; xyw_word a = *yw; xyw_word b = us_popw(); init body; } break; \ + case XYW_MODE_X|XYW_MODE_Y|XYW_MODE_W|opc: { const xyw_byte w = 1, r = 1; xyw_word a = *xw; xyw_word b = *yw; init body; } break; \ } //// Operations that support X or Y and W modes only #define OPC_XorYW(opc, init, body) { \ - case opc: { const xyw_byte w = 0, a = POP(); init body; } break; \ - case XYW_MODE_X|opc: { const xyw_byte w = 0, a = *x; init body; } break; \ - case XYW_MODE_Y|opc: { const xyw_byte w = 0, a = *y; init body; } break; \ - case XYW_MODE_W|opc: { const xyw_byte w = 1; xyw_word a = POPw(); init body; } break; \ - case XYW_MODE_X|XYW_MODE_W|opc: { const xyw_byte w = 1; xyw_word a = *xw; init body; } break; \ - case XYW_MODE_Y|XYW_MODE_W|opc: { const xyw_byte w = 1; xyw_word a = *yw; init body; } break; \ + case opc: { const xyw_byte w = 0, r = 0, a = us_pop(); init body; } break; \ + case XYW_MODE_X|opc: { const xyw_byte w = 0, r = 1, a = *x; init body; } break; \ + case XYW_MODE_Y|opc: { const xyw_byte w = 0, r = 1, a = *y; init body; } break; \ + case XYW_MODE_W|opc: { const xyw_byte w = 1, r = 0; xyw_word a = us_popw(); init body; } break; \ + case XYW_MODE_X|XYW_MODE_W|opc: { const xyw_byte w = 1, r = 1; xyw_word a = *xw; init body; } break; \ + case XYW_MODE_Y|XYW_MODE_W|opc: { const xyw_byte w = 1, r = 1; xyw_word a = *yw; init body; } break; \ } //// Operations that support W mode only #define OPC_W(opc, init, body) { \ - case opc: { const xyw_byte w = 0; init body; } break; \ - case XYW_MODE_W|opc: { const xyw_byte w = 1; init body; } break; \ + case opc: { const xyw_byte w = 0, r = 0; init body; } break; \ + case XYW_MODE_W|opc: { const xyw_byte w = 1, r = 0; init body; } break; \ } //// "Microcode" similar to Uxn's, to be used with above macros -#define PUSH(n) if (w) { us_pushw(n); } else { us_push(n); } + +// Push a value as word or byte depending on width flag 'w' +#define PUSH(n) do { if(w && !!r) { us_pushw((xyw_word)(n)); } else { us_push((xyw_byte)(n)); } } while(0) +// Push only if a register is not being used +#define PUSHS(n) do { if(!(r)) { PUSH(n); } } while(0) +// Pop value as word or byte depending on width flag 'w' +#define POP() (w ? us_popw() : (xyw_word)us_pop()) +// Read value as word or byte depending on width flag 'w' +#define READ(addr) (w ? mget(addr) : (xyw_byte)xyw_memory[addr]) +// Write value as word or byte depending on width flag 'w' +#define WRITE(addr, val) do { if(w) { mset(addr, (xyw_word)(val)); } else { xyw_memory[addr] = (xyw_byte)(val); } } while(0) + + + +static void STA(xyw_byte val) +{ + xyw_word addr = us_popw(); + xyw_memory[addr] = val; +} + +static void STAw(xyw_word val) +{ + xyw_word addr = us_popw(); + mset(addr, val); +} // clang-format on

@@ -383,36 +349,36 @@ // Infix operations

// Postfix-ish operations (INC/DEC) #define PoOP(opcode, op) \ - case opcode: us_push(POP() op); break; \ + case opcode: us_push(us_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_W|opcode: us_pushw(us_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; // Prefix operations with two operands #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 opcode: op(us_pop(), us_pop()); break; \ + case XYW_MODE_X|opcode: op(*x, us_pop()); break; \ + case XYW_MODE_Y|opcode: op(*y, us_pop()); break; \ case XYW_MODE_X|XYW_MODE_Y|opcode: op(*x, *y); break; // Prefix operations with two 2-byte operands #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_W|opcode: op(us_popw(), us_popw()); break; \ + case XYW_MODE_X|XYW_MODE_W|opcode: op(*xw, us_popw()); break; \ + case XYW_MODE_Y|XYW_MODE_W|opcode: op(*yw, us_popw()); break; \ case XYW_MODE_X|XYW_MODE_Y|XYW_MODE_W|opcode: op(*xw, *yw); break; // Prefix operations with one operand #define PrOP(opcode, op) \ - case opcode: op(POP()); break; \ + case opcode: op(us_pop()); break; \ case XYW_MODE_X|opcode: op(*x); break; \ case XYW_MODE_Y|opcode: op(*y); break; // Prefix operations with one 2-byte operand #define PrOPw(opcode, op) \ - case XYW_MODE_W|opcode: op(POPw()); break; \ + case XYW_MODE_W|opcode: op(us_popw()); break; \ case XYW_MODE_X|XYW_MODE_W|opcode: op(*xw); break; \ case XYW_MODE_Y|XYW_MODE_W|opcode: op(*yw); break;

@@ -463,8 +429,8 @@ /* 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; + /* POP */ case 0x02: us_pop(); break; + /* POPw */ case XYW_MODE_W|0x02: us_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;

@@ -481,8 +447,8 @@ /* LDP */ case 0x06: LDP(); break;

/* LDPw */ case XYW_MODE_W|0x06: LDPw(); break; /* STP */ PrOP(0x07, STP); /* STPw */ PrOPw(0x07, STPw); - /* INC */ PoOP(0x08, + 1); - /* DEC */ PoOP(0x09, - 1); + /* INC */ OPC_XorYW(0x08, , PUSHS(a + 1)); // When in register mode, don't push anything on stack + /* DEC */ OPC_XorYW(0x09, , PUSHS(a - 1)); // When in register mode, don't push anything on stack /* SHL */ OPC_XYW(0x0A, , PUSH(b << a)); /* SHR */ OPC_XYW(0x0B, , PUSH(b >> a)); /* ADD */ OPC_XYW(0x0C, , PUSH(a + b));

@@ -497,14 +463,10 @@ /* AND */ OPC_XYW(0x14, , PUSH(b & a));

/* IOR */ OPC_XYW(0x15, , PUSH(b | a)); /* XOR */ OPC_XYW(0x16, , PUSH(b ^ a)); /* NOT */ OPC_XorYW(0x17, , PUSH(~a)); - /* 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); + /* SWP */ OPC_XYW(0x18, , PUSHS(a); PUSHS(b)); + /* DUP */ OPC_XorYW(0x19, , PUSH(a)); + /* OVR */ OPC_XYW(0x1A, , PUSH(b); PUSH(a); PUSH(b)); + /* ROT */ OPC_XYW(0x1B, , PUSH(b); PUSH(POP()); PUSH(a)); /* JMP */ case 0x1C: JMP(); break; /* JCN */ PrOP(0x1D, JCN); /* JCNw */ PrOPw(0x1D, JCNw);