-
Notifications
You must be signed in to change notification settings - Fork 202
Expand file tree
/
Copy pathwasm4.nelua
More file actions
201 lines (163 loc) · 11 KB
/
wasm4.nelua
File metadata and controls
201 lines (163 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
-- WASM-4: https://wasm4.org/docs
-- Configure compiler.
-- NOTE: This must come first because it changes some compiler settings!
##[[
ldflags "-Wl,-zstack-size=14752,--no-entry,--import-memory -mexec-model=reactor"
ldflags "-Wl,--initial-memory=65536,--max-memory=65536,--stack-first,--export-dynamic"
if DEBUG then
-- We should use at least 01 optimization, otherwise the application may use too much stack space.
cflags "-O1 -g"
ldflags "-Wl,--export-all,--no-gc-sections"
else
-- Optimization for the making the application small as possible.
cflags "-Oz -g0 -flto"
ldflags "-Wl,--strip-all,--gc-sections,--lto-O3"
end
-- Generates an illegal instruction on aborts/panics
context.rootpragmas.abort = "trap"
-- We will not write to stdout, instead any write to it will be hooked.
context.rootpragmas.writestderr = "hooked"
-- We don't need to emit `main()` entry point, we will hook this ourselves.
context.rootpragmas.nogcentry = true
-- Bundle `snprintf` (used by `string.format`).
context.rootpragmas.usenanoprintf = true
]]
-- ┌───────────────────────────────────────────────────────────────────────────┐
-- │ │
-- │ Platform Constants │
-- │ │
-- └───────────────────────────────────────────────────────────────────────────┘
global SCREEN_SIZE <comptime> = 160
-- ┌───────────────────────────────────────────────────────────────────────────┐
-- │ │
-- │ Memory Addresses │
-- │ │
-- └───────────────────────────────────────────────────────────────────────────┘
global PALETTE <comptime> = (@*[4]uint32)(0x04)
global DRAW_COLORS <comptime> = (@*uint16)(0x14)
global GAMEPAD1 <comptime> = (@*uint8)(0x16)
global GAMEPAD2 <comptime> = (@*uint8)(0x17)
global GAMEPAD3 <comptime> = (@*uint8)(0x18)
global GAMEPAD4 <comptime> = (@*uint8)(0x19)
global MOUSE_X <comptime> = (@*int16)(0x1a)
global MOUSE_Y <comptime> = (@*int16)(0x1c)
global MOUSE_BUTTONS <comptime> = (@*uint8)(0x1e)
global SYSTEM_FLAGS <comptime> = (@*uint8)(0x1f)
global START_TIME <comptime> = (@*uint64)(0x20)
global FRAMEBUFFER <comptime> = (@*[6400]uint8)(0xa0)
global BUTTON_1 <comptime> = 1
global BUTTON_2 <comptime> = 2
global BUTTON_LEFT <comptime> = 16
global BUTTON_RIGHT <comptime> = 32
global BUTTON_UP <comptime> = 64
global BUTTON_DOWN <comptime> = 128
global MOUSE_LEFT <comptime> = 1
global MOUSE_RIGHT <comptime> = 2
global MOUSE_MIDDLE <comptime> = 4
global SYSTEM_PRESERVE_FRAMEBUFFER <comptime> = 1
global SYSTEM_HIDE_GAMEPAD_OVERLAY <comptime> = 2
-- ┌───────────────────────────────────────────────────────────────────────────┐
-- │ │
-- │ Drawing Functions │
-- │ │
-- └───────────────────────────────────────────────────────────────────────────┘
-- Copies pixels to the framebuffer.
global function blit(data: *[0]uint8, x: int32, y: int32, width: uint32, height: uint32, flags: uint32): void <cimport,cattribute'import_name("blit")'> end
-- Copies a subregion within a larger sprite atlas to the framebuffer.
global function blitSub(data: *[0]uint8, x: int32, y: int32, width: uint32, height: uint32, srcX: uint32, srcY: uint32, stride: uint32, flags: uint32): void <cimport,cattribute'import_name("blitSub")'> end
global BLIT_2BPP <comptime> = 1
global BLIT_1BPP <comptime> = 0
global BLIT_FLIP_X <comptime> = 2
global BLIT_FLIP_Y <comptime> = 4
global BLIT_ROTATE <comptime> = 8
-- Draws a line between two points.
global function line(x: int32, y: int32, width: uint32, height: uint32): void <cimport,cattribute'import_name("line")'> end
-- Draws a horizontal line.
global function hline(x: int32, y: int32, len: uint32): void <cimport,cattribute'import_name("hline")'> end
-- Draws a vertical line.
global function vline(x: int32, y: int32, len: uint32): void <cimport,cattribute'import_name("vline")'> end
-- Draws an oval (or circle).
global function oval(x: int32, y: int32, width: uint32, height: uint32): void <cimport,cattribute'import_name("oval")'> end
-- Draws a rectangle.
global function rect(x: int32, y: int32, width: uint32, height: uint32): void <cimport,cattribute'import_name("rect")'> end
-- Draws text using the built-in system font.
global function text(str: cstring, x: int32, y: int32): void <cimport,cattribute'import_name("text")'> end
-- ┌───────────────────────────────────────────────────────────────────────────┐
-- │ │
-- │ Sound Functions │
-- │ │
-- └───────────────────────────────────────────────────────────────────────────┘
-- Plays a sound tone.
global function tone(frequency: uint32, duration: uint32, volume: uint32, flags: uint32): void <cimport,cattribute'import_name("tone")'> end
global TONE_PULSE1 <comptime> = 0
global TONE_PULSE2 <comptime> = 1
global TONE_TRIANGLE <comptime> = 2
global TONE_NOISE <comptime> = 3
global TONE_MODE1 <comptime> = 0
global TONE_MODE2 <comptime> = 4
global TONE_MODE3 <comptime> = 8
global TONE_MODE4 <comptime> = 12
-- ┌───────────────────────────────────────────────────────────────────────────┐
-- │ │
-- │ Storage Functions │
-- │ │
-- └───────────────────────────────────────────────────────────────────────────┘
-- Reads up to `size` bytes from persistent storage into the pointer `dest`.
global function diskr(dest: pointer, size: uint32): uint32 <cimport,cattribute'import_name("diskr")'> end
-- Writes up to `size` bytes from the pointer `src` into persistent storage.
global function diskw(src: pointer, size: uint32): uint32 <cimport,cattribute'import_name("diskw")'> end
-- ┌───────────────────────────────────────────────────────────────────────────┐
-- │ │
-- │ Trace functions │
-- │ │
-- └───────────────────────────────────────────────────────────────────────────┘
-- Prints a message to the debug console.
global function trace(str: cstring): void <cimport,cattribute'import_name("trace")'> end
-- Prints a message to the debug console (C style printf).
global function tracef(format: cstring, ...: cvarargs): void <cimport,cattribute'import_name("tracef"),__format__ (__printf__, 1, 2)'> end
-- ┌───────────────────────────────────────────────────────────────────────────┐
-- │ │
-- │ Nelua hooks and compiler configuration │
-- │ │
-- └───────────────────────────────────────────────────────────────────────────┘
## if not pragmas.nogc then
require 'allocators.gc'
## end
require "stringbuilder" -- for `print()`
-- Hook runtime errors to write using `trace()` instead of writing to C `stderr`.
local function write_stderr(msg: cstring, len: usize, flush: boolean): void <codename "nelua_write_stderr">
trace(msg)
end
-- Replace global print function to write using `trace()` instead of writing to C `stdout`.
global function print(...: varargs)
local sb: stringbuilder <close>
## for i=1,select('#', ...) do
## if i > 1 then
sb:write('\t')
## end
sb:write(#[select(i, ...)]#)
## end
trace(sb:view())
end
-- Macro used to install `update` and `_start` WASM4 callbacks.
## function setup_wasm4_callbacks(update)
## static_assert(update, 'please declare update function!')
local function _update(): void <cexport,codename'update'>
#[update]#()
## if not pragmas.nogc then
-- We must always manually call garbage collection in the end of every frame.
-- This is the only safe point to do so, because in WASM we cannot scan the function stack.
gc:step()
## end
end
-- Hook application entry point.
local function _start(): void <cexport,entrypoint>
## if not pragmas.nogc then
-- The GC should be initialized as the first thing.
gc:init(nilptr)
## end
local function nelua_main(argc: cint, argv: *cstring): cint <cimport,nodecl> end
-- This will all code in top scopes.
nelua_main(0,nilptr)
end
## end