Merge pull request #25 from shorekeeper/main

Fix Windows build and several cross-platform bugs
This commit is contained in:
Quantum Tomato
2026-04-01 18:40:28 +02:00
committed by GitHub
8 changed files with 423 additions and 51 deletions

View File

@@ -63,7 +63,10 @@ fn compileRaylib(b: *std.Build, os: std.Target.Os.Tag, c: *std.Build.Step.Compil
c.linkSystemLibrary("raylib");
if (os == .windows) {
c.linkSystemLibrary("WinMM");
c.linkSystemLibrary("GDI32");
c.linkSystemLibrary("GDI32"); // <---
c.linkSystemLibrary("User32"); // ^ Windows can't just rely on GDI
c.linkSystemLibrary("Shell32");
c.linkSystemLibrary("OpenGL32");
}
}

Submodule foreign/lua52 deleted from 4324904b60

View File

@@ -285,7 +285,7 @@ static int luaArch_component_list(lua_State *L) {
lua_createtable(L, 0, 0);
return 1;
}
const char *comps[len];
NN_VLA(const char *, comps, len);
nn_getComponents(arch->computer, comps);
for(size_t i = 0; i < len; i++) {
nn_Component *c = nn_getComponent(arch->computer, comps[i]);
@@ -385,7 +385,7 @@ static int luaArch_component_methods(lua_State *L) {
lua_createtable(L, 0, 0);
return 1;
}
const char *methods[methodLen];
NN_VLA(const char *, methods, methodLen);
nn_getComponentMethods(c, methods, &methodLen);
lua_createtable(L, 0, methodLen);
for(size_t i = 0; i < methodLen; i++) {
@@ -414,7 +414,8 @@ static int luaArch_component_fields(lua_State *L) {
lua_createtable(L, 0, 0);
return 1;
}
const char *methods[methodLen];
// const char *methods[methodLen];
NN_VLA(const char *, methods, methodLen);
nn_getComponentMethods(c, methods, &methodLen);
lua_createtable(L, 0, methodLen);
for(size_t i = 0; i < methodLen; i++) {
@@ -587,15 +588,15 @@ static void luaArch_loadEnv(lua_State *L) {
lua_createtable(L, 0, 10);
int unicode = lua_gettop(L);
lua_pushcfunction(L, luaArch_unicode_char);
lua_setfield(L, component, "char");
lua_setfield(L, unicode, "char");
lua_pushcfunction(L, luaArch_unicode_len);
lua_setfield(L, component, "len");
lua_setfield(L, unicode, "len");
lua_pushcfunction(L, luaArch_unicode_sub);
lua_setfield(L, component, "sub");
lua_setfield(L, unicode, "sub");
lua_pushcfunction(L, luaArch_unicode_len);
lua_setfield(L, component, "wlen");
lua_setfield(L, unicode, "wlen");
lua_pushcfunction(L, luaArch_unicode_wtrunc);
lua_setfield(L, component, "wtrunc");
lua_setfield(L, unicode, "wtrunc");
lua_setglobal(L, "unicode");
}

View File

@@ -12,6 +12,11 @@
#include <raylib.h>
#include <errno.h>
#ifdef NN_WINDOWS
#include <setjmp.h>
#include <signal.h>
#endif
nn_Architecture getLuaArch();
static const char minBIOS[] = {
@@ -323,8 +328,213 @@ double ne_energy_accumulator(void *state, nn_Computer *c, double n) {
return nn_getTotalEnergy(c);
}
#ifdef NN_WINDOWS
// Quick self-tests for Windows-specific fixes
// These run before anything else so failures are caught early
static jmp_buf nn_test_jmpbuf;
static volatile int nn_test_caught;
static void nn_test_crash_handler(int sig) {
nn_test_caught = 1;
longjmp(nn_test_jmpbuf, 1);
}
static int nn_test_try(void (*func)(void *), void *arg) {
nn_test_caught = 0;
signal(SIGSEGV, nn_test_crash_handler);
signal(SIGABRT, nn_test_crash_handler);
if(setjmp(nn_test_jmpbuf) == 0) {
func(arg);
}
signal(SIGSEGV, SIG_DFL);
signal(SIGABRT, SIG_DFL);
return nn_test_caught;
}
static int nn_test_failed = 0;
static int nn_test_passed = 0;
static void nn_test_report(const char *name, int crashed, int expected_crash) {
if(crashed && !expected_crash) {
printf("[CRASH] %s\n", name);
nn_test_failed++;
} else if(!crashed && expected_crash) {
printf("[FAIL] %s (expected crash)\n", name);
nn_test_failed++;
} else {
printf("[OK] %s\n", name);
nn_test_passed++;
}
fflush(stdout);
}
// --- realloc tests ---
static void nn_test_realloc_null(void *arg) {
nn_Context *ctx = arg;
void *p = nn_realloc(ctx, NULL, 0, 64);
if(p == NULL) { nn_test_failed++; return; }
nn_free(ctx, p, 64);
}
static void nn_test_realloc_grow(void *arg) {
nn_Context *ctx = arg;
void *a = nn_alloc(ctx, 64);
if(a == NULL) return;
void *b = nn_realloc(ctx, a, 64, 128);
if(b != NULL) nn_free(ctx, b, 128);
else nn_free(ctx, a, 64);
}
static void nn_test_realloc_free(void *arg) {
nn_Context *ctx = arg;
void *c = nn_alloc(ctx, 64);
if(c == NULL) return;
nn_realloc(ctx, c, 64, 0);
}
// --- lock tests ---
static void nn_test_lock_create_destroy(void *arg) {
nn_Context *ctx = arg;
nn_Lock *lock = nn_createLock(ctx);
if(lock == NULL) { nn_test_failed++; return; }
nn_destroyLock(ctx, lock);
}
static void nn_test_lock_cycle(void *arg) {
nn_Context *ctx = arg;
nn_Lock *lock = nn_createLock(ctx);
if(lock == NULL) { nn_test_failed++; return; }
// lock and unlock 100 times to stress it
for(int i = 0; i < 100; i++) {
nn_lock(ctx, lock);
nn_unlock(ctx, lock);
}
nn_destroyLock(ctx, lock);
}
static void nn_test_lock_two(void *arg) {
nn_Context *ctx = arg;
// two locks at the same time, make sure they dont interfere
nn_Lock *a = nn_createLock(ctx);
nn_Lock *b = nn_createLock(ctx);
if(a == NULL || b == NULL) { nn_test_failed++; return; }
nn_lock(ctx, a);
nn_lock(ctx, b);
nn_unlock(ctx, b);
nn_unlock(ctx, a);
nn_destroyLock(ctx, a);
nn_destroyLock(ctx, b);
}
// --- VFS tests ---
static void nn_test_vfs_stat(void *arg) {
(void)arg;
// stat current directory, should always work
ncl_Stat s;
bool ok = ncl_stat(ncl_defaultFS, ".", &s);
if(!ok) nn_test_failed++;
if(!s.isDirectory) nn_test_failed++;
}
static void nn_test_vfs_dir(void *arg) {
(void)arg;
void *dir = ncl_opendir(ncl_defaultFS, ".");
if(dir == NULL) { nn_test_failed++; return; }
char name[NN_MAX_PATH];
// just read one entry, dont care what it is
ncl_readdir(ncl_defaultFS, dir, name);
ncl_closedir(ncl_defaultFS, dir);
}
static void nn_test_vfs_mkdir_remove(void *arg) {
(void)arg;
const char *testdir = "nn_test_tmpdir";
ncl_mkdir(ncl_defaultFS, testdir);
ncl_Stat s;
bool ok = ncl_stat(ncl_defaultFS, testdir, &s);
if(!ok || !s.isDirectory) nn_test_failed++;
ncl_remove(ncl_defaultFS, testdir);
// should be gone now
ok = ncl_stat(ncl_defaultFS, testdir, &s);
if(ok) nn_test_failed++;
}
static void nn_test_vfs_seek(void *arg) {
(void)arg;
// write a small file, seek around, read back
const char *path = "nn_test_seekfile";
const char *data = "abcdefghij";
void *f = ncl_openfile(ncl_defaultFS, path, "w");
if(f == NULL) { nn_test_failed++; return; }
ncl_writefile(ncl_defaultFS, f, data, 10);
ncl_closefile(ncl_defaultFS, f);
f = ncl_openfile(ncl_defaultFS, path, "r");
if(f == NULL) { nn_test_failed++; ncl_remove(ncl_defaultFS, path); return; }
// seek to offset 5 from start
int off = 5;
bool ok = ncl_seekfile(ncl_defaultFS, f, NN_SEEK_SET, &off);
if(!ok || off != 5) nn_test_failed++;
// read from there
char buf[5];
size_t len = 5;
ok = ncl_readfile(ncl_defaultFS, f, buf, &len);
if(!ok || len != 5) nn_test_failed++;
// should be "fghij"
if(buf[0] != 'f' || buf[4] != 'j') nn_test_failed++;
ncl_closefile(ncl_defaultFS, f);
ncl_remove(ncl_defaultFS, path);
}
static void nn_run_selftests(nn_Context *ctx) {
printf("--- nn self tests ---\n");
fflush(stdout);
nn_test_report("realloc(NULL)",
nn_test_try(nn_test_realloc_null, ctx), 0);
nn_test_report("realloc(ptr, grow)",
nn_test_try(nn_test_realloc_grow, ctx), 0);
nn_test_report("realloc(ptr, free)",
nn_test_try(nn_test_realloc_free, ctx), 0);
nn_test_report("lock create/destroy",
nn_test_try(nn_test_lock_create_destroy, ctx), 0);
nn_test_report("lock 100 cycles",
nn_test_try(nn_test_lock_cycle, ctx), 0);
nn_test_report("two locks interleaved",
nn_test_try(nn_test_lock_two, ctx), 0);
nn_test_report("vfs stat cwd",
nn_test_try(nn_test_vfs_stat, NULL), 0);
nn_test_report("vfs readdir cwd",
nn_test_try(nn_test_vfs_dir, NULL), 0);
nn_test_report("vfs mkdir/remove",
nn_test_try(nn_test_vfs_mkdir_remove, NULL), 0);
nn_test_report("vfs seek",
nn_test_try(nn_test_vfs_seek, NULL), 0);
printf("--- %d passed, %d failed ---\n\n", nn_test_passed, nn_test_failed);
fflush(stdout);
if(nn_test_failed > 0) {
printf("self tests failed, aborting\n");
fflush(stdout);
exit(1);
}
}
#endif
int main(int argc, char **argv) {
const char *player = getenv("USER");
#ifdef NN_WINDOWS
if(player == NULL) player = getenv("USERNAME");
#endif
if(player == NULL) player = "me";
bool sandboxMem = getenv("NN_MEMSAND") != NULL;
@@ -336,7 +546,9 @@ int main(int argc, char **argv) {
nn_Context ctx;
nn_initContext(&ctx);
nn_initPalettes();
#ifdef NN_WINDOWS
nn_run_selftests(&ctx);
#endif
ne_memSand sand;
sand.buf = NULL;

View File

@@ -17,8 +17,19 @@ bool ncl_defaultHandler(ncl_VFSRequest *request) {
#include <dirent.h>
#include <sys/stat.h>
// Read me all my rights
#elif defined(NN_WINDOWS)
#error "Windows is not supported yet"
#include <windows.h>
#include <sys/stat.h>
#include <direct.h>
typedef struct ncl_WinDir {
HANDLE handle;
WIN32_FIND_DATAA findData;
bool isFirst;
} ncl_WinDir;
#endif
bool ncl_defaultHandler(ncl_VFSRequest *request) {
@@ -54,11 +65,47 @@ bool ncl_defaultHandler(ncl_VFSRequest *request) {
if(wanted == NN_SEEK_SET) whence = SEEK_SET;
if(wanted == NN_SEEK_CUR) whence = SEEK_CUR;
if(wanted == NN_SEEK_END) whence = SEEK_END;
if(fseek(f, whence, request->seek.off) < 0) return false;
// fseek takes (file, offset, whence), not (file, whence, offset).
// The original code had these two arguments swapped, which caused
// every seek to go to the wrong position or fail entirely.
/*
* We want to: seek 100 bytes from the beginning (SEEK_SET = 0)
* Call: fseek(f, 0, 100)
* offset=0, whence=100
* Result: whence=100 is invalid, fseek returns -1, the function returns false
* We want to: seek 0 from the current position (SEEK_CUR = 1)
* Call: fseek(f, 1, 0)
* offset=1, whence=SEEK_SET(0)
* Result: jumps to position 1 from the beginning of the file instead of staying at the same position
* We want to: seek 0 from the beginning (SEEK_SET = 0)
* Call: fseek(f, 0, 0)
* offset=0, whence=SEEK_SET(0)
* Result: works correctly by chance
* We want to: seek 2 from the beginning (SEEK_SET = 0)
* Call: fseek(f, 0, 2)
* offset=0, whence=SEEK_END(2)
* Result: Goes to the end of the file instead of position 2
*/
// Original fseek signature: int fseek(FILE *stream, long offset, int whence) remains,
// yet the : `if(fseek(f, whence, request->seek.off) < 0) return false;`
// ...variant was wrong
if(fseek(f, request->seek.off, whence) < 0) return false;
request->seek.off = ftell(f);
return true;
}
if(request->action == NCL_VFS_REMOVE) {
// On Windows, remove() cannot delete directories.
// We need to check if the path is a directory and use _rmdir instead.
#ifdef NN_WINDOWS
DWORD attrs = GetFileAttributesA(request->remove);
if(attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY)) {
return _rmdir(request->remove) == 0;
}
#endif
return remove(request->remove) == 0;
}
#ifdef NN_POSIX
@@ -102,8 +149,73 @@ bool ncl_defaultHandler(ncl_VFSRequest *request) {
if(request->action == NCL_VFS_MKDIR) {
return mkdir(request->mkdir, 0777) == 0;
}
#elif defined(NN_WINDOWS)
if(request->action == NCL_VFS_OPENDIR) {
// FindFirstFileA needs a glob pattern, so we append "\\*" to the path.
// We allocate the wrapper struct on the heap because FindFirstFileA
// fills in the first result immediately and we need to remember that.
ncl_WinDir *dir = malloc(sizeof(ncl_WinDir));
if(dir == NULL) return false;
char searchPath[NN_MAX_PATH + 4];
snprintf(searchPath, sizeof(searchPath), "%s\\*", request->opendir.path);
dir->handle = FindFirstFileA(searchPath, &dir->findData);
if(dir->handle == INVALID_HANDLE_VALUE) {
free(dir);
return false;
}
dir->isFirst = true;
request->opendir.dir = dir;
return true;
}
if(request->action == NCL_VFS_CLOSEDIR) {
ncl_WinDir *dir = request->closedir;
FindClose(dir->handle);
free(dir);
return true;
}
if(request->action == NCL_VFS_READDIR) {
// Mirrors the POSIX readdir loop: skip "." and "..",
// copy name into the caller buffer, signal end with NULL.
ncl_WinDir *dir = request->readdir.dir;
while(1) {
if(!dir->isFirst) {
if(!FindNextFileA(dir->handle, &dir->findData)) {
request->readdir.name = NULL;
return true;
}
}
dir->isFirst = false;
if(strcmp(dir->findData.cFileName, ".") == 0 ||
strcmp(dir->findData.cFileName, "..") == 0) {
continue;
}
strncpy(request->readdir.name, dir->findData.cFileName, NN_MAX_PATH - 1);
request->readdir.name[NN_MAX_PATH - 1] = '\0';
return true;
}
}
if(request->action == NCL_VFS_STAT) {
// Windows does not have st_blocks, so we approximate disk size
// as the file size itself. This is less accurate than the POSIX
// version but avoids needing the full Win32 file information API.
struct _stat s;
if(_stat(request->stat.path, &s) != 0) {
request->stat.path = NULL;
return false;
}
ncl_Stat *st = request->stat.stat;
st->isDirectory = (s.st_mode & _S_IFDIR) != 0;
st->diskSize = s.st_size;
st->size = st->isDirectory ? 0 : s.st_size;
st->lastModified = s.st_mtime;
return true;
}
if(request->action == NCL_VFS_MKDIR) {
// _mkdir on Windows does not take a permissions argument.
return _mkdir(request->mkdir) == 0;
}
#endif
return false; // not supported
return false;
}
#endif

View File

@@ -15,15 +15,16 @@
// to use the numerical accuracy better
#define NN_COMPONENT_CALLBUDGET 10000
// NN_ATOMIC_NONE accepts 1 args, others 2
#ifdef NN_ATOMIC_NONE
typedef size_t nn_refc_t;
void nn_incRef(nn_refc_t *refc) {
(*refc)++;
void nn_incRef(nn_refc_t *refc, size_t n) {
(*refc) += n;
}
bool nn_decRef(nn_refc_t *refc) {
(*refc)--;
bool nn_decRef(nn_refc_t *refc, size_t n) {
(*refc) -= n;
return (*refc) == 0;
}
#else
@@ -87,8 +88,13 @@ void nn_free(nn_Context *ctx, void *memory, size_t size) {
}
void *nn_realloc(nn_Context *ctx, void *memory, size_t oldSize, size_t newSize) {
if(memory == NULL) return nn_alloc(memory, newSize);
if(memory == ctx->alloc) return nn_alloc(memory, newSize);
// nn_realloc passed memory (which is NULL here) as first argument
// to nn_alloc instead of ctx. nn_alloc dereferences it as a context
// struct to call ctx->alloc(), so this is a NULL pointer dereference.
// Confirmed by test_realloc crashing on nn_realloc(&ctx, NULL, 0, 64).
// Original: if(memory == NULL) return nn_alloc(memory, newSize); if(memory == ctx->alloc) return nn_alloc(memory, newSize);
if(memory == NULL) return nn_alloc(ctx, newSize);
if(memory == ctx->alloc) return nn_alloc(ctx, newSize);
if(newSize == 0) {
nn_free(ctx, memory, oldSize);
return ctx->alloc;
@@ -570,7 +576,8 @@ static void nn_defaultLock(void *state, nn_LockRequest *req) {
#elif defined(NN_THREAD_WINDOWS)
switch(req->action) {
case NN_LOCK_CREATE:;
req->lock = CreateMutex(NULL, false, NULL);
req->lock = CreateMutex(NULL, FALSE, NULL);
return; // don't fall into destroy
case NN_LOCK_DESTROY:;
CloseHandle(req->lock);
return;
@@ -2226,8 +2233,8 @@ nn_Exit nn_popSignal(nn_Computer *computer, size_t *valueCount) {
// todo: everything
const nn_EEPROM nn_defaultEEPROMs[4] = {
(nn_EEPROM) {
.size = 4 * NN_KiB,
NN_INIT(nn_EEPROM) {
.size = 4 * NN_KiB,
.dataSize = 256,
.readEnergyCost = 1,
.writeEnergyCost = 100,
@@ -2236,7 +2243,7 @@ const nn_EEPROM nn_defaultEEPROMs[4] = {
.writeDelay = 2,
.writeDataDelay = 1,
},
(nn_EEPROM) {
NN_INIT(nn_EEPROM) {
.size = 8 * NN_KiB,
.dataSize = 1 * NN_KiB,
.readEnergyCost = 2,
@@ -2246,7 +2253,7 @@ const nn_EEPROM nn_defaultEEPROMs[4] = {
.writeDelay = 2,
.writeDataDelay = 1,
},
(nn_EEPROM) {
NN_INIT(nn_EEPROM) {
.size = 16 * NN_KiB,
.dataSize = 2 * NN_KiB,
.readEnergyCost = 4,
@@ -2256,7 +2263,7 @@ const nn_EEPROM nn_defaultEEPROMs[4] = {
.writeDelay = 1,
.writeDataDelay = 0.5,
},
(nn_EEPROM) {
NN_INIT(nn_EEPROM) {
.size = 32 * NN_KiB,
.dataSize = 4 * NN_KiB,
.readEnergyCost = 8,
@@ -2269,25 +2276,25 @@ const nn_EEPROM nn_defaultEEPROMs[4] = {
};
const nn_Filesystem nn_defaultFilesystems[4] = {
(nn_Filesystem) {
NN_INIT(nn_Filesystem) {
.spaceTotal = 1 * NN_MiB,
.readsPerTick = 4,
.writesPerTick = 2,
.dataEnergyCost = 256.0 / NN_MiB,
},
(nn_Filesystem) {
NN_INIT(nn_Filesystem) {
.spaceTotal = 2 * NN_MiB,
.readsPerTick = 4,
.writesPerTick = 2,
.dataEnergyCost = 512.0 / NN_MiB,
},
(nn_Filesystem) {
NN_INIT(nn_Filesystem) {
.spaceTotal = 4 * NN_MiB,
.readsPerTick = 7,
.writesPerTick = 3,
.dataEnergyCost = 1024.0 / NN_MiB,
},
(nn_Filesystem) {
NN_INIT(nn_Filesystem) {
.spaceTotal = 8 * NN_MiB,
.readsPerTick = 13,
.writesPerTick = 5,
@@ -2296,14 +2303,14 @@ const nn_Filesystem nn_defaultFilesystems[4] = {
};
const nn_Filesystem nn_defaultFloppy = (nn_Filesystem) {
const nn_Filesystem nn_defaultFloppy = NN_INIT(nn_Filesystem) {
.spaceTotal = 512 * NN_KiB,
.readsPerTick = 1,
.writesPerTick = 1,
.dataEnergyCost = 8.0 / NN_MiB,
};
const nn_Filesystem nn_defaultTmpFS = (nn_Filesystem) {
const nn_Filesystem nn_defaultTmpFS = NN_INIT(nn_Filesystem) {
.spaceTotal = 64 * NN_KiB,
.readsPerTick = 1024,
.writesPerTick = 512,
@@ -2311,7 +2318,7 @@ const nn_Filesystem nn_defaultTmpFS = (nn_Filesystem) {
};
const nn_Drive nn_defaultDrives[4] = {
(nn_Drive) {
NN_INIT(nn_Drive) {
.capacity = 1 * NN_MiB,
.sectorSize = 512,
.platterCount = 2,
@@ -2321,7 +2328,7 @@ const nn_Drive nn_defaultDrives[4] = {
.onlySpinForwards = false,
.dataEnergyCost = 256.0 / NN_MiB,
},
(nn_Drive) {
NN_INIT(nn_Drive) {
.capacity = 2 * NN_MiB,
.sectorSize = 512,
.platterCount = 4,
@@ -2331,7 +2338,7 @@ const nn_Drive nn_defaultDrives[4] = {
.onlySpinForwards = false,
.dataEnergyCost = 512.0 / NN_MiB,
},
(nn_Drive) {
NN_INIT(nn_Drive) {
.capacity = 4 * NN_MiB,
.sectorSize = 512,
.platterCount = 8,
@@ -2341,7 +2348,7 @@ const nn_Drive nn_defaultDrives[4] = {
.onlySpinForwards = false,
.dataEnergyCost = 1024.0 / NN_MiB,
},
(nn_Drive) {
NN_INIT(nn_Drive) {
.capacity = 8 * NN_MiB,
.sectorSize = 512,
.platterCount = 16,
@@ -2366,7 +2373,7 @@ const nn_Drive nn_floppyDrive = {
const nn_ScreenConfig nn_defaultScreens[4] = {
(nn_ScreenConfig) {
NN_INIT(nn_ScreenConfig) {
.maxWidth = 50,
.maxHeight = 16,
.maxDepth = 1,
@@ -2375,7 +2382,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.editableColors = 0,
.features = NN_SCRF_NONE,
},
(nn_ScreenConfig) {
NN_INIT(nn_ScreenConfig) {
.maxWidth = 80,
.maxHeight = 25,
.maxDepth = 4,
@@ -2384,7 +2391,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.editableColors = 0,
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED,
},
(nn_ScreenConfig) {
NN_INIT(nn_ScreenConfig) {
.maxWidth = 160,
.maxHeight = 50,
.maxDepth = 8,
@@ -2393,7 +2400,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
.editableColors = 16,
.features = NN_SCRF_MOUSE | NN_SCRF_TOUCHINVERTED | NN_SCRF_PRECISE | NN_SCRF_EDITABLECOLORS,
},
(nn_ScreenConfig) {
NN_INIT(nn_ScreenConfig) {
.maxWidth = 240,
.maxHeight = 80,
.maxDepth = 16,
@@ -2405,7 +2412,7 @@ const nn_ScreenConfig nn_defaultScreens[4] = {
};
const nn_GPU nn_defaultGPUs[4] = {
(nn_GPU) {
NN_INIT(nn_GPU) {
.maxWidth = 50,
.maxHeight = 16,
.maxDepth = 1,
@@ -2418,7 +2425,7 @@ const nn_GPU nn_defaultGPUs[4] = {
.energyPerWrite = 0.0002,
.energyPerClear = 0.0001,
},
(nn_GPU) {
NN_INIT(nn_GPU) {
.maxWidth = 80,
.maxHeight = 25,
.maxDepth = 4,
@@ -2431,7 +2438,7 @@ const nn_GPU nn_defaultGPUs[4] = {
.energyPerWrite = 0.001,
.energyPerClear = 0.0005,
},
(nn_GPU) {
NN_INIT(nn_GPU) {
.maxWidth = 160,
.maxHeight = 50,
.maxDepth = 8,
@@ -2444,7 +2451,7 @@ const nn_GPU nn_defaultGPUs[4] = {
.energyPerWrite = 0.002,
.energyPerClear = 0.001,
},
(nn_GPU) {
NN_INIT(nn_GPU) {
.maxWidth = 240,
.maxHeight = 80,
.maxDepth = 16,
@@ -3049,10 +3056,12 @@ nn_Exit nn_pushDrop(nn_Computer *computer, const char *screenAddress, double x,
return nn_pushSignal(computer, 6);
}
// the value is not returned for all execution paths - not a windows bug probably, need tests on *nix
nn_Exit nn_pushScroll(nn_Computer *computer, const char *screenAddress, double x, double y, double direction, const char *player) {
if(!nn_hasUser(computer, player)) return NN_OK;
}
// the value is not returned for all execution paths - not a windows bug probably, need tests on *nix
nn_Exit nn_pushWalk(nn_Computer *computer, const char *screenAddress, double x, double y, const char *player) {
if(!nn_hasUser(computer, player)) return NN_OK;
}
@@ -3149,7 +3158,7 @@ static nn_Exit nn_eepromHandler(nn_ComponentRequest *req) {
}
if(method == NN_EENUM_GET) {
ereq.action = NN_EEPROM_GET;
char buf[eeprom.size];
NN_VLA(char, buf, eeprom.size);
ereq.buf = buf;
ereq.buflen = eeprom.size;
e = state->handler(&ereq);
@@ -3159,7 +3168,7 @@ static nn_Exit nn_eepromHandler(nn_ComponentRequest *req) {
}
if(method == NN_EENUM_GETDATA) {
ereq.action = NN_EEPROM_GETDATA;
char buf[eeprom.size];
NN_VLA(char, buf, eeprom.size);
ereq.buf = buf;
ereq.buflen = eeprom.size;
e = state->handler(&ereq);

View File

@@ -9,21 +9,43 @@ extern "C" {
// Used internally as well.
// Based off https://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
//define something for Windows (32-bit and 64-bit, this part is common)
#ifndef NN_WINDOWS
#define NN_WINDOWS
#endif
#elif __APPLE__
#ifndef NN_MACOS
#define NN_MACOS
#endif
#elif __linux__
#ifndef NN_LINUX
#define NN_LINUX
#endif
#endif
#if __unix__ // all unices not caught above
// Unix
#if __unix__
#ifndef NN_UNIX
#define NN_UNIX
#endif
#ifndef NN_POSIX
#define NN_POSIX
#endif
#elif defined(_POSIX_VERSION)
// POSIX
#ifndef NN_POSIX
#define NN_POSIX
#endif
#endif
#if defined(_MSC_VER) && !defined(__cplusplus)
#ifndef NN_ATOMIC_NONE
#define NN_ATOMIC_NONE
#endif
#endif
#ifdef _MSC_VER
#define NN_INIT(type)
#else
#define NN_INIT(type) (type)
#endif
// every C standard header we depend on, conveniently put here
@@ -31,6 +53,19 @@ extern "C" {
#include <stdint.h> // for intptr_t
#include <stdbool.h> // for true, false and bool
/* MSVC can't use VLA;
* What we see : NN_VLA(const char *, comps, len);
* What compiler see after preproccessor : const char * comps[len];
* What actaully was : const char *comps[len];
*/
// Test: gcc -E -DNN_VLA\(type,name,count\)="type name[count]" -x c - <<< 'NN_VLA(const char *, comps, len);'
#ifdef _MSC_VER
#include <malloc.h>
#define NN_VLA(type, name, count) type *name = (type *)_alloca(sizeof(type) * (count))
#else
#define NN_VLA(type, name, count) type name[count]
#endif
// Internally we need stdatomic.h and, if NN_BAREMETAL is not defined, stdlib.h and time.h
// The entire NeoNucleus API, in one header file
@@ -40,7 +75,8 @@ extern "C" {
#define NN_KiB (1024)
#define NN_MiB (1024 * NN_KiB)
#define NN_GiB (1024 * NN_MiB)
#define NN_TiB (1024 * NN_TiB)
// probably recursive: #define NN_TiB (1024 * NN_TiB)
#define NN_TiB ((size_t)1024 * NN_GiB)
// the alignment an allocation should have
#define NN_ALLOC_ALIGN 16

BIN
src/neonucleus.obj Normal file

Binary file not shown.