diff --git a/TODO.md b/TODO.md index 12747dd..53f2b8e 100644 --- a/TODO.md +++ b/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,6 @@ 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 +# Internal 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 +- use dynamic arrays for signals (and maybe components), but still keep the maximums to prevent memory hogging diff --git a/src/components/drive.c b/src/components/drive.c index 46bc6e6..ab648fd 100644 --- a/src/components/drive.c +++ b/src/components/drive.c @@ -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. + 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; } diff --git a/src/components/filesystem.c b/src/components/filesystem.c index fcb3f64..7e32a55 100644 --- a/src/components/filesystem.c +++ b/src/components/filesystem.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) { @@ -63,11 +67,8 @@ void nn_fs_getLabel(nn_filesystem *fs, void *_, nn_component *component, nn_comp } else { 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) { @@ -136,10 +129,8 @@ 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) { @@ -244,9 +228,8 @@ 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); } diff --git a/src/emulator.c b/src/emulator.c index 14853ef..ed19387 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -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, }; } diff --git a/src/neonucleus.h b/src/neonucleus.h index 0ef1d58..2e3342d 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -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; - - // call budget - nn_size_t readCostPerSector; - nn_size_t writeCostPerSector; - nn_size_t seekCostPerSector; + double readEnergyPerSector; + double writeEnergyPerSector; + double motorEnergyPerSector; + + // if not, seeking *backwards* will cost as much as a full spin. + nn_bool_t reversable; } nn_driveControl; typedef struct nn_drive {