diff --git a/cli/assets/templates/assemblyscript/src/wasm4.ts b/cli/assets/templates/assemblyscript/src/wasm4.ts index dc044009..fa89cbbe 100644 --- a/cli/assets/templates/assemblyscript/src/wasm4.ts +++ b/cli/assets/templates/assemblyscript/src/wasm4.ts @@ -25,6 +25,7 @@ export const MOUSE_X: usize = 0x1a; export const MOUSE_Y: usize = 0x1c; export const MOUSE_BUTTONS: usize = 0x1e; export const SYSTEM_FLAGS: usize = 0x1f; +export const TIME: usize = 0x20; export const FRAMEBUFFER: usize = 0xa0; export const BUTTON_1: u8 = 1; diff --git a/cli/assets/templates/c/src/wasm4.h b/cli/assets/templates/c/src/wasm4.h index 8b911c8a..5134f53c 100644 --- a/cli/assets/templates/c/src/wasm4.h +++ b/cli/assets/templates/c/src/wasm4.h @@ -35,6 +35,7 @@ WASM_EXPORT("update") void update (); #define MOUSE_Y ((const int16_t*)0x1c) #define MOUSE_BUTTONS ((const uint8_t*)0x1e) #define SYSTEM_FLAGS ((uint8_t*)0x1f) +#define TIME ((uint64_t*)0x20) #define FRAMEBUFFER ((uint8_t*)0xa0) #define BUTTON_1 1 diff --git a/cli/assets/templates/go/w4/wasm4.go b/cli/assets/templates/go/w4/wasm4.go index e4eda6bf..82c777ca 100644 --- a/cli/assets/templates/go/w4/wasm4.go +++ b/cli/assets/templates/go/w4/wasm4.go @@ -29,6 +29,7 @@ var MOUSE_X = (*int16)(unsafe.Pointer(uintptr(0x1a))) var MOUSE_Y = (*int16)(unsafe.Pointer(uintptr(0x1c))) var MOUSE_BUTTONS = (*uint8)(unsafe.Pointer(uintptr(0x1e))) var SYSTEM_FLAGS = (*uint8)(unsafe.Pointer(uintptr(0x1f))); +var TIME = (*uint64)(unsafe.Pointer(uintptr(0x20))); var FRAMEBUFFER = (*[6400]uint8)(unsafe.Pointer(uintptr(0xa0))) const BUTTON_1 byte = 1 diff --git a/cli/assets/templates/nelua/src/wasm4.nelua b/cli/assets/templates/nelua/src/wasm4.nelua index 867fa196..a4f1ad84 100644 --- a/cli/assets/templates/nelua/src/wasm4.nelua +++ b/cli/assets/templates/nelua/src/wasm4.nelua @@ -50,6 +50,7 @@ global MOUSE_X = (@*int16)(0x1a) global MOUSE_Y = (@*int16)(0x1c) global MOUSE_BUTTONS = (@*uint8)(0x1e) global SYSTEM_FLAGS = (@*uint8)(0x1f) +global TIME = (@*uint64)(0x20) global FRAMEBUFFER = (@*[6400]uint8)(0xa0) global BUTTON_1 = 1 diff --git a/cli/assets/templates/odin/src/w4/wasm4_wasm32.odin b/cli/assets/templates/odin/src/w4/wasm4_wasm32.odin index 62725072..3d83fd23 100644 --- a/cli/assets/templates/odin/src/w4/wasm4_wasm32.odin +++ b/cli/assets/templates/odin/src/w4/wasm4_wasm32.odin @@ -23,6 +23,7 @@ MOUSE_X := (^i16)(uintptr(0x1a)) MOUSE_Y := (^i16)(uintptr(0x1c)) MOUSE_BUTTONS := (^Mouse_Buttons)(uintptr(0x1e)) SYSTEM_FLAGS := (^System_Flags)(uintptr(0x1f)) +TIME := (^u64)(uintptr(0x20)) FRAMEBUFFER := (^[6400]u8)(uintptr(0xa0)) // 4 bits * (160*160) Palette :: distinct [4]u32 diff --git a/cli/assets/templates/rust/src/wasm4.rs b/cli/assets/templates/rust/src/wasm4.rs index c3dde0d1..dcac9ab9 100644 --- a/cli/assets/templates/rust/src/wasm4.rs +++ b/cli/assets/templates/rust/src/wasm4.rs @@ -27,6 +27,7 @@ pub const MOUSE_X: *const i16 = 0x1a as *const i16; pub const MOUSE_Y: *const i16 = 0x1c as *const i16; pub const MOUSE_BUTTONS: *const u8 = 0x1e as *const u8; pub const SYSTEM_FLAGS: *mut u8 = 0x1f as *mut u8; +pub const TIME: *mut u64 = 0x20 as *mut u64; pub const FRAMEBUFFER: *mut [u8; 6400] = 0xa0 as *mut [u8; 6400]; pub const BUTTON_1: u8 = 1; diff --git a/cli/assets/templates/wat/main.wat b/cli/assets/templates/wat/main.wat index fda829ab..7aef62f1 100644 --- a/cli/assets/templates/wat/main.wat +++ b/cli/assets/templates/wat/main.wat @@ -77,6 +77,7 @@ (global $MOUSE_Y i32 (i32.const 0x1c)) (global $MOUSE_BUTTONS i32 (i32.const 0x1e)) (global $SYSTEM_FLAGS i32 (i32.const 0x1f)) +(global $TIME u64 (u64.const 0x20)) (global $FRAMEBUFFER i32 (i32.const 0xa0)) (global $BUTTON_1 i32 (i32.const 1)) diff --git a/cli/assets/templates/zig/src/wasm4.zig b/cli/assets/templates/zig/src/wasm4.zig index 322dc926..e640396e 100644 --- a/cli/assets/templates/zig/src/wasm4.zig +++ b/cli/assets/templates/zig/src/wasm4.zig @@ -25,6 +25,7 @@ pub const MOUSE_X: *const i16 = @intToPtr(*const i16, 0x1a); pub const MOUSE_Y: *const i16 = @intToPtr(*const i16, 0x1c); pub const MOUSE_BUTTONS: *const u8 = @intToPtr(*const u8, 0x1e); pub const SYSTEM_FLAGS: *u8 = @intToPtr(*u8, 0x1f); +pub const TIME: *u64 = @intToPtr(*u64, 0x20); pub const FRAMEBUFFER: *[6400]u8 = @intToPtr(*[6400]u8, 0xA0); pub const BUTTON_1: u8 = 1; diff --git a/devtools/web/src/constants.ts b/devtools/web/src/constants.ts index b3bde521..8e2651cf 100644 --- a/devtools/web/src/constants.ts +++ b/devtools/web/src/constants.ts @@ -17,6 +17,7 @@ export const ADDR_MOUSE_X = 0x1a; export const ADDR_MOUSE_Y = 0x1c; export const ADDR_MOUSE_BUTTONS = 0x1e; export const ADDR_SYSTEM_FLAGS = 0x1f; +export const ADDR_TIME = 0x20; export const ADDR_FRAMEBUFFER = 0xa0; export const BUTTON_X = 1; @@ -83,9 +84,13 @@ export const memoryMap: Readonly> = { offset: ADDR_SYSTEM_FLAGS, len: 1, }, + TIME: { + offset: ADDR_TIME, + len: 8, + }, RESERVED: { offset: 0x0020, - len: 128, + len: 120, }, FRAMEBUFFER: { offset: ADDR_FRAMEBUFFER, diff --git a/devtools/web/src/models/MemoryView.ts b/devtools/web/src/models/MemoryView.ts index 75f576da..ce0632d5 100644 --- a/devtools/web/src/models/MemoryView.ts +++ b/devtools/web/src/models/MemoryView.ts @@ -44,6 +44,7 @@ export class MemoryView implements MemoryViewComputedProperties { readonly pointerPos: Point; readonly mouseBtnByte: number; readonly systemFlags: number; + readonly time: number; readonly gamepads: number[]; readonly palette: [number, number, number, number]; readonly drawColors: number; @@ -58,6 +59,7 @@ export class MemoryView implements MemoryViewComputedProperties { this.palette = extractPalette(dataView); this.gamepads = extractGamepads(dataView, bufferedData); this.systemFlags = dataView.getUint8(constants.ADDR_SYSTEM_FLAGS); + this.time = dataView.getUint32(constants.ADDR_TIME); // TODO: DataView doesn't support uint64? this.mouseBtnByte = dataView.getUint8(constants.ADDR_MOUSE_BUTTONS) | bufferedData.mouseButtons; diff --git a/examples/clock/.gitignore b/examples/clock/.gitignore new file mode 100644 index 00000000..1221a6a3 --- /dev/null +++ b/examples/clock/.gitignore @@ -0,0 +1,3 @@ +/build +/package-lock.json +/node_modules \ No newline at end of file diff --git a/examples/clock/asconfig.json b/examples/clock/asconfig.json new file mode 100644 index 00000000..59b16455 --- /dev/null +++ b/examples/clock/asconfig.json @@ -0,0 +1,32 @@ +{ + "entries": [ + "./src/main.ts" + ], + "options": { + "binaryFile": "build/cart.wasm", + "runtime": "incremental", + "importMemory": true, + "initialMemory": 1, + "maximumMemory": 1, + "noExportMemory": true, + "zeroFilledMemory": true, + "memoryBase": 6560, + "use": [ + "seed=src/wasm4/seedHandler", + "trace=" + ] + }, + "targets": { + "release": { + "optimizeLevel": 3, + "shrinkLevel": 0, + "noAssert": true, + "use": "abort=" + }, + "debug": { + "debug": true, + "sourceMap": "http://localhost:4444/cart.wasm.map", + "use": "abort=src/wasm4/abortHandler" + } + } +} diff --git a/examples/clock/package.json b/examples/clock/package.json new file mode 100644 index 00000000..0234618c --- /dev/null +++ b/examples/clock/package.json @@ -0,0 +1,15 @@ +{ + "name": "wasm4-clock", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "asc --target release", + "build:debug": "asc --target debug" + }, + "dependencies": { + "as-date": "^0.1.3" + }, + "devDependencies": { + "assemblyscript": "^0.19.11" + } +} diff --git a/examples/clock/src/main.ts b/examples/clock/src/main.ts new file mode 100644 index 00000000..6eb23ed7 --- /dev/null +++ b/examples/clock/src/main.ts @@ -0,0 +1,82 @@ +import * as w4 from "./wasm4"; +import { Date } from "as-date"; + +let time: f64; +let timezone: i32; +let previousGamepad: u8; + +export function start(): void { + // Get the time the runtime was started. + time = load(w4.TIME) as f64; + + // Load the timezone. + const ptr = memory.data(sizeof()); + w4.diskr(ptr, sizeof()); + timezone = load(ptr); + + // Palette. + store(w4.PALETTE, Number.parseInt("000000", 16) as u32); + store(w4.PALETTE, Number.parseInt("ffffff", 16) as u32, 4); + store(w4.PALETTE, Number.parseInt("ff0000", 16) as u32, 8); + store(w4.PALETTE, Number.parseInt("00ff00", 16) as u32, 12); +} + +function setTimezone(newTimezone:i32): void { + const ptr = memory.data(sizeof()); + store(ptr, newTimezone); + w4.diskw(ptr, sizeof()); + timezone = newTimezone; +} + +export function update(): void { + // Increase the seconds. + time += 1 / 60; // 60 frames per second + + // Clear the screen. + store(w4.DRAW_COLORS, 0x2); + w4.rect(0, 0, w4.SCREEN_SIZE, w4.SCREEN_SIZE); + + // Interpret the time into a valid Date. + const date = new Date((time as i64) * 1000); // Date() expects milliseconds + date.setTimezoneOffset(timezone * 60); + + // Draw the clock. + let center:i32 = w4.SCREEN_SIZE / 2; + let clockRadius = w4.SCREEN_SIZE / 2 * 0.95; + store(w4.DRAW_COLORS, 0x12); + w4.oval(center - clockRadius as u32, center - clockRadius as u32, clockRadius * 2 as u32, clockRadius * 2 as u32); + + // Draw the numbers on the clock. + store(w4.DRAW_COLORS, 0x1); + let textRadius = clockRadius * 0.85 + for (let i = 0; i < 12; i++) { + let clockPosition = i * 5; + let text = i == 0 ? "12" : i.toString() + let textWidth = text.length * 8; + let textHeight = 8; + w4.text(text, center + textRadius * Math.sin(clockPosition * (2 * Math.PI / 60)) - textWidth / 2 as i32 , center - textRadius * Math.cos(clockPosition * (2 * Math.PI / 60)) - textHeight / 2 as i32); + } + + // Draw the hands. + let sradius = clockRadius * 0.8; + let mradius = clockRadius * 0.9; + let hradius = clockRadius * 0.6; + store(w4.DRAW_COLORS, 0x3); + w4.line(center, center, center + sradius * Math.sin(date.getSeconds() * (2 * Math.PI / 60)) as i32, center - sradius * Math.cos(date.getSeconds() * (2 * Math.PI / 60)) as i32) + store(w4.DRAW_COLORS, 0x1); + w4.line(center, center, center + mradius * Math.sin(date.getMinutes() * (2 * Math.PI / 60)) as i32, center - mradius * Math.cos(date.getMinutes() * (2 * Math.PI / 60)) as i32); + store(w4.DRAW_COLORS, 0x1); + let h = date.getHours() % 12 + date.getMinutes() / 60.0; + w4.line(center, center, center + hradius * Math.sin(h * (2 * Math.PI / 60)) as i32, center - hradius * Math.cos(h * (2 * Math.PI / 60)) as i32); + + // Allow changing the timezone. + const gamepad = load(w4.GAMEPAD1); + const pressedThisFrame = gamepad & (gamepad ^ previousGamepad); + previousGamepad = gamepad; + if (pressedThisFrame & w4.BUTTON_LEFT) { + setTimezone(timezone - 1); + } + if (pressedThisFrame & w4.BUTTON_RIGHT) { + setTimezone(timezone + 1); + } +} diff --git a/examples/clock/src/wasm4.ts b/examples/clock/src/wasm4.ts new file mode 100644 index 00000000..311a7186 --- /dev/null +++ b/examples/clock/src/wasm4.ts @@ -0,0 +1,189 @@ +// +// WASM-4: https://wasm4.org/docs + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Platform Constants │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +export const SCREEN_SIZE: u32 = 160; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Memory Addresses │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +export const PALETTE: usize = 0x04; +export const DRAW_COLORS: usize = 0x14; +export const GAMEPAD1: usize = 0x16; +export const GAMEPAD2: usize = 0x17; +export const GAMEPAD3: usize = 0x18; +export const GAMEPAD4: usize = 0x19; +export const MOUSE_X: usize = 0x1a; +export const MOUSE_Y: usize = 0x1c; +export const MOUSE_BUTTONS: usize = 0x1e; +export const SYSTEM_FLAGS: usize = 0x1f; +export const TIME: usize = 0x20; +export const FRAMEBUFFER: usize = 0xa0; + +export const BUTTON_1: u8 = 1; +export const BUTTON_2: u8 = 2; +export const BUTTON_LEFT: u8 = 16; +export const BUTTON_RIGHT: u8 = 32; +export const BUTTON_UP: u8 = 64; +export const BUTTON_DOWN: u8 = 128; + +export const MOUSE_LEFT: u8 = 1; +export const MOUSE_RIGHT: u8 = 2; +export const MOUSE_MIDDLE: u8 = 4; + +export const SYSTEM_PRESERVE_FRAMEBUFFER = 1; +export const SYSTEM_HIDE_GAMEPAD_OVERLAY = 2; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Drawing Functions │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +/** Copies pixels to the framebuffer. */ +// @ts-ignore: decorator +@external("env", "blit") +export declare function blit ( + spritePtr: usize, + x: i32, + y: i32, + width: u32, + height: u32, + flags: u32 +): void; + +/** Copies a subregion within a larger sprite atlas to the framebuffer. */ +// @ts-ignore: decorator +@external("env", "blitSub") +export declare function blitSub ( + spritePtr: usize, + x: i32, + y: i32, + width: u32, + height: u32, + srcX: u32, + srcY: u32, + stride: i32, + flags: u32 +): void; + +export const BLIT_1BPP: u32 = 0; +export const BLIT_2BPP: u32 = 1; +export const BLIT_FLIP_X: u32 = 2; +export const BLIT_FLIP_Y: u32 = 4; +export const BLIT_ROTATE: u32 = 8; + +/** Draws a line between two points. */ +// @ts-ignore: decorator +@external("env", "line") +export declare function line (x1: i32, y1: i32, x2: i32, y2: i32): void; + +/** Draws a horizontal line. */ +// @ts-ignore: decorator +@external("env", "hline") +export declare function hline (x: i32, y: i32, len: u32): void; + +/** Draws a vertical line. */ +// @ts-ignore: decorator +@external("env", "vline") +export declare function vline (x: i32, y: i32, len: u32): void; + +/** Draws an oval (or circle). */ +// @ts-ignore: decorator +@external("env", "oval") +export declare function oval (x: i32, y: i32, width: u32, height: u32): void; + +/** Draws a rectangle. */ +// @ts-ignore: decorator +@external("env", "rect") +export declare function rect (x: i32, y: i32, width: u32, height: u32): void; + +/** Draws text using the built-in system font. */ +export function text (str: string, x: i32, y: i32): void { + const byteLength = load(changetype(str) - 4); + textUtf16(str, byteLength, x, y); +} + +// @ts-ignore: decorator +@external("env", "textUtf16") +declare function textUtf16 (text: string, byteLength: u32, x: i32, y: i32): void; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Sound Functions │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +/** Plays a sound tone. */ +// @ts-ignore: decorator +@external("env", "tone") +export declare function tone (frequency: u32, duration: u32, volume: u32, flags: u32): void; + +export const TONE_PULSE1: u32 = 0; +export const TONE_PULSE2: u32 = 1; +export const TONE_TRIANGLE: u32 = 2; +export const TONE_NOISE: u32 = 3; +export const TONE_MODE1: u32 = 0; +export const TONE_MODE2: u32 = 4; +export const TONE_MODE3: u32 = 8; +export const TONE_MODE4: u32 = 12; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Storage Functions │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +/** Reads up to `size` bytes from persistent storage into the pointer `destPtr`. */ +// @ts-ignore: decorator +@external("env", "diskr") +export declare function diskr (dest: usize, size: u32): u32; + +/** Writes up to `size` bytes from the pointer `srcPtr` into persistent storage. */ +// @ts-ignore: decorator +@external("env", "diskw") +export declare function diskw (src: usize, size: u32): u32; + +// ┌───────────────────────────────────────────────────────────────────────────┐ +// │ │ +// │ Other Functions │ +// │ │ +// └───────────────────────────────────────────────────────────────────────────┘ + +/** Prints a message to the debug console. */ +export function trace (str: string): void { + const ptr = changetype(str); + const byteLength = load(ptr - 4); + traceUtf16(ptr, byteLength); +} + +// @ts-ignore: decorator +@external("env", "traceUtf16") +declare function traceUtf16 (str: usize, byteLength: u32): void; + +// Pass abort messages to trace() +function abortHandler ( + message: string | null, + fileName: string | null, + lineNumber: u32, + columnNumber: u32 +): void { + const ptr = changetype(message); + if (ptr != 0) { + const byteLength = load(ptr - 4); + traceUtf16(ptr, byteLength); + } +} + +// Avoid requiring an external seed. Call `Math.seedRandom()` to manually seed `Math.random()`. +function seedHandler (): f64 { + return 0; +} diff --git a/examples/clock/tsconfig.json b/examples/clock/tsconfig.json new file mode 100644 index 00000000..6109ef48 --- /dev/null +++ b/examples/clock/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "assemblyscript/std/assembly.json", + "include": [ + "./src/**/*.ts" + ] +} diff --git a/examples/snake/package-lock.json b/examples/snake/package-lock.json index 57ab12f4..3dfdf03c 100644 --- a/examples/snake/package-lock.json +++ b/examples/snake/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "wasm4-snake", "version": "1.0.0", "devDependencies": { "assemblyscript": "^0.19.11" diff --git a/examples/snake/src/wasm4.ts b/examples/snake/src/wasm4.ts index 32178d36..311a7186 100644 --- a/examples/snake/src/wasm4.ts +++ b/examples/snake/src/wasm4.ts @@ -25,6 +25,7 @@ export const MOUSE_X: usize = 0x1a; export const MOUSE_Y: usize = 0x1c; export const MOUSE_BUTTONS: usize = 0x1e; export const SYSTEM_FLAGS: usize = 0x1f; +export const TIME: usize = 0x20; export const FRAMEBUFFER: usize = 0xa0; export const BUTTON_1: u8 = 1; diff --git a/runtimes/native/src/runtime.c b/runtimes/native/src/runtime.c index 152b9a06..7dff4363 100644 --- a/runtimes/native/src/runtime.c +++ b/runtimes/native/src/runtime.c @@ -2,6 +2,7 @@ #include #include +#include #include #include "apu.h" @@ -23,7 +24,8 @@ typedef struct { int16_t mouseY; uint8_t mouseButtons; uint8_t systemFlags; - uint8_t _reserved[128]; + uint64_t time; + uint8_t _reserved[120]; uint8_t framebuffer[WIDTH*HEIGHT>>2]; uint8_t _user[58975]; } Memory; @@ -53,6 +55,7 @@ void w4_runtimeInit (uint8_t* memoryBytes, w4_Disk* diskBytes) { memory->drawColors[1] = 0x12; m3ApiWriteMem16(&memory->mouseX, 0x7fff); m3ApiWriteMem16(&memory->mouseY, 0x7fff); + m3ApiWriteMem64(&memory->time, (uint64_t)(time(NULL))); w4_apuInit(); w4_framebufferInit(&memory->drawColors, memory->framebuffer); diff --git a/runtimes/web/src/constants.js b/runtimes/web/src/constants.js index 4e814c43..980c480f 100644 --- a/runtimes/web/src/constants.js +++ b/runtimes/web/src/constants.js @@ -28,6 +28,7 @@ export const ADDR_MOUSE_X = 0x1a; export const ADDR_MOUSE_Y = 0x1c; export const ADDR_MOUSE_BUTTONS = 0x1e; export const ADDR_SYSTEM_FLAGS = 0x1f; +export const ADDR_TIME = 0x20; export const ADDR_FRAMEBUFFER = 0xa0; export const BUTTON_X = 1; diff --git a/runtimes/web/src/runtime.js b/runtimes/web/src/runtime.js index bb6eb9a1..8c08d754 100644 --- a/runtimes/web/src/runtime.js +++ b/runtimes/web/src/runtime.js @@ -52,6 +52,10 @@ export class Runtime { return this.data.getUint8(constants.ADDR_SYSTEM_FLAGS) & mask; } + getTime () { + return this.data.getUint32(constants.ADDR_TIME) & mask; // TODO: dataView doesn't support getUint64? + } + maskGamepad (idx, mask, down) { const addr = constants.ADDR_GAMEPAD1 + idx; let buttons = this.data.getUint8(addr); @@ -102,6 +106,11 @@ export class Runtime { // Initialize the mouse off screen this.data.setInt16(constants.ADDR_MOUSE_X, 0x7fff, true); this.data.setInt16(constants.ADDR_MOUSE_Y, 0x7fff, true); + + // Set the timestamp in seconds + const currentDate = new Date(); + const timestamp = Math.floor(currentDate.getTime() / 1000); + this.data.setBigUint64(constants.ADDR_TIME, BigInt.asUintN(64, BigInt(timestamp)), true); } async load (wasmBuffer) { diff --git a/scripts/generate-memory-map b/scripts/generate-memory-map index 6d143d03..05eb7f42 100755 --- a/scripts/generate-memory-map +++ b/scripts/generate-memory-map @@ -20,7 +20,9 @@ const memory = { SYSTEM_FLAGS: 1, - _RESERVED: 128, + TIME: 8, + + _RESERVED: 120, // Framebuffer should be 64 bit aligned FRAMEBUFFER: 160*160 >> 2, @@ -32,6 +34,7 @@ const cTypes = { MOUSE_X: "const int16_t", MOUSE_Y: "const int16_t", SYSTEM_FLAGS: "uint8_t", + TIME: "uint64_t", FRAMEBUFFER: "uint8_t", }; @@ -53,6 +56,7 @@ const neluaTypes = { MOUSE_X: "int16", MOUSE_Y: "int16", SYSTEM_FLAGS: "uint8", + TIME: "uint64", FRAMEBUFFER: "uint8", }; diff --git a/site/docs/reference/memory.md b/site/docs/reference/memory.md index 0012647b..a941f6f9 100644 --- a/site/docs/reference/memory.md +++ b/site/docs/reference/memory.md @@ -12,7 +12,8 @@ WASM-4 uses a fixed memory layout of 64 KB. | `$001c` | 2 | [MOUSE_Y](#mouse_y) | | `$001e` | 1 | [MOUSE_BUTTONS](#mouse_buttons) | | `$001f` | 1 | [SYSTEM_FLAGS](#system_flags) | -| `$0020` | 128 | Reserved for future use | +| `$0020` | 8 | [TIME](#TIME) | +| `$0028` | 112 | Reserved for future use | | `$00a0` | 6400 | [FRAMEBUFFER](#framebuffer) | | `$19a0` | 58975 | Available program memory | @@ -91,6 +92,10 @@ Byte containing flags that modify WASM-4's operation. By default all flags are o | 0 | `SYSTEM_PRESERVE_FRAMEBUFFER` | Prevent clearing the framebuffer between frames. | | 1 | `SYSTEM_HIDE_GAMEPAD_OVERLAY` | Hide the gamepad UI overlay on mobile. | +### TIME + +Unsigned 64 bit integer representing the unix timestamp of when the runtime was started. + ### FRAMEBUFFER Array of 160x160 pixels, with each pixel packed into 2 bits (colors 0 to 3).