Compare commits
46 Commits
cd10093673
...
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 | |||
| edca903416 | |||
| d5a7869d12 | |||
| 94033f3520 | |||
| eef7568185 | |||
| 4a5f1d4d07 | |||
| cb0dcf03ad | |||
| de1553725f | |||
| 571ccb3e3d |
51
Makefile
51
Makefile
@@ -3,17 +3,38 @@ DYNLIB=libneonucleus.so
|
|||||||
LIB=libneonucleus.a
|
LIB=libneonucleus.a
|
||||||
|
|
||||||
CC=cc
|
CC=cc
|
||||||
OPT=-Oz
|
|
||||||
SANITIZE=
|
|
||||||
DEBUG=
|
|
||||||
NNFLAGS=
|
|
||||||
CFLAGS=-fPIC $(OPT) $(SANITIZE) $(DEBUG) $(NNFLAGS)
|
|
||||||
|
|
||||||
LD=$(CC)
|
LD=$(CC)
|
||||||
LDFLAGS=$(OPT) $(DEBUG) $(SANITIZE)
|
|
||||||
|
|
||||||
AR=ar
|
AR=ar
|
||||||
RANLIB=ranlib
|
RANLIB=ranlib
|
||||||
|
WARN=-Wall -Werror -Wno-format-truncation
|
||||||
|
|
||||||
|
ifeq ($(MODE), release)
|
||||||
|
OPT=-Oz
|
||||||
|
DEBUG=
|
||||||
|
else ifeq ($(MODE), release-lto)
|
||||||
|
OPT=-Oz -flto
|
||||||
|
DEBUG=
|
||||||
|
else
|
||||||
|
OPT=-O0
|
||||||
|
SANITIZE=undefined,address
|
||||||
|
DEBUG=-g
|
||||||
|
endif
|
||||||
|
|
||||||
|
NN_STD=gnu99
|
||||||
|
EMU_STD=gnu23
|
||||||
|
|
||||||
|
NNFLAGS=
|
||||||
|
|
||||||
|
SANITIZE_FLAGS=
|
||||||
|
|
||||||
|
ifdef SANITIZE
|
||||||
|
SANITIZE_FLAGS += -fsanitize=$(SANITIZE)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
LINKRAYLIB=-lraylib
|
LINKRAYLIB=-lraylib
|
||||||
INCLUA=-I /usr/include/lua5.3
|
INCLUA=-I /usr/include/lua5.3
|
||||||
@@ -24,22 +45,24 @@ LINKLIBC=
|
|||||||
BUILD_DIR=build
|
BUILD_DIR=build
|
||||||
SRC_DIR=src
|
SRC_DIR=src
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -51,8 +74,6 @@ lib: nn
|
|||||||
dynlib: nn
|
dynlib: nn
|
||||||
$(LD) $(LDFLAGS) -o $(DYNLIB) -shared $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o $(LINKLIBM) $(LINKLIBC)
|
$(LD) $(LDFLAGS) -o $(DYNLIB) -shared $(BUILD_DIR)/neonucleus.o $(BUILD_DIR)/ncomplib.o $(LINKLIBM) $(LINKLIBC)
|
||||||
|
|
||||||
all: bin lib dynlib
|
|
||||||
|
|
||||||
cleancache:
|
cleancache:
|
||||||
rm -rf $(BUILD_DIR)/*.o
|
rm -rf $(BUILD_DIR)/*.o
|
||||||
|
|
||||||
|
|||||||
48
TODO.md
48
TODO.md
@@ -1,32 +1,11 @@
|
|||||||
# 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
|
|
||||||
|
|
||||||
# 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?)
|
||||||
@@ -52,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
|
||||||
@@ -64,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
|
||||||
|
|
||||||
@@ -147,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
|
||||||
@@ -164,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
|
||||||
@@ -190,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
|
||||||
|
|
||||||
@@ -230,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,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
153
src/luaarch.c
153
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);
|
||||||
@@ -133,7 +161,8 @@ static int luaArch_computer_beep(lua_State *L) {
|
|||||||
if(beep.frequency > 20000) beep.frequency = 20000;
|
if(beep.frequency > 20000) beep.frequency = 20000;
|
||||||
if(beep.duration > 5) beep.duration = 5;
|
if(beep.duration > 5) beep.duration = 5;
|
||||||
if(beep.volume > 1) beep.volume = 1;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,6 +327,27 @@ fail:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int luaArch_computer_getDeviceInfo(lua_State *L) {
|
||||||
|
luaArch *arch = luaArch_from(L);
|
||||||
|
nn_Computer *C = arch->computer;
|
||||||
|
lua_createtable(L, 0, 0);
|
||||||
|
for(size_t i = 0;; i++) {
|
||||||
|
const char *devAddr = nn_deviceInfoAt(C, i);
|
||||||
|
if(devAddr == NULL) break;
|
||||||
|
size_t len;
|
||||||
|
const nn_DeviceField *fields = nn_getDeviceInfo(C, i, &len);
|
||||||
|
lua_pushstring(L, devAddr);
|
||||||
|
lua_createtable(L, 0, len);
|
||||||
|
for(size_t j = 0; j < len; j++) {
|
||||||
|
lua_pushstring(L, fields[j].name);
|
||||||
|
lua_pushstring(L, fields[j].value);
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
lua_settable(L, -3);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int luaArch_component_list(lua_State *L) {
|
static int luaArch_component_list(lua_State *L) {
|
||||||
luaArch *arch = luaArch_from(L);
|
luaArch *arch = luaArch_from(L);
|
||||||
lua_createtable(L, 64, 0);
|
lua_createtable(L, 64, 0);
|
||||||
@@ -571,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);
|
||||||
@@ -612,7 +740,10 @@ static void luaArch_loadEnv(lua_State *L) {
|
|||||||
lua_setfield(L, computer, "pushSignal");
|
lua_setfield(L, computer, "pushSignal");
|
||||||
lua_pushcfunction(L, luaArch_computer_popSignal);
|
lua_pushcfunction(L, luaArch_computer_popSignal);
|
||||||
lua_setfield(L, computer, "popSignal");
|
lua_setfield(L, computer, "popSignal");
|
||||||
|
lua_pushcfunction(L, luaArch_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);
|
||||||
@@ -632,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);
|
||||||
@@ -640,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) {
|
||||||
@@ -710,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,
|
||||||
|
|||||||
359
src/main.c
359
src/main.c
@@ -42,12 +42,211 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static nn_Exit ne_dataBullshit(nn_DataCardRequest *req) {
|
||||||
|
nn_Computer *C = req->computer;
|
||||||
|
nn_DataCardAction action = req->action;
|
||||||
|
nn_Exit e;
|
||||||
|
|
||||||
|
if(action == NN_DATA_DROP) {
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_ENCODE64) {
|
||||||
|
int outSize = 0;
|
||||||
|
char *out = EncodeDataBase64((const unsigned char *)req->data, req->datalen, &outSize);
|
||||||
|
if(out == NULL) return NN_ENOMEM;
|
||||||
|
// -1 because raylib includes the NUL terminator??
|
||||||
|
e = nn_pushlstring(C, out, outSize-1);
|
||||||
|
MemFree(out);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_DECODE64) {
|
||||||
|
int outSize = 0;
|
||||||
|
char *out = (char *)DecodeDataBase64(req->data, &outSize);
|
||||||
|
if(out == NULL) return NN_ENOMEM;
|
||||||
|
e = nn_pushlstring(C, out, outSize);
|
||||||
|
MemFree(out);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_DEFLATE) {
|
||||||
|
int outSize = 0;
|
||||||
|
char *out = (char *)CompressData((const unsigned char *)req->data, req->datalen, &outSize);
|
||||||
|
if(out == NULL) return NN_ENOMEM;
|
||||||
|
e = nn_pushlstring(C, out, outSize);
|
||||||
|
MemFree(out);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_INFLATE) {
|
||||||
|
int outSize = 0;
|
||||||
|
char *out = (char *)DecompressData((unsigned char *)req->data, req->datalen, &outSize);
|
||||||
|
if(out == NULL) return NN_ENOMEM;
|
||||||
|
e = nn_pushlstring(C, out, outSize);
|
||||||
|
MemFree(out);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_CRC32) {
|
||||||
|
unsigned int check = nn_computeCRC32(req->crc32.data, req->crc32.datalen);
|
||||||
|
req->crc32.checksum[0] = (check >> 0) & 0xFF;
|
||||||
|
req->crc32.checksum[1] = (check >> 8) & 0xFF;
|
||||||
|
req->crc32.checksum[2] = (check >> 16) & 0xFF;
|
||||||
|
req->crc32.checksum[3] = (check >> 24) & 0xFF;
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_MD5) {
|
||||||
|
unsigned int *out = ComputeMD5((unsigned char *)req->md5.data, req->md5.datalen);
|
||||||
|
if(out == NULL) return NN_ENOMEM;
|
||||||
|
memcpy(req->md5.checksum, out, 16);
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_SHA256) {
|
||||||
|
unsigned int *out = ComputeSHA256((unsigned char *)req->sha256.data, req->sha256.datalen);
|
||||||
|
if(out == NULL) return NN_ENOMEM;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_RANDOM) {
|
||||||
|
for(size_t i = 0; i < req->randbuf.buflen; i++) {
|
||||||
|
req->randbuf.buf[i] = rand();
|
||||||
|
}
|
||||||
|
return NN_OK;
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_ENCRYPT) {
|
||||||
|
return nn_pushlstring(C, req->data, req->datalen);
|
||||||
|
}
|
||||||
|
if(action == NN_DATA_DECRYPT) {
|
||||||
|
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");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static nn_Exit ne_modemBullshit(nn_ModemRequest *req) {
|
||||||
|
nn_Computer *C = req->computer;
|
||||||
|
|
||||||
|
if(req->action == NN_MODEM_DROP) {
|
||||||
|
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) {
|
||||||
|
req->send.strengthSent = req->modem->maxRange;
|
||||||
|
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");
|
||||||
|
return NN_EBADCALL;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned char ne_processColorPart(unsigned char channel, double brightness) {
|
static unsigned char ne_processColorPart(unsigned char channel, double brightness) {
|
||||||
double n = (double)channel / 255;
|
double n = (double)channel / 255;
|
||||||
n *= brightness;
|
n *= brightness;
|
||||||
@@ -301,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) {
|
||||||
@@ -310,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
|
||||||
@@ -323,19 +527,54 @@ 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 ne_energy_accumulator(void *state, nn_Computer *c, double n) {
|
void ne_env(nn_EnvironmentRequest *req) {
|
||||||
accumulatedEnergyCost += n;
|
if(req->action == NN_ENV_BEEP) {
|
||||||
totalEnergyLoss += n;
|
printf("beep: %f Hz %fs %.02f%%\n", req->beep.frequency, req->beep.duration, req->beep.volume*100);
|
||||||
return nn_getTotalEnergy(c);
|
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) {
|
||||||
|
accumulatedEnergyCost += req->energy;
|
||||||
|
totalEnergyLoss += req->energy;
|
||||||
|
allEnergy -= req->energy;
|
||||||
|
req->energy = nn_getTotalEnergy(req->computer);
|
||||||
|
req->energy = allEnergy;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
@@ -356,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
|
||||||
@@ -369,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);
|
||||||
|
|
||||||
@@ -382,6 +626,11 @@ int main(int argc, char **argv) {
|
|||||||
nn_setComponentMethods(ocelotCard, sandboxMethods);
|
nn_setComponentMethods(ocelotCard, sandboxMethods);
|
||||||
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 *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);
|
||||||
const char *eepromPath = getenv("NN_EEPROM");
|
const char *eepromPath = getenv("NN_EEPROM");
|
||||||
@@ -405,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"
|
||||||
@@ -445,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);
|
||||||
|
|
||||||
@@ -469,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));
|
||||||
@@ -482,28 +719,48 @@ 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[3]);
|
nn_Component *screen = ncl_createScreen(u, NULL, &nn_defaultScreens[tier-1]);
|
||||||
nn_Component *gpuCard = ncl_createGPU(u, NULL, &nn_defaultGPUs[3]);
|
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, "computer0", ramTotal, 256, 256);
|
// we assume server basically
|
||||||
nn_Component *wrappedC = nn_wrapComputer(c);
|
nn_Computer * volatile c = nn_createComputer(u, NULL, NULL, ramTotal, nn_defaultComponentLimits[tier-1] * 4, 256);
|
||||||
if(showStats) {
|
nn_Environment cEnv = {
|
||||||
// collects stats
|
.userdata = NULL,
|
||||||
nn_setEnergyHandler(c, NULL, ne_energy_accumulator);
|
.handler = ne_env,
|
||||||
|
};
|
||||||
|
nn_setComputerEnvironment(c, cEnv);
|
||||||
|
// 5 cuz CPU + each RAM stick all have same tier call budgets
|
||||||
|
nn_setCallBudget(c, nn_defaultCallBudgets[tier-1] * 5);
|
||||||
|
nn_setTotalEnergy(c, allEnergy);
|
||||||
|
if(getenv("NN_FAST") != NULL) {
|
||||||
|
tickDelay = 0;
|
||||||
|
noIdle = true;
|
||||||
|
nn_setCallBudget(c, 0);
|
||||||
}
|
}
|
||||||
nn_setCallBudget(c, 0);
|
|
||||||
|
|
||||||
nn_setArchitecture(c, &arch);
|
nn_setArchitecture(c, &arch);
|
||||||
nn_addSupportedArchitecture(c, &arch);
|
nn_addSupportedArchitecture(c, &arch);
|
||||||
|
|
||||||
nn_setTmpAddress(c, nn_getComponentAddress(tmpfs));
|
nn_setTmpAddress(c, nn_getComponentAddress(tmpfs));
|
||||||
|
|
||||||
nn_mountComponent(c, wrappedC, 255, false);
|
nn_CommonDeviceInfo cinfo;
|
||||||
|
nn_clearCommonDeviceInfo(&cinfo);
|
||||||
|
cinfo.CLASS = NN_DEVICECLASS_SYSTEM;
|
||||||
|
cinfo.DESC = "The main computer";
|
||||||
|
cinfo.VENDOR = "NeoNucleus Inc.";
|
||||||
|
cinfo.PRODUCT = "NeoComputer";
|
||||||
|
cinfo.VERSION = "0.-1.0";
|
||||||
|
cinfo.CLOCK = "1 MHz";
|
||||||
|
cinfo.CAPACITY = "10 kJ";
|
||||||
|
|
||||||
|
nn_addCommonDeviceInfo(c, nn_getComputerAddress(c), cinfo);
|
||||||
|
|
||||||
nn_mountComponent(c, screen, -1, false);
|
nn_mountComponent(c, screen, -1, false);
|
||||||
nn_mountComponent(c, ocelotCard, -1, false);
|
nn_mountComponent(c, ocelotCard, -1, false);
|
||||||
nn_mountComponent(c, tmpfs, -1, false);
|
nn_mountComponent(c, tmpfs, -1, false);
|
||||||
@@ -514,8 +771,14 @@ int main(int argc, char **argv) {
|
|||||||
nn_mountComponent(c, testingfs, 3, false);
|
nn_mountComponent(c, testingfs, 3, false);
|
||||||
nn_mountComponent(c, testDrive, 4, false);
|
nn_mountComponent(c, testDrive, 4, false);
|
||||||
nn_mountComponent(c, testFlash, 5, false);
|
nn_mountComponent(c, testFlash, 5, false);
|
||||||
|
nn_mountComponent(c, dataCard, 6, 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;
|
||||||
@@ -620,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();
|
||||||
@@ -687,7 +952,18 @@ int main(int argc, char **argv) {
|
|||||||
nn_removeEnergy(c, ncl_getScreenEnergyUsage(nn_getComponentState(screen)));
|
nn_removeEnergy(c, ncl_getScreenEnergyUsage(nn_getComponentState(screen)));
|
||||||
|
|
||||||
if(noIdle) nn_resetIdleTime(c);
|
if(noIdle) nn_resetIdleTime(c);
|
||||||
|
// OC computers consume 0.5W when running, 0.05W when running but idle
|
||||||
|
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;
|
||||||
@@ -721,12 +997,6 @@ int main(int argc, char **argv) {
|
|||||||
continue;
|
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:;
|
cleanup:;
|
||||||
@@ -741,12 +1011,19 @@ cleanup:;
|
|||||||
nn_dropComponent(screen);
|
nn_dropComponent(screen);
|
||||||
nn_dropComponent(gpuCard);
|
nn_dropComponent(gpuCard);
|
||||||
nn_dropComponent(keyboard);
|
nn_dropComponent(keyboard);
|
||||||
nn_dropComponent(wrappedC);
|
nn_dropComponent(dataCard);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
843
src/ncomplib.c
843
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);
|
||||||
|
|||||||
2194
src/neonucleus.c
2194
src/neonucleus.c
File diff suppressed because it is too large
Load Diff
1152
src/neonucleus.h
1152
src/neonucleus.h
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user