all repos — xyw @ 3f803629c71a6e57353a27a9c5f70cf25d308563

A minimal virtual machine and assembler for terminals.

Fixed assembler problems.
h3rald h3rald@h3rald.com
Mon, 01 Dec 2025 15:26:59 +0100
commit

3f803629c71a6e57353a27a9c5f70cf25d308563

parent

00a108b7d04201efbda539b47b58b843869108de

4 files changed, 116 insertions(+), 88 deletions(-)

jump to
M xyw.cxyw.c

@@ -4,6 +4,17 @@ #include "xyw.h"

int xyw_debug = 0; +// Instruction mnemonics definition +const char xyw_instructions[][4] = { + "BRK", "PSH", "POP", "LDR", + "LDA", "STA", "LDD", "STD", + "INC", "DEC", "SHL", "SHR", + "ADD", "SUB", "MUL", "DIV", + "EQU", "NEQ", "GTH", "LTH", + "AND", "IOR", "XOR", "NOT", + "SWP", "DUP", "OVR", "ROT", + "JMP", "JCN", "JSR", "RTS"}; + //// Main Function int main(int argc, char *argv[]) {

@@ -20,9 +31,36 @@ const char *input_file = argv[i];

// Output file is the same as input but with .rom extension char output_file[256]; snprintf(output_file, sizeof(output_file), "%.*s.xim", (int)(strlen(input_file) - 4), input_file); - if (xyw_assemble(input_file, output_file) != 0) + // Only assemble if input file ends with .xyw + const char *ext = strrchr(input_file, '.'); + if (ext && strcmp(ext, ".xyw") == 0) { - fprintf(stderr, "Assembly failed for file: %s\n", input_file); + if (xyw_assemble(input_file, output_file) != 0) + { + fprintf(stderr, "Assembly failed for file: %s\n", input_file); + return -1; + } + else + { + if (xyw_debug) + { + printf("Assembled %s to %s\n", input_file, output_file); + } + } + } + else if (ext && strcmp(ext, ".xim") == 0) + { + // Load and run the .xim file + // (Assuming a run function exists) + if (run(input_file) != 0) + { + fprintf(stderr, "Execution failed for file: %s\n", input_file); + return -1; + } + } + else + { + fprintf(stderr, "Unsupported file type: %s\n", input_file); return -1; } }
M xyw.hxyw.h

@@ -4,12 +4,18 @@

#define XYW_MODE_X 0x20 #define XYW_MODE_Y 0x40 #define XYW_MODE_W 0x80 +// clang-format off +#define dbg(...) do { if (xyw_debug) fprintf(stdout, __VA_ARGS__); } while(0) +// clang-format on typedef unsigned char xyw_byte; typedef unsigned short xyw_word; +extern const char xyw_instructions[][4]; +// Number of instruction mnemonics +#define XYW_INSTRUCTION_COUNT 32 extern int xyw_debug; int xyw_assemble(const char *input, const char *output); -int run(); +int run(const char *input); #endif // XYW_H
M xywasm.cxywasm.c

@@ -10,8 +10,6 @@

#define error(msg) fprintf(stderr, "Error - %s [%s]\n", msg, ctx->file) #define token_error(msg) fprintf(stderr, "Error - %s: %s [%s - Ln %d, Col %d]\n", token, msg, ctx->file, ctx->line, ctx->column) #define symbol_error(symbol, msg) fprintf(stderr, "Error - %s: %s [%s - Ln %d, Col %d]\n", symbol, msg, ctx->file, ctx->line, ctx->column) -// clang-format off -#define dbg(...) do { if (xyw_debug) fprintf(stdout, __VA_ARGS__); } while(0) #define PSH 0x01

@@ -63,17 +61,6 @@ TOKEN_END_SPACE,

TOKEN_END_INVALID } xyw_token_terminator; -// Instruction mnemonics -static char xyw_instructions[][4] = { - "BRK", "PSH", "POP", "LDR", - "LDA", "STA", "LDD", "STD", - "INC", "DEC", "SHL", "SHR", - "ADD", "SUB", "MUL", "DIV", - "EQU", "NEQ", "GTH", "LTH", - "AND", "IOR", "XOR", "NOT", - "SWP", "DUP", "OVR", "ROT", - "JMP", "JCN", "JSR", "RTS"}; - // The token being processed static char token[TOKEN_MAX_LENGTH]; static unsigned int token_length = 0;

@@ -84,7 +71,7 @@ // Tracks whether we are inside a directive or not

static unsigned int directive = 0; // Bytecode to be written, including header -xyw_byte data[0xffff] = { (xyw_byte)0x0F, (xyw_byte)'x', (xyw_byte)'y', (xyw_byte)'w', (xyw_byte)0x00, (xyw_byte)0xF0 }; +xyw_byte data[0xffff] = {(xyw_byte)0x0F, (xyw_byte)'x', (xyw_byte)'y', (xyw_byte)'w', (xyw_byte)0x00, (xyw_byte)0xF0}; // Current write pointer starts after header xyw_word ptr = 6;

@@ -160,7 +147,6 @@ static int assemble_string(xyw_context *ctx);

static int assemble_file(xyw_context *ctx); //// Utilities - static int find_symbol(char *name) {

@@ -248,8 +234,9 @@ static inline void write(xyw_word addr, xyw_word val)

{ if (val > 0xff) { - data[addr] = val & 0xFF; - data[addr+1] = (val >> 8) & 0xFF; + data[addr] = (val >> 8) & 0xFF; + data[addr + 1] = val & 0xFF; + ptr++; return; } data[addr] = (xyw_byte)val;

@@ -422,7 +409,7 @@ {

(void)ctx; xyw_byte opcode = 0; // Match token against instruction mnemonics - for (unsigned int i = 0; i < sizeof(xyw_instructions) / sizeof(xyw_instructions[0]); i++) + for (unsigned int i = 0; i < XYW_INSTRUCTION_COUNT; i++) { if (strcmpn(token, xyw_instructions[i], 3) == 0) {

@@ -460,14 +447,7 @@ byte_to_binary(opcode, bits);

dbg("Instruction:\t%s\t(%02X - %s)\n", token, opcode, bits); token_type = TOKEN_TYPE_INSTRUCTION; token_value = opcode; - if (!directive) - { - push(opcode); - } - else - { - append(opcode); - } + append(opcode); return 0; } }
M xywrun.cxywrun.c

@@ -1,11 +1,14 @@

+#include <stdio.h> #include "xyw.h" #define MEMORY_SIZE 0xffff #define STACK_SIZE 0xff -#define DEVICE_AREA_START 0x0000 -#define SYSTEM_STACK_START 0x0100 -#define USER_STACK_START 0x0200 -#define USER_MEMORY_START 0x0300 + +#define USER_MEMORY_START 0x000 +#define SYSTEM_MEMORY_START 0xfd00 +#define USER_STACK_START 0xfd00 +#define SYSTEM_STACK_START 0xfe00 +#define DEVICE_AREA_START 0xff00 typedef enum {

@@ -17,54 +20,19 @@ XYW_ERROR_DEVICE_ERROR

} xyw_error; /* system device */ -#define SYSTEM_STATE 0x00 -#define SYSTEM_ERROR 0x01 -#define SYSTEM_SSP 0x02 -#define SYSTEM_USP 0x03 -#define SYSTEM_PAGE 0x0C -#define SYSTEM_ON_ERROR 0x0D +#define SYSTEM_STATE 0xff00 +#define SYSTEM_ERROR 0xff01 +#define SYSTEM_SSP 0xff02 +#define SYSTEM_USP 0xff03 +#define SYSTEM_PAGE 0xff04 +#define SYSTEM_ON_ERROR 0xff05 /* console device */ -#define CONSOLE_BASE 0x10 -#define CONSOLE_INPUT 0x10 -#define CONSOLE_OUTPUT 0x11 -#define CONSOLE_ERROR 0x12 -#define CONSOLE_ON_KEYPRESS 0x13 - -/* clock device */ -#define CLOCK_YEAR 0x20 -#define CLOCK_MONTH 0x22 -#define CLOCK_WEEK 0x23 -#define CLOCK_MONTHDAY 0x24 -#define CLOCK_WEEKDAY 0x25 -#define CLOCK_HOUR 0x26 -#define CLOCK_MINUTE 0x27 -#define CLOCK_SECOND 0x28 -#define CLOCK_TIMER 0x29 -#define CLOCK_ON_TIMER_ELAPSED 0x2B - -/* file device */ -#define FILE_PATH 0x30 -#define FILE_OPERATION 0x32 -#define FILE_STATE 0x33 -#define FILE_TYPE 0x34 -#define FILE_READ 0x35 -#define FILE_WRITE 0x36 -#define FILE_APPEND 0x37 - -/* display device */ -#define DISPLAY_WIDTH 0x40 -#define DISPLAY_HEIGHT 0x41 -#define DISPLAY_FILL 0x42 -#define DISPLAY_X 0x43 -#define DISPLAY_Y 0x44 -#define DISPLAY_ON_RENDER 0x45 - -/* display device */ -#define BUZZER_STATE 0x50 -#define BUZZER_SAMPLES 0x51 -#define BUZZER_N_SAMPLES 0x53 -#define BUZZER_ON_STOP 0x55 +#define CONSOLE_BASE 0xff10 +#define CONSOLE_INPUT 0xff10 +#define CONSOLE_OUTPUT 0xff11 +#define CONSOLE_ERROR 0xff12 +#define CONSOLE_ON_KEYPRESS 0xff13 /// Main memory and stacks xyw_byte xyw_memory[MEMORY_SIZE];

@@ -74,13 +42,18 @@

//// 1-byte pointers and registers xyw_byte *ssp = &xyw_memory[SYSTEM_SSP]; xyw_byte *usp = &xyw_memory[SYSTEM_USP]; -xyw_byte *x = 0x00; -xyw_byte *y = 0x00; +static xyw_byte x_val = 0; // X register storage +static xyw_byte y_val = 0; // Y register storage +xyw_byte *x = &x_val; +xyw_byte *y = &y_val; //// 2-byte registers -xyw_word *pc = 0x00; -xyw_word *xw = 0x00; -xyw_word *yw = 0x00; +static xyw_word pc_storage = 0; // Program counter storage +static xyw_word xw_storage = 0; // 16-bit X register storage +static xyw_word yw_storage = 0; // 16-bit Y register storage +xyw_word *pc = &pc_storage; +xyw_word *xw = &xw_storage; +xyw_word *yw = &yw_storage; //// Helpers to manage 2-byte values to memory (big-endian)

@@ -472,11 +445,44 @@ case XYW_MODE_Y|XYW_MODE_W|opcode: op(*yw); break;

// clang-format on -int run() +int run(const char *input) { + + // Load bytecode into memory + FILE *fp = fopen(input, "rb"); + if (!fp) + { + fprintf(stderr, "Error - Could not open file [%s]\n", input); + return -1; + } + // Check header + xyw_byte header[6]; + printf("Reading header from file [%s]\n", input); + fread(header, 1, 6, fp); + if (header[0] != 0x0F || header[1] != 'x' || header[2] != 'y' || header[3] != 'w' || header[4] != 0x00 || header[5] != 0xF0) + { + fprintf(stderr, "Error - Invalid file header [%s]\n", input); + fclose(fp); + return -1; + } + printf("File header OK\n"); + // Load the rest of the file into memory + size_t bytes_read = fread(&xyw_memory[USER_MEMORY_START], 1, MEMORY_SIZE - USER_MEMORY_START, fp); + printf("Read %zu bytes into memory\n", bytes_read); + if (bytes_read == 0) + { + fprintf(stderr, "Error - Could not read file contents [%s]\n", input); + fclose(fp); + return -1; + } + fclose(fp); + printf("Starting execution...\n"); xyw_memory[SYSTEM_STATE] = 1; - while (xyw_memory[SYSTEM_STATE]) + printf("PC: %04X: opcode: %02X\n", *pc, xyw_memory[*pc]); + while (xyw_memory[SYSTEM_STATE] && *pc < 20) { + printf("PC: %04X\n", *pc); + dbg("Executing opcode: %02X (%s)\n", xyw_memory[*pc], xyw_instructions[xyw_memory[*pc] & 0x1F]); switch (xyw_memory[*pc]) { // clang-format off

@@ -529,7 +535,6 @@ /* AND */ InOP(0x14, &);

/* IOR */ InOP(0x15, |); /* XOR */ InOP(0x16, ^); /* NOT */ UnOP(0x17, ~); - /* SWP */ PrOP2(0x18, SWP); /* SWPw */ PrOP2w(0x18, SWPw); /* DUP */ PrOP(0x19, DUP);

@@ -538,7 +543,6 @@ /* OVR */ PrOP2(0x1A, OVR);

/* OVRw */ PrOP2w(0x1A, OVRw); /* ROT */ PrOP2(0x1B, ROT); /* ROTw */ PrOP2w(0x1B, ROTw); - /* JMP */ case 0x1C: JMP(); break; /* JCN */ PrOP(0x1D, JCN); /* JCNw */ PrOPw(0x1D, JCNw);