mirror of
https://github.com/exoticorn/microw8.git
synced 2026-11-13 23:17:19 +01:00
move all imports to module "env", some tweaks to rust example
This commit is contained in:
1 parent
32d2519d2d
commit
d86f91789b
8 files changed
+113
-73
No files matched your search
@@ -5,8 +5,8 @@ A nightly rust compiler is needed for the unstable sqrtf32
|
|||||||
intrinsic.
|
intrinsic.
|
||||||
|
|
||||||
Simply compiling with rustc as shown in build.sh results in a
|
Simply compiling with rustc as shown in build.sh results in a
|
||||||
339 byte tunnel.wasm. Using wasm-opt this can be reduced to
|
342 byte tunnel.wasm. Using wasm-opt this can be reduced to
|
||||||
244 bytes.
|
243 bytes.
|
||||||
|
|
||||||
When you disassemble this wasm file using wasm2wat you can see
|
When you disassemble this wasm file using wasm2wat you can see
|
||||||
these globals and exports:
|
these globals and exports:
|
||||||
@@ -21,5 +21,5 @@ values that are not simple scalars (i32, f32, etc.). Since our
|
|||||||
code doesn't actually use any of that, we can just delete them
|
code doesn't actually use any of that, we can just delete them
|
||||||
in a text editor and assemble the code again with wat2wasm.
|
in a text editor and assemble the code again with wat2wasm.
|
||||||
|
|
||||||
This gives us a 200 byte wasm file. Running this through
|
This gives us a 199 byte wasm file. Running this through
|
||||||
uw8-tool pack brings us to the final size of 137 bytes.
|
uw8-tool pack brings us to the final size of 137 bytes.
|
||||||
+29
-11
@@ -1,25 +1,43 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
|
|
||||||
#[link(wasm_import_module = "math")]
|
mod env {
|
||||||
extern "C" {
|
// "env" is the default module for imports, but it is still needed here
|
||||||
fn atan2(x: f32, y: f32) -> f32;
|
// since there is a compiler builtin of the same name which is used
|
||||||
|
// if we don't make it clear that this is a module import.
|
||||||
|
#[link(wasm_import_module = "env")]
|
||||||
|
extern "C" {
|
||||||
|
pub fn atan2(x: f32, y: f32) -> f32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn atan2(x: f32, y: f32) -> f32 {
|
||||||
|
unsafe { env::atan2(x, y) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sqrt(v: f32) -> f32 {
|
fn sqrt(v: f32) -> f32 {
|
||||||
unsafe { core::intrinsics::sqrtf32(v) }
|
unsafe { core::intrinsics::sqrtf32(v) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ftoi(v: f32) -> i32 {
|
||||||
|
// The compiler is allowed to do bad things to our code if this
|
||||||
|
// ever results in a value that doesn't fit in an i32.
|
||||||
|
// (the joy of undefined behavior)
|
||||||
|
// But that would trap in wasm anyway, so we don't really
|
||||||
|
// care.
|
||||||
|
unsafe { v.to_int_unchecked() }
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn tic(time: i32) {
|
pub fn tic(time: i32) {
|
||||||
unsafe {
|
for i in 0..320 * 256 {
|
||||||
for i in 0..320 * 256 {
|
let t = time as f32 / 10 as f32;
|
||||||
let t = time as f32 / 10 as f32;
|
let x = (i % 320 - 160) as f32;
|
||||||
let x = (i % 320 - 160) as f32;
|
let y = (i / 320 - 128) as f32;
|
||||||
let y = (i / 320 - 128) as f32;
|
let d = 20000 as f32 / sqrt(x * x + y * y + 1 as f32);
|
||||||
let d = 20000 as f32 / sqrt(x * x + y * y + 1 as f32);
|
let u = atan2(x, y) * 512f32 / 3.141;
|
||||||
let u = atan2(x, y) * 512f32 / 3.141;
|
let c = (ftoi(d + t) ^ ftoi(u + t)) as u8;
|
||||||
let c = ((d + t).to_int_unchecked::<i32>() ^ (u + t).to_int_unchecked::<i32>()) as u8;
|
unsafe {
|
||||||
*((120 + i) as *mut u8) = c;
|
*((120 + i) as *mut u8) = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
/public/
|
||||||
+11
-12
@@ -14,19 +14,18 @@ at offset 120 in memory.
|
|||||||
|
|
||||||
The memory has to be imported as `"env" "memory"` and has a maximum size of 256kb (4 pages).
|
The memory has to be imported as `"env" "memory"` and has a maximum size of 256kb (4 pages).
|
||||||
|
|
||||||
Other imports provided by the platform:
|
Other imports provided by the platform, also all in module `env`:
|
||||||
|
|
||||||
* in module `math`:
|
* `fn acos(f32) -> f32`
|
||||||
* * `fn acos(f32) -> f32`
|
* `fn asin(f32) -> f32`
|
||||||
* * `fn asin(f32) -> f32`
|
* `fn atan(f32) -> f32`
|
||||||
* * `fn atan(f32) -> f32`
|
* `fn atan2(f32, f32) -> f32`
|
||||||
* * `fn atan2(f32, f32) -> f32`
|
* `fn cos(f32) -> f32`
|
||||||
* * `fn cos(f32) -> f32`
|
* `fn exp(f32, f32) -> f32`
|
||||||
* * `fn exp(f32, f32) -> f32`
|
* `fn log(f32) -> f32`
|
||||||
* * `fn log(f32) -> f32`
|
* `fn sin(f32) -> f32`
|
||||||
* * `fn sin(f32) -> f32`
|
* `fn tan(f32) -> f32`
|
||||||
* * `fn tan(f32) -> f32`
|
* `fn pow(f32) -> f32`
|
||||||
* * `fn pow(f32) -> f32`
|
|
||||||
|
|
||||||
## `.uw8` format
|
## `.uw8` format
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<!doctype html><html><head><meta charset="utf8"><title>MicroW8</title><link href="https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@500&display=swap" rel="stylesheet"><style>body,canvas,html{margin:0;padding:0}html{background-color:#202024;color:#808070;font-family:Josefin Sans,Verdana,Arial Black,sans-serif}body,html{height:100%}body{display:grid;grid-template-rows:1fr 0fr}#centered{align-self:center;justify-self:center}.footer{color:#202420}a{color:#303630}a:hover{color:#405040}canvas{background-color:#202428;border:4px solid #303040;box-shadow:5px 5px 20px #000}#message,canvas{margin-bottom:8px}.error{color:#e04030}button{background-color:#303440;border:1px solid #404040;border-radius:4px;color:#808070;font-family:inherit;padding:4px}button:hover{background-color:#202010}button:active{background-color:#504450}</style></head><body> <div id="centered"> <canvas id="screen" width="640" height="512"></canvas> <div id="message"></div> <button id="cartButton">Load cart...</button> </div> <div id="footer"> <a href="http://unlicense.org/" ref="license">Unlicense</a> </div> </body><script type="module">function A(A){return A&&A.__esModule?A.default:A}function e(A,e){let t=A?`${A} bytes`:"Insert cart";e&&(t+=` - <span class="error">${e.replaceAll("<","<")}</span>`),document.getElementById("message").innerHTML=t}let t=document.createElement("canvas");t.width=320,t.height=256;let n,c=t.getContext("2d"),f=c.createImageData(320,256),a=document.getElementById("screen"),l=a.getContext("2d");async function X(X){n&&(n(),n=null);let g=X.byteLength;if(e(g),0==g)return;let Z=new Uint8Array(X),y=window.location.pathname;if(g<=1024){let A="";for(let e of Z)A+=String.fromCharCode(e);y+="#"+btoa(A)}y!=window.location.pathname+window.location.hash&&history.pushState(null,null,y),a.width=a.width;try{let a={env:{memory:new WebAssembly.Memory({initial:8})}},y=a.env.memory.buffer,d=await async function(A,e){let t=await(await fetch(A)).arrayBuffer(),n=await WebAssembly.compile(t);return new WebAssembly.Instance(n,e)}(A("data:application/wasm;base64,AGFzbQEAAAABGgRgBH9%2Ff38Bf2ABfwF%2FYAJ%2FfwF%2FYAN%2Ff38AAg8BA2VudgZtZW1vcnkCAAgDBQQAAQIDBwwBCGxvYWRfdXc4AAAKtAIErwEBBX8gAC0AAEEARgRAIAMgACABIABrIgQQAyADIARqDwsgAyACQQgQAyACQQhqIQIgA0EIaiEFIABBAWohBgNAIAYgAUggAiADTiAGLQAAIAItAABMcnEEQCAFIAUgBhACIgdqIQUgAiADSCAGLQAAIAItAABGcQRAIAIgAhABaiECCyAGIAdqIQYMAQsgAiADSARAIAUgBSACEAIiCGohBSACIAhqIQIMAQsLIAULRwEEfyAAQQFqIQFBACECQQAhAwNAIAIgAS0AACIEQf8AcSADdHIhAiADQQdqIQMgAUEBaiEBIARBgAFxDQALIAEgAGsgAmoLEgEBfyAAIAEgARABIgIQAyACCyYAIAJBAEoEQANAIAAgAkEBayICaiABIAJqLQAAOgAAIAINAAsLCw%3D%3D"),a),i=await(await fetch(A("data:application/wasm;base64,AGFzbQEAAAABugM%2FYAAAYAABf2AAAX1gAX8AYAF%2FAX9gAX8BfWABfQBgAX0Bf2ABfQF9YAJ%2FfwBgAn9%2FAX9gAn9%2FAX1gAn1%2FAGACfX8Bf2ACfX8BfWACfX0AYAJ9fQF%2FYAJ9fQF9YAN%2Ff38AYAN%2Ff38Bf2ADf39%2FAX1gA31%2FfwBgA31%2FfwF%2FYAN9f38BfWADfX1%2FAGADfX1%2FAX9gA319fwF9YAN9fX0AYAN9fX0Bf2ADfX19AX1gBH9%2Ff38AYAR%2Ff39%2FAX9gBH9%2Ff38BfWAEfX9%2FfwBgBH1%2Ff38Bf2AEfX9%2FfwF9YAR9fX9%2FAGAEfX1%2FfwF%2FYAR9fX9%2FAX1gBH19fX8AYAR9fX1%2FAX9gBH19fX8BfWAEfX19fQBgBH19fX0Bf2AEfX19fQF9YAV%2Ff39%2FfwBgBX9%2Ff39%2FAX9gBX9%2Ff39%2FAX1gBX1%2Ff39%2FAGAFfX9%2Ff38Bf2AFfX9%2Ff38BfWAFfX1%2Ff38AYAV9fX9%2FfwF%2FYAV9fX9%2FfwF9YAV9fX1%2FfwBgBX19fX9%2FAX9gBX19fX9%2FAX1gBX19fX1%2FAGAFfX19fX8Bf2AFfX19fX8BfWAFfX19fX0AYAV9fX19fQF%2FYAV9fX19fQF9Ap0IQQRtYXRoA3NpbgAIBG1hdGgDY29zAAgEbWF0aAN0YW4ACARtYXRoBGFzaW4ACARtYXRoBGFjb3MACARtYXRoBGF0YW4ACARtYXRoBWF0YW4yABEEbWF0aANwb3cAEQRtYXRoA2xvZwAIA3V3OAlyZXNlcnZlZDkAAAN1dzgKcmVzZXJ2ZWQxMAAAA3V3OApyZXNlcnZlZDExAAADdXc4CnJlc2VydmVkMTIAAAN1dzgKcmVzZXJ2ZWQxMwAAA3V3OApyZXNlcnZlZDE0AAADdXc4CnJlc2VydmVkMTUAAAN1dzgKcmVzZXJ2ZWQxNgAAA3V3OApyZXNlcnZlZDE3AAADdXc4CnJlc2VydmVkMTgAAAN1dzgKcmVzZXJ2ZWQxOQAAA3V3OApyZXNlcnZlZDIwAAADdXc4CnJlc2VydmVkMjEAAAN1dzgKcmVzZXJ2ZWQyMgAAA3V3OApyZXNlcnZlZDIzAAADdXc4CnJlc2VydmVkMjQAAAN1dzgKcmVzZXJ2ZWQyNQAAA3V3OApyZXNlcnZlZDI2AAADdXc4CnJlc2VydmVkMjcAAAN1dzgKcmVzZXJ2ZWQyOAAAA3V3OApyZXNlcnZlZDI5AAADdXc4CnJlc2VydmVkMzAAAAN1dzgKcmVzZXJ2ZWQzMQAAA3V3OApyZXNlcnZlZDMyAAADdXc4CnJlc2VydmVkMzMAAAN1dzgKcmVzZXJ2ZWQzNAAAA3V3OApyZXNlcnZlZDM1AAADdXc4CnJlc2VydmVkMzYAAAN1dzgKcmVzZXJ2ZWQzNwAAA3V3OApyZXNlcnZlZDM4AAADdXc4CnJlc2VydmVkMzkAAAN1dzgKcmVzZXJ2ZWQ0MAAAA3V3OApyZXNlcnZlZDQxAAADdXc4CnJlc2VydmVkNDIAAAN1dzgKcmVzZXJ2ZWQ0MwAAA3V3OApyZXNlcnZlZDQ0AAADdXc4CnJlc2VydmVkNDUAAAN1dzgKcmVzZXJ2ZWQ0NgAAA3V3OApyZXNlcnZlZDQ3AAADdXc4CnJlc2VydmVkNDgAAAN1dzgKcmVzZXJ2ZWQ0OQAAA3V3OApyZXNlcnZlZDUwAAADdXc4CnJlc2VydmVkNTEAAAN1dzgKcmVzZXJ2ZWQ1MgAAA3V3OApyZXNlcnZlZDUzAAADdXc4CnJlc2VydmVkNTQAAAN1dzgKcmVzZXJ2ZWQ1NQAAA3V3OApyZXNlcnZlZDU2AAADdXc4CnJlc2VydmVkNTcAAAN1dzgKcmVzZXJ2ZWQ1OAAAA3V3OApyZXNlcnZlZDU5AAADdXc4CnJlc2VydmVkNjAAAAN1dzgKcmVzZXJ2ZWQ2MQAAA3V3OApyZXNlcnZlZDYyAAADdXc4CnJlc2VydmVkNjMAAANlbnYGbWVtb3J5AgAEAwIBAwcHAQN0aWMAQAoEAQIACw%3D%3D"))).arrayBuffer();if(0!=Z[0]){new Uint8Array(y).set(Z),new Uint8Array(y).set(new Uint8Array(i),X.byteLength);let A=X.byteLength+i.byteLength,e=d.exports.load_uw8(0,X.byteLength,X.byteLength,A);X=new ArrayBuLine truncated
|
<!doctype html><html><head><meta charset="utf8"><title>MicroW8</title><link href="https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@500&display=swap" rel="stylesheet"><style>body,canvas,html{margin:0;padding:0}html{background-color:#202024;color:#808070;font-family:Josefin Sans,Verdana,Arial Black,sans-serif}body,html{height:100%}body{display:grid;grid-template-rows:1fr 0fr}#centered{align-self:center;justify-self:center}.footer{color:#202420}a{color:#303630}a:hover{color:#405040}canvas{background-color:#202428;border:4px solid #303040;box-shadow:5px 5px 20px #000}#message,canvas{margin-bottom:8px}.error{color:#e04030}button{background-color:#303440;border:1px solid #404040;border-radius:4px;color:#808070;font-family:inherit;padding:4px}button:hover{background-color:#202010}button:active{background-color:#504450}</style></head><body> <div id="centered"> <canvas id="screen" width="640" height="512"></canvas> <div id="message"></div> <button id="cartButton">Load cart...</button> </div> <div id="footer"> <a href="http://unlicense.org/" ref="license">Unlicense</a> </div> </body><script type="module">function A(A){return A&&A.__esModule?A.default:A}function n(A,n){let e=A?`${A} bytes`:"Insert cart";n&&(e+=` - <span class="error">${n.replaceAll("<","<")}</span>`),document.getElementById("message").innerHTML=e}let e=document.createElement("canvas");e.width=320,e.height=256;let t,l=e.getContext("2d"),f=l.createImageData(320,256),a=document.getElementById("screen"),c=a.getContext("2d");async function Z(Z){t&&(t(),t=null);let g=Z.byteLength;if(n(g),0==g)return;let X=new Uint8Array(Z),y=window.location.pathname;if(g<=1024){let A="";for(let n of X)A+=String.fromCharCode(n);y+="#"+btoa(A)}y!=window.location.pathname+window.location.hash&&history.pushState(null,null,y),a.width=a.width;try{let a={env:{memory:new WebAssembly.Memory({initial:8})}},y=a.env.memory.buffer,i=await async function(A,n){let e=await(await fetch(A)).arrayBuffer(),t=await WebAssembly.compile(e);return new WebAssembly.Instance(t,n)}(A("data:application/wasm;base64,AGFzbQEAAAABGgRgBH9%2Ff38Bf2ABfwF%2FYAJ%2FfwF%2FYAN%2Ff38AAg8BA2VudgZtZW1vcnkCAAgDBQQAAQIDBwwBCGxvYWRfdXc4AAAKtAIErwEBBX8gAC0AAEEARgRAIAMgACABIABrIgQQAyADIARqDwsgAyACQQgQAyACQQhqIQIgA0EIaiEFIABBAWohBgNAIAYgAUggAiADTiAGLQAAIAItAABMcnEEQCAFIAUgBhACIgdqIQUgAiADSCAGLQAAIAItAABGcQRAIAIgAhABaiECCyAGIAdqIQYMAQsgAiADSARAIAUgBSACEAIiCGohBSACIAhqIQIMAQsLIAULRwEEfyAAQQFqIQFBACECQQAhAwNAIAIgAS0AACIEQf8AcSADdHIhAiADQQdqIQMgAUEBaiEBIARBgAFxDQALIAEgAGsgAmoLEgEBfyAAIAEgARABIgIQAyACCyYAIAJBAEoEQANAIAAgAkEBayICaiABIAJqLQAAOgAAIAINAAsLCw%3D%3D"),a),m=await(await fetch(A("data:application/wasm;base64,AGFzbQEAAAABugM%2FYAAAYAABf2AAAX1gAX8AYAF%2FAX9gAX8BfWABfQBgAX0Bf2ABfQF9YAJ%2FfwBgAn9%2FAX9gAn9%2FAX1gAn1%2FAGACfX8Bf2ACfX8BfWACfX0AYAJ9fQF%2FYAJ9fQF9YAN%2Ff38AYAN%2Ff38Bf2ADf39%2FAX1gA31%2FfwBgA31%2FfwF%2FYAN9f38BfWADfX1%2FAGADfX1%2FAX9gA319fwF9YAN9fX0AYAN9fX0Bf2ADfX19AX1gBH9%2Ff38AYAR%2Ff39%2FAX9gBH9%2Ff38BfWAEfX9%2FfwBgBH1%2Ff38Bf2AEfX9%2FfwF9YAR9fX9%2FAGAEfX1%2FfwF%2FYAR9fX9%2FAX1gBH19fX8AYAR9fX1%2FAX9gBH19fX8BfWAEfX19fQBgBH19fX0Bf2AEfX19fQF9YAV%2Ff39%2FfwBgBX9%2Ff39%2FAX9gBX9%2Ff39%2FAX1gBX1%2Ff39%2FAGAFfX9%2Ff38Bf2AFfX9%2Ff38BfWAFfX1%2Ff38AYAV9fX9%2FfwF%2FYAV9fX9%2FfwF9YAV9fX1%2FfwBgBX19fX9%2FAX9gBX19fX9%2FAX1gBX19fX1%2FAGAFfX19fX8Bf2AFfX19fX8BfWAFfX19fX0AYAV9fX19fQF%2FYAV9fX19fQF9ApQIQQNlbnYDc2luAAgDZW52A2NvcwAIA2VudgN0YW4ACANlbnYEYXNpbgAIA2VudgRhY29zAAgDZW52BGF0YW4ACANlbnYFYXRhbjIAEQNlbnYDcG93ABEDZW52A2xvZwAIA2VudglyZXNlcnZlZDkAAANlbnYKcmVzZXJ2ZWQxMAAAA2VudgpyZXNlcnZlZDExAAADZW52CnJlc2VydmVkMTIAAANlbnYKcmVzZXJ2ZWQxMwAAA2VudgpyZXNlcnZlZDE0AAADZW52CnJlc2VydmVkMTUAAANlbnYKcmVzZXJ2ZWQxNgAAA2VudgpyZXNlcnZlZDE3AAADZW52CnJlc2VydmVkMTgAAANlbnYKcmVzZXJ2ZWQxOQAAA2VudgpyZXNlcnZlZDIwAAADZW52CnJlc2VydmVkMjEAAANlbnYKcmVzZXJ2ZWQyMgAAA2VudgpyZXNlcnZlZDIzAAADZW52CnJlc2VydmVkMjQAAANlbnYKcmVzZXJ2ZWQyNQAAA2VudgpyZXNlcnZlZDI2AAADZW52CnJlc2VydmVkMjcAAANlbnYKcmVzZXJ2ZWQyOAAAA2VudgpyZXNlcnZlZDI5AAADZW52CnJlc2VydmVkMzAAAANlbnYKcmVzZXJ2ZWQzMQAAA2VudgpyZXNlcnZlZDMyAAADZW52CnJlc2VydmVkMzMAAANlbnYKcmVzZXJ2ZWQzNAAAA2VudgpyZXNlcnZlZDM1AAADZW52CnJlc2VydmVkMzYAAANlbnYKcmVzZXJ2ZWQzNwAAA2VudgpyZXNlcnZlZDM4AAADZW52CnJlc2VydmVkMzkAAANlbnYKcmVzZXJ2ZWQ0MAAAA2VudgpyZXNlcnZlZDQxAAADZW52CnJlc2VydmVkNDIAAANlbnYKcmVzZXJ2ZWQ0MwAAA2VudgpyZXNlcnZlZDQ0AAADZW52CnJlc2VydmVkNDUAAANlbnYKcmVzZXJ2ZWQ0NgAAA2VudgpyZXNlcnZlZDQ3AAADZW52CnJlc2VydmVkNDgAAANlbnYKcmVzZXJ2ZWQ0OQAAA2VudgpyZXNlcnZlZDUwAAADZW52CnJlc2VydmVkNTEAAANlbnYKcmVzZXJ2ZWQ1MgAAA2VudgpyZXNlcnZlZDUzAAADZW52CnJlc2VydmVkNTQAAANlbnYKcmVzZXJ2ZWQ1NQAAA2VudgpyZXNlcnZlZDU2AAADZW52CnJlc2VydmVkNTcAAANlbnYKcmVzZXJ2ZWQ1OAAAA2VudgpyZXNlcnZlZDU5AAADZW52CnJlc2VydmVkNjAAAANlbnYKcmVzZXJ2ZWQ2MQAAA2VudgpyZXNlcnZlZDYyAAADZW52CnJlc2VydmVkNjMAAANlbnYGbWVtb3J5AgAEAwIBAwcHAQN0aWMAQAoEAQIACw%3D%3D"))).arrayBuffer();if(0!=X[0]){new Uint8Array(y).set(X),new Uint8Array(y).set(new Uint8Array(m),Z.byteLength);let A=Z.byteLength+m.byteLength,n=i.exports.load_uw8(0,Z.byteLength,Z.byteLength,A);Z=new ArrayBuffer(n-A),neLine truncated
|
||||||
+50
-26
@@ -1,25 +1,25 @@
|
|||||||
use std::{collections::HashMap, fs::File, path::Path};
|
use std::{collections::HashMap, fs::File, path::Path};
|
||||||
|
|
||||||
|
use anyhow::{bail, Result};
|
||||||
|
use std::io::prelude::*;
|
||||||
use wasm_encoder::{
|
use wasm_encoder::{
|
||||||
CodeSection, EntityType, Export, ExportSection, Function, FunctionSection,
|
CodeSection, EntityType, Export, ExportSection, Function, FunctionSection, ImportSection,
|
||||||
ImportSection, Instruction, MemoryType, Module, TypeSection, ValType,
|
Instruction, MemoryType, Module, TypeSection, ValType,
|
||||||
};
|
};
|
||||||
use ValType::*;
|
use ValType::*;
|
||||||
use anyhow::{Result, bail};
|
|
||||||
use std::io::prelude::*;
|
|
||||||
|
|
||||||
pub struct BaseModule {
|
pub struct BaseModule {
|
||||||
pub types: Vec<FunctionType>,
|
pub types: Vec<FunctionType>,
|
||||||
pub function_imports: Vec<(&'static str, String, u32)>,
|
pub function_imports: Vec<(&'static str, String, u32)>,
|
||||||
pub functions: Vec<u32>,
|
pub functions: Vec<u32>,
|
||||||
pub exports: Vec<(&'static str, u32)>,
|
pub exports: Vec<(&'static str, u32)>,
|
||||||
pub memory: u32
|
pub memory: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct FunctionType {
|
pub struct FunctionType {
|
||||||
pub params: Vec<ValType>,
|
pub params: Vec<ValType>,
|
||||||
pub result: Option<ValType>
|
pub result: Option<ValType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BaseModule {
|
impl BaseModule {
|
||||||
@@ -48,18 +48,24 @@ impl BaseModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut functions = vec![];
|
let mut functions = vec![];
|
||||||
add_function(&mut functions, &type_map, "math","sin", &[F32], Some(F32));
|
add_function(&mut functions, &type_map, "sin", &[F32], Some(F32));
|
||||||
add_function(&mut functions, &type_map, "math", "cos", &[F32], Some(F32));
|
add_function(&mut functions, &type_map, "cos", &[F32], Some(F32));
|
||||||
add_function(&mut functions, &type_map, "math", "tan", &[F32], Some(F32));
|
add_function(&mut functions, &type_map, "tan", &[F32], Some(F32));
|
||||||
add_function(&mut functions, &type_map, "math", "asin", &[F32], Some(F32));
|
add_function(&mut functions, &type_map, "asin", &[F32], Some(F32));
|
||||||
add_function(&mut functions, &type_map, "math", "acos", &[F32], Some(F32));
|
add_function(&mut functions, &type_map, "acos", &[F32], Some(F32));
|
||||||
add_function(&mut functions, &type_map, "math", "atan", &[F32], Some(F32));
|
add_function(&mut functions, &type_map, "atan", &[F32], Some(F32));
|
||||||
add_function(&mut functions, &type_map, "math", "atan2", &[F32, F32], Some(F32));
|
add_function(&mut functions, &type_map, "atan2", &[F32, F32], Some(F32));
|
||||||
add_function(&mut functions, &type_map, "math", "pow", &[F32, F32], Some(F32));
|
add_function(&mut functions, &type_map, "pow", &[F32, F32], Some(F32));
|
||||||
add_function(&mut functions, &type_map, "math", "log", &[F32], Some(F32));
|
add_function(&mut functions, &type_map, "log", &[F32], Some(F32));
|
||||||
|
|
||||||
for i in functions.len()..64 {
|
for i in functions.len()..64 {
|
||||||
add_function(&mut functions, &type_map, "uw8", &format!("reserved{}", i), &[], None);
|
add_function(
|
||||||
|
&mut functions,
|
||||||
|
&type_map,
|
||||||
|
&format!("reserved{}", i),
|
||||||
|
&[],
|
||||||
|
None,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let first_function = functions.len() as u32;
|
let first_function = functions.len() as u32;
|
||||||
@@ -69,7 +75,7 @@ impl BaseModule {
|
|||||||
function_imports: functions,
|
function_imports: functions,
|
||||||
functions: vec![lookup_type(&type_map, &[I32], None)],
|
functions: vec![lookup_type(&type_map, &[I32], None)],
|
||||||
exports: vec![("tic", first_function)],
|
exports: vec![("tic", first_function)],
|
||||||
memory: 4
|
memory: 4,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,11 +98,15 @@ impl BaseModule {
|
|||||||
imports.import(*module, Some(name.as_str()), EntityType::Function(*type_));
|
imports.import(*module, Some(name.as_str()), EntityType::Function(*type_));
|
||||||
}
|
}
|
||||||
|
|
||||||
imports.import("env", Some("memory"), MemoryType {
|
imports.import(
|
||||||
minimum: m.memory as u64,
|
"env",
|
||||||
maximum: None,
|
Some("memory"),
|
||||||
memory64: false
|
MemoryType {
|
||||||
});
|
minimum: m.memory as u64,
|
||||||
|
maximum: None,
|
||||||
|
memory64: false,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
module.section(&imports);
|
module.section(&imports);
|
||||||
}
|
}
|
||||||
@@ -143,14 +153,28 @@ impl BaseModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_function(functions: &mut Vec<(&'static str, String, u32)>, type_map: &HashMap<FunctionType, u32>, module: &'static str, name: &str, params: &[ValType], result: Option<ValType>) {
|
fn add_function(
|
||||||
functions.push((module, name.to_string(), lookup_type(type_map, params, result)));
|
functions: &mut Vec<(&'static str, String, u32)>,
|
||||||
|
type_map: &HashMap<FunctionType, u32>,
|
||||||
|
name: &str,
|
||||||
|
params: &[ValType],
|
||||||
|
result: Option<ValType>,
|
||||||
|
) {
|
||||||
|
functions.push((
|
||||||
|
"env".into(),
|
||||||
|
name.to_string(),
|
||||||
|
lookup_type(type_map, params, result),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_type(type_map: &HashMap<FunctionType, u32>, params: &[ValType], result: Option<ValType>) -> u32 {
|
fn lookup_type(
|
||||||
|
type_map: &HashMap<FunctionType, u32>,
|
||||||
|
params: &[ValType],
|
||||||
|
result: Option<ValType>,
|
||||||
|
) -> u32 {
|
||||||
let key = FunctionType {
|
let key = FunctionType {
|
||||||
params: params.to_vec(),
|
params: params.to_vec(),
|
||||||
result
|
result,
|
||||||
};
|
};
|
||||||
*type_map.get(&key).unwrap()
|
*type_map.get(&key).unwrap()
|
||||||
}
|
}
|
||||||
+18
-20
@@ -10,7 +10,7 @@ async function loadWasm(url, imports) {
|
|||||||
|
|
||||||
function setMessage(size, error) {
|
function setMessage(size, error) {
|
||||||
let html = size ? `${size} bytes` : 'Insert cart';
|
let html = size ? `${size} bytes` : 'Insert cart';
|
||||||
if(error) {
|
if (error) {
|
||||||
html += ` - <span class="error">${error.replaceAll('<', '<')}</span>`
|
html += ` - <span class="error">${error.replaceAll('<', '<')}</span>`
|
||||||
}
|
}
|
||||||
document.getElementById('message').innerHTML = html;
|
document.getElementById('message').innerHTML = html;
|
||||||
@@ -27,7 +27,7 @@ let canvasCtx = screen.getContext('2d');
|
|||||||
let cancelFunction;
|
let cancelFunction;
|
||||||
|
|
||||||
async function runModule(data) {
|
async function runModule(data) {
|
||||||
if(cancelFunction) {
|
if (cancelFunction) {
|
||||||
cancelFunction();
|
cancelFunction();
|
||||||
cancelFunction = null;
|
cancelFunction = null;
|
||||||
}
|
}
|
||||||
@@ -35,21 +35,21 @@ async function runModule(data) {
|
|||||||
let cartridgeSize = data.byteLength;
|
let cartridgeSize = data.byteLength;
|
||||||
|
|
||||||
setMessage(cartridgeSize);
|
setMessage(cartridgeSize);
|
||||||
if(cartridgeSize == 0) {
|
if (cartridgeSize == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let dataU8Array = new Uint8Array(data);
|
let dataU8Array = new Uint8Array(data);
|
||||||
|
|
||||||
let newURL = window.location.pathname;
|
let newURL = window.location.pathname;
|
||||||
if(cartridgeSize <= 1024) {
|
if (cartridgeSize <= 1024) {
|
||||||
let dataString = '';
|
let dataString = '';
|
||||||
for(let byte of dataU8Array) {
|
for (let byte of dataU8Array) {
|
||||||
dataString += String.fromCharCode(byte);
|
dataString += String.fromCharCode(byte);
|
||||||
}
|
}
|
||||||
newURL += '#' + btoa(dataString);
|
newURL += '#' + btoa(dataString);
|
||||||
}
|
}
|
||||||
if(newURL != window.location.pathname + window.location.hash) {
|
if (newURL != window.location.pathname + window.location.hash) {
|
||||||
history.pushState(null, null, newURL);
|
history.pushState(null, null, newURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ async function runModule(data) {
|
|||||||
|
|
||||||
let baseModule = await (await fetch(baseUrl)).arrayBuffer();
|
let baseModule = await (await fetch(baseUrl)).arrayBuffer();
|
||||||
|
|
||||||
if(dataU8Array[0] != 0) {
|
if (dataU8Array[0] != 0) {
|
||||||
new Uint8Array(loadMem).set(dataU8Array);
|
new Uint8Array(loadMem).set(dataU8Array);
|
||||||
new Uint8Array(loadMem).set(new Uint8Array(baseModule), data.byteLength);
|
new Uint8Array(loadMem).set(new Uint8Array(baseModule), data.byteLength);
|
||||||
|
|
||||||
@@ -82,16 +82,14 @@ async function runModule(data) {
|
|||||||
env: {
|
env: {
|
||||||
memory: new WebAssembly.Memory({ initial: 4, maximum: 4 }),
|
memory: new WebAssembly.Memory({ initial: 4, maximum: 4 }),
|
||||||
},
|
},
|
||||||
math: {},
|
|
||||||
uw8: {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for(let n of ['acos','asin','atan','atan2','cos','exp','log','sin','tan','pow']) {
|
for (let n of ['acos', 'asin', 'atan', 'atan2', 'cos', 'exp', 'log', 'sin', 'tan', 'pow']) {
|
||||||
importObject.math[n] = Math[n];
|
importObject.env[n] = Math[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
for(let i = 9; i < 64; ++i) {
|
for (let i = 9; i < 64; ++i) {
|
||||||
importObject.uw8['reserved' + i] = () => {};
|
importObject.env['reserved' + i] = () => { };
|
||||||
}
|
}
|
||||||
|
|
||||||
let instance = new WebAssembly.Instance(await WebAssembly.compile(data), importObject);
|
let instance = new WebAssembly.Instance(await WebAssembly.compile(data), importObject);
|
||||||
@@ -104,15 +102,15 @@ async function runModule(data) {
|
|||||||
cancelFunction = () => keepRunning = false;
|
cancelFunction = () => keepRunning = false;
|
||||||
|
|
||||||
function mainloop() {
|
function mainloop() {
|
||||||
if(!keepRunning) {
|
if (!keepRunning) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
instance.exports.tic(Date.now() - startTime);
|
instance.exports.tic(Date.now() - startTime);
|
||||||
|
|
||||||
let framebuffer = new Uint8Array(importObject.env.memory.buffer.slice(120, 120 + 320*256));
|
let framebuffer = new Uint8Array(importObject.env.memory.buffer.slice(120, 120 + 320 * 256));
|
||||||
for(let i = 0; i < 320*256; ++i) {
|
for (let i = 0; i < 320 * 256; ++i) {
|
||||||
buffer[i * 4] = framebuffer[i];
|
buffer[i * 4] = framebuffer[i];
|
||||||
buffer[i * 4 + 1] = framebuffer[i];
|
buffer[i * 4 + 1] = framebuffer[i];
|
||||||
buffer[i * 4 + 2] = framebuffer[i];
|
buffer[i * 4 + 2] = framebuffer[i];
|
||||||
@@ -123,13 +121,13 @@ async function runModule(data) {
|
|||||||
canvasCtx.drawImage(framebufferCanvas, 0, 0, 640, 512);
|
canvasCtx.drawImage(framebufferCanvas, 0, 0, 640, 512);
|
||||||
|
|
||||||
window.requestAnimationFrame(mainloop);
|
window.requestAnimationFrame(mainloop);
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
setMessage(cartridgeSize, err.toString());
|
setMessage(cartridgeSize, err.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mainloop();
|
mainloop();
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
setMessage(cartridgeSize, err.toString());
|
setMessage(cartridgeSize, err.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -140,7 +138,7 @@ async function runModuleFromURL(url) {
|
|||||||
|
|
||||||
function runModuleFromHash() {
|
function runModuleFromHash() {
|
||||||
let base64Data = window.location.hash.slice(1);
|
let base64Data = window.location.hash.slice(1);
|
||||||
if(base64Data.length > 0) {
|
if (base64Data.length > 0) {
|
||||||
runModuleFromURL('data:;base64,' + base64Data);
|
runModuleFromURL('data:;base64,' + base64Data);
|
||||||
} else {
|
} else {
|
||||||
runModule(new ArrayBuffer(0));
|
runModule(new ArrayBuffer(0));
|
||||||
@@ -155,7 +153,7 @@ document.getElementById('cartButton').onclick = () => {
|
|||||||
fileInput.type = 'file';
|
fileInput.type = 'file';
|
||||||
fileInput.accept = '.wasm,.uw8,application/wasm';
|
fileInput.accept = '.wasm,.uw8,application/wasm';
|
||||||
fileInput.onchange = () => {
|
fileInput.onchange = () => {
|
||||||
if(fileInput.files.length > 0) {
|
if (fileInput.files.length > 0) {
|
||||||
runModuleFromURL(URL.createObjectURL(fileInput.files[0]));
|
runModuleFromURL(URL.createObjectURL(fileInput.files[0]));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in new issue
Block a user