mirror of
https://github.com/NeoFlock/neonucleus.git
synced 2025-09-24 09:03:32 +02:00
Compare commits
2 Commits
833d919066
...
4fecda06d4
Author | SHA1 | Date | |
---|---|---|---|
|
4fecda06d4 | ||
|
1fa8284aea |
21
TODO.md
21
TODO.md
@ -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
|
||||
|
@ -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, nn_drive *drive) {
|
||||
return drive->control(component, drive->userdata);
|
||||
nn_driveControl nn_drive_getControl(nn_component *component, nni_drive *drive) {
|
||||
return drive->funcs->control(component, drive->funcs->userdata);
|
||||
}
|
||||
|
||||
void nn_drive_getLabel(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) {
|
||||
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_simulateBufferedIndirect(component, moved, ctrl.seekSectorsPerTick);
|
||||
nn_addHeat(computer, ctrl.motorHeatPerSector * moved);
|
||||
nn_removeEnergy(computer, ctrl.motorEnergyPerSector * moved);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user