Enhanced error reporting.
@@ -2,9 +2,10 @@ ## Changelog
### v320-1 — TBD -#### New functionality +#### New Features - Now detecting if an audio backend is present. If not, beeper errors out when used. +- Enhanced error reporting: now printing a user-friendly debug message in case of every error and returning xyw error code as program error. #### Fixes
@@ -1,3 +1,4 @@
+#include <stdio.h> #include <stdlib.h> #include <string.h> #include "../xyw.h"@@ -92,6 +93,7 @@ {
(void)frequency_hz; (void)duration_ms; (void)volume; + XYW_DBG("Error: Beeper device not available\n"); *error = BEEPER_ERROR_DEVICE; }@@ -110,6 +112,7 @@ size_t total = 44 + data_bytes;
unsigned char *wav = (unsigned char *)malloc(total); if (!wav) { + XYW_DBG("Error: Unable to allocate memory for beeper device\n"); *error = BEEPER_ERROR_MEMORY; return; }@@ -134,6 +137,7 @@
// SND_SYNC: PlaySound doesn't return until the clip has finished. if (!PlaySoundA((LPCSTR)wav, NULL, SND_MEMORY | SND_SYNC)) { + XYW_DBG("Error: Unable to play beeper tone\n"); *error = BEEPER_ERROR_PLAYBACK; } free(wav);@@ -150,6 +154,7 @@ size_t frames;
short *buf = generate_square_wave(frequency_hz, duration_ms, volume, &frames); if (!buf) { + XYW_DBG("Error: Unable to allocate memory for beeper device\n"); *error = BEEPER_ERROR_MEMORY; return; }@@ -187,6 +192,7 @@
AudioQueueRef queue; if (AudioQueueNewOutput(&asbd, noop_callback, NULL, NULL, NULL, 0, &queue) != noErr) { + XYW_DBG("Error: Beeper device not available\n"); *error = BEEPER_ERROR_DEVICE; return; }@@ -195,6 +201,7 @@ AudioQueueBufferRef buf;
size_t bytes = frames * sizeof(short); if (AudioQueueAllocateBuffer(queue, (UInt32)bytes, &buf) != noErr) { + XYW_DBG("Error: Beeper device not available\n"); *error = BEEPER_ERROR_DEVICE; AudioQueueDispose(queue, true); return;@@ -205,6 +212,7 @@
if (AudioQueueEnqueueBuffer(queue, buf, 0, NULL) != noErr || AudioQueueStart(queue, NULL) != noErr) { + XYW_DBG("Error: Unable to play beeper tone\n"); *error = BEEPER_ERROR_PLAYBACK; AudioQueueDispose(queue, true); return;@@ -226,6 +234,7 @@ size_t frames;
short *buf = generate_square_wave(frequency_hz, duration_ms, volume, &frames); if (!buf) { + XYW_DBG("Error: Unable to allocate memory for beeper device\n"); *error = BEEPER_ERROR_MEMORY; return; }@@ -243,6 +252,7 @@ {
snd_pcm_t *pcm; if (snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) { + XYW_DBG("Error: Beeper device not available\n"); *error = BEEPER_ERROR_DEVICE; return; }@@ -250,6 +260,7 @@
if (snd_pcm_set_params(pcm, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 1, sample_rate, 1, 500000) < 0) { + XYW_DBG("Error: Beeper device not available\n"); *error = BEEPER_ERROR_DEVICE; snd_pcm_close(pcm); return;@@ -263,6 +274,7 @@ if (n < 0)
{ if (snd_pcm_recover(pcm, (int)n, 1) < 0) { + XYW_DBG("Error: Unable to play beeper tone\n"); *error = BEEPER_ERROR_PLAYBACK; break; }@@ -285,6 +297,7 @@ size_t frames;
short *buf = generate_square_wave(frequency_hz, duration_ms, volume, &frames); if (!buf) { + XYW_DBG("Error: Unable to allocate memory for beeper device\n"); *error = BEEPER_ERROR_MEMORY; return; }@@ -305,6 +318,7 @@ {
int fd = open("/dev/dsp", O_WRONLY); if (fd < 0) { + XYW_DBG("Error: Beeper device not available\n"); *error = BEEPER_ERROR_DEVICE; return; }@@ -321,6 +335,7 @@ }
if (write(fd, samples, frames * sizeof(short)) < 0) { + XYW_DBG("Error: Unable to play beeper tone\n"); *error = BEEPER_ERROR_PLAYBACK; } ioctl(fd, SNDCTL_DSP_SYNC, 0); // blocks until the driver has drained the buffer@@ -338,6 +353,7 @@ size_t frames;
short *buf = generate_square_wave(frequency_hz, duration_ms, volume, &frames); if (!buf) { + XYW_DBG("Error: Unable to allocate memory for beeper device\n"); *error = BEEPER_ERROR_MEMORY; return; }
@@ -147,7 +147,7 @@ XYW_POKEW(&data[FILE_SUCCESS], 0);
if (path_addr == 0 || buffer_addr == 0 || length == 0) { - XYW_DBG(" Invalid parameters for file_read\n"); + XYW_DBG("Error: Invalid parameters for file_read\n"); *error = FILE_ERROR_INVALID_OP; return; }@@ -182,7 +182,7 @@ hFind = FindFirstFileA(searchPath, &findData);
if (hFind == INVALID_HANDLE_VALUE) { - XYW_DBG(" Failed to open directory: %s\n", path); + XYW_DBG("Error: Unable to access directory '%s'\n", path); *error = FILE_ERROR_ACCESS_DENIED; return; }@@ -237,7 +237,7 @@ char full_path[FILE_MAX_PATH * 2 + 2];
if (!dir) { - XYW_DBG(" Failed to open directory: %s\n", path); + XYW_DBG("Error: Unable to access directory '%s'\n", path); *error = FILE_ERROR_ACCESS_DENIED; return; }@@ -314,7 +314,7 @@ file_close();
file_handle = fopen(path, "rb"); if (!file_handle) { - XYW_DBG(" Failed to open file: %s\n", path); + XYW_DBG("Error: Failed to open file '%s'\n", path); *error = FILE_ERROR_NOT_FOUND; return; }@@ -327,7 +327,7 @@
// Seek to cursor position, only if not already there if (ftell(file_handle) != file_cursor && fseek(file_handle, file_cursor, SEEK_SET) != 0) { - XYW_DBG(" Failed to seek in file: %s\n", path); + XYW_DBG("Error: Failed to seek in file '%s'\n", path); *error = FILE_ERROR_IO_ERROR; return; }@@ -361,7 +361,7 @@ XYW_POKEW(&data[FILE_SUCCESS], 0);
if (path_addr == 0 || buffer_addr == 0 || length == 0) { - XYW_DBG(" Invalid parameters for file_write\n"); + XYW_DBG("Error: Invalid parameters for file_write\n"); *error = FILE_ERROR_INVALID_OP; return; }@@ -407,7 +407,7 @@ }
if (!file_handle) { - XYW_DBG(" Failed to open file for writing: %s (errno=%d: %s)\n", path, errno, strerror(errno)); + XYW_DBG("Error: Failed to open file '%s' for writing (errno=%d: %s)\n", path, errno, strerror(errno)); *error = FILE_ERROR_ACCESS_DENIED; return; }@@ -473,7 +473,7 @@ XYW_POKEW(&data[FILE_SUCCESS], 0);
if (path_addr == 0) { - XYW_DBG(" Invalid path address for file_delete\n"); + XYW_DBG("Error: Invalid path address for file_delete\n"); *error = FILE_ERROR_INVALID_OP; return; }@@ -494,7 +494,7 @@ XYW_DBG(" Deleting file: %s\n", path);
if (remove(path) != 0) { - XYW_DBG(" Failed to delete file: %s\n", path); + XYW_DBG("Error: Failed to delete file '%s'\n", path); *error = FILE_ERROR_ACCESS_DENIED; return; }@@ -513,7 +513,9 @@ xyw_word path_addr = XYW_PEEKW(&data[FILE_PATH]);
char combined[FILE_MAX_PATH * 2]; if (path_addr == 0) + { return -1; + } if (get_path_string(path_addr, combined, sizeof(combined)) != 0) {@@ -541,6 +543,7 @@ XYW_POKEW(&data[FILE_SUCCESS], 0);
if (split_path_pair(data, src, dst, FILE_MAX_PATH) != 0) { + XYW_DBG("Error: Incorrect path pair specified\n"); *error = FILE_ERROR_INVALID_OP; return; }@@ -554,6 +557,7 @@
FILE *in = fopen(src, "rb"); if (!in) { + XYW_DBG("Error: Failed to open source file '%s'\n", src); *error = FILE_ERROR_NOT_FOUND; return; }@@ -562,6 +566,7 @@ FILE *out = fopen(dst, "wb");
if (!out) { fclose(in); + XYW_DBG("Error: Failed to access destination file '%s'\n", dst); *error = FILE_ERROR_ACCESS_DENIED; return; }@@ -596,6 +601,7 @@ XYW_POKEW(&data[FILE_SUCCESS], 0);
if (split_path_pair(data, src, dst, FILE_MAX_PATH) != 0) { + XYW_DBG("Error: Incorrect path pair specified\n"); *error = FILE_ERROR_INVALID_OP; return; }@@ -676,6 +682,7 @@ break;
default: if (op != 0) { + XYW_DBG("Error: Invalid file operation code: %2X", op); *error = FILE_ERROR_INVALID_OP; } break;
@@ -89,6 +89,7 @@ exec_pending = 0;
if (exec_stack_depth >= MAX_IMAGE_EXEC_DEPTH) { + XYW_DBG("Error: Maximum image execution depth exceeded\n"); data[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_EXEC_DEPTH_EXCEEDED; return; }
@@ -162,13 +162,14 @@ struct termios raw;
if (!isatty(STDIN_FILENO)) { + XYW_DBG("Error: Terminal is not a TTY\n"); *error = TERMINAL_ERROR_NOT_A_TTY; return; } if (tcgetattr(STDIN_FILENO, &terminal_orig_termios) != 0) { - XYW_DBG("terminal: tcgetattr failed, raw mode not enabled\n"); + XYW_DBG("Error: tcgetattr failed, terminal raw mode not enabled\n"); *error = TERMINAL_ERROR_NOT_A_TTY; return; }
@@ -115,9 +115,10 @@ break;
} else if (ext && strcmp(ext, ".xim") == 0) { - if (xyw_run(input_file) != 0) + xyw_byte result = xyw_run(input_file); + if (result != 0) { - fprintf(stderr, "Execution failed for file: %s\n", input_file); + fprintf(stderr, "Execution failed for file: %s (Error: $%2X)\n", input_file, result); return -1; } break;
@@ -120,6 +120,7 @@ static void ss_push_frame(xyw_word return_addr)
{ if (s >= SYSTEM_MAX_FRAMES) { + XYW_DBG("Error: System stack overflow\n"); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_SYSTEM_STACK_OVERFLOW; return; }@@ -139,6 +140,7 @@ static xyw_word ss_pop_frame()
{ if (s < 1) { + XYW_DBG("Error: System stack underflow\n"); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_SYSTEM_STACK_UNDERFLOW; return -1; }@@ -156,7 +158,7 @@ }
//// Internal VM state -static int XYW_SYSTEM_ERROR_state() +static int system_error_state() { return xyw_memory[SYSTEM_STATE] & XYW_STATE_ERROR; }@@ -195,7 +197,7 @@ }
int xyw_vm_is_running(void) { return system_running_state(); } int xyw_vm_is_waiting(void) { return system_waiting_state(); } -int xyw_vm_is_error_state(void) { return XYW_SYSTEM_ERROR_state(); } +int xyw_vm_is_error_state(void) { return system_error_state(); } void xyw_vm_reset(void) {@@ -219,6 +221,7 @@ static void us_push(xyw_byte val)
{ if (u > XYW_USER_STACK_SIZE - 1) { + XYW_DBG("Error: User stack overflow\n"); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_USER_STACK_OVERFLOW; return; }@@ -229,6 +232,7 @@ static void us_pushw(xyw_word val)
{ if (u > XYW_USER_STACK_SIZE - 2) { + XYW_DBG("Error: User stack overflow\n"); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_USER_STACK_OVERFLOW; return; }@@ -241,6 +245,7 @@ static xyw_byte us_pop()
{ if (u < 1) { + XYW_DBG("Error: User stack underflow\n"); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_USER_STACK_UNDERFLOW; return -1; }@@ -254,6 +259,7 @@ static xyw_word us_popw()
{ if (u < 2) { + XYW_DBG("Error: User stack underflow\n"); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_USER_STACK_UNDERFLOW; return -1; }@@ -426,10 +432,10 @@ {
FILE *fp = fopen(path, "rb"); if (!fp) { - fprintf(stderr, "Error - Could not open file [%s]\n", path); + XYW_DBG("Error: Image file '%s' not found\n", path); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_IMAGE_NOT_FOUND; xyw_memory[SYSTEM_STATE] &= ~XYW_STATE_RUNNING; - return -1; + return XYW_SYSTEM_ERROR_IMAGE_NOT_FOUND; } fseek(fp, 0, SEEK_END); long file_size = ftell(fp);@@ -437,29 +443,29 @@ fseek(fp, 0, SEEK_SET);
if (file_size < 0) { - fprintf(stderr, "Error - Could not determine file size [%s]\n", path); + XYW_DBG("Error: Unable to determine size of image file '%s'\n", path); fclose(fp); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_IMAGE_READ_ERROR; xyw_memory[SYSTEM_STATE] &= ~XYW_STATE_RUNNING; - return -1; + return XYW_SYSTEM_ERROR_IMAGE_READ_ERROR; } if ((size_t)file_size > XYW_MEMORY_SIZE) { - fprintf(stderr, "Error - Image exceeds %d-byte memory size [%s]\n", XYW_MEMORY_SIZE, path); + XYW_DBG("Error: Image file '%s' is too large (%ld bytes)\n", path, file_size); fclose(fp); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_IMAGE_TOO_LARGE; xyw_memory[SYSTEM_STATE] &= ~XYW_STATE_RUNNING; - return -1; + return XYW_SYSTEM_ERROR_IMAGE_TOO_LARGE; } size_t bytes_read = fread(&xyw_memory[0x000], 1, XYW_MEMORY_SIZE - 0x000, fp); fclose(fp); if (bytes_read == 0) { - fprintf(stderr, "Error - Could not read file contents [%s]\n", path); + XYW_DBG("Error: Unable to read image file '%s'\n", path); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_IMAGE_READ_ERROR; xyw_memory[SYSTEM_STATE] &= ~XYW_STATE_RUNNING; - return -1; + return XYW_SYSTEM_ERROR_IMAGE_READ_ERROR; } xyw_memory[SYSTEM_STATE] |= XYW_STATE_RUNNING;@@ -624,7 +630,7 @@ /* SHR */ OPC_SR1r(0x0B, xyw_byte val = us_pop(); SETX(ARGX >> val); SETY(ARGY >> val); );
/* ADD */ OPC_SR2(0x0C, PUSH(a + b)); /* SUB */ OPC_SR2(0x0D, PUSH(a - b)); /* MUL */ OPC_SR2(0x0E, PUSH(a * b)); - /* DIV */ OPC_SR2(0x0F, if (b) { PUSH(a % b); PUSH(a / b); } else { xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_DIVISION_BY_ZERO; } ); + /* DIV */ OPC_SR2(0x0F, if (b) { PUSH(a % b); PUSH(a / b); } else { XYW_DBG("Error: Division by zero\n"); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_DIVISION_BY_ZERO; } ); /* EQU */ OPC_SR2(0x10, us_push(a == b)); /* NEQ */ OPC_SR2(0x11, us_push(a != b)); /* GTH */ OPC_SR2(0x12, us_push(a > b));@@ -646,6 +652,7 @@ /* RTS */ case 0x1F:
*pc = ss_pop_frame()-1; break; default: + XYW_DBG("Error: Invalid opcode\n"); xyw_memory[SYSTEM_ERROR] = XYW_SYSTEM_ERROR_INVALID_OPCODE; break; // clang-format on@@ -685,9 +692,10 @@ atexit(xyw_teardown_devices);
signal(SIGINT, xyw_signal_exit); signal(SIGTERM, xyw_signal_exit); - if (xyw_vm_load_image(input, NULL) != 0) + xyw_byte result = xyw_vm_load_image(input, NULL); + if (result != 0) { - return -1; + return result; } XYW_DBG("Loaded image into memory\n");