From 0c3a3f0d7598a27e47042749e722a9f7f0f7b18b Mon Sep 17 00:00:00 2001 From: IonutParau Date: Fri, 25 Jul 2025 18:10:16 +0200 Subject: [PATCH] disk drives and resources --- build.zig | 4 +- src/components/diskDrive.c | 112 +++++++++++++++++++++++++++++++++++++ src/components/gpu.c | 2 +- src/computer.c | 95 +++++++++++++++++++++++++++++++ src/computer.h | 10 +++- src/neonucleus.h | 49 +++++++++++++++- src/resource.c | 29 ++++++++++ src/resource.h | 21 +++++++ src/testLuaArch.c | 1 + src/universe.c | 1 + src/value.c | 7 +++ 11 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 src/components/diskDrive.c create mode 100644 src/resource.c create mode 100644 src/resource.h diff --git a/build.zig b/build.zig index ab72490..ffa9c98 100644 --- a/build.zig +++ b/build.zig @@ -24,6 +24,7 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module { "src/lock.c", "src/utils.c", "src/value.c", + "src/resource.c", "src/component.c", "src/computer.c", "src/universe.c", @@ -40,6 +41,7 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module { "src/components/keyboard.c", "src/components/modem.c", "src/components/loopbackModem.c", + "src/components/diskDrive.c", }, .flags = &.{ if(opts.baremetal) "-DNN_BAREMETAL" else "", @@ -178,7 +180,7 @@ pub fn build(b: *std.Build) !void { emulator.linkLibrary(raylib.artifact("raylib")); } - const luaVer = b.option(LuaVersion, "lua", "The version of Lua to use.") orelse LuaVersion.lua52; + const luaVer = b.option(LuaVersion, "lua", "The version of Lua to use.") orelse LuaVersion.lua53; emulator.addCSourceFiles(.{ .files = &.{ "src/testLuaArch.c", diff --git a/src/components/diskDrive.c b/src/components/diskDrive.c new file mode 100644 index 0000000..e99a895 --- /dev/null +++ b/src/components/diskDrive.c @@ -0,0 +1,112 @@ +#include "../neonucleus.h" + +typedef struct nn_diskDrive { + nn_Context ctx; + nn_guard *lock; + nn_refc refc; + nn_diskDriveTable table; +} nn_diskDrive; + +nn_diskDrive *nn_newDiskDrive(nn_Context *context, nn_diskDriveTable table) { + nn_diskDrive *drive = nn_alloc(&context->allocator, sizeof(nn_diskDrive)); + if(drive == NULL) return NULL; + drive->lock = nn_newGuard(context); + if(drive->lock == NULL) { + nn_dealloc(&context->allocator, drive, sizeof(nn_diskDrive)); + } + drive->refc = 1; + drive->table = table; + drive->ctx = *context; + return drive; +} + +nn_guard *nn_getDiskDriveLock(nn_diskDrive *diskDrive) { + return diskDrive->lock; +} + +void nn_retainDiskDrive(nn_diskDrive *diskDrive) { + nn_incRef(&diskDrive->refc); +} + +nn_bool_t nn_destroyDiskDrive(nn_diskDrive *diskDrive) { + if(!nn_decRef(&diskDrive->refc)) return false; + if(diskDrive->table.deinit != NULL) { + diskDrive->table.deinit(diskDrive->table.userdata); + } + nn_Context ctx = diskDrive->ctx; + nn_Alloc a = ctx.allocator; + + nn_deleteGuard(&ctx, diskDrive->lock); + nn_dealloc(&a, diskDrive, sizeof(nn_diskDrive)); + return true; +} + +void nn_diskDrive_destroy(void *_, nn_component *component, nn_diskDrive *diskDrive) { + nn_destroyDiskDrive(diskDrive); +} + +void nn_diskDrive_eject(nn_diskDrive *diskDrive, void *_, nn_component *component, nn_computer *computer) { + double velocity = nn_toNumberOr(nn_getArgument(computer, 0), 0); + + nn_errorbuf_t err = ""; + nn_lock(&diskDrive->ctx, diskDrive->lock); + if(diskDrive->table.isEmpty(diskDrive->table.userdata)) { + nn_unlock(&diskDrive->ctx, diskDrive->lock); + nn_return_boolean(computer, false); + return; + } + diskDrive->table.eject(diskDrive->table.userdata, velocity, err); + nn_unlock(&diskDrive->ctx, diskDrive->lock); + + if(!nn_error_isEmpty(err)) { + nn_setError(computer, err); + return; + } + + nn_return_boolean(computer, true); +} + +void nn_diskDrive_isEmpty(nn_diskDrive *diskDrive, void *_, nn_component *component, nn_computer *computer) { + nn_lock(&diskDrive->ctx, diskDrive->lock); + nn_bool_t empty = diskDrive->table.isEmpty(diskDrive->table.userdata); + nn_unlock(&diskDrive->ctx, diskDrive->lock); + + nn_return_boolean(computer, empty); +} + +void nn_diskDrive_media(nn_diskDrive *diskDrive, void *_, nn_component *component, nn_computer *computer) { + nn_errorbuf_t err = ""; + nn_Alloc *a = &diskDrive->ctx.allocator; + nn_lock(&diskDrive->ctx, diskDrive->lock); + if(diskDrive->table.isEmpty(diskDrive->table.userdata)) { + nn_unlock(&diskDrive->ctx, diskDrive->lock); + nn_setCError(computer, "drive is empty"); + return; + } + nn_address s = diskDrive->table.media(diskDrive->table.userdata, a, err); + nn_unlock(&diskDrive->ctx, diskDrive->lock); + + if(!nn_error_isEmpty(err)) { + nn_deallocStr(a, s); + nn_setError(computer, err); + return; + } + + nn_return_string(computer, s, nn_strlen(s)); + nn_deallocStr(a, s); +} + +void nn_loadDiskDriveTable(nn_universe *universe) { + nn_componentTable *diskDriveTable = nn_newComponentTable(nn_getAllocator(universe), "disk_drive", NULL, NULL, (void *)nn_diskDrive_destroy); + nn_storeUserdata(universe, "NN:DISK_DRIVE", diskDriveTable); + + nn_defineMethod(diskDriveTable, "eject", (nn_componentMethod *)nn_diskDrive_eject, "eject([velocity: number]): boolean - Ejects the floopy, if present. Returns whether it was present."); + nn_defineMethod(diskDriveTable, "isEmpty", (nn_componentMethod *)nn_diskDrive_isEmpty, "isEmpty(): boolean - Returns whether the drive is empty."); + nn_defineMethod(diskDriveTable, "media", (nn_componentMethod *)nn_diskDrive_media, "media(): string - Returns the address of the inner floppy disk."); +} + +nn_component *nn_addDiskDrive(nn_computer *computer, nn_address address, int slot, nn_diskDrive *diskDrive) { + nn_componentTable *diskDriveTable = nn_queryUserdata(nn_getUniverse(computer), "NN:DISK_DRIVE"); + + return nn_newComponent(computer, address, slot, diskDriveTable, diskDrive); +} diff --git a/src/components/gpu.c b/src/components/gpu.c index 0e4bf41..d8da480 100644 --- a/src/components/gpu.c +++ b/src/components/gpu.c @@ -220,6 +220,7 @@ nni_gpu *nni_newGPU(nn_Alloc *alloc, nn_gpuControl *ctrl) { for(int i = 0; i < ctrl->maximumBufferCount; i++) { gpu->buffers[i] = NULL; } + gpu->activeBuffer = 0; gpu->usedVRAM = 0; return gpu; } @@ -320,7 +321,6 @@ void nni_gpu_set(nni_gpu *gpu, void *_, nn_component *component, nn_computer *co } if(gpu->activeBuffer != 0) { - nni_buffer *buffer = gpu->buffers[gpu->activeBuffer - 1]; nni_vram_set(gpu, x, y, s, isVertical); return; } diff --git a/src/computer.c b/src/computer.c index 6d59d74..b52b726 100644 --- a/src/computer.c +++ b/src/computer.c @@ -2,6 +2,7 @@ #include "component.h" #include "universe.h" #include "neonucleus.h" +#include "resource.h" nn_computer *nn_newComputer(nn_universe *universe, nn_address address, nn_architecture *arch, void *userdata, nn_size_t memoryLimit, nn_size_t componentLimit) { nn_Alloc *alloc = &universe->ctx.allocator; @@ -58,6 +59,11 @@ nn_computer *nn_newComputer(nn_universe *universe, nn_address address, nn_archit return NULL; } + c->rid = NN_NULL_RESOURCE; + for(nn_size_t i = 0; i < NN_MAX_CONCURRENT_RESOURCES; i++) { + c->resources[i].id = NN_NULL_RESOURCE; + } + return c; } @@ -135,6 +141,11 @@ void nn_deleteComputer(nn_computer *computer) { for(nn_size_t i = 0; i < computer->userCount; i++) { nn_deallocStr(a, computer->users[i]); } + for(nn_size_t i = 0; i < NN_MAX_CONCURRENT_RESOURCES; i++) { + if(computer->resources[i].id != NN_NULL_RESOURCE) { + nn_resource_release(computer, computer->resources[i].id); + } + } computer->arch->teardown(computer, computer->archState, computer->arch->userdata); nn_deleteGuard(&computer->universe->ctx, computer->lock); nn_deallocStr(a, computer->address); @@ -524,6 +535,10 @@ nn_value nn_return_table(nn_computer *computer, nn_size_t len) { return val; } +void nn_return_resource(nn_computer *computer, nn_size_t userdata) { + nn_return(computer, nn_values_resource(userdata)); +} + nn_bool_t nn_wakeupMatches(nn_value *values, nn_size_t valueLen, const char *wakeUp, nn_bool_t fuzzy) { if(valueLen == 0) return false; nn_value header = values[0]; @@ -551,3 +566,83 @@ const char *nn_pushNetworkMessage(nn_computer *computer, nn_address receiver, nn return nn_pushSignal(computer, buffer, valueLen + 5); } + +static nn_resource_t *nn_resource_find(nn_computer *computer, nn_size_t id) { + for(nn_size_t i = 0; i < NN_MAX_CONCURRENT_RESOURCES; i++) { + if(computer->resources[i].id == id) { + return computer->resources + i; + } + } + return NULL; +} + +nn_size_t nn_resource_allocate(nn_computer *computer, void *userdata, nn_resourceTable_t *table) { + nn_size_t i = 0; + for(nn_size_t j = 0; j < NN_MAX_CONCURRENT_RESOURCES; j++) { + if(computer->resources[j].id == NN_NULL_RESOURCE) { + i = j; + goto slotFound; + } + } + return NN_NULL_RESOURCE; +slotFound: + computer->rid++; + nn_size_t rid = computer->rid; + computer->resources[i] = (nn_resource_t) { + .id = rid, + .ptr = userdata, + .table = table, + }; + return rid; +} + +void nn_resource_release(nn_computer *computer, nn_size_t id) { + nn_resource_t *res = nn_resource_find(computer, id); + if(res == NULL) return; + res->id = NN_NULL_RESOURCE; + if(res->table->dtor != NULL) { + res->table->dtor(res->ptr); + } +} + +nn_resourceTable_t *nn_resource_fetchTable(nn_computer *computer, nn_size_t resourceID) { + nn_resource_t *res = nn_resource_find(computer, resourceID); + if(res == NULL) return NULL; + return res->table; +} + +nn_bool_t nn_resource_invoke(nn_computer *computer, nn_size_t resourceID, const char *method) { + nn_resource_t *res = nn_resource_find(computer, resourceID); + if(res == NULL) return false; + nn_resourceTable_t *t = res->table; + for(nn_size_t i = 0; i < t->methodCount; i++) { + nn_resourceMethod_t m = t->methods[i]; + if(nn_strcmp(m.name, method) != 0) continue; + if(m.condition != NULL) { + if(!m.condition(res->ptr, m.userdata)) continue; + } + m.callback(res->ptr, m.userdata, computer); + return true; + } + return false; +} + +// returns the name, and NULL for out of bounds +const char *nn_resource_nextMethodInfo(nn_computer *computer, nn_size_t id, const char **doc, nn_size_t *idx) { + nn_resource_t *res = nn_resource_find(computer, id); + if(res == NULL) return false; + nn_resourceTable_t *t = res->table; + for(nn_size_t i = *idx; i < t->methodCount; i++) { + nn_resourceMethod_t method = t->methods[i]; + if(method.condition != NULL) { + if(!method.condition(res->ptr, method.userdata)) { + continue; + } + } + + *idx = i + 1; + *doc = method.doc; + return method.name; + } + return NULL; +} diff --git a/src/computer.h b/src/computer.h index 5449c18..439adc1 100644 --- a/src/computer.h +++ b/src/computer.h @@ -8,6 +8,12 @@ typedef struct nn_signal { nn_value values[NN_MAX_SIGNAL_VALS]; } nn_signal; +typedef struct nn_resource_t { + size_t id; + void *ptr; + nn_resourceTable_t *table; +} nn_resource_t; + typedef struct nn_computer { char state; nn_bool_t allocatedError; @@ -21,7 +27,7 @@ typedef struct nn_computer { nn_size_t argc; nn_value rets[NN_MAX_RETS]; nn_size_t retc; - nn_architecture *arch; + nn_architecture *arch; // btw void *archState; nn_architecture *nextArch; nn_architecture *supportedArch[NN_MAX_ARCHITECTURES]; @@ -42,6 +48,8 @@ typedef struct nn_computer { double roomTemperature; double callCost; double callBudget; + nn_size_t rid; + nn_resource_t resources[NN_MAX_CONCURRENT_RESOURCES]; } nn_computer; #endif diff --git a/src/neonucleus.h b/src/neonucleus.h index ed33636..769ed99 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -119,6 +119,8 @@ extern "C" { #define NN_MAX_CHANNEL_SIZE 256 #define NN_TUNNEL_PORT 0 #define NN_PORT_CLOSEALL 0 +#define NN_MAX_CONCURRENT_RESOURCES 64 +#define NN_NULL_RESOURCE 0 #define NN_OVERHEAT_MIN 100 #define NN_CALL_HEAT 0.05 @@ -243,6 +245,7 @@ void nn_error_clear(nn_errorbuf_t buf); #define NN_VALUE_ARRAY 5 #define NN_VALUE_TABLE 6 #define NN_VALUE_NIL 7 +#define NN_VALUE_RESOURCE 8 typedef struct nn_string { char *data; @@ -275,6 +278,7 @@ typedef struct nn_value { nn_string *string; nn_array *array; nn_table *table; + nn_size_t resourceID; }; } nn_value; @@ -542,6 +546,27 @@ const char *nn_getTableMethod(nn_componentTable *table, nn_size_t idx, nn_bool_t const char *nn_methodDoc(nn_componentTable *table, const char *methodName); nn_bool_t nn_isMethodEnabled(nn_component *component, const char *methodName); +// Resource stuff + +typedef struct nn_resourceTable_t nn_resourceTable_t; +typedef struct nn_resourceMethod_t nn_resourceMethod_t; + +typedef void nn_resourceDestructor_t(void *userdata); +typedef void nn_resourceMethodCallback_t(void *userdata, void *methodUserdata, nn_computer *computer); +typedef nn_bool_t nn_resourceMethodCondition_t(void *userdata, void *methodUserdata); + +nn_resourceTable_t *nn_resource_newTable(nn_Context *ctx, nn_resourceDestructor_t *dtor); +nn_resourceMethod_t *nn_resource_addMethod(nn_resourceTable_t *table, const char *methodName, nn_resourceMethodCallback_t *method, const char *doc); +void nn_resource_setUserdata(nn_resourceMethod_t *method, void *methodUserdata); +void nn_resource_setCondition(nn_resourceMethod_t *method, nn_resourceMethodCondition_t *methodCondition); +nn_bool_t nn_resource_invoke(nn_computer *computer, nn_size_t resourceID, const char *method); +// returns the name, and NULL for out of bounds +const char *nn_resource_nextMethodInfo(nn_computer *computer, nn_size_t id, const char **doc, nn_size_t *idx); + +nn_resourceTable_t *nn_resource_fetchTable(nn_computer *computer, nn_size_t resourceID); +nn_size_t nn_resource_allocate(nn_computer *computer, void *userdata, nn_resourceTable_t *table); +void nn_resource_release(nn_computer *computer, nn_size_t id); + // Component calling /* Returns false if the method does not exist */ @@ -565,6 +590,7 @@ nn_value nn_values_cstring(const char *string); nn_value nn_values_string(nn_Alloc *alloc, const char *string, nn_size_t len); nn_value nn_values_array(nn_Alloc *alloc, nn_size_t len); nn_value nn_values_table(nn_Alloc *alloc, nn_size_t pairCount); +nn_value nn_values_resource(nn_size_t id); void nn_return_nil(nn_computer *computer); void nn_return_integer(nn_computer *computer, nn_intptr_t integer); @@ -574,6 +600,7 @@ void nn_return_cstring(nn_computer *computer, const char *cstr); void nn_return_string(nn_computer *computer, const char *str, nn_size_t len); nn_value nn_return_array(nn_computer *computer, nn_size_t len); nn_value nn_return_table(nn_computer *computer, nn_size_t len); +void nn_return_resource(nn_computer *computer, nn_size_t userdata); nn_size_t nn_values_getType(nn_value val); nn_value nn_values_retain(nn_value val); @@ -616,6 +643,7 @@ void nn_loadGraphicsCardTable(nn_universe *universe); void nn_loadKeyboardTable(nn_universe *universe); void nn_loadModemTable(nn_universe *universe); void nn_loadTunnelTable(nn_universe *universe); +void nn_loadDiskDriveTable(nn_universe *universe); nn_component *nn_mountKeyboard(nn_computer *computer, nn_address address, int slot); @@ -998,7 +1026,26 @@ nn_guard *nn_getTunnelLock(nn_tunnel *tunnel); void nn_retainTunnel(nn_tunnel *tunnel); nn_bool_t nn_destroyTunnel(nn_tunnel *tunnel); -nn_component *nn_addTunnel(nn_computer *computer, nn_address address, int slot, nn_tunnel *modem); +nn_component *nn_addTunnel(nn_computer *computer, nn_address address, int slot, nn_tunnel *tunnel); + +typedef struct nn_diskDriveTable { + void *userdata; + void (*deinit)(void *userdata); + + // velocity is 0 or less for "default" + void (*eject)(void *userdata, double velocity, nn_errorbuf_t err); + nn_bool_t (*isEmpty)(void *userdata); + nn_address (*media)(void *userdata, nn_Alloc *alloc, nn_errorbuf_t err); +} nn_diskDriveTable; + +typedef struct nn_diskDrive nn_diskDrive; + +nn_diskDrive *nn_newDiskDrive(nn_Context *context, nn_diskDriveTable table); +nn_guard *nn_getDiskDriveLock(nn_diskDrive *diskDrive); +void nn_retainDiskDrive(nn_diskDrive *diskDrive); +nn_bool_t nn_destroyDiskDrive(nn_diskDrive *diskDrive); + +nn_component *nn_addDiskDrive(nn_computer *computer, nn_address address, int slot, nn_diskDrive *diskDrive); #ifdef __cplusplus } diff --git a/src/resource.c b/src/resource.c new file mode 100644 index 0000000..f499b18 --- /dev/null +++ b/src/resource.c @@ -0,0 +1,29 @@ +#include "resource.h" + +nn_resourceTable_t *nn_resource_newTable(nn_Context *ctx, nn_resourceDestructor_t *dtor) { + nn_resourceTable_t *t = nn_alloc(&ctx->allocator, sizeof(nn_resourceTable_t)); + if(t == NULL) return NULL; + t->dtor = dtor; + t->methodCount = 0; + return t; +} + +nn_resourceMethod_t *nn_resource_addMethod(nn_resourceTable_t *table, const char *methodName, nn_resourceMethodCallback_t *method, const char *doc) { + if(table->methodCount == NN_MAX_METHODS) return NULL; + nn_resourceMethod_t *m = &table->methods[table->methodCount]; + table->methodCount++; + nn_Alloc *a = &table->ctx.allocator; + m->name = nn_strdup(a, methodName); + m->doc = nn_strdup(a, doc); + m->callback = method; + m->condition = NULL; + return m; +} + +void nn_resource_setUserdata(nn_resourceMethod_t *method, void *methodUserdata) { + method->userdata = methodUserdata; +} + +void nn_resource_setCondition(nn_resourceMethod_t *method, nn_resourceMethodCondition_t *methodCondition) { + method->condition = methodCondition; +} diff --git a/src/resource.h b/src/resource.h new file mode 100644 index 0000000..04bf41a --- /dev/null +++ b/src/resource.h @@ -0,0 +1,21 @@ +#ifndef NN_RESOURCE +#define NN_RESOURCE + +#include "neonucleus.h" + +typedef struct nn_resourceMethod_t { + const char *name; + const char *doc; + void *userdata; + nn_resourceMethodCallback_t *callback; + nn_resourceMethodCondition_t *condition; +} nn_resourceMethod_t; + +typedef struct nn_resourceTable_t { + nn_Context ctx; + nn_resourceDestructor_t *dtor; + nn_size_t methodCount; + nn_resourceMethod_t methods[NN_MAX_METHODS]; +} nn_resourceTable_t; + +#endif diff --git a/src/testLuaArch.c b/src/testLuaArch.c index dce41d6..638eeb3 100644 --- a/src/testLuaArch.c +++ b/src/testLuaArch.c @@ -160,6 +160,7 @@ static void testLuaArch_pushValue(lua_State *L, nn_value val) { } return; } + luaL_error(L, "invalid return type: %d", t); } static int testLuaArch_computer_clearError(lua_State *L) { diff --git a/src/universe.c b/src/universe.c index 2786845..958ebd7 100644 --- a/src/universe.c +++ b/src/universe.c @@ -54,4 +54,5 @@ void nn_loadCoreComponentTables(nn_universe *universe) { nn_loadGraphicsCardTable(universe); nn_loadKeyboardTable(universe); nn_loadModemTable(universe); + nn_loadDiskDriveTable(universe); } diff --git a/src/value.c b/src/value.c index a87da72..6003101 100644 --- a/src/value.c +++ b/src/value.c @@ -82,6 +82,13 @@ nn_value nn_values_table(nn_Alloc *alloc, nn_size_t pairCount) { return (nn_value) {.tag = NN_VALUE_TABLE, .table = table}; } +nn_value nn_values_resource(nn_size_t id) { + return (nn_value) { + .tag = NN_VALUE_RESOURCE, + .resourceID = id, + }; +} + nn_size_t nn_values_getType(nn_value val) { return val.tag; }