mirror of
https://github.com/NeoFlock/neonucleus.git
synced 2025-09-24 09:03:32 +02:00
the sound of progress
- Medic TF2
This commit is contained in:
parent
af1244b829
commit
863e04f19e
7
TODO.md
7
TODO.md
@ -1,6 +1,6 @@
|
||||
# Parity with Vanilla OC (only the stuff that makes sense for an emulator)
|
||||
|
||||
- in-memory version of `filesystem` and `drive`
|
||||
- in-memory version of `filesystem`
|
||||
- `hologram` component
|
||||
- `computer` component
|
||||
- `modem` component
|
||||
@ -18,7 +18,6 @@
|
||||
# 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,10 +34,6 @@
|
||||
- `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
|
||||
|
||||
- use dynamic arrays for signals (and maybe components), but still keep the maximums to prevent memory hogging
|
||||
|
@ -28,6 +28,7 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module {
|
||||
"src/components/eeprom.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 +69,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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -367,7 +367,11 @@ nn_component *nn_newComponent(nn_computer *computer, nn_address address, int slo
|
||||
computer->componentLen++;
|
||||
}
|
||||
|
||||
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,26 @@ 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,
|
||||
};
|
||||
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, NULL);
|
||||
nn_addDrive(computer, NULL, 4, genericDrive);
|
||||
|
||||
int maxWidth = 80, maxHeight = 32;
|
||||
|
||||
@ -711,7 +667,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 +687,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);
|
||||
@ -691,28 +693,39 @@ 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;
|
||||
} nn_vdriveOptions;
|
||||
|
||||
typedef struct nn_drive nn_drive;
|
||||
|
||||
nn_drive *nn_newDrive(nn_Context *context, nn_driveTable table, nn_driveControl control);
|
||||
nn_drive *nn_volatileDrive(nn_Context *context, nn_vdriveOptions opts, nn_driveControl control, const char *initialData);
|
||||
nn_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
|
||||
|
@ -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) {
|
||||
|
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