Compare commits

...

5 Commits

Author SHA1 Message Date
IonutParau
2621554165 stuff 2025-07-12 21:09:39 +02:00
IonutParau
760bdacf6d update TODO 2025-07-12 20:59:47 +02:00
IonutParau
99a8259c80 stuff 2025-07-12 19:23:06 +02:00
IonutParau
aa8bdfb88c volatile stuff 2025-07-12 19:22:49 +02:00
IonutParau
863e04f19e the sound of progress
- Medic TF2
2025-07-12 18:42:38 +02:00
15 changed files with 488 additions and 188 deletions

15
TODO.md
View File

@ -1,6 +1,10 @@
# Parity with Vanilla OC (only the stuff that makes sense for an emulator) # Parity with Vanilla OC (only the stuff that makes sense for an emulator)
- in-memory version of `filesystem` and `drive` - make the `unicode` library in testLuaArch support invalid UTF-8 (WHY IS IT OK WITH THAT)
- in-memory version of `filesystem`
- complete the GPU implementation (screen buffers and missing methods)
- complete the screen implementation (bunch of missing methods)
- support invalid UTF-8 for GPU set and fill, which should pretend the byte value is the codepoint.
- `hologram` component - `hologram` component
- `computer` component - `computer` component
- `modem` component - `modem` component
@ -11,14 +15,10 @@
- `disk_drive` component - `disk_drive` component
- `computer.getDeviceInfo()`, and subsequently, component device information - `computer.getDeviceInfo()`, and subsequently, component device information
- `computer.beep(frequency?: number, duration?: number, volume?: number)`, frequency between 20 and 2000 Hz, duration up to 5 seconds, volume from 0 to 1. - `computer.beep(frequency?: number, duration?: number, volume?: number)`, frequency between 20 and 2000 Hz, duration up to 5 seconds, volume from 0 to 1.
- complete the GPU implementation (screen buffers and missing methods)
- complete the screen implementation (bunch of missing methods)
- support invalid UTF-8 for GPU set and fill, which should pretend the byte value is the codepoint.
# Bugfixes # Bugfixes
- Rework filesystem component to pre-process paths to ensure proper sandboxing and not allow arbitrary remote file access - Rework filesystem component to pre-process paths to ensure proper sandboxing and not allow arbitrary remote file access
- Ensure the recursive locks are used correctly to prevent race conditions
- Do a huge audit at some point - Do a huge audit at some point
# The extra components # The extra components
@ -35,11 +35,8 @@
- `tape_drive` component, compatible with Computronics, except maybe with proper seek times and support for multiple tapes - `tape_drive` component, compatible with Computronics, except maybe with proper seek times and support for multiple tapes
- `cd_reader` and `cd_writer` components, to work with CDs - `cd_reader` and `cd_writer` components, to work with CDs
# API changes
- move controls into the component instances instead of using getters, to boost performance
# Internal changes # 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 - 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 - setup an extensive testing system to find bugs easier

View File

@ -26,8 +26,10 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module {
"src/unicode.c", "src/unicode.c",
// components // components
"src/components/eeprom.c", "src/components/eeprom.c",
"src/components/volatileEeprom.c",
"src/components/filesystem.c", "src/components/filesystem.c",
"src/components/drive.c", "src/components/drive.c",
"src/components/volatileDrive.c",
"src/components/screen.c", "src/components/screen.c",
"src/components/gpu.c", "src/components/gpu.c",
"src/components/keyboard.c", "src/components/keyboard.c",
@ -68,7 +70,7 @@ fn compileTheRightLua(b: *std.Build, target: std.Build.ResolvedTarget, version:
const c = b.addObject(.{ const c = b.addObject(.{
.name = "lua", .name = "lua",
.link_libc = true, .link_libc = true,
.optimize = .ReleaseSafe, .optimize = .ReleaseFast,
.target = target, .target = target,
}); });

View File

@ -1,28 +1,58 @@
#include "../neonucleus.h" #include "../neonucleus.h"
typedef struct nni_drive { typedef struct nn_drive {
nn_drive *funcs; nn_refc refc;
nn_guard *lock;
nn_Context ctx;
nn_size_t currentSector; nn_size_t currentSector;
} nni_drive; nn_driveTable table;
nn_driveControl ctrl;
} nn_drive;
void nn_drive_destroy(void *_, nn_component *component, nni_drive *drive) { nn_drive *nn_newDrive(nn_Context *context, nn_driveTable table, nn_driveControl control) {
if(!nn_decRef(&drive->funcs->refc)) return; nn_drive *d = nn_alloc(&context->allocator, sizeof(nn_drive));
if(d == NULL) return NULL;
if(drive->funcs->deinit != NULL) { d->lock = nn_newGuard(context);
drive->funcs->deinit(component, drive->funcs->userdata); if(d->lock == NULL) {
nn_dealloc(&context->allocator, d, sizeof(nn_drive));
return NULL;
}
d->refc = 1;
d->table = table;
d->ctrl = control;
d->currentSector = 0;
d->ctx = *context;
return d;
} }
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(nn_getComputerOfComponent(component))); nn_guard *nn_getDriveLock(nn_drive *drive) {
return drive->lock;
nn_dealloc(alloc, drive, sizeof(nni_drive));
} }
nn_driveControl nn_drive_getControl(nn_component *component, nni_drive *drive) { void nn_retainDrive(nn_drive *drive) {
return drive->funcs->control(component, drive->funcs->userdata); nn_incRef(&drive->refc);
} }
void nni_drive_readCost(nn_component *component, nni_drive *drive) { nn_bool_t nn_destroyDrive(nn_drive *drive) {
nn_driveControl ctrl = nn_drive_getControl(component, drive); if(!nn_decRef(&drive->refc)) return false;
if(drive->table.deinit != NULL) {
drive->table.deinit(drive->table.userdata);
}
nn_Context ctx = drive->ctx;
nn_deleteGuard(&ctx, drive->lock);
nn_dealloc(&ctx.allocator, drive, sizeof(nn_drive));
return true;
}
void nn_drive_destroy(void *_, nn_component *component, nn_drive *drive) {
nn_destroyDrive(drive);
}
void nni_drive_readCost(nn_component *component, nn_drive *drive) {
nn_driveControl ctrl = drive->ctrl;
nn_computer *computer = nn_getComputerOfComponent(component); nn_computer *computer = nn_getComputerOfComponent(component);
nn_simulateBufferedIndirect(component, 1, ctrl.readSectorsPerTick); nn_simulateBufferedIndirect(component, 1, ctrl.readSectorsPerTick);
@ -30,8 +60,8 @@ void nni_drive_readCost(nn_component *component, nni_drive *drive) {
nn_removeEnergy(computer, ctrl.readEnergyPerSector); nn_removeEnergy(computer, ctrl.readEnergyPerSector);
} }
void nni_drive_writeCost(nn_component *component, nni_drive *drive) { void nni_drive_writeCost(nn_component *component, nn_drive *drive) {
nn_driveControl ctrl = nn_drive_getControl(component, drive); nn_driveControl ctrl = drive->ctrl;
nn_computer *computer = nn_getComputerOfComponent(component); nn_computer *computer = nn_getComputerOfComponent(component);
nn_simulateBufferedIndirect(component, 1, ctrl.writeSectorsPerTick); nn_simulateBufferedIndirect(component, 1, ctrl.writeSectorsPerTick);
@ -39,19 +69,19 @@ void nni_drive_writeCost(nn_component *component, nni_drive *drive) {
nn_removeEnergy(computer, ctrl.writeEnergyPerSector); nn_removeEnergy(computer, ctrl.writeEnergyPerSector);
} }
void nni_drive_seekTo(nn_component *component, nni_drive *drive, nn_size_t sector) { void nni_drive_seekTo(nn_component *component, nn_drive *drive, nn_size_t sector) {
sector = sector - 1; // switch to 0 to N-1 sector addressing, sector = sector - 1; // switch to 0 to N-1 sector addressing,
// which is much nicer to do math with // which is much nicer to do math with
// and Lua made a big oopsie. // and Lua made a big oopsie.
nn_size_t old = drive->currentSector; nn_size_t old = drive->currentSector;
nn_driveControl ctrl = nn_drive_getControl(component, drive); nn_driveControl ctrl = drive->ctrl;
if(ctrl.seekSectorsPerTick == 0) return; // seek latency disabled if(ctrl.seekSectorsPerTick == 0) return; // seek latency disabled
nn_computer *computer = nn_getComputerOfComponent(component); nn_computer *computer = nn_getComputerOfComponent(component);
// Compute important constants // Compute important constants
nn_size_t sectorSize = drive->funcs->getSectorSize(component, drive->funcs->userdata); nn_size_t sectorSize = drive->table.sectorSize;
nn_size_t platterCount = drive->funcs->getPlatterCount(component, drive->funcs->userdata); nn_size_t platterCount = drive->table.platterCount;
nn_size_t capacity = drive->funcs->getCapacity(component, drive->funcs->userdata); nn_size_t capacity = drive->table.capacity;
nn_size_t sectorsPerPlatter = (capacity / sectorSize) / platterCount; nn_size_t sectorsPerPlatter = (capacity / sectorSize) / platterCount;
@ -83,17 +113,19 @@ void nni_drive_seekTo(nn_component *component, nni_drive *drive, nn_size_t secto
nn_removeEnergy(computer, ctrl.motorEnergyPerSector * moved); nn_removeEnergy(computer, ctrl.motorEnergyPerSector * moved);
} }
void nn_drive_getLabel(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { void nn_drive_getLabel(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
char buf[NN_LABEL_SIZE]; char buf[NN_LABEL_SIZE];
nn_size_t l = NN_LABEL_SIZE; nn_size_t l = NN_LABEL_SIZE;
drive->funcs->getLabel(component, drive->funcs->userdata, buf, &l); nn_lock(&drive->ctx, drive->lock);
drive->table.getLabel(drive->table.userdata, buf, &l);
nn_unlock(&drive->ctx, drive->lock);
if(l == 0) { if(l == 0) {
nn_return(computer, nn_values_nil()); nn_return(computer, nn_values_nil());
} else { } else {
nn_return_string(computer, buf, l); nn_return_string(computer, buf, l);
} }
} }
void nn_drive_setLabel(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { void nn_drive_setLabel(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t l = 0; nn_size_t l = 0;
nn_value label = nn_getArgument(computer, 0); nn_value label = nn_getArgument(computer, 0);
const char *buf = nn_toString(label, &l); const char *buf = nn_toString(label, &l);
@ -101,38 +133,42 @@ void nn_drive_setLabel(nni_drive *drive, void *_, nn_component *component, nn_co
nn_setCError(computer, "bad label (string expected)"); nn_setCError(computer, "bad label (string expected)");
return; return;
} }
l = drive->funcs->setLabel(component, drive->funcs->userdata, buf, l); nn_lock(&drive->ctx, drive->lock);
l = drive->table.setLabel(drive->table.userdata, buf, l);
nn_unlock(&drive->ctx, drive->lock);
nn_return_string(computer, buf, l); nn_return_string(computer, buf, l);
} }
void nn_drive_getSectorSize(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { void nn_drive_getSectorSize(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); nn_size_t sector_size = drive->table.sectorSize;
nn_return(computer, nn_values_integer(sector_size)); nn_return(computer, nn_values_integer(sector_size));
} }
void nn_drive_getPlatterCount(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { void nn_drive_getPlatterCount(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t platter_count = drive->funcs->getPlatterCount(component, drive->funcs->userdata); nn_size_t platter_count = drive->table.platterCount;
nn_return(computer, nn_values_integer(platter_count)); nn_return(computer, nn_values_integer(platter_count));
} }
void nn_drive_getCapacity(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { void nn_drive_getCapacity(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t capacity = drive->funcs->getCapacity(component, drive->funcs->userdata); nn_size_t capacity = drive->table.capacity;
nn_return(computer, nn_values_integer(capacity)); nn_return(computer, nn_values_integer(capacity));
} }
void nn_drive_readSector(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { void nn_drive_readSector(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_value sectorValue = nn_getArgument(computer, 0); nn_value sectorValue = nn_getArgument(computer, 0);
int sector = nn_toInt(sectorValue); int sector = nn_toInt(sectorValue);
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); nn_size_t sector_size = drive->table.sectorSize;
// we leave the +1 intentionally to compare the end of the real sector // we leave the +1 intentionally to compare the end of the real sector
if (sector < 1 || (sector * sector_size > drive->funcs->getCapacity(component, drive->funcs->userdata))) { if (sector < 1 || (sector * sector_size > drive->table.capacity)) {
nn_setCError(computer, "bad argument #1 (sector out of range)"); nn_setCError(computer, "bad argument #1 (sector out of range)");
return; return;
} }
char buf[sector_size]; char buf[sector_size];
drive->funcs->readSector(component, drive->funcs->userdata, sector, buf); nn_lock(&drive->ctx, drive->lock);
drive->table.readSector(drive->table.userdata, sector, buf);
nn_unlock(&drive->ctx, drive->lock);
nn_return_string(computer, buf, sector_size); nn_return_string(computer, buf, sector_size);
} }
void nn_drive_writeSector(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { void nn_drive_writeSector(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_value sectorValue = nn_getArgument(computer, 0); nn_value sectorValue = nn_getArgument(computer, 0);
int sector = nn_toInt(sectorValue); int sector = nn_toInt(sectorValue);
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); nn_size_t sector_size = drive->table.sectorSize;
nn_value bufValue = nn_getArgument(computer, 1); nn_value bufValue = nn_getArgument(computer, 1);
nn_size_t buf_size = 0; nn_size_t buf_size = 0;
@ -142,34 +178,40 @@ void nn_drive_writeSector(nni_drive *drive, void *_, nn_component *component, nn
return; return;
} }
// we leave the +1 intentionally to compare the end of the real sector // we leave the +1 intentionally to compare the end of the real sector
if (sector < 1 || (sector * sector_size > drive->funcs->getCapacity(component, drive->funcs->userdata))) { if (sector < 1 || (sector * sector_size > drive->table.capacity)) {
nn_setCError(computer, "bad argument #1 (sector out of range)"); nn_setCError(computer, "bad argument #1 (sector out of range)");
return; return;
} }
drive->funcs->writeSector(component, drive->funcs->userdata, sector, buf); nn_lock(&drive->ctx, drive->lock);
drive->table.writeSector(drive->table.userdata, sector, buf);
nn_unlock(&drive->ctx, drive->lock);
nn_return_boolean(computer, true);
} }
void nn_drive_readByte(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { void nn_drive_readByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_value offsetValue = nn_getArgument(computer, 0); nn_value offsetValue = nn_getArgument(computer, 0);
nn_size_t disk_offset = nn_toInt(offsetValue) - 1; nn_size_t disk_offset = nn_toInt(offsetValue) - 1;
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); nn_size_t sector_size = drive->table.sectorSize;
int sector = (disk_offset / sector_size) + 1; int sector = (disk_offset / sector_size) + 1;
nn_size_t sector_offset = disk_offset % sector_size; nn_size_t sector_offset = disk_offset % sector_size;
if (disk_offset >= drive->funcs->getCapacity(component, drive->funcs->userdata)) { if (disk_offset >= drive->table.capacity) {
nn_setCError(computer, "bad argument #1 (index out of range)"); nn_setCError(computer, "bad argument #1 (index out of range)");
return; return;
} }
char buf[sector_size]; char buf[sector_size];
drive->funcs->readSector(component, drive->funcs->userdata, sector, buf); nn_lock(&drive->ctx, drive->lock);
drive->table.readSector(drive->table.userdata, sector, buf);
nn_unlock(&drive->ctx, drive->lock);
nn_return(computer, nn_values_integer(buf[sector_offset])); nn_return(computer, nn_values_integer(buf[sector_offset]));
} }
void nn_drive_writeByte(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { void nn_drive_writeByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_value offsetValue = nn_getArgument(computer, 0); nn_value offsetValue = nn_getArgument(computer, 0);
nn_value writeValue = nn_getArgument(computer, 1); nn_value writeValue = nn_getArgument(computer, 1);
nn_size_t disk_offset = nn_toInt(offsetValue) - 1; nn_size_t disk_offset = nn_toInt(offsetValue) - 1;
nn_intptr_t write = nn_toInt(writeValue); nn_intptr_t write = nn_toInt(writeValue);
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); nn_size_t sector_size = drive->table.sectorSize;
int sector = (disk_offset / sector_size) + 1; int sector = (disk_offset / sector_size) + 1;
nn_size_t sector_offset = disk_offset % sector_size; nn_size_t sector_offset = disk_offset % sector_size;
@ -177,16 +219,20 @@ void nn_drive_writeByte(nni_drive *drive, void *_, nn_component *component, nn_c
nn_setCError(computer, "bad argument #2 (byte out of range)"); nn_setCError(computer, "bad argument #2 (byte out of range)");
return; return;
} }
if (disk_offset >= drive->funcs->getCapacity(component, drive->funcs->userdata)) { if (disk_offset >= drive->table.capacity) {
nn_setCError(computer, "bad argument #1 (index out of range)"); nn_setCError(computer, "bad argument #1 (index out of range)");
return; return;
} }
nn_lock(&drive->ctx, drive->lock);
char buf[sector_size]; char buf[sector_size];
drive->funcs->readSector(component, drive->funcs->userdata, sector, buf); drive->table.readSector(drive->table.userdata, sector, buf);
buf[sector_offset] = write; buf[sector_offset] = write;
drive->funcs->writeSector(component, drive->funcs->userdata, sector, buf); drive->table.writeSector(drive->table.userdata, sector, buf);
nn_unlock(&drive->ctx, drive->lock);
nn_return_boolean(computer, true);
} }
void nn_loadDriveTable(nn_universe *universe) { void nn_loadDriveTable(nn_universe *universe) {
@ -205,15 +251,7 @@ void nn_loadDriveTable(nn_universe *universe) {
} }
nn_component *nn_addDrive(nn_computer *computer, nn_address address, int slot, nn_drive *drive) { nn_component *nn_addDrive(nn_computer *computer, nn_address address, int slot, nn_drive *drive) {
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer));
nni_drive *d = nn_alloc(alloc, sizeof(nni_drive));
d->currentSector = 0;
d->funcs = drive;
nn_componentTable *driveTable = nn_queryUserdata(nn_getUniverse(computer), "NN:DRIVE"); nn_componentTable *driveTable = nn_queryUserdata(nn_getUniverse(computer), "NN:DRIVE");
nn_component *c = nn_newComponent(computer, address, slot, driveTable, drive); return nn_newComponent(computer, address, slot, driveTable, drive);
if(c == NULL) {
nn_dealloc(alloc, d, sizeof(nni_drive));
}
return 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); 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); eeprom->table.set(eeprom->table.userdata, buf, len);
nn_unlock(&eeprom->ctx, eeprom->lock); nn_unlock(&eeprom->ctx, eeprom->lock);
@ -187,6 +192,11 @@ void nn_eeprom_setData(nn_eeprom *eeprom, void *_, nn_component *component, nn_c
return; return;
} }
nn_lock(&eeprom->ctx, eeprom->lock); 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); eeprom->table.setData(eeprom->table.userdata, buf, len);
nn_unlock(&eeprom->ctx, eeprom->lock); 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_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"); nn_componentTable *eepromTable = nn_queryUserdata(nn_getUniverse(computer), "NN:EEPROM");
return nn_newComponent(computer, address, slot, eepromTable, eeprom); return nn_newComponent(computer, address, slot, eepromTable, eeprom);

View File

@ -58,19 +58,28 @@ nn_bool_t nn_destroyFilesystem(nn_filesystem *fs) {
} }
nn_size_t nn_fs_getSpaceUsed(nn_filesystem *fs) { nn_size_t nn_fs_getSpaceUsed(nn_filesystem *fs) {
if(fs->spaceUsedCache != 0) return fs->spaceUsedCache; nn_lock(&fs->ctx, fs->lock);
if(fs->spaceUsedCache != 0) {
nn_unlock(&fs->ctx, fs->lock);
return fs->spaceUsedCache;
}
nn_size_t spaceUsed = fs->table.spaceUsed(fs->table.userdata); nn_size_t spaceUsed = fs->table.spaceUsed(fs->table.userdata);
fs->spaceUsedCache = spaceUsed; fs->spaceUsedCache = spaceUsed;
nn_unlock(&fs->ctx, fs->lock);
return spaceUsed; return spaceUsed;
} }
void nn_fs_invalidateSpaceUsed(nn_filesystem *fs) { void nn_fs_invalidateSpaceUsed(nn_filesystem *fs) {
nn_lock(&fs->ctx, fs->lock);
fs->spaceUsedCache = 0; fs->spaceUsedCache = 0;
nn_unlock(&fs->ctx, fs->lock);
} }
nn_size_t nn_fs_getSpaceRemaining(nn_filesystem *fs) { nn_size_t nn_fs_getSpaceRemaining(nn_filesystem *fs) {
nn_lock(&fs->ctx, fs->lock);
nn_size_t used = nn_fs_getSpaceUsed(fs); nn_size_t used = nn_fs_getSpaceUsed(fs);
nn_size_t total = fs->table.spaceTotal; nn_size_t total = fs->table.spaceTotal;
nn_unlock(&fs->ctx, fs->lock);
return total - used; return total - used;
} }
@ -78,7 +87,9 @@ void *nn_fs_unwrapFD(nn_filesystem *fs, nn_size_t fd) {
if(fd >= NN_MAX_OPEN_FILES) { if(fd >= NN_MAX_OPEN_FILES) {
return NULL; return NULL;
} }
nn_lock(&fs->ctx, fs->lock);
void *file = fs->files[fd]; void *file = fs->files[fd];
nn_unlock(&fs->ctx, fs->lock);
if(file == NULL) { if(file == NULL) {
return NULL; return NULL;
} }
@ -134,7 +145,9 @@ void nn_fs_createCost(nn_filesystem *fs, nn_size_t count, nn_component *componen
void nn_fs_getLabel(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { void nn_fs_getLabel(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
char buf[NN_LABEL_SIZE]; char buf[NN_LABEL_SIZE];
nn_size_t l = NN_LABEL_SIZE; nn_size_t l = NN_LABEL_SIZE;
nn_lock(&fs->ctx, fs->lock);
fs->table.getLabel(fs->table.userdata, buf, &l); fs->table.getLabel(fs->table.userdata, buf, &l);
nn_unlock(&fs->ctx, fs->lock);
if(l == 0) { if(l == 0) {
nn_return(computer, nn_values_nil()); nn_return(computer, nn_values_nil());
} else { } else {
@ -152,7 +165,9 @@ void nn_fs_setLabel(nn_filesystem *fs, void *_, nn_component *component, nn_comp
nn_setCError(computer, "bad label (string expected)"); nn_setCError(computer, "bad label (string expected)");
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
l = fs->table.setLabel(fs->table.userdata, buf, l); l = fs->table.setLabel(fs->table.userdata, buf, l);
nn_unlock(&fs->ctx, fs->lock);
nn_return_string(computer, buf, l); nn_return_string(computer, buf, l);
nn_fs_writeCost(fs, l, component); nn_fs_writeCost(fs, l, component);
@ -168,7 +183,9 @@ void nn_fs_spaceTotal(nn_filesystem *fs, void *_, nn_component *component, nn_co
} }
void nn_fs_isReadOnly(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { void nn_fs_isReadOnly(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
nn_lock(&fs->ctx, fs->lock);
nn_return_boolean(computer, fs->table.isReadOnly(fs->table.userdata)); nn_return_boolean(computer, fs->table.isReadOnly(fs->table.userdata));
nn_unlock(&fs->ctx, fs->lock);
} }
void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -183,7 +200,9 @@ void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
nn_size_t byteSize = fs->table.size(fs->table.userdata, path); nn_size_t byteSize = fs->table.size(fs->table.userdata, path);
nn_unlock(&fs->ctx, fs->lock);
nn_return(computer, nn_values_integer(byteSize)); nn_return(computer, nn_values_integer(byteSize));
} }
@ -200,7 +219,9 @@ void nn_fs_remove(nn_filesystem *fs, void *_, nn_component *component, nn_comput
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
nn_size_t removed = fs->table.remove(fs->table.userdata, path); nn_size_t removed = fs->table.remove(fs->table.userdata, path);
nn_unlock(&fs->ctx, fs->lock);
nn_return_boolean(computer, removed > 0); nn_return_boolean(computer, removed > 0);
nn_fs_removeCost(fs, removed, component); nn_fs_removeCost(fs, removed, component);
@ -218,7 +239,9 @@ void nn_fs_lastModified(nn_filesystem *fs, void *_, nn_component *component, nn_
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
nn_size_t t = fs->table.lastModified(fs->table.userdata, path); nn_size_t t = fs->table.lastModified(fs->table.userdata, path);
nn_unlock(&fs->ctx, fs->lock);
// OpenOS does BULLSHIT with this thing, dividing it by 1000 and expecting it to be // OpenOS does BULLSHIT with this thing, dividing it by 1000 and expecting it to be
// fucking usable as a date, meaning it needs to be an int. // fucking usable as a date, meaning it needs to be an int.
@ -251,7 +274,9 @@ void nn_fs_rename(nn_filesystem *fs, void *_, nn_component *component, nn_comput
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
nn_size_t movedCount = fs->table.rename(fs->table.userdata, from, to); nn_size_t movedCount = fs->table.rename(fs->table.userdata, from, to);
nn_unlock(&fs->ctx, fs->lock);
nn_return(computer, nn_values_boolean(movedCount > 0)); nn_return(computer, nn_values_boolean(movedCount > 0));
nn_fs_removeCost(fs, movedCount, component); nn_fs_removeCost(fs, movedCount, component);
@ -270,7 +295,9 @@ void nn_fs_exists(nn_filesystem *fs, void *_, nn_component *component, nn_comput
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
nn_return_boolean(computer, fs->table.exists(fs->table.userdata, path)); nn_return_boolean(computer, fs->table.exists(fs->table.userdata, path));
nn_unlock(&fs->ctx, fs->lock);
} }
void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -285,7 +312,9 @@ void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_c
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
nn_return_boolean(computer, fs->table.isDirectory(fs->table.userdata, path)); nn_return_boolean(computer, fs->table.isDirectory(fs->table.userdata, path));
nn_unlock(&fs->ctx, fs->lock);
} }
void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -300,7 +329,9 @@ void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
nn_return_boolean(computer, fs->table.makeDirectory(fs->table.userdata, path)); nn_return_boolean(computer, fs->table.makeDirectory(fs->table.userdata, path));
nn_unlock(&fs->ctx, fs->lock);
nn_fs_createCost(fs, 1, component); nn_fs_createCost(fs, 1, component);
} }
@ -320,7 +351,9 @@ void nn_fs_list(nn_filesystem *fs, void *_, nn_component *component, nn_computer
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer)); nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer));
nn_size_t fileCount = 0; nn_size_t fileCount = 0;
nn_lock(&fs->ctx, fs->lock);
char **files = fs->table.list(alloc, fs->table.userdata, path, &fileCount); char **files = fs->table.list(alloc, fs->table.userdata, path, &fileCount);
nn_unlock(&fs->ctx, fs->lock);
if(files != NULL) { if(files != NULL) {
// operation succeeded // operation succeeded
@ -352,6 +385,7 @@ void nn_fs_open(nn_filesystem *fs, void *_, nn_component *component, nn_computer
mode = "r"; mode = "r";
} }
nn_lock(&fs->ctx, fs->lock);
// technically wrongfully // technically wrongfully
if(!fs->table.exists(fs->table.userdata, path)) { if(!fs->table.exists(fs->table.userdata, path)) {
nn_fs_createCost(fs, 1, component); nn_fs_createCost(fs, 1, component);
@ -361,15 +395,18 @@ void nn_fs_open(nn_filesystem *fs, void *_, nn_component *component, nn_computer
while(fs->files[fd] != NULL) { while(fs->files[fd] != NULL) {
fd++; fd++;
if(fd == NN_MAX_OPEN_FILES) { if(fd == NN_MAX_OPEN_FILES) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "too many open files"); nn_setCError(computer, "too many open files");
return; return;
} }
} }
void *file = fs->table.open(fs->table.userdata, path, mode); void *file = fs->table.open(fs->table.userdata, path, mode);
if(file == NULL) { if(file == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "no such file or directory"); nn_setCError(computer, "no such file or directory");
return; return;
} }
nn_unlock(&fs->ctx, fs->lock);
fs->files[fd] = file; fs->files[fd] = file;
nn_return(computer, nn_values_integer(fd)); nn_return(computer, nn_values_integer(fd));
} }
@ -383,10 +420,12 @@ void nn_fs_close(nn_filesystem *fs, void *_, nn_component *component, nn_compute
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
nn_bool_t closed = fs->table.close(fs->table.userdata, file); nn_bool_t closed = fs->table.close(fs->table.userdata, file);
if(closed) { if(closed) {
fs->files[fd] = NULL; fs->files[fd] = NULL;
} }
nn_unlock(&fs->ctx, fs->lock);
nn_return(computer, nn_values_boolean(closed)); nn_return(computer, nn_values_boolean(closed));
} }
@ -402,15 +441,18 @@ void nn_fs_write(nn_filesystem *fs, void *_, nn_component *component, nn_compute
return; return;
} }
size_t spaceRemaining = nn_fs_getSpaceRemaining(fs); nn_lock(&fs->ctx, fs->lock);
nn_size_t spaceRemaining = nn_fs_getSpaceRemaining(fs);
// overwriting would still work but OC does the same thing so... // overwriting would still work but OC does the same thing so...
if(spaceRemaining < len) { if(spaceRemaining < len) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "out of space"); nn_setCError(computer, "out of space");
return; return;
} }
void *file = nn_fs_unwrapFD(fs, fd); void *file = nn_fs_unwrapFD(fs, fd);
if(file == NULL) { if(file == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "bad file descriptor"); nn_setCError(computer, "bad file descriptor");
return; return;
} }
@ -418,6 +460,7 @@ void nn_fs_write(nn_filesystem *fs, void *_, nn_component *component, nn_compute
nn_bool_t written = fs->table.write(fs->table.userdata, file, buf, len); nn_bool_t written = fs->table.write(fs->table.userdata, file, buf, len);
nn_return(computer, nn_values_boolean(written)); nn_return(computer, nn_values_boolean(written));
if(written) nn_fs_invalidateSpaceUsed(fs); if(written) nn_fs_invalidateSpaceUsed(fs);
nn_unlock(&fs->ctx, fs->lock);
nn_fs_writeCost(fs, len, component); nn_fs_writeCost(fs, len, component);
} }
@ -433,8 +476,10 @@ void nn_fs_read(nn_filesystem *fs, void *_, nn_component *component, nn_computer
if(len > capacity) len = capacity; if(len > capacity) len = capacity;
nn_size_t byteLen = len; nn_size_t byteLen = len;
nn_lock(&fs->ctx, fs->lock);
void *file = nn_fs_unwrapFD(fs, fd); void *file = nn_fs_unwrapFD(fs, fd);
if(file == NULL) { if(file == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "bad file descriptor"); nn_setCError(computer, "bad file descriptor");
return; return;
} }
@ -442,11 +487,13 @@ void nn_fs_read(nn_filesystem *fs, void *_, nn_component *component, nn_computer
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer)); nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer));
char *buf = nn_alloc(alloc, byteLen); char *buf = nn_alloc(alloc, byteLen);
if(buf == NULL) { if(buf == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "out of memory"); nn_setCError(computer, "out of memory");
return; return;
} }
nn_size_t readLen = fs->table.read(fs->table.userdata, file, buf, byteLen); nn_size_t readLen = fs->table.read(fs->table.userdata, file, buf, byteLen);
nn_unlock(&fs->ctx, fs->lock);
if(readLen > 0) { if(readLen > 0) {
// Nothing read means EoF. // Nothing read means EoF.
nn_return_string(computer, buf, readLen); nn_return_string(computer, buf, readLen);
@ -480,13 +527,16 @@ void nn_fs_seek(nn_filesystem *fs, void *_, nn_component *component, nn_computer
return; return;
} }
nn_lock(&fs->ctx, fs->lock);
void *file = nn_fs_unwrapFD(fs, fd); void *file = nn_fs_unwrapFD(fs, fd);
if(file == NULL) { if(file == NULL) {
nn_unlock(&fs->ctx, fs->lock);
nn_setCError(computer, "bad file descriptor"); nn_setCError(computer, "bad file descriptor");
return; return;
} }
nn_size_t pos = fs->table.seek(fs->table.userdata, file, whence, off); nn_size_t pos = fs->table.seek(fs->table.userdata, file, whence, off);
nn_unlock(&fs->ctx, fs->lock);
nn_return_integer(computer, pos); nn_return_integer(computer, pos);
} }

View File

@ -131,22 +131,23 @@ void nni_gpu_set(nni_gpu *gpu, void *_, nn_component *component, nn_computer *co
return; return;
} }
if(!nn_unicode_validate(s)) {
nn_setCError(computer, "invalid utf-8");
return;
}
int current = 0; int current = 0;
int len = 0; int len = 0;
while(s[current] != 0) { while(s[current] != 0) {
if(nn_unicode_isValidCodepoint(s + current)) {
int codepoint = nn_unicode_codepointAt(s, current); int codepoint = nn_unicode_codepointAt(s, current);
nn_setPixel(gpu->currentScreen, x, y, nni_gpu_makePixel(gpu, s + current)); nn_setPixel(gpu->currentScreen, x, y, nni_gpu_makePixel(gpu, s + current));
current += nn_unicode_codepointSize(codepoint);
} else {
unsigned int codepoint = (unsigned char)s[current];
nn_setPixel(gpu->currentScreen, x, y, nni_gpu_makePixel(gpu, s + current));
current++;
}
if(isVertical) { if(isVertical) {
y++; y++;
} else { } else {
x++; x++;
} }
current += nn_unicode_codepointSize(codepoint);
len++; len++;
} }

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

@ -367,7 +367,11 @@ nn_component *nn_newComponent(nn_computer *computer, nn_address address, int slo
computer->componentLen++; computer->componentLen++;
} }
if(address == NULL) {
c->address = nn_randomUUID(&computer->universe->ctx);
} else {
c->address = nn_strdup(&computer->universe->ctx.allocator, address); c->address = nn_strdup(&computer->universe->ctx.allocator, address);
}
if(c->address == NULL) return NULL; if(c->address == NULL) return NULL;
c->table = table; c->table = table;
c->slot = slot; c->slot = slot;

View File

@ -1,5 +1,4 @@
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -291,47 +290,6 @@ bool ne_fs_exists(nn_address addr, const char *path) {
return FileExists(p) || DirectoryExists(p); return FileExists(p) || DirectoryExists(p);
} }
typedef struct ne_drive {
FILE *file;
} ne_drive;
void ne_drive_close(nn_component *component, ne_drive *drive) {
fclose(drive->file);
}
nn_driveControl ne_drive_getControl(nn_component *component, ne_drive *_) {
return (nn_driveControl){};
}
size_t ne_drive_getPlatterCount(nn_component *component, ne_drive *_) {
return 1;
}
size_t ne_drive_getSectorSize(nn_component *component, ne_drive *_) {
return 512;
}
size_t ne_drive_getCapacity(nn_component *component, ne_drive *drive) {
fseek(drive->file, 0, SEEK_END);
return ftell(drive->file);
}
void ne_drive_readSector(nn_component *component, ne_drive *drive, int shifted_sector, char *buf) {
int sector = shifted_sector - 1;
size_t sectorSize = ne_drive_getSectorSize(component, drive);
size_t offset = sector * sectorSize;
fseek(drive->file, offset, SEEK_SET);
fread(buf, sizeof(char), sectorSize, drive->file);
}
void ne_drive_writeSector(nn_component *component, ne_drive *drive, int shifted_sector, const char *buf) {
int sector = shifted_sector - 1;
size_t sectorSize = ne_drive_getSectorSize(component, drive);
size_t offset = sector * sectorSize;
fseek(drive->file, offset, SEEK_SET);
fwrite(buf, sizeof(char), sectorSize, drive->file);
// this is probably not needed but i believe someone isn't running the deinit
fflush(drive->file);
}
int keycode_to_oc(int keycode) { int keycode_to_oc(int keycode) {
switch (keycode) { switch (keycode) {
case KEY_NULL: case KEY_NULL:
@ -656,7 +614,7 @@ int main() {
nn_eeprom *genericEEPROM = nn_newEEPROM(&ctx, genericEEPROMTable, ne_eeprom_ctrl); nn_eeprom *genericEEPROM = nn_newEEPROM(&ctx, genericEEPROMTable, ne_eeprom_ctrl);
nn_addEeprom(computer, "luaBios.lua", 0, genericEEPROM); nn_addEEPROM(computer, NULL, 0, genericEEPROM);
nn_address fsFolder = "OpenOS"; nn_address fsFolder = "OpenOS";
nn_filesystemTable genericFSTable = { nn_filesystemTable genericFSTable = {
@ -682,28 +640,28 @@ int main() {
.seek = (void *)ne_fs_seek, .seek = (void *)ne_fs_seek,
}; };
nn_filesystem *genericFS = nn_newFilesystem(&ctx, genericFSTable, ne_fs_ctrl); nn_filesystem *genericFS = nn_newFilesystem(&ctx, genericFSTable, ne_fs_ctrl);
nn_addFileSystem(computer, fsFolder, 1, genericFS); nn_addFileSystem(computer, NULL, 1, genericFS);
ne_drive drive = { nn_vdriveOptions vdriveOpts = {
.file = fopen("data/drive.img", "r+") .sectorSize = 512,
.capacity = 1*1024*1024,
.platterCount = 1,
.labelLen = 0,
.data = NULL,
}; };
assert(drive.file != NULL); nn_driveControl vdriveCtrl = {
.readSectorsPerTick = 32768,
nn_drive genericDrive = { .writeSectorsPerTick = 16384,
.refc = 0, .seekSectorsPerTick = 8192,
.userdata = &drive, .readHeatPerSector = 0.0015,
.deinit = (void *)ne_drive_close, .writeHeatPerSector = 0.015,
.control = (void *)ne_drive_getControl, .motorHeatPerSector = 0.000005,
.getLabel = ne_fs_getLabel, .readEnergyPerSector = 0.0015,
.setLabel = ne_fs_setLabel, .writeEnergyPerSector = 0.015,
.getPlatterCount = (void *)ne_drive_getPlatterCount, .motorEnergyPerSector = 0.00005,
.getSectorSize = (void *)ne_drive_getSectorSize,
.getCapacity = (void *)ne_drive_getCapacity,
.readSector = (void *)ne_drive_readSector,
.writeSector = (void *)ne_drive_writeSector,
}; };
nn_drive *genericDrive = nn_volatileDrive(&ctx, vdriveOpts, vdriveCtrl);
nn_addDrive(computer, "drive.img", 4, &genericDrive); nn_addDrive(computer, NULL, 4, genericDrive);
int maxWidth = 80, maxHeight = 32; int maxWidth = 80, maxHeight = 32;
@ -711,7 +669,7 @@ int main() {
nn_setDepth(s, 4); // looks cool nn_setDepth(s, 4); // looks cool
nn_addKeyboard(s, "shitty keyboard"); nn_addKeyboard(s, "shitty keyboard");
nn_mountKeyboard(computer, "shitty keyboard", 2); nn_mountKeyboard(computer, "shitty keyboard", 2);
nn_addScreen(computer, "Main Screen", 2, s); nn_addScreen(computer, NULL, 2, s);
ne_premappedPixel *premap = ne_allocPremap(maxWidth, maxHeight); ne_premappedPixel *premap = ne_allocPremap(maxWidth, maxHeight);
@ -731,7 +689,7 @@ int main() {
.energyPerVRAMChange = 0.0015, .energyPerVRAMChange = 0.0015,
}; };
nn_addGPU(computer, "RTX 6090", 3, &gpuCtrl); nn_addGPU(computer, NULL, 3, &gpuCtrl);
SetConfigFlags(FLAG_WINDOW_RESIZABLE); SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(800, 600, "emulator"); InitWindow(800, 600, "emulator");

View File

@ -196,6 +196,7 @@ double nn_randf(nn_Rng *rng);
// returns from 0 to 1 (exclusive) // returns from 0 to 1 (exclusive)
double nn_randfe(nn_Rng *rng); double nn_randfe(nn_Rng *rng);
typedef struct nn_Context { typedef struct nn_Context {
nn_Alloc allocator; nn_Alloc allocator;
nn_LockManager lockManager; nn_LockManager lockManager;
@ -281,6 +282,7 @@ void nn_dealloc(nn_Alloc *alloc, void *memory, nn_size_t size);
char *nn_strdup(nn_Alloc *alloc, const char *s); char *nn_strdup(nn_Alloc *alloc, const char *s);
void *nn_memdup(nn_Alloc *alloc, const void *buf, nn_size_t len); void *nn_memdup(nn_Alloc *alloc, const void *buf, nn_size_t len);
void nn_deallocStr(nn_Alloc *alloc, char *s); void nn_deallocStr(nn_Alloc *alloc, char *s);
nn_address nn_randomUUID(nn_Context *ctx);
nn_guard *nn_newGuard(nn_Context *context); nn_guard *nn_newGuard(nn_Context *context);
void nn_lock(nn_Context *context, nn_guard *guard); void nn_lock(nn_Context *context, nn_guard *guard);
@ -298,6 +300,8 @@ nn_bool_t nn_decRef(nn_refc *refc);
// Unicode (more specifically, UTF-8) stuff // Unicode (more specifically, UTF-8) stuff
nn_bool_t nn_unicode_validate(const char *s); nn_bool_t nn_unicode_validate(const char *s);
// expects NULL terminator
nn_bool_t nn_unicode_isValidCodepoint(const char *s);
// returned string must be nn_deallocStr()'d // returned string must be nn_deallocStr()'d
char *nn_unicode_char(nn_Alloc *alloc, unsigned int *codepoints, nn_size_t codepointCount); char *nn_unicode_char(nn_Alloc *alloc, unsigned int *codepoints, nn_size_t codepointCount);
// returned array must be nn_dealloc()'d // returned array must be nn_dealloc()'d
@ -601,11 +605,24 @@ typedef struct nn_eepromTable {
typedef struct nn_eeprom nn_eeprom; 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_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); nn_guard *nn_getEEPROMLock(nn_eeprom *eeprom);
void nn_retainEEPROM(nn_eeprom *eeprom); void nn_retainEEPROM(nn_eeprom *eeprom);
nn_bool_t nn_destroyEEPROM(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 // FileSystem
typedef struct nn_filesystemControl { typedef struct nn_filesystemControl {
@ -691,28 +708,42 @@ typedef struct nn_driveControl {
nn_bool_t reversable; nn_bool_t reversable;
} nn_driveControl; } nn_driveControl;
typedef struct nn_drive { typedef struct nn_driveTable {
nn_refc refc;
void *userdata; void *userdata;
void (*deinit)(nn_component *component, void *userdata); void (*deinit)(void *userdata);
nn_driveControl (*control)(nn_component *component, void *userdata); void (*getLabel)(void *userdata, char *buf, nn_size_t *buflen);
void (*getLabel)(nn_component *component, void *userdata, char *buf, nn_size_t *buflen); nn_size_t (*setLabel)(void *userdata, const char *buf, nn_size_t buflen);
nn_size_t (*setLabel)(nn_component *component, void *userdata, const char *buf, nn_size_t buflen);
nn_size_t (*getPlatterCount)(nn_component *component, void *userdata); nn_size_t platterCount;
nn_size_t (*getCapacity)(nn_component *component, void *userdata); nn_size_t capacity;
nn_size_t (*getSectorSize)(nn_component *component, void *userdata); nn_size_t sectorSize;
// sectors start at 1 as per OC. // sectors start at 1 as per OC.
void (*readSector)(nn_component *component, void *userdata, int sector, char *buf); void (*readSector)(void *userdata, int sector, char *buf);
void (*writeSector)(nn_component *component, void *userdata, int sector, const char *buf); void (*writeSector)(void *userdata, int sector, const char *buf);
// readByte and writeByte will internally use readSector and writeSector. This is to ensure they are handled *consistently.* // readByte and writeByte will internally use readSector and writeSector. This is to ensure they are handled *consistently.*
// Also makes the interface less redundant // Also makes the interface less redundant
} nn_drive; } nn_driveTable;
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);
nn_guard *nn_getDriveLock(nn_drive *drive);
void nn_retainDrive(nn_drive *drive);
nn_bool_t nn_destroyDrive(nn_drive *drive);
nn_drive *nn_volatileDrive(nn_size_t capacity, nn_size_t platterCount, nn_driveControl *control);
nn_component *nn_addDrive(nn_computer *computer, nn_address address, int slot, nn_drive *drive); nn_component *nn_addDrive(nn_computer *computer, nn_address address, int slot, nn_drive *drive);
// Screens and GPUs // Screens and GPUs

View File

@ -17,6 +17,14 @@ local function copy(v, p)
end end
end end
local function spcall(f, ...)
local t = {pcall(f, ...)}
if t[1] then
return table.unpack(t, 2)
end
return nil, t[2]
end
local function nextDeadline() local function nextDeadline()
return computer.uptime() + 5 return computer.uptime() + 5
end end
@ -392,40 +400,9 @@ sandbox = {
utf8 = copy(utf8), utf8 = copy(utf8),
unicode = copy(unicode, { unicode = copy(unicode, {
wtrunc = function (str,space)
space = space - 1
return str:sub(1,(space >= utf8.len(str)) and (#str) or (utf8.offset(str,space+1)-1))
end,
isWide = function(s) return unicode.wlen(s) > unicode.len(s) end, isWide = function(s) return unicode.wlen(s) > unicode.len(s) end,
upper = string.upper, upper = string.upper,
lower = string.lower, lower = string.lower,
--[[
sub = function (str,a,b)
if not b then b = utf8.len(str) end
if not a then a = 1 end
-- a = math.max(a,1)
if a < 0 then
-- negative
a = utf8.len(str) + a + 1
end
if b < 0 then
b = utf8.len(str) + b + 1
end
if a > b then return "" end
if b >= utf8.len(str) then b = #str else b = utf8.offset(str,b+1)-1 end
if a > utf8.len(str) then return "" end
a = utf8.offset(str,a)
return str:sub(a,b)
-- return str:sub(a, b)
end,
]]
}), }),
checkArg = checkArg, checkArg = checkArg,
component = libcomponent, component = libcomponent,

View File

@ -59,12 +59,12 @@ const char *testLuaArch_pushlstring(lua_State *L, const char *s, size_t len) {
} }
return lua_pushlstring(L, s, len); return lua_pushlstring(L, s, len);
} }
const char *testLuaArch_pushstring(lua_State *L, const char *s) { const char *testLuaArch_pushstring(lua_State *L, const char *s) {
size_t len = strlen(s); size_t len = strlen(s);
return testLuaArch_pushlstring(L, s, len); return testLuaArch_pushlstring(L, s, len);
} }
void *testLuaArch_alloc(testLuaArch *arch, void *ptr, size_t osize, size_t nsize) { void *testLuaArch_alloc(testLuaArch *arch, void *ptr, size_t osize, size_t nsize) {
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(arch->computer)); nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(arch->computer));
if(nsize == 0) { if(nsize == 0) {

View File

@ -162,6 +162,36 @@ static nn_bool_t nn_unicode_is_continuation(unsigned char byte) {
return (byte >> 6) == 0b10; return (byte >> 6) == 0b10;
} }
nn_bool_t nn_unicode_isValidCodepoint(const char *s) {
if(s[0] <= 0x7F) {
return true;
} else if((s[0] >> 5) == 0b110) {
if (!nn_unicode_is_continuation(s[1])) {
return false;
}
} else if((s[0] >> 4) == 0b1110) {
if (!nn_unicode_is_continuation(s[1])) {
return false;
}
if (!nn_unicode_is_continuation(s[2])) {
return false;
}
} else if((s[0] >> 3) == 0b11110) {
if (!nn_unicode_is_continuation(s[1])) {
return false;
}
if (!nn_unicode_is_continuation(s[2])) {
return false;
}
if (!nn_unicode_is_continuation(s[3])) {
return false;
}
} else {
return false;
}
return true;
}
nn_bool_t nn_unicode_validate(const char *b) { nn_bool_t nn_unicode_validate(const char *b) {
const unsigned char* s = (const unsigned char*)b; const unsigned char* s = (const unsigned char*)b;
while (*s) { while (*s) {

View File

@ -104,6 +104,36 @@ void nn_deallocStr(nn_Alloc *alloc, char *s) {
nn_dealloc(alloc, s, nn_strlen(s)+1); nn_dealloc(alloc, s, nn_strlen(s)+1);
} }
static void nni_randomHex(nn_Context *ctx, char *buf, nn_size_t len) {
const char *hex = "0123456789abcdef";
for(nn_size_t i = 0; i < len; i++) {
int r = nn_rand(&ctx->rng) % 16;
buf[i] = hex[r];
}
}
nn_address nn_randomUUID(nn_Context *ctx) {
nn_address addr = nn_alloc(&ctx->allocator, 37);
if(addr == NULL) return NULL;
nni_randomHex(ctx, addr + 0, 8);
addr[8] = '-';
nni_randomHex(ctx, addr + 9, 4);
addr[13] = '-';
nni_randomHex(ctx, addr + 14, 4);
addr[18] = '-';
nni_randomHex(ctx, addr + 19, 4);
addr[23] = '-';
nni_randomHex(ctx, addr + 24, 12);
addr[36] = '\0';
// UUIDv4 variant 1
addr[14] = '4';
addr[19] = '1';
return addr;
}
nn_size_t nn_rand(nn_Rng *rng) { nn_size_t nn_rand(nn_Rng *rng) {
return rng->proc(rng->userdata); return rng->proc(rng->userdata);
} }