From d95726cbf63309cc1eea16b435bd313d8734d6df Mon Sep 17 00:00:00 2001 From: IonutParau Date: Wed, 1 Apr 2026 12:34:57 +0200 Subject: [PATCH] slight bugfix and work on drive --- src/ncomplib.c | 5 ++ src/neonucleus.c | 122 +++++++++++++++++++++++++++++++++++++---------- src/neonucleus.h | 63 ++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 24 deletions(-) diff --git a/src/ncomplib.c b/src/ncomplib.c index efa0099..56a4bc8 100644 --- a/src/ncomplib.c +++ b/src/ncomplib.c @@ -588,6 +588,11 @@ static nn_Exit ncl_fsHandler(nn_FSRequest *req) { } if(req->action == NN_FS_SETLABEL) { nn_lock(ctx, state->lock); + if(state->isReadonly) { + nn_unlock(ctx, state->lock); + nn_setError(C, "is readonly"); + return NN_EBADCALL; + } state->usage++; size_t len = req->setlabel.len; if(len > NN_MAX_LABEL) len = NN_MAX_LABEL; diff --git a/src/neonucleus.c b/src/neonucleus.c index 0f7a93c..f772416 100644 --- a/src/neonucleus.c +++ b/src/neonucleus.c @@ -2364,30 +2364,6 @@ const nn_Drive nn_floppyDrive = { .dataEnergyCost = 128.0 / NN_MiB, }; -void nn_drive_seekPenalty(nn_Computer *C, size_t lastSector, size_t newSector, const nn_Drive *drive) { - // Check if SSD - if(drive->rpm == 0) return; - - size_t maxSectors = drive->capacity / drive->sectorSize; - size_t sectorsPerPlatter = maxSectors / drive->platterCount; - // RPM over the number of sectors, over 60 seconds. - double latencyPerSector = 1.0 / ((double)drive->rpm / 60 * maxSectors); - - // magic - lastSector %= sectorsPerPlatter; - newSector %= sectorsPerPlatter; - - size_t sectorDelta; - if(newSector >= lastSector) { - sectorDelta = newSector - lastSector; - } else if(drive->onlySpinForwards) { - sectorDelta = sectorsPerPlatter - (lastSector - newSector); - } else { - sectorDelta = lastSector - newSector; - } - - nn_addIdleTime(C, sectorDelta * latencyPerSector); -} const nn_ScreenConfig nn_defaultScreens[4] = { (nn_ScreenConfig) { @@ -3780,6 +3756,104 @@ nn_Component *nn_createFilesystem(nn_Universe *universe, const char *address, co nn_Component *nn_createVFilesystem(nn_Universe *universe, const char *address, const nn_VFilesystem *vfs, const nn_Filesystem *fs); +static void nn_drive_seekPenalty(nn_Computer *C, size_t lastSector, size_t newSector, const nn_Drive *drive) { + // Check if SSD + if(drive->rpm == 0) return; + + size_t maxSectors = drive->capacity / drive->sectorSize; + size_t sectorsPerPlatter = maxSectors / drive->platterCount; + // RPM over the number of sectors, over 60 seconds. + double latencyPerSector = 1.0 / ((double)drive->rpm / 60 * maxSectors); + + // magic + lastSector %= sectorsPerPlatter; + newSector %= sectorsPerPlatter; + + size_t sectorDelta; + if(newSector >= lastSector) { + sectorDelta = newSector - lastSector; + } else if(drive->onlySpinForwards) { + sectorDelta = sectorsPerPlatter - (lastSector - newSector); + } else { + sectorDelta = lastSector - newSector; + } + + nn_addIdleTime(C, sectorDelta * latencyPerSector); +} + +typedef enum nn_DrvNum { + NN_DRVNUM_GETCAPACITY, + NN_DRVNUM_GETSECTORSIZE, + NN_DRVNUM_GETPLATTERCOUNT, + NN_DRVNUM_GETLABEL, + NN_DRVNUM_SETLABEL, + NN_DRVNUM_READSECTOR, + NN_DRVNUM_WRITESECTOR, + NN_DRVNUM_READBYTE, + NN_DRVNUM_READUBYTE, + NN_DRVNUM_WRITEBYTE, + + NN_DRVNUM_COUNT, +} nn_DrvNum; + +typedef struct nn_DrvState { + nn_Context *ctx; + nn_Drive drive; + nn_DriveHandler *handler; +} nn_DrvState; + +static nn_Exit nn_drvHandler(nn_ComponentRequest *request) { + nn_Context *ctx = request->ctx; + nn_Computer *C = request->computer; + nn_DrvState *state = request->classState; + + nn_DriveRequest dreq; + dreq.ctx = ctx; + dreq.computer = C; + dreq.state = request->state; + + if(request->action == NN_COMP_DROP) { + dreq.action = NN_DRIVE_DROP; + state->handler(&dreq); + nn_free(ctx, state, sizeof(*state)); + return NN_OK; + } + if(C) nn_setError(C, "bad call"); + return NN_EBADCALL; +} + +nn_Component *nn_createDrive(nn_Universe *universe, const char *address, const nn_Drive *drive, void *state, nn_DriveHandler *handler) { + nn_Component *c = nn_createComponent(universe, address, "drive"); + if(c == NULL) return NULL; + const nn_Method methods[NN_DRVNUM_COUNT] = { + [NN_DRVNUM_GETCAPACITY] = {"getCapacity", "function(): integer - Get drive capacity", NN_DIRECT}, + [NN_DRVNUM_GETSECTORSIZE] = {"getSectorSize", "function(): integer - Get sector size", NN_DIRECT}, + [NN_DRVNUM_GETPLATTERCOUNT] = {"getPlatterCount", "function(): integer - Get number of platters on this drive", NN_DIRECT}, + [NN_DRVNUM_GETLABEL] = {"getLabel", "function(): string? - Get drive label", NN_DIRECT}, + [NN_DRVNUM_SETLABEL] = {"setLabel", "function(label: string?): string - Set drive label", NN_DIRECT}, + }; + nn_Exit e = nn_setComponentMethodsArray(c, methods, NN_DRVNUM_COUNT); + if(e) { + nn_dropComponent(c); + return NULL; + } + nn_Context *ctx = &universe->ctx; + nn_DrvState *drvstate = nn_alloc(ctx, sizeof(*drvstate)); + if(drvstate == NULL) { + nn_dropComponent(c); + return NULL; + } + drvstate->ctx = ctx; + drvstate->drive = *drive; + drvstate->handler = handler; + nn_setComponentState(c, state); + nn_setComponentClassState(c, drvstate); + nn_setComponentHandler(c, nn_drvHandler); + return c; +} + +nn_Component *nn_createVDrive(nn_Universe *universe, const char *address, const nn_VDrive *vdrive, const nn_Drive *drive); + typedef struct nn_ScreenState { nn_Context *ctx; nn_ScreenConfig scrconf; diff --git a/src/neonucleus.h b/src/neonucleus.h index c6db470..e5ffc89 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -1130,6 +1130,69 @@ typedef struct nn_VDrive { extern const nn_Drive nn_defaultDrives[4]; extern const nn_Drive nn_floppyDrive; +typedef enum nn_DriveAction { + // drive gone + NN_DRIVE_DROP, + // get current label + NN_DRIVE_GETLABEL, + // set or remove current label + NN_DRIVE_SETLABEL, + // get the last read position + NN_DRIVE_LASTREADPOS, + // read a sector + NN_DRIVE_READSECTOR, + // write a sector + NN_DRIVE_WRITESECTOR, + // read a byte + NN_DRIVE_READBYTE, + // write a byte + NN_DRIVE_WRITEBYTE, +} nn_DriveAction; + +typedef struct nn_DriveRequest { + nn_Context *ctx; + nn_Computer *computer; + void *state; + const nn_Filesystem *fs; + nn_DriveAction action; + union { + struct { + char *buf; + size_t len; + } getlabel; + struct { + const char *label; + size_t len; + } setlabel; + size_t lastReadPos; + struct { + // 1-indexed + size_t sector; + char *buf; + } readSector; + struct { + // 1-indexed + size_t sector; + const char *buf; + } writeSector; + struct { + // 1-indexed + size_t byte; + unsigned char value; + } readByte; + struct { + // 1-indexed + size_t byte; + unsigned char value; + } writeByte; + }; +} nn_DriveRequest; + +typedef nn_Exit (nn_DriveHandler)(nn_DriveRequest *request); + +nn_Component *nn_createDrive(nn_Universe *universe, const char *address, const nn_Drive *drive, void *state, nn_DriveHandler *handler); +nn_Component *nn_createVDrive(nn_Universe *universe, const char *address, const nn_VDrive *vdrive, const nn_Drive *drive); + // Screen class typedef enum nn_ScreenFeatures {