Compare commits

..

2 Commits

Author SHA1 Message Date
IonutParau
4fecda06d4 small tweaks 2025-07-11 00:47:13 +02:00
IonutParau
1fa8284aea reworked drive controls 2025-07-10 20:57:05 +02:00
5 changed files with 199 additions and 170 deletions

21
TODO.md
View File

@ -1,9 +1,5 @@
# Parity with Vanilla OC (only the stuff that makes sense for an emulator)
- rework literally all the costs to just be heat and amount per tick
- change more methods to be direct but with buffered indirects
- complete the GPU implementation (screen buffers and missing methods)
- complete the screen implementation (bunch of missing methods)
- in-memory version of `filesystem` and `drive`
- `hologram` component
- `computer` component
@ -15,14 +11,14 @@
- `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.
Should use the *busy* machine state to let the sandbox suspend it until it is done playing
- ensure the recursive locks are used correctly to prevent race conditions
- use dynamic arrays for signals (and maybe components)
- 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
@ -39,9 +35,10 @@ Should use the *busy* machine state to let the sandbox suspend it until it is do
- `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
# Internal stuff
# API changes
- custom atomic, lock and improved custom clock support. Perhaps generalizing it to an nn_Context
- no longer depend on libc functions
- no longer depend on libc headers
- no longer link any libc when NN_BAREMETAL
- 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

View File

@ -1,28 +1,99 @@
#include "../neonucleus.h"
void nn_drive_destroy(void *_, nn_component *component, nn_drive *drive) {
if(!nn_decRef(&drive->refc)) return;
typedef struct nni_drive {
nn_drive *funcs;
nn_size_t currentSector;
} nni_drive;
if(drive->deinit != NULL) {
drive->deinit(component, drive->userdata);
void nn_drive_destroy(void *_, nn_component *component, nni_drive *drive) {
if(!nn_decRef(&drive->funcs->refc)) return;
if(drive->funcs->deinit != NULL) {
drive->funcs->deinit(component, drive->funcs->userdata);
}
nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(nn_getComputerOfComponent(component)));
nn_dealloc(alloc, drive, sizeof(nni_drive));
}
nn_driveControl nn_drive_getControl(nn_component *component, nni_drive *drive) {
return drive->funcs->control(component, drive->funcs->userdata);
}
void nni_drive_readCost(nn_component *component, nni_drive *drive) {
nn_driveControl ctrl = nn_drive_getControl(component, drive);
nn_computer *computer = nn_getComputerOfComponent(component);
nn_simulateBufferedIndirect(component, 1, ctrl.readSectorsPerTick);
nn_addHeat(computer, ctrl.readHeatPerSector);
nn_removeEnergy(computer, ctrl.readEnergyPerSector);
}
void nni_drive_writeCost(nn_component *component, nni_drive *drive) {
nn_driveControl ctrl = nn_drive_getControl(component, drive);
nn_computer *computer = nn_getComputerOfComponent(component);
nn_simulateBufferedIndirect(component, 1, ctrl.writeSectorsPerTick);
nn_addHeat(computer, ctrl.writeHeatPerSector);
nn_removeEnergy(computer, ctrl.writeEnergyPerSector);
}
void nni_drive_seekTo(nn_component *component, nni_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);
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 sectorsPerPlatter = (capacity / sectorSize) / platterCount;
sector %= sectorsPerPlatter;
if(old == sector) return;
drive->currentSector = sector;
nn_size_t moved = 0;
if(sector > old) {
moved = sector - old; // moved forwards
} else if(sector < old) {
// moved back, depends on some options
if(ctrl.reversable) {
// horribly fucking unrealistic, as HDDs
// spin at ~7200 RPM, and if it decides
// to spontaneously instantly reverse direction,
// the force would crack the disk
// However, real life is a myth.
moved = old - sector;
} else {
// full turn
moved = sectorsPerPlatter - old;
}
}
nn_driveControl nn_drive_getControl(nn_component *component, nn_drive *drive) {
return drive->control(component, drive->userdata);
nn_simulateBufferedIndirect(component, moved, ctrl.seekSectorsPerTick);
nn_addHeat(computer, ctrl.motorHeatPerSector * moved);
nn_removeEnergy(computer, ctrl.motorEnergyPerSector * moved);
}
void nn_drive_getLabel(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_getLabel(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) {
char buf[NN_LABEL_SIZE];
nn_size_t l = NN_LABEL_SIZE;
drive->getLabel(component, drive->userdata, buf, &l);
drive->funcs->getLabel(component, drive->funcs->userdata, buf, &l);
if(l == 0) {
nn_return(computer, nn_values_nil());
} else {
nn_return_string(computer, buf, l);
}
}
void nn_drive_setLabel(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_setLabel(nni_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);
@ -30,38 +101,38 @@ void nn_drive_setLabel(nn_drive *drive, void *_, nn_component *component, nn_com
nn_setCError(computer, "bad label (string expected)");
return;
}
l = drive->setLabel(component, drive->userdata, buf, l);
l = drive->funcs->setLabel(component, drive->funcs->userdata, buf, l);
nn_return_string(computer, buf, l);
}
void nn_drive_getSectorSize(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t sector_size = drive->getSectorSize(component, drive->userdata);
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);
nn_return(computer, nn_values_integer(sector_size));
}
void nn_drive_getPlatterCount(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t platter_count = drive->getPlatterCount(component, drive->userdata);
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);
nn_return(computer, nn_values_integer(platter_count));
}
void nn_drive_getCapacity(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
nn_size_t capacity = drive->getCapacity(component, drive->userdata);
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);
nn_return(computer, nn_values_integer(capacity));
}
void nn_drive_readSector(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_readSector(nni_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->getSectorSize(component, drive->userdata);
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
// we leave the +1 intentionally to compare the end of the real sector
if (sector < 1 || (sector * sector_size > drive->getCapacity(component, drive->userdata))) {
if (sector < 1 || (sector * sector_size > drive->funcs->getCapacity(component, drive->funcs->userdata))) {
nn_setCError(computer, "bad argument #1 (sector out of range)");
return;
}
char buf[sector_size];
drive->readSector(component, drive->userdata, sector, buf);
drive->funcs->readSector(component, drive->funcs->userdata, sector, buf);
nn_return_string(computer, buf, sector_size);
}
void nn_drive_writeSector(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_writeSector(nni_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->getSectorSize(component, drive->userdata);
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
nn_value bufValue = nn_getArgument(computer, 1);
nn_size_t buf_size = 0;
@ -71,34 +142,34 @@ void nn_drive_writeSector(nn_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->getCapacity(component, drive->userdata))) {
if (sector < 1 || (sector * sector_size > drive->funcs->getCapacity(component, drive->funcs->userdata))) {
nn_setCError(computer, "bad argument #1 (sector out of range)");
return;
}
drive->writeSector(component, drive->userdata, sector, buf);
drive->funcs->writeSector(component, drive->funcs->userdata, sector, buf);
}
void nn_drive_readByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_readByte(nni_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->getSectorSize(component, drive->userdata);
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
int sector = (disk_offset / sector_size) + 1;
nn_size_t sector_offset = disk_offset % sector_size;
if (disk_offset >= drive->getCapacity(component, drive->userdata)) {
if (disk_offset >= drive->funcs->getCapacity(component, drive->funcs->userdata)) {
nn_setCError(computer, "bad argument #1 (index out of range)");
return;
}
char buf[sector_size];
drive->readSector(component, drive->userdata, sector, buf);
drive->funcs->readSector(component, drive->funcs->userdata, sector, buf);
nn_return(computer, nn_values_integer(buf[sector_offset]));
}
void nn_drive_writeByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
void nn_drive_writeByte(nni_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->getSectorSize(component, drive->userdata);
nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata);
int sector = (disk_offset / sector_size) + 1;
nn_size_t sector_offset = disk_offset % sector_size;
@ -106,16 +177,16 @@ void nn_drive_writeByte(nn_drive *drive, void *_, nn_component *component, nn_co
nn_setCError(computer, "bad argument #2 (byte out of range)");
return;
}
if (disk_offset >= drive->getCapacity(component, drive->userdata)) {
if (disk_offset >= drive->funcs->getCapacity(component, drive->funcs->userdata)) {
nn_setCError(computer, "bad argument #1 (index out of range)");
return;
}
char buf[sector_size];
drive->readSector(component, drive->userdata, sector, buf);
drive->funcs->readSector(component, drive->funcs->userdata, sector, buf);
buf[sector_offset] = write;
drive->writeSector(component, drive->userdata, sector, buf);
drive->funcs->writeSector(component, drive->funcs->userdata, sector, buf);
}
void nn_loadDriveTable(nn_universe *universe) {
@ -125,7 +196,7 @@ void nn_loadDriveTable(nn_universe *universe) {
nn_defineMethod(driveTable, "getLabel", false, (void *)nn_drive_getLabel, NULL, "getLabel():string - Get the current label of the drive.");
nn_defineMethod(driveTable, "setLabel", false, (void *)nn_drive_setLabel, NULL, "setLabel(value:string):string - Sets the label of the drive. Returns the new value, which may be truncated.");
nn_defineMethod(driveTable, "getSectorSize", true, (void *)nn_drive_getSectorSize, NULL, "getSectorSize():number - Returns the size of a single sector on the drive, in bytes.");
nn_defineMethod(driveTable, "getPlatterCounter", true, (void *)nn_drive_getPlatterCount, NULL, "getPlatterCount():number - Returns the number of platters in the drive.");
nn_defineMethod(driveTable, "getPlatterCount", true, (void *)nn_drive_getPlatterCount, NULL, "getPlatterCount():number - Returns the number of platters in the drive.");
nn_defineMethod(driveTable, "getCapacity", true, (void *)nn_drive_getCapacity, NULL, "getCapacity():number - Returns the total capacity of the drive, in bytes.");
nn_defineMethod(driveTable, "readSector", false, (void *)nn_drive_readSector, NULL, "readSector(sector:number):string - Read the current contents of the specified sector.");
nn_defineMethod(driveTable, "writeSector", false, (void *)nn_drive_writeSector, NULL, "writeSector(sector:number, value:string) - Write the specified contents to the specified sector.");
@ -134,7 +205,15 @@ 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");
return nn_newComponent(computer, address, slot, driveTable, drive);
nn_component *c = nn_newComponent(computer, address, slot, driveTable, drive);
if(c == NULL) {
nn_dealloc(alloc, d, sizeof(nni_drive));
}
return c;
}

View File

@ -22,36 +22,40 @@ nn_filesystemControl nn_fs_getControl(nn_component *component, nn_filesystem *fs
return fs->control(component, fs->userdata);
}
nn_size_t nn_fs_countChunks(nn_filesystem *fs, nn_size_t bytes, nn_component *component) {
void nn_fs_readCost(nn_filesystem *fs, nn_size_t bytes, nn_component *component) {
nn_filesystemControl control = nn_fs_getControl(component, fs);
nn_computer *computer = nn_getComputerOfComponent(component);
nn_size_t chunks = bytes / control.pretendChunkSize;
if(bytes % control.pretendChunkSize != 0) chunks++;
return chunks;
nn_simulateBufferedIndirect(component, bytes, control.readBytesPerTick);
nn_removeEnergy(computer, control.readEnergyPerByte * bytes);
nn_addHeat(computer, control.readHeatPerByte * bytes);
}
void nn_fs_readCost(nn_filesystem *fs, nn_size_t count, nn_component *component, nn_computer *computer) {
void nn_fs_writeCost(nn_filesystem *fs, nn_size_t bytes, nn_component *component) {
nn_filesystemControl control = nn_fs_getControl(component, fs);
nn_removeEnergy(computer, control.readEnergyCost * count);
nn_callCost(computer, control.readCostPerChunk * count);
nn_computer *computer = nn_getComputerOfComponent(component);
nn_simulateBufferedIndirect(component, bytes, control.writeBytesPerTick);
nn_removeEnergy(computer, control.writeEnergyPerByte * bytes);
nn_addHeat(computer, control.writeHeatPerByte * bytes);
}
void nn_fs_writeCost(nn_filesystem *fs, nn_size_t count, nn_component *component, nn_computer *computer) {
void nn_fs_removeCost(nn_filesystem *fs, nn_size_t count, nn_component *component) {
nn_filesystemControl control = nn_fs_getControl(component, fs);
nn_removeEnergy(computer, control.writeEnergyCost * count);
nn_addHeat(computer, control.writeHeatPerChunk * count);
nn_callCost(computer, control.writeCostPerChunk * count);
nn_computer *computer = nn_getComputerOfComponent(component);
nn_simulateBufferedIndirect(component, count, control.removeFilesPerTick);
nn_removeEnergy(computer, control.removeEnergy * count);
nn_addHeat(computer, control.removeHeat * count);
}
void nn_fs_seekCost(nn_filesystem *fs, nn_size_t count, nn_component *component, nn_computer *computer) {
void nn_fs_createCost(nn_filesystem *fs, nn_size_t count, nn_component *component) {
nn_filesystemControl control = nn_fs_getControl(component, fs);
if(control.pretendRPM == 0) return; // disabled, likely SSD
double rps = (double)control.pretendRPM / 60;
double seekLatency = 1.0 / ((double)fs->spaceTotal(component, fs->userdata) / control.pretendChunkSize) / rps;
nn_computer *computer = nn_getComputerOfComponent(component);
nn_removeEnergy(computer, control.writeEnergyCost * count);
nn_addHeat(computer, control.writeHeatPerChunk * count);
nn_callCost(computer, control.writeCostPerChunk * count);
nn_simulateBufferedIndirect(component, count, control.createFilesPerTick);
nn_removeEnergy(computer, control.createEnergy * count);
nn_addHeat(computer, control.createHeat * count);
}
void nn_fs_getLabel(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -64,10 +68,7 @@ void nn_fs_getLabel(nn_filesystem *fs, void *_, nn_component *component, nn_comp
nn_return_string(computer, buf, l);
}
// Latency, energy costs and stuff
nn_filesystemControl control = nn_fs_getControl(component, fs);
nn_removeEnergy(computer, control.readEnergyCost);
nn_callCost(computer, control.readCostPerChunk);
nn_fs_readCost(fs, l, component);
}
void nn_fs_setLabel(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -81,27 +82,21 @@ void nn_fs_setLabel(nn_filesystem *fs, void *_, nn_component *component, nn_comp
l = fs->setLabel(component, fs->userdata, buf, l);
nn_return_string(computer, buf, l);
nn_fs_readCost(fs, 1, component, computer);
nn_fs_writeCost(fs, l, component);
}
void nn_fs_spaceUsed(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
nn_size_t space = fs->spaceUsed(component, fs->userdata);
nn_return(computer, nn_values_integer(space));
nn_fs_readCost(fs, 1, component, computer);
}
void nn_fs_spaceTotal(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
nn_size_t space = fs->spaceUsed(component, fs->userdata);
nn_return(computer, nn_values_integer(space));
nn_fs_readCost(fs, 1, component, computer);
}
void nn_fs_isReadOnly(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
nn_return(computer, nn_values_boolean(fs->isReadOnly(component, fs->userdata)));
nn_fs_readCost(fs, 1, component, computer);
}
void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -119,8 +114,6 @@ void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer
nn_size_t byteSize = fs->size(component, fs->userdata, path);
nn_return(computer, nn_values_integer(byteSize));
nn_fs_readCost(fs, 1, component, computer);
}
void nn_fs_remove(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -137,9 +130,7 @@ void nn_fs_remove(nn_filesystem *fs, void *_, nn_component *component, nn_comput
nn_return(computer, nn_values_boolean(fs->remove(component, fs->userdata, path)));
// Considered 1 safety check + the actual write
nn_fs_readCost(fs, 1, component, computer);
nn_fs_writeCost(fs, 1, component, computer);
nn_fs_removeCost(fs, 1, component);
}
void nn_fs_lastModified(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -162,8 +153,6 @@ void nn_fs_lastModified(nn_filesystem *fs, void *_, nn_component *component, nn_
t -= t % 1000;
nn_return(computer, nn_values_integer(t));
nn_fs_readCost(fs, 1, component, computer);
}
void nn_fs_rename(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -192,9 +181,8 @@ void nn_fs_rename(nn_filesystem *fs, void *_, nn_component *component, nn_comput
nn_size_t movedCount = fs->rename(component, fs->userdata, from, to);
nn_return(computer, nn_values_boolean(movedCount > 0));
// Considered 2 safety checks + 1 read per file + 1 write per file
nn_fs_readCost(fs, 2 + movedCount, component, computer);
nn_fs_writeCost(fs, movedCount, component, computer);
nn_fs_removeCost(fs, movedCount, component);
nn_fs_createCost(fs, movedCount, component);
}
void nn_fs_exists(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -210,8 +198,6 @@ void nn_fs_exists(nn_filesystem *fs, void *_, nn_component *component, nn_comput
}
nn_return(computer, nn_values_boolean(fs->exists(component, fs->userdata, path)));
nn_fs_readCost(fs, 1, component, computer);
}
void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -227,8 +213,6 @@ void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_c
}
nn_return(computer, nn_values_boolean(fs->isDirectory(component, fs->userdata, path)));
nn_fs_readCost(fs, 1, component, computer);
}
void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -245,8 +229,7 @@ void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn
nn_return(computer, nn_values_boolean(fs->makeDirectory(component, fs->userdata, path)));
nn_fs_readCost(fs, 1, component, computer);
nn_fs_writeCost(fs, 1, component, computer);
nn_fs_createCost(fs, 1, component);
}
void nn_fs_list(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -276,8 +259,6 @@ void nn_fs_list(nn_filesystem *fs, void *_, nn_component *component, nn_computer
nn_dealloc(alloc, files, sizeof(char *) * fileCount);
nn_return(computer, arr);
}
nn_fs_readCost(fs, 1 + fileCount, component, computer);
}
void nn_fs_open(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -298,11 +279,13 @@ void nn_fs_open(nn_filesystem *fs, void *_, nn_component *component, nn_computer
mode = "r";
}
// technically wrongfully
if(!fs->exists(component, fs->userdata, path)) {
nn_fs_createCost(fs, 1, component);
}
nn_size_t fd = fs->open(component, fs->userdata, path, mode);
nn_return(computer, nn_values_integer(fd));
// 1 safety check
nn_fs_readCost(fs, 1, component, computer);
}
void nn_fs_close(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -311,9 +294,6 @@ void nn_fs_close(nn_filesystem *fs, void *_, nn_component *component, nn_compute
nn_bool_t closed = fs->close(component, fs->userdata, fd);
nn_return(computer, nn_values_boolean(closed));
// do not ask where it comes from, balance is hard
nn_fs_readCost(fs, 1, component, computer);
}
void nn_fs_write(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -333,9 +313,8 @@ void nn_fs_write(nn_filesystem *fs, void *_, nn_component *component, nn_compute
nn_bool_t closed = fs->write(component, fs->userdata, fd, buf, len);
nn_return(computer, nn_values_boolean(closed));
// do not ask where it comes from, balance is hard
nn_fs_writeCost(fs, nn_fs_countChunks(fs, len, component), component, computer);
nn_fs_seekCost(fs, nn_fs_countChunks(fs, len, component), component, computer);
nn_fs_writeCost(fs, len, component);
nn_return_boolean(computer, true);
}
void nn_fs_read(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) {
@ -362,9 +341,7 @@ void nn_fs_read(nn_filesystem *fs, void *_, nn_component *component, nn_computer
}
nn_dealloc(alloc, buf, byteLen);
// do not ask where it comes from, balance is hard
nn_fs_readCost(fs, nn_fs_countChunks(fs, readLen, component), component, computer);
nn_fs_seekCost(fs, nn_fs_countChunks(fs, readLen, component), component, computer);
nn_fs_readCost(fs, len, component);
}
nn_bool_t nn_fs_validWhence(const char *s) {
@ -397,9 +374,6 @@ void nn_fs_seek(nn_filesystem *fs, void *_, nn_component *component, nn_computer
nn_size_t pos = fs->seek(component, fs->userdata, fd, whence, off, &moved);
if(moved < 0) moved = -moved;
// do not ask where it comes from, balance is hard
nn_fs_readCost(fs, 1, component, computer);
nn_fs_seekCost(fs, nn_fs_countChunks(fs, moved, component), component, computer);
nn_return_integer(computer, pos);
}

View File

@ -174,20 +174,20 @@ typedef struct ne_fs {
nn_filesystemControl ne_fs_getControl(nn_component *component, ne_fs *_) {
return (nn_filesystemControl) {
.pretendChunkSize = 512,
.pretendRPM = 12,
.writeHeatPerChunk = 0.01,
.writeCostPerChunk = 3,
.writeEnergyCost = 0.015,
.writeLatencyPerChunk = 0.0003,
.readEnergyCost = 0.007,
.readCostPerChunk = 1,
.readLatencyPerChunk = 0.0001,
.randomLatencyMin = 0.0005,
.randomLatencyMax = 0.0019,
.seekCostPerChunk = 1,
.motorHeat = 0.03,
.motorEnergyCost = 0.5,
.readBytesPerTick = 65536,
.writeBytesPerTick = 32768,
.removeFilesPerTick = 16,
.createFilesPerTick = 16,
.readHeatPerByte = 0.0000015,
.writeHeatPerByte = 0.000015,
.removeHeat = 0.035,
.createHeat = 0.045,
.readEnergyPerByte = 0.0015,
.writeEnergyPerByte = 0.0035,
.removeEnergy = 0.135,
.createEnergy = 0.325,
};
}

View File

@ -606,34 +606,20 @@ nn_component *nn_addEeprom(nn_computer *computer, nn_address address, int slot,
// FileSystem
typedef struct nn_filesystemControl {
int pretendChunkSize;
double readBytesPerTick;
double writeBytesPerTick;
double removeFilesPerTick;
double createFilesPerTick;
// speed
// used to calculate the latency of seeking a file. It will treat the file as continuous within the storage medium, which is completely
// unrealistic. Essentially, after a seek, it will check how much the file pointer was changed. If it went backwards, the drive spins
// in the opposite direction. Drives work the same way.
int pretendRPM;
double readLatencyPerChunk;
double writeLatencyPerChunk;
double readHeatPerByte;
double writeHeatPerByte;
double removeHeat;
double createHeat;
// these control *random* latencies that each operation will do
double randomLatencyMin;
double randomLatencyMax;
// thermals
double motorHeat; // this times how many chunks have been seeked will be the heat addres, +/- the motor heat range.
double motorHeatRange;
double writeHeatPerChunk;
// call budget
nn_size_t readCostPerChunk;
nn_size_t writeCostPerChunk;
nn_size_t seekCostPerChunk;
// energy cost
double readEnergyCost;
double writeEnergyCost;
double motorEnergyCost;
double readEnergyPerByte;
double writeEnergyPerByte;
double removeEnergy;
double createEnergy;
} nn_filesystemControl;
typedef struct nn_filesystem {
@ -681,28 +667,21 @@ nn_component *nn_addFileSystem(nn_computer *computer, nn_address address, int sl
// Drive
typedef struct nn_driveControl {
double readSectorsPerTick;
double writeSectorsPerTick;
// Set it to 0 to disable seek latency.
int rpm;
double seekSectorsPerTick;
double readLatencyPerSector;
double writeLatencyPerSector;
double randomLatencyMin;
double randomLatencyMax;
double motorHeat;
double motorHeatRange;
double readHeatPerSector;
double writeHeatPerSector;
double motorHeatPerSector;
// These are per sector
double motorEnergyCost;
double readEnergyCost;
double writeEnergyCost;
double readEnergyPerSector;
double writeEnergyPerSector;
double motorEnergyPerSector;
// call budget
nn_size_t readCostPerSector;
nn_size_t writeCostPerSector;
nn_size_t seekCostPerSector;
// if not, seeking *backwards* will cost as much as a full spin.
nn_bool_t reversable;
} nn_driveControl;
typedef struct nn_drive {