Compare commits
38 Commits
edca903416
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f06a5659c | |||
| de13eeb85a | |||
| 7c086f6b8e | |||
| c58e57b7c7 | |||
| 3b04fd45c7 | |||
| b88fd280ea | |||
| b732f67b06 | |||
| 5c905e6f77 | |||
| 2275cbf47d | |||
| 79ea1c7f6f | |||
| 60b12ee507 | |||
| a6d7278735 | |||
| 810bf23942 | |||
| bcf0c06458 | |||
| f0f6a21fef | |||
| a41e53f98f | |||
| 172b7ce783 | |||
| 37faa466f3 | |||
| fbd91be56d | |||
| 461416362c | |||
| e4d342a36f | |||
| e7a166f85c | |||
| f832369ce0 | |||
| f9905d14fa | |||
| 754a04de3c | |||
| f13635fb5e | |||
| d739ddbd38 | |||
| 13ecbd3b26 | |||
| 7580bfddcb | |||
| 51bc2ad8e6 | |||
| ac79e6af35 | |||
| 862563b12f | |||
| 6834ef932b | |||
| 9b16a7b8e2 | |||
| 2ccd3a84b5 | |||
| fa0910d730 | |||
| 855fb71b4e | |||
| 63b7db4936 |
22
Makefile
22
Makefile
@@ -6,16 +6,23 @@ CC=cc
|
|||||||
LD=$(CC)
|
LD=$(CC)
|
||||||
AR=ar
|
AR=ar
|
||||||
RANLIB=ranlib
|
RANLIB=ranlib
|
||||||
|
WARN=-Wall -Werror -Wno-format-truncation
|
||||||
|
|
||||||
ifeq ($(MODE), release)
|
ifeq ($(MODE), release)
|
||||||
OPT=-Oz
|
OPT=-Oz
|
||||||
DEBUG=
|
DEBUG=
|
||||||
|
else ifeq ($(MODE), release-lto)
|
||||||
|
OPT=-Oz -flto
|
||||||
|
DEBUG=
|
||||||
else
|
else
|
||||||
OPT=-O0
|
OPT=-O0
|
||||||
SANITIZE=undefined,address
|
SANITIZE=undefined,address
|
||||||
DEBUG=-ggdb
|
DEBUG=-g
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
NN_STD=gnu99
|
||||||
|
EMU_STD=gnu23
|
||||||
|
|
||||||
NNFLAGS=
|
NNFLAGS=
|
||||||
|
|
||||||
SANITIZE_FLAGS=
|
SANITIZE_FLAGS=
|
||||||
@@ -24,7 +31,8 @@ ifdef SANITIZE
|
|||||||
SANITIZE_FLAGS += -fsanitize=$(SANITIZE)
|
SANITIZE_FLAGS += -fsanitize=$(SANITIZE)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS=-fPIC $(OPT) $(SANITIZE_FLAGS) $(DEBUG) $(NNFLAGS)
|
# no-omit-frame-pointer so if a crash does happen we can trace it
|
||||||
|
CFLAGS=-fPIC -fno-omit-frame-pointer $(OPT) $(SANITIZE_FLAGS) $(DEBUG) $(NNFLAGS) $(WARN)
|
||||||
|
|
||||||
LDFLAGS=$(OPT) $(DEBUG) $(SANITIZE_FLAGS)
|
LDFLAGS=$(OPT) $(DEBUG) $(SANITIZE_FLAGS)
|
||||||
|
|
||||||
@@ -40,21 +48,21 @@ SRC_DIR=src
|
|||||||
all: bin lib dynlib
|
all: bin lib dynlib
|
||||||
|
|
||||||
$(BUILD_DIR)/neonucleus.o: $(SRC_DIR)/neonucleus.c $(SRC_DIR)/neonucleus.h
|
$(BUILD_DIR)/neonucleus.o: $(SRC_DIR)/neonucleus.c $(SRC_DIR)/neonucleus.h
|
||||||
$(CC) -o $(BUILD_DIR)/neonucleus.o -c $(SRC_DIR)/neonucleus.c $(CFLAGS)
|
$(CC) -o $(BUILD_DIR)/neonucleus.o -c $(SRC_DIR)/neonucleus.c $(CFLAGS) -std=$(NN_STD)
|
||||||
|
|
||||||
$(BUILD_DIR)/ncomplib.o: $(SRC_DIR)/ncomplib.c $(SRC_DIR)/ncomplib.h
|
$(BUILD_DIR)/ncomplib.o: $(SRC_DIR)/ncomplib.c $(SRC_DIR)/ncomplib.h
|
||||||
$(CC) -o $(BUILD_DIR)/ncomplib.o -c $(SRC_DIR)/ncomplib.c $(CFLAGS)
|
$(CC) -o $(BUILD_DIR)/ncomplib.o -c $(SRC_DIR)/ncomplib.c $(CFLAGS) -std=$(NN_STD)
|
||||||
|
|
||||||
nn: $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o
|
nn: $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o
|
||||||
|
|
||||||
$(BUILD_DIR)/luaarch.o: $(SRC_DIR)/luaarch.c $(SRC_DIR)/machine.lua
|
$(BUILD_DIR)/luaarch.o: $(SRC_DIR)/luaarch.c $(SRC_DIR)/machine.lua
|
||||||
$(CC) -o $(BUILD_DIR)/luaarch.o -c $(SRC_DIR)/luaarch.c $(CFLAGS) $(INCLUA)
|
$(CC) -o $(BUILD_DIR)/luaarch.o -c $(SRC_DIR)/luaarch.c $(CFLAGS) $(INCLUA) -std=$(EMU_STD)
|
||||||
|
|
||||||
$(BUILD_DIR)/glyphcache.o: $(SRC_DIR)/glyphcache.c $(SRC_DIR)/glyphcache.h
|
$(BUILD_DIR)/glyphcache.o: $(SRC_DIR)/glyphcache.c $(SRC_DIR)/glyphcache.h
|
||||||
$(CC) -o $(BUILD_DIR)/glyphcache.o -c $(SRC_DIR)/glyphcache.c $(CFLAGS)
|
$(CC) -o $(BUILD_DIR)/glyphcache.o -c $(SRC_DIR)/glyphcache.c $(CFLAGS) -std=$(EMU_STD)
|
||||||
|
|
||||||
$(BUILD_DIR)/main.o: $(SRC_DIR)/main.c $(SRC_DIR)/minBIOS.lua
|
$(BUILD_DIR)/main.o: $(SRC_DIR)/main.c $(SRC_DIR)/minBIOS.lua
|
||||||
$(CC) -o $(BUILD_DIR)/main.o -c $(SRC_DIR)/main.c $(CFLAGS) $(INCLUA)
|
$(CC) -o $(BUILD_DIR)/main.o -c $(SRC_DIR)/main.c $(CFLAGS) $(INCLUA) -std=$(EMU_STD)
|
||||||
|
|
||||||
bin: nn $(BUILD_DIR)/main.o $(BUILD_DIR)/luaarch.o $(BUILD_DIR)/glyphcache.o
|
bin: nn $(BUILD_DIR)/main.o $(BUILD_DIR)/luaarch.o $(BUILD_DIR)/glyphcache.o
|
||||||
$(LD) $(LDFLAGS) -o $(BIN) $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o $(BUILD_DIR)/main.o $(BUILD_DIR)/glyphcache.o $(BUILD_DIR)/luaarch.o $(LINKLIBC) $(LINKLIBM) $(LINKRAYLIB) $(LINKLUA)
|
$(LD) $(LDFLAGS) -o $(BIN) $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o $(BUILD_DIR)/main.o $(BUILD_DIR)/glyphcache.o $(BUILD_DIR)/luaarch.o $(LINKLIBC) $(LINKLIBM) $(LINKRAYLIB) $(LINKLUA)
|
||||||
|
|||||||
45
TODO.md
45
TODO.md
@@ -1,29 +1,11 @@
|
|||||||
# For MVP functionality
|
|
||||||
|
|
||||||
- make `computer` component use callbacks
|
|
||||||
- finish tmpfs (rework the whole thing)
|
|
||||||
- userdata support
|
|
||||||
|
|
||||||
# To re-evaluate
|
|
||||||
|
|
||||||
- Exposing the internal non-resizing hashmap implementation.
|
|
||||||
- More stack manipulation functions to allow libraries to have better APIs. (rotate)
|
|
||||||
- Having a copy of the context stored directly in requests instead of having to use getComputerContext, as it simplifies the APIs and allows them
|
|
||||||
to be made more portable.
|
|
||||||
- Exposing more internal functions that may be useful to the user to prevent pointless rewriting and duplicate machine code.
|
|
||||||
|
|
||||||
# Vanilla components needed
|
# Vanilla components needed
|
||||||
|
|
||||||
Not everything OC has (as a few of them are really MC-centered) but most of it.
|
Not everything OC has (as a few of them are really MC-centered) but most of it.
|
||||||
|
|
||||||
- `data` component (note: deflate, sha256 and aes impl are callbacks, to keep NN small and simple)
|
- `computer` component
|
||||||
- `modem` component
|
|
||||||
- `tunnel` component
|
|
||||||
- `internet` component (note: NN does not handle internet requests, those are up to the emulator)
|
- `internet` component (note: NN does not handle internet requests, those are up to the emulator)
|
||||||
- `relay` component (note: OCDoc still refers to it as `access_point`)
|
- `relay` component (note: OCDoc still refers to it as `access_point`)
|
||||||
- `computer` component
|
|
||||||
- `geolyzer` component
|
- `geolyzer` component
|
||||||
- `net_splitter` component
|
|
||||||
- `redstone` component
|
- `redstone` component
|
||||||
- `motion_sensor` component
|
- `motion_sensor` component
|
||||||
- `printer3d` component (note: maybe add signal for when printer completes?)
|
- `printer3d` component (note: maybe add signal for when printer completes?)
|
||||||
@@ -49,11 +31,11 @@ Not everything OC has (as a few of them are really MC-centered) but most of it.
|
|||||||
- `serial` component, for serial communications with other devices (see Serial)
|
- `serial` component, for serial communications with other devices (see Serial)
|
||||||
- `iron_noteblock` component
|
- `iron_noteblock` component
|
||||||
- `colorful_lamp` component
|
- `colorful_lamp` component
|
||||||
- OpenSolidState flash storage
|
|
||||||
|
|
||||||
# To make it good
|
# To make it good
|
||||||
|
|
||||||
- make more stuff const if it can be. Gotta help out the optimizer
|
- make more stuff const if it can be. Gotta help out the optimizer
|
||||||
|
- put a bunch of internal-only functions as fastcall
|
||||||
- write a bunch of unit tests to ensure the public API works correctly
|
- write a bunch of unit tests to ensure the public API works correctly
|
||||||
- ensure OOMs are recoverable
|
- ensure OOMs are recoverable
|
||||||
- do a hude audit for bugs at some point
|
- do a hude audit for bugs at some point
|
||||||
@@ -61,9 +43,11 @@ Not everything OC has (as a few of them are really MC-centered) but most of it.
|
|||||||
# To make it fast
|
# To make it fast
|
||||||
|
|
||||||
NOTE: we're mostly bottlenecked by the architecture (typically a Lua VM) and the intentional bottlenecking from call costs.
|
NOTE: we're mostly bottlenecked by the architecture (typically a Lua VM) and the intentional bottlenecking from call costs.
|
||||||
|
breaking changes are allowed but like try to avoid them.
|
||||||
|
|
||||||
- make signals use a circular buffer instead of a simple array
|
- make signals use a circular buffer instead of a simple array
|
||||||
- use more arenas if possible
|
- use more arenas if possible
|
||||||
|
- reduce pointer nesting, not only for simplicity, but so we spend less time reading from main memory
|
||||||
|
|
||||||
# Component extensions
|
# Component extensions
|
||||||
|
|
||||||
@@ -144,9 +128,9 @@ The `vt` component has:
|
|||||||
- `getColor(index: integer): integer`, to get a color
|
- `getColor(index: integer): integer`, to get a color
|
||||||
- `setColor(index: integer, color: integer): integer`, sets a color and returns the old one. Characters who's colors were table indexes would be updated
|
- `setColor(index: integer, color: integer): integer`, sets a color and returns the old one. Characters who's colors were table indexes would be updated
|
||||||
- `setForeground(color: integer, fromTable?: boolean)`, sets a foreground color, optionally as a table index
|
- `setForeground(color: integer, fromTable?: boolean)`, sets a foreground color, optionally as a table index
|
||||||
- `getForeground(): integer, integer?`, returns what the foreground color was, and the palette index if applicable
|
- `getForeground(): integer, integer?`, returns what the foreground color was, and the table index if applicable
|
||||||
- `setBackground(color: integer, fromTable?: boolean)`, sets a background color, optionally as a table index
|
- `setBackground(color: integer, fromTable?: boolean)`, sets a background color, optionally as a table index
|
||||||
- `getBackground(): integer, integer?`, returns what the background color was, and the palette index if applicable
|
- `getBackground(): integer, integer?`, returns what the background color was, and the table index if applicable
|
||||||
- `set(idx: integer, data: string): boolean`, to write to the screen's unicode buffer. While `data` is UTF-8, the buffer stores codepoints. Pretend
|
- `set(idx: integer, data: string): boolean`, to write to the screen's unicode buffer. While `data` is UTF-8, the buffer stores codepoints. Pretend
|
||||||
the terminal does an internal conversion from UTF-8 to UTF-32
|
the terminal does an internal conversion from UTF-8 to UTF-32
|
||||||
- `getColorOf(idx: integer): integer, integer, integer?, integer?`, to get the foreground color, background color, and palette indexes of a tile
|
- `getColorOf(idx: integer): integer, integer, integer?, integer?`, to get the foreground color, background color, and palette indexes of a tile
|
||||||
@@ -161,10 +145,11 @@ If `x` and `y` are 0-indexed, then `x + y * width` is the index in the buffer
|
|||||||
|
|
||||||
The `cd_drive` component has:
|
The `cd_drive` component has:
|
||||||
- `hasDisk(): boolean`, to check whether a disk is in the drive
|
- `hasDisk(): boolean`, to check whether a disk is in the drive
|
||||||
- `isReadonly(): boolean`, to check where the drive is read-only (often is)
|
- `isReadonly(): boolean`, to check whether the drive is read-only (often is)
|
||||||
- `isDiskErasable(): boolean`, to check whether the disk is erasable, which requires support from both the disk and the drive
|
- `isDiskErasable(): boolean`, to check whether the disk is erasable, which requires support from both the disk and the drive
|
||||||
|
- `getCapacity(): integer`, gets the capacity of the disk
|
||||||
- `tell(): integer`, current 0-indexed byte offset into the disk
|
- `tell(): integer`, current 0-indexed byte offset into the disk
|
||||||
- `seekTo(position: integer): boolean`, seek to a current 0-indexed byte offset in the disk
|
- `seekTo(position: integer): boolean`, seek to a 0-indexed byte offset in the disk
|
||||||
- `moveBy(delta: integer): boolean`, move the current position by some amount of bytes (+/-), can wrap around
|
- `moveBy(delta: integer): boolean`, move the current position by some amount of bytes (+/-), can wrap around
|
||||||
- `maxReadSize(): integer`, to return the maximum size of a read
|
- `maxReadSize(): integer`, to return the maximum size of a read
|
||||||
- `read(len: integer): string`, to read some data. Does wrap around
|
- `read(len: integer): string`, to read some data. Does wrap around
|
||||||
@@ -187,7 +172,9 @@ Tape has high capacity, CDs do not.
|
|||||||
|
|
||||||
### CDs vs unmanaged floppies
|
### CDs vs unmanaged floppies
|
||||||
|
|
||||||
CDs are slower for random reads as they have no cache.
|
CDs require special software support, while floppies appear as just smaller HDDs.
|
||||||
|
Unmanaged floppies are always erasable, while CDs may not be.
|
||||||
|
CDs are typically lower capacity.
|
||||||
|
|
||||||
## LED
|
## LED
|
||||||
|
|
||||||
@@ -227,3 +214,11 @@ TODO: interface
|
|||||||
## OLED/IPU
|
## OLED/IPU
|
||||||
|
|
||||||
TODO: interface
|
TODO: interface
|
||||||
|
|
||||||
|
# To re-evaluate
|
||||||
|
|
||||||
|
- Make the hashmap growing/shrinking to save on memory.
|
||||||
|
- Exposing the internal hashmap implementation.
|
||||||
|
- Having a copy of the context stored directly in requests instead of having to use getComputerContext, as it simplifies the APIs and allows them
|
||||||
|
to be made more portable.
|
||||||
|
- Exposing more internal functions that may be useful to the user to prevent pointless rewriting and duplicate machine code.
|
||||||
|
|||||||
11
build.zig
11
build.zig
@@ -17,10 +17,9 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module {
|
|||||||
.strip = if (opts.optimize == .Debug) false else true,
|
.strip = if (opts.optimize == .Debug) false else true,
|
||||||
.unwind_tables = if (opts.optimize == .Debug) null else .none,
|
.unwind_tables = if (opts.optimize == .Debug) null else .none,
|
||||||
.pic = true,
|
.pic = true,
|
||||||
.sanitize_c = if(strict) .full else null,
|
.sanitize_c = if (strict) .full else null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
dataMod.addCSourceFiles(.{
|
dataMod.addCSourceFiles(.{
|
||||||
.files = &[_][]const u8{
|
.files = &[_][]const u8{
|
||||||
"src/neonucleus.c",
|
"src/neonucleus.c",
|
||||||
@@ -62,7 +61,7 @@ fn compileRaylib(b: *std.Build, os: std.Target.Os.Tag, buildOpts: LibBuildOpts,
|
|||||||
|
|
||||||
// passing it breaks it for some reason?
|
// passing it breaks it for some reason?
|
||||||
// TODO: make it not break
|
// TODO: make it not break
|
||||||
const raylib = b.addSystemCommand(&.{ "zig", "build"});
|
const raylib = b.addSystemCommand(&.{ "zig", "build" });
|
||||||
raylib.setCwd(b.path("foreign/raylib/"));
|
raylib.setCwd(b.path("foreign/raylib/"));
|
||||||
raylib.stdio = .inherit;
|
raylib.stdio = .inherit;
|
||||||
|
|
||||||
@@ -89,11 +88,7 @@ fn compileTheRightLua(b: *std.Build, target: std.Build.ResolvedTarget, version:
|
|||||||
// its a static library because COFF is a pile of shit
|
// its a static library because COFF is a pile of shit
|
||||||
const c = b.addLibrary(.{
|
const c = b.addLibrary(.{
|
||||||
.name = "lua",
|
.name = "lua",
|
||||||
.root_module = b.addModule("luamod", .{
|
.root_module = b.addModule("luamod", .{ .link_libc = true, .optimize = .ReleaseFast, .target = target, .pic = true }),
|
||||||
.link_libc = true,
|
|
||||||
.optimize = .ReleaseFast,
|
|
||||||
.target = target,
|
|
||||||
}),
|
|
||||||
.linkage = .static,
|
.linkage = .static,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
127
src/luaarch.c
127
src/luaarch.c
@@ -73,6 +73,9 @@ static nn_Exit luaArch_luaToNN(luaArch *arch, lua_State *L, int luaIdx) {
|
|||||||
if(lua_isboolean(L, luaIdx)) {
|
if(lua_isboolean(L, luaIdx)) {
|
||||||
return nn_pushbool(C, lua_toboolean(L, luaIdx));
|
return nn_pushbool(C, lua_toboolean(L, luaIdx));
|
||||||
}
|
}
|
||||||
|
if(lua_isuserdata(L, luaIdx)) {
|
||||||
|
return nn_pushuserdata(C, (size_t)lua_touserdata(L, luaIdx));
|
||||||
|
}
|
||||||
luaL_error(L, "bad Lua value: %s", luaL_typename(L, luaIdx));
|
luaL_error(L, "bad Lua value: %s", luaL_typename(L, luaIdx));
|
||||||
return NN_EBADSTATE;
|
return NN_EBADSTATE;
|
||||||
}
|
}
|
||||||
@@ -112,11 +115,36 @@ static void luaArch_nnToLua(luaArch *arch, lua_State *L, size_t nnIdx) {
|
|||||||
nn_popn(C, len * 2);
|
nn_popn(C, len * 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(nn_isuserdata(C, nnIdx)) {
|
||||||
|
lua_pushlightuserdata(L, (void *)nn_touserdata(C, nnIdx));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
luaL_error(L, "bad NN value: %s", nn_typenameof(C, nnIdx));
|
luaL_error(L, "bad NN value: %s", nn_typenameof(C, nnIdx));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int luaArch_computer_beep(lua_State *L) {
|
static int luaArch_computer_beep(lua_State *L) {
|
||||||
|
if(lua_type(L, 1) == LUA_TSTRING) {
|
||||||
|
nn_MorseBeep beep = {.frequency = 1000, .beepDuration = 200, .volume = 1};
|
||||||
|
beep.pattern = lua_tostring(L, 1);
|
||||||
|
if(lua_isnumber(L, 2)) {
|
||||||
|
beep.frequency = lua_tonumber(L, 2);
|
||||||
|
}
|
||||||
|
if(lua_isnumber(L, 3)) {
|
||||||
|
beep.beepDuration = lua_tonumber(L, 3);
|
||||||
|
}
|
||||||
|
if(lua_isnumber(L, 4)) {
|
||||||
|
beep.volume = lua_tonumber(L, 4);
|
||||||
|
}
|
||||||
|
if(beep.frequency < 20) beep.frequency = 20;
|
||||||
|
if(beep.beepDuration < 0) beep.beepDuration = 0;
|
||||||
|
if(beep.volume < 0) beep.volume = 0;
|
||||||
|
if(beep.frequency > 20000) beep.frequency = 20000;
|
||||||
|
if(beep.beepDuration > 5) beep.beepDuration = 5;
|
||||||
|
if(beep.volume > 1) beep.volume = 1;
|
||||||
|
nn_beepComputerMorse(luaArch_from(L)->computer, beep);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
nn_Beep beep = {.frequency = 1000, .duration = 1, .volume = 1};
|
nn_Beep beep = {.frequency = 1000, .duration = 1, .volume = 1};
|
||||||
if(lua_isnumber(L, 1)) {
|
if(lua_isnumber(L, 1)) {
|
||||||
beep.frequency = lua_tonumber(L, 1);
|
beep.frequency = lua_tonumber(L, 1);
|
||||||
@@ -593,6 +621,84 @@ static int luaArch_unicode_wtrunc(lua_State *L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int luaArch_userdata_free(lua_State *L) {
|
||||||
|
luaArch *arch = luaArch_from(L);
|
||||||
|
size_t user = (size_t)lua_touserdata(L, 1);
|
||||||
|
nn_freeUserdata(arch->computer, user);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int luaArch_userdata_methods(lua_State *L) {
|
||||||
|
luaArch *arch = luaArch_from(L);
|
||||||
|
size_t user = (size_t)lua_touserdata(L, 1);
|
||||||
|
if(!nn_isUserdataValid(arch->computer, user)) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "no such userdata");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
lua_createtable(L, 0, 0);
|
||||||
|
size_t idx = 0;
|
||||||
|
while(true) {
|
||||||
|
nn_Method m;
|
||||||
|
if(nn_getUserdataMethod(arch->computer, user, idx, &m)) break;
|
||||||
|
idx++;
|
||||||
|
if(m.name == NULL) continue;
|
||||||
|
lua_pushstring(L, m.name);
|
||||||
|
lua_createtable(L, 0, 4);
|
||||||
|
|
||||||
|
// the method data
|
||||||
|
{
|
||||||
|
lua_pushstring(L, "doc");
|
||||||
|
if(m.doc == NULL) lua_pushnil(L); else lua_pushstring(L, m.doc);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "direct");
|
||||||
|
lua_pushboolean(L, (m.flags & NN_DIRECT) != 0);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "getter");
|
||||||
|
lua_pushboolean(L, (m.flags & NN_GETTER) != 0);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
|
||||||
|
lua_pushstring(L, "setter");
|
||||||
|
lua_pushboolean(L, (m.flags & NN_SETTER) != 0);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int luaArch_userdata_invoke(lua_State *L) {
|
||||||
|
luaArch *arch = luaArch_from(L);
|
||||||
|
size_t user = (size_t)lua_touserdata(L, 1);
|
||||||
|
if(!nn_isUserdataValid(arch->computer, user)) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, "no such userdata");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
const char *method = luaL_checkstring(L, 2);
|
||||||
|
size_t argc = lua_gettop(L);
|
||||||
|
|
||||||
|
nn_clearstack(arch->computer);
|
||||||
|
for(size_t i = 3; i <= argc; i++) {
|
||||||
|
luaArch_luaToNN(arch, L, i);
|
||||||
|
}
|
||||||
|
nn_Exit err = nn_invokeUserdata(arch->computer, user, method);
|
||||||
|
if(err != NN_OK) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
lua_pushstring(L, nn_getError(arch->computer));
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
size_t retc = nn_getstacksize(arch->computer);
|
||||||
|
for(size_t i = 0; i < retc; i++) {
|
||||||
|
luaArch_nnToLua(arch, L, i);
|
||||||
|
}
|
||||||
|
nn_clearstack(arch->computer);
|
||||||
|
return retc;
|
||||||
|
}
|
||||||
|
|
||||||
static void luaArch_loadEnv(lua_State *L) {
|
static void luaArch_loadEnv(lua_State *L) {
|
||||||
lua_createtable(L, 0, 10);
|
lua_createtable(L, 0, 10);
|
||||||
int computer = lua_gettop(L);
|
int computer = lua_gettop(L);
|
||||||
@@ -637,6 +743,7 @@ static void luaArch_loadEnv(lua_State *L) {
|
|||||||
lua_pushcfunction(L, luaArch_computer_getDeviceInfo);
|
lua_pushcfunction(L, luaArch_computer_getDeviceInfo);
|
||||||
lua_setfield(L, computer, "getDeviceInfo");
|
lua_setfield(L, computer, "getDeviceInfo");
|
||||||
lua_setglobal(L, "computer");
|
lua_setglobal(L, "computer");
|
||||||
|
|
||||||
lua_createtable(L, 0, 10);
|
lua_createtable(L, 0, 10);
|
||||||
int component = lua_gettop(L);
|
int component = lua_gettop(L);
|
||||||
lua_pushcfunction(L, luaArch_component_list);
|
lua_pushcfunction(L, luaArch_component_list);
|
||||||
@@ -656,6 +763,7 @@ static void luaArch_loadEnv(lua_State *L) {
|
|||||||
lua_pushcfunction(L, luaArch_component_fields);
|
lua_pushcfunction(L, luaArch_component_fields);
|
||||||
lua_setfield(L, component, "fields");
|
lua_setfield(L, component, "fields");
|
||||||
lua_setglobal(L, "component");
|
lua_setglobal(L, "component");
|
||||||
|
|
||||||
lua_createtable(L, 0, 10);
|
lua_createtable(L, 0, 10);
|
||||||
int unicode = lua_gettop(L);
|
int unicode = lua_gettop(L);
|
||||||
lua_pushcfunction(L, luaArch_unicode_char);
|
lua_pushcfunction(L, luaArch_unicode_char);
|
||||||
@@ -664,11 +772,21 @@ static void luaArch_loadEnv(lua_State *L) {
|
|||||||
lua_setfield(L, unicode, "len");
|
lua_setfield(L, unicode, "len");
|
||||||
lua_pushcfunction(L, luaArch_unicode_sub);
|
lua_pushcfunction(L, luaArch_unicode_sub);
|
||||||
lua_setfield(L, unicode, "sub");
|
lua_setfield(L, unicode, "sub");
|
||||||
lua_pushcfunction(L, luaArch_unicode_len);
|
lua_pushcfunction(L, luaArch_unicode_wlen);
|
||||||
lua_setfield(L, unicode, "wlen");
|
lua_setfield(L, unicode, "wlen");
|
||||||
lua_pushcfunction(L, luaArch_unicode_wtrunc);
|
lua_pushcfunction(L, luaArch_unicode_wtrunc);
|
||||||
lua_setfield(L, unicode, "wtrunc");
|
lua_setfield(L, unicode, "wtrunc");
|
||||||
lua_setglobal(L, "unicode");
|
lua_setglobal(L, "unicode");
|
||||||
|
|
||||||
|
lua_createtable(L, 0, 10);
|
||||||
|
int userdata = lua_gettop(L);
|
||||||
|
lua_pushcfunction(L, luaArch_userdata_free);
|
||||||
|
lua_setfield(L, userdata, "free");
|
||||||
|
lua_pushcfunction(L, luaArch_userdata_methods);
|
||||||
|
lua_setfield(L, userdata, "methods");
|
||||||
|
lua_pushcfunction(L, luaArch_userdata_invoke);
|
||||||
|
lua_setfield(L, userdata, "invoke");
|
||||||
|
lua_setglobal(L, "userdata");
|
||||||
}
|
}
|
||||||
|
|
||||||
static nn_Exit luaArch_handler(nn_ArchitectureRequest *req) {
|
static nn_Exit luaArch_handler(nn_ArchitectureRequest *req) {
|
||||||
@@ -734,8 +852,11 @@ static nn_Exit luaArch_handler(nn_ArchitectureRequest *req) {
|
|||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
default:
|
case NN_ARCH_SERIALIZE:
|
||||||
break;
|
return nn_pushstring(computer, "lua stuff");
|
||||||
|
case NN_ARCH_DESERIALIZE:
|
||||||
|
// do nothing
|
||||||
|
return NN_OK;
|
||||||
}
|
}
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,19 +70,79 @@ end
|
|||||||
|
|
||||||
local syncedMethodStats
|
local syncedMethodStats
|
||||||
|
|
||||||
|
local function unsandboxValue(val)
|
||||||
|
if type(val) == "table" then
|
||||||
|
local meta = getmetatable(val)
|
||||||
|
if meta then
|
||||||
|
if type(meta.__userdata) == "userdata" then
|
||||||
|
return meta.__userdata
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local nt = {}
|
||||||
|
for sk, sv in pairs(val) do
|
||||||
|
local k, v = unsandboxValue(sk), unsandboxValue(sv)
|
||||||
|
if k ~= nil then nt[k] = v end
|
||||||
|
end
|
||||||
|
return nt
|
||||||
|
end
|
||||||
|
return val
|
||||||
|
end
|
||||||
|
|
||||||
|
local function sandboxValue(val)
|
||||||
|
if type(val) == "table" then
|
||||||
|
local nt = {}
|
||||||
|
for k, v in pairs(val) do
|
||||||
|
local sk, sv = sandboxValue(k), sandboxValue(v)
|
||||||
|
if sk ~= nil then nt[sk] = sv end
|
||||||
|
end
|
||||||
|
return nt
|
||||||
|
end
|
||||||
|
if type(val) == "userdata" then
|
||||||
|
-- This matches how OC wraps it
|
||||||
|
-- TODO: just make our own shi with fields and stuff
|
||||||
|
-- like a component proxy, because this sucks
|
||||||
|
local userMeta = {
|
||||||
|
__gc = function()
|
||||||
|
userdata.free(val)
|
||||||
|
end,
|
||||||
|
__userdata = val,
|
||||||
|
}
|
||||||
|
|
||||||
|
local wrapped = {type = "userdata", userdata = val}
|
||||||
|
for name, m in pairs(userdata.methods(val)) do
|
||||||
|
wrapped[name] = {
|
||||||
|
name = name,
|
||||||
|
proxy = wrapped,
|
||||||
|
}
|
||||||
|
setmetatable(wrapped[name], {
|
||||||
|
__tostring = function() return m.doc or "function" end,
|
||||||
|
__call = function(_, ...)
|
||||||
|
return userdata.invoke(val, name, ...)
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
return setmetatable(wrapped, userMeta)
|
||||||
|
end
|
||||||
|
return val
|
||||||
|
end
|
||||||
|
|
||||||
local function realInvoke(address, method, ...)
|
local function realInvoke(address, method, ...)
|
||||||
local t = {pcall(cinvoke, address, method, ...)}
|
local args = {...}
|
||||||
|
for i=1,#args do args[i] = unsandboxValue(args[i]) end
|
||||||
|
local t = {pcall(cinvoke, address, method, table.unpack(args))}
|
||||||
if not _SYNCED and not os.getenv("NN_FAST") then
|
if not _SYNCED and not os.getenv("NN_FAST") then
|
||||||
if computer.energy() <= 0 then sysyield() end -- out of power
|
if computer.energy() <= 0 then sysyield() end -- out of power
|
||||||
if computer.isOverused() then sysyield() end -- overused
|
if computer.isOverused() then sysyield() end -- overused
|
||||||
if computer.isIdle() then sysyield() end -- machine idle
|
if computer.isIdle() then sysyield() end -- machine idle
|
||||||
end
|
end
|
||||||
|
|
||||||
if os.getenv("NN_INVDBG") and component.type(address) == os.getenv("NN_INVDBG") then
|
if component.type(address) == os.getenv("NN_INVDBG") or string.find(os.getenv("NN_METDBG") or "", method, nil, true) then
|
||||||
print("invoked", address, method, ...)
|
print("invoked", address, method, ...)
|
||||||
print("got", table.unpack(t))
|
print(string.format("got %d values", #t), table.unpack(t))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
for i=1,#t do t[i] = sandboxValue(t[i]) end
|
||||||
|
|
||||||
if t[1] then
|
if t[1] then
|
||||||
return table.unpack(t, 2)
|
return table.unpack(t, 2)
|
||||||
end
|
end
|
||||||
@@ -192,6 +252,7 @@ function computer.pullSignal(timeout)
|
|||||||
while true do
|
while true do
|
||||||
if computer.uptime() >= deadline then return end
|
if computer.uptime() >= deadline then return end
|
||||||
local t = {computer.popSignal()}
|
local t = {computer.popSignal()}
|
||||||
|
for i=1,#t do t[i] = unsandboxValue(t[i]) end
|
||||||
if #t == 0 then
|
if #t == 0 then
|
||||||
sysyield()
|
sysyield()
|
||||||
else
|
else
|
||||||
@@ -426,7 +487,18 @@ sandbox = {
|
|||||||
isRobot = computer.isRobot,
|
isRobot = computer.isRobot,
|
||||||
maxEnergy = computer.maxEnergy,
|
maxEnergy = computer.maxEnergy,
|
||||||
pullSignal = computer.pullSignal,
|
pullSignal = computer.pullSignal,
|
||||||
pushSignal = computer.pushSignal,
|
pushSignal = function(name, ...)
|
||||||
|
checkArg(1, name, "string")
|
||||||
|
local t = {...}
|
||||||
|
for i=1,#t do
|
||||||
|
local v = unsandboxValue(t[i])
|
||||||
|
if type(v) == "userdata" then
|
||||||
|
return nil, "userdata is forbidden"
|
||||||
|
end
|
||||||
|
t[i] = v
|
||||||
|
end
|
||||||
|
return computer.pushSignal(name, table.unpack(t))
|
||||||
|
end,
|
||||||
removeUser = computer.removeUser,
|
removeUser = computer.removeUser,
|
||||||
setArchitecture = computer.setArchitecture,
|
setArchitecture = computer.setArchitecture,
|
||||||
shutdown = computer.shutdown,
|
shutdown = computer.shutdown,
|
||||||
|
|||||||
221
src/main.c
221
src/main.c
@@ -42,7 +42,7 @@ static nn_Exit sandbox_handler(nn_ComponentRequest *req) {
|
|||||||
return NN_OK;
|
return NN_OK;
|
||||||
case NN_COMP_DROP:
|
case NN_COMP_DROP:
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
case NN_COMP_SIGNAL:
|
case NN_COMP_USERDATA:
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
@@ -104,10 +104,17 @@ static nn_Exit ne_dataBullshit(nn_DataCardRequest *req) {
|
|||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
if(action == NN_DATA_SHA256) {
|
if(action == NN_DATA_SHA256) {
|
||||||
// does not match OC, dunno why
|
|
||||||
unsigned int *out = ComputeSHA256((unsigned char *)req->sha256.data, req->sha256.datalen);
|
unsigned int *out = ComputeSHA256((unsigned char *)req->sha256.data, req->sha256.datalen);
|
||||||
if(out == NULL) return NN_ENOMEM;
|
if(out == NULL) return NN_ENOMEM;
|
||||||
memcpy(req->sha256.checksum, out, 32);
|
unsigned char buf[32];
|
||||||
|
for(size_t i = 0; i < 8; i++) {
|
||||||
|
// OC does BE
|
||||||
|
buf[i*4+3] = (out[i] >> 0) & 0xFF;
|
||||||
|
buf[i*4+2] = (out[i] >> 8) & 0xFF;
|
||||||
|
buf[i*4+1] = (out[i] >> 16) & 0xFF;
|
||||||
|
buf[i*4+0] = (out[i] >> 24) & 0xFF;
|
||||||
|
}
|
||||||
|
memcpy(req->sha256.checksum, buf, 32);
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
if(action == NN_DATA_RANDOM) {
|
if(action == NN_DATA_RANDOM) {
|
||||||
@@ -123,6 +130,32 @@ static nn_Exit ne_dataBullshit(nn_DataCardRequest *req) {
|
|||||||
return nn_pushlstring(C, req->data, req->datalen);
|
return nn_pushlstring(C, req->data, req->datalen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(action == NN_DATA_VALIDATEKEY) {
|
||||||
|
// its valid, trust
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action == NN_DATA_GENKEYS) {
|
||||||
|
char a = 'A' + rand() % 26;
|
||||||
|
char b = 'A' + rand() % 26;
|
||||||
|
nn_pushlstring(C, &a, 1);
|
||||||
|
return nn_pushlstring(C, &b, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action == NN_DATA_ECDH) {
|
||||||
|
char buf[32];
|
||||||
|
memset(buf, 'e', 32);
|
||||||
|
return nn_pushlstring(C, buf, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action == NN_DATA_ECDSA_SIGN) {
|
||||||
|
return nn_pushstring(C, "epic signature bro");
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_ECDSA_VERIFY) {
|
||||||
|
req->checksig.sigpassed = strcmp(req->checksig.signature, "epic signature bro");
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if(C) nn_setError(C, "ne: data method not implemented");
|
if(C) nn_setError(C, "ne: data method not implemented");
|
||||||
return NN_EBADCALL;
|
return NN_EBADCALL;
|
||||||
}
|
}
|
||||||
@@ -133,9 +166,81 @@ static nn_Exit ne_modemBullshit(nn_ModemRequest *req) {
|
|||||||
if(req->action == NN_MODEM_DROP) {
|
if(req->action == NN_MODEM_DROP) {
|
||||||
return NN_OK;
|
return NN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_MODEM_ISOPEN) {
|
||||||
|
int port = req->isOpen.port;
|
||||||
|
req->isOpen.opened = port >= 1 && port <= 3;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_MODEM_OPEN) {
|
||||||
|
printf("pretend we opened port %zu\n", req->openPort);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_MODEM_CLOSE) {
|
||||||
|
printf("pretend we closed ");
|
||||||
|
if(req->closePort == NN_CLOSEPORTS) {
|
||||||
|
printf("all ports\n");
|
||||||
|
} else {
|
||||||
|
printf("port %zu\n", req->closePort);
|
||||||
|
}
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(req->action == NN_MODEM_GETPORTS) {
|
||||||
|
// lies
|
||||||
|
req->getPorts.len = 3;
|
||||||
|
req->getPorts.activePorts[0] = 1;
|
||||||
|
req->getPorts.activePorts[1] = 2;
|
||||||
|
req->getPorts.activePorts[2] = 3;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if(req->action == NN_MODEM_SEND) {
|
if(req->action == NN_MODEM_SEND) {
|
||||||
printf("Transmission from %s to %s (port %zu) of %zu bytes (%zu values)\n", req->localAddress, req->send.address == NULL ? "*" : req->send.address, req->send.port, req->send.contents->buflen, req->send.contents->valueCount);
|
req->send.strengthSent = req->modem->maxRange;
|
||||||
return nn_pushModemMessage(C, req->localAddress, nn_getComputerAddress(C), req->send.port, 0, req->send.contents);
|
const char *dest = req->send.address == NULL ? "*" : req->send.address;
|
||||||
|
printf("Transmission from %s to %s (port %zu) of %zu bytes (%zu values)\n", req->localAddress, dest, req->send.port, req->send.contents->buflen, req->send.contents->valueCount);
|
||||||
|
return nn_pushModemMessage(C, req->localAddress, dest, req->send.port, 0, req->send.contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_MODEM_GETWAKEMESSAGE) {
|
||||||
|
req->getWake.len = 0;
|
||||||
|
req->getWake.isFuzzy = false;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_MODEM_SETWAKEMESSAGE) {
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(C) nn_setError(C, "ne: modem method not implemented");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static nn_Exit ne_tunnelBullshit(nn_TunnelRequest *req) {
|
||||||
|
nn_Computer *C = req->computer;
|
||||||
|
|
||||||
|
if(req->action == NN_TUNNEL_DROP) {
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_TUNNEL_GETCHANNEL) {
|
||||||
|
return nn_pushstring(C, "creative");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_TUNNEL_SEND) {
|
||||||
|
printf("Transmission from tunnel %s of %zu bytes (%zu values)\n", req->localAddress, req->toSend->buflen, req->toSend->valueCount);
|
||||||
|
return nn_pushModemMessage(C, req->localAddress, nn_getComputerAddress(C), NN_TUNNEL_PORT, 0, req->toSend);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_TUNNEL_GETWAKEMESSAGE) {
|
||||||
|
req->getWake.len = 0;
|
||||||
|
req->getWake.isFuzzy = false;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_TUNNEL_SETWAKEMESSAGE) {
|
||||||
|
return NN_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(C) nn_setError(C, "ne: modem method not implemented");
|
if(C) nn_setError(C, "ne: modem method not implemented");
|
||||||
@@ -395,6 +500,7 @@ typedef struct ne_memSand {
|
|||||||
char *buf;
|
char *buf;
|
||||||
size_t used;
|
size_t used;
|
||||||
size_t cap;
|
size_t cap;
|
||||||
|
size_t active;
|
||||||
} ne_memSand;
|
} ne_memSand;
|
||||||
|
|
||||||
void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize) {
|
void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize) {
|
||||||
@@ -404,12 +510,16 @@ void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize
|
|||||||
newSize = ne_alignAlloc(newSize, NN_ALLOC_ALIGN);
|
newSize = ne_alignAlloc(newSize, NN_ALLOC_ALIGN);
|
||||||
|
|
||||||
// never free
|
// never free
|
||||||
if(newSize == 0) return NULL;
|
if(newSize == 0) {
|
||||||
|
sand->active -= oldSize;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
if(memory == NULL) {
|
if(memory == NULL) {
|
||||||
if(sand->cap - sand->used < newSize) return NULL;
|
if(sand->cap - sand->used < newSize) return NULL;
|
||||||
// alloc new
|
// alloc new
|
||||||
void *mem = sand->buf + sand->used;
|
void *mem = sand->buf + sand->used;
|
||||||
sand->used += newSize;
|
sand->used += newSize;
|
||||||
|
sand->active += newSize;
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
// realloc
|
// realloc
|
||||||
@@ -417,12 +527,14 @@ void *ne_sandbox_alloc(void *state, void *memory, size_t oldSize, size_t newSize
|
|||||||
if(sand->cap - sand->used < newSize) return NULL;
|
if(sand->cap - sand->used < newSize) return NULL;
|
||||||
void *mem = sand->buf + sand->used;
|
void *mem = sand->buf + sand->used;
|
||||||
sand->used += newSize;
|
sand->used += newSize;
|
||||||
|
sand->active += newSize;
|
||||||
memcpy(mem, memory, oldSize);
|
memcpy(mem, memory, oldSize);
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
double accumulatedEnergyCost = 0;
|
double accumulatedEnergyCost = 0;
|
||||||
double totalEnergyLoss = 0;
|
double totalEnergyLoss = 0;
|
||||||
|
// default capacity of a tablet
|
||||||
double allEnergy = 10000;
|
double allEnergy = 10000;
|
||||||
|
|
||||||
void ne_env(nn_EnvironmentRequest *req) {
|
void ne_env(nn_EnvironmentRequest *req) {
|
||||||
@@ -430,6 +542,10 @@ void ne_env(nn_EnvironmentRequest *req) {
|
|||||||
printf("beep: %f Hz %fs %.02f%%\n", req->beep.frequency, req->beep.duration, req->beep.volume*100);
|
printf("beep: %f Hz %fs %.02f%%\n", req->beep.frequency, req->beep.duration, req->beep.volume*100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(req->action == NN_ENV_BEEPMORSE) {
|
||||||
|
printf("morse beep: %s, %f Hz %fs %.02f%%\n", req->morseBeep.pattern, req->morseBeep.frequency, req->morseBeep.beepDuration, req->morseBeep.volume*100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(req->action == NN_ENV_DRAWENERGY) {
|
if(req->action == NN_ENV_DRAWENERGY) {
|
||||||
accumulatedEnergyCost += req->energy;
|
accumulatedEnergyCost += req->energy;
|
||||||
totalEnergyLoss += req->energy;
|
totalEnergyLoss += req->energy;
|
||||||
@@ -440,6 +556,25 @@ void ne_env(nn_EnvironmentRequest *req) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nn_Exit ne_inetBullshit(nn_InternetRequest *req) {
|
||||||
|
// welcome to hell
|
||||||
|
nn_Computer *C = req->computer;
|
||||||
|
|
||||||
|
// TODO: make this shi connect to the real internet
|
||||||
|
// preferrably use libcurl, openssl and a basic blocking socket layer
|
||||||
|
|
||||||
|
if(req->action == NN_INTERNET_CONNECT) {
|
||||||
|
req->connection->state = ne_inetBullshit;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req->action == NN_INTERNET_CLOSE) {
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(C) nn_setError(C, "inet bullshit: not supported");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
const char *player = getenv("USER");
|
const char *player = getenv("USER");
|
||||||
@@ -460,6 +595,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
ne_memSand sand;
|
ne_memSand sand;
|
||||||
sand.buf = NULL;
|
sand.buf = NULL;
|
||||||
|
sand.active = 0;
|
||||||
|
|
||||||
if(sandboxMem) {
|
if(sandboxMem) {
|
||||||
// 1 MiB pre-allocated to prevent erasing the free-list
|
// 1 MiB pre-allocated to prevent erasing the free-list
|
||||||
@@ -473,6 +609,10 @@ int main(int argc, char **argv) {
|
|||||||
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
|
||||||
InitWindow(800, 600, "NeoNucleus Test Emulator");
|
InitWindow(800, 600, "NeoNucleus Test Emulator");
|
||||||
|
|
||||||
|
const char *tierStr = getenv("NN_TIER");
|
||||||
|
if(tierStr == NULL) tierStr = "4";
|
||||||
|
int tier = atoi(tierStr);
|
||||||
|
|
||||||
// create the universe
|
// create the universe
|
||||||
nn_Universe *u = nn_createUniverse(&ctx, NULL);
|
nn_Universe *u = nn_createUniverse(&ctx, NULL);
|
||||||
|
|
||||||
@@ -487,7 +627,9 @@ int main(int argc, char **argv) {
|
|||||||
nn_setComponentHandler(ocelotCard, sandbox_handler);
|
nn_setComponentHandler(ocelotCard, sandbox_handler);
|
||||||
|
|
||||||
nn_Component *dataCard = nn_createDataCard(u, NULL, &nn_defaultDataCards[2], NULL, ne_dataBullshit);
|
nn_Component *dataCard = nn_createDataCard(u, NULL, &nn_defaultDataCards[2], NULL, ne_dataBullshit);
|
||||||
nn_Component *modem = nn_createModem(u, NULL, &nn_defaultWiredModem, NULL, ne_modemBullshit);
|
nn_Component *modem = nn_createModem(u, NULL, &nn_defaultWirelessModems[1], NULL, ne_modemBullshit);
|
||||||
|
nn_Component *tunnel = nn_createTunnel(u, NULL, &nn_defaultTunnel, NULL, ne_tunnelBullshit);
|
||||||
|
nn_Component *inet = nn_createInternet(u, NULL, &nn_defaultInternetCard, NULL, ne_inetBullshit);
|
||||||
|
|
||||||
char *eepromCode = (char *)minBIOS;
|
char *eepromCode = (char *)minBIOS;
|
||||||
size_t eepromSize = strlen(minBIOS);
|
size_t eepromSize = strlen(minBIOS);
|
||||||
@@ -512,20 +654,12 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
nn_Component *eepromCard = ncl_createEEPROM(u, NULL, &nn_defaultEEPROMs[3], eepromCode, eepromSize, false);
|
nn_Component *eepromCard = ncl_createEEPROM(u, NULL, &nn_defaultEEPROMs[3], eepromCode, eepromSize, false);
|
||||||
|
|
||||||
nn_Filesystem mainfsconf;
|
|
||||||
nn_Filesystem fsparts[] = {
|
|
||||||
nn_defaultFilesystems[3],
|
|
||||||
nn_defaultFilesystems[3],
|
|
||||||
nn_defaultFilesystems[3],
|
|
||||||
};
|
|
||||||
nn_mergeFilesystems(&mainfsconf, fsparts, sizeof(fsparts) / sizeof(fsparts[0]));
|
|
||||||
|
|
||||||
char mainfspath[NN_MAX_PATH];
|
char mainfspath[NN_MAX_PATH];
|
||||||
snprintf(mainfspath, NN_MAX_PATH, "data/%s", mainDir);
|
snprintf(mainfspath, NN_MAX_PATH, "data/%s", mainDir);
|
||||||
nn_Component *managedfs = ncl_createFilesystem(u, NULL, mainfspath, &mainfsconf, true);
|
nn_Component *managedfs = ncl_createFilesystem(u, NULL, mainfspath, &nn_defaultFilesystems[tier-1], true);
|
||||||
//nn_Component *tmpfs = ncl_createTmpFS(u, NULL, &nn_defaultTmpFS, NCL_FILECOST_DEFAULT, false);
|
nn_Component *tmpfs = ncl_createTmpFS(u, NULL, &nn_defaultTmpFS, NCL_FILECOST_DEFAULT, false);
|
||||||
nn_Component *tmpfs = ncl_createFilesystem(u, NULL, "/tmp", &mainfsconf, false);
|
|
||||||
nn_Component *testingfs = ncl_createFilesystem(u, NULL, "aux", &nn_defaultFilesystems[3], false);
|
nn_Component *testingfs = ncl_createFilesystem(u, NULL, "aux", &nn_defaultFilesystems[3], false);
|
||||||
|
nn_Component *debugfs = ncl_createTmpFS(u, NULL, &nn_defaultFilesystems[3], NCL_FILECOST_DEFAULT, false);
|
||||||
|
|
||||||
const char * const testDriveData =
|
const char * const testDriveData =
|
||||||
"local g, s = component.list('gpu')(), component.list('screen')()\n"
|
"local g, s = component.list('gpu')(), component.list('screen')()\n"
|
||||||
@@ -552,18 +686,18 @@ int main(int argc, char **argv) {
|
|||||||
"while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n"
|
"while computer.uptime() < now + 3 do computer.pullSignal(0.05) end\n"
|
||||||
"computer.shutdown(true)\n"
|
"computer.shutdown(true)\n"
|
||||||
;
|
;
|
||||||
nn_Component *testDrive = ncl_createDrive(u, NULL, &nn_defaultDrives[3], testDriveData, strlen(testDriveData), false);
|
nn_Component *testDrive = ncl_createDrive(u, NULL, &nn_defaultDrives[tier-1], testDriveData, strlen(testDriveData), false);
|
||||||
nn_Component *testFlash = ncl_createFlash(u, NULL, &nn_defaultSSDs[3], testDriveData, strlen(testDriveData), false);
|
nn_Component *testFlash = ncl_createFlash(u, NULL, &nn_defaultSSDs[tier-1], testDriveData, strlen(testDriveData), false);
|
||||||
|
|
||||||
ncl_setCLabel(eepromCard, "EEPROM");
|
ncl_setCLabel(eepromCard, "EEPROM");
|
||||||
ncl_setCLabel(managedfs, "Main Filesystem");
|
ncl_setCLabel(managedfs, "Main Filesystem");
|
||||||
ncl_setCLabel(testingfs, "Secondary Filesystem");
|
ncl_setCLabel(testingfs, "Secondary Filesystem");
|
||||||
ncl_setCLabel(testDrive, "Unmanaged Storage");
|
ncl_setCLabel(testDrive, "Unmanaged Storage");
|
||||||
ncl_setCLabel(testFlash, "Flash Storage");
|
ncl_setCLabel(testFlash, "Flash Storage");
|
||||||
|
ncl_setCLabel(debugfs, "Debug Filesystem");
|
||||||
|
|
||||||
size_t ramTotal = 0;
|
size_t ramTotal = 0;
|
||||||
ramTotal += 4 * nn_ramSizes[5];
|
ramTotal += 4 * nn_ramSizes[tier*2-1];
|
||||||
//ramTotal += nn_ramSizes[0];
|
|
||||||
|
|
||||||
SetExitKey(KEY_NULL);
|
SetExitKey(KEY_NULL);
|
||||||
|
|
||||||
@@ -576,10 +710,6 @@ int main(int argc, char **argv) {
|
|||||||
if(getenv("NN_TICKDELAY") != NULL) {
|
if(getenv("NN_TICKDELAY") != NULL) {
|
||||||
tickDelay = atof(getenv("NN_TICKDELAY"));
|
tickDelay = atof(getenv("NN_TICKDELAY"));
|
||||||
}
|
}
|
||||||
if(getenv("NN_FAST") != NULL) {
|
|
||||||
tickDelay = 0;
|
|
||||||
noIdle = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct {int key; nn_codepoint unicode;} keybuf[512];
|
struct {int key; nn_codepoint unicode;} keybuf[512];
|
||||||
memset(keybuf, 0, sizeof(keybuf));
|
memset(keybuf, 0, sizeof(keybuf));
|
||||||
@@ -589,22 +719,30 @@ int main(int argc, char **argv) {
|
|||||||
double nextSecond = 0;
|
double nextSecond = 0;
|
||||||
double wattage = 0;
|
double wattage = 0;
|
||||||
|
|
||||||
nn_Component *screen = ncl_createScreen(u, NULL, &nn_defaultScreens[2]);
|
nn_Component *screen = ncl_createScreen(u, NULL, &nn_defaultScreens[tier-1]);
|
||||||
nn_Component *gpuCard = ncl_createGPU(u, NULL, &nn_defaultGPUs[2]);
|
nn_GPU gpuConf = nn_defaultGPUs[tier-1];
|
||||||
|
nn_Component *gpuCard = ncl_createGPU(u, NULL, &gpuConf);
|
||||||
nn_Component *keyboard = nn_createComponent(
|
nn_Component *keyboard = nn_createComponent(
|
||||||
u, "mainKB", "keyboard");
|
u, "mainKB", "keyboard");
|
||||||
|
|
||||||
ncl_ScreenState *scrstate = nn_getComponentState(screen);
|
ncl_ScreenState *scrstate = nn_getComponentState(screen);
|
||||||
ncl_mountKeyboard(scrstate, "mainKB");
|
ncl_mountKeyboard(scrstate, "mainKB");
|
||||||
|
|
||||||
nn_Computer *c = nn_createComputer(u, NULL, NULL, ramTotal, 256, 256);
|
// we assume server basically
|
||||||
|
nn_Computer * volatile c = nn_createComputer(u, NULL, NULL, ramTotal, nn_defaultComponentLimits[tier-1] * 4, 256);
|
||||||
nn_Environment cEnv = {
|
nn_Environment cEnv = {
|
||||||
.userdata = NULL,
|
.userdata = NULL,
|
||||||
.handler = ne_env,
|
.handler = ne_env,
|
||||||
};
|
};
|
||||||
nn_setComputerEnvironment(c, cEnv);
|
nn_setComputerEnvironment(c, cEnv);
|
||||||
nn_setCallBudget(c, 0);
|
// 5 cuz CPU + each RAM stick all have same tier call budgets
|
||||||
|
nn_setCallBudget(c, nn_defaultCallBudgets[tier-1] * 5);
|
||||||
nn_setTotalEnergy(c, allEnergy);
|
nn_setTotalEnergy(c, allEnergy);
|
||||||
|
if(getenv("NN_FAST") != NULL) {
|
||||||
|
tickDelay = 0;
|
||||||
|
noIdle = true;
|
||||||
|
nn_setCallBudget(c, 0);
|
||||||
|
}
|
||||||
|
|
||||||
nn_setArchitecture(c, &arch);
|
nn_setArchitecture(c, &arch);
|
||||||
nn_addSupportedArchitecture(c, &arch);
|
nn_addSupportedArchitecture(c, &arch);
|
||||||
@@ -635,8 +773,12 @@ int main(int argc, char **argv) {
|
|||||||
nn_mountComponent(c, testFlash, 5, false);
|
nn_mountComponent(c, testFlash, 5, false);
|
||||||
nn_mountComponent(c, dataCard, 6, false);
|
nn_mountComponent(c, dataCard, 6, false);
|
||||||
nn_mountComponent(c, modem, 7, false);
|
nn_mountComponent(c, modem, 7, false);
|
||||||
|
nn_mountComponent(c, tunnel, 8, false);
|
||||||
|
nn_mountComponent(c, debugfs, 9, false);
|
||||||
|
nn_mountComponent(c, inet, 10, false);
|
||||||
int ltx = 0, lty = 0;
|
int ltx = 0, lty = 0;
|
||||||
double scrollBuf = 0;
|
double scrollBuf = 0;
|
||||||
|
double tickTime = 0;
|
||||||
SetTargetFPS(60);
|
SetTargetFPS(60);
|
||||||
while(true) {
|
while(true) {
|
||||||
if(WindowShouldClose()) break;
|
if(WindowShouldClose()) break;
|
||||||
@@ -741,6 +883,8 @@ int main(int argc, char **argv) {
|
|||||||
statY += 20;
|
statY += 20;
|
||||||
DrawText(TextFormat("VM mem usage: %.2f%%", memUsagePercent), 10, statY, 20, GREEN);
|
DrawText(TextFormat("VM mem usage: %.2f%%", memUsagePercent), 10, statY, 20, GREEN);
|
||||||
statY += 20;
|
statY += 20;
|
||||||
|
DrawText(TextFormat("Tick time: %.5fs", tickTime), 10, statY, 20, (tickTime < tickDelay || tickDelay == 0) ? GREEN : RED);
|
||||||
|
statY += 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
EndDrawing();
|
EndDrawing();
|
||||||
@@ -809,8 +953,17 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
if(noIdle) nn_resetIdleTime(c);
|
if(noIdle) nn_resetIdleTime(c);
|
||||||
// OC computers consume 0.5W when running, 0.05W when running but idle
|
// OC computers consume 0.5W when running, 0.05W when running but idle
|
||||||
nn_removeEnergy(c, nn_isComputerIdle(c) ? 0.05 : 0.5);
|
double normalPowerUsage = 0.5, idlePowerUsage = 0.05;
|
||||||
nn_Exit e = nn_tick(c);
|
nn_Exit e = nn_tick(c);
|
||||||
|
tickTime = GetTime() - tickNow;
|
||||||
|
if(tickTime < tickDelay) {
|
||||||
|
double working = tickTime / tickDelay;
|
||||||
|
nn_removeEnergy(c, normalPowerUsage * working + idlePowerUsage * (1 - working));
|
||||||
|
} else if(tickDelay == 0) {
|
||||||
|
nn_removeEnergy(c, normalPowerUsage);
|
||||||
|
} else {
|
||||||
|
nn_removeEnergy(c, normalPowerUsage * tickTime / tickDelay);
|
||||||
|
}
|
||||||
if(e != NN_OK) {
|
if(e != NN_OK) {
|
||||||
printf("error: %s\n", nn_getError(c));
|
printf("error: %s\n", nn_getError(c));
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -860,11 +1013,17 @@ cleanup:;
|
|||||||
nn_dropComponent(keyboard);
|
nn_dropComponent(keyboard);
|
||||||
nn_dropComponent(dataCard);
|
nn_dropComponent(dataCard);
|
||||||
nn_dropComponent(modem);
|
nn_dropComponent(modem);
|
||||||
|
nn_dropComponent(tunnel);
|
||||||
|
nn_dropComponent(debugfs);
|
||||||
|
nn_dropComponent(inet);
|
||||||
// rip the universe
|
// rip the universe
|
||||||
nn_destroyUniverse(u);
|
nn_destroyUniverse(u);
|
||||||
ncl_destroyGlyphCache(gc);
|
ncl_destroyGlyphCache(gc);
|
||||||
if(eepromPath != NULL) free(eepromCode);
|
if(eepromPath != NULL) free(eepromCode);
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
free(sand.buf);
|
free(sand.buf);
|
||||||
|
if(sand.buf != NULL) {
|
||||||
|
printf("Leaked: %zu bytes\n", sand.active);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
851
src/ncomplib.c
851
src/ncomplib.c
File diff suppressed because it is too large
Load Diff
@@ -258,35 +258,29 @@ typedef struct ncl_ComponentStat {
|
|||||||
// specific properties
|
// specific properties
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
const nn_EEPROM *conf;
|
|
||||||
size_t codeUsed;
|
size_t codeUsed;
|
||||||
size_t dataUsed;
|
size_t dataUsed;
|
||||||
} eeprom;
|
} eeprom;
|
||||||
struct {
|
struct {
|
||||||
const nn_Filesystem *conf;
|
|
||||||
size_t spaceUsed;
|
size_t spaceUsed;
|
||||||
size_t realDiskUsage;
|
size_t realDiskUsage;
|
||||||
size_t filesOpen;
|
size_t filesOpen;
|
||||||
const char *path;
|
const char *path;
|
||||||
} fs;
|
} fs;
|
||||||
struct {
|
struct {
|
||||||
const nn_Drive *conf;
|
|
||||||
size_t lastSector;
|
size_t lastSector;
|
||||||
} drive;
|
} drive;
|
||||||
struct {
|
struct {
|
||||||
const nn_NandFlash *conf;
|
|
||||||
size_t currentWriteCount;
|
size_t currentWriteCount;
|
||||||
double wearlevel;
|
double wearlevel;
|
||||||
} flash;
|
} flash;
|
||||||
struct {
|
struct {
|
||||||
const nn_GPU *conf;
|
|
||||||
size_t vramFree;
|
size_t vramFree;
|
||||||
size_t bufferCount;
|
size_t bufferCount;
|
||||||
// can be NULL if there is none
|
// can be NULL if there is none
|
||||||
const char *boundScreen;
|
const char *boundScreen;
|
||||||
} gpu;
|
} gpu;
|
||||||
struct {
|
struct {
|
||||||
const nn_ScreenConfig *conf;
|
|
||||||
ncl_ScreenState *state;
|
ncl_ScreenState *state;
|
||||||
ncl_ScreenFlags flags;
|
ncl_ScreenFlags flags;
|
||||||
int viewportWidth;
|
int viewportWidth;
|
||||||
@@ -333,6 +327,8 @@ void ncl_unlockScreen(ncl_ScreenState *state);
|
|||||||
void ncl_resetScreen(ncl_ScreenState *state);
|
void ncl_resetScreen(ncl_ScreenState *state);
|
||||||
void ncl_getScreenResolution(const ncl_ScreenState *state, size_t *width, size_t *height);
|
void ncl_getScreenResolution(const ncl_ScreenState *state, size_t *width, size_t *height);
|
||||||
void ncl_setScreenResolution(ncl_ScreenState *state, size_t width, size_t height);
|
void ncl_setScreenResolution(ncl_ScreenState *state, size_t width, size_t height);
|
||||||
|
void ncl_getScreenMaxResolution(const ncl_ScreenState *state, size_t *width, size_t *height);
|
||||||
|
nn_Exit ncl_setScreenMaxResolution(ncl_ScreenState *state, size_t width, size_t height);
|
||||||
void ncl_getScreenViewport(const ncl_ScreenState *state, size_t *width, size_t *height);
|
void ncl_getScreenViewport(const ncl_ScreenState *state, size_t *width, size_t *height);
|
||||||
void ncl_setScreenViewport(ncl_ScreenState *state, size_t width, size_t height);
|
void ncl_setScreenViewport(ncl_ScreenState *state, size_t width, size_t height);
|
||||||
ncl_Pixel ncl_getScreenPixel(const ncl_ScreenState *state, int x, int y);
|
ncl_Pixel ncl_getScreenPixel(const ncl_ScreenState *state, int x, int y);
|
||||||
|
|||||||
1468
src/neonucleus.c
1468
src/neonucleus.c
File diff suppressed because it is too large
Load Diff
859
src/neonucleus.h
859
src/neonucleus.h
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user