From aa8bdfb88cd06c996e79b0aacad453f66459e498 Mon Sep 17 00:00:00 2001 From: IonutParau Date: Sat, 12 Jul 2025 19:22:49 +0200 Subject: [PATCH] volatile stuff --- TODO.md | 3 +- build.zig | 1 + src/components/eeprom.c | 12 +++- src/components/volatileDrive.c | 74 +++++++++++++++++++++++++ src/components/volatileEeprom.c | 98 +++++++++++++++++++++++++++++++++ src/emulator.c | 18 +++++- src/neonucleus.h | 20 ++++++- 7 files changed, 220 insertions(+), 6 deletions(-) create mode 100644 src/components/volatileDrive.c create mode 100644 src/components/volatileEeprom.c diff --git a/TODO.md b/TODO.md index 1841cee..3602c0c 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,6 @@ # Parity with Vanilla OC (only the stuff that makes sense for an emulator) -- in-memory version of `filesystem` +- in-memory version of `eeprom`, `filesystem` - `hologram` component - `computer` component - `modem` component @@ -36,5 +36,6 @@ # Internal changes +- rework some interfaces to account for possibility of errors - use dynamic arrays for signals (and maybe components), but still keep the maximums to prevent memory hogging - setup an extensive testing system to find bugs easier diff --git a/build.zig b/build.zig index 12b170d..2d1f872 100644 --- a/build.zig +++ b/build.zig @@ -26,6 +26,7 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module { "src/unicode.c", // components "src/components/eeprom.c", + "src/components/volatileEeprom.c", "src/components/filesystem.c", "src/components/drive.c", "src/components/volatileDrive.c", diff --git a/src/components/eeprom.c b/src/components/eeprom.c index 1c99039..c325ebf 100644 --- a/src/components/eeprom.c +++ b/src/components/eeprom.c @@ -142,6 +142,11 @@ void nn_eeprom_set(nn_eeprom *eeprom, void *_, nn_component *component, nn_compu } } nn_lock(&eeprom->ctx, eeprom->lock); + if(eeprom->table.isReadonly(eeprom->table.userdata)) { + nn_unlock(&eeprom->ctx, eeprom->lock); + nn_setCError(computer, "readonly"); + return; + } eeprom->table.set(eeprom->table.userdata, buf, len); nn_unlock(&eeprom->ctx, eeprom->lock); @@ -187,6 +192,11 @@ void nn_eeprom_setData(nn_eeprom *eeprom, void *_, nn_component *component, nn_c return; } nn_lock(&eeprom->ctx, eeprom->lock); + if(eeprom->table.isReadonly(eeprom->table.userdata)) { + nn_unlock(&eeprom->ctx, eeprom->lock); + nn_setCError(computer, "readonly"); + return; + } eeprom->table.setData(eeprom->table.userdata, buf, len); nn_unlock(&eeprom->ctx, eeprom->lock); @@ -255,7 +265,7 @@ void nn_loadEepromTable(nn_universe *universe) { nn_defineMethod(eepromTable, "getChecksum", true, (void *)nn_eeprom_getChecksum, NULL, "getChecksum(): string - Returns a checksum of the data on the EEPROM."); } -nn_component *nn_addEeprom(nn_computer *computer, nn_address address, int slot, nn_eeprom *eeprom) { +nn_component *nn_addEEPROM(nn_computer *computer, nn_address address, int slot, nn_eeprom *eeprom) { nn_componentTable *eepromTable = nn_queryUserdata(nn_getUniverse(computer), "NN:EEPROM"); return nn_newComponent(computer, address, slot, eepromTable, eeprom); diff --git a/src/components/volatileDrive.c b/src/components/volatileDrive.c new file mode 100644 index 0000000..b227409 --- /dev/null +++ b/src/components/volatileDrive.c @@ -0,0 +1,74 @@ +#include "../neonucleus.h" + +// TODO: make it allocate lazily + +typedef struct nn_vdrive { + nn_Context ctx; + char *buffer; + nn_size_t sectorSize; + nn_size_t capacity; + char label[NN_LABEL_SIZE]; + nn_size_t labelLen; +} nn_vdrive; + +static void nni_vdrive_deinit(nn_vdrive *vdrive) { + nn_Alloc a = vdrive->ctx.allocator; + nn_dealloc(&a, vdrive->buffer, vdrive->capacity); + nn_dealloc(&a, vdrive, sizeof(nn_vdrive)); +} + +static void nni_vdrive_getLabel(nn_vdrive *vdrive, char *buf, nn_size_t *buflen) { + nn_memcpy(buf, vdrive->label, vdrive->labelLen); + *buflen = vdrive->labelLen; +} + +static nn_size_t nni_vdrive_setLabel(nn_vdrive *vdrive, const char *buf, nn_size_t buflen) { + if(buflen > NN_LABEL_SIZE) buflen = NN_LABEL_SIZE; + nn_memcpy(vdrive->label, buf, buflen); + vdrive->labelLen = buflen; + return buflen; +} + +static void nni_vdrive_readSector(nn_vdrive *vdrive, int sector, char *buf) { + nn_memcpy(buf, vdrive->buffer + (sector - 1) * vdrive->sectorSize, vdrive->sectorSize); +} + +static void nni_vdrive_writeSector(nn_vdrive *vdrive, int sector, const char *buf) { + nn_memcpy(vdrive->buffer + (sector - 1) * vdrive->sectorSize, buf, vdrive->sectorSize); +} + +nn_drive *nn_volatileDrive(nn_Context *context, nn_vdriveOptions opts, nn_driveControl control) { + nn_Alloc *alloc = &context->allocator; + + char *buffer = nn_alloc(alloc, opts.capacity); + if(buffer == NULL) return NULL; + nn_vdrive *drive = nn_alloc(alloc, sizeof(nn_vdrive)); + if(drive == NULL) { + nn_dealloc(alloc, buffer, opts.capacity); + return NULL; + } + drive->ctx = *context; + drive->buffer = buffer; + drive->sectorSize = opts.sectorSize; + drive->capacity = opts.capacity; + nn_memcpy(drive->label, opts.label, opts.labelLen); + drive->labelLen = opts.labelLen; + if(opts.data == NULL) { + nn_memset(buffer, 0, opts.capacity); + } else { + nn_memcpy(buffer, opts.data, opts.capacity); + } + + nn_driveTable table = { + .userdata = drive, + .deinit = (void *)nni_vdrive_deinit, + .getLabel = (void *)nni_vdrive_getLabel, + .setLabel = (void *)nni_vdrive_setLabel, + .readSector = (void *)nni_vdrive_readSector, + .writeSector = (void *)nni_vdrive_writeSector, + .sectorSize = opts.sectorSize, + .platterCount = opts.platterCount, + .capacity = opts.capacity, + }; + return nn_newDrive(context, table, control); +} diff --git a/src/components/volatileEeprom.c b/src/components/volatileEeprom.c new file mode 100644 index 0000000..5868f79 --- /dev/null +++ b/src/components/volatileEeprom.c @@ -0,0 +1,98 @@ +#include "../neonucleus.h" + +typedef struct nn_veeprom { + nn_Context ctx; + char *code; + nn_size_t codeLen; + nn_size_t codeSize; + char *data; + nn_size_t dataLen; + nn_size_t dataSize; + char label[NN_LABEL_SIZE]; + nn_size_t labelLen; + nn_bool_t isReadOnly; +} nn_veeprom; + +static void nni_veeprom_deinit(nn_veeprom *veeprom) { + nn_Alloc a = veeprom->ctx.allocator; + nn_dealloc(&a, veeprom->code, veeprom->codeSize); + nn_dealloc(&a, veeprom->data, veeprom->dataSize); + nn_dealloc(&a, veeprom, sizeof(nn_veeprom)); +} + +static void nni_veeprom_getLabel(nn_veeprom *veeprom, char *buf, nn_size_t *buflen) { + nn_memcpy(buf, veeprom->label, veeprom->labelLen); + *buflen = veeprom->labelLen; +} + +static nn_size_t nni_veeprom_setLabel(nn_veeprom *veeprom, const char *buf, nn_size_t buflen) { + if(buflen > NN_LABEL_SIZE) buflen = NN_LABEL_SIZE; + nn_memcpy(veeprom->label, buf, buflen); + veeprom->labelLen = buflen; + return buflen; +} + +static nn_size_t nni_veeprom_get(nn_veeprom *veeprom, char *buf) { + nn_memcpy(buf, veeprom->code, veeprom->codeLen); + return veeprom->codeLen; +} + +static void nni_veeprom_set(nn_veeprom *veeprom, const char *buf, nn_size_t len) { + nn_memcpy(veeprom->code, buf, len); + veeprom->codeLen = len; +} + +static nn_size_t nni_veeprom_getData(nn_veeprom *veeprom, char *buf) { + nn_memcpy(buf, veeprom->data, veeprom->dataLen); + return veeprom->dataLen; +} + +static void nni_veeprom_setData(nn_veeprom *veeprom, const char *buf, nn_size_t len) { + nn_memcpy(veeprom->data, buf, len); + veeprom->dataLen = len; +} + +static nn_bool_t nni_veeprom_isReadonly(nn_veeprom *eeprom) { + return eeprom->isReadOnly; +} + +static void nni_veeprom_makeReadonly(nn_veeprom *eeprom) { + eeprom->isReadOnly = true; +} + +nn_eeprom *nn_volatileEEPROM(nn_Context *context, nn_veepromOptions opts, nn_eepromControl control) { + nn_Alloc *a = &context->allocator; + + // TODO: handle OOM + nn_veeprom *veeprom = nn_alloc(a, sizeof(nn_veeprom)); + veeprom->ctx = *context; + veeprom->codeSize = opts.size; + veeprom->code = nn_alloc(a, veeprom->codeSize); + veeprom->codeLen = opts.len; + veeprom->dataSize = opts.dataSize; + veeprom->data = nn_alloc(a, veeprom->dataSize); + veeprom->dataLen = opts.dataLen; + veeprom->isReadOnly = opts.isReadOnly; + veeprom->labelLen = opts.labelLen; + nn_memcpy(veeprom->label, opts.label, veeprom->labelLen); + + nn_memcpy(veeprom->code, opts.code, veeprom->codeLen); + nn_memcpy(veeprom->data, opts.data, veeprom->dataLen); + + nn_eepromTable table = { + .userdata = veeprom, + .deinit = (void *)nni_veeprom_deinit, + .size = opts.size, + .dataSize = opts.dataSize, + .getLabel = (void *)nni_veeprom_getLabel, + .setLabel = (void *)nni_veeprom_setLabel, + .get = (void *)nni_veeprom_get, + .set = (void *)nni_veeprom_set, + .getData = (void *)nni_veeprom_getData, + .setData = (void *)nni_veeprom_setData, + .isReadonly = (void *)nni_veeprom_isReadonly, + .makeReadonly = (void *)nni_veeprom_makeReadonly, + }; + + return nn_newEEPROM(context, table, control); +} diff --git a/src/emulator.c b/src/emulator.c index 15f920a..05bcdfd 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -614,7 +614,7 @@ int main() { nn_eeprom *genericEEPROM = nn_newEEPROM(&ctx, genericEEPROMTable, ne_eeprom_ctrl); - nn_addEeprom(computer, NULL, 0, genericEEPROM); + nn_addEEPROM(computer, NULL, 0, genericEEPROM); nn_address fsFolder = "OpenOS"; nn_filesystemTable genericFSTable = { @@ -646,6 +646,8 @@ int main() { .sectorSize = 512, .capacity = 1*1024*1024, .platterCount = 1, + .labelLen = 0, + .data = NULL, }; nn_driveControl vdriveCtrl = { .readSectorsPerTick = 32768, @@ -658,7 +660,7 @@ int main() { .writeEnergyPerSector = 0.015, .motorEnergyPerSector = 0.00005, }; - nn_drive *genericDrive = nn_volatileDrive(&ctx, vdriveOpts, vdriveCtrl, NULL); + nn_drive *genericDrive = nn_volatileDrive(&ctx, vdriveOpts, vdriveCtrl); nn_addDrive(computer, NULL, 4, genericDrive); int maxWidth = 80, maxHeight = 32; @@ -689,6 +691,18 @@ int main() { nn_addGPU(computer, NULL, 3, &gpuCtrl); + nn_veepromOptions eepromOpts = { + .isReadOnly = false, + .data = NULL, + .dataLen = 0, + .dataSize = 65536, + .labelLen = 0, + .code = NULL, + .len = 0, + .size = 131072, + }; + nn_addEEPROM(computer, NULL, 9, nn_volatileEEPROM(&ctx, eepromOpts, ne_eeprom_ctrl)); + SetConfigFlags(FLAG_WINDOW_RESIZABLE); InitWindow(800, 600, "emulator"); diff --git a/src/neonucleus.h b/src/neonucleus.h index 2a3c85a..7d2b788 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -603,11 +603,24 @@ typedef struct nn_eepromTable { typedef struct nn_eeprom nn_eeprom; +typedef struct nn_veepromOptions { + const char *code; + nn_size_t len; + nn_size_t size; + const char *data; + nn_size_t dataLen; + nn_size_t dataSize; + char label[NN_LABEL_SIZE]; + nn_size_t labelLen; + nn_bool_t isReadOnly; +} nn_veepromOptions; + nn_eeprom *nn_newEEPROM(nn_Context *context, nn_eepromTable table, nn_eepromControl control); +nn_eeprom *nn_volatileEEPROM(nn_Context *context, nn_veepromOptions opts, nn_eepromControl control); nn_guard *nn_getEEPROMLock(nn_eeprom *eeprom); void nn_retainEEPROM(nn_eeprom *eeprom); nn_bool_t nn_destroyEEPROM(nn_eeprom *eeprom); -nn_component *nn_addEeprom(nn_computer *computer, nn_address address, int slot, nn_eeprom *eeprom); +nn_component *nn_addEEPROM(nn_computer *computer, nn_address address, int slot, nn_eeprom *eeprom); // FileSystem typedef struct nn_filesystemControl { @@ -716,12 +729,15 @@ typedef struct nn_vdriveOptions { nn_size_t sectorSize; nn_size_t platterCount; nn_size_t capacity; + const char *data; + char label[NN_LABEL_SIZE]; + nn_size_t labelLen; } nn_vdriveOptions; typedef struct nn_drive nn_drive; nn_drive *nn_newDrive(nn_Context *context, nn_driveTable table, nn_driveControl control); -nn_drive *nn_volatileDrive(nn_Context *context, nn_vdriveOptions opts, nn_driveControl control, const char *initialData); +nn_drive *nn_volatileDrive(nn_Context *context, nn_vdriveOptions opts, nn_driveControl control); nn_guard *nn_getDriveLock(nn_drive *drive); void nn_retainDrive(nn_drive *drive); nn_bool_t nn_destroyDrive(nn_drive *drive);