disk drives and resources

This commit is contained in:
IonutParau 2025-07-25 18:10:16 +02:00
parent 3f873f5165
commit 0c3a3f0d75
11 changed files with 327 additions and 4 deletions

View File

@ -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",

112
src/components/diskDrive.c Normal file
View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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
}

29
src/resource.c Normal file
View File

@ -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;
}

21
src/resource.h Normal file
View File

@ -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

View File

@ -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) {

View File

@ -54,4 +54,5 @@ void nn_loadCoreComponentTables(nn_universe *universe) {
nn_loadGraphicsCardTable(universe);
nn_loadKeyboardTable(universe);
nn_loadModemTable(universe);
nn_loadDiskDriveTable(universe);
}

View File

@ -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;
}