From 571ccb3e3d584688b4d6fbd9638eb6314e9acb1c Mon Sep 17 00:00:00 2001 From: ionut Date: Sun, 3 May 2026 15:55:11 +0300 Subject: [PATCH] more balanced power usage and computer environments --- TODO.md | 2 - src/luaarch.c | 3 +- src/main.c | 35 +++++++------ src/neonucleus.c | 129 +++++++++++++++++++++++++---------------------- src/neonucleus.h | 70 ++++++++++++------------- 5 files changed, 122 insertions(+), 117 deletions(-) diff --git a/TODO.md b/TODO.md index 454274f..72199fa 100644 --- a/TODO.md +++ b/TODO.md @@ -1,8 +1,6 @@ # For MVP functionality - make `computer` component use callbacks -- make beeps, power, etc. be callbacks on one shared local state (computer environment) -- write a tester OS, basically a menu with tests to run - finish tmpfs (rework the whole thing) - device info - userdata support diff --git a/src/luaarch.c b/src/luaarch.c index f20ccf6..a4f8e21 100644 --- a/src/luaarch.c +++ b/src/luaarch.c @@ -133,7 +133,8 @@ static int luaArch_computer_beep(lua_State *L) { if(beep.frequency > 20000) beep.frequency = 20000; if(beep.duration > 5) beep.duration = 5; if(beep.volume > 1) beep.volume = 1; - nn_setComputerBeep(luaArch_from(L)->computer, beep); + nn_beepComputer(luaArch_from(L)->computer, beep); + nn_addIdleTime(luaArch_from(L)->computer, beep.duration); return 0; } diff --git a/src/main.c b/src/main.c index bbebeb6..cab1bde 100644 --- a/src/main.c +++ b/src/main.c @@ -329,11 +329,21 @@ void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize double accumulatedEnergyCost = 0; double totalEnergyLoss = 0; +double allEnergy = 10000; -double ne_energy_accumulator(void *state, nn_Computer *c, double n) { - accumulatedEnergyCost += n; - totalEnergyLoss += n; - return nn_getTotalEnergy(c); +void ne_env(nn_EnvironmentRequest *req) { + if(req->action == NN_ENV_BEEP) { + printf("beep: %f Hz %fs %.02f%%\n", req->beep.frequency, req->beep.duration, req->beep.volume*100); + return; + } + if(req->action == NN_ENV_DRAWENERGY) { + accumulatedEnergyCost += req->energy; + totalEnergyLoss += req->energy; + allEnergy -= req->energy; + req->energy = nn_getTotalEnergy(req->computer); + req->energy = allEnergy; + return; + } } @@ -490,20 +500,16 @@ int main(int argc, char **argv) { ncl_ScreenState *scrstate = nn_getComponentState(screen); ncl_mountKeyboard(scrstate, "mainKB"); - nn_Computer *c = nn_createComputer(u, NULL, "computer0", ramTotal, 256, 256); - nn_Component *wrappedC = nn_wrapComputer(c); - if(showStats) { - // collects stats - nn_setEnergyHandler(c, NULL, ne_energy_accumulator); - } + nn_Computer *c = nn_createComputer(u, NULL, NULL, ramTotal, 256, 256); + nn_setComputerEnvironment(c, (nn_Environment) {.userdata = NULL, .handler = ne_env}); nn_setCallBudget(c, 0); + nn_setTotalEnergy(c, allEnergy); nn_setArchitecture(c, &arch); nn_addSupportedArchitecture(c, &arch); nn_setTmpAddress(c, nn_getComponentAddress(tmpfs)); - nn_mountComponent(c, wrappedC, 255, false); nn_mountComponent(c, screen, -1, false); nn_mountComponent(c, ocelotCard, -1, false); nn_mountComponent(c, tmpfs, -1, false); @@ -721,12 +727,6 @@ int main(int argc, char **argv) { continue; } } - - nn_Beep beep; - if(nn_getComputerBeep(c, &beep)) { - nn_clearComputerBeep(c); - printf("beep: %f Hz, %fs, %f%% volume\n", beep.frequency, beep.duration, beep.volume * 100); - } } cleanup:; @@ -741,7 +741,6 @@ cleanup:; nn_dropComponent(screen); nn_dropComponent(gpuCard); nn_dropComponent(keyboard); - nn_dropComponent(wrappedC); // rip the universe nn_destroyUniverse(u); ncl_destroyGlyphCache(gc); diff --git a/src/neonucleus.c b/src/neonucleus.c index 651d5c6..1b6f622 100644 --- a/src/neonucleus.c +++ b/src/neonucleus.c @@ -474,6 +474,7 @@ void nn_destroyLock(nn_Context *ctx, nn_Lock *lock) { } void nn_lock(nn_Context *ctx, nn_Lock *lock) { + if(lock == NULL) return; nn_LockRequest req; req.lock = lock; req.action = NN_LOCK_LOCK; @@ -481,6 +482,7 @@ void nn_lock(nn_Context *ctx, nn_Lock *lock) { } void nn_unlock(nn_Context *ctx, nn_Lock *lock) { + if(lock == NULL) return; nn_LockRequest req; req.lock = lock; req.action = NN_LOCK_UNLOCK; @@ -1036,6 +1038,7 @@ typedef struct nn_Signal { typedef struct nn_Computer { nn_ComputerState state; nn_Universe *universe; + nn_Environment env; nn_Lock *lock; void *userdata; char *address; @@ -1047,8 +1050,6 @@ typedef struct nn_Computer { size_t totalCallBudget; nn_HashMap components; double totalEnergy; - void *energyState; - nn_EnergyHandler *energyHandler; size_t totalMemory; double creationTimestamp; size_t stackSize; @@ -1056,7 +1057,6 @@ typedef struct nn_Computer { size_t signalCount; size_t userCount; double idleTimestamp; - nn_Beep beep; nn_Value callstack[NN_MAX_STACK]; char errorBuffer[NN_MAX_ERROR_SIZE]; nn_Architecture archs[NN_MAX_ARCHITECTURES]; @@ -1111,10 +1111,10 @@ size_t nn_limitStorage(nn_Universe *universe, size_t storage) { return storage; } -double nn_default_energyHandler(void *state, nn_Computer *computer, double amount) { - (void)state; - (void)amount; - return nn_getTotalEnergy(computer); +static void nn_default_envHandler(nn_EnvironmentRequest *req) { + if(req->action == NN_ENV_DRAWENERGY) { + req->energy = req->computer->totalEnergy; + } } size_t nn_ramSizes[8] = { @@ -1146,7 +1146,12 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char return NULL; } - c->address = nn_strdup(ctx, address); + if(address == NULL) { + c->address = nn_alloc(ctx, sizeof(nn_uuid)); + if(c->address != NULL) nn_randomUUID(ctx, c->address); + } else { + c->address = nn_strdup(ctx, address); + } if(c->address == NULL) { nn_destroyLock(ctx, c->lock); nn_free(ctx, c, sizeof(nn_Computer)); @@ -1170,8 +1175,7 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char } c->totalEnergy = 500; - c->energyState = NULL; - c->energyHandler = nn_default_energyHandler; + c->env.handler = nn_default_envHandler; c->totalMemory = totalMemory; c->creationTimestamp = nn_currentTime(ctx); c->stackSize = 0; @@ -1181,7 +1185,6 @@ nn_Computer *nn_createComputer(nn_Universe *universe, void *userdata, const char c->idleTimestamp = 0; // set to empty string c->errorBuffer[0] = '\0'; - nn_clearComputerBeep(c); return c; } @@ -1251,19 +1254,18 @@ bool nn_isComputerOn(nn_Computer *computer) { return computer->archState != NULL; } -void nn_setComputerBeep(nn_Computer *computer, nn_Beep beep) { +void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment env) { + computer->env = env; +} + +void nn_beepComputer(nn_Computer *computer, nn_Beep beep) { if(beep.duration < 0) beep.duration = 0; - computer->beep = beep; - nn_addIdleTime(computer, beep.duration); -} - -bool nn_getComputerBeep(nn_Computer *computer, nn_Beep *beep) { - *beep = computer->beep; - return computer->beep.volume > 0; -} - -void nn_clearComputerBeep(nn_Computer *computer) { - computer->beep.volume = 0; + nn_EnvironmentRequest req; + req.userdata = computer->env.userdata; + req.computer = computer; + req.action = NN_ENV_BEEP; + req.beep = beep; + computer->env.handler(&req); } void nn_destroyComputer(nn_Computer *computer) { @@ -1422,29 +1424,34 @@ double nn_getTotalEnergy(nn_Computer *computer) { } double nn_getEnergy(nn_Computer *computer) { - double newEnergy = computer->energyHandler(computer->energyState, computer, 0); - if(newEnergy <= 0) { - newEnergy = 0; + nn_EnvironmentRequest req; + req.userdata = computer->env.userdata; + req.computer = computer; + req.action = NN_ENV_DRAWENERGY; + req.energy = 0; + computer->env.handler(&req); + if(req.energy <= 0) { + req.energy = 0; computer->state = NN_BLACKOUT; } - return newEnergy; + return req.energy; } bool nn_removeEnergy(nn_Computer *computer, double energy) { - double newEnergy = computer->energyHandler(computer->energyState, computer, energy); - if(newEnergy <= 0) { - newEnergy = 0; + nn_EnvironmentRequest req; + req.userdata = computer->env.userdata; + req.computer = computer; + req.action = NN_ENV_DRAWENERGY; + req.energy = energy; + computer->env.handler(&req); + if(req.energy <= 0) { + req.energy = 0; computer->state = NN_BLACKOUT; return true; } return false; } -void nn_setEnergyHandler(nn_Computer *computer, void *energyState, nn_EnergyHandler *handler) { - computer->energyState = energyState; - computer->energyHandler = handler; -} - size_t nn_getTotalMemory(nn_Computer *computer) { return computer->totalMemory; } @@ -2561,7 +2568,7 @@ const nn_Filesystem nn_defaultFilesystems[4] = { .readsPerTick = 4, .writesPerTick = 2, .opensPerTick = 4, - .dataEnergyCost = 256.0 / NN_MiB, + .dataEnergyCost = 0.1 / NN_KiB, .maxReadSize = 4096, }, NN_INIT(nn_Filesystem) { @@ -2569,7 +2576,7 @@ const nn_Filesystem nn_defaultFilesystems[4] = { .readsPerTick = 4, .writesPerTick = 2, .opensPerTick = 8, - .dataEnergyCost = 512.0 / NN_MiB, + .dataEnergyCost = 0.1 / NN_KiB, .maxReadSize = 8192, }, NN_INIT(nn_Filesystem) { @@ -2577,7 +2584,7 @@ const nn_Filesystem nn_defaultFilesystems[4] = { .readsPerTick = 7, .writesPerTick = 3, .opensPerTick = 16, - .dataEnergyCost = 1024.0 / NN_MiB, + .dataEnergyCost = 0.1 / NN_KiB, .maxReadSize = 16384, }, NN_INIT(nn_Filesystem) { @@ -2585,7 +2592,7 @@ const nn_Filesystem nn_defaultFilesystems[4] = { .readsPerTick = 13, .writesPerTick = 5, .opensPerTick = 32, - .dataEnergyCost = 2048.0 / NN_MiB, + .dataEnergyCost = 0.1 / NN_KiB, .maxReadSize = 32768, }, }; @@ -2595,7 +2602,7 @@ const nn_Filesystem nn_defaultFloppy = NN_INIT(nn_Filesystem) { .spaceTotal = 512 * NN_KiB, .readsPerTick = 1, .writesPerTick = 1, - .dataEnergyCost = 8.0 / NN_MiB, + .dataEnergyCost = 0.1 / NN_KiB, .maxReadSize = 2048, }; @@ -2728,7 +2735,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = { .paletteColors = 0, .editableColors = 0, .features = NN_SCRF_NONE, - .energyPerPixel = 0.05, + .energyPerPixel = 0.05 / (50*16), .minBrightness = 0.5, .maxBrightness = 1, }, @@ -2740,7 +2747,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = { .paletteColors = 16, .editableColors = 0, .features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED, - .energyPerPixel = 0.05, + .energyPerPixel = 0.05 / (50*16), .minBrightness = 0.25, .maxBrightness = 1.2, }, @@ -2752,7 +2759,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = { .paletteColors = 256, .editableColors = 16, .features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS, - .energyPerPixel = 0.05, + .energyPerPixel = 0.05 / (50*16), .minBrightness = 0.1, .maxBrightness = 1.5, }, @@ -2763,8 +2770,8 @@ const nn_ScreenConfig nn_defaultScreens[4] = { .defaultPalette = nn_ocpalette8, .paletteColors = 256, .editableColors = 256, - .features = NN_SCRF_NONE | NN_SCRF_EDITABLECOLORS, - .energyPerPixel = 0.05, + .features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS, + .energyPerPixel = 0.05 / (50*16), .minBrightness = 0.1, .maxBrightness = 2, }, @@ -2781,8 +2788,8 @@ const nn_GPU nn_defaultGPUs[4] = { .setPerTick = 64, .setForegroundPerTick = 32, .setBackgroundPerTick = 32, - .energyPerWrite = 0.0002, - .energyPerClear = 0.0001, + .energyPerWrite = 0.2 / (50*16), + .energyPerClear = 0.1 / (50*16), }, NN_INIT(nn_GPU) { .maxWidth = 80, @@ -2794,8 +2801,8 @@ const nn_GPU nn_defaultGPUs[4] = { .setPerTick = 128, .setForegroundPerTick = 64, .setBackgroundPerTick = 64, - .energyPerWrite = 0.001, - .energyPerClear = 0.0005, + .energyPerWrite = 0.2 / (50*16), + .energyPerClear = 0.1 / (50*16), }, NN_INIT(nn_GPU) { .maxWidth = 160, @@ -2807,8 +2814,8 @@ const nn_GPU nn_defaultGPUs[4] = { .setPerTick = 256, .setForegroundPerTick = 128, .setBackgroundPerTick = 128, - .energyPerWrite = 0.002, - .energyPerClear = 0.001, + .energyPerWrite = 0.2 / (50*16), + .energyPerClear = 0.1 / (50*16), }, NN_INIT(nn_GPU) { .maxWidth = 240, @@ -2820,8 +2827,8 @@ const nn_GPU nn_defaultGPUs[4] = { .setPerTick = 512, .setForegroundPerTick = 256, .setBackgroundPerTick = 256, - .energyPerWrite = 0.0025, - .energyPerClear = 0.0012, + .energyPerWrite = 0.2 / (50*16), + .energyPerClear = 0.1 / (50*16), }, }; @@ -5977,8 +5984,8 @@ nn_Modem nn_defaultWiredModem = { .maxPacketSize = 8192, .maxOpenPorts = 16, .isWired = true, - .basePacketCost = 50, - .fullPacketCost = 100, + .basePacketCost = 0.5, + .fullPacketCost = 1, .costPerStrength = 0, }; nn_Modem nn_defaultWirelessModems[2] = { @@ -5988,9 +5995,9 @@ nn_Modem nn_defaultWirelessModems[2] = { .maxPacketSize = 8192, .maxOpenPorts = 16, .isWired = true, - .basePacketCost = 100, - .fullPacketCost = 500, - .costPerStrength = 30, + .basePacketCost = 1, + .fullPacketCost = 5, + .costPerStrength = 0.05, }, NN_INIT(nn_Modem) { .maxRange = 400, @@ -5998,8 +6005,8 @@ nn_Modem nn_defaultWirelessModems[2] = { .maxPacketSize = 8192, .maxOpenPorts = 16, .isWired = true, - .basePacketCost = 200, - .fullPacketCost = 1000, - .costPerStrength = 20, + .basePacketCost = 2, + .fullPacketCost = 10, + .costPerStrength = 0.05, }, }; diff --git a/src/neonucleus.h b/src/neonucleus.h index 46fc672..b43c6a2 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -397,6 +397,39 @@ typedef struct nn_Architecture { // NN adds 2 more tiers. extern size_t nn_ramSizes[8]; +typedef struct nn_Beep { + double frequency; + double duration; + double volume; +} nn_Beep; + +typedef enum nn_EnvironmentAction { + NN_ENV_DRAWENERGY, + NN_ENV_POWERON, + NN_ENV_POWEROFF, + NN_ENV_CRASHED, + NN_ENV_BEEP, +} nn_EnvironmentAction; + +typedef struct nn_EnvironmentRequest { + nn_Computer *computer; + void *userdata; + nn_EnvironmentAction action; + union { + // for DRAWENERGY, is the amount to remove, and must be set to the amount remaining + double energy; + // for BEEP, information about the beep + nn_Beep beep; + }; +} nn_EnvironmentRequest; + +typedef void nn_EnvironmentHandler(nn_EnvironmentRequest *req); + +typedef struct nn_Environment { + void *userdata; + nn_EnvironmentHandler *handler; +} nn_Environment; + // The state of a *RUNNING* computer. // Powered off computers shall not have a state, and as far as NeoNucleus is aware, // not exist. @@ -420,30 +453,9 @@ void nn_stopComputer(nn_Computer *computer); void nn_forceCrashComputer(nn_Computer *computer, const char *s); // returns whether an architecture state is present bool nn_isComputerOn(nn_Computer *computer); +void nn_setComputerEnvironment(nn_Computer *computer, nn_Environment env); -typedef enum nn_ComputerEvent { - // when powered on - NN_COMPUTER_POWERON, - // when powered off - NN_COMPUTER_POWEROFF, - // when force-crashed - NN_COMPUTER_FORCECRASH, - // when crashed - NN_COMPUTER_CRASH, -} nn_ComputerEvent; - -typedef void nn_ComputerListener(nn_Computer *computer, nn_ComputerEvent event); -void nn_setComputerListener(nn_Computer *computer, nn_ComputerListener *listener); - -typedef struct nn_Beep { - double frequency; - double duration; - double volume; -} nn_Beep; - -void nn_setComputerBeep(nn_Computer *computer, nn_Beep beep); -bool nn_getComputerBeep(nn_Computer *computer, nn_Beep *beep); -void nn_clearComputerBeep(nn_Computer *computer); +void nn_beepComputer(nn_Computer *computer, nn_Beep beep); // get the userdata pointer void *nn_getComputerUserdata(nn_Computer *computer); @@ -529,18 +541,6 @@ double nn_getEnergy(nn_Computer *computer); // Returns true if there is no more energy left, and a blackout has occured. bool nn_removeEnergy(nn_Computer *computer, double energy); -// the handler of energy costs. -// The default handler just returns the total energy. -// Computers do not keep track of their current energy, they just call this function. -// getEnergy() calls this with amountToRemove set to 0. It is recommended to handle this as a fastpath. -// This should return the new amount of energy after the removal. -// A negative amount can be returned, it will be clamped to 0. -// If an error occurs, it is recommended to just return 0 and trigger a blackout. -// TODO: evaluate if API should be reworked to handle errors in energy handler. -typedef double nn_EnergyHandler(void *energyState, nn_Computer *computer, double amountToRemove); - -void nn_setEnergyHandler(nn_Computer *computer, void *energyState, nn_EnergyHandler *handler); - // copies the string into the local error buffer. The error is NULL terminated, but also capped by NN_MAX_ERROR_SIZE void nn_setError(nn_Computer *computer, const char *s); // set a default error message from an exit.