34 Commits

Author SHA1 Message Date
37f12f5a2c update web runtime 2022-04-04 09:31:43 +02:00
8ad2885a55 implement ring modulation 2022-04-02 18:19:45 +02:00
1917057b81 fixed one pole filter, wide stereo bit 2022-04-02 00:06:04 +02:00
82c1ddb867 improve attack and noise 2022-04-01 00:40:56 +02:00
8713aa8930 adjust tim_ges to new soundchip version 2022-03-19 22:55:40 +01:00
0f82e6e711 removed aliasing in rect and saw oscilators 2022-03-19 14:53:21 +01:00
0ade24ebf6 add source file to build wasm module with just ges emulation 2022-03-19 11:03:05 +01:00
29186c806f add pulse width support to other wave types 2022-03-10 23:05:07 +01:00
b626d2609a implement proper exponential envelope timings 2022-03-09 23:03:15 +01:00
39ead8220f slight optimization, add pulse width modulation to melody voices 2022-03-09 09:22:27 +01:00
ce18a8a162 add initial pulse width support 2022-03-08 22:52:12 +01:00
a15e796489 first full version of time for ges 2022-03-08 22:20:54 +01:00
f178076b86 all basic wave forms, filters, panning 2022-03-08 09:46:35 +01:00
81adcf0198 implement more of the sound-chip 2022-03-07 23:58:54 +01:00
780caf965a sync sound registers to sound thread 2022-03-07 09:35:11 +01:00
2033f9a172 wait for audio ready before starting cart, add button to unsuspend audio
fixes missing sound when auto-starting cart in chrome
2022-03-06 14:08:44 +01:00
0d514c7dd3 steady on now down to 197 bytes 2022-03-06 10:13:48 +01:00
a8eb3bda27 some clean up and optimization on steady on tim 2022-03-05 23:54:13 +01:00
8b765a5742 Merge branch 'master' into sound 2022-03-05 23:10:14 +01:00
7197c11586 fix microw8.html no-autoload mode 2022-03-05 23:10:04 +01:00
99a423619e fix watch mode not working when initial compile fails 2022-03-05 21:18:55 +01:00
9063e872d3 ported steady on tim as a sound test 2022-03-04 23:38:27 +01:00
85240599e8 first working version with sound 2022-03-04 09:50:10 +01:00
35ec5fdb59 add simple bytebeat example to test first implementation with 2022-03-02 22:42:23 +01:00
a6a82ff5a1 update wasmtime version 2022-03-02 21:50:26 +01:00
973814a629 update hero link to 0.1.2 2022-03-02 08:54:34 +01:00
00d21b4745 add include dir to release script 2022-02-28 23:59:51 +01:00
d11b46576a prepare for 0.1.2 release 2022-02-28 23:19:58 +01:00
add49a1f8b fix #2: Crash when drawing zero sized line 2022-02-27 22:09:54 +01:00
8815a8e02e add full dependencies to file watcher 2022-02-27 21:50:33 +01:00
eb7c33d412 update curlywas, use 'include "microw8-api.cwa"' in examples 2022-02-26 23:41:15 +01:00
47ad3b4f30 add command to uw8-tool to write api include file 2022-02-26 22:13:15 +01:00
0f668fb6e9 fix typo in atan2 docs, change 'i' character in font 2022-02-26 21:01:57 +01:00
f876f59e80 Merge branch 'browser-run' into next 2022-02-26 21:00:58 +01:00
43 changed files with 1381 additions and 313 deletions

245
Cargo.lock generated
View File

@@ -2,22 +2,13 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "addr2line"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
dependencies = [
"gimli 0.25.0",
]
[[package]] [[package]]
name = "addr2line" name = "addr2line"
version = "0.17.0" version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
dependencies = [ dependencies = [
"gimli 0.26.1", "gimli",
] ]
[[package]] [[package]]
@@ -68,6 +59,17 @@ dependencies = [
"yansi", "yansi",
] ]
[[package]]
name = "async-trait"
version = "0.1.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@@ -91,12 +93,12 @@ version = "0.3.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6"
dependencies = [ dependencies = [
"addr2line 0.17.0", "addr2line",
"cc", "cc",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"miniz_oxide", "miniz_oxide",
"object 0.27.1", "object",
"rustc-demangle", "rustc-demangle",
] ]
@@ -238,9 +240,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chumsky" name = "chumsky"
version = "0.5.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2d3efff85e8572b1c3fa0127706af58c4fff8458f8d9436d54b1e97573c7a3f" checksum = "8d02796e4586c6c41aeb68eae9bfb4558a522c35f1430c14b40136c3706e09e4"
dependencies = [ dependencies = [
"ahash", "ahash",
] ]
@@ -332,24 +334,24 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-bforest" name = "cranelift-bforest"
version = "0.77.0" version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15013642ddda44eebcf61365b2052a23fd8b7314f90ba44aa059ec02643c5139" checksum = "32f027f29ace03752bb83c112eb4f53744bc4baadf19955e67fcde1d71d2f39d"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
] ]
[[package]] [[package]]
name = "cranelift-codegen" name = "cranelift-codegen"
version = "0.77.0" version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "298f2a7ed5fdcb062d8e78b7496b0f4b95265d20245f2d0ca88f846dd192a3a3" checksum = "6c10af69cbf4e228c11bdc26d8f9d5276773909152a769649a160571b282f92f"
dependencies = [ dependencies = [
"cranelift-bforest", "cranelift-bforest",
"cranelift-codegen-meta", "cranelift-codegen-meta",
"cranelift-codegen-shared", "cranelift-codegen-shared",
"cranelift-entity", "cranelift-entity",
"gimli 0.25.0", "gimli",
"log", "log",
"regalloc", "regalloc",
"smallvec", "smallvec",
@@ -358,34 +360,33 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-codegen-meta" name = "cranelift-codegen-meta"
version = "0.77.0" version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cf504261ac62dfaf4ffb3f41d88fd885e81aba947c1241275043885bc5f0bac" checksum = "290ac14d2cef43cbf1b53ad5c1b34216c9e32e00fa9b6ac57b5e5a2064369e02"
dependencies = [ dependencies = [
"cranelift-codegen-shared", "cranelift-codegen-shared",
"cranelift-entity",
] ]
[[package]] [[package]]
name = "cranelift-codegen-shared" name = "cranelift-codegen-shared"
version = "0.77.0" version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd2a72db4301dbe7e5a4499035eedc1e82720009fb60603e20504d8691fa9cd" checksum = "beb9142d134a03d01e3995e6d8dd3aecf16312261d0cb0c5dcd73d5be2528c1c"
[[package]] [[package]]
name = "cranelift-entity" name = "cranelift-entity"
version = "0.77.0" version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48868faa07cacf948dc4a1773648813c0e453ff9467e800ff10f6a78c021b546" checksum = "1268a50b7cbbfee8514d417fc031cedd9965b15fa9e5ed1d4bc16de86f76765e"
dependencies = [ dependencies = [
"serde", "serde",
] ]
[[package]] [[package]]
name = "cranelift-frontend" name = "cranelift-frontend"
version = "0.77.0" version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "351c9d13b4ecd1a536215ec2fd1c3ee9ee8bc31af172abf1e45ed0adb7a931df" checksum = "97ac0d440469e19ab12183e31a9e41b4efd8a4ca5fbde2a10c78c7bb857cc2a4"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"log", "log",
@@ -395,9 +396,9 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-native" name = "cranelift-native"
version = "0.77.0" version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6df8b556663d7611b137b24db7f6c8d9a8a27d7f29c7ea7835795152c94c1b75" checksum = "794cd1a5694a01c68957f9cfdc5ac092cf8b4e9c2d1697c4a5100f90103e9e9e"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"libc", "libc",
@@ -406,9 +407,9 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-wasm" name = "cranelift-wasm"
version = "0.77.0" version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a69816d90db694fa79aa39b89dda7208a4ac74b6f2b8f3c4da26ee1c8bdfc5e" checksum = "f2ddd4ca6963f6e94d00e8935986411953581ac893587ab1f0eb4f0b5a40ae65"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"cranelift-entity", "cranelift-entity",
@@ -416,7 +417,7 @@ dependencies = [
"itertools", "itertools",
"log", "log",
"smallvec", "smallvec",
"wasmparser 0.80.2", "wasmparser 0.82.0",
"wasmtime-types", "wasmtime-types",
] ]
@@ -498,14 +499,14 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
[[package]] [[package]]
name = "curlywas" name = "curlywas"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/exoticorn/curlywas.git?rev=196719b#196719b35ef377cb7e001554b27ac5de013dcf2b" source = "git+https://github.com/exoticorn/curlywas.git?rev=557c3a84#557c3a842675a1ebd77e84021f9f5236d4fa5648"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"ariadne", "ariadne",
"chumsky", "chumsky",
"pico-args", "pico-args",
"wasm-encoder", "wasm-encoder 0.10.0",
"wasmparser 0.81.0", "wasmparser 0.83.0",
] ]
[[package]] [[package]]
@@ -810,21 +811,15 @@ dependencies = [
[[package]] [[package]]
name = "gimli" name = "gimli"
version = "0.25.0" version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
dependencies = [ dependencies = [
"fallible-iterator", "fallible-iterator",
"indexmap", "indexmap",
"stable_deref_trait", "stable_deref_trait",
] ]
[[package]]
name = "gimli"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
[[package]] [[package]]
name = "glob" name = "glob"
version = "0.3.0" version = "0.3.0"
@@ -1035,6 +1030,12 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
[[package]]
name = "io-lifetimes"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec58677acfea8a15352d42fc87d11d63596ade9239e0a7c9352914417515dbe6"
[[package]] [[package]]
name = "iovec" name = "iovec"
version = "0.1.4" version = "0.1.4"
@@ -1141,6 +1142,12 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "linux-raw-sys"
version = "0.0.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5284f00d480e1c39af34e72f8ad60b94f47007e3481cd3b731c1d67190ddc7b7"
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.14" version = "0.4.14"
@@ -1456,9 +1463,9 @@ dependencies = [
[[package]] [[package]]
name = "object" name = "object"
version = "0.26.2" version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2" checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"indexmap", "indexmap",
@@ -1466,13 +1473,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "object" name = "once_cell"
version = "0.27.1" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "opaque-debug" name = "opaque-debug"
@@ -1729,9 +1733,9 @@ dependencies = [
[[package]] [[package]]
name = "regalloc" name = "regalloc"
version = "0.0.31" version = "0.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "571f7f397d61c4755285cd37853fe8e03271c243424a907415909379659381c5" checksum = "62446b1d3ebf980bdc68837700af1d77b37bc430e524bf95319c6eada2a4cc02"
dependencies = [ dependencies = [
"log", "log",
"rustc-hash", "rustc-hash",
@@ -1788,6 +1792,20 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9466f25b92a648960ac1042fd3baa6b0bf285e60f754d7e5070770c813a177a"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.9" version = "1.0.9"
@@ -2312,7 +2330,7 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]] [[package]]
name = "uw8" name = "uw8"
version = "0.1.1" version = "0.1.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"curlywas", "curlywas",
@@ -2338,7 +2356,7 @@ dependencies = [
"pico-args", "pico-args",
"upkr", "upkr",
"walrus", "walrus",
"wasm-encoder", "wasm-encoder 0.8.0",
"wasmparser 0.81.0", "wasmparser 0.81.0",
] ]
@@ -2506,18 +2524,21 @@ dependencies = [
"leb128", "leb128",
] ]
[[package]]
name = "wasm-encoder"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9d9bf45fc46f71c407837c9b30b1e874197f2dc357588430b21e5017d290ab"
dependencies = [
"leb128",
]
[[package]] [[package]]
name = "wasmparser" name = "wasmparser"
version = "0.77.0" version = "0.77.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35c86d22e720a07d954ebbed772d01180501afe7d03d464f413bb5f8914a8d6" checksum = "b35c86d22e720a07d954ebbed772d01180501afe7d03d464f413bb5f8914a8d6"
[[package]]
name = "wasmparser"
version = "0.80.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "449167e2832691a1bff24cde28d2804e90e09586a448c8e76984792c44334a6b"
[[package]] [[package]]
name = "wasmparser" name = "wasmparser"
version = "0.81.0" version = "0.81.0"
@@ -2525,29 +2546,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc" checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc"
[[package]] [[package]]
name = "wasmtime" name = "wasmparser"
version = "0.30.0" version = "0.82.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899b1e5261e3d3420860dacfb952871ace9d7ba9f953b314f67aaf9f8e2a4d89" checksum = "0559cc0f1779240d6f894933498877ea94f693d84f3ee39c9a9932c6c312bd70"
[[package]]
name = "wasmparser"
version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a"
[[package]]
name = "wasmtime"
version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4882e78d9daceeaff656d82869f298fd472ea8d8ccf96fbd310da5c1687773ac"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait",
"backtrace", "backtrace",
"bincode", "bincode",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"cpp_demangle",
"indexmap", "indexmap",
"lazy_static", "lazy_static",
"libc", "libc",
"log", "log",
"object 0.26.2", "object",
"once_cell",
"paste", "paste",
"psm", "psm",
"rayon", "rayon",
"region", "region",
"rustc-demangle",
"serde", "serde",
"target-lexicon", "target-lexicon",
"wasmparser 0.80.2", "wasmparser 0.82.0",
"wasmtime-cache", "wasmtime-cache",
"wasmtime-cranelift", "wasmtime-cranelift",
"wasmtime-environ", "wasmtime-environ",
@@ -2560,18 +2593,17 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-cache" name = "wasmtime-cache"
version = "0.30.0" version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2493b81d7a9935f7af15e06beec806f256bc974a90a843685f3d61f2fc97058" checksum = "cf5b9af2d970624455f9ea109acc60cc477afe097f86c190eb519a8b7d6646cd"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64", "base64",
"bincode", "bincode",
"directories-next", "directories-next",
"errno",
"file-per-thread-logger", "file-per-thread-logger",
"libc",
"log", "log",
"rustix",
"serde", "serde",
"sha2", "sha2",
"toml", "toml",
@@ -2581,9 +2613,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-cranelift" name = "wasmtime-cranelift"
version = "0.30.0" version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99706bacdf5143f7f967d417f0437cce83a724cf4518cb1a3ff40e519d793021" checksum = "1ed6ff21d2dbfe568af483f0c508e049fc6a497c73635e2c50c9b1baf3a93ed8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
@@ -2591,67 +2623,67 @@ dependencies = [
"cranelift-frontend", "cranelift-frontend",
"cranelift-native", "cranelift-native",
"cranelift-wasm", "cranelift-wasm",
"gimli 0.25.0", "gimli",
"log",
"more-asserts", "more-asserts",
"object 0.26.2", "object",
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmparser 0.80.2", "wasmparser 0.82.0",
"wasmtime-environ", "wasmtime-environ",
] ]
[[package]] [[package]]
name = "wasmtime-environ" name = "wasmtime-environ"
version = "0.30.0" version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac42cb562a2f98163857605f02581d719a410c5abe93606128c59a10e84de85b" checksum = "860936d38df423b4291b3e31bc28d4895e2208f9daba351c2397d18a0a10e0bf"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cfg-if 1.0.0",
"cranelift-entity", "cranelift-entity",
"gimli 0.25.0", "gimli",
"indexmap", "indexmap",
"log", "log",
"more-asserts", "more-asserts",
"object 0.26.2", "object",
"serde", "serde",
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmparser 0.80.2", "wasmparser 0.82.0",
"wasmtime-types", "wasmtime-types",
] ]
[[package]] [[package]]
name = "wasmtime-fiber" name = "wasmtime-fiber"
version = "0.30.0" version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8779dd78755a248512233df4f6eaa6ba075c41bea2085fec750ed2926897bf95" checksum = "67e285306aa274d85a22753bef826226e1cc473bac0b541523f46dccf80751cc"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "rustix",
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]] [[package]]
name = "wasmtime-jit" name = "wasmtime-jit"
version = "0.30.0" version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24f46dd757225f29a419be415ea6fb8558df9b0194f07e3a6a9c99d0e14dd534" checksum = "e794310a0df5266c7ac73e8211a024a49e3860ac0ca2af5db8527be942ad063e"
dependencies = [ dependencies = [
"addr2line 0.16.0", "addr2line",
"anyhow", "anyhow",
"bincode", "bincode",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"gimli 0.25.0", "cpp_demangle",
"libc", "gimli",
"log", "log",
"more-asserts", "object",
"object 0.26.2",
"region", "region",
"rustc-demangle",
"rustix",
"serde", "serde",
"target-lexicon", "target-lexicon",
"thiserror", "thiserror",
"wasmparser 0.80.2",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-runtime", "wasmtime-runtime",
"winapi 0.3.9", "winapi 0.3.9",
@@ -2659,9 +2691,9 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-runtime" name = "wasmtime-runtime"
version = "0.30.0" version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0122215a44923f395487048cb0a1d60b5b32c73aab15cf9364b798dbaff0996f" checksum = "90ffe5cb3db705ea43fcf37475a79891a3ada754c1cbe333540879649de943d5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"backtrace", "backtrace",
@@ -2676,6 +2708,7 @@ dependencies = [
"more-asserts", "more-asserts",
"rand", "rand",
"region", "region",
"rustix",
"thiserror", "thiserror",
"wasmtime-environ", "wasmtime-environ",
"wasmtime-fiber", "wasmtime-fiber",
@@ -2684,14 +2717,14 @@ dependencies = [
[[package]] [[package]]
name = "wasmtime-types" name = "wasmtime-types"
version = "0.30.0" version = "0.34.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9b01caf8a204ef634ebac99700e77ba716d3ebbb68a1abbc2ceb6b16dbec9e4" checksum = "70a5b60d70c1927c5a403f7c751de179414b6b91da75b2312c3ae78196cf9dc3"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
"serde", "serde",
"thiserror", "thiserror",
"wasmparser 0.80.2", "wasmparser 0.82.0",
] ]
[[package]] [[package]]
@@ -2856,18 +2889,18 @@ checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
[[package]] [[package]]
name = "zstd" name = "zstd"
version = "0.9.2+zstd.1.5.1" version = "0.10.0+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2390ea1bf6c038c39674f22d95f0564725fc06034a47129179810b2fc58caa54" checksum = "3b1365becbe415f3f0fcd024e2f7b45bacfb5bdd055f0dc113571394114e7bdd"
dependencies = [ dependencies = [
"zstd-safe", "zstd-safe",
] ]
[[package]] [[package]]
name = "zstd-safe" name = "zstd-safe"
version = "4.1.3+zstd.1.5.1" version = "4.1.4+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e99d81b99fb3c2c2c794e3fe56c305c63d5173a16a46b5850b07c935ffc7db79" checksum = "2f7cd17c9af1a4d6c24beb1cc54b17e2ef7b593dc92f19e9d9acad8b182bbaee"
dependencies = [ dependencies = [
"libc", "libc",
"zstd-sys", "zstd-sys",
@@ -2875,9 +2908,9 @@ dependencies = [
[[package]] [[package]]
name = "zstd-sys" name = "zstd-sys"
version = "1.6.2+zstd.1.5.1" version = "1.6.3+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2daf2f248d9ea44454bfcb2516534e8b8ad2fc91bf818a1885495fc42bc8ac9f" checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "uw8" name = "uw8"
version = "0.1.1" version = "0.1.2"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -11,12 +11,12 @@ native = ["wasmtime"]
browser = ["warp", "tokio", "tokio-stream", "webbrowser"] browser = ["warp", "tokio", "tokio-stream", "webbrowser"]
[dependencies] [dependencies]
wasmtime = { version = "0.30", optional = true } wasmtime = { version = "0.34", optional = true }
anyhow = "1" anyhow = "1"
minifb = { version = "0.20", default-features = false, features = ["x11"] } minifb = { version = "0.20", default-features = false, features = ["x11"] }
notify = "4" notify = "4"
pico-args = "0.4" pico-args = "0.4"
curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "196719b" } curlywas = { git = "https://github.com/exoticorn/curlywas.git", rev = "557c3a84" }
wat = "1" wat = "1"
uw8-tool = { path = "uw8-tool" } uw8-tool = { path = "uw8-tool" }
same-file = "1" same-file = "1"

View File

@@ -15,9 +15,9 @@ See [here](https://exoticorn.github.io/microw8/) for more information and docs.
## Downloads ## Downloads
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-linux.tgz) * [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-macos.tgz) * [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.0/microw8-0.1.0-windows.zip) * [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-windows.zip)
The download includes The download includes
@@ -35,6 +35,7 @@ Runs <file> which can be a binary WebAssembly module, an `.uw8` cart, a wat (Web
Options: Options:
-b, --browser : Run in browser instead of using native runtime
-t, --timeout FRAMES : Sets the timeout in frames (1/60s) -t, --timeout FRAMES : Sets the timeout in frames (1/60s)
-w, --watch : Reloads the given file every time it changes on disk. -w, --watch : Reloads the given file every time it changes on disk.
-p, --pack : Pack the file into an .uw8 cart before running it and print the resulting size. -p, --pack : Pack the file into an .uw8 cart before running it and print the resulting size.

View File

@@ -1,5 +1,4 @@
import "env.memory" memory(4); include "../include/microw8-api.cwa"
import "env.printString" fn printString(i32);
export fn upd() { export fn upd() {
printString(0x20000); printString(0x20000);

View File

@@ -1,11 +1,4 @@
import "env.time" fn time() -> f32; include "../include/microw8-api.cwa"
import "env.circle" fn circle(f32, f32, f32, i32);
import "env.cls" fn cls(i32);
import "env.randomSeed" fn seed(i32);
import "env.randomf" fn randomf() -> f32;
import "env.sin" fn sin(f32) -> f32;
import "env.cos" fn cos(f32) -> f32;
import "env.fmod" fn fmod(f32, f32) -> f32;
export fn upd() { export fn upd() {
cls(0); cls(0);
@@ -15,10 +8,10 @@ export fn upd() {
let inline rocket = i #>> 9; let inline rocket = i #>> 9;
let lazy local_time = fmod(time() + rocket as f32 / 5 as f32, 2 as f32); let lazy local_time = fmod(time() + rocket as f32 / 5 as f32, 2 as f32);
let lazy rocket = rocket + nearest(time() - local_time) as i32 * 10; let lazy rocket = rocket + nearest(time() - local_time) as i32 * 10;
seed(rocket); randomSeed(rocket);
let inline x = randomf() * 645 as f32; let inline x = randomf() * 645 as f32;
let y = randomf() * 133 as f32; let y = randomf() * 133 as f32;
let lazy angle = { seed(i); randomf() } * 44 as f32; let lazy angle = { randomSeed(i); randomf() } * 44 as f32;
let inline dx = sin(angle); let inline dx = sin(angle);
let inline dy = cos(angle); let inline dy = cos(angle);
let lazy dist = local_time * (randomf() * 44 as f32); let lazy dist = local_time * (randomf() * 44 as f32);

View File

@@ -1,38 +1,30 @@
import "env.memory" memory(4); include "../include/microw8-api.cwa"
import "env.cls" fn cls(i32);
import "env.printString" fn printString(i32);
import "env.printChar" fn printChar(i32);
import "env.setCursorPosition" fn setCursor(i32, i32);
import "env.setTextColor" fn setTextColor(i32);
import "env.line" fn line(f32, f32, f32, f32, i32);
import "env.isButtonTriggered" fn triggered(i32) -> i32;
global mut mode: i32 = 0; global mut mode: i32 = 0;
export fn upd() { export fn upd() {
cls(0); cls(0);
if triggered(4) { if isButtonTriggered(BUTTON_A) {
mode = !mode; mode = !mode;
} }
setTextColor(15); setTextColor(15);
printString(mode * 0x20000); printString(mode * USER_MEM);
let y: i32; let y: i32;
loop y { loop y {
line(0 as f32, (y * 9 + 39) as f32, (14+16*9) as f32, (y * 9 + 39) as f32, 1); line(0 as f32, (y * 9 + 39) as f32, (14+16*9) as f32, (y * 9 + 39) as f32, 1);
line((y * 9 + 15) as f32, 24 as f32, (y * 9 + 15) as f32, (38+16*9) as f32, 1); line((y * 9 + 15) as f32, 24 as f32, (y * 9 + 15) as f32, (38+16*9) as f32, 1);
setTextColor(15); setTextColor(15);
setCursor(y * 9 + 16, 24); setCursorPosition(y * 9 + 16, 24);
let lazy hexChar = select(y < 10, y + 48, y + 87); let lazy hexChar = select(y < 10, y + 48, y + 87);
printChar(hexChar); printChar(hexChar);
setCursor(0, y * 9 + 24+16); setCursorPosition(0, y * 9 + 24+16);
printChar(hexChar); printChar(hexChar);
let x = 0; let x = 0;
loop x { loop x {
setCursor(x * 9 + 16, y * 9 + 24+16); setCursorPosition(x * 9 + 16, y * 9 + 24+16);
setTextColor(select(mode, x + y * 16, -9)); setTextColor(select(mode, x + y * 16, -9));
if y >= 2 | mode { if y >= 2 | mode {
printChar(select(mode, 0xa4, x + y * 16)); printChar(select(mode, 0xa4, x + y * 16));
@@ -47,6 +39,6 @@ data 0 {
"Default font: (press " i8(0xcc) " for palette)" i8(5, 0) "Default font: (press " i8(0xcc) " for palette)" i8(5, 0)
} }
data 0x20000 { data USER_MEM {
"Default palette: (press " i8(0xcc) " for font)" i8(5, 0) "Default palette: (press " i8(0xcc) " for font)" i8(5, 0)
} }

View File

@@ -1,10 +1,4 @@
import "env.memory" memory(4); include "../include/microw8-api.cwa"
import "env.cls" fn cls(i32);
import "env.time" fn time() -> f32;
import "env.line" fn line(f32, f32, f32, f32, i32);
import "env.sin" fn sin(f32) -> f32;
import "env.cos" fn cos(f32) -> f32;
export fn upd() { export fn upd() {
cls(0); cls(0);

View File

@@ -1,12 +1,4 @@
import "env.memory" memory(4); include "../include/microw8-api.cwa"
import "env.rectangle" fn rect(f32, f32, f32, f32, i32);
import "env.circle" fn circle(f32, f32, f32, i32);
import "env.isButtonPressed" fn btn(i32) -> i32;
import "env.random" fn random() -> i32;
import "env.randomSeed" fn randomSeed(i32);
import "env.cls" fn cls(i32);
import "env.printInt" fn printInt(i32);
global mut pz: i32 = 4; global mut pz: i32 = 4;
global mut px: f32 = 2.0; global mut px: f32 = 2.0;
@@ -19,7 +11,7 @@ export fn upd() {
let inline zero = 0.0; let inline zero = 0.0;
let lazy control_speed = 0.03125; let lazy control_speed = 0.03125;
s = s + 0.1875 - (f + control_speed) * btn(4 <| cls(4)) as f32; s = s + 0.1875 - (f + control_speed) * isButtonPressed(4 <| cls(4)) as f32;
f = f * 0.5625; f = f * 0.5625;
printInt(pz); printInt(pz);
@@ -33,8 +25,8 @@ export fn upd() {
let inline c = (z & 1) * -2; let inline c = (z & 1) * -2;
let inline yf = y as f32; let inline yf = y as f32;
rect(rx, yf, rw, yf / 6 as f32, c + 1); rectangle(rx, yf, rw, yf / 6 as f32, c + 1);
rect(rx, yf, rw, 1 as f32, c - 4); rectangle(rx, yf, rw, 1 as f32, c - 4);
if y == 180 & py > zero { if y == 180 & py > zero {
if x > w | x < zero { if x > w | x < zero {
@@ -51,7 +43,7 @@ export fn upd() {
circle(160 as f32, 160 as f32 + py, 22 as f32, -28); circle(160 as f32, 160 as f32 + py, 22 as f32, -28);
circle((160 - 6) as f32, (160 - 6) as f32 + py, 6 as f32, -26); circle((160 - 6) as f32, (160 - 6) as f32 + py, 6 as f32, -26);
px = px + (btn(3) - btn(2)) as f32 * control_speed; px = px + (isButtonPressed(3) - isButtonPressed(2)) as f32 * control_speed;
py = py + s; py = py + s;
pz = pz + 1; pz = pz + 1;
} }

View File

@@ -0,0 +1,38 @@
// Steady On Tim, It's Only A Budget Game
// by Gasman / Hooy-Program
// ported to MicroW8 by exoticorn/icebird
include "../include/microw8-api.cwa"
fn melody(t: i32, T: i32) -> i32 {
let inline riff_pos = abs(((T&31) - 16) as f32) as i32;
let lazy shift = ((1-((T>>5)&3))%2-1) as f32 / 6 as f32;
let inline note_count = 5 - (T >= 512);
let inline octave = (riff_pos/5) as f32;
let inline riff_note = 5514 >> (riff_pos % note_count * 4) & 15;
let inline melody_freq = pow(2 as f32, shift + octave - (riff_note as f32 / 12 as f32));
let inline melody = (t as f32 * melody_freq) as i32 & 128;
let inline arp_note = ((0x85>>((t>>12)%3*4)) & 15) - 1;
let inline arp_freq = pow(2 as f32, shift + (arp_note as f32 / 12 as f32));
let inline arp_vol = (T >= 256) * (12-T%12);
let inline arpeggio = ((t as f32 * arp_freq) as i32 & 128) * arp_vol / 12;
melody + arpeggio
}
export fn snd(t: i32) -> f32 {
let lazy T = t/10000;
let inline mel_arp = melody(t, T)/3 + melody(t, T-3)/5;
let inline bass_vol = (T >= 128) & (197 >> (T % 8));
let inline bass_freq = pow(2 as f32, (((T & 4) * ((T & 7) - 1)) as f32 / 24 as f32 - 5 as f32));
let inline bass = ((t as f32 * bass_freq) as i32 & 63) * bass_vol;
let inline snare_ish = (random() & 31) * (8 - (T + 4) % 8) / 8;
let inline sample = mel_arp + bass + snare_ish;
sample as f32 / 255 as f32
}

View File

@@ -1,7 +1,4 @@
import "env.memory" memory(4); include "../include/microw8-api.cwa"
import "env.sin" fn sin(f32) -> f32;
import "env.time" fn time() -> f32;
import "env.setPixel" fn setPixel(i32, i32, i32);
export fn upd() { export fn upd() {
let x: i32; let x: i32;

View File

@@ -0,0 +1,59 @@
import "env.memory" memory(4);
fn melody(ch: i32, t: i32, T: i32) {
let lazy riff_pos = abs(((T&31) - 16) as f32) as i32;
let lazy shift = ((1-((T>>5)&3))%2-1) * 2;
let inline note_count = 5 - (T >= 512);
let inline octave = (riff_pos/5) * 12;
let inline riff_note = 5514 >> (riff_pos % note_count * 4) & 15;
let inline melody_note = shift + octave - riff_note;
ch?1 = 248 - riff_pos * 15;
ch?3 = melody_note + 64;
let inline arp_note = shift + ((0x85>>((t/2)%3*4)) & 15) - 1;
80?3 = arp_note + 64;
}
export fn upd() {
let lazy t = 32!32 / (1000/60);
let lazy T = t / 7;
melody(98, t, T - 3);
melody(92, t, T);
80?0 = ((T >= 256) & (T/12+(T-3)/12)) * 2 | 0x44; // arp trigger
if T >= 128 {
let inline bass_step = T % 8;
86?3 = if bass_step / 2 == 2 {
86?0 = 0xc2;
80
} else {
86?0 = ((197 >> bass_step) & 1) | 0x48;
((T & 4) * ((T & 7) - 1)) / 2 + 28
};
}
}
data 80 {
i8(
0, 0x81, 0, 0, 0, 0x90,
0, 0x4c, 0, 0, 0, 0x5c,
5, 0, 0, 0, 0, 0x4c,
5, 0, 0, 0, 0, 0x4c,
0xfa, 0x85,
0x81, 0x81, 0, 110, 0, 90
)
}
/*
include "../../platform/src/ges.cwa"
import "env.pow" fn pow(f32, f32) -> f32;
import "env.sin" fn sin(f32) -> f32;
export fn snd(t: i32) -> f32 {
gesSnd(t)
}
*/

View File

@@ -1,7 +1,4 @@
import "env.memory" memory(2); include "../include/microw8-api.cwa"
import "env.fmod" fn fmod(f32, f32) -> f32;
import "env.time" fn time() -> f32;
export fn upd() { export fn upd() {
let i: i32; let i: i32;

View File

@@ -1,7 +1,4 @@
import "env.memory" memory(4); include "../include/microw8-api.cwa"
import "env.atan2" fn atan2(f32, f32) -> f32;
import "env.time" fn time() -> f32;
export fn upd() { export fn upd() {
let i: i32; let i: i32;
@@ -12,7 +9,7 @@ export fn upd() {
let inline d = 40000 as f32 / sqrt(x * x + y * y); let inline d = 40000 as f32 / sqrt(x * x + y * y);
let inline u = atan2(x, y) * (512.0 / 3.141); let inline u = atan2(x, y) * (512.0 / 3.141);
let inline c = ((i32.trunc_sat_f32_s(d + t * 2 as f32) ^ i32.trunc_sat_f32_s(u + t)) & 255) >> 4; let inline c = ((i32.trunc_sat_f32_s(d + t * 2 as f32) ^ i32.trunc_sat_f32_s(u + t)) & 255) >> 4;
i?120 = c; i?FRAMEBUFFER = c;
branch_if (i := i + 1) < 320*240: pixels; branch_if (i := i + 1) < 320*240: pixels;
} }

View File

@@ -0,0 +1,50 @@
// MicroW8 APIs, to be `include`d in CurlyWas sources
import "env.memory" memory(4);
import "env.sin" fn sin(f32) -> f32;
import "env.cos" fn cos(f32) -> f32;
import "env.tan" fn tan(f32) -> f32;
import "env.asin" fn asin(f32) -> f32;
import "env.acos" fn acos(f32) -> f32;
import "env.atan" fn atan(f32) -> f32;
import "env.atan2" fn atan2(f32, f32) -> f32;
import "env.pow" fn pow(f32, f32) -> f32;
import "env.log" fn log(f32) -> f32;
import "env.fmod" fn fmod(f32, f32) -> f32;
import "env.random" fn random() -> i32;
import "env.randomf" fn randomf() -> f32;
import "env.randomSeed" fn randomSeed(i32);
import "env.cls" fn cls(i32);
import "env.setPixel" fn setPixel(i32, i32, i32);
import "env.getPixel" fn getPixel(i32, i32) -> i32;
import "env.hline" fn hline(i32, i32, i32, i32);
import "env.rectangle" fn rectangle(f32, f32, f32, f32, i32);
import "env.circle" fn circle(f32, f32, f32, i32);
import "env.line" fn line(f32, f32, f32, f32, i32);
import "env.time" fn time() -> f32;
import "env.isButtonPressed" fn isButtonPressed(i32) -> i32;
import "env.isButtonTriggered" fn isButtonTriggered(i32) -> i32;
import "env.printChar" fn printChar(i32);
import "env.printString" fn printString(i32);
import "env.printInt" fn printInt(i32);
import "env.setTextColor" fn setTextColor(i32);
import "env.setBackgroundColor" fn setBackgroundColor(i32);
import "env.setCursorPosition" fn setCursorPosition(i32, i32);
import "env.rectangle_outline" fn rectangle_outline(f32, f32, f32, f32, i32);
import "env.circle_outline" fn circle_outline(f32, f32, f32, i32);
import "env.exp" fn exp(f32) -> f32;
const TIME_MS = 0x40;
const GAMEPAD = 0x44;
const FRAMEBUFFER = 0x78;
const PALETTE = 0x13000;
const FONT = 0x13400;
const USER_MEM = 0x14000;
const BUTTON_UP = 0x0;
const BUTTON_DOWN = 0x1;
const BUTTON_LEFT = 0x2;
const BUTTON_RIGHT = 0x3;
const BUTTON_A = 0x4;
const BUTTON_B = 0x5;
const BUTTON_X = 0x6;
const BUTTON_Y = 0x7;

View File

@@ -0,0 +1,52 @@
;; MicroW8 APIs, in WAT (Wasm Text) format
(import "env" "memory" (memory 4))
(import "env" "sin" (func $sin (param f32) (result f32)))
(import "env" "cos" (func $cos (param f32) (result f32)))
(import "env" "tan" (func $tan (param f32) (result f32)))
(import "env" "asin" (func $asin (param f32) (result f32)))
(import "env" "acos" (func $acos (param f32) (result f32)))
(import "env" "atan" (func $atan (param f32) (result f32)))
(import "env" "atan2" (func $atan2 (param f32) (param f32) (result f32)))
(import "env" "pow" (func $pow (param f32) (param f32) (result f32)))
(import "env" "log" (func $log (param f32) (result f32)))
(import "env" "fmod" (func $fmod (param f32) (param f32) (result f32)))
(import "env" "random" (func $random (result i32)))
(import "env" "randomf" (func $randomf (result f32)))
(import "env" "randomSeed" (func $randomSeed (param i32)))
(import "env" "cls" (func $cls (param i32)))
(import "env" "setPixel" (func $setPixel (param i32) (param i32) (param i32)))
(import "env" "getPixel" (func $getPixel (param i32) (param i32) (result i32)))
(import "env" "hline" (func $hline (param i32) (param i32) (param i32) (param i32)))
(import "env" "rectangle" (func $rectangle (param f32) (param f32) (param f32) (param f32) (param i32)))
(import "env" "circle" (func $circle (param f32) (param f32) (param f32) (param i32)))
(import "env" "line" (func $line (param f32) (param f32) (param f32) (param f32) (param i32)))
(import "env" "time" (func $time (result f32)))
(import "env" "isButtonPressed" (func $isButtonPressed (param i32) (result i32)))
(import "env" "isButtonTriggered" (func $isButtonTriggered (param i32) (result i32)))
(import "env" "printChar" (func $printChar (param i32)))
(import "env" "printString" (func $printString (param i32)))
(import "env" "printInt" (func $printInt (param i32)))
(import "env" "setTextColor" (func $setTextColor (param i32)))
(import "env" "setBackgroundColor" (func $setBackgroundColor (param i32)))
(import "env" "setCursorPosition" (func $setCursorPosition (param i32) (param i32)))
(import "env" "rectangle_outline" (func $rectangle_outline (param f32) (param f32) (param f32) (param f32) (param i32)))
(import "env" "circle_outline" (func $circle_outline (param f32) (param f32) (param f32) (param i32)))
(import "env" "exp" (func $exp (param f32) (result f32)))
;; to use defines, include this file with a preprocessor
;; like gpp (https://logological.org/gpp).
#define TIME_MS 0x40;
#define GAMEPAD 0x44;
#define FRAMEBUFFER 0x78;
#define PALETTE 0x13000;
#define FONT 0x13400;
#define USER_MEM 0x14000;
#define BUTTON_UP 0x0;
#define BUTTON_DOWN 0x1;
#define BUTTON_LEFT 0x2;
#define BUTTON_RIGHT 0x3;
#define BUTTON_A 0x4;
#define BUTTON_B 0x5;
#define BUTTON_X 0x6;
#define BUTTON_Y 0x7;

127
platform/Cargo.lock generated
View File

@@ -79,9 +79,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "chumsky" name = "chumsky"
version = "0.5.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2d3efff85e8572b1c3fa0127706af58c4fff8458f8d9436d54b1e97573c7a3f" checksum = "8d02796e4586c6c41aeb68eae9bfb4558a522c35f1430c14b40136c3706e09e4"
dependencies = [ dependencies = [
"ahash 0.3.8", "ahash 0.3.8",
] ]
@@ -146,14 +146,14 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]] [[package]]
name = "curlywas" name = "curlywas"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/exoticorn/curlywas.git?rev=196719b#196719b35ef377cb7e001554b27ac5de013dcf2b" source = "git+https://github.com/exoticorn/curlywas.git?rev=557c3a84#557c3a842675a1ebd77e84021f9f5236d4fa5648"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"ariadne", "ariadne",
"chumsky", "chumsky",
"pico-args", "pico-args",
"wasm-encoder", "wasm-encoder 0.10.0",
"wasmparser", "wasmparser 0.83.0",
] ]
[[package]] [[package]]
@@ -197,6 +197,21 @@ dependencies = [
"ahash 0.7.6", "ahash 0.7.6",
] ]
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "id-arena"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005"
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@@ -227,6 +242,15 @@ dependencies = [
"rgb", "rgb",
] ]
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
version = "0.4.4" version = "0.4.4"
@@ -286,6 +310,24 @@ version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
[[package]] [[package]]
name = "rgb" name = "rgb"
version = "0.8.31" version = "0.8.31"
@@ -304,6 +346,17 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "syn"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.43" version = "0.1.43"
@@ -323,6 +376,18 @@ dependencies = [
"crunchy", "crunchy",
] ]
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]] [[package]]
name = "upkr" name = "upkr"
version = "0.1.0" version = "0.1.0"
@@ -342,8 +407,9 @@ dependencies = [
"pbr", "pbr",
"pico-args", "pico-args",
"upkr", "upkr",
"wasm-encoder", "walrus",
"wasmparser", "wasm-encoder 0.8.0",
"wasmparser 0.81.0",
] ]
[[package]] [[package]]
@@ -352,6 +418,32 @@ version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "walrus"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb08e48cde54c05f363d984bb54ce374f49e242def9468d2e1b6c2372d291f8"
dependencies = [
"anyhow",
"id-arena",
"leb128",
"log",
"walrus-macro",
"wasmparser 0.77.0",
]
[[package]]
name = "walrus-macro"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e5bd22c71e77d60140b0bd5be56155a37e5bd14e24f5f87298040d0cc40d7"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.10.2+wasi-snapshot-preview1" version = "0.10.2+wasi-snapshot-preview1"
@@ -367,12 +459,33 @@ dependencies = [
"leb128", "leb128",
] ]
[[package]]
name = "wasm-encoder"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa9d9bf45fc46f71c407837c9b30b1e874197f2dc357588430b21e5017d290ab"
dependencies = [
"leb128",
]
[[package]]
name = "wasmparser"
version = "0.77.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b35c86d22e720a07d954ebbed772d01180501afe7d03d464f413bb5f8914a8d6"
[[package]] [[package]]
name = "wasmparser" name = "wasmparser"
version = "0.81.0" version = "0.81.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc" checksum = "98930446519f63d00a836efdc22f67766ceae8dbcc1571379f2bcabc6b2b9abc"
[[package]]
name = "wasmparser"
version = "0.83.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"

View File

@@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
curlywas = { git="https://github.com/exoticorn/curlywas.git", rev="196719b" } curlywas = { git="https://github.com/exoticorn/curlywas.git", rev="557c3a84" }
uw8-tool = { path="../uw8-tool" } uw8-tool = { path="../uw8-tool" }
anyhow = "1" anyhow = "1"
lodepng = "3.4" lodepng = "3.4"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

221
platform/src/ges.cwa Normal file
View File

@@ -0,0 +1,221 @@
const GesChannelState.Trigger = 0;
const GesChannelState.EnvState = 1;
const GesChannelState.EnvVol = 2;
const GesChannelState.Phase = 4;
const GesChannelState.Size = 8;
const GesState.Filter = GesChannelState.Size * 4;
const GesState.Size = GesState.Filter + 8*4;
const GesStateOffset = 112;
const GesBufferOffset = 112 + GesState.Size;
export fn gesSnd(t: i32) -> f32 {
if !(t & 127) {
let i: i32;
loop clearLoop {
i!GesBufferOffset = 0;
branch_if (i := i + 4) < 128*8: clearLoop;
}
let ch: i32;
loop channelLoop {
let lazy channelState = GesStateOffset + ch * GesChannelState.Size;
let lazy channelReg = 80 + ch * 6;
let envState = channelState?GesChannelState.EnvState;
let envVol = i32.load16_u(channelState, GesChannelState.EnvVol);
let lazy oldTrigger = channelState?GesChannelState.Trigger;
let lazy ctrl = channelReg?0;
if (oldTrigger ^ ctrl) & (ctrl | 2) & 3 {
envState = 1;
envVol = 0;
}
channelState?GesChannelState.Trigger = ctrl;
if envState {
let lazy attack = channelReg?4 & 15;
envVol = envVol + 12 * pow(1.675, (15 - attack) as f32) as i32;
if envVol >= 65535 {
envVol = 65535;
envState = 0;
}
} else {
let inline decay = (channelReg - (ctrl & 1))?5 >> 4;
let inline dec = 8 * pow(1.5625, (15 - decay) as f32) as i32;
envVol = envVol - ((dec * (envVol + 8192)) >> 16);
let inline sustain = (channelReg?5 & 15) << 12;
let lazy targetVol = (ctrl & 1) * sustain;
if envVol < targetVol {
envVol = targetVol;
}
}
channelState?GesChannelState.EnvState = envState;
i32.store16(envVol, channelState, GesChannelState.EnvVol);
let inline note = i32.load16_u(channelReg, 2);
let lazy freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32);
let phaseInc = (freq * (65536.0 / 44100.0)) as i32;
let phase = channelState!GesChannelState.Phase;
let inline pulseWidth = channelReg?1;
let phaseShift = (pulseWidth - 128) * 255;
let invPhaseInc = 1 as f32 / phaseInc as f32;
i = 0;
let wave = ctrl >> 6;
if wave < 2 {
if wave {
let pulsePhase1 = pulseWidth << 23;
let pulsePhase2 = (511 - pulseWidth) << 23;
loop sawLoop {
let p = (phase ^ 32768) << 16;
let saw = (p >> 16) - polyBlep(phase, invPhaseInc, -32767);
let saw2 = select(p #>= pulsePhase1 & p #< pulsePhase2, -saw, saw);
let saw2 = saw2 -
polyBlep((p - pulsePhase1) >> 16, invPhaseInc, -saw) -
polyBlep((p - pulsePhase2) >> 16, invPhaseInc, saw);
i!(GesBufferOffset + 128*4) = saw2;
phase = phase + phaseInc;
branch_if (i := i + 4) < 64*4: sawLoop;
}
}
else
{
let pulsePhase = 32768 + pulseWidth * 128;
loop rectLoop {
i!(GesBufferOffset + 128*4) = select((phase & 65535) < pulsePhase, -32768, 32767) -
polyBlep(phase, invPhaseInc, -32767) -
polyBlep(phase - pulsePhase, invPhaseInc, 32767);
phase = phase + phaseInc;
branch_if (i := i + 4) < 64*4: rectLoop;
}
}
} else {
if wave == 2 {
let scale = pulseWidth + 256;
loop triLoop {
let s = phase << 16;
s = (s ^ (s >> 31));
s = (s >> 8) * scale;
s = (s ^ (s >> 31));
i!(GesBufferOffset + 128*4) = (s >> 15) - 32768;
phase = phase + phaseInc;
branch_if (i := i + 4) < 64*4: triLoop;
}
} else {
loop noiseLoop {
let s = phase >> 12;
let inline pulse = ((phase >> 8) & 255) >= pulseWidth;
s = s * 0x6746ba73;
s = s ^ (s >> 15) * pulse;
i!(GesBufferOffset + 128*4) = (s * 0x835776c7) >> 16;
phase = phase + phaseInc;
branch_if (i := i + 4) < 64*4: noiseLoop;
}
}
}
channelState!GesChannelState.Phase = phase;
if ctrl & 32 {
let lazy modSrc = (ch - 1) & 3;
let inline channelState = GesStateOffset + modSrc * GesChannelState.Size;
let inline channelReg = 80 + modSrc * 6;
let inline note = i32.load16_u(channelReg, 2);
let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32);
let phaseInc = (freq * (65536.0 / 44100.0)) as i32;
let phase = channelState!GesChannelState.Phase;
if modSrc > ch {
phase = phase - (phaseInc << 6);
}
i = 0;
loop ringLoop {
let s = phase << 16;
s = (s ^ (s >> 31));
i!(GesBufferOffset + 128*4) = (i!(GesBufferOffset + 128*4) * ((s >> 15) - 32768)) >> 15;
phase = phase + phaseInc;
branch_if (i := i + 4) < 64*4: ringLoop;
}
}
let channelVol = ((ch >> 1)?0x68 >> ((ch & 1) * 4)) & 15;
envVol = envVol * channelVol / 15;
let leftVol = (select(ctrl & 16, 0x3d5b, 0x6a79) >> (ch * 4)) & 15;
let rightVol = 16 - leftVol;
let lazy filter = (ctrl >> 2) & 3;
i = 0;
if filter < 2 {
if filter {
let f = (4096 as f32 - min(4096 as f32, 4096 as f32 * exp(freq * (-8.0 * 3.141 / 44100.0)))) as i32;
let low = (ch * 8)!(GesStateOffset + GesState.Filter);
loop filterLoop {
let in = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
low = low + (((in - low) * f) >> 12);
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((low * leftVol) >> 4);
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((low * rightVol) >> 4);
branch_if (i := i + 4) < 64*4: filterLoop;
(ch * 8)!(GesStateOffset + GesState.Filter) = low;
(ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
}
} else {
loop mixLoop {
let sample = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
branch_if (i := i + 4) < 64*4: mixLoop;
(ch * 8)!(GesStateOffset + GesState.Filter) = sample;
(ch * 8)!(GesStateOffset + GesState.Filter + 4) = 0;
}
}
} else {
filter = filter - 2;
let ctrl = filter?0x6a;
let note = i32.load16_u(filter * 2, 0x6c);
let inline freq = 440 as f32 * pow(2.0, (note - 69*256) as f32 / (12*256) as f32);
let F = (8192 as f32 * sin(min(0.25, freq / 44100 as f32) * 3.1415)) as i32;
let Q = 8192 - (ctrl >> 4) * (7000/15);
let Qlimit = (8192*4096/F - F/2) * 3 / 4;
if Q > Qlimit {
Q = Qlimit;
}
let low_out = ctrl & 1;
let high_out = (ctrl >> 1) & 1;
let band_out = (ctrl >> 2) & 1;
let low = (ch * 8)!(GesStateOffset + GesState.Filter);
let band = (ch * 8)!(GesStateOffset + GesState.Filter + 4);
loop filterLoop {
let in = (i!(GesBufferOffset + 128*4) * envVol) >> 18;
let high = in - low - ((band * Q) >> 12);
band = band + ((F * high) >> 12);
low = low + ((F * band) >> 12);
let sample = low * low_out + high * high_out + band * band_out;
(i * 2)!GesBufferOffset = (i * 2)!GesBufferOffset + ((sample * leftVol) >> 4);
(i * 2)!(GesBufferOffset + 4) = (i * 2)!(GesBufferOffset + 4) + ((sample * rightVol) >> 4);
branch_if (i := i + 4) < 64*4: filterLoop;
(ch * 8)!(GesStateOffset + GesState.Filter) = low;
(ch * 8)!(GesStateOffset + GesState.Filter + 4) = band;
}
}
branch_if (ch := ch + 1) < 4: channelLoop;
}
}
(((t & 127) * 4)!GesBufferOffset) as f32 / 32768 as f32
}
fn polyBlep(transientPhase: i32, invPhaseInc: f32, magnitude: i32) -> i32 {
let lazy t = ((transientPhase << 16) >> 16) as f32 * invPhaseInc;
let lazy x = max(0 as f32, 1 as f32 - abs(t));
(f32.copysign(x * x, t) * magnitude as f32) as i32
}

View File

@@ -0,0 +1,6 @@
import "env.memory" memory(1);
import "env.sin" fn sin(f32) -> f32;
import "env.pow" fn pow(f32, f32) -> f32;
import "env.exp" fn exp(f32) -> f32;
include "ges.cwa"

View File

@@ -11,13 +11,13 @@ fn main() -> Result<()> {
convert_font()?; convert_font()?;
println!("Compiling loader module"); println!("Compiling loader module");
let loader = curlywas::compile_file("src/loader.cwa", curlywas::Options::default())?; let loader = curlywas::compile_file("src/loader.cwa", curlywas::Options::default()).0?;
File::create("bin/loader.wasm")?.write_all(&loader)?; File::create("bin/loader.wasm")?.write_all(&loader)?;
println!("Loader (including base module): {} bytes", loader.len()); println!("Loader (including base module): {} bytes", loader.len());
println!("Compiling platform module"); println!("Compiling platform module");
let platform = curlywas::compile_file("src/platform.cwa", curlywas::Options::default())?; let platform = curlywas::compile_file("src/platform.cwa", curlywas::Options::default()).0?;
println!("Compressing platform module"); println!("Compressing platform module");
let platform = uw8_tool::pack( let platform = uw8_tool::pack(
&platform, &platform,

View File

@@ -1,6 +1,9 @@
import "env.memory" memory(4); import "env.memory" memory(4);
import "env.sin" fn sin(f32) -> f32;
import "env.cos" fn cos(f32) -> f32; import "env.cos" fn cos(f32) -> f32;
import "env.pow" fn pow(f32, f32) -> f32;
import "env.exp" fn exp(f32) -> f32;
export fn time() -> f32 { export fn time() -> f32 {
(0!64) as f32 / 1000 as f32 (0!64) as f32 / 1000 as f32
@@ -256,6 +259,11 @@ export fn line(x1: f32, y1: f32, x2: f32, y2: f32, col: i32) {
p = y1; p = y1;
} }
if max_axis == 0 as f32 {
setPixel(x1 as i32, y1 as i32, col);
return;
}
let steps = floor(p + max_axis) as i32 - floor(p) as i32; let steps = floor(p + max_axis) as i32 - floor(p) as i32;
p = floor(p) + 0.5 - p; p = floor(p) + 0.5 - p;
if max_axis < 0 as f32 { if max_axis < 0 as f32 {
@@ -267,7 +275,7 @@ export fn line(x1: f32, y1: f32, x2: f32, y2: f32, col: i32) {
dy = dy / max_axis; dy = dy / max_axis;
let f = min(max_axis, max(0 as f32, p)); let f = min(max_axis, max(0 as f32, p));
setPixel((x1 + f * dx) as i32, (y1 + f * dy) as i32, col); setPixel(i32.trunc_sat_f32_s(x1 + f * dx), i32.trunc_sat_f32_s(y1 + f * dy), col);
if !steps { if !steps {
return; return;
@@ -280,7 +288,7 @@ export fn line(x1: f32, y1: f32, x2: f32, y2: f32, col: i32) {
loop pixels { loop pixels {
if steps := steps - 1 { if steps := steps - 1 {
setPixel(x1 as i32, y1 as i32, col); setPixel(i32.trunc_sat_f32_s(x1), i32.trunc_sat_f32_s(y1), col);
x1 = x1 + dx; x1 = x1 + dx;
y1 = y1 + dy; y1 = y1 + dy;
branch pixels; branch pixels;
@@ -288,7 +296,7 @@ export fn line(x1: f32, y1: f32, x2: f32, y2: f32, col: i32) {
} }
f = min(max_axis, p) - p; f = min(max_axis, p) - p;
setPixel((x1 + f * dx) as i32, (y1 + f * dy) as i32, col); setPixel(i32.trunc_sat_f32_s(x1 + f * dx), i32.trunc_sat_f32_s(y1 + f * dy), col);
} }
////////// //////////
@@ -495,6 +503,12 @@ export fn setCursorPosition(x: i32, y: i32) {
textCursorY = y * scale; textCursorY = y * scale;
} }
///////////
// SOUND //
///////////
include "ges.cwa"
/////////// ///////////
// SETUP // // SETUP //
/////////// ///////////
@@ -503,6 +517,13 @@ export fn endFrame() {
68!4 = 68!0; 68!4 = 68!0;
} }
fn memclr(base: i32, size: i32) {
loop bytes {
(base + (size := size - 1))?0 = 0;
branch_if size: bytes;
}
}
start fn setup() { start fn setup() {
let i: i32 = 12*16*3-1; let i: i32 = 12*16*3-1;
let avg: f32; let avg: f32;
@@ -535,10 +556,26 @@ start fn setup() {
branch_if (i := i - 1) >= 0: expand_sweetie; branch_if (i := i - 1) >= 0: expand_sweetie;
} }
memclr(0, 64);
memclr(112, 8);
memclr(0x14000, 0x2c000);
cls(0); cls(0);
randomSeed(random()); randomSeed(random());
} }
data 80 {
i8(
0, 128, 0, 69, 0x8, 0xc8,
0, 128, 0, 69, 0x8, 0xc8,
0, 128, 0, 69, 0x8, 0xc8,
0, 128, 0, 69, 0x8, 0xc8,
0xff, 0xff,
1, 1, 0, 100, 0, 100
)
}
data 0x13000+192*4 { data 0x13000+192*4 {
i32( i32(
0x2c1c1a, 0x2c1c1a,

View File

@@ -36,6 +36,8 @@ for dir in build/*; do
cp $example $dir/examples cp $example $dir/examples
done done
cp -r ../examples/include $dir/include
mkdir $dir/carts mkdir $dir/carts
for example in $dir/examples/*; do for example in $dir/examples/*; do
build/microw8-linux/uw8 pack -l 9 $example $dir/carts/$(basename ${example%.*}).uw8 build/microw8-linux/uw8 pack -l 9 $example $dir/carts/$(basename ${example%.*}).uw8

View File

@@ -15,11 +15,11 @@ The initial motivation behind MicroW8 was to explore whether there was a way to
* Gamepad input (D-Pad + 4 Buttons) * Gamepad input (D-Pad + 4 Buttons)
## Examples ## Examples
* [Fireworks](v0.1.1#AgwvgP+M59snqjl4CMKw5sqm1Zw9yJCbSviMjeLUdHus2a3yl/a99+uiBeqZgP/2jqSjrLjRk73COMM6OSLpsxK8ugT1kuk/q4hQUqqPpGozHoa0laulzGGcahzdfdJsYaK1sIdeIYS9M5PnJx/Wk9H+PvWEPy2Zvv7I6IW7Fg==) (127 bytes): Some fireworks to welcome 2022. * [Fireworks](v0.1.2#AgwvgP+M59snqjl4CMKw5sqm1Zw9yJCbSviMjeLUdHus2a3yl/a99+uiBeqZgP/2jqSjrLjRk73COMM6OSLpsxK8ugT1kuk/q4hQUqqPpGozHoa0laulzGGcahzdfdJsYaK1sIdeIYS9M5PnJx/Wk9H+PvWEPy2Zvv7I6IW7Fg==) (127 bytes): Some fireworks to welcome 2022.
* [Skip Ahead](v0.1.1#AgyfpZ80wkW28kiUZ9VIK4v+RPnVxqjK1dz2BcDoNyQPsS2g4OgEzkTe6jyoAfFOmqKrS8SM2aRljBal9mjNn8i4fP9eBK+RehQKxxGtJa9FqftvqEnh3ez1YaYxqj7jgTdzJ/WAYVmKMovBT1myrX3FamqKSOgMsNedLhVTLAhQup3sNcYEjGNo8b0HZ5+AgMgCwYRGCe//XQOMAaAAzqDILgmpEZ/43RKHcQpHEQwbURfNQJpadJe2sz3q5FlQnTGXQ9oSMokidhlC+aR/IpNHieuBGLhFZ2GfnwVQ0geBbQpTPA==) (229 bytes): A port of my [TIC-80 256byte game](http://tic80.com/play?cart=1735) from LoveByte'21 * [Skip Ahead](v0.1.2#AgyfpZ80wkW28kiUZ9VIK4v+RPnVxqjK1dz2BcDoNyQPsS2g4OgEzkTe6jyoAfFOmqKrS8SM2aRljBal9mjNn8i4fP9eBK+RehQKxxGtJa9FqftvqEnh3ez1YaYxqj7jgTdzJ/WAYVmKMovBT1myrX3FamqKSOgMsNedLhVTLAhQup3sNcYEjGNo8b0HZ5+AgMgCwYRGCe//XQOMAaAAzqDILgmpEZ/43RKHcQpHEQwbURfNQJpadJe2sz3q5FlQnTGXQ9oSMokidhlC+aR/IpNHieuBGLhFZ2GfnwVQ0geBbQpTPA==) (229 bytes): A port of my [TIC-80 256byte game](http://tic80.com/play?cart=1735) from LoveByte'21
* [OhNoAnotherTunnel](v0.1.1#AgPP1oEFvPzY/rBZwTumtYn37zeMFgpir1Bkn91jsNcp26VzoUpkAOOJTtnzVBfW+/dGnnIdbq/irBUJztY5wuua80DORTYZndgdwZHcSk15ajc4nyO0g1A6kGWyW56oZk0iPYJA9WtUmoj0Plvy1CGwIZrMe57X7QZcdqc3u6zjTA41Tpiqi9vnO3xbhi8o594Vx0XPXwVzpYq1ZCTYenfAGaXKkDmAFJqiVIsiCg==) (175 bytes): A port of my [entry](http://tic80.com/play?cart=1871) in the Outline'21 bytebattle final * [OhNoAnotherTunnel](v0.1.2#AgPP1oEFvPzY/rBZwTumtYn37zeMFgpir1Bkn91jsNcp26VzoUpkAOOJTtnzVBfW+/dGnnIdbq/irBUJztY5wuua80DORTYZndgdwZHcSk15ajc4nyO0g1A6kGWyW56oZk0iPYJA9WtUmoj0Plvy1CGwIZrMe57X7QZcdqc3u6zjTA41Tpiqi9vnO3xbhi8o594Vx0XPXwVzpYq1ZCTYenfAGaXKkDmAFJqiVIsiCg==) (175 bytes): A port of my [entry](http://tic80.com/play?cart=1871) in the Outline'21 bytebattle final
* [Technotunnel](v0.1.1#AhPXpq894LaUhp5+HQf39f39/Jc8g5zUrBSc0uyKh36ivskczhY84h55zL8gWpkdvKuRQI+KIt80isKzh8jkM8nILcx0RUvyk8yjE8TgNsgkcORVI0RY5k3qE4ySjaycxa2DVZH61UWZuLsCouuwT7I80TbmmetQSbMywJ/avrrCZIAH0UzQfvOiCJNG48NI0FFY1vjB7a7dcp8Uqg==) (157 bytes): A port of my [entry](https://tic80.com/play?cart=1873) in the Outline'21 bytebattle quater final * [Technotunnel](v0.1.2#AhPXpq894LaUhp5+HQf39f39/Jc8g5zUrBSc0uyKh36ivskczhY84h55zL8gWpkdvKuRQI+KIt80isKzh8jkM8nILcx0RUvyk8yjE8TgNsgkcORVI0RY5k3qE4ySjaycxa2DVZH61UWZuLsCouuwT7I80TbmmetQSbMywJ/avrrCZIAH0UzQfvOiCJNG48NI0FFY1vjB7a7dcp8Uqg==) (157 bytes): A port of my [entry](https://tic80.com/play?cart=1873) in the Outline'21 bytebattle quater final
* [Font & Palette](v0.1.1#At/p39+IBnj6ry1TRe7jzVy2A4tXgBvmoW2itzoyF2aM28pGy5QDiKxqrk8l9sbWZLtnAb+jgOfU+9QhpuyCAkhN6gPOU481IUL/df96vNe3h288Dqwhd3sfFpothIVFsMwRK72kW2hiR7zWsaXyy5pNmjR6BJk4piWx9ApT1ZwoUajhk6/zij6itq/FD1U3jj/J3MOwqZ2ef8Bv6ZPQlJIYVf62icGa69wS6SI1qBpIFiF14F8PcztRVbKIxLpT4ArCS6nz6FPnyUkqATGSBNPJ): Just a simple viewer for the default font and palette. * [Font & Palette](v0.1.2#At/p39+IBnj6ry1TRe7jzVy2A4tXgBvmoW2itzoyF2aM28pGy5QDiKxqrk8l9sbWZLtnAb+jgOfU+9QhpuyCAkhN6gPOU481IUL/df96vNe3h288Dqwhd3sfFpothIVFsMwRK72kW2hiR7zWsaXyy5pNmjR6BJk4piWx9ApT1ZwoUajhk6/zij6itq/FD1U3jj/J3MOwqZ2ef8Bv6ZPQlJIYVf62icGa69wS6SI1qBpIFiF14F8PcztRVbKIxLpT4ArCS6nz6FPnyUkqATGSBNPJ): Just a simple viewer for the default font and palette.
Examplers for older versions: Examplers for older versions:
@@ -29,6 +29,20 @@ Examplers for older versions:
## Versions ## Versions
### v0.1.2
* [Web runtime](v0.1.2)
* [Linux](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-linux.tgz)
* [MacOS](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-macos.tgz)
* [Windows](https://github.com/exoticorn/microw8/releases/download/v0.1.2/microw8-0.1.2-windows.zip)
Changes:
* add option to `uw8 run` to run the cart in the browser using the web runtime
* CurlyWas: implement `include` support
* CurlyWas: implement support for constants
* fix crash when trying to draw zero sized line
### v0.1.1 ### v0.1.1
* [Web runtime](v0.1.1) * [Web runtime](v0.1.1)

View File

@@ -18,7 +18,9 @@ The memory has to be imported as `env` `memory` and has a maximum size of 256kb
00000-00040: user memory 00000-00040: user memory
00040-00044: time since module start in ms 00040-00044: time since module start in ms
00044-0004c: gamepad state 00044-0004c: gamepad state
0004c-00078: reserved 0004c-00050: reserved
00050-00070: sound registers
00070-00078: reserved
00078-12c78: frame buffer 00078-12c78: frame buffer
12c78-13000: reserved 12c78-13000: reserved
13000-13400: palette 13000-13400: palette
@@ -47,7 +49,7 @@ Returns the arccosine of `x`.
Returns the arctangent of `x`. Returns the arctangent of `x`.
### fn atan2(y: f32, y: f32) -> f32 ### fn atan2(y: f32, x: f32) -> f32
Returns the angle between the point `(x, y)` and the positive x-axis. Returns the angle between the point `(x, y)` and the positive x-axis.
@@ -269,6 +271,38 @@ Sets the background color.
Sets the cursor position. In normal mode `x` and `y` are multiplied by 8 to get the pixel position, in graphics mode they are used as is. Sets the cursor position. In normal mode `x` and `y` are multiplied by 8 to get the pixel position, in graphics mode they are used as is.
## Sound
```
Per channel:
00 : CTRL - wave form, ring, sync, filter send, trigger
bit 0: note on flag
bit 1: note trigger
bit 2,3: filter 0,1 send
bit 6,7: wave form (rect, saw, tri, noise)
01 : PULS - pulse width
02 : FINE - fine tuning
03 : NOTE - note
04 : ENVA - attack, decay
05 : ENVR - sustain, release
50-56: channel 0
56-5b: channel 1
5c-61: channel 2
62-67: channel 3
68: VO01 - volumes channel 0&1
69: VO23 - volumes channel 2&3
6a : FCTR 0 - type, resonance
6b : FCTR 1 - type, resonance
6c : FFIN 0 - cutoff fine tuning
6d : FNOT 0 - cutoff note
6e : FFIN 1 - cutoff fine tuning
6f : FNOT 1 - cutoff note
```
# The `uw8` tool # The `uw8` tool
The `uw8` tool included in the MicroW8 download includes a number of useful tools for developing MicroW8 carts. For small productions written in The `uw8` tool included in the MicroW8 download includes a number of useful tools for developing MicroW8 carts. For small productions written in
@@ -284,7 +318,8 @@ Runs `<file>` which can be a binary WebAssembly module, an `.uw8` cart, a wat (W
Options: Options:
* `-t FRAMES`, `--timeout FRAMES` : Sets the timeout in frames (1/60s). If the start or update function runs longer than this it is forcibly interupted * `-b`, `--browser`: Run in browser instead of using native runtime
* `-t FRAMES`, `--timeout FRAMES`: Sets the timeout in frames (1/60s). If the start or update function runs longer than this it is forcibly interupted
and execution of the cart is stopped. Defaults to 30 (0.5s) and execution of the cart is stopped. Defaults to 30 (0.5s)
* `-w`, `--watch`: Reloads the given file every time it changes on disk. * `-w`, `--watch`: Reloads the given file every time it changes on disk.
* `-p`, `--pack`: Pack the file into an `.uw8` cart before running it and print the resulting size. * `-p`, `--pack`: Pack the file into an `.uw8` cart before running it and print the resulting size.

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@
<section> <section>
<h1 class="text-center heading-text">A WebAssembly based fantasy console</h1> <h1 class="text-center heading-text">A WebAssembly based fantasy console</h1>
</section> </section>
<a href="v0.1.1"> <a href="v0.1.2">
<img class="demonstration-gif" style="width:640px;height:480px;image-rendering:pixelated" src="img/technotunnel.png"></img> <img class="demonstration-gif" style="width:640px;height:480px;image-rendering:pixelated" src="img/technotunnel.png"></img>
</a> </a>
</div> </div>

View File

@@ -1,23 +1,38 @@
use anyhow::{bail, Result}; use anyhow::{anyhow, bail, Result};
use notify::{DebouncedEvent, Watcher, RecommendedWatcher}; use notify::{DebouncedEvent, RecommendedWatcher, Watcher};
use std::{ use std::{collections::BTreeSet, path::PathBuf, sync::mpsc, time::Duration};
collections::BTreeSet,
path::{Path, PathBuf},
sync::mpsc,
time::Duration,
};
pub struct FileWatcher { pub struct FileWatcher {
_watcher: RecommendedWatcher, watcher: RecommendedWatcher,
watched_files: BTreeSet<PathBuf>, watched_files: BTreeSet<PathBuf>,
directories: BTreeSet<PathBuf>,
rx: mpsc::Receiver<DebouncedEvent>, rx: mpsc::Receiver<DebouncedEvent>,
} }
pub struct FileWatcherBuilder(BTreeSet<PathBuf>);
impl FileWatcher { impl FileWatcher {
pub fn builder() -> FileWatcherBuilder { pub fn new() -> Result<FileWatcher> {
FileWatcherBuilder(BTreeSet::new()) let (tx, rx) = mpsc::channel();
let watcher = notify::watcher(tx, Duration::from_millis(100))?;
Ok(FileWatcher {
watcher,
watched_files: BTreeSet::new(),
directories: BTreeSet::new(),
rx,
})
}
pub fn add_file<P: Into<PathBuf>>(&mut self, path: P) -> Result<()> {
let path = path.into();
let parent = path.parent().ok_or_else(|| anyhow!("File has no parent"))?;
if !self.directories.contains(parent) {
self.watcher
.watch(parent, notify::RecursiveMode::NonRecursive)?;
self.directories.insert(parent.to_path_buf());
}
self.watched_files.insert(path);
Ok(())
} }
pub fn poll_changed_file(&self) -> Result<Option<PathBuf>> { pub fn poll_changed_file(&self) -> Result<Option<PathBuf>> {
@@ -38,33 +53,3 @@ impl FileWatcher {
Ok(None) Ok(None)
} }
} }
impl FileWatcherBuilder {
pub fn add_file<P: Into<PathBuf>>(&mut self, path: P) -> &mut Self {
self.0.insert(path.into());
self
}
pub fn build(self) -> Result<FileWatcher> {
let mut directories: BTreeSet<&Path> = BTreeSet::new();
for file in &self.0 {
if let Some(directory) = file.parent() {
directories.insert(directory);
}
}
let (tx, rx) = mpsc::channel();
let mut watcher = notify::watcher(tx, Duration::from_millis(100))?;
for directory in directories {
watcher.watch(directory, notify::RecursiveMode::NonRecursive)?;
}
Ok(FileWatcher {
_watcher: watcher,
watched_files: self.0,
rx,
})
}
}

View File

@@ -77,13 +77,7 @@ fn run(mut args: Arguments) -> Result<()> {
let filename = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?; let filename = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
let mut watcher = uw8::FileWatcher::builder(); let mut watcher = uw8::FileWatcher::new()?;
if watch_mode {
watcher.add_file(&filename);
}
let watcher = watcher.build()?;
use std::process::exit; use std::process::exit;
@@ -103,18 +97,23 @@ fn run(mut args: Arguments) -> Result<()> {
runtime.set_timeout(timeout); runtime.set_timeout(timeout);
} }
if let Err(err) = start_cart(&filename, &mut *runtime, &config) { let mut first_run = true;
eprintln!("Load error: {}", err);
if !watch_mode {
exit(1);
}
}
while runtime.is_open() { while runtime.is_open() {
if watcher.poll_changed_file()?.is_some() { if first_run || watcher.poll_changed_file()?.is_some() {
if let Err(err) = start_cart(&filename, &mut *runtime, &config) { let (result, dependencies) = start_cart(&filename, &mut *runtime, &config);
eprintln!("Load error: {}", err); if watch_mode {
for dep in dependencies {
watcher.add_file(dep)?;
}
} }
if let Err(err) = result {
eprintln!("Load error: {}", err);
if !watch_mode {
exit(1);
}
}
first_run = false;
} }
if let Err(err) = runtime.run_frame() { if let Err(err) = runtime.run_frame() {
@@ -134,40 +133,99 @@ struct Config {
output_path: Option<PathBuf>, output_path: Option<PathBuf>,
} }
fn load_cart(filename: &Path, config: &Config) -> Result<Vec<u8>> { fn load_cart(filename: &Path, config: &Config) -> (Result<Vec<u8>>, Vec<PathBuf>) {
let mut cart = vec![]; let mut dependencies = Vec::new();
File::open(filename)?.read_to_end(&mut cart)?; fn inner(filename: &Path, config: &Config, dependencies: &mut Vec<PathBuf>) -> Result<Vec<u8>> {
let mut cart = match SourceType::of_file(filename)? {
if cart[0] >= 10 { SourceType::Binary => {
let src = String::from_utf8(cart)?; let mut cart = vec![];
cart = if src.chars().find(|c| !c.is_whitespace()) == Some('(') { File::open(filename)?.read_to_end(&mut cart)?;
wat::parse_str(src)? cart
} else { }
curlywas::compile_str(&src, filename, curlywas::Options::default())? SourceType::Wat => {
let cart = wat::parse_file(filename)?;
cart
}
SourceType::CurlyWas => {
let (module, deps) = curlywas::compile_file(filename, curlywas::Options::default());
*dependencies = deps;
module?
}
}; };
if let Some(ref pack_config) = config.pack {
cart = uw8_tool::pack(&cart, pack_config)?;
println!("packed size: {} bytes", cart.len());
}
if let Some(ref path) = config.output_path {
File::create(path)?.write_all(&cart)?;
}
Ok(cart)
} }
if let Some(ref pack_config) = config.pack { let result = inner(filename, config, &mut dependencies);
cart = uw8_tool::pack(&cart, pack_config)?;
println!("packed size: {} bytes", cart.len()); if dependencies.is_empty() {
dependencies.push(filename.to_path_buf());
} }
if let Some(ref path) = config.output_path { (result, dependencies)
File::create(path)?.write_all(&cart)?; }
}
Ok(cart) enum SourceType {
Binary,
Wat,
CurlyWas,
}
impl SourceType {
fn of_file(filename: &Path) -> Result<SourceType> {
if let Some(extension) = filename.extension() {
if extension == "uw8" || extension == "wasm" {
return Ok(SourceType::Binary);
} else if extension == "wat" || extension == "wast" {
return Ok(SourceType::Wat);
} else if extension == "cwa" {
return Ok(SourceType::CurlyWas);
}
}
let mut cart = vec![];
File::open(filename)?.read_to_end(&mut cart)?;
let ty = if cart[0] < 10 {
SourceType::Binary
} else {
let src = String::from_utf8(cart)?;
if src.chars().find(|&c| !c.is_whitespace() && c != ';') == Some('(') {
SourceType::Wat
} else {
SourceType::CurlyWas
}
};
Ok(ty)
}
} }
#[cfg(any(feature = "native", feature = "browser"))] #[cfg(any(feature = "native", feature = "browser"))]
fn start_cart(filename: &Path, runtime: &mut dyn Runtime, config: &Config) -> Result<()> { fn start_cart(
let cart = load_cart(filename, config)?; filename: &Path,
runtime: &mut dyn Runtime,
config: &Config,
) -> (Result<()>, Vec<PathBuf>) {
let (cart, dependencies) = load_cart(filename, config);
let cart = match cart {
Ok(cart) => cart,
Err(err) => return (Err(err), dependencies),
};
if let Err(err) = runtime.load(&cart) { if let Err(err) = runtime.load(&cart) {
eprintln!("Load error: {}", err); eprintln!("Load error: {}", err);
Err(err) (Err(err), dependencies)
} else { } else {
Ok(()) (Ok(()), dependencies)
} }
} }
@@ -192,7 +250,8 @@ fn pack(mut args: Arguments) -> Result<()> {
pack: Some(pack_config), pack: Some(pack_config),
output_path: None, output_path: None,
}, },
)?; )
.0?;
File::create(out_file)?.write_all(&cart)?; File::create(out_file)?.write_all(&cart)?;
@@ -215,7 +274,7 @@ fn compile(mut args: Arguments) -> Result<()> {
let in_file = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?; let in_file = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
let out_file = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?; let out_file = args.free_from_os_str::<PathBuf, bool>(|s| Ok(s.into()))?;
let module = curlywas::compile_file(in_file, options)?; let module = curlywas::compile_file(in_file, options).0?;
File::create(out_file)?.write_all(&module)?; File::create(out_file)?.write_all(&module)?;
Ok(()) Ok(())

File diff suppressed because one or more lines are too long

30
test/ges_test.cwa Normal file
View File

@@ -0,0 +1,30 @@
import "env.memory" memory(4);
import "env.pow" fn pow(f32, f32) -> f32;
import "env.sin" fn sin(f32) -> f32;
import "env.cls" fn cls(i32);
import "env.rectangle" fn rectangle(f32, f32, f32, f32, i32);
include "../platform/src/ges.cwa"
export fn snd(t: i32) -> f32 {
gesSnd(t)
}
export fn upd() {
80?0 = 32!32 / 200 & 2 | 0x41;
80?3 = (32!32 / 400)%7*12/7 + 40;
let pulse = (32!32 * 256 / 2000) & 511;
if pulse >= 256 {
pulse = 511 - pulse;
}
80?1 = pulse;
cls(0);
rectangle(0.0, 100.0, (pulse * 320 / 256) as f32, 16.0, 15);
}
data 80 {
i8(
0x41, 0, 0, 80, 0x70, 0
)
}

59
tests/plot_ges.cwa Normal file
View File

@@ -0,0 +1,59 @@
include "../examples/include/microw8-api.cwa"
export fn upd() {
80?0 = (32!32 >> 11 << 6) | 5;
80?1 = (sin(time() * 6 as f32) * 95 as f32) as i32 + 128;
plotGes();
}
data 80 { i8 (
1, 128, 0, 69, 0, 15,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0xff, 0xff,
0xc1, 0, 0, 110, 0, 0
) }
//import "env.gesSnd" fn gesSnd(i32) -> f32;
include "../platform/src/ges.cwa"
export fn snd(t: i32) -> f32 {
gesSnd(t)
}
global mut samplePos: i32 = 0;
const SoundBuffer = 0x30000;
fn plotGes() {
rectangle(0 as f32, 10 as f32, 320 as f32, 320 as f32, 0);
let count = (time() * 44100 as f32) as i32 * 2 - samplePos;
let i: i32;
loop genLoop {
(i*4)$SoundBuffer = gesSnd(samplePos + i);
branch_if (i := i + 1) < count: genLoop;
}
samplePos = samplePos + count;
let ch: i32;
loop channelLoop {
let offset = 159;
i = 0;
loop searchLoop {
offset = offset + 1;
branch_if (offset * 8 + ch - 8)$SoundBuffer < 0 as f32 | (offset * 8 + ch)$SoundBuffer >= 0 as f32 & offset + 160 < count: searchLoop;
}
offset = ch + (offset - 160) * 8;
i = 0;
loop plotLoop {
setPixel(i, floor((i * 8 + offset)$SoundBuffer * 127 as f32) as i32 + 60 + ch * (120/8), 15);
branch_if (i := i + 1) < 320: plotLoop;
}
branch_if (ch := ch + 8) < 16: channelLoop;
}
}

View File

@@ -71,26 +71,100 @@ impl BaseModule {
add_function(&mut functions, &type_map, "randomSeed", &[I32], None); add_function(&mut functions, &type_map, "randomSeed", &[I32], None);
add_function(&mut functions, &type_map, "cls", &[I32], None); add_function(&mut functions, &type_map, "cls", &[I32], None);
add_function(&mut functions, &type_map, "setPixel", &[I32, I32, I32], None); add_function(
add_function(&mut functions, &type_map, "getPixel", &[I32, I32], Some(I32)); &mut functions,
add_function(&mut functions, &type_map, "hline", &[I32, I32, I32, I32], None); &type_map,
add_function(&mut functions, &type_map, "rectangle", &[F32, F32, F32, F32, I32], None); "setPixel",
add_function(&mut functions, &type_map, "circle", &[F32, F32, F32, I32], None); &[I32, I32, I32],
add_function(&mut functions, &type_map, "line", &[F32, F32, F32, F32, I32], None); None,
);
add_function(
&mut functions,
&type_map,
"getPixel",
&[I32, I32],
Some(I32),
);
add_function(
&mut functions,
&type_map,
"hline",
&[I32, I32, I32, I32],
None,
);
add_function(
&mut functions,
&type_map,
"rectangle",
&[F32, F32, F32, F32, I32],
None,
);
add_function(
&mut functions,
&type_map,
"circle",
&[F32, F32, F32, I32],
None,
);
add_function(
&mut functions,
&type_map,
"line",
&[F32, F32, F32, F32, I32],
None,
);
add_function(&mut functions, &type_map, "time", &[], Some(F32)); add_function(&mut functions, &type_map, "time", &[], Some(F32));
add_function(&mut functions, &type_map, "isButtonPressed", &[I32], Some(I32)); add_function(
add_function(&mut functions, &type_map, "isButtonTriggered", &[I32], Some(I32)); &mut functions,
&type_map,
"isButtonPressed",
&[I32],
Some(I32),
);
add_function(
&mut functions,
&type_map,
"isButtonTriggered",
&[I32],
Some(I32),
);
add_function(&mut functions, &type_map, "printChar", &[I32], None); add_function(&mut functions, &type_map, "printChar", &[I32], None);
add_function(&mut functions, &type_map, "printString", &[I32], None); add_function(&mut functions, &type_map, "printString", &[I32], None);
add_function(&mut functions, &type_map, "printInt", &[I32], None); add_function(&mut functions, &type_map, "printInt", &[I32], None);
add_function(&mut functions, &type_map, "setTextColor", &[I32], None); add_function(&mut functions, &type_map, "setTextColor", &[I32], None);
add_function(&mut functions, &type_map, "setBackgroundColor", &[I32], None); add_function(
add_function(&mut functions, &type_map, "setCursorPosition", &[I32, I32], None); &mut functions,
&type_map,
"setBackgroundColor",
&[I32],
None,
);
add_function(
&mut functions,
&type_map,
"setCursorPosition",
&[I32, I32],
None,
);
add_function(&mut functions, &type_map, "rectangle_outline", &[F32, F32, F32, F32, I32], None); add_function(
add_function(&mut functions, &type_map, "circle_outline", &[F32, F32, F32, I32], None); &mut functions,
&type_map,
"rectangle_outline",
&[F32, F32, F32, F32, I32],
None,
);
add_function(
&mut functions,
&type_map,
"circle_outline",
&[F32, F32, F32, I32],
None,
);
add_function(&mut functions, &type_map, "exp", &[F32], Some(F32));
for i in functions.len()..64 { for i in functions.len()..64 {
add_function( add_function(
@@ -214,6 +288,68 @@ impl BaseModule {
File::create(path)?.write_all(&data)?; File::create(path)?.write_all(&data)?;
Ok(()) Ok(())
} }
pub fn write_as_cwa<P: AsRef<Path>>(&self, path: P) -> Result<()> {
fn inner(mut file: File, base: &BaseModule) -> Result<()> {
writeln!(file, "// MicroW8 APIs, to be `include`d in CurlyWas sources")?;
writeln!(file, "import \"env.memory\" memory({});", base.memory)?;
writeln!(file)?;
for &(module, ref name, type_id) in &base.function_imports {
if !name.contains("reserved") {
let ty = &base.types[type_id as usize];
let params: Vec<&str> = ty.params.iter().copied().map(type_to_str).collect();
write!(
file,
"import \"{}.{}\" fn {}({})",
module,
name,
name,
params.join(", ")
)?;
if let Some(result) = ty.result {
write!(file, " -> {}", type_to_str(result))?;
}
writeln!(file, ";")?;
}
}
writeln!(file)?;
for &(name, value) in CONSTANTS {
writeln!(file, "const {} = 0x{:x};", name, value)?;
}
Ok(())
}
inner(File::create(path)?, self)
}
pub fn write_as_wat<P: AsRef<Path>>(&self, path: P) -> Result<()> {
fn inner(mut file: File, base: &BaseModule) -> Result<()> {
writeln!(file, ";; MicroW8 APIs, in WAT (Wasm Text) format")?;
writeln!(file, "(import \"env\" \"memory\" (memory {}))", base.memory)?;
writeln!(file)?;
for &(module, ref name, type_id) in &base.function_imports {
if !name.contains("reserved") {
let ty = &base.types[type_id as usize];
write!(file, "(import \"{}\" \"{}\" (func ${}", module, name, name)?;
for &param in &ty.params {
write!(file, " (param {})", type_to_str(param))?;
}
if let Some(result) = ty.result {
write!(file, " (result {})", type_to_str(result))?;
}
writeln!(file, "))")?;
}
}
writeln!(file)?;
writeln!(file, ";; to use defines, include this file with a preprocessor\n;; like gpp (https://logological.org/gpp).")?;
for &(name, value) in CONSTANTS {
writeln!(file, "#define {} 0x{:x};", name, value)?;
}
Ok(())
}
inner(File::create(path)?, self)
}
} }
fn add_function( fn add_function(
@@ -241,3 +377,30 @@ fn lookup_type(
}; };
*type_map.get(&key).unwrap() *type_map.get(&key).unwrap()
} }
fn type_to_str(ty: ValType) -> &'static str {
match ty {
ValType::I32 => "i32",
ValType::I64 => "i64",
ValType::F32 => "f32",
ValType::F64 => "f64",
_ => unimplemented!(),
}
}
const CONSTANTS: &[(&str, u32)] = &[
("TIME_MS", 0x40),
("GAMEPAD", 0x44),
("FRAMEBUFFER", 0x78),
("PALETTE", 0x13000),
("FONT", 0x13400),
("USER_MEM", 0x14000),
("BUTTON_UP", 0),
("BUTTON_DOWN", 1),
("BUTTON_LEFT", 2),
("BUTTON_RIGHT", 3),
("BUTTON_A", 4),
("BUTTON_B", 5),
("BUTTON_X", 6),
("BUTTON_Y", 7)
];

View File

@@ -1,8 +1,8 @@
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use uw8_tool::BaseModule;
use pico_args::Arguments; use pico_args::Arguments;
use uw8_tool::BaseModule;
fn main() -> Result<()> { fn main() -> Result<()> {
let mut args = Arguments::from_env(); let mut args = Arguments::from_env();
@@ -32,6 +32,14 @@ fn main() -> Result<()> {
let dest: PathBuf = args.free_from_str()?; let dest: PathBuf = args.free_from_str()?;
uw8_tool::filter_exports(&source, &dest)?; uw8_tool::filter_exports(&source, &dest)?;
} }
"base-cwa" => {
let path: PathBuf = args.free_from_str()?;
BaseModule::for_format_version(1)?.write_as_cwa(path)?;
}
"base-wat" => {
let path: PathBuf = args.free_from_str()?;
BaseModule::for_format_version(1)?.write_as_wat(path)?;
}
_ => { _ => {
eprintln!("Unknown subcommand '{}'", cmd); eprintln!("Unknown subcommand '{}'", cmd);
print_help(); print_help();

2
web/run Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
rm -rf .parcel-cache && yarn parcel src/index.html

69
web/src/audiolet.js Normal file
View File

@@ -0,0 +1,69 @@
let U8 = (...a) => new Uint8Array(...a);
class APU extends AudioWorkletProcessor {
constructor() {
super();
this.sampleIndex = 0;
this.port.onmessage = (ev) => {
if(this.memory) {
U8(this.memory.buffer, 80, 32).set(U8(ev.data));
} else {
this.load(ev.data[0], ev.data[1]);
}
};
}
async load(platform_data, data) {
let memory = new WebAssembly.Memory({ initial: 4, maximum: 4 });
let importObject = {
env: {
memory
},
};
for (let n of ['acos', 'asin', 'atan', 'atan2', 'cos', 'exp', 'log', 'sin', 'tan', 'pow']) {
importObject.env[n] = Math[n];
}
for (let i = 9; i < 64; ++i) {
importObject.env['reserved' + i] = () => { };
}
for (let i = 0; i < 16; ++i) {
importObject.env['g_reserved' + i] = 0;
}
let instantiate = async (data) => (await WebAssembly.instantiate(data, importObject)).instance;
let platform_instance = await instantiate(platform_data);
for (let name in platform_instance.exports) {
importObject.env[name] = platform_instance.exports[name]
}
let instance = await instantiate(data);
this.memory = memory;
this.snd = instance.exports.snd || platform_instance.exports.gesSnd;
this.port.postMessage(2);
}
process(inputs, outputs, parameters) {
if(this.snd) {
let channels = outputs[0];
let index = this.sampleIndex;
let numSamples = channels[0].length;
for(let i = 0; i < numSamples; ++i) {
channels[0][i] = this.snd(index++);
channels[1][i] = this.snd(index++);
}
this.sampleIndex = index & 0xffffffff;
}
return true;
}
}
registerProcessor('apu', APU);

View File

@@ -10,13 +10,14 @@
</head> </head>
<body> <body>
<div id="uw8"> <div id="uw8">
<a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.1.1 <a href="https://exoticorn.github.io/microw8">MicroW8</a> 0.1.2
</div> </div>
<div id="centered"> <div id="centered">
<canvas id="screen" width="320" height="240"> <canvas class="screen" id="screen" width="320" height="240">
</canvas> </canvas>
<div id="timer" hidden="true"></div> <button class="screen" id="start" style="display:none">Click to start</button>
<div id="message"></div> <div id="timer" hidden="true"></div>
<div id="message"></div>
<button id="cartButton" style="visibility:hidden">Load cart...</button> <button id="cartButton" style="visibility:hidden">Load cart...</button>
</div> </div>
<div id="footer"> <div id="footer">

View File

@@ -12,6 +12,7 @@ let uw8 = MicroW8(document.getElementById('screen'), {
setMessage, setMessage,
keyboardElement: window, keyboardElement: window,
timerElement: document.getElementById("timer"), timerElement: document.getElementById("timer"),
startButton: document.getElementById("start")
}); });
function runModuleFromHash() { function runModuleFromHash() {
@@ -79,7 +80,9 @@ if(location.hash.length != 0) {
url += 'cart.uw8'; url += 'cart.uw8';
} }
try { try {
await uw8.runModuleFromURL(url, true); if(!await uw8.runModuleFromURL(url, true)) {
setupLoad();
}
} catch(e) { } catch(e) {
setupLoad(); setupLoad();
} }

View File

@@ -1,5 +1,15 @@
import loaderUrl from "data-url:../../platform/bin/loader.wasm"; import loaderUrl from "data-url:../../platform/bin/loader.wasm";
import platformUrl from "data-url:../../platform/bin/platform.uw8"; import platformUrl from "data-url:../../platform/bin/platform.uw8";
import audioWorkletUrl from "data-url:./audiolet.js";
class AudioNode extends AudioWorkletNode {
constructor(context) {
super(context, 'apu', {outputChannelCount: [2]});
}
}
let U8 = (...a) => new Uint8Array(...a);
let U32 = (...a) => new Uint32Array(...a);
export default function MicroW8(screen, config = {}) { export default function MicroW8(screen, config = {}) {
if(!config.setMessage) { if(!config.setMessage) {
@@ -18,9 +28,6 @@ export default function MicroW8(screen, config = {}) {
let currentData; let currentData;
let U8 = (d) => new Uint8Array(d);
let U32 = (d) => new Uint32Array(d);
let pad = 0; let pad = 0;
let keyboardElement = config.keyboardElement == undefined ? screen : config.keyboardElement; let keyboardElement = config.keyboardElement == undefined ? screen : config.keyboardElement;
if(keyboardElement) { if(keyboardElement) {
@@ -90,6 +97,13 @@ export default function MicroW8(screen, config = {}) {
cancelFunction = null; cancelFunction = null;
} }
let audioContext = new AudioContext({sampleRate: 44100});
let keepRunning = true;
cancelFunction = () => {
audioContext.close();
keepRunning = false;
}
let cartridgeSize = data.byteLength; let cartridgeSize = data.byteLength;
config.setMessage(cartridgeSize); config.setMessage(cartridgeSize);
@@ -97,6 +111,40 @@ export default function MicroW8(screen, config = {}) {
return; return;
} }
await audioContext.audioWorklet.addModule(audioWorkletUrl);
let audioNode = new AudioNode(audioContext);
let audioReadyFlags = 0;
let audioReadyResolve;
let audioReadyPromise = new Promise(resolve => audioReadyResolve = resolve);
let updateAudioReady = (f) => {
audioReadyFlags |= f;
if(audioReadyFlags == 3 && audioReadyResolve) {
audioReadyResolve(true);
audioReadyResolve = null;
}
};
audioNode.port.onmessage = (e) => updateAudioReady(e.data);
let audioStateChange = () => {
if(audioContext.state == 'suspended') {
if(config.startButton) {
config.startButton.style = '';
screen.style = 'display:none';
}
(config.startButton || screen).onclick = () => {
audioContext.resume();
};
} else {
if(config.startButton) {
config.startButton.style = 'display:none';
screen.style = '';
}
updateAudioReady(1);
}
};
audioContext.onstatechange = audioStateChange;
audioStateChange();
currentData = data; currentData = data;
let newURL = window.location.pathname; let newURL = window.location.pathname;
@@ -119,7 +167,7 @@ export default function MicroW8(screen, config = {}) {
if(!devkitMode) { if(!devkitMode) {
memSize.maximum = 4; memSize.maximum = 4;
} }
let memory = new WebAssembly.Memory({ initial: 4, maximum: devkitMode ? 16 : 4 }); let memory = new WebAssembly.Memory(memSize);
let memU8 = U8(memory.buffer); let memU8 = U8(memory.buffer);
let importObject = { let importObject = {
@@ -142,9 +190,9 @@ export default function MicroW8(screen, config = {}) {
let instantiate = async (data) => (await WebAssembly.instantiate(data, importObject)).instance; let instantiate = async (data) => (await WebAssembly.instantiate(data, importObject)).instance;
let loadModuleURL = async (url) => instantiate(loadModuleData(await (await fetch(url)).arrayBuffer())); let loadModuleURL = async (url) => loadModuleData(await (await fetch(url)).arrayBuffer());
loader = await loadModuleURL(loaderUrl); loader = await instantiate(await loadModuleURL(loaderUrl));
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.env[n] = Math[n]; importObject.env[n] = Math[n];
@@ -160,7 +208,10 @@ export default function MicroW8(screen, config = {}) {
data = loadModuleData(data); data = loadModuleData(data);
let platform_instance = await loadModuleURL(platformUrl); let platform_data = await loadModuleURL(platformUrl);
audioNode.port.postMessage([platform_data, data]);
let platform_instance = await instantiate(platform_data);
for (let name in platform_instance.exports) { for (let name in platform_instance.exports) {
importObject.env[name] = platform_instance.exports[name] importObject.env[name] = platform_instance.exports[name]
@@ -170,14 +221,15 @@ export default function MicroW8(screen, config = {}) {
let buffer = U32(imageData.data.buffer); let buffer = U32(imageData.data.buffer);
let startTime = Date.now(); await audioReadyPromise;
let keepRunning = true; let startTime = Date.now();
cancelFunction = () => keepRunning = false;
const timePerFrame = 1000 / 60; const timePerFrame = 1000 / 60;
let nextFrame = startTime; let nextFrame = startTime;
audioNode.connect(audioContext.destination);
function mainloop() { function mainloop() {
if (!keepRunning) { if (!keepRunning) {
return; return;
@@ -216,10 +268,16 @@ export default function MicroW8(screen, config = {}) {
let u32Mem = U32(memory.buffer); let u32Mem = U32(memory.buffer);
u32Mem[16] = now - startTime; u32Mem[16] = now - startTime;
u32Mem[17] = pad | gamepad; u32Mem[17] = pad | gamepad;
instance.exports.upd(); if(instance.exports.upd) {
instance.exports.upd();
}
platform_instance.exports.endFrame(); platform_instance.exports.endFrame();
let palette = U32(memory.buffer.slice(0x13000, 0x13000 + 1024)); let soundRegisters = new ArrayBuffer(32);
U8(soundRegisters).set(U8(memory.buffer, 80, 32));
audioNode.port.postMessage(soundRegisters, [soundRegisters]);
let palette = U32(memory.buffer, 0x13000, 1024);
for (let i = 0; i < 320 * 240; ++i) { for (let i = 0; i < 320 * 240; ++i) {
buffer[i] = palette[memU8[i + 120]] | 0xff000000; buffer[i] = palette[memU8[i + 120]] | 0xff000000;
} }
@@ -305,10 +363,11 @@ export default function MicroW8(screen, config = {}) {
async function runModuleFromURL(url, keepUrl) { async function runModuleFromURL(url, keepUrl) {
let response = await fetch(url); let response = await fetch(url);
let type = response.headers.get('Content-Type'); let type = response.headers.get('Content-Type');
if(type && type.includes('html')) { if((type && type.includes('html')) || response.status != 200) {
throw false; return false;
} }
runModule(await response.arrayBuffer(), keepUrl || devkitMode); runModule(await response.arrayBuffer(), keepUrl || devkitMode);
return true;
} }
return { return {

View File

@@ -37,7 +37,7 @@ a:hover {
color: #405040; color: #405040;
} }
#screen { .screen {
width: 320px; width: 320px;
height: 240px; height: 240px;
image-rendering: pixelated; image-rendering: pixelated;
@@ -45,9 +45,16 @@ a:hover {
margin-bottom: 8px; margin-bottom: 8px;
border: 4px solid #303040; border: 4px solid #303040;
box-shadow: 5px 5px 20px black; box-shadow: 5px 5px 20px black;
}
#screen {
cursor: none; cursor: none;
} }
#start {
font-size: 150%;
}
#timer::before { #timer::before {
content: ''; content: '';
display: inline-block; display: inline-block;
@@ -84,21 +91,21 @@ button:active {
} }
@media (min-width: 680px) and (min-height: 620px) { @media (min-width: 680px) and (min-height: 620px) {
#screen { .screen {
width: 640px; width: 640px;
height: 480px; height: 480px;
} }
} }
@media (min-width: 1000px) and (min-height: 800px) { @media (min-width: 1000px) and (min-height: 800px) {
#screen { .screen {
width: 960px; width: 960px;
height: 720px; height: 720px;
} }
} }
@media (width:640px) and (height:480px) { @media (width:640px) and (height:480px) {
#screen { .screen {
width: 640px; width: 640px;
height: 480px; height: 480px;
border: 0; border: 0;