devices/system.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../xyw.h"
#define SYSTEM_STATE 0x00
#define SYSTEM_ERROR 0x01
#define SYSTEM_PAGE 0x02
#define SYSTEM_RANDOM 0x03
#define SYSTEM_ON_ERROR 0x04
#define SYSTEM_IMAGE_EXEC 0x06
#define MAX_IMAGE_EXEC_DEPTH 8
#define MAX_IMAGE_EXEC_PATH_LENGTH 256
/// Error handler tracking
static xyw_byte error_handler_entry_s = 0;
/// Exec stack management
static xyw_vm_snapshot exec_stack[MAX_IMAGE_EXEC_DEPTH];
static int exec_stack_depth = 0;
static int exec_pending = 0;
static char exec_path_buf[MAX_IMAGE_EXEC_PATH_LENGTH];
void system_setup(xyw_byte *data)
{
(void)data;
srand(time(NULL));
error_handler_entry_s = 0;
}
xyw_byte system_input(xyw_byte *data, xyw_byte addr, xyw_byte *error)
{
if (addr == SYSTEM_RANDOM)
return (xyw_byte)(rand() & 0xFF);
(void)error;
return data[addr];
}
static void get_string_from_memory(xyw_word addr, char *buf, size_t bufsize)
{
size_t i;
for (i = 0; i < bufsize - 1 && xyw_memory[addr + i] != 0; i++)
buf[i] = xyw_memory[addr + i];
buf[i] = '\0';
}
static void request_exec(xyw_word path_addr)
{
get_string_from_memory(path_addr, exec_path_buf, sizeof(exec_path_buf));
exec_pending = 1;
}
void system_output(xyw_byte *data, xyw_byte addr, xyw_byte *error)
{
(void)error;
if (addr == SYSTEM_IMAGE_EXEC + 1)
{
xyw_word target = XYW_PEEKW(&data[SYSTEM_IMAGE_EXEC]);
if (target != 0)
request_exec(target);
}
}
static void split_exec_string(char *full, char **path, char **argstart)
{
char *sp = strchr(full, ' ');
if (sp)
{
*sp = '\0';
*argstart = sp + 1;
}
else
{
*argstart = NULL;
}
*path = full;
}
static void handle_exec_requests(xyw_byte *data)
{
if (!exec_pending)
return;
exec_pending = 0;
if (exec_stack_depth >= MAX_IMAGE_EXEC_DEPTH)
{
data[SYSTEM_ERROR] = XYW_ERROR_EXEC_DEPTH_EXCEEDED;
return;
}
xyw_vm_save_snapshot(&exec_stack[exec_stack_depth++]);
char path_copy[MAX_IMAGE_EXEC_PATH_LENGTH];
strncpy(path_copy, exec_path_buf, sizeof(path_copy) - 1);
path_copy[sizeof(path_copy) - 1] = '\0';
char *path, *argstart;
split_exec_string(path_copy, &path, &argstart);
xyw_vm_reset();
if (xyw_vm_load_image(path, argstart) != 0)
{
// Restore parent state so error handler can run in the caller's context
xyw_vm_restore_snapshot(&exec_stack[--exec_stack_depth]);
}
}
void system_tick(xyw_byte *data)
{
// Check if returning from error handler (after RTS popped the frame)
if ((data[SYSTEM_STATE] & XYW_STATE_ERROR) &&
error_handler_entry_s != 0 &&
xyw_vm_get_system_depth() == error_handler_entry_s)
{
data[SYSTEM_STATE] &= ~XYW_STATE_ERROR;
error_handler_entry_s = 0;
}
// Check for new error condition
if (data[SYSTEM_ERROR] != XYW_ERROR_NONE && !(data[SYSTEM_STATE] & XYW_STATE_ERROR))
{
xyw_word on_error_handler = XYW_PEEKW(&data[SYSTEM_ON_ERROR]);
if (on_error_handler != 0)
{
XYW_DBG("Error occurred: %02X, jumping to error handler at %04X\n", data[SYSTEM_ERROR], on_error_handler);
data[SYSTEM_STATE] |= XYW_STATE_ERROR;
error_handler_entry_s = xyw_vm_get_system_depth();
xyw_vm_push_frame(*pc);
*pc = on_error_handler;
}
else
{
// No error handler: halt execution
data[SYSTEM_STATE] &= ~XYW_STATE_RUNNING;
}
}
// Handle exec requests
handle_exec_requests(data);
}
void system_save(xyw_byte *data, xyw_byte *state)
{
(void)data;
state[0] = error_handler_entry_s;
}
void system_restore(xyw_byte *data, const xyw_byte *state)
{
(void)data;
error_handler_entry_s = state[0];
}
int xyw_system_try_restore_parent(void)
{
if (exec_stack_depth > 0)
{
xyw_vm_restore_snapshot(&exec_stack[--exec_stack_depth]);
return 1;
}
return 0;
}
|