mirror of
https://github.com/NeoFlock/neonucleus.git
synced 2025-09-24 09:03:32 +02:00
Compare commits
5 Commits
af1244b829
...
2621554165
Author | SHA1 | Date | |
---|---|---|---|
|
2621554165 | ||
|
760bdacf6d | ||
|
99a8259c80 | ||
|
aa8bdfb88c | ||
|
863e04f19e |
15
TODO.md
15
TODO.md
@ -1,6 +1,10 @@
|
||||
# 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
|
||||
- `computer` component
|
||||
- `modem` component
|
||||
@ -11,14 +15,10 @@
|
||||
- `disk_drive` component
|
||||
- `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.
|
||||
- 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
|
||||
|
||||
- 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
|
||||
|
||||
# The extra components
|
||||
@ -35,11 +35,8 @@
|
||||
- `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
|
||||
|
||||
# API changes
|
||||
|
||||
- move controls into the component instances instead of using getters, to boost performance
|
||||
|
||||
# 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
|
||||
|
@ -26,8 +26,10 @@ 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",
|
||||
"src/components/screen.c",
|
||||
"src/components/gpu.c",
|
||||
"src/components/keyboard.c",
|
||||
@ -68,7 +70,7 @@ fn compileTheRightLua(b: *std.Build, target: std.Build.ResolvedTarget, version:
|
||||
const c = b.addObject(.{
|
||||
.name = "lua",
|
||||
.link_libc = true,
|
||||
.optimize = .ReleaseSafe,
|
||||
.optimize = .ReleaseFast,
|
||||
.target = target,
|
||||
});
|
||||
|
||||
|
@ -1,28 +1,58 @@
|
||||
#include "../neonucleus.h"
|
||||
|
||||
typedef struct nni_drive {
|
||||
nn_drive *funcs;
|
||||
typedef struct nn_drive {
|
||||
nn_refc refc;
|
||||
nn_guard *lock;
|
||||
nn_Context ctx;
|
||||
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) {
|
||||
if(!nn_decRef(&drive->funcs->refc)) return;
|
||||
nn_drive *nn_newDrive(nn_Context *context, nn_driveTable table, nn_driveControl control) {
|
||||
nn_drive *d = nn_alloc(&context->allocator, sizeof(nn_drive));
|
||||
if(d == NULL) return NULL;
|
||||
d->lock = nn_newGuard(context);
|
||||
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;
|
||||
}
|
||||
|
||||
if(drive->funcs->deinit != NULL) {
|
||||
drive->funcs->deinit(component, drive->funcs->userdata);
|
||||
nn_guard *nn_getDriveLock(nn_drive *drive) {
|
||||
return drive->lock;
|
||||
}
|
||||
|
||||
void nn_retainDrive(nn_drive *drive) {
|
||||
nn_incRef(&drive->refc);
|
||||
}
|
||||
|
||||
nn_bool_t nn_destroyDrive(nn_drive *drive) {
|
||||
if(!nn_decRef(&drive->refc)) return false;
|
||||
|
||||
if(drive->table.deinit != NULL) {
|
||||
drive->table.deinit(drive->table.userdata);
|
||||
}
|
||||
|
||||
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(nn_getComputerOfComponent(component)));
|
||||
nn_Context ctx = drive->ctx;
|
||||
|
||||
nn_dealloc(alloc, drive, sizeof(nni_drive));
|
||||
nn_deleteGuard(&ctx, drive->lock);
|
||||
nn_dealloc(&ctx.allocator, drive, sizeof(nn_drive));
|
||||
return true;
|
||||
}
|
||||
|
||||
nn_driveControl nn_drive_getControl(nn_component *component, nni_drive *drive) {
|
||||
return drive->funcs->control(component, drive->funcs->userdata);
|
||||
void nn_drive_destroy(void *_, nn_component *component, nn_drive *drive) {
|
||||
nn_destroyDrive(drive);
|
||||
}
|
||||
|
||||
void nni_drive_readCost(nn_component *component, nni_drive *drive) {
|
||||
nn_driveControl ctrl = nn_drive_getControl(component, drive);
|
||||
void nni_drive_readCost(nn_component *component, nn_drive *drive) {
|
||||
nn_driveControl ctrl = drive->ctrl;
|
||||
nn_computer *computer = nn_getComputerOfComponent(component);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void nni_drive_writeCost(nn_component *component, nni_drive *drive) {
|
||||
nn_driveControl ctrl = nn_drive_getControl(component, drive);
|
||||
void nni_drive_writeCost(nn_component *component, nn_drive *drive) {
|
||||
nn_driveControl ctrl = drive->ctrl;
|
||||
nn_computer *computer = nn_getComputerOfComponent(component);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
// which is much nicer to do math with
|
||||
// and Lua made a big oopsie.
|
||||
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
|
||||
nn_computer *computer = nn_getComputerOfComponent(component);
|
||||
|
||||
// Compute important constants
|
||||
nn_size_t sectorSize = drive->funcs->getSectorSize(component, drive->funcs->userdata);
|
||||
nn_size_t platterCount = drive->funcs->getPlatterCount(component, drive->funcs->userdata);
|
||||
nn_size_t capacity = drive->funcs->getCapacity(component, drive->funcs->userdata);
|
||||
nn_size_t sectorSize = drive->table.sectorSize;
|
||||
nn_size_t platterCount = drive->table.platterCount;
|
||||
nn_size_t capacity = drive->table.capacity;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
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) {
|
||||
nn_return(computer, nn_values_nil());
|
||||
} else {
|
||||
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_value label = nn_getArgument(computer, 0);
|
||||
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)");
|
||||
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);
|
||||
}
|
||||
void nn_drive_getSectorSize(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
|
||||
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
|
||||
void nn_drive_getSectorSize(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
|
||||
nn_size_t sector_size = drive->table.sectorSize;
|
||||
nn_return(computer, nn_values_integer(sector_size));
|
||||
}
|
||||
void nn_drive_getPlatterCount(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
|
||||
nn_size_t platter_count = drive->funcs->getPlatterCount(component, drive->funcs->userdata);
|
||||
void nn_drive_getPlatterCount(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
|
||||
nn_size_t platter_count = drive->table.platterCount;
|
||||
nn_return(computer, nn_values_integer(platter_count));
|
||||
}
|
||||
void nn_drive_getCapacity(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
|
||||
nn_size_t capacity = drive->funcs->getCapacity(component, drive->funcs->userdata);
|
||||
void nn_drive_getCapacity(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
|
||||
nn_size_t capacity = drive->table.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);
|
||||
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
|
||||
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)");
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
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_size_t buf_size = 0;
|
||||
@ -142,34 +178,40 @@ void nn_drive_writeSector(nni_drive *drive, void *_, nn_component *component, nn
|
||||
return;
|
||||
}
|
||||
// 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)");
|
||||
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_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;
|
||||
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)");
|
||||
return;
|
||||
}
|
||||
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]));
|
||||
}
|
||||
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 writeValue = nn_getArgument(computer, 1);
|
||||
nn_size_t disk_offset = nn_toInt(offsetValue) - 1;
|
||||
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;
|
||||
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)");
|
||||
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)");
|
||||
return;
|
||||
}
|
||||
nn_lock(&drive->ctx, drive->lock);
|
||||
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;
|
||||
|
||||
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) {
|
||||
@ -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_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_component *c = nn_newComponent(computer, address, slot, driveTable, drive);
|
||||
if(c == NULL) {
|
||||
nn_dealloc(alloc, d, sizeof(nni_drive));
|
||||
}
|
||||
return c;
|
||||
return nn_newComponent(computer, address, slot, driveTable, drive);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -58,19 +58,28 @@ nn_bool_t nn_destroyFilesystem(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);
|
||||
fs->spaceUsedCache = spaceUsed;
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
return spaceUsed;
|
||||
}
|
||||
|
||||
void nn_fs_invalidateSpaceUsed(nn_filesystem *fs) {
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
fs->spaceUsedCache = 0;
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
}
|
||||
|
||||
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 total = fs->table.spaceTotal;
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
return total - used;
|
||||
}
|
||||
|
||||
@ -78,7 +87,9 @@ void *nn_fs_unwrapFD(nn_filesystem *fs, nn_size_t fd) {
|
||||
if(fd >= NN_MAX_OPEN_FILES) {
|
||||
return NULL;
|
||||
}
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
void *file = fs->files[fd];
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
if(file == 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) {
|
||||
char buf[NN_LABEL_SIZE];
|
||||
nn_size_t l = NN_LABEL_SIZE;
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
fs->table.getLabel(fs->table.userdata, buf, &l);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
if(l == 0) {
|
||||
nn_return(computer, nn_values_nil());
|
||||
} 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)");
|
||||
return;
|
||||
}
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
l = fs->table.setLabel(fs->table.userdata, buf, l);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_return_string(computer, buf, l);
|
||||
|
||||
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) {
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
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) {
|
||||
@ -183,7 +200,9 @@ void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_size_t byteSize = fs->table.size(fs->table.userdata, path);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_size_t removed = fs->table.remove(fs->table.userdata, path);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_return_boolean(computer, removed > 0);
|
||||
|
||||
nn_fs_removeCost(fs, removed, component);
|
||||
@ -218,7 +239,9 @@ void nn_fs_lastModified(nn_filesystem *fs, void *_, nn_component *component, nn_
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
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_fs_removeCost(fs, movedCount, component);
|
||||
@ -270,7 +295,9 @@ void nn_fs_exists(nn_filesystem *fs, void *_, nn_component *component, nn_comput
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
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) {
|
||||
@ -285,7 +312,9 @@ void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_c
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
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) {
|
||||
@ -300,7 +329,9 @@ void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_return_boolean(computer, fs->table.makeDirectory(fs->table.userdata, path));
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
|
||||
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_size_t fileCount = 0;
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
char **files = fs->table.list(alloc, fs->table.userdata, path, &fileCount);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
|
||||
if(files != NULL) {
|
||||
// operation succeeded
|
||||
@ -352,6 +385,7 @@ void nn_fs_open(nn_filesystem *fs, void *_, nn_component *component, nn_computer
|
||||
mode = "r";
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
// technically wrongfully
|
||||
if(!fs->table.exists(fs->table.userdata, path)) {
|
||||
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) {
|
||||
fd++;
|
||||
if(fd == NN_MAX_OPEN_FILES) {
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_setCError(computer, "too many open files");
|
||||
return;
|
||||
}
|
||||
}
|
||||
void *file = fs->table.open(fs->table.userdata, path, mode);
|
||||
if(file == NULL) {
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_setCError(computer, "no such file or directory");
|
||||
return;
|
||||
}
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
fs->files[fd] = file;
|
||||
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;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_bool_t closed = fs->table.close(fs->table.userdata, file);
|
||||
if(closed) {
|
||||
fs->files[fd] = NULL;
|
||||
}
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
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;
|
||||
}
|
||||
|
||||
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...
|
||||
if(spaceRemaining < len) {
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_setCError(computer, "out of space");
|
||||
return;
|
||||
}
|
||||
void *file = nn_fs_unwrapFD(fs, fd);
|
||||
if(file == NULL) {
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_setCError(computer, "bad file descriptor");
|
||||
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_return(computer, nn_values_boolean(written));
|
||||
if(written) nn_fs_invalidateSpaceUsed(fs);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
|
||||
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;
|
||||
nn_size_t byteLen = len;
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
void *file = nn_fs_unwrapFD(fs, fd);
|
||||
if(file == NULL) {
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_setCError(computer, "bad file descriptor");
|
||||
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));
|
||||
char *buf = nn_alloc(alloc, byteLen);
|
||||
if(buf == NULL) {
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_setCError(computer, "out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
nn_size_t readLen = fs->table.read(fs->table.userdata, file, buf, byteLen);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
if(readLen > 0) {
|
||||
// Nothing read means EoF.
|
||||
nn_return_string(computer, buf, readLen);
|
||||
@ -480,13 +527,16 @@ void nn_fs_seek(nn_filesystem *fs, void *_, nn_component *component, nn_computer
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
void *file = nn_fs_unwrapFD(fs, fd);
|
||||
if(file == NULL) {
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_setCError(computer, "bad file descriptor");
|
||||
return;
|
||||
}
|
||||
|
||||
nn_size_t pos = fs->table.seek(fs->table.userdata, file, whence, off);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
|
||||
nn_return_integer(computer, pos);
|
||||
}
|
||||
|
@ -131,22 +131,23 @@ void nni_gpu_set(nni_gpu *gpu, void *_, nn_component *component, nn_computer *co
|
||||
return;
|
||||
}
|
||||
|
||||
if(!nn_unicode_validate(s)) {
|
||||
nn_setCError(computer, "invalid utf-8");
|
||||
return;
|
||||
}
|
||||
|
||||
int current = 0;
|
||||
int len = 0;
|
||||
while(s[current] != 0) {
|
||||
int codepoint = nn_unicode_codepointAt(s, current);
|
||||
nn_setPixel(gpu->currentScreen, x, y, nni_gpu_makePixel(gpu, s + current));
|
||||
if(nn_unicode_isValidCodepoint(s + current)) {
|
||||
int codepoint = nn_unicode_codepointAt(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) {
|
||||
y++;
|
||||
} else {
|
||||
x++;
|
||||
}
|
||||
current += nn_unicode_codepointSize(codepoint);
|
||||
len++;
|
||||
}
|
||||
|
||||
|
74
src/components/volatileDrive.c
Normal file
74
src/components/volatileDrive.c
Normal 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);
|
||||
}
|
98
src/components/volatileEeprom.c
Normal file
98
src/components/volatileEeprom.c
Normal 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);
|
||||
}
|
@ -367,7 +367,11 @@ nn_component *nn_newComponent(nn_computer *computer, nn_address address, int slo
|
||||
computer->componentLen++;
|
||||
}
|
||||
|
||||
c->address = nn_strdup(&computer->universe->ctx.allocator, address);
|
||||
if(address == NULL) {
|
||||
c->address = nn_randomUUID(&computer->universe->ctx);
|
||||
} else {
|
||||
c->address = nn_strdup(&computer->universe->ctx.allocator, address);
|
||||
}
|
||||
if(c->address == NULL) return NULL;
|
||||
c->table = table;
|
||||
c->slot = slot;
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@ -291,47 +290,6 @@ bool ne_fs_exists(nn_address addr, const char *path) {
|
||||
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) {
|
||||
switch (keycode) {
|
||||
case KEY_NULL:
|
||||
@ -656,7 +614,7 @@ int main() {
|
||||
|
||||
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_filesystemTable genericFSTable = {
|
||||
@ -682,28 +640,28 @@ int main() {
|
||||
.seek = (void *)ne_fs_seek,
|
||||
};
|
||||
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 = {
|
||||
.file = fopen("data/drive.img", "r+")
|
||||
nn_vdriveOptions vdriveOpts = {
|
||||
.sectorSize = 512,
|
||||
.capacity = 1*1024*1024,
|
||||
.platterCount = 1,
|
||||
.labelLen = 0,
|
||||
.data = NULL,
|
||||
};
|
||||
assert(drive.file != NULL);
|
||||
|
||||
nn_drive genericDrive = {
|
||||
.refc = 0,
|
||||
.userdata = &drive,
|
||||
.deinit = (void *)ne_drive_close,
|
||||
.control = (void *)ne_drive_getControl,
|
||||
.getLabel = ne_fs_getLabel,
|
||||
.setLabel = ne_fs_setLabel,
|
||||
.getPlatterCount = (void *)ne_drive_getPlatterCount,
|
||||
.getSectorSize = (void *)ne_drive_getSectorSize,
|
||||
.getCapacity = (void *)ne_drive_getCapacity,
|
||||
.readSector = (void *)ne_drive_readSector,
|
||||
.writeSector = (void *)ne_drive_writeSector,
|
||||
nn_driveControl vdriveCtrl = {
|
||||
.readSectorsPerTick = 32768,
|
||||
.writeSectorsPerTick = 16384,
|
||||
.seekSectorsPerTick = 8192,
|
||||
.readHeatPerSector = 0.0015,
|
||||
.writeHeatPerSector = 0.015,
|
||||
.motorHeatPerSector = 0.000005,
|
||||
.readEnergyPerSector = 0.0015,
|
||||
.writeEnergyPerSector = 0.015,
|
||||
.motorEnergyPerSector = 0.00005,
|
||||
};
|
||||
|
||||
nn_addDrive(computer, "drive.img", 4, &genericDrive);
|
||||
nn_drive *genericDrive = nn_volatileDrive(&ctx, vdriveOpts, vdriveCtrl);
|
||||
nn_addDrive(computer, NULL, 4, genericDrive);
|
||||
|
||||
int maxWidth = 80, maxHeight = 32;
|
||||
|
||||
@ -711,7 +669,7 @@ int main() {
|
||||
nn_setDepth(s, 4); // looks cool
|
||||
nn_addKeyboard(s, "shitty keyboard");
|
||||
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);
|
||||
|
||||
@ -731,7 +689,7 @@ int main() {
|
||||
.energyPerVRAMChange = 0.0015,
|
||||
};
|
||||
|
||||
nn_addGPU(computer, "RTX 6090", 3, &gpuCtrl);
|
||||
nn_addGPU(computer, NULL, 3, &gpuCtrl);
|
||||
|
||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||
InitWindow(800, 600, "emulator");
|
||||
|
@ -196,6 +196,7 @@ double nn_randf(nn_Rng *rng);
|
||||
// returns from 0 to 1 (exclusive)
|
||||
double nn_randfe(nn_Rng *rng);
|
||||
|
||||
|
||||
typedef struct nn_Context {
|
||||
nn_Alloc allocator;
|
||||
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);
|
||||
void *nn_memdup(nn_Alloc *alloc, const void *buf, nn_size_t len);
|
||||
void nn_deallocStr(nn_Alloc *alloc, char *s);
|
||||
nn_address nn_randomUUID(nn_Context *ctx);
|
||||
|
||||
nn_guard *nn_newGuard(nn_Context *context);
|
||||
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
|
||||
|
||||
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
|
||||
char *nn_unicode_char(nn_Alloc *alloc, unsigned int *codepoints, nn_size_t codepointCount);
|
||||
// returned array must be nn_dealloc()'d
|
||||
@ -601,11 +605,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 {
|
||||
@ -691,28 +708,42 @@ typedef struct nn_driveControl {
|
||||
nn_bool_t reversable;
|
||||
} nn_driveControl;
|
||||
|
||||
typedef struct nn_drive {
|
||||
nn_refc refc;
|
||||
typedef struct nn_driveTable {
|
||||
void *userdata;
|
||||
void (*deinit)(nn_component *component, void *userdata);
|
||||
void (*deinit)(void *userdata);
|
||||
|
||||
nn_driveControl (*control)(nn_component *component, void *userdata);
|
||||
void (*getLabel)(nn_component *component, void *userdata, char *buf, nn_size_t *buflen);
|
||||
nn_size_t (*setLabel)(nn_component *component, void *userdata, const char *buf, nn_size_t buflen);
|
||||
void (*getLabel)(void *userdata, char *buf, nn_size_t *buflen);
|
||||
nn_size_t (*setLabel)(void *userdata, const char *buf, nn_size_t buflen);
|
||||
|
||||
nn_size_t (*getPlatterCount)(nn_component *component, void *userdata);
|
||||
nn_size_t (*getCapacity)(nn_component *component, void *userdata);
|
||||
nn_size_t (*getSectorSize)(nn_component *component, void *userdata);
|
||||
nn_size_t platterCount;
|
||||
nn_size_t capacity;
|
||||
nn_size_t sectorSize;
|
||||
|
||||
// sectors start at 1 as per OC.
|
||||
void (*readSector)(nn_component *component, void *userdata, int sector, char *buf);
|
||||
void (*writeSector)(nn_component *component, void *userdata, int sector, const char *buf);
|
||||
void (*readSector)(void *userdata, int sector, 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.*
|
||||
// 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);
|
||||
|
||||
// Screens and GPUs
|
||||
|
@ -17,6 +17,14 @@ local function copy(v, p)
|
||||
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()
|
||||
return computer.uptime() + 5
|
||||
end
|
||||
@ -392,40 +400,9 @@ sandbox = {
|
||||
|
||||
utf8 = copy(utf8),
|
||||
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,
|
||||
upper = string.upper,
|
||||
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,
|
||||
component = libcomponent,
|
||||
|
@ -59,12 +59,12 @@ const char *testLuaArch_pushlstring(lua_State *L, const char *s, size_t len) {
|
||||
}
|
||||
return lua_pushlstring(L, s, len);
|
||||
}
|
||||
|
||||
const char *testLuaArch_pushstring(lua_State *L, const char *s) {
|
||||
size_t len = strlen(s);
|
||||
return testLuaArch_pushlstring(L, s, len);
|
||||
}
|
||||
|
||||
|
||||
void *testLuaArch_alloc(testLuaArch *arch, void *ptr, size_t osize, size_t nsize) {
|
||||
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(arch->computer));
|
||||
if(nsize == 0) {
|
||||
|
@ -162,6 +162,36 @@ static nn_bool_t nn_unicode_is_continuation(unsigned char byte) {
|
||||
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) {
|
||||
const unsigned char* s = (const unsigned char*)b;
|
||||
while (*s) {
|
||||
|
30
src/utils.c
30
src/utils.c
@ -104,6 +104,36 @@ void nn_deallocStr(nn_Alloc *alloc, char *s) {
|
||||
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) {
|
||||
return rng->proc(rng->userdata);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user