volatile stuff

This commit is contained in:
IonutParau 2025-07-12 19:22:49 +02:00
parent 863e04f19e
commit aa8bdfb88c
7 changed files with 220 additions and 6 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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