1
0
Fork 0
forked from AbleOS/ableos

Compare commits

...

122 commits

Author SHA1 Message Date
koniifer 90f1b3fdc5 possibly ata pio 2024-12-26 02:00:51 +00:00
koniifer 986077435f (sunset) fix mouse cursor and one multi-program crash bug 2024-12-26 00:38:46 +00:00
koniifer 530b62aa3d code churn to save the universe 2024-12-23 02:58:28 +00:00
Able b864463ad8 Merge branch 'master' of ssh://git.ablecorp.us:20/AbleOS/ableos 2024-12-22 16:23:46 -06:00
Able 1e1943d940 VFSaur swapped to slices and parse to exclude the : 2024-12-22 16:23:31 -06:00
Jakub Doka 47d727855d
adding instruction log
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-22 22:10:24 +01:00
koniifer 5b123be9ea semi-broken again 2024-12-22 19:48:12 +00:00
Able 2fb17ac610 VFSaur restructuring 2024-12-22 05:47:53 -06:00
koniifer 1ec9d0fd46 printf, various syntax updates, better string manipulation miscellaneous changes 2024-12-21 19:28:10 +00:00
Able 59cf6ef4d7 VFSaur work. String split bug. 2024-12-21 06:05:12 -06:00
koniifer 8cce5ef731 fiddling 2024-12-21 12:01:48 +00:00
koniifer 0fc95160cc tuple and array syntax 2024-12-20 11:21:03 +00:00
koniifer 25fecab5b3 new broken 2024-12-20 10:47:22 +00:00
Jakub Doka f6bfb73bd7
migrating to new hblang syntax
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-20 11:37:06 +01:00
koniifer f8523f5b3e working + fiddling 2024-12-19 19:07:54 +00:00
koniifer d2cb73c2ce almost enums 2024-12-19 17:29:39 +00:00
koniifer d0bd3714ee logger work 2024-12-19 17:19:57 +00:00
koniifer e8f1bce4d6 update test 2024-12-17 23:22:04 +00:00
Jakub Doka dc4878bc2b
fixing the optional formatting
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-18 00:08:59 +01:00
koniifer 04ca5f07d5 more and less broken 2024-12-17 22:30:22 +00:00
Jakub Doka ad587fe464
fixing a bug in a disasm
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
2024-12-17 20:24:53 +01:00
Jakub Doka 9a06b329f4
save 2024-12-17 19:23:01 +01:00
koniifer 936c9e6525 less less broken 2024-12-17 18:22:39 +00:00
koniifer a8572da351 less broken 2024-12-17 18:20:16 +00:00
koniifer b059faa7f8 broken for now 2024-12-17 17:43:00 +00:00
koniifer d55fd895c9 formatter update 2024-12-17 13:50:04 +00:00
koniifer e2dd379fea minor change 2024-12-17 02:10:30 +00:00
koniifer d907df14dd primitive string formatter with struct & array support 2024-12-17 02:06:48 +00:00
koniifer 3506c83535 math changes & compiler update 2024-12-16 14:36:14 +00:00
Able eff1323e94 fixes for the absolutely huge breakage pushed 2024-12-16 08:12:12 -06:00
Able 8849017db2 Merge branch 'master' of ssh://git.ablecorp.us:20/AbleOS/ableos 2024-12-16 08:01:46 -06:00
Able f3b78d1699 local changes 👍 2024-12-16 07:58:04 -06:00
koniifer 5eff0facb1 push 2024-12-16 13:22:03 +00:00
koniifer 6e3fea0713 fiddling and move some stuff to stn.math 2024-12-16 01:06:55 +00:00
koniifer 55c8d9b8b2 hblang update 2024-12-15 22:27:09 +00:00
koniifer 642b0b74b5 cooler mandelbrot 2024-12-15 22:05:06 +00:00
koniifer 5b3a97e580 fixed struct method things 2024-12-14 19:43:33 +00:00
koniifer ee68a2662c broken struct method things 2024-12-14 16:39:45 +00:00
Able 72cf91a928 proposed replacement for system.toml 2024-12-10 08:43:47 -06:00
Able f714775091 Stress testing. 2024-12-07 19:25:01 -06:00
Able 6af68994d8 Merge branch 'master' of ssh://git.ablecorp.us:20/AbleOS/ableos 2024-12-07 10:44:56 -06:00
Able df7982d9e5 ata pio mode 2024-12-07 10:44:29 -06:00
koniifer e688fdf4f0 cool mandelbrot also fix circle rendering a bit 2024-12-07 15:41:58 +00:00
Able bcc7c827ab omnibar change & conceptualization. 2024-12-05 11:04:28 -06:00
Able eff2a22018 begin work on hblang2 2024-12-05 11:03:07 -06:00
Able 883c01b2ba minor patch to make things more clear 2024-12-05 11:02:48 -06:00
Able 635ed1be42 theoretically works but is broken in practice :( 2024-12-04 04:21:24 -06:00
Able 36d50f6b38 filling out the ide_select_drive function 2024-12-04 03:58:23 -06:00
Able 559f25bb4e minor sketch work for ata 2024-12-04 03:53:13 -06:00
Able 82b9cb1206 a 2024-12-03 12:31:33 -06:00
Able 2afa83a615 update hblang compiler 2024-12-02 07:13:37 -06:00
Able 28258e0d45 hacky impl of a fetch program 2024-12-01 15:31:39 -06:00
Able 190f0941dc Remove old ps2_keyboard driver 2024-12-01 14:20:51 -06:00
Able 68840571c0 fat32 cleanup patch 2024-12-01 11:52:26 -06:00
Able dc3b7f71d5 arm arch patch 2024-12-01 11:44:46 -06:00
Able bff8db4c13 Merge branch 'peony-master' 2024-12-01 06:54:45 -06:00
peony 13c4649fd6 /shrug 2024-12-01 13:53:45 +01:00
peony f7f5b677e9 Merge 2024-12-01 13:53:44 +01:00
peony 821497fbe6 Deleted Cargo.lock 2024-12-01 13:52:12 +01:00
Able 5abdef4be6 Merge branch 'master' of ssh://git.ablecorp.us:20/AbleOS/ableos 2024-12-01 06:46:08 -06:00
Able b5282ea6fb rtc+tempfs skeleton 2024-12-01 06:45:34 -06:00
peony 498cfbf913 Removed error dump. 2024-12-01 13:39:40 +01:00
peony e3abec2927 Errorrr 2024-12-01 13:36:12 +01:00
peony b3d07b5235 Uhm, I dunno how that got there. 2024-12-01 13:13:13 +01:00
peony a93512eed1 Merged master. 2024-12-01 13:11:53 +01:00
peony c429641f98 Tiny commit. 2024-12-01 13:10:41 +01:00
koniifer db01da58e1 new path resolver and stuff 2024-11-30 21:52:18 +00:00
koniifer 38d3a10659 updates and updates 2024-11-30 11:46:33 +00:00
koniifer a551b2672f buffer awaiting -> free performance and free bugs 2024-11-27 16:53:17 +00:00
koniifer fd26ec734b temp interrupt fix, problem with sds_search_service 2024-11-27 12:52:48 +00:00
koniifer 9d1c59b65d consolidate simple tests, bug revealed 2024-11-27 12:41:51 +00:00
able cda022e6f0 Merge pull request 'Ktest major improvements' (#23) from funky/ableos:ktest_merge_conflict_fix into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/23
2024-11-27 06:16:25 -06:00
funky 95cf948d59 Ktest major improvements 2024-11-27 19:09:15 +11:00
koniifer f6a8a78b6c mini size fixes 2024-11-26 22:02:54 +00:00
kodin 5d152811b2 Interrupt Forwarding (#22)
Co-authored-by: Talha Qamar <qamartalha@proton.me>
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/22
Co-authored-by: kodin <kodin@yourmoms.house>
Co-committed-by: kodin <kodin@yourmoms.house>
2024-11-26 15:53:50 -06:00
koniifer 685c6f0b20 task scheduler weirdness 2024-11-26 19:32:19 +00:00
Able 1b3dc153e8 SDoom + pcspkr: Both prerelease 2024-11-26 07:39:16 -06:00
Able 9aa84a0f40 👍 checkpoint 2024-11-24 23:51:37 -06:00
Able bdb762c986 Magic function style guide 2024-11-24 23:50:46 -06:00
koniifer 0b57c2e9bb simple foldhash implementation 2024-11-24 20:58:14 +00:00
Able 8c88c0b5ae defer in alloc 2024-11-24 12:43:15 -06:00
Able 8b2b50e433 Style guide update, vscode config to make tab indent follow the style guide 2024-11-24 12:22:06 -06:00
Able d7e0d573e2 Style guide commit. Feel free to bikeshed about it. What should be added etcetc 2024-11-24 11:57:06 -06:00
Able 0ee8b7a4e4 janky error handling 2024-11-24 11:08:22 -06:00
Able 2261f36101 simply just dont inline 2024-11-24 11:04:12 -06:00
Able 6f82c92c30 sorta alloc support. Compiler error checkpoint 2024-11-24 11:03:06 -06:00
koniifer 5ea3ee9fe1 able sanity check 2024-11-24 16:39:24 +00:00
Able 241139f5af changes 2024-11-24 10:18:09 -06:00
Able 5c4056bc5c commit checkpoint 2024-11-24 10:00:24 -06:00
peony 5028062e39 Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-24 13:32:27 +01:00
peony f7f9fece4f Merged once more 2024-11-24 13:31:57 +01:00
able b505622601 Merge pull request 'Ktest + Nix Flake' (#20) from FunkyEgg/ableos:master into master
Reviewed-on: https://git.ablecorp.us/AbleOS/ableos/pulls/20
2024-11-23 21:13:23 -06:00
peony f4ceab972c Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-23 17:13:04 +01:00
peony 96c07e137b Removed error.error because its in #aos-geeral. 2024-11-18 20:47:46 +01:00
peony d78878a12f Compiler error 2024-11-18 20:29:51 +01:00
peony 8f265ebf40 PS/2 literally almost work 2024-11-17 22:59:05 +01:00
peony 3d5a8f6f10 End meeeee 2024-11-17 22:38:07 +01:00
peony f11122e58e Merge master 2024-11-17 21:31:51 +01:00
peony 2fdede7199 PS/2 workkkk 2024-11-17 21:30:58 +01:00
peony 13422dfd9f Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-17 19:11:33 +01:00
peony 90a97cd160 more work 2024-11-17 19:11:13 +01:00
peony 23b45b1887 Driver workkkk 2024-11-17 17:57:06 +01:00
peony cf37eaf086 Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-17 11:17:59 +01:00
peony 284aa5a5e6 PS/2 is so close 2024-11-17 11:17:32 +01:00
peony 11976b752f PS/2 driver going well (it still doesn't work) 2024-11-16 22:56:00 +01:00
peony 98b15d4c10 Merge master 2024-11-16 21:52:45 +01:00
peony f5c6d7d822 PS/2 driver refactoring and poassibly completion process 2024-11-16 21:51:55 +01:00
peony efcd6c0631 Uuugh, jesus this sucks 2024-11-15 22:55:44 +01:00
peony b795aced8e Merge branch 'master' of https://git.ablecorp.us/AbleOS/ableos 2024-11-15 20:48:23 +01:00
peony 08099b0877 Barely any PS/2 driver work 2024-11-15 20:47:11 +01:00
peony a1bfd8e85f Driver not work 2024-11-12 22:36:43 +01:00
peony edfb588060 Merge main. 2024-11-10 21:26:54 +01:00
peony cc4a32afaa PS/2 work 2024-11-10 21:24:19 +01:00
peony be6a095c14 Cargo stuff 2024-11-10 19:14:20 +01:00
peony aac1164d55 More git stuff 2024-11-10 15:45:01 +01:00
peony 89d08d8a62 Alighning with master. 2024-11-10 15:44:17 +01:00
peony 8f5833955f Circle test. (Precision issues) 2024-11-10 15:42:41 +01:00
peony 4c0adbe15d Circle rendring. 2024-11-10 15:19:55 +01:00
peony 3708acc077 Revert to mainline 2024-11-10 15:09:41 +01:00
peony b5b122f451 Complete revert to mainline, I think? 2024-11-10 15:04:59 +01:00
peony 39ebaa03ba Uuuugh 2024-10-14 14:35:41 +02:00
peony de8000f596 Fixed software renderer; added vline,hline,trirect 2024-10-13 23:15:10 +02:00
143 changed files with 3693 additions and 1634 deletions

View file

@ -1,4 +1,6 @@
{
"editor.insertSpaces": false,
"editor.detectIndentation": false,
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.showUnlinkedFileNotification": false,
"C_Cpp.errorSquiggles": "disabled"

94
Cargo.lock generated
View file

@ -13,15 +13,15 @@ dependencies = [
[[package]]
name = "allocator-api2"
version = "0.2.20"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "anyhow"
version = "1.0.93"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
name = "autocfg"
@ -73,9 +73,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.2.1"
version = "1.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
dependencies = [
"shlex",
]
@ -88,18 +88,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-queue"
version = "0.3.11"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35"
checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "derive_more"
@ -175,9 +175,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foldhash"
version = "0.1.3"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
[[package]]
name = "form_urlencoded"
@ -201,9 +201,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.1"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
dependencies = [
"allocator-api2",
"equivalent",
@ -213,12 +213,12 @@ dependencies = [
[[package]]
name = "hbbytecode"
version = "0.1.0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#86ca959ea3eae1cb32298e135a444820583d24a0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#08fc9d6ab6a8dd539255bf45d892f4b7f08776c5"
[[package]]
name = "hblang"
version = "0.1.0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#86ca959ea3eae1cb32298e135a444820583d24a0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#08fc9d6ab6a8dd539255bf45d892f4b7f08776c5"
dependencies = [
"hashbrown",
"hbbytecode",
@ -229,7 +229,7 @@ dependencies = [
[[package]]
name = "hbvm"
version = "0.1.0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#86ca959ea3eae1cb32298e135a444820583d24a0"
source = "git+https://git.ablecorp.us/AbleOS/holey-bytes.git#08fc9d6ab6a8dd539255bf45d892f4b7f08776c5"
dependencies = [
"hbbytecode",
]
@ -375,9 +375,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.6.0"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
"hashbrown",
@ -401,7 +401,7 @@ dependencies = [
"uart_16550",
"versioning",
"x2apic",
"x86_64 0.15.1",
"x86_64 0.15.2",
"xml",
]
@ -421,9 +421,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.164"
version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f"
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "limine"
@ -455,18 +455,18 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "logos"
version = "0.14.2"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c6b6e02facda28ca5fb8dbe4b152496ba3b1bd5a4b40bb2b1b2d8ad74e0f39b"
checksum = "7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458"
dependencies = [
"logos-derive",
]
[[package]]
name = "logos-codegen"
version = "0.14.2"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b32eb6b5f26efacd015b000bfc562186472cd9b34bdba3f6b264e2a052676d10"
checksum = "59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f"
dependencies = [
"beef",
"fnv",
@ -479,9 +479,9 @@ dependencies = [
[[package]]
name = "logos-derive"
version = "0.14.2"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e5d0c5463c911ef55624739fc353238b4e310f0144be1f875dc42fec6bfd5ec"
checksum = "24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d"
dependencies = [
"logos-codegen",
]
@ -593,9 +593,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.23.18"
version = "0.23.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f"
checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
dependencies = [
"log",
"once_cell",
@ -608,9 +608,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
version = "1.10.0"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
[[package]]
name = "rustls-webpki"
@ -643,24 +643,24 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.23"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
[[package]]
name = "serde"
version = "1.0.215"
version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.215"
version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
dependencies = [
"proc-macro2",
"quote",
@ -726,9 +726,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.89"
version = "2.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035"
dependencies = [
"proc-macro2",
"quote",
@ -827,9 +827,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "ureq"
version = "2.10.1"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a"
checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
dependencies = [
"base64",
"log",
@ -996,7 +996,7 @@ dependencies = [
"bitflags 1.3.2",
"paste",
"raw-cpuid 10.7.0",
"x86_64 0.14.12",
"x86_64 0.14.13",
]
[[package]]
@ -1012,9 +1012,9 @@ dependencies = [
[[package]]
name = "x86_64"
version = "0.14.12"
version = "0.14.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96cb6fd45bfeab6a5055c5bffdb08768bd0c069f1d946debe585bbb380a7c062"
checksum = "c101112411baafbb4bf8d33e4c4a80ab5b02d74d2612331c61e8192fc9710491"
dependencies = [
"bit_field",
"bitflags 2.6.0",
@ -1024,9 +1024,9 @@ dependencies = [
[[package]]
name = "x86_64"
version = "0.15.1"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bc79523af8abf92fb1a970c3e086c5a343f6bcc1a0eb890f575cbb3b45743df"
checksum = "0f042214de98141e9c8706e8192b73f56494087cc55ebec28ce10f26c5c364ae"
dependencies = [
"bit_field",
"bitflags 2.6.0",

77
STYLE_GUIDE.md Normal file
View file

@ -0,0 +1,77 @@
# Style Guide
This style guide has two modes that a guideline may be.
`strict` means that prs will be rejected if they do not follow the guideline.
`loose` means that a pr would be accepted but should later be fixed.
## Empty Functions | loose
Empty functions are typically a sign of an unfinished program or driver.
In cases where there is a clear reason to have an empty function it will be allowed.
For example FakeAlloc is only empty functions because it is a example of an the allocator api.
### Allowed
```rust
/// in example.hb
a := fn(): void {}
```
### Not Allowed
```rust
/// in fat32.hb
a := fn(): void {}
```
## Magic Functions | loose
'Magic functions' are what I am calling small helper functions that do one or two things.
### Example
```rust
a := null
magic_a := fn(){
a = 10
}
```
The exact policy I want to have here is a bit fuzzy. I think that functions like this are nice in certain situations and not in others.
Regardless of if you use them or not, put a comment above the function explaining rational.
## Magic Numbers | loose
The policy on magic numbers is make them const and have a comment above them. Typically linking to a source of information about the magic number.
This helps cut down on magic numbers while making acceptable names and atleast half assed documentation.
Constants are inlined anyways, so its the same thing in the binary.
```rust
// The standard vga port is mapped at 0xB8000
$VGA_PTR := 0xB8000
```
## Tabs Vs Spaces | strict
I prefer for hblang code to use hard tabs.
The rational behind this is that a tab is `1 Indent` which some developers might want to be various different sizes when displayed
Soft tabs do not allow this user/editor specific as soft tabs always become spaces.
Bottom line is this is an accessibility feature.
There are some samples below.
```
\t means hard tab
\n means new line
\0x20 means space
```
### Allowed
```rust
if x == y {\n
\tlog(z)\n
}\n
```
### Not Allowed
```rust
if x == y {\n
\0x20\0x20\0x20\0x20log(z)\n
}\n
```

View file

@ -9,7 +9,7 @@ ktest = []
[dependencies]
# embedded-graphics = "0.8"
hbvm = { git = "https://git.ablecorp.us/AbleOS/holey-bytes.git", features = [
"nightly",
"nightly", "alloc", "disasm"
] }
ktest_macro = { path = "ktest_macro" }
log = "0.4"

View file

@ -1,28 +1,85 @@
extern crate proc_macro;
extern crate quote;
extern crate syn;
use {
proc_macro::TokenStream,
quote::quote,
syn::{parse_macro_input, ItemFn}
syn::{parse::Parse, parse_macro_input, Expr, ItemFn, Token}
};
struct KtestInput {
lhs: Expr,
_comma: Token![,],
rhs: Expr,
}
impl Parse for KtestInput {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
Ok(Self {
lhs: input.parse()?,
_comma: input.parse()?,
rhs: input.parse()?,
})
}
}
#[proc_macro]
pub fn ktest_eq(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as KtestInput);
let lhs = input.lhs;
let rhs = input.rhs;
let out = quote! {
if #lhs != #rhs {
return Err(name);
}
};
TokenStream::from(out)
}
#[proc_macro]
pub fn ktest_neq(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as KtestInput);
let lhs = input.lhs;
let rhs = input.rhs;
let out = quote! {
if #lhs == #rhs {
return Err(name);
}
};
TokenStream::from(out)
}
#[proc_macro_attribute]
pub fn ktest(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn);
let test_name = &input.sig.ident;
let test_string = test_name.to_string();
let static_var_name = syn::Ident::new(
&format!("__ktest_{}", test_name),
&format!("__ktest_{}", test_name).to_uppercase(),
test_name.span(),
);
let out = quote! {
// #[cfg(feature = "ktest")]
#input
// #[cfg(feature = "ktest")]
let block = &input.block;
let out = quote! {
#[cfg(feature = "ktest")]
fn #test_name() -> Result<String, String> {
use crate::alloc::string::ToString;
let name = #test_string.to_string();
#block
return Ok(name);
}
#[cfg(feature = "ktest")]
#[unsafe(link_section = ".note.ktest")]
#[used]
pub static #static_var_name: fn() = #test_name;
pub static #static_var_name: fn() -> Result<String, String> = #test_name;
};
TokenStream::from(out)

View file

@ -6,6 +6,11 @@ SECTIONS
.text.boot : { *(.text.boot) }
.text : { *(.text) }
.data : { *(.data) }
.note.ktest : {
__ktest_start = .;
*(.note.ktest)
__ktest_end = .;
}
.rodata : { *(.rodata) }
.bss : {
*(COMMON)

View file

@ -62,7 +62,7 @@ extern "x86-interrupt" fn page_fault(
}
extern "x86-interrupt" fn timer(_isf: InterruptStackFrame) {
// interrupt(Interrupt::Timer);
interrupt(Interrupt::Timer);
unsafe {
LAPIC.end_of_interrupt();
@ -83,28 +83,31 @@ extern "x86-interrupt" fn spurious(_: InterruptStackFrame) {
}
}
#[allow(unused_imports)]
fn interrupt(interrupt_type: Interrupt) {
use crate::arch::INTERRUPT_LIST;
let il = INTERRUPT_LIST.lock();
let val = il.list.get(&interrupt_type).unwrap();
use crate::{arch::INTERRUPT_LIST, kmain::EXECUTOR};
// let il = INTERRUPT_LIST.lock();
// let val = il.list.get(&interrupt_type).unwrap();
use crate::holeybytes::kernel_services::service_definition_service::sds_search_service;
let buffer = sds_search_service(val);
if buffer != 0 {
use {crate::kmain::IPC_BUFFERS, alloc::vec::Vec};
let mut buffs = IPC_BUFFERS.lock();
match buffs.get_mut(&buffer) {
Some(buff) => {
let mut msg_vec = Vec::new();
msg_vec.push(0xFF);
buff.push(msg_vec.to_vec());
log::debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer);
}
None => {
log::error!("Access of non-existent buffer {}", buffer)
}
}
// use crate::holeybytes::kernel_services::service_definition_service::sds_search_service;
// let buffer = sds_search_service(val);
// if buffer != 0 {
// use {crate::kmain::IPC_BUFFERS, alloc::vec::Vec};
// let mut buffs = IPC_BUFFERS.lock();
// match buffs.get_mut(&buffer) {
// Some(buff) => {
// let mut msg_vec = Vec::new();
// msg_vec.push(0xFF);
// buff.push(msg_vec.to_vec());
// log::debug!("Sent Message {:?} to Buffer({})", msg_vec, buffer);
// }
// None => {
// log::error!("Access of non-existent buffer {}", buffer)
// }
// }
// }
// log::info!("{}", buffer);
unsafe {
EXECUTOR.send_interrupt(interrupt_type as u8);
}
}

View file

@ -33,7 +33,7 @@ unsafe fn x86_in<T: x86_64::instructions::port::PortRead>(address: u16) -> T {
}
#[inline(always)]
pub fn handler(vm: &mut Vm) {
pub fn handler(vm: &mut Vm, pid: &usize) {
let ecall_number = vm.registers[2].cast::<u64>();
match ecall_number {
@ -80,6 +80,10 @@ pub fn handler(vm: &mut Vm) {
let length = vm.registers[5].cast::<u64>() as usize;
trace!("IPC address: {:?}", mem_addr);
unsafe { LazyCell::<Executor>::get_mut(&mut EXECUTOR) }
.unwrap()
.send_buffer(buffer_id as usize);
match buffer_id {
0 => match sds_msg_handler(vm, mem_addr, length) {
Ok(()) => {}
@ -209,7 +213,6 @@ pub fn handler(vm: &mut Vm) {
let buffer_id = vm.registers[3].cast::<u64>();
let map_ptr = vm.registers[4].cast::<u64>();
let max_length = vm.registers[5].cast::<u64>();
let mut buffs = IPC_BUFFERS.lock();
let buff: &mut IpcBuffer = match buffs.get_mut(&buffer_id) {
Some(buff) => buff,
@ -243,6 +246,28 @@ pub fn handler(vm: &mut Vm) {
vm.registers[3] = x
}
}
6 => {
// Wait till interrupt
use crate::kmain::EXECUTOR;
let interrupt_type = vm.registers[3].cast::<u8>();
debug!("Interrupt subscribed: {}", interrupt_type);
unsafe {
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
.unwrap()
.interrupt_subscribe(*pid, interrupt_type);
}
}
7 => {
// Wait till buffer
use crate::kmain::EXECUTOR;
let buffer_id = vm.registers[3].cast::<u64>() as usize;
debug!("Buffer subscribed: {}", buffer_id);
unsafe {
LazyCell::<Executor>::get_mut(&mut EXECUTOR)
.unwrap()
.buffer_subscribe(*pid, buffer_id);
}
}
_ => {
log::error!("Syscall unknown {:?}{:?}", ecall_number, vm.registers);
}

View file

@ -96,18 +96,21 @@ pub fn memory_msg_handler(
log::debug!(" {} pages", page_count);
}
4 => unsafe {
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
let src = u64::from_le_bytes(msg_vec[5..13].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[13..21].try_into().unwrap_unchecked()) as *mut u8;
let count = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap_unchecked()) as usize;
let src = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *mut u8;
debug_assert!(src.addr() & 0xFFFF000000000000 != 0);
debug_assert!(dest.addr() & 0xFFFF000000000000 != 0);
src.copy_to_nonoverlapping(dest, count);
},
5 => unsafe {
let count = u32::from_le_bytes(msg_vec[1..5].try_into().unwrap_unchecked()) as usize;
let size = u32::from_le_bytes(msg_vec[5..9].try_into().unwrap_unchecked()) as usize;
let src = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *mut u8;
let count = u64::from_le_bytes(msg_vec[1..9].try_into().unwrap_unchecked()) as usize;
let size = u64::from_le_bytes(msg_vec[9..17].try_into().unwrap_unchecked()) as usize;
let src =
u64::from_le_bytes(msg_vec[17..25].try_into().unwrap_unchecked()) as *const u8;
let dest = u64::from_le_bytes(msg_vec[25..33].try_into().unwrap_unchecked()) as *mut u8;
debug_assert!(src.addr() & 0xFFFF000000000000 != 0);
debug_assert!(dest.addr() & 0xFFFF000000000000 != 0);
memset(dest, src, count, size);
},
_ => {

View file

@ -15,8 +15,10 @@ fn calc_start_of_page(ptr: u64) -> u64 {
panic!("unaligned");
}
#[derive(Default)]
pub struct Memory {
// TODO: map page aligned segments of memory into a table or some sort here
logger: hbvm::mem::InstrLogger,
}
impl Memory {
@ -56,4 +58,11 @@ impl hbvm::mem::Memory for Memory {
unsafe fn prog_read<T: Copy>(&mut self, addr: Address) -> T {
(addr.get() as *const T).read()
}
#[inline(always)]
fn log_instr(&mut self, at: Address, regs: &[hbvm::value::Value]) {
log::debug!("exec: [{:02x}] {}", at.get(), unsafe {
self.logger.display_instr(at, regs)
});
}
}

View file

@ -36,7 +36,7 @@ impl ExecThread {
pub unsafe fn new(program: &[u8], entrypoint: Address) -> Self {
let mut vm = Vm::new(
mem::Memory {},
mem::Memory::default(),
Address::new(program.as_ptr() as u64 + entrypoint.get()),
);
@ -65,7 +65,12 @@ impl<'p> Future for ExecThread {
return Poll::Ready(Err(err));
}
Ok(VmRunOk::End) => return Poll::Ready(Ok(())),
Ok(VmRunOk::Ecall) => ecah::handler(&mut self.vm),
Ok(VmRunOk::Ecall) => ecah::handler(
&mut self.vm,
cx.ext()
.downcast_ref()
.expect("PID did not exist in Context"),
),
Ok(VmRunOk::Timer) => (),
Ok(VmRunOk::Breakpoint) => {
log::error!(

View file

@ -22,12 +22,16 @@ use {
pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
debug!("Entered kmain");
#[cfg(feature = "ktest")] {
use crate::ktest;
debug!("TESTING");
#[cfg(feature = "ktest")]
{
use {
crate::ktest,
log::info,
};
info!("Running tests");
ktest::test_main();
loop {};
loop {}
}
// let kcmd = build_cmd("Kernel Command Line", cmdline);
@ -75,6 +79,7 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
"Graphics front ptr {:?}",
fb1.address.as_ptr().unwrap() as *const u8
);
log::info!("Started AbleOS");
unsafe {
let executor = LazyCell::<Executor>::force_mut(&mut EXECUTOR);
@ -120,7 +125,7 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
if cmd_len > 0 {
thr.set_arguments(cmd.as_ptr() as u64, cmd_len);
}
executor.spawn(Box::pin(async move {
executor.spawn(Box::pin(async {
if let Err(e) = thr.await {
log::error!("{e:?}");
}
@ -131,7 +136,6 @@ pub fn kmain(_cmdline: &str, boot_modules: BootModules) -> ! {
executor.run();
};
crate::arch::spin_loop()
}

View file

@ -1,38 +1,51 @@
pub use ktest_macro::ktest;
use log::debug;
pub use ktest_macro::*;
use {
alloc::string::String,
log::{error, info},
};
extern "C" {
static __ktest_start: fn();
static __ktest_end: fn();
static __ktest_start: fn() -> Result<String, String>;
static __ktest_end: fn() -> Result<String, String>;
}
// TODO: Get test_fn linker name (may require no_mangle in macro)
// More info on tests (run the rest even if panic)
// Implement ktest for arm and riscv (Later problems, see below)
// TODO: Implement ktest for arm and riscv (Later problems, see below)
// Allow for arch specific tests (Leave for now)
// Allow for ktest test name attr
// Usefull message at the end of testing
// Should panic tests
// Test specific panic handler
pub fn test_main() {
unsafe {
let mut current_test = &__ktest_start as *const fn();
let mut current = 1;
let test_end = &__ktest_end as *const fn();
let mut current_test = &__ktest_start as *const fn() -> Result<String, String>;
let test_end = &__ktest_end as *const fn() -> Result<String, String>;
let mut pass = 0;
let mut fail = 0;
while current_test < test_end {
let test_fn = *current_test;
debug!("Running test {}", current);
test_fn();
debug!("Test {} passed", current);
let test_name = test_fn();
match test_name {
Ok(name) => {
info!("Test: {} passed", name);
pass += 1;
},
Err(name) => {
error!("Test: {} failed", name);
fail += 1;
}
}
current_test = current_test.add(1);
current += 1;
}
info!("{}/{} tests passed", pass, pass + fail);
}
}
#[ktest]
pub fn trivial_assertion() {
assert_eq!(1, 1);
}
ktest_eq!(1, 1);
ktest_neq!(0, 1);
}

View file

@ -10,9 +10,11 @@
abi_x86_interrupt,
lazy_get,
alloc_error_handler,
local_waker,
context_ext,
ptr_sub_ptr,
naked_functions,
pointer_is_aligned_to,
pointer_is_aligned_to
)]
#![allow(dead_code, internal_features, static_mut_refs)]
extern crate alloc;
@ -32,10 +34,9 @@ mod memory;
mod task;
mod utils;
// #[cfg(feature = "tests")]
#[allow(improper_ctypes, non_upper_case_globals)]
mod ktest;
use alloc::string::ToString;
use versioning::Version;
/// Kernel's version
@ -48,6 +49,7 @@ pub const VERSION: Version = Version {
#[panic_handler]
#[cfg(target_os = "none")]
fn panic(info: &core::panic::PanicInfo) -> ! {
use alloc::string::ToString;
arch::register_dump();
if let Some(loc) = info.location() {

View file

@ -1,9 +1,14 @@
use {
alloc::{boxed::Box, sync::Arc},
alloc::{
boxed::Box,
collections::{BTreeMap, BTreeSet},
sync::Arc,
},
core::{
future::Future,
pin::Pin,
task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
sync::atomic::{AtomicBool, Ordering},
task::{Context, ContextBuilder, Poll, RawWaker, RawWakerVTable, Waker},
},
crossbeam_queue::SegQueue,
slab::Slab,
@ -14,7 +19,6 @@ pub fn yield_now() -> impl Future<Output = ()> {
impl Future for YieldNow {
type Output = ();
#[inline(always)]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.0 {
Poll::Ready(())
@ -29,150 +33,184 @@ pub fn yield_now() -> impl Future<Output = ()> {
YieldNow(false)
}
pub trait Process: Future<Output = ()> + Send {}
impl<T: Future<Output = ()> + Send> Process for T {}
pub struct Executor {
tasks: Slab<Task>,
task_queue: Arc<TaskQueue>,
tasks: Slab<Task>,
task_queue: Arc<SegQueue<usize>>,
interrupt_lookup: [Option<usize>; u8::MAX as usize],
buffer_lookup: BTreeMap<usize, BTreeSet<usize>>,
}
impl Executor {
pub fn new() -> Self {
Self {
tasks: Slab::new(),
task_queue: Arc::new(TaskQueue::new()),
tasks: Slab::new(),
task_queue: Arc::new(SegQueue::new()),
interrupt_lookup: [None; u8::MAX as usize],
buffer_lookup: BTreeMap::new(),
}
}
#[inline]
pub fn spawn(&mut self, future: Pin<Box<dyn Future<Output = ()> + Send>>) -> usize {
pub fn spawn(&mut self, future: Pin<Box<dyn Process>>) -> usize {
let id = self.tasks.insert(Task::new(future));
self.task_queue.queue.push(id);
self.task_queue.push(id);
id
}
pub fn pause(&self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(true);
}
}
pub fn unpause(&self, id: usize) {
if let Some(task) = self.tasks.get(id) {
task.set_paused(false);
self.task_queue.push(id);
}
}
pub fn interrupt_subscribe(&mut self, pid: usize, interrupt_type: u8) {
self.pause(pid);
self.interrupt_lookup[interrupt_type as usize] = Some(pid);
}
pub fn buffer_subscribe(&mut self, pid: usize, buffer_id: usize) {
self.pause(pid);
if let Some(buf) = self.buffer_lookup.get_mut(&buffer_id) {
buf.insert(pid);
} else {
self.buffer_lookup.insert(buffer_id, BTreeSet::from([pid]));
}
}
pub fn run(&mut self) {
let mut task_batch = [0; 32];
let mut batch_len = 0;
loop {
self.task_queue.batch_pop(&mut task_batch, &mut batch_len);
let mut batch_len = 0;
if batch_len == 0 {
if self.task_queue.is_empty() {
while let Some(id) = self.task_queue.pop() {
task_batch[batch_len] = id;
batch_len += 1;
if batch_len == task_batch.len() {
break;
} else {
continue;
}
}
for &id in &task_batch[..batch_len] {
if let Some(task) = self.tasks.get_mut(id) {
let waker = task
.waker
.get_or_insert_with(|| TaskWaker::new(id, Arc::clone(&self.task_queue)));
if batch_len == 0 {
// break;
continue;
}
let waker = unsafe { Waker::from_raw(TaskWaker::into_raw_waker(waker)) };
let mut cx = Context::from_waker(&waker);
for &(mut id) in &task_batch[..batch_len] {
if let Some(task) = self.tasks.get_mut(id) {
if task.is_paused() {
continue;
}
let waker = create_waker(id, Arc::clone(&self.task_queue));
let mut cx = ContextBuilder::from_waker(&waker).ext(&mut id).build();
if let Poll::Ready(()) = task.poll(&mut cx) {
self.tasks.remove(id);
self.task_queue.free_tasks.push(id);
self.interrupt_lookup.map(|pid| {
if let Some(pid) = pid {
if pid == id {
return None;
}
}
return pid;
});
self.buffer_lookup.iter_mut().for_each(|(_, pid_set)| {
pid_set.remove(&id);
});
}
}
}
}
}
pub fn send_interrupt(&self, interrupt: u8) {
let id = self.interrupt_lookup[interrupt as usize];
if let Some(id) = id {
self.unpause(id);
}
}
pub fn send_buffer(&self, id: usize) {
if let Some(buf) = self.buffer_lookup.get(&id) {
buf.iter().for_each(|pid| self.unpause(*pid));
}
}
}
struct Task {
future: Pin<Box<dyn Future<Output = ()> + Send>>,
waker: Option<TaskWaker>,
future: Pin<Box<dyn Process>>,
paused: AtomicBool,
}
impl Task {
#[inline(always)]
pub fn new(future: Pin<Box<dyn Future<Output = ()> + Send>>) -> Self {
fn new(future: Pin<Box<dyn Process>>) -> Self {
Self {
future,
waker: None,
paused: AtomicBool::new(false),
}
}
#[inline(always)]
fn poll(&mut self, cx: &mut Context) -> Poll<()> {
self.future.as_mut().poll(cx)
}
fn is_paused(&self) -> bool {
self.paused.load(Ordering::Acquire)
}
fn set_paused(&self, paused: bool) {
self.paused.store(paused, Ordering::Release)
}
}
fn create_waker(task_id: usize, task_queue: Arc<SegQueue<usize>>) -> Waker {
let data = Box::new(TaskWaker {
task_id,
task_queue,
});
let raw_waker = RawWaker::new(Box::into_raw(data) as *const (), &VTABLE);
unsafe { Waker::from_raw(raw_waker) }
}
#[derive(Clone)]
struct TaskWaker {
id: usize,
task_queue: Arc<TaskQueue>,
task_id: usize,
task_queue: Arc<SegQueue<usize>>,
}
impl TaskWaker {
#[inline(always)]
fn new(id: usize, task_queue: Arc<TaskQueue>) -> Self {
Self { id, task_queue }
}
#[inline(always)]
fn wake(&self) {
self.task_queue.queue.push(self.id);
}
fn into_raw_waker(waker: &TaskWaker) -> RawWaker {
let ptr = waker as *const TaskWaker;
RawWaker::new(ptr.cast(), &VTABLE)
self.task_queue.push(self.task_id);
}
}
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone_raw, wake_raw, wake_by_ref_raw, drop_raw);
unsafe fn clone_raw(ptr: *const ()) -> RawWaker {
let waker = &*(ptr as *const TaskWaker);
TaskWaker::into_raw_waker(waker)
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
let raw_waker = RawWaker::new(Box::into_raw(task_waker.clone()) as *const (), &VTABLE);
raw_waker
}
unsafe fn wake_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
let task_waker = Box::from_raw(ptr as *mut TaskWaker);
task_waker.wake();
}
unsafe fn wake_by_ref_raw(ptr: *const ()) {
let waker = &*(ptr as *const TaskWaker);
waker.wake();
let task_waker = &*(ptr as *const TaskWaker);
task_waker.wake();
}
unsafe fn drop_raw(_: *const ()) {}
struct TaskQueue {
queue: SegQueue<usize>,
next_task: usize,
free_tasks: SegQueue<usize>,
}
impl TaskQueue {
fn new() -> Self {
Self {
queue: SegQueue::new(),
next_task: 0,
free_tasks: SegQueue::new(),
}
}
#[inline(always)]
fn batch_pop(&self, output: &mut [usize], len: &mut usize) {
*len = 0;
while let Some(id) = self.queue.pop() {
output[*len] = id;
*len += 1;
if *len == output.len() {
break;
}
}
}
#[inline(always)]
fn is_empty(&self) -> bool {
self.queue.is_empty()
}
unsafe fn drop_raw(ptr: *const ()) {
drop(Box::from_raw(ptr as *mut TaskWaker));
}

View file

@ -1,25 +1,25 @@
{
"arch": "aarch64",
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
"disable-redzone": true,
"env": "",
"executables": true,
"features": "+strict-align,+neon,+fp-armv8",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"linker-is-gnu": true,
"pre-link-args": {
"ld.lld": [
"-Tkernel/lds/aarch64-qemu.ld"
]
},
"llvm-target": "aarch64-unknown-none",
"max-atomic-width": 128,
"os": "none",
"panic-strategy": "abort",
"relocation-model": "static",
"target-c-int-width": "32",
"target-endian": "little",
"target-pointer-width": "64",
"vendor": ""
"arch": "aarch64",
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
"disable-redzone": true,
"env": "",
"executables": true,
"features": "+strict-align,+neon,+fp-armv8",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"linker-is-gnu": true,
"pre-link-args": {
"ld.lld": [
"-Tkernel/lds/aarch64-qemu.ld"
]
},
"llvm-target": "aarch64-unknown-none",
"max-atomic-width": 128,
"os": "none",
"panic-strategy": "abort",
"relocation-model": "static",
"target-c-int-width": "32",
"target-endian": "little",
"target-pointer-width": "64",
"vendor": "ablecorp"
}

View file

@ -15,6 +15,7 @@ fatfs = { version = "0.3", default-features = false, features = [
] }
toml = "0.8"
hblang.git = "https://git.ablecorp.us/AbleOS/holey-bytes.git"
# hblang.path = "../../holey-bytes/lang/"
log = "0.4"
raw-cpuid = "11"
ureq = { version = "2", default-features = false, features = ["tls"] }

View file

@ -83,7 +83,8 @@ impl Package {
&path,
Options {
fmt: true,
in_house_regalloc: true,
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
..Default::default()
},
out,
@ -99,7 +100,7 @@ impl Package {
hblang::run_compiler(
&path,
Options {
in_house_regalloc: true,
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
..Default::default()
},
out,
@ -108,18 +109,20 @@ impl Package {
std::fs::write(format!("target/programs/{}.hbf", self.name), &out)?;
out.clear();
hblang::run_compiler(
let err = hblang::run_compiler(
&path,
Options {
resolver: Some(hblang::ABLEOS_PATH_RESOLVER),
dump_asm: true,
in_house_regalloc: true,
..Default::default()
},
out,
&mut warnings,
)?;
);
std::fs::write(format!("target/programs/{}.hba", self.name), &out)?;
out.clear();
return err;
}
Ok(())
}

View file

@ -90,7 +90,7 @@ fn main() -> Result<(), Error> {
} else if arg == "avx2" {
target = Target::X86_64Avx2;
} else if arg == "--ktest" {
tests = true;
tests = true;
} else {
return Err(report!(Error::InvalidSubCom));
}
@ -253,10 +253,10 @@ TERM_BACKDROP={}
);
match p.build(&mut out) {
Ok(()) => {}
Err(_) => {
writeln!(errors, "========= while compiling {} =========", path)
Err(e) => {
writeln!(errors, "========= while compiling {} {} =========", path, e)
.unwrap();
errors.push_str(core::str::from_utf8(&out).expect("no"));
errors.push_str(&String::from_utf8_lossy(&out));
out.clear();
}
}
@ -455,11 +455,16 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
#[rustfmt::skip]
com.args([
"-bios", &ovmf_path.change_context(Error::OvmfFetch)?,
"-drive", "file=target/disk.img,format=raw",
//"-hda", "target/disk.img",
"-drive", "file=target/disk.img,index=0,if=ide,format=raw",
"-device", "vmware-svga",
// "-serial", "stdio",
"-m", "2G",
"-smp", "1",
"-audiodev",
"pa,id=speaker",
"-machine",
"pcspk-audiodev=speaker",
"-parallel", "none",
"-monitor", "none",
"-machine", accel,
@ -485,7 +490,7 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
#[rustfmt::skip]
com.args([
"-M", "virt",
"-cpu", "neoverse-n2",
"-cpu", "max",
"-device", "ramfb",
"-device", "qemu-xhci",
"-device", "usb-kbd",
@ -506,7 +511,6 @@ fn run(release: bool, target: Target, do_accel: bool) -> Result<(), Error> {
}
}
fn fetch_ovmf(target: Target) -> Result<String, OvmfFetchError> {
let (ovmf_url, ovmf_path) = match target {
Target::X86_64 | Target::X86_64Avx2 => (

View file

@ -1,5 +1,7 @@
[toolchain]
# old toolchain
# channel = "nightly-2024-07-27"
channel = "nightly-2024-11-20"
# last stable
# channel = "nightly-2024-11-20"
channel = "nightly"
components = ["rust-src", "llvm-tools"]

View file

@ -9,39 +9,33 @@ widgets := @use("widgets/widgets.hb")
ui := @use("ui.hb")
WindowID := struct {
host_id: int,
window_id: int,
host_id: uint,
window_id: uint,
}
VoidWindowID := WindowID.(0, 0)
create_window := fn(channel: int): ^render.Surface {
create_window := fn(channel: uint): ^render.Surface {
// get the horizon buffer
// request a new window and provide the callback buffer
// wait to recieve a message
windowing_system_buffer := buffer.search("XHorizon\0")
windowing_system_buffer := buffer.search("XHorizon")
mem_buf := memory.request_page(1)
if windowing_system_buffer == 0 {
return @as(^render.Surface, idk)
} else {
// ! bad able, stop using string messages :ragey:
// msg := "\{01}\0"
// msg_length := 2
// @as(void, @eca(3, windowing_system_buffer, msg, msg_length))
x := 0
loop if x > 1000 break else x += 1
ret := buffer.recv([u8; 4096], windowing_system_buffer, mem_buf)
ret := buffer.recv([4096]u8, windowing_system_buffer, mem_buf)
if ret == null {
log.info("No messages\0")
log.info("No messages")
}
if *mem_buf == 0 {
log.info("No messages\0")
log.info("No messages")
}
return @as(^render.Surface, idk)

View file

@ -6,7 +6,7 @@ render := @use("../../../libraries/render/src/lib.hb");
.{Surface} := render;
.{Font} := render.text
UI := struct {raw: ^u8, raw_length: uint, is_dirty: bool, surface: Surface, // Each child has their WidgetType as their first byte
UI := struct {raw: []u8, is_dirty: bool, surface: Surface, // Each child has their WidgetType as their first byte
// children: ^^u8,
}
@ -19,29 +19,26 @@ render_ui := fn(surface: Surface, ui: UI): void {
render.put_surface(surface, ui.surface, pos, false)
}
sexpr_parser := fn(sexpr: ^u8): UI {
cursor := sexpr
sexpr_parser := fn(sexpr: []u8): UI {
i := 0
paren_balance := 0
loop {
if *cursor == 0 {
if i == sexpr.len {
if paren_balance != 0 {
log.error("Unbalanced Parens\0")
log.error("Unbalanced Parens")
}
break
} else if *cursor == 40 {
log.info("Open paren\0")
} else if sexpr[i] == '(' {
log.info("Open paren")
paren_balance += 1
} else if *cursor == 41 {
log.info("Closed paren\0")
} else if sexpr[i] == ')' {
log.info("Closed paren")
paren_balance -= 1
}
cursor += 1
i += 1
}
length := string.length(sexpr)
ui_surface := render.new_surface(100, 100)
return UI.(sexpr, length, true, ui_surface)
return UI.(sexpr, true, ui_surface)
}

View file

@ -10,37 +10,32 @@ Label := struct {
magic: uint,
is_dirty: bool,
surface: Surface,
text: ^u8,
text_length: uint,
text: []u8,
bg: Color,
fg: Color,
}
set_label_text := fn(label: Label, text: ^u8): void {
text_length := string.length(text)
new_label := fn(text: []u8, width: uint): Self {
text_surface := render.Surface.new(width, 20)
label := Self.(3, true, text_surface, text, render.BLACK, render.WHITE)
return label
}
label.is_dirty = true
label.text = text
label.text_length = text_length
$set_label_text := fn(self: ^Self, text: []u8): void {
self.is_dirty = true
self.text = text
}
$set_color := fn(self: ^Self, bg: Color, fg: Color): void {
self.bg = bg
self.fg = fg
self.is_dirty = true
}
}
render_label_to_surface := fn(surface: Surface, label: Label, font: Font, pos: Vec2(uint)): void {
if label.is_dirty {
render.clear(label.surface, label.bg)
render.put_text(label.surface, font, .(0, 0), label.fg, label.text)
label.surface.clear(label.bg)
label.surface.put_text(font, .(0, 0), label.fg, label.text)
}
render.put_surface(surface, label.surface, pos, false)
}
new_label := fn(text: ^u8): Label {
text_surface := render.new_surface(1024, 20)
text_length := string.length(text)
label := Label.(3, true, text_surface, text, text_length, render.black, render.white)
return label
}
$set_color := fn(label: Label, bg: Color, fg: Color): void {
label.bg = bg
label.fg = fg
label.is_dirty = true
surface.put_surface(label.surface, pos, false)
}

View file

@ -1,4 +1,4 @@
stn := @use("../../stn/src/lib.hb");
stn := @use("stn");
.{log, buffer, memory} := stn
keycodes := @use("keycodes.hb")
@ -8,7 +8,7 @@ events := @use("events.hb");
recieve_key_event := fn(): ?KeyEvent {
kevent := KeyEvent.(false, false, 0)
buf_id := buffer.search("PS/2 Keyboard\0")
buf_id := buffer.search("PS/2 Keyboard")
// Read out of the Keyboard buffer here
buffer.recv(KeyEvent, buf_id, &kevent)
@ -23,7 +23,7 @@ recieve_key_event := fn(): ?KeyEvent {
recieve_mouse_event := fn(): ?MouseEvent {
mevent := MouseEvent.(0, 0, false, false, false)
buf_id := buffer.search("PS/2 Mouse\0")
buf_id := buffer.search("PS/2 Mouse")
// Read out of the Mouse buffer here
buffer.recv(MouseEvent, buf_id, &mevent)

View file

@ -1,4 +1,4 @@
.{string, memory, buffer, log} := @use("../../stn/src/lib.hb")
.{string, memory, buffer, log} := @use("stn")
PCIAddress := struct {
bus: u8,
@ -51,9 +51,9 @@ check_device := fn(bus: u8, device: u8): PciDeviceInfo {
pci_id := get_ids(bus, device, 0)
if pci_id.vendor == 0xFFFF {
log.warn(":|\0")
log.warn(":|")
} else {
log.info(":)\0")
log.info(":)")
}
address := calculate_address(bus, device, 0, 0x8)
reg2 := config_read32(bus, device, 0, 0x8)

View file

@ -3,7 +3,4 @@ Rendering interface for SVGA and Software renderers
# TODO:
- SVGA Driver
- needs pci driver
- needs init (requiring program)
- Double Buffer mode for Software renderer
- needs init (requiring program)
- needs pci driver

View file

@ -1,5 +1,5 @@
.{Color, Surface, new_surface, put_surface} := @use("../lib.hb");
.{log} := @use("../../../stn/src/lib.hb")
.{Color, Surface, new_surface, put_surface} := @use("lib:render");
.{log} := @use("stn")
BitmapFileHeader := packed struct {
magic: u16,
@ -37,13 +37,13 @@ from := fn(bmp: ^u8): ?Surface {
info_header := @as(^BitmapInfoHeader, @bitcast(bmp + @sizeof(BitmapFileHeader)))
if file_header.magic != 0x4D42 | info_header.width == 0 | info_header.height == 0 {
log.error("Invalid BMP image.\0")
log.error("Invalid BMP image.")
return null
}
lhs := Surface.(@bitcast(bmp + file_header.offset), info_header.width, info_header.height, info_header.width * info_header.height)
rhs := new_surface(info_header.width, info_header.height)
put_surface(rhs, lhs, .(0, 0), true)
rhs := Surface.new(info_header.width, info_header.height)
rhs.put_surface(lhs, .(0, 0), true)
return rhs
}

View file

@ -1,5 +1,5 @@
.{log} := @use("../../../stn/src/lib.hb");
.{Surface} := @use("../lib.hb")
.{log} := @use("stn");
.{Surface} := @use("lib:render")
bmp := @use("bmp.hb")
qoi := @use("qoi.hb")
$BMP := 0x4D42
@ -19,7 +19,7 @@ from := fn(file: ^u8): ?Surface {
format := get_format(file)
if format == null {
log.error("Could not detect image format.\0")
log.error("Could not detect image format.")
return null
} else if format == BMP {
return bmp.from(file)

View file

@ -1,5 +1,5 @@
.{Color, Surface, new_surface} := @use("../lib.hb");
.{log} := @use("../../../stn/src/lib.hb")
.{Color, Surface, new_surface} := @use("lib:render");
.{log} := @use("stn")
/* source:
https://github.com/phoboslab/qoi/blob/master/qoi.h */
@ -40,12 +40,12 @@ from := fn(qoi: ^u8): ?Surface {
height := be_to_le(header.height)
if be_to_le(header.magic) != QOI_MAGIC | width == 0 | height == 0 | header.channels < 3 | header.channels > 4 {
log.error("Invalid QOI image.\0")
log.error("Invalid QOI image.")
return null
}
surface := new_surface(width, height)
index := @as([Color; 64], idk)
surface := Surface.new(width, height)
index := @as([64]Color, idk)
run := 0
px := Color.(0, 0, 0, 255)

View file

@ -6,52 +6,23 @@ text := @use("text.hb")
mode := software
init := mode.init
doublebuffer := mode.doublebuffer
Surface := mode.Surface
new_surface := mode.new_surface
surface_from_ptr := mode.surface_from_ptr
clone_surface := mode.clone_surface
free_surface := mode.free_surface
index := mode.index
indexptr := mode.indexptr
// Colours
Color := packed struct {b: u8, g: u8, r: u8, a: u8}
$white := Color.(255, 255, 255, 255)
$black := Color.(0, 0, 0, 255)
$gray := Color.(127, 127, 127, 255)
$red := Color.(0, 0, 205, 255)
$green := Color.(0, 205, 0, 255)
$yellow := Color.(0, 205, 205, 255)
$blue := Color.(205, 0, 0, 255)
$magenta := Color.(205, 0, 205, 255)
$cyan := Color.(205, 205, 0, 255)
$light_gray := Color.(229, 229, 229, 255)
$light_red := Color.(0, 0, 255, 255)
$light_green := Color.(0, 255, 0, 255)
$light_yellow := Color.(0, 255, 255, 255)
$light_blue := Color.(255, 0, 0, 255)
$light_magenta := Color.(255, 0, 255, 255)
$light_cyan := Color.(255, 255, 0, 255)
// Drawing
put_pixel := mode.put_pixel
put_rect := mode.put_rect
put_filled_rect := mode.put_filled_rect
put_trirect := mode.put_trirect
put_circle := mode.put_circle
put_filled_circle := mode.put_filled_circle
put_textured_circle := mode.put_textured_circle
put_line := mode.put_line
put_vline := mode.put_vline
put_hline := mode.put_hline
clear := mode.clear
put_surface := mode.put_surface
put_text := mode.put_text
// thanks peony for these three!
//put_trirect := mode.put_trirect
//put_vline := mode.put_vline
//put_hline := mode.put_hline
// Display
sync := mode.sync
$WHITE := Color.(255, 255, 255, 255)
$BLACK := Color.(0, 0, 0, 255)
$GRAY := Color.(127, 127, 127, 255)
$RED := Color.(0, 0, 205, 255)
$GREEN := Color.(0, 205, 0, 255)
$YELLOW := Color.(0, 205, 205, 255)
$BLUE := Color.(205, 0, 0, 255)
$MAGENTA := Color.(205, 0, 205, 255)
$CYAN := Color.(205, 205, 0, 255)
$LIGHT_GRAY := Color.(229, 229, 229, 255)
$LIGHT_RED := Color.(0, 0, 255, 255)
$LIGHT_GREEN := Color.(0, 255, 0, 255)
$LIGHT_YELLOW := Color.(0, 255, 255, 255)
$LIGHT_BLUE := Color.(255, 0, 0, 255)
$LIGHT_MAGENTA := Color.(255, 0, 255, 255)
$LIGHT_CYAN := Color.(255, 255, 0, 255)

View file

@ -1,472 +1,443 @@
.{math, memory, dt} := @use("../../stn/src/lib.hb");
.{Color, text} := @use("lib.hb");
.{math, memory, dt} := @use("stn");
.{Color, text} := @use("lib:render");
.{get_glyph, get_glyph_unicode, Font, UNC_TABLE_SIZE} := text;
.{Vec2} := math
// safety: don't use before init() or you will get a memory access violation
framebuffer := memory.dangling(Color)
utf8_len_table := u8.[0, 0, 2, 3]
init := fn(doublebuffer: bool): Surface {
framebuffer = dt.get(^Color, "framebuffer/fb0/ptr")
width := dt.get(uint, "framebuffer/fb0/width")
height := dt.get(uint, "framebuffer/fb0/height")
if doublebuffer {
return Surface.new(width, height)
} else {
return .(framebuffer, width, height, width * height)
}
}
Surface := struct {
buf: ^Color,
width: uint,
height: uint,
size: uint,
}
new_surface := fn(width: uint, height: uint): Surface {
return .(
memory.alloc(Color, width * height),
width,
height,
width * height,
)
}
clone_surface := fn(surface: ^Surface): Surface {
new := new_surface(surface.width, surface.height)
memory.copy(Color, surface.buf, new.buf, @intcast(surface.size))
return new
}
init := fn(doublebuffer: bool): Surface {
framebuffer = dt.get(^Color, "framebuffer/fb0/ptr\0")
width := dt.get(uint, "framebuffer/fb0/width\0")
height := dt.get(uint, "framebuffer/fb0/height\0")
if doublebuffer {
return new_surface(width, height)
} else {
return .(framebuffer, width, height, width * height)
}
}
$clear := fn(surface: Surface, color: Color): void {
memory.set(Color, &color, surface.buf, surface.width * surface.height)
}
$sync := fn(surface: Surface): void {
memory.copy(Color, surface.buf, framebuffer, @bitcast(surface.width * surface.height))
}
$index := fn(surface: Surface, x: uint, y: uint): uint {
return x + surface.width * y
}
$indexptr := fn(surface: Surface, x: uint, y: uint): ^Color {
return surface.buf + index(surface, x, y)
}
$put_pixel := fn(surface: Surface, pos: Vec2(uint), color: Color): void {
return *indexptr(surface, pos.x, pos.y) = color
}
put_filled_rect := fn(surface: Surface, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
top_start_idx := indexptr(surface, pos.x, pos.y)
bottom_start_idx := indexptr(surface, pos.x, pos.y + tr.y - 1)
rows_to_fill := tr.y
loop if rows_to_fill <= 1 break else {
memory.set(Color, &color, top_start_idx, tr.x)
memory.set(Color, &color, bottom_start_idx, tr.x)
top_start_idx += surface.width
bottom_start_idx -= surface.width
rows_to_fill -= 2
new := fn(width: uint, height: uint): Self {
size := width * height
return .(
memory.alloc(Color, size),
width,
height,
size,
)
}
if rows_to_fill == 1 {
memory.set(Color, &color, top_start_idx, tr.x)
clone := fn(self: ^Self): Self {
new_self := Self.new(self.width, self.height)
memory.copy(Color, self.buf, new_self.buf, self.size)
return new_self
}
$clear := fn(self: Self, color: Color): void {
memory.set(Color, &color, self.buf, self.size)
}
return
}
put_rect := fn(surface: Surface, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
start_idx := indexptr(surface, pos.x, pos.y)
end_idx := indexptr(surface, pos.x, pos.y + tr.y)
right_start_idx := indexptr(surface, pos.x + tr.x, pos.y)
loop if start_idx > end_idx break else {
*start_idx = color;
*right_start_idx = color
start_idx += surface.width
right_start_idx += surface.width
$sync := fn(self: Self): void {
memory.copy(Color, self.buf, framebuffer, self.size)
}
memory.set(Color, &color, indexptr(surface, pos.x, pos.y), @bitcast(tr.x + 1))
memory.set(Color, &color, indexptr(surface, pos.x, pos.y + tr.y), @bitcast(tr.x + 1))
return
}
put_line_low := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
dx := @as(int, @bitcast(p1.x - p0.x))
dy := @as(int, @bitcast(p1.y - p0.y))
yi := 1
if dy < 0 {
yi = -1
dy = -dy
$index := fn(self: Self, x: uint, y: uint): uint {
return x + self.width * y
}
D := @as(int, 2) * dy - dx
y := p0.y
x := p0.x
loop if x == p1.x break else {
*indexptr(surface, x, y) = color
if D > 0 {
y += yi
D += 2 * (dy - dx)
} else {
D += 2 * dy
$indexptr := fn(self: Self, x: uint, y: uint): ^Color {
return self.buf + self.index(x, y)
}
$put_pixel := fn(self: Self, pos: Vec2(uint), color: Color): void {
*self.indexptr(pos.x, pos.y) = color
}
put_filled_rect := fn(self: Self, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
top_start_idx := self.indexptr(pos.x, pos.y)
bottom_start_idx := self.indexptr(pos.x, pos.y + tr.y - 1)
rows_to_fill := tr.y
loop if rows_to_fill <= 1 break else {
memory.set(Color, &color, top_start_idx, tr.x)
memory.set(Color, &color, bottom_start_idx, tr.x)
top_start_idx += self.width
bottom_start_idx -= self.width
rows_to_fill -= 2
}
x += 1
}
return
}
put_line_high := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
dx := @as(int, @bitcast(p1.x - p0.x))
dy := @as(int, @bitcast(p1.y - p0.y))
xi := 1
if dy < 0 {
xi = -1
dx = -dx
}
D := @as(int, 2) * dx - dy
x := p0.x
y := p0.y
loop if y == p1.y break else {
*indexptr(surface, x, y) = color
if D > 0 {
x += xi
D += 2 * (dx - dy)
} else {
D += 2 * dx
}
y += 1
}
return
}
put_line := fn(surface: Surface, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
if math.abs(uint, p1.y - p0.y) < math.abs(uint, p1.x - p0.x) {
if p0.x > p1.x {
@inline(put_line_low, surface, p1, p0, color)
} else {
@inline(put_line_low, surface, p0, p1, color)
}
} else {
if p0.y > p1.y {
@inline(put_line_high, surface, p1, p0, color)
} else {
@inline(put_line_high, surface, p0, p1, color)
if rows_to_fill == 1 {
memory.set(Color, &color, top_start_idx, tr.x)
}
}
return
}
put_surface := fn(surface: Surface, top: Surface, pos: Vec2(uint), flip_v: bool): void {
src_top_cursor := top.buf
src_bottom_cursor := top.buf + top.width * (top.height - 1)
put_rect := fn(self: Self, pos: Vec2(uint), tr: Vec2(uint), color: Color): void {
start_idx := self.indexptr(pos.x, pos.y)
end_idx := self.indexptr(pos.x, pos.y + tr.y)
right_start_idx := self.indexptr(pos.x + tr.x, pos.y)
dst_top_idx := indexptr(surface, pos.x, pos.y)
dst_bottom_idx := indexptr(surface, pos.x, pos.y + top.height - 1)
dst_increment := surface.width
if flip_v {
dst_increment = -dst_increment
tmp := dst_top_idx
dst_top_idx = dst_bottom_idx
dst_bottom_idx = tmp
}
rows_to_copy := top.height
loop if rows_to_copy <= 1 break else {
memory.copy(Color, src_top_cursor, dst_top_idx, top.width)
memory.copy(Color, src_bottom_cursor, dst_bottom_idx, top.width)
dst_top_idx += dst_increment
dst_bottom_idx -= dst_increment
src_top_cursor += top.width
src_bottom_cursor -= top.width
rows_to_copy -= 2
}
if rows_to_copy == 1 {
memory.copy(Color, src_top_cursor, dst_top_idx, top.width)
}
return
}
// peony-made
put_trirect := fn(surface: Surface, pos: Vec2(uint), size: Vec2(int), color0: Color, color1: Color): void {
step := Vec2(int).(1, 1)
if size.x < 0 {
step.x = -1
}
if size.y < 0 {
step.y /= @bitcast(size.x)
}
start_y := pos.y
target := pos + @bitcast(size)
loop if pos.x == target.x break else {
@inline(put_vline, surface, pos.x, pos.y, target.y, color0)
@inline(put_vline, surface, pos.x, pos.y, start_y, color1)
pos += @bitcast(step)
}
return
}
// peony-made
put_vline := fn(surface: Surface, x: uint, y0: uint, y1: uint, color: Color): void {
if y1 < y0 {
tmp := y0
y0 = y1
y1 = tmp
}
y := y0
loop if y == y1 break else {
*indexptr(surface, x, y) = color
y += 1
}
return
}
// peony-made
put_hline := fn(surface: Surface, y: uint, x0: uint, x1: uint, color: Color): void {
if x1 < x0 {
tmp := x0
x0 = x1
x1 = tmp
}
// x0 = math.min(x0, x1)
memory.set(Color, &color, indexptr(surface, x0, y), @bitcast(x1 - x0 - 1))
return
}
put_circle := fn(surface: Surface, pos: Vec2(uint), radius: uint, color: Color): void {
x := 0
y := radius
error := @as(int, 3) - @intcast(2 * radius);
*indexptr(surface, pos.x + radius, pos.y) = color;
*indexptr(surface, pos.x - radius, pos.y) = color;
*indexptr(surface, pos.x, pos.y + radius) = color;
*indexptr(surface, pos.x, pos.y - radius) = color
loop if y < x break else {
x += 1
if error > 0 {
y -= 1
error += 4 * (@intcast(x) - @intcast(y)) + 10
} else {
error += 4 * @intcast(x) + 6
};
*indexptr(surface, pos.x + x, pos.y + y) = color;
*indexptr(surface, pos.x + y, pos.y + x) = color;
*indexptr(surface, pos.x - x, pos.y + y) = color;
*indexptr(surface, pos.x - y, pos.y + x) = color;
*indexptr(surface, pos.x + x, pos.y - y) = color;
*indexptr(surface, pos.x + y, pos.y - x) = color;
*indexptr(surface, pos.x - x, pos.y - y) = color;
*indexptr(surface, pos.x - y, pos.y - x) = color
}
return
}
put_filled_circle := fn(surface: Surface, pos: Vec2(uint), radius: uint, color: Color): void {
x := 0
y := radius
error := @as(int, 3) - @intcast(2 * radius)
put_hline(surface, pos.y - x, pos.x - radius, pos.x + radius, color);
*indexptr(surface, pos.x, pos.y + radius) = color;
*indexptr(surface, pos.x, pos.y - radius) = color
loop if y < x break else {
x += 1
if error > 0 {
put_hline(surface, pos.y + y, pos.x - x, pos.x + x, color)
put_hline(surface, pos.y - y, pos.x - x, pos.x + x, color)
y -= 1
error += 4 * (@intcast(x) - @intcast(y)) + 10
} else {
error += 4 * @intcast(x) + 6
loop if start_idx > end_idx break else {
*start_idx = color;
*right_start_idx = color
start_idx += self.width
right_start_idx += self.width
}
put_hline(surface, pos.y + x, pos.x - y, pos.x + y, color)
put_hline(surface, pos.y - x, pos.x - y, pos.x + y, color)
memory.set(Color, &color, self.indexptr(pos.x, pos.y), @bitcast(tr.x + 1))
memory.set(Color, &color, self.indexptr(pos.x, pos.y + tr.y), @bitcast(tr.x + 1))
}
return
}
put_textured_circle := fn(surface: Surface, source: Surface, source_pos: Vec2(uint), pos: Vec2(uint), radius: uint): void {
x := 0
y := radius
error := @as(int, 3) - @intcast(2 * radius)
memory.copy(Color, indexptr(source, source_pos.x - y, source_pos.y), indexptr(surface, pos.x - y, pos.y), 2 * y);
*indexptr(surface, pos.x, pos.y + y) = *indexptr(source, source_pos.x, source_pos.y + y);
*indexptr(surface, pos.x, pos.y - y) = *indexptr(source, source_pos.x, source_pos.y - y)
loop if y < x break else {
x += 1
if error > 0 {
memory.copy(Color, indexptr(source, source_pos.x - x, source_pos.y + y), indexptr(surface, pos.x - x, pos.y + y), 2 * x)
memory.copy(Color, indexptr(source, source_pos.x - x, source_pos.y - y), indexptr(surface, pos.x - x, pos.y - y), 2 * x)
y -= 1
error += 4 * (@intcast(x) - @intcast(y)) + 10
} else {
error += 4 * @intcast(x) + 6
put_line_low := fn(self: Self, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
dx := @as(int, @bitcast(p1.x - p0.x))
dy := @as(int, @bitcast(p1.y - p0.y))
yi := 1
if dy < 0 {
yi = -1
dy = -dy
}
D := @as(int, 2) * dy - dx
y := p0.y
x := p0.x
loop if x == p1.x break else {
*self.indexptr(x, y) = color
if D > 0 {
y += yi
D += 2 * (dy - dx)
} else {
D += 2 * dy
}
x += 1
}
memory.copy(Color, indexptr(source, source_pos.x - y, source_pos.y + x), indexptr(surface, pos.x - y, pos.y + x), 2 * y)
memory.copy(Color, indexptr(source, source_pos.x - y, source_pos.y - x), indexptr(surface, pos.x - y, pos.y - x), 2 * y)
}
return
}
put_line_high := fn(self: Self, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
dx := @as(int, @bitcast(p1.x - p0.x))
dy := @as(int, @bitcast(p1.y - p0.y))
xi := 1
if dy < 0 {
xi = -1
dx = -dx
}
D := @as(int, 2) * dx - dy
x := p0.x
y := p0.y
loop if y == p1.y break else {
*self.indexptr(x, y) = color
if D > 0 {
x += xi
D += 2 * (dx - dy)
} else {
D += 2 * dx
}
y += 1
}
}
utf8_len_table := [u8].(0, 0, 2, 3)
put_line := fn(self: Self, p0: Vec2(uint), p1: Vec2(uint), color: Color): void {
if math.abs(int, @bitcast(p1.y - p0.y)) < math.abs(int, @bitcast(p1.x - p0.x)) {
if p0.x > p1.x {
@inline(put_line_low, self, p1, p0, color)
} else {
@inline(put_line_low, self, p0, p1, color)
}
} else {
if p0.y > p1.y {
@inline(put_line_high, self, p1, p0, color)
} else {
@inline(put_line_high, self, p0, p1, color)
}
}
}
put_text := fn(surface: Surface, font: Font, pos: Vec2(uint), color: Color, str: ^u8): void {
cursor := Vec2(uint).(pos.x, pos.y)
put_surface := fn(self: Self, top: Self, pos: Vec2(uint), flip_v: bool): void {
src_top_cursor := top.buf
src_bottom_cursor := top.buf + top.width * (top.height - 1)
max_y := surface.height - font.height
next_line_y := font.height + font.line_gap
char_advance := font.width + font.char_gap
surface_width := surface.width
dst_top_idx := self.indexptr(pos.x, pos.y)
dst_bottom_idx := self.indexptr(pos.x, pos.y + top.height - 1)
loop if *str == 0 break else {
if cursor.y > max_y break
dst_increment := self.width
glyph_data := @as(^u8, idk)
code_point := @as(uint, 0)
if flip_v {
dst_increment = -dst_increment
tmp := dst_top_idx
dst_top_idx = dst_bottom_idx
dst_bottom_idx = tmp
}
if (*str & 0x80) == 0 {
if *str == 10 {
cursor.x = pos.x
cursor.y += next_line_y
str += 1
continue
rows_to_copy := top.height
loop if rows_to_copy <= 1 break else {
memory.copy(Color, src_top_cursor, dst_top_idx, top.width)
memory.copy(Color, src_bottom_cursor, dst_bottom_idx, top.width)
dst_top_idx += dst_increment
dst_bottom_idx -= dst_increment
src_top_cursor += top.width
src_bottom_cursor -= top.width
rows_to_copy -= 2
}
if rows_to_copy == 1 {
memory.copy(Color, src_top_cursor, dst_top_idx, top.width)
}
}
// peony-made
put_trirect := fn(self: Self, pos: Vec2(uint), size: Vec2(int), color0: Color, color1: Color): void {
step := Vec2(int).(1, 1)
if size.x < 0 {
step.x = -1
}
if size.y < 0 {
step.y /= @bitcast(size.x)
}
start_y := pos.y
target := pos + @bitcast(size)
loop if pos.x == target.x break else {
@inline(put_vline, self, pos.x, pos.y, target.y, color0)
@inline(put_vline, self, pos.x, pos.y, start_y, color1)
pos += @bitcast(step)
}
}
// peony-made
put_vline := fn(self: Self, x: uint, y0: uint, y1: uint, color: Color): void {
if y1 < y0 {
tmp := y0
y0 = y1
y1 = tmp
}
y := y0
loop if y == y1 break else {
*self.indexptr(x, y) = color
y += 1
}
}
// peony-made
put_hline := fn(self: Self, y: uint, x0: uint, x1: uint, color: Color): void {
if x1 < x0 {
tmp := x0
x0 = x1
x1 = tmp
}
memory.set(Color, &color, self.indexptr(x0, y), @bitcast(x1 - x0))
}
put_circle := fn(self: Self, pos: Vec2(uint), radius: uint, color: Color): void {
x := 0
y := radius
error := @as(int, 3) - 2 * @intcast(radius)
loop if x > y break else {
self.put_pixel(pos + .(x, y), color)
self.put_pixel(pos + .(-x, y), color)
self.put_pixel(pos + .(x, -y), color)
self.put_pixel(pos + .(-x, -y), color)
self.put_pixel(pos + .(y, x), color)
self.put_pixel(pos + .(-y, x), color)
self.put_pixel(pos + .(y, -x), color)
self.put_pixel(pos + .(-y, -x), color)
if error < 0 {
error += 4 * @intcast(x) + 6
} else {
error += 4 * (@intcast(x) - @intcast(y)) + 10
y -= 1
}
x += 1
}
}
put_filled_circle := fn(self: Self, pos: Vec2(uint), radius: uint, color: Color): void {
x := 0
y := radius
error := @as(int, 3) - 2 * @intcast(radius)
loop if x > y break else {
self.put_hline(pos.y + y, pos.x - x, pos.x + x, color)
self.put_hline(pos.y - y, pos.x - x, pos.x + x, color)
if x != y {
self.put_hline(pos.y + x, pos.x - y, pos.x + y, color)
self.put_hline(pos.y - x, pos.x - y, pos.x + y, color)
}
if font.unicode == null {
if *str > font.num_glyphs {
str += 1
if error < 0 {
error += 4 * @intcast(x) + 6
} else {
error += 4 * (@intcast(x) - @intcast(y)) + 10
y -= 1
}
x += 1
}
}
put_textured_circle := fn(self: Self, source: Self, source_pos: Vec2(uint), pos: Vec2(uint), radius: uint): void {
x := 0
y := radius
error := @as(int, 3) - 2 * @intcast(radius)
loop if x > y break else {
memory.copy(Color, source.indexptr(source_pos.x - x, source_pos.y + y), self.indexptr(pos.x - x, pos.y + y), 2 * x)
memory.copy(Color, source.indexptr(source_pos.x - x, source_pos.y - y), self.indexptr(pos.x - x, pos.y - y), 2 * x)
if x != y {
memory.copy(Color, source.indexptr(source_pos.x - y, source_pos.y + x), self.indexptr(pos.x - y, pos.y + x), 2 * y)
memory.copy(Color, source.indexptr(source_pos.x - y, source_pos.y - x), self.indexptr(pos.x - y, pos.y - x), 2 * y)
}
if error < 0 {
error += 4 * @intcast(x) + 6
} else {
error += 4 * (@intcast(x) - @intcast(y)) + 10
y -= 1
}
x += 1
}
}
put_text := fn(self: Self, font: Font, pos: Vec2(uint), color: Color, str: []u8): void {
cursor := Vec2(uint).(pos.x, pos.y)
max_y := self.height - font.height
next_line_y := font.height + font.line_gap
char_advance := font.width + font.char_gap
self_width := self.width
i := 0
loop if i >= str.len break else {
if cursor.y > max_y break
glyph_data := @as(^u8, idk)
code_point := @as(uint, 0)
if (str[i] & 0x80) == 0 {
if str[i] == '\n' {
cursor.x = pos.x
cursor.y += next_line_y
i += 1
continue
}
glyph_data = get_glyph(font, *str)
} else {
if *str < UNC_TABLE_SIZE {
glyph_index := *(font.unicode + *str)
if glyph_index == 0xFFFF {
str += 1
if font.unicode == null {
if str[i] > font.num_glyphs {
i += 1
continue
}
glyph_data = font.data + glyph_index * font.bytes_per_glyph
glyph_data = get_glyph(font, str[i])
} else {
str += 1
if str[i] < UNC_TABLE_SIZE {
glyph_index := *(font.unicode + str[i])
if glyph_index == 0xFFFF {
i += 1
continue
}
glyph_data = font.data + glyph_index * font.bytes_per_glyph
} else {
i += 1
continue
}
}
i += 1
} else if font.unicode != null {
first_byte := str[i]
num_bytes := @as(uint, 0)
num_bytes = utf8_len_table[first_byte >> 5 & 0x3]
if num_bytes == 0 {
i += 1
continue
}
}
str += 1
} else if font.unicode != null {
first_byte := *str
num_bytes := @as(uint, 0)
num_bytes = utf8_len_table[first_byte >> 5 & 0x3]
code_point = first_byte & (0x7F >> num_bytes | 0x1F)
if num_bytes == 0 {
str += 1
continue
}
valid_sequence := true
bytes_processed := 1
code_point = first_byte & (0x7F >> num_bytes | 0x1F)
valid_sequence := true
bytes_processed := 1
loop if bytes_processed >= num_bytes break else {
str += 1
if *str == 0 | (*str & 0xC0) != 0x80 {
valid_sequence = false
loop if bytes_processed >= num_bytes break else {
i += 1
if i == str.len | (str[i] & 0xC0) != 0x80 {
valid_sequence = false
}
if valid_sequence == false {
break
}
code_point = code_point << 6 | str[i] & 0x3F
bytes_processed += 1
}
if valid_sequence == false {
break
i += 1
continue
}
code_point = code_point << 6 | *str & 0x3F
bytes_processed += 1
i += 1
if code_point == '\n' {
cursor.x = pos.x
cursor.y += next_line_y
continue
}
if code_point >= UNC_TABLE_SIZE {
continue
}
glyph_index := *(font.unicode + code_point)
if glyph_index == 0xFFFF {
continue
}
glyph_data = font.data + glyph_index * font.bytes_per_glyph
}
if valid_sequence == false {
str += 1
continue
}
str += 1
if code_point == 10 {
if cursor.x + font.width >= self_width {
cursor.x = pos.x
cursor.y += next_line_y
continue
}
if code_point >= UNC_TABLE_SIZE {
continue
}
dest := self.indexptr(cursor.x, cursor.y)
rows := font.height
glyph_index := *(font.unicode + code_point)
if glyph_index == 0xFFFF {
continue
}
glyph_data = font.data + glyph_index * font.bytes_per_glyph
}
loop if rows == 0 break else {
byte := *glyph_data
pixel_dest := dest
mask := @as(u8, 0x80)
bits := font.width
if cursor.x + font.width >= surface_width {
cursor.x = pos.x
cursor.y += next_line_y
}
dest := indexptr(surface, cursor.x, cursor.y)
rows := font.height
loop if rows == 0 break else {
byte := *glyph_data
pixel_dest := dest
mask := @as(u8, 0x80)
bits := font.width
loop if bits == 0 break else {
if (byte & mask) != 0 {
*pixel_dest = color
loop if bits == 0 break else {
if (byte & mask) != 0 {
*pixel_dest = color
}
pixel_dest += 1
mask >>= 1
if mask == 0 & bits > 0 {
glyph_data += 1
byte = *glyph_data
mask = 0x80
}
bits -= 1
}
pixel_dest += 1
mask >>= 1
if mask == 0 & bits > 0 {
if mask != 0x80 {
glyph_data += 1
byte = *glyph_data
mask = 0x80
}
bits -= 1
dest += self_width
rows -= 1
}
if mask != 0x80 {
glyph_data += 1
}
dest += surface_width
rows -= 1
cursor.x += char_advance
}
cursor.x += char_advance
}
return
}

View file

@ -1,4 +1,4 @@
.{log, memory} := @use("../../stn/src/lib.hb")
.{log, memory} := @use("stn")
PSF1Header := packed struct {
magic: u16,
@ -31,7 +31,7 @@ Font := struct {
font_from_psf1 := fn(psf: ^u8): ?Font {
header := @as(^PSF1Header, @bitcast(psf))
if header.magic != 0x436 {
log.error("failed to load psf font: not a psf1 font, idiot\0")
log.error("failed to load psf font: not a psf1 font, idiot")
return null
}
@ -52,7 +52,7 @@ font_from_psf1 := fn(psf: ^u8): ?Font {
font_from_psf2 := fn(psf: ^u8, unicode: bool): ?Font {
header := @as(^PSF2Header, @bitcast(psf))
if header.magic != 0x864AB572 {
log.error("failed to load psf font: not a psf2 font, idiot\0")
log.error("failed to load psf font: not a psf2 font, idiot")
return null
}

View file

@ -0,0 +1,4 @@
AllocReturn := struct {
byte_count: uint,
ptr: ?^u8,
}

View file

@ -0,0 +1,90 @@
.{log, panic, memory} := @use("stn")
alloc_return := @use("alloc_return.hb")
/* the block size is 64 bytes, 64 blocks of 64 bytes.
this will very quickly lead to exhaustion of free blocks.
*/
BlockAlloc := struct {
// hi
state: uint,
ptr: ?^u8,
$init := fn(): Self {
alloc_page_ptr := memory.request_page(1)
state := 0xFFFFFFFFFFFFFFFF
return .(state, alloc_page_ptr)
}
alloc := fn(self: Self, alloc_type: type, count: uint): alloc_return.AllocReturn {
offset := 0
state_2 := 0
loop {
xyz := self.state & 1
abc := if xyz == 1 {
true
} else {
false
}
// check if the `offset` bit is 1, if it is move to the next offset
if abc {
offset += 1
return .(0, null)
} else {
log.info("Already Allocated")
}
// else {
// // self it to 1 and return the ptr to the allocation
// self.state |= a
// // return ptr + offset * 64
// if self.ptr != null {
// return .(64, self.ptr + offset * 64)
// } else {
// // panic.panic("Allocator is not inited.")
// // return .(0, null)
// }
// }
// there are only 64 blocks
if offset >= 64 {
return .(0, null)
}
}
}
dealloc := fn(self: Self, ptr: ^u8, alloc_type: type, count: uint): void {
// size := size_of(alloc_type)*count
size := 64
// get the size alligned to the nearest block
// rounded_size := nearest_block_size_rounded_up(size)
rounded_size := 64
state_bit_start := {
// Do math here to figure out what starting ptr corresponds to what bit
3
}
offset := 0
loop {
if rounded_size > 0 {
// set state_bit_start+offset to 0
// at the end move to the next one
offset += 1
} else {
break
}
rounded_size -= 64
}
return void
}
$deinit := fn(self: Self): void {
self.state = 0
self.ptr = null
}
}
// request a kernel page
// ptr := memory.alloc(1)

View file

@ -0,0 +1,19 @@
alloc_return := @use("alloc_return.hb")
FakeAlloc := struct {
$init := fn(): Self {
return .()
}
$alloc := fn(self: Self, alloc_type: type, count: uint): alloc_return.AllocReturn {
return .(0, null)
}
$dealloc := fn(self: Self, ptr: ^u8, alloc_type: type, count: uint): void {
return void
}
// Nothing to clean up here
$deinit := fn(self: Self): void {
return void
}
}

View file

@ -0,0 +1,2 @@
.{BlockAlloc} := @use("block_alloc.hb");
.{FakeAlloc} := @use("fake_alloc.hb")

View file

@ -0,0 +1,25 @@
allocators := @use("alloc/alloc.hb")
AStruct := struct {
a_field: u8,
}
main := fn():void{
alloc := allocators.FakeAlloc.init()
astruct := alloc.alloc(AStruct, 2)
if astruct.ptr != null{
panic("FakeAlloc actually allocated.")
}
alloc.dealloc(astruct_ptr, AStruct, 2)
alloc.deinit()
balloc := allocators.BlockAlloc.init()
bstruct_ptr := balloc.alloc(AStruct, 2)
if bstruct_ptr == null {
panic("BlockAlloc actually didn't allocate.")
}
balloc.dealloc(bstruct_ptr, AStruct, 2)
balloc.deinit()
}

View file

@ -1,4 +1,6 @@
string := @use("string.hb")
$await := fn(buffer_id: uint): void {
return @eca(7, buffer_id)
}
$recv := fn($Expr: type, buffer_id: uint, memory_map_location: ^Expr): void {
return @eca(4, buffer_id, memory_map_location, @sizeof(Expr))
@ -18,18 +20,18 @@ $write_length := fn(length: uint, msg: ^u8, buffer_id: uint): void {
BufferMsg := packed struct {operation: u8, msg: ^u8, msg_len: uint}
create := fn(msg: ^u8): uint {
return @eca(3, 0, BufferMsg.(0, msg, @inline(string.length, msg)), @sizeof(BufferMsg))
$create := fn(msg: []u8): uint {
return @eca(3, 0, BufferMsg.(0, msg.ptr, msg.len), @sizeof(BufferMsg))
}
$create_nameless := fn(): uint {
return @eca(1, 0)
}
$delete_buffer := fn(buffer_id: uint): void {
$delete := fn(buffer_id: uint): void {
return @eca(2, buffer_id)
}
search := fn(msg: ^u8): uint {
return @eca(3, 0, BufferMsg.(3, msg, @inline(string.length, msg)), @sizeof(BufferMsg))
$search := fn(msg: []u8): uint {
return @eca(3, 0, BufferMsg.(3, msg.ptr, msg.len), @sizeof(BufferMsg))
}

View file

@ -1,5 +1,3 @@
.{string} := @use("../../stn/src/lib.hb")
get := fn($Expr: type, query: ^u8): Expr {
return @eca(3, 5, query, @inline(string.length, query))
$get := fn($Expr: type, query: []u8): Expr {
return @eca(3, 5, query, query.len)
}

View file

@ -2,7 +2,7 @@ acs := @use("acs.hb");
.{DiskID, FileID} := acs
// Paths without a node-disk component are to be treated as local files.
// file_path := "DID:/test\0";
// file_path := "DID:/test"
Path := struct {
// DiskID holds the host id
disk_id: DiskID,

View file

@ -0,0 +1,285 @@
.{Kind, usize, string, signed_int, panic, float, integer, memory, log: .{LogLevel}} := @use("stn")
fmt_int := fn(v: @Any(), str: []u8, radix: @TypeOf(v)): uint {
is_negative := signed_int(@TypeOf(v)) & v < 0
prefix_len := 0
if is_negative {
v = -v
str[0] = '-'
prefix_len += 1
}
if radix == 16 {
*@as(^[2]u8, @bitcast(str.ptr + prefix_len)) = *@bitcast("0x".ptr)
prefix_len += 2
} else if radix == 2 {
*@as(^[2]u8, @bitcast(str.ptr + prefix_len)) = *@bitcast("0b".ptr)
prefix_len += 2
} else if radix == 8 {
*@as(^[2]u8, @bitcast(str.ptr + prefix_len)) = *@bitcast("0o".ptr)
prefix_len += 2
}
if v == 0 {
str[prefix_len] = '0'
return prefix_len + 1
}
i := prefix_len
loop if v <= 0 break else {
remainder := v % radix
v /= radix
if remainder > 9 {
str[i] = @intcast(remainder - 10 + 'A')
} else {
str[i] = @intcast(remainder + '0')
}
i += 1
}
string.reverse(str[prefix_len..i])
return i
}
fmt_bool := fn(v: bool, str: []u8): uint {
if v {
*@as(^[4]u8, @bitcast(str.ptr)) = *@bitcast("true".ptr)
return 4
} else {
*@as(^[5]u8, @bitcast(str.ptr)) = *@bitcast("false".ptr)
return 5
}
}
$FP_TOLERANCE := 0.00000001
fmt_float := fn(v: @Any(), str: []u8, precision: uint, radix: int): uint {
is_negative := v < 0
prefix_len := 0
if is_negative {
v = -v
str[0] = '-'
prefix_len += 1
}
if radix == 16 {
*@as(^[2]u8, @bitcast(str.ptr + prefix_len)) = *@bitcast("0x".ptr)
prefix_len += 2
} else if radix == 2 {
*@as(^[2]u8, @bitcast(str.ptr + prefix_len)) = *@bitcast("0b".ptr)
prefix_len += 2
} else if radix == 8 {
*@as(^[2]u8, @bitcast(str.ptr + prefix_len)) = *@bitcast("0o".ptr)
prefix_len += 2
}
integer_part := @fti(v)
fractional_part := v - @itf(integer_part)
i := prefix_len
loop if integer_part == 0 & i > prefix_len break else {
remainder := integer_part % radix
integer_part /= radix
if remainder > 9 {
str[i] = @intcast(remainder - 10 + 'A')
} else {
str[i] = @intcast(remainder + '0')
}
i += 1
}
string.reverse(str[prefix_len..i])
str[i] = '.'
i += 1
p := precision
loop if p <= 0 | fractional_part < FP_TOLERANCE break else {
fractional_part *= @itf(radix)
digit := @fti(fractional_part)
if digit > 9 {
str[i] = @intcast(digit - 10 + 'A')
} else {
str[i] = @intcast(digit + '0')
}
i += 1
fractional_part -= @itf(digit)
p -= 1
}
return i
}
fmt_container := fn(v: @Any(), str: []u8, opts: FormatOptions): uint {
T2 := @TypeOf(v)
kind := Kind.of(T2)
i := 0
len := 0
if kind == .Struct {
*@as(^[@intcast(@nameof(T2).len)]u8, @bitcast(str.ptr + len)) = *@bitcast(@nameof(T2).ptr)
len += @nameof(T2).len;
*@as(^[2]u8, @bitcast(str.ptr + len)) = *@bitcast(".(".ptr)
len += 2
} else if kind == .Slice {
*@as(^[@intcast(@nameof(@ChildOf(T2)).len)]u8, @bitcast(str.ptr + len)) = *@bitcast(@nameof(@ChildOf(T2)).ptr)
len += @nameof(@ChildOf(T2)).len;
*@as(^[2]u8, @bitcast(str.ptr + len)) = *@bitcast(".[".ptr)
len += 2
} else if kind == .Tuple {
*@as(^[2]u8, @bitcast(str.ptr + len)) = *@bitcast(".(".ptr)
len += 2
}
if kind == .Slice {
loop {
len += @inline(format, v[i], str[len..], opts)
i += 1
if i == v.len break else {
*@as(^[2]u8, @bitcast(str.ptr + len)) = *@bitcast(", ".ptr)
len += 2
}
}
} else {
$loop {
len += @inline(format, v[i], str[len..], opts)
i += 1
if i == @lenof(T2) break else {
*@as(^[2]u8, @bitcast(str.ptr + len)) = *@bitcast(", ".ptr)
len += 2
}
}
}
if kind == .Struct | kind == .Tuple {
*@as(^[1]u8, @bitcast(str.ptr + len)) = *@bitcast(")".ptr)
len += 1
} else if kind == .Slice {
*@as(^[1]u8, @bitcast(str.ptr + len)) = *@bitcast("]".ptr)
len += 1
}
return len
}
fmt_nullable := fn(v: @Any(), str: []u8, opts: FormatOptions): uint {
if v == null {
*@as(^[4]u8, @bitcast(str.ptr)) = *@bitcast("null".ptr)
return 4
} else {
return @inline(format, @as(@ChildOf(@TypeOf(v)), v), str, opts)
}
}
fmt_enum := fn(v: @Any(), str: []u8, opts: FormatOptions): uint {
T := @TypeOf(v)
len := @nameof(T).len;
*@as(^[@intcast(@nameof(T).len)]u8, @bitcast(str.ptr)) = *@bitcast(@nameof(T).ptr);
*@as(^[2]u8, @bitcast(str.ptr + len)) = *@bitcast(".(".ptr)
len += 2
len += fmt_int(@as(usize(T), @bitcast(v)), str[len..], 10);
*@as(^[2]u8, @bitcast(str.ptr + len)) = *@bitcast(")".ptr)
return len + 1
}
/* TODO:
* Custom formatters using struct methods (T._fmt(self, str): uint),
* Format struct fields "Name.{a: x, b: y, c: z}"
* Optionally tabulate
* Add more FormatOption fields
* Support scientific notation for floating point
* Support format string
*/
FormatOptions := struct {
precision: uint = 2,
radix: uint = 10,
// temporarily here, will change later maybe
log: LogLevel = .Info,
}
/* SAFETY:
* Assumes the buffer is wide enough for the formatted text and a null char
* Does not clear the buffer for you
*/
format := fn(v: @Any(), str: []u8, opts: FormatOptions): uint {
T := @TypeOf(v)
match Kind.of(T) {
.Pointer => return @inline(fmt_int, @as(uint, @bitcast(v)), str, 16),
.Builtin => {
if integer(T) {
return @inline(fmt_int, v, str, @intcast(opts.radix))
} else if T == bool {
return @inline(fmt_bool, v, str)
} else if float(T) {
return @inline(fmt_float, v, str, opts.precision, @intcast(opts.radix))
}
},
.Opt => return @inline(fmt_nullable, v, str, opts),
.Enum => return @inline(fmt_enum, v, str, opts),
.Struct => return @inline(fmt_container, v, str, opts),
.Tuple => return @inline(fmt_container, v, str, opts),
.Slice => if T != []u8 return @inline(fmt_container, v, str, opts) else {
i := 0
loop if i == v.len break else {
str[i] = v[i]
i += 1
}
return v.len
},
_ => @error("Type: \"", T, "\" is not supported."),
}
}
format_with_str := fn(v: @Any(), read: []u8, write: []u8, opts: FormatOptions): uint {
T := @TypeOf(v)
n := string.count(read, '{')
if n != string.count(read, '}') panic("Missing closing '}' in format string.")
if Kind.of(T) == .Tuple {
if @lenof(T) != n panic("Format string has different number of '{}' than args given.")
m := 0
i := 0
j := 0
$loop if m > @lenof(T) break else {
if m == @lenof(T) {
loop if i == read.len break else {
write[j] = read[i]
i += 1
j += 1
}
m += 1
} else {
v2 := v[m]
loop if i == read.len break else {
if read[i] == '{' & read[i + 1] == '}' {
j += format(v2, write[j..], opts)
i += 2
break
} else {
write[j] = read[i]
i += 1
j += 1
}
}
m += 1
}
}
return j
} else if n > 1 {
panic("Format string has multiple '{}' but value provided is not a tuple.")
} else {
i := 0
j := 0
loop if i == read.len break else {
if read[i] == '{' & read[i + 1] == '}' {
j += format(v, write[j..], opts)
i += 2
} else {
write[j] = read[i]
i += 1
j += 1
}
}
return j
}
}

View file

@ -0,0 +1,181 @@
/*
* This code is an implementation of the FoldHash algorithm from https://github.com/orlp/foldhash,
* originally written by Orson Peters under the zlib license.
*
* Changes to the original code were made to meet the simplicity requirements of this implementation.
* Behaviour aims to be equivalent but not identical to the original code.
*
* Copyright (c) 2024 Orson Peters
*
* This software is provided 'as-is', without any express or implied warranty. In
* no event will the authors be held liable for any damages arising from the use of
* this software.
*
* Permission is granted to anyone to use this software for any purpose, including
* commercial applications, and to alter it and redistribute it freely, subject to
* the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim
* that you wrote the original software. If you use this software in a product,
* an acknowledgment in the product documentation would be appreciated but is
* not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/;
.{math, random} := @use("stn")
$ARBITRARY0 := 0x243F6A8885A308D3
$ARBITRARY1 := 0x13198A2E03707344
$ARBITRARY2 := 0xA4093822299F31D0
$ARBITRARY3 := 0x82EFA98EC4E6C89
$ARBITRARY4 := 0x452821E638D01377
$ARBITRARY5 := 0xBE5466CF34E90C6C
$ARBITRARY6 := 0xC0AC29B7C97C50DD
$ARBITRARY7 := 0x3F84D5B5B5470917
$ARBITRARY8 := 0x9216D5D98979FB1B
$ARBITRARY9 := 0xD1310BA698DFB5AC
$FIXED_GLOBAL_SEED := uint.[ARBITRARY4, ARBITRARY5, ARBITRARY6, ARBITRARY7]
global_seed := 0
u128 := packed struct {a: uint, b: uint}
$folded_multiply := fn(x: uint, y: uint): uint {
lx := @as(u32, @intcast(x))
ly := @as(u32, @intcast(y))
hx := x >> 32
hy := y >> 32
afull := lx * hy
bfull := hx * ly
return afull ^ (bfull << 32 | bfull >> 32)
}
hash_bytes_medium := fn(bytes: ^u8, len: uint, s0: uint, s1: uint, fold_seed: uint): uint {
lo := bytes
end := bytes + len
hi := end - 16
loop if lo >= hi break else {
a := *@as(^uint, @bitcast(lo))
b := *@as(^uint, @bitcast(lo + 8))
c := *@as(^uint, @bitcast(hi))
d := *@as(^uint, @bitcast(hi + 8))
s0 = folded_multiply(a ^ s0, c ^ fold_seed)
s1 = folded_multiply(b ^ s1, d ^ fold_seed)
hi -= 16
lo += 16
}
return s0 ^ s1
}
hash_bytes_long := fn(bytes: ^u8, len: uint, s0: uint, s1: uint, s2: uint, s3: uint, fold_seed: uint): uint {
$chunk_size := 64
chunks := len / chunk_size
remainder := len % chunk_size
ptr := bytes
i := 0
loop if i >= chunks break else {
a := *@as(^uint, @bitcast(ptr))
b := *@as(^uint, @bitcast(ptr + 8))
c := *@as(^uint, @bitcast(ptr + 16))
d := *@as(^uint, @bitcast(ptr + 24))
e := *@as(^uint, @bitcast(ptr + 32))
f := *@as(^uint, @bitcast(ptr + 40))
g := *@as(^uint, @bitcast(ptr + 48))
h := *@as(^uint, @bitcast(ptr + 56))
s0 = folded_multiply(a ^ s0, e ^ fold_seed)
s1 = folded_multiply(b ^ s1, f ^ fold_seed)
s2 = folded_multiply(c ^ s2, g ^ fold_seed)
s3 = folded_multiply(d ^ s3, h ^ fold_seed)
ptr += chunk_size
i += 1
}
s0 ^= s2
s1 ^= s3
if remainder > 0 {
remainder_start := bytes + len - math.max(uint, remainder, 16)
return @inline(hash_bytes_medium, remainder_start, math.max(uint, remainder, 16), s0, s1, fold_seed)
}
return s0 ^ s1
}
FoldHasher := struct {
accumulator: uint,
original_seed: uint,
sponge: u128,
sponge_len: u8,
fold_seed: uint,
expand_seed: uint,
expand_seed2: uint,
expand_seed3: uint,
$new := fn(seed: uint): Self {
return .(
seed,
seed,
.(0, 0),
0,
FIXED_GLOBAL_SEED[0],
FIXED_GLOBAL_SEED[1],
FIXED_GLOBAL_SEED[2],
FIXED_GLOBAL_SEED[3],
)
}
default := fn(): Self {
if global_seed == 0 {
// ! consider this "secure enough" for now
global_seed = random.any(uint)
}
return Self.new(global_seed)
}
write := fn(self: ^Self, bytes: ^u8, len: uint): void {
s0 := self.accumulator
s1 := self.expand_seed
if len <= 16 {
if len >= 8 {
s0 ^= *@bitcast(bytes)
s1 ^= *@bitcast(bytes + len - 8)
} else if len >= 4 {
s0 ^= *@as(^u32, @bitcast(bytes))
s1 ^= *@as(^u32, @bitcast(bytes + len - 4))
} else if len > 0 {
lo := *bytes
mid := *(bytes + len / 2)
hi := *(bytes + len - 1)
s0 ^= lo
s1 ^= @as(uint, hi) << 8 | mid
}
self.accumulator = folded_multiply(s0, s1)
} else if len < 256 {
self.accumulator = @inline(hash_bytes_medium, bytes, len, s0, s1, self.fold_seed)
} else {
self.accumulator = @inline(hash_bytes_long, bytes, len, s0, s1, self.expand_seed2, self.expand_seed3, self.fold_seed)
}
}
finish := fn(self: ^Self): uint {
if self.sponge_len > 0 {
return folded_multiply(self.sponge.b ^ self.accumulator, self.sponge.a ^ self.fold_seed)
} else {
return self.accumulator
}
}
reset := fn(self: ^Self): void {
self.accumulator = self.original_seed
self.sponge = .(0, 0)
self.sponge_len = 0
}
}

View file

@ -0,0 +1,2 @@
//! NON CRYPTOGRAPHIC HASHER
foldhash := @use("foldhash.hb")

View file

@ -1,4 +1,7 @@
acs := @use("acs.hb")
allocators := @use("alloc/lib.hb")
fmt := @use("fmt.hb")
hashers := @use("hash/lib.hb")
string := @use("string.hb")
log := @use("log.hb")
memory := @use("memory.hb")
@ -8,13 +11,56 @@ random := @use("random.hb")
file := @use("file_io.hb")
dt := @use("dt.hb")
process := @use("process.hb")
sleep := @use("sleep.hb")
panic := fn(message: ?^u8): never {
log.error("Error: Panic Called, Message:\0")
if message == null {
log.error("None\0")
} else {
log.error(message)
}
panic := fn(message: ?[]u8): never {
log.printf("HBLang Panic: {}", message, .{log: .Error})
die
}
Kind := enum {
Builtin,
Struct,
Tuple,
Enum,
Union,
Pointer,
Slice,
Opt,
Function,
Template,
Global,
Const,
Module,
$of := fn($T: type): Self {
return @bitcast(@kindof(T))
}
}
$unsigned_int := fn($T: type): bool {
return T == uint | T == u8 | T == u16 | T == u32
}
$signed_int := fn($T: type): bool {
return T == int | T == i8 | T == i16 | T == i32
}
$integer := fn($T: type): bool {
return unsigned_int(T) | signed_int(T)
}
$float := fn($T: type): bool {
return T == f32 | T == f64
}
$usize := fn($T: type): type {
if @sizeof(T) == 1 return u8 else if @sizeof(T) == 2 return u16 else if @sizeof(T) == 4 return u32 else return uint
}
$bits := fn($T: type): usize(T) {
return @sizeof(T) << 3
}
$bitmask := fn($T: type): usize(T) {
return -1
}

View file

@ -1,13 +1,41 @@
string := @use("string.hb")
.{string, fmt, memory} := @use("stn")
LogMsg := packed struct {level: u8, string: ^u8, strlen: uint}
LogMsg := packed struct {level: LogLevel, string: ^u8, strlen: uint}
log := fn(level: u8, message: ^u8): void {
return @eca(3, 1, LogMsg.(level, message, @inline(string.length, message)), @sizeof(LogMsg))
LogLevel := enum {
Error,
Warn,
Info,
Debug,
Trace,
}
error := fn(message: ^u8): void return @inline(log, 0, message)
warn := fn(message: ^u8): void return @inline(log, 1, message)
info := fn(message: ^u8): void return @inline(log, 2, message)
debug := fn(message: ^u8): void return @inline(log, 3, message)
trace := fn(message: ^u8): void return @inline(log, 4, message)
$log := fn(level: LogLevel, message: []u8): void {
return @eca(3, 1, LogMsg.(level, message.ptr, message.len), @sizeof(LogMsg))
}
$error := fn(message: []u8): void return log(LogLevel.Error, message)
$warn := fn(message: []u8): void return log(LogLevel.Warn, message)
$info := fn(message: []u8): void return log(LogLevel.Info, message)
$debug := fn(message: []u8): void return log(LogLevel.Debug, message)
$trace := fn(message: []u8): void return log(LogLevel.Trace, message)
print_buffer := memory.dangling(u8)
print := fn(v: @Any(), opts: fmt.FormatOptions): void {
if print_buffer == memory.dangling(u8) {
print_buffer = memory.request_page(1)
}
len := @inline(fmt.format, v, print_buffer[0..memory.PAGE_SIZE], opts)
@eca(3, 1, LogMsg.(opts.log, print_buffer, len), @sizeof(LogMsg))
memory.set(u8, &0, print_buffer, len)
}
printf := fn(str: []u8, v: @Any(), opts: fmt.FormatOptions): void {
if print_buffer == memory.dangling(u8) {
print_buffer = memory.request_page(1)
}
len := @inline(fmt.format_with_str, v, str, print_buffer[0..memory.PAGE_SIZE], opts)
@eca(3, 1, LogMsg.(opts.log, print_buffer, len), @sizeof(LogMsg))
memory.set(u8, &0, print_buffer, len)
}

File diff suppressed because one or more lines are too long

View file

@ -2,7 +2,11 @@ $PAGE_SIZE := 4096
$MAX_ALLOC := 0xFF
$MAX_FREE := 0xFF
$uninit := fn($Expr: type): ?Expr {
$uninit := fn($Expr: type): Expr {
return idk
}
$nulled := fn($Expr: type): ?Expr {
return null
}
@ -65,12 +69,22 @@ $inl := fn(addr: u16): u32 {
return @eca(3, 3, &InlMsg.(0, 2, addr), @sizeof(InlMsg))
}
CopyMsg := packed struct {a: u8, count: u32, src: ^u8, dest: ^u8}
$copy := fn($Expr: type, src: ^Expr, dest: ^Expr, count: uint): void {
return @eca(3, 2, &CopyMsg.(4, @intcast(count * @sizeof(Expr)), @bitcast(src), @bitcast(dest)), @sizeof(CopyMsg))
OutsMsg := packed struct {a: u8, b: u8, addr: u16, value: u16}
$outs := fn(addr: u16, value: u32): void {
return @eca(3, 3, &OutsMsg.(1, 1, addr, value), @sizeof(OutsMsg))
}
SetMsg := packed struct {a: u8, count: u32, size: u32, src: ^u8, dest: ^u8}
InsMsg := packed struct {a: u8, b: u8, addr: u16}
$ins := fn(addr: u16): u16 {
return @eca(3, 3, &InsMsg.(0, 1, addr), @sizeof(InsMsg))
}
CopyMsg := packed struct {a: u8, count: uint, src: ^u8, dest: ^u8}
$copy := fn($Expr: type, src: ^Expr, dest: ^Expr, count: uint): void {
return @eca(3, 2, &CopyMsg.(4, count * @sizeof(Expr), @bitcast(src), @bitcast(dest)), @sizeof(CopyMsg))
}
SetMsg := packed struct {a: u8, count: uint, size: uint, src: ^u8, dest: ^u8}
$set := fn($Expr: type, src: ^Expr, dest: ^Expr, count: uint): void {
return @eca(3, 2, &SetMsg.(5, @intcast(count), @intcast(@sizeof(Expr)), @bitcast(src), @bitcast(dest)), @sizeof(SetMsg))
return @eca(3, 2, &SetMsg.(5, count, @sizeof(Expr), @bitcast(src), @bitcast(dest)), @sizeof(SetMsg))
}

View file

@ -1,6 +1,7 @@
subscribe_to_interrupt := fn(interrupt_number: u8): bool {
$subscribe_to_interrupt := fn(interrupt_number: u8): bool {
return false
}
// Pauses execution until the interrupt occures
sleep_until_interrupt := fn(interrupt_number: u8): void {
$sleep_until_interrupt := fn(interrupt_number: u8): void {
@eca(6, interrupt_number)
}

View file

@ -1,216 +1,172 @@
length := fn(ptr: ^u8): uint {
len := 0
loop if *(ptr + len) == 0 return len else len += 1
}
// todo: splice function
display_int := fn(num: int, p: ^u8, radix: uint): ^u8 {
is_negative := num < 0
if is_negative num = -num
ptr := p
if num == 0 {
*ptr = 0x30;
*(ptr + 1) = 0
return p
}
loop if num == 0 break else {
remainder := num % @bitcast(radix)
num /= @bitcast(radix);
*ptr = @intcast(remainder + 0x30)
if remainder > 9 {
*ptr = @intcast(remainder - 10 + 0x41)
}
ptr += 1
}
if is_negative {
*ptr = 0x2D
ptr += 1
}
// ! it gets broked when you do this ??
// *ptr = 0
@inline(reverse, p)
return p
}
reverse := fn(s: ^u8): void {
j := s + @inline(length, s) - 1
reverse := fn(str: []u8): void {
if str.len == 0 return;
j := str.len - 1
i := 0
temp := @as(u8, 0)
loop if s < j {
temp = *s;
*s = *j;
*j = temp
s += 1
loop if i < j {
temp = str[i]
str[i] = str[j]
str[j] = temp
i += 1
j -= 1
} else return
}
equals := fn(lhs: ^u8, rhs: ^u8): bool {
if lhs == rhs {
return true
equals := fn(lhs: []u8, rhs: []u8): bool {
if lhs.len != rhs.len return false
if lhs.ptr == rhs.ptr return true
i := 0
loop if i == lhs.len break else {
if lhs[i] != rhs[i] return false
i += 1
}
loop if *lhs != *rhs {
return false
} else if *lhs == 0 {
return true
return true
}
clear := fn(str: []u8): void {
i := 0
loop if i == str.len break else {
str[i] = 0
i += 1
}
}
split_once := fn(haystack: []u8, needle: @Any()): ?struct {left: []u8, right: []u8} {
T := @TypeOf(needle)
i := 0
if T == []u8 {
if needle.len == 0 return null
loop {
if i + needle.len > haystack.len return null
if haystack[i] == needle[0] {
matches := true
n := 1
loop {
if n == needle.len break
if haystack[i + n] != needle[n] {
matches = false
break
}
n += 1
}
if matches return .(haystack[0..i], haystack[i + needle.len..])
}
i += 1
}
} else if T == u8 {
loop {
if haystack[i] == needle {
return .(haystack[0..i], haystack[i + 1..])
} else if i == haystack.len return null
i += 1
}
} else {
lhs += 1
rhs += 1
@error("Type of needle must be []u8 or u8.")
}
}
clear := fn(ptr: ^u8): void {
loop if *ptr == 0 break else {
*ptr = 0
ptr += 1
}
}
split_once := fn(haystack: ^u8, needle: u8): ?^u8 {
loop if *haystack == needle return haystack else if *haystack == 0 return null else haystack += 1
}
split_once_str := fn(haystack: ^u8, needle: ^u8): ?^u8 {
if *needle == 0 return null
loop if *haystack == 0 return null else {
if *haystack == *needle {
h := haystack
n := needle
loop {
n += 1
h += 1
if *n == 0 {
return haystack
} else if *h == 0 | *h != *n {
break
}
}
}
haystack += 1
}
}
Split := struct {
str: ^u8,
needle: u8,
split := fn(iter: []u8, needle: @Any()): struct {
str: []u8,
needle: @TypeOf(needle),
done: bool,
}
split := fn(iter: ^u8, needle: u8): Split {
return .(
iter,
needle,
false,
)
}
next := fn(self: ^Self): ?[]u8 {
if self.done return null;
iter_split := fn(iter: ^Split): ?^u8 {
if iter.done | *iter.str == 0 {
return null
}
next := split_once(iter.str + 1, iter.needle)
if next == null {
iter.done = true
return iter.str
}
s := iter.str
iter.str = next + 1
return s
}
SplitStr := struct {
str: ^u8,
needle: ^u8,
done: bool,
}
split_str := fn(iter: ^u8, needle: ^u8): SplitStr {
return .(
iter,
needle,
false,
)
}
iter_split_str := fn(iter: ^SplitStr): ?^u8 {
if iter.done | *iter.str == 0 {
return null
}
next := split_once_str(iter.str, iter.needle)
if next == null {
iter.done = true
return iter.str
}
s := iter.str
iter.str = next + length(iter.needle)
return s
}
find_once := fn(haystack: ^u8, needle: u8): ?uint {
return @bitcast(@inline(split_once, haystack, needle) - haystack)
}
find_once_str := fn(haystack: ^u8, needle: ^u8): ?uint {
return @bitcast(@inline(split_once_str, haystack, needle) - haystack)
}
count := fn(haystack: ^u8, needle: ^u8): uint {
c := 0
loop if *haystack == needle {
c += 1
haystack += 1
} else if *haystack == 0 return c else haystack += 1
}
count_str := fn(haystack: ^u8, needle: ^u8): uint {
if *needle == 0 return 0
c := 0
loop if *haystack == 0 return c else {
if *haystack == *needle {
h := haystack
n := needle
loop {
n += 1
h += 1
if *n == 0 {
c += 1
break
} else if *h == 0 | *h != *n {
break
}
}
}
haystack += 1
}
}
left_trim := fn(str: ^u8, sub: ^u8): ^u8 {
original := str
if *str == *sub {
loop if *sub == 0 {
return str
} else if *str != *sub {
return original
} else if *str == 0 {
return original
splits := split_once(self.str, self.needle)
if splits != null {
self.str = splits.right
return splits.left
} else {
str += 1
sub += 1
self.done = true
return self.str
}
}
} {
T := @TypeOf(needle)
if T != []u8 & T != u8 {
@error("Type of needle must be []u8 or u8.")
}
return .(iter, needle, false)
}
chars := fn(iter: []u8): struct {
str: []u8,
next := fn(self: ^Self): ?u8 {
if self.str.len == 0 return null
self.str = self.str[1..]
return self.str[0]
}
} {
return .(iter)
}
count := fn(haystack: []u8, needle: @Any()): uint {
T := @TypeOf(needle)
i := 0
c := 0
if T == []u8 {
if needle.len == 0 return null
loop {
if i + needle.len > haystack.len return c
if haystack[i] == needle[0] {
matches := true
n := 1
loop {
if n == needle.len break
if haystack[i + n] != needle[n] {
matches = false
break
}
n += 1
}
if matches c += 1
}
i += 1
}
} else if T == u8 {
loop {
if haystack[i] == needle c += 1 else if i == haystack.len return c
i += 1
}
} else {
@error("Type of needle must be []u8 or u8.")
}
}
left_trim := fn(str: []u8, sub: []u8): []u8 {
i := 0
if str[0] == sub[0] {
loop if i == sub.len {
return str[i..str.len]
} else if str[i] != sub[i] | i == str.len {
break
} else {
i += 1
}
}
return str
}
right_trim := fn(str: []u8, sub: []u8): []u8 {
i := 0
if str[str.len - 1] == sub[sub.len - 1] {
loop if i == sub.len {
return str[0..str.len - i]
} else if str[str.len - i - 1] != sub[sub.len - i - 1] | i == str.len {
break
} else {
i += 1
}
}
return str
}
trim := fn(str: []u8, sub: []u8): []u8 {
return right_trim(left_trim(str, sub), sub)
}

View file

@ -1,16 +1,16 @@
.{math: .{Vec2}, buffer, log, memory, string} := @use("../../stn/src/lib.hb");
.{Channel, Window, send_header, send_message, await_channel, await_header, await_message, message, BUFFER_SERVER, BUFFER_CLIENT, WindowProps, WindowData} := @use("./lib.hb");
.{new_surface, Color} := @use("../../render/src/lib.hb")
.{math: .{Vec2}, buffer, log, memory, string} := @use("stn");
.{Channel, Window, send_header, send_message, await_channel, await_header, await_message, message, BUFFER_SERVER, BUFFER_CLIENT, WindowProps, WindowData} := @use("lib:sunset_proto");
.{Surface, Color} := @use("lib:render")
// ! in the future this should be safely handled
channel := Channel.(0, 0)
find_server := fn(): void {
log.info("client: locating server\0")
log.info("client: locating server")
channel2 := await_channel()
channel.server = channel2.server
channel.client = channel2.client
log.info("client: server located\0")
log.info("client: server located")
}
new := fn(props: WindowProps): ?Window {
@ -19,14 +19,14 @@ new := fn(props: WindowProps): ?Window {
if response.header.kind != message.ack {
return null
}
log.info("client: recv ack\0")
log.info("client: recv ack")
send_message(WindowProps, message.props, props, response.body.server)
windowdata := await_message(WindowData, response.body.client)
if windowdata.header.kind != message.ack {
return null
}
log.info("client: recv windowdata\0")
surface := new_surface(windowdata.body.props.dimensions.x, windowdata.body.props.dimensions.y)
log.info("client: recv windowdata")
surface := Surface.new(windowdata.body.props.dimensions.x, windowdata.body.props.dimensions.y)
return .(windowdata.body, surface)
}

View file

@ -1,8 +1,8 @@
.{math: .{Vec2}, buffer, memory} := @use("../../stn/src/lib.hb");
.{Surface} := @use("../../render/src/lib.hb")
.{math: .{Vec2}, buffer, memory} := @use("stn");
.{Surface} := @use("lib:render")
$BUFFER_SERVER := "sunset_server\0"
$BUFFER_CLIENT := "sunset_client\0"
$BUFFER_SERVER := "sunset_server"
$BUFFER_CLIENT := "sunset_client"
Channel := packed struct {
client: uint,
@ -48,6 +48,8 @@ await_channel := fn(): Channel {
await_message := fn($Expr: type, buffer_id: uint): Message(Expr) {
response := @as(?Message(Expr), null)
loop {
// awaiting here causes flickering... idk why
buffer.await(buffer_id)
buffer.recv(?Message(Expr), buffer_id, &response)
if response != null {
return @as(Message(Expr), response)
@ -58,9 +60,11 @@ await_message := fn($Expr: type, buffer_id: uint): Message(Expr) {
await_header := fn(buffer_id: uint): MessageHeader {
response := @as(?MessageHeader, null)
loop {
// awaiting here causes flickering... idk why
buffer.await(buffer_id)
buffer.recv(?MessageHeader, buffer_id, &response)
if response != null {
return @as(?MessageHeader, response)
return @as(MessageHeader, response)
}
}
}
@ -81,8 +85,7 @@ Message := fn($Expr: type): type {
WindowProps := struct {
position: Vec2(uint),
dimensions: Vec2(uint),
// ! replace with owned string type later
title: ^u8,
title: []u8,
}
WindowData := struct {

View file

@ -1,33 +1,33 @@
.{math, log, string, random, buffer, memory} := @use("../../stn/src/lib.hb");
.{Color, Surface, new_surface, put_surface, sync, put_rect, put_filled_rect, text, put_text, clear, white, black} := @use("../../render/src/lib.hb");
.{Channel, Window, WindowProps, WindowData, MessageHeader, BUFFER_SERVER, BUFFER_CLIENT, message, permissions, recv_header, recv_message, send_message, send_header, await_message} := @use("./lib.hb")
.{math, log, string, random, buffer, memory} := @use("stn");
.{Color, Surface, text} := @use("lib:render");
.{Channel, Window, WindowProps, WindowData, MessageHeader, BUFFER_SERVER, BUFFER_CLIENT, message, permissions, recv_header, recv_message, send_message, send_header, await_message} := @use("lib:sunset_proto")
WindowServer := struct {
window_count: uint,
channel: Channel,
// ! replace this with a collection when we get an allocator
windows: [?Window; 10],
windows: [10]?Window,
font: text.Font,
}
// ! in the future this should be safely handled
server := @as(WindowServer, idk)
psf := @embed("../../../assets/consolefonts/tamsyn/10x20r.psf")
psf := @embed("sysdata:assets/consolefonts/tamsyn/10x20r.psf")
start := fn(): void {
font := text.font_from_psf2(@bitcast(&psf), false)
if font == null {
log.error("server: failed to load asset\0")
log.error("server: failed to load asset")
return
}
server = .(
0,
.{client: buffer.create(BUFFER_CLIENT), server: buffer.create(BUFFER_SERVER)},
.(null, null, null, null, null, null, null, null, null, null),
.[null, null, null, null, null, null, null, null, null, null],
@as(text.Font, font),
)
log.info("server: started server\0")
log.info("server: started server")
}
incoming := fn(): bool {
@ -36,14 +36,14 @@ incoming := fn(): bool {
return true
}
if msg.kind == message.syn {
log.info("server: recv syn\0")
log.info("server: recv syn")
channel := Channel.(buffer.create_nameless(), buffer.create_nameless())
send_message(Channel, message.ack, channel, server.channel.client)
props := await_message(WindowProps, channel.server)
if props.header.kind != message.props {
return true
}
log.info("server: recv props\0")
log.info("server: recv props")
// ! do inspection of requested props here
data := WindowData.(props.body, channel, permissions.default)
send_message(WindowData, message.ack, data, channel.client)
@ -51,17 +51,16 @@ incoming := fn(): bool {
// decorations
{
title := data.props.title
title_length := string.length(title)
deco_length := title_length * 10
deco_length := title.len * 10
// draw the window tab bar
put_filled_rect(surface, .(0, 0), .(data.props.dimensions.x + DECO_WIDTH + deco_length, DECO_HEIGHT_TOP), DECO_COLOUR)
surface.put_filled_rect(.(0, 0), .(data.props.dimensions.x + DECO_WIDTH + deco_length, DECO_HEIGHT_TOP), DECO_COLOUR)
// Draw the window tab
put_filled_rect(surface, .(0, 0), .(deco_length, DECO_HEIGHT_TOP - 1), DECO_COLOUR_DARKER)
surface.put_filled_rect(.(0, 0), .(deco_length, DECO_HEIGHT_TOP - 1), DECO_COLOUR_DARKER)
// Draw the outside box
put_rect(surface, .(0, 0), data.props.dimensions + .(DECO_WIDTH - 1, DECO_HEIGHT_TOP + DECO_HEIGHT_BOTTOM - 1), DECO_COLOUR)
surface.put_rect(.(0, 0), data.props.dimensions + .(DECO_WIDTH - 1, DECO_HEIGHT_TOP + DECO_HEIGHT_BOTTOM - 1), DECO_COLOUR)
put_text(surface, server.font, .(2, 1), .(0, 0, 0, 255), data.props.title)
surface.put_text(server.font, .(2, 1), .(0, 0, 0, 255), data.props.title)
}
server.windows[server.window_count] = .(data, surface)
server.window_count += 1
@ -76,10 +75,7 @@ $DECO_COLOUR := Color.(100, 200, 255, 255)
$DECO_COLOUR_DARKER := Color.(89, 57, 89, 255)
new_window_decorations := fn(dimensions: math.Vec2(uint)): Surface {
return new_surface(
dimensions.x + DECO_WIDTH,
dimensions.y + DECO_HEIGHT_TOP + DECO_HEIGHT_BOTTOM,
)
return @inline(Surface.new, dimensions.x + DECO_WIDTH, dimensions.y + DECO_HEIGHT_TOP + DECO_HEIGHT_BOTTOM)
}
// ! compositor code. this currently disallows tearing.
@ -104,10 +100,10 @@ collect_frames := fn(): void {
send_header(message.ack, window.data.channel.client)
ptr := await_message(^Color, window.data.channel.server)
if ptr.header.kind != message.ack {
return
i += 1
continue
}
put_surface(
window.surface,
window.surface.put_surface(
Surface.(
ptr.body,
window.data.props.dimensions.x,
@ -129,7 +125,7 @@ render_clients := fn(screen: Surface): void {
i += 1
continue
}
put_surface(screen, window.surface, window.data.props.position, false)
screen.put_surface(window.surface, window.data.props.position, false)
i += 1
}
}

View file

@ -0,0 +1 @@
# ablefetch

View file

@ -1,6 +1,6 @@
[package]
name = "processes"
authors = ["koniifer"]
name = "ablefetch"
authors = [""]
[dependants.libraries]

View file

@ -0,0 +1,43 @@
stn := @use("stn")
sunset := @use("lib:sunset_proto")
render := @use("lib:render")
psf := @embed("sysdata:assets/consolefonts/tamsyn/10x20r.psf")
horizon_api := @use("lib:horizon_api");
.{Vec2} := stn.math;
.{log} := stn;
.{set_color, render_label_to_surface, Label} := horizon_api.widgets.label
main := fn(): void {
sunset.client.find_server()
window := sunset.client.new(.(.(10, 10), .(400, 300), "ableFetch!"))
font := @unwrap(render.text.font_from_psf2(@bitcast(&psf), false))
// pos := Vec2(uint).(1, 100)
if window == null {
log.error("got no window")
return
}
text_label := Label.new_label("kernel : akern 0.2.0", 300)
text_label_2 := Label.new_label("os : ableos", 300)
text_label_3 := Label.new_label("wm : sunset", 300)
text_label.set_color(render.BLACK, render.WHITE)
text_label_2.set_color(render.BLACK, render.WHITE)
text_label_3.set_color(render.BLACK, render.WHITE)
pos1 := Vec2(uint).(1, 1)
pos2 := Vec2(uint).(1, 20)
pos3 := Vec2(uint).(1, 40)
render_label_to_surface(window.surface, text_label, font, pos1)
render_label_to_surface(window.surface, text_label_2, font, pos2)
render_label_to_surface(window.surface, text_label_3, font, pos3)
loop {
// stn.log.info("AAAA")
_ = sunset.client.send_frame(window)
// stn.sleep.sleep_until_interrupt(100)
}
}

View file

@ -0,0 +1,5 @@
# angels_halo
A Minix 3 style reincarnation service.
Running in the background restarting your drivers.

View file

@ -1,5 +1,5 @@
[package]
name = "dt_buffer_test"
name = "angels_halo"
authors = ["able"]
[dependants.libraries]

View file

@ -0,0 +1,7 @@
(pkg angels-halo
(authors ("able"))
(version 0 1 0))
(dependencies
(libraries ())
(programs (hblang)))

View file

@ -0,0 +1,18 @@
stn := @use("stn");
.{log} := stn;
.{ProcessID} := stn.acs
Strategy := enum {
None,
Restart,
}
MonitoredProcess := struct {
pid: ProcessID,
}
main := fn(): int {
log.info("Angels Halo reincarnation server started.")
return 0
}

View file

@ -1,13 +1,111 @@
.{memory, buffer} := @use("../../../libraries/stn/src/lib.hb")
.{memory: .{inb, outb, ins, alloc}, log} := @use("stn")
main := fn(): int {
// shuts down ableOS
// memory.outb(0xF400, 0)
$ATA_PRIMARY_DATA := 0x1F0
$ATA_PRIMARY_ERR := 0x1F1
$ATA_PRIMARY_SECCOUNT := 0x1F2
$ATA_PRIMARY_LBA_LO := 0x1F3
$ATA_PRIMARY_LBA_MID := 0x1F4
$ATA_PRIMARY_LBA_HI := 0x1F5
$ATA_PRIMARY_DRIVE_HEAD := 0x1F6
$ATA_PRIMARY_COMM_REGSTAT := 0x1F7
$ATA_PRIMARY_ALTSTAT_DCR := 0x3F6
a := memory.inb(0x4600)
b := memory.inb(0x4700)
$STAT_ERR := 1 << 0
$STAT_DRQ := 1 << 3
$STAT_SRV := 1 << 4
$STAT_DF := 1 << 5
$STAT_RDY := 1 << 6
$STAT_BSY := 1 << 7
c := buffer.search("XNumber\0")
Drive := enum {Master, Slave}
select_drive := fn(drive: Drive): void {
match drive {
.Master => outb(ATA_PRIMARY_DRIVE_HEAD, 0xA0),
.Slave => outb(ATA_PRIMARY_DRIVE_HEAD, 0xB0),
}
}
identify := fn(drive: Drive): u8 {
if inb(ATA_PRIMARY_COMM_REGSTAT) == 0xFF {
log.error("(ata: drive not present) status=0xFF")
return 0
}
select_drive(drive)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_SECCOUNT, 0)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_LBA_LO, 0)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_LBA_MID, 0)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_LBA_HI, 0)
inb(ATA_PRIMARY_COMM_REGSTAT)
outb(ATA_PRIMARY_COMM_REGSTAT, 0xEC)
outb(ATA_PRIMARY_COMM_REGSTAT, 0xE7)
status := inb(ATA_PRIMARY_COMM_REGSTAT)
loop if (status & STAT_BSY) == 0 break else {
// if DEBUG_PRINT log.printf("(ata: waiting for status) status={}", .(status), .{radix: 16, log: .Warn})
status = inb(ATA_PRIMARY_COMM_REGSTAT)
}
if status == 0 {
log.error("(ata: drive not present) status=0")
return 0
}
loop if (status & STAT_BSY) == 0 break else {
if DEBUG_PRINT log.printf("(ata: waiting for busy to end) status={}", .(status), .{radix: 16, log: .Warn})
status = inb(ATA_PRIMARY_COMM_REGSTAT)
}
mid := inb(ATA_PRIMARY_LBA_MID)
hi := inb(ATA_PRIMARY_LBA_HI)
if (mid | hi) != 0 {
log.error("the drive is not ata...?")
return 0
}
loop if (status & (STAT_ERR | STAT_DRQ)) != 0 break else {
if DEBUG_PRINT log.printf("(ata: waiting for ERR or DRQ) status={}", .(status), .{radix: 16, log: .Warn})
status = inb(ATA_PRIMARY_COMM_REGSTAT)
}
if (status & STAT_ERR) != 0 {
if DEBUG_PRINT log.printf("(ata: drive error) status={}", .(status), .{radix: 16, log: .Error})
return 0
}
if DEBUG_PRINT log.printf("status={}", .(status), .{radix: 16})
buffer := alloc(u16, 255)[0..255]
read(buffer)
if DEBUG_PRINT {
if (buffer[83] & 1 << 10) != 0 {
log.info("LBA48 mode supported")
log.printf("{} 48 bit addressable sectors", *@as(^uint, @bitcast(buffer[100..].ptr)), .{})
}
log.print(buffer, .{})
}
return 0
}
read := fn(buffer: []u16): void {
i := 0
loop if i == buffer.len break else {
buffer[i] = ins(ATA_PRIMARY_DATA)
i += 1
}
}
// inflates asm a lot
$DEBUG_PRINT := true
main := fn(): void {
identify(.Master)
}

View file

@ -0,0 +1,35 @@
// $ATA_PRIMARY_DATA := @intcast(0x1F0)
// $ATA_PRIMARY_ERR := @intcast(0x1F1)
// $ATA_PRIMARY_SECCOUNT := @intcast(0x1F2)
// $ATA_PRIMARY_LBA_LO := @intcast(0x1F3)
// $ATA_PRIMARY_LBA_MID := @intcast(0x1F4)
// $ATA_PRIMARY_LBA_HI := @intcast(0x1F5)
// $ATA_PRIMARY_DRIVE_HEAD := @intcast(0x1F6)
// $ATA_PRIMARY_COMM_REGSTAT := @intcast(0x1F7)
// $ATA_PRIMARY_ALTSTAT_DCR := @intcast(0x3F6)
$ATA_PRIMARY_IO := @intcast(0x1F0)
$ATA_PRIMARY_DEVCTL := @intcast(0x3F6)
$ATA_SECONDARY_DEVCTL := @intcast(0x3F6)
$ATA_REG_STAT := @intcast(0x7)
// // Indicates an error occurred. Send a new command to clear it
// STAT_ERR := 1 << 0
// // Set when the drive has PIO data to transfer, or is ready to accept PIO data.
// STAT_DRQ := 1 << 3
// // Overlapped Mode Service Request.
// STAT_SRV := 1 << 4
// // Drive Fault Error (does not set ERR).
// STAT_DF := 1 << 5
// // Bit is clear when drive is spun down, or after an error. Set otherwise.
// STAT_RDY := 1 << 6
// // Indicates the drive is preparing to send/receive data (wait for it to clear).
// // In case of 'hang' (it never clears), do a software reset.
// STAT_BSY := 1 << 7
$ATA_SR_BSY := 0x80
$ATA_SR_DF := 0x20
$ATA_SR_DRQ := 0x8
$ATA_SR_ERR := 0x1

View file

@ -1 +0,0 @@
# dt_buffer_test

View file

@ -1,13 +0,0 @@
.{dt} := @use("../../../libraries/stn/src/lib.hb")
main := fn(): void {
dt.get(void, "framebuffer/fb0/width\0")
dt.get(void, "cpu/cpu0/architecture\0")
// Checking if the first detected serial port is memory mapped or port mapped
// 0 -> memory mapped
// 1 -> port mapped
dt.get(void, "serial_ports/sp0/mapping\0")
return
}

View file

@ -1,7 +1,7 @@
READ_ONLY := @as(u32, 0x1)
HIDDEN := @as(u32, 0x2)
SYSTEM := @as(u32, 0x4)
VOLUME_ID := @as(u32, 0x8)
DIRECTORY := @as(u32, 0x10)
ARCHIVE := @as(u32, 0x20)
$READ_ONLY := 0x1
$HIDDEN := 0x2
$SYSTEM := 0x4
$VOLUME_ID := 0x8
$DIRECTORY: 0x10
$ARCHIVE := 0x20
LFN := READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID

View file

@ -1,19 +1,19 @@
stn := @use("../../../libraries/stn/src/lib.hb");
stn := @use("stn");
.{string, memory, buffer, log} := stn
VALID_JUMP_BYTES := [u8].(0xEB, 0x3C, 0x90)
VALID_JUMP_BYTES := u8.[0xEB, 0x3C, 0x90]
OemIdent := struct {
dos_version: [u8; 8],
dos_version_name: [u8; 8],
}
dos_version: [8]u8,
dos_version_name: [8]u8,
new_oem_ident := fn(major: int, minor: int): OemIdent {
return .(.(0, 0, 0, 0, 0, 0, 0, 0), .(0, 0, 0, 0, 0, 0, 0, 0))
new := fn(major: int, minor: int): OemIdent {
return .(.[0, 0, 0, 0, 0, 0, 0, 0], .[0, 0, 0, 0, 0, 0, 0, 0])
}
}
BiosParameterBlock := struct {
jump_bytes: [u8; 3],
jump_bytes: [3]u8,
oem_ident: OemIdent,
bytes_per_sector: u16,
sectors_per_cluster: u8,
@ -30,21 +30,21 @@ BiosParameterBlock := struct {
head_count: u16,
hidden_sectors: u32,
large_sector_count: u32,
}
bpb_sanity_check := fn(bpb: BiosParameterBlock): int {
return 0
}
sanity_check := fn(bpb: BiosParameterBlock): int {
return 0
}
new_bpb := fn(): BiosParameterBlock {
return .(VALID_JUMP_BYTES, new_oem_ident(0, 0), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
}
new := fn(): BiosParameterBlock {
return .(VALID_JUMP_BYTES, OemIdent.new(0, 0), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
}
sector_count := fn(bpb: BiosParameterBlock): u32 {
if bpb.total_sectors == 0 {
return bpb.large_sector_count
} else {
return bpb.total_sectors
sector_count := fn(bpb: BiosParameterBlock): u32 {
if bpb.total_sectors == 0 {
return bpb.large_sector_count
} else {
return bpb.total_sectors
}
}
}
@ -53,16 +53,16 @@ FatVersionNumber := struct {
minor_version: u8,
}
FormatReservation := [u8; 12]
FormatReservation := [12]u8
// Padded with spaces.
VolumeName := [u8; 11]
VolumeName := [11]u8
SystemIdentifierString := [u8; 8]
VALID_SYSTEM_IDENTIFIER_STRING := [u8].(46, 41, 54, 33, 32, 20, 20, 20)
SystemIdentifierString := [8]u8
VALID_SYSTEM_IDENTIFIER_STRING := u8.[46, 41, 54, 33, 32, 20, 20, 20]
BOOTABLE_PARTITION_SIGNATURE := @as(u32, 0xAA55)
BootCode := [u8; 420]
BootCode := [420]u8
ExtendedBootRecord := struct {
sectors_per_fat: u32,
@ -85,48 +85,48 @@ ExtendedBootRecord := struct {
system_identifier_string: SystemIdentifierString,
boot_code: BootCode,
partition_signature: u16,
}
ebr_sanity_check := fn(ebr: ExtendedBootRecord): int {
ret := 0
if ebr.drive_number != 0x0 | ebr.drive_number != 0x80 {
log.warn("EBR-Drive-Number sanity check failed\0")
sanity_check := fn(ebr: ExtendedBootRecord): int {
ret := 0
if ebr.drive_number != 0x0 | ebr.drive_number != 0x80 {
log.warn("EBR-Drive-Number sanity check failed")
}
if ebr.signature != 0x28 | ebr.signature != 0x29 {
log.warn("EBR-Signature sanity check failed")
}
// ! comparison between [u8] is not supported in hblang
// if ebr.system_identifier_string != VALID_SYSTEM_IDENTIFIER_STRING {
// log.warn("EBR-Signature-Identifier-String sanity check failed")
// }
return 0
}
if ebr.signature != 0x28 | ebr.signature != 0x29 {
log.warn("EBR-Signature sanity check failed\0")
new := fn(): ExtendedBootRecord {
version := FatVersionNumber.(0, 0)
fmt_res := u8.[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
vol_name := @as([11]u8, idk)
boot_code := @as([420]u8, idk)
return ExtendedBootRecord.(
0,
0,
version,
0,
0,
0,
fmt_res,
0,
0,
0,
0,
vol_name,
VALID_SYSTEM_IDENTIFIER_STRING,
boot_code,
0,
)
}
// ! comparison between [u8] is not supported in hblang
// if ebr.system_identifier_string != VALID_SYSTEM_IDENTIFIER_STRING {
// log.warn("EBR-Signature-Identifier-String sanity check failed\0")
// }
return 0
}
new_ebr := fn(): ExtendedBootRecord {
version := FatVersionNumber.(0, 0)
fmt_res := FormatReservation.(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
vol_name := @as([u8; 11], idk)
boot_code := @as([u8; 420], idk)
return ExtendedBootRecord.(
0,
0,
version,
0,
0,
0,
fmt_res,
0,
0,
0,
0,
vol_name,
VALID_SYSTEM_IDENTIFIER_STRING,
boot_code,
0,
)
}
VALID_LEAD_FS_INFO := @as(u32, 0x41615252)
@ -135,45 +135,45 @@ VALID_TRAIL_FS_INFO := @as(u32, 0xAA550000)
FSInfo := struct {
// Must be 0x41615252 to indicate a valid FSInfo structure
lead_signature: u32,
lead_reserved: [u8; 480],
lead_reserved: [480]u8,
// If the value is 0xFFFFFFFF, then the free count is unknown and must be computed. However, this value might be incorrect and should at least be range checked (<= volume cluster count)
last_known_free_cluster_count: u32,
last_known_avalible_cluster: u32,
trail_reserved: [u8; 12],
trail_reserved: [12]u8,
trail_signature: u32,
}
fs_info_sanity_check := fn(fs_info: FSInfo): uint {
ret := 0
if fs_info.lead_signature != VALID_LEAD_FS_INFO {
ret &= 1
log.warn("Invalid leading signature in FSInfo.\0")
}
if fs_info.last_known_free_cluster_count == 0xFFFFFFFF {
ret &= 2
log.warn("Last known free cluster count unknown.\0")
}
if fs_info.last_known_avalible_cluster == 0xFFFFFFFF {
ret &= 4
log.warn("Last known avalible cluster count unknown.\0")
}
if fs_info.trail_signature != VALID_TRAIL_FS_INFO {
ret &= 8
log.warn("Invalid trailing signature in FSInfo.\0")
sanity_check := fn(fs_info: FSInfo): uint {
ret := 0
if fs_info.lead_signature != VALID_LEAD_FS_INFO {
ret &= 1
log.warn("Invalid leading signature in FSInfo.")
}
if fs_info.last_known_free_cluster_count == 0xFFFFFFFF {
ret &= 2
log.warn("Last known free cluster count unknown.")
}
if fs_info.last_known_avalible_cluster == 0xFFFFFFFF {
ret &= 4
log.warn("Last known avalible cluster count unknown.")
}
if fs_info.trail_signature != VALID_TRAIL_FS_INFO {
ret &= 8
log.warn("Invalid trailing signature in FSInfo.")
}
return ret
}
return ret
}
new_fs_info := fn(): FSInfo {
lead_reserved := @as([u8; 480], idk)
trail_reserved := @as([u8; 12], idk)
return FSInfo.(
VALID_LEAD_FS_INFO,
lead_reserved,
0,
0,
trail_reserved,
VALID_TRAIL_FS_INFO,
)
new := fn(): FSInfo {
lead_reserved := @as([480]u8, idk)
trail_reserved := @as([12]u8, idk)
return FSInfo.(
VALID_LEAD_FS_INFO,
lead_reserved,
0,
0,
trail_reserved,
VALID_TRAIL_FS_INFO,
)
}
}

View file

@ -2,24 +2,25 @@ Date := struct {
year: u16,
month: u16,
day: u16,
compress_date := fn(year: u16, month: u16, day: u16): u16 {
return 0
}
decompress_date := fn(date: u16): Date {
return Date.(0, 0, 0)
}
}
Time := struct {
hour: u16,
minutes: u16,
seconds: u16,
}
compress_date := fn(year: u16, month: u16, day: u16): u16 {
return 0
}
decompress_date := fn(date: u16): Date {
return Date.(0, 0, 0)
}
compress_time := fn(hour: u16, minutes: u16, seconds: u16): u16 {
return 0
}
compress_time := fn(hour: u16, minutes: u16, seconds: u16): u16 {
return 0
}
decompress_time := fn(time: u16): Time {
return Time.(0, 0, 0)
decompress_time := fn(time: u16): Time {
return Time.(0, 0, 0)
}
}

View file

@ -1,7 +1,7 @@
attributes := @use("attributes.hb")
datetime := @use("datetime.hb")
FileName := [u8; 11]
FileName := [11]u8
// This is the File Allocation Table entry that tells us where on disk the File is.
FileEntry := struct {
@ -18,4 +18,4 @@ FileEntry := struct {
last_modification_date: datetime.date,
low_cluster_number: u16,
file_size: u32,
}
}

View file

@ -1,4 +1,4 @@
stn := @use("../../../libraries/stn/src/lib.hb");
stn := @use("stn");
.{string, memory, buffer, log} := stn
attributes := @use("attributes.hb")
@ -6,19 +6,19 @@ datetime := @use("datetime.hb")
directory := @use("file.hb")
bios_parameter_block := @use("bios_parameter_block.hb");
.{bpb_sanity_check, ebr_sanity_check, fs_info_sanity_check} := bios_parameter_block;
.{new_bpb, new_ebr, new_fs_info} := bios_parameter_block
.{BiosParameterBlock, ExtendedBootRecord, FSInfo} := bios_parameter_block
FAT12_THRESHOLD := 4085
FAT16_THRESHOLD := 65525
$FAT12_THRESHOLD := 4085
$FAT16_THRESHOLD := 65525
ExFAT := 0
FAT12 := 1
FAT16 := 2
FAT32 := 3
$EXFAT := 0
$FAT12 := 1
$FAT16 := 2
$FAT32 := 3
calculate_fat_type := fn(sector_size: uint, total_clusters: uint): uint {
if sector_size == 0 {
return ExFAT
return EXFAT
} else if total_clusters < 4085 {
return FAT12
} else if total_clusters < 65525 {
@ -29,19 +29,19 @@ calculate_fat_type := fn(sector_size: uint, total_clusters: uint): uint {
}
main := fn(): int {
bpb := new_bpb()
ebr := new_ebr()
fsi := new_fs_info()
bpb := BiosParameterBlock.new()
ebr := ExtendedBootRecord.new()
fsi := FSInfo.new()
fat_type := calculate_fat_type(1, 100)
if fat_type != FAT32 {
log.warn("filesystem_fat32 driver only supports Fat32.\0")
log.warn("filesystem_fat32 driver only supports Fat32.")
}
bsc := bpb_sanity_check(bpb)
esc := ebr_sanity_check(ebr)
fssc := fs_info_sanity_check(fsi)
bsc := bpb.sanity_check()
esc := ebr.sanity_check()
fssc := fsi.sanity_check()
msg_type := 0
@ -49,7 +49,7 @@ main := fn(): int {
// Open file
if msg_type == 0 {
// Paths without a node-disk component are to be treated as local files.
file_path := "node-disk:/test\0"
file_path := "node-disk:/test"
} else {
// error
}

View file

@ -0,0 +1,5 @@
# hblang²
The hblang² or hblang2 compiler is intended to compile hblang to hbvm bytecode while also being written in hblang.
This is the first step in bootstrapping ableOS.

View file

@ -1,6 +1,6 @@
[package]
name = "serial_driver_test"
authors = ["able"]
name = "hblang2"
authors = [""]
[dependants.libraries]

View file

@ -0,0 +1,5 @@
stn := @use("stn")
main := fn(): int {
return 0
}

View file

@ -1,16 +1,16 @@
stn := @use("../../../libraries/stn/src/lib.hb");
stn := @use("stn");
.{string, memory, buffer, random, log} := stn;
.{Vec2} := stn.math
horizon_api := @use("../../../libraries/horizon_api/src/lib.hb");
horizon_api := @use("lib:horizon_api");
.{new_label, render_label_to_surface, set_label_text} := horizon_api.widgets.label;
.{sexpr_parser, render_ui} := horizon_api.ui
render := @use("../../../libraries/render/src/lib.hb");
render := @use("lib:render");
.{Surface} := render;
.{Font} := render.text
intouch := @use("../../../libraries/intouch/src/lib.hb")
intouch := @use("lib:intouch")
Window := struct {
// TODO: Replace this with widgets
@ -21,23 +21,23 @@ Window := struct {
y: int,
}
psf := @embed("../../../assets/consolefonts/tamsyn/10x20r.psf")
img := @embed("../../../assets/wallpaper.qoi")
psf := @embed("sysdata:assets/consolefonts/tamsyn/10x20r.psf")
img := @embed("sysdata:assets/wallpaper.qoi")
main := fn(): int {
win_buff := buffer.create("XHorizon\0")
win_buff := buffer.create("XHorizon")
screen := render.init(true)
// Clear the screen to black.
render.clear(screen, render.black)
screen.clear(render.BLACK)
wallpaper := render.image.from(@bitcast(&img))
if wallpaper == null {
return 1
}
window := render.new_surface(screen.width / 3, screen.height / 3)
window := render.Surface.new(screen.width / 3, screen.height / 3)
mem_buf := memory.request_page(1)
color := random.any(render.Color)
@ -48,16 +48,16 @@ main := fn(): int {
mouse_x := @as(i16, 0)
mouse_y := @as(i16, 0)
text_label := new_label("Hi\0")
text_label := new_label("Hi")
// widgets := "()\0"
// widgets := "()"
// ui := sexpr_parser(widgets)
loop {
// Clear the screen
render.clear(screen, render.black)
screen.clear(render.BLACK)
render.put_surface(screen, wallpaper, .(0, 0), false)
screen.put_surface(wallpaper, .(0, 0), false)
// TODO: Read the window buffer here
{
@ -65,33 +65,33 @@ main := fn(): int {
if false {
// Scroll bar :ThumbsUp:
render.put_rect(screen, .(100, 100), .(100, 10), render.white)
render.put_filled_rect(screen, .(110, 100), .(20, 10), render.white)
screen.put_rect(.(100, 100), .(100, 10), render.WHITE)
screen.put_filled_rect(.(110, 100), .(20, 10), render.WHITE)
render.put_rect(screen, .(90, 110), .(10, 100), render.white)
render.put_filled_rect(screen, .(90, 120), .(10, 20), render.white)
screen.put_rect(.(90, 110), .(10, 100), render.WHITE)
screen.put_filled_rect(.(90, 120), .(10, 20), render.WHITE)
}
{
// osu dots
render.put_rect(screen, .(400, 100), .(100, 100), render.red)
render.put_rect(screen, .(100, 100 + 300), .(100, 100), render.red)
screen.put_rect(.(400, 100), .(100, 100), render.RED)
screen.put_rect(.(100, 100 + 300), .(100, 100), render.RED)
}
{
pos := Vec2(uint).(1, screen.height - 21)
render_label_to_surface(screen, text_label, font, pos)
render.put_rect(screen, .(0, screen.height - 21), .(screen.width - 1, 20), render.white)
screen.put_rect(.(0, screen.height - 21), .(screen.width - 1, 20), render.WHITE)
}
// Screen border
render.put_rect(screen, .(0, 0), .(screen.width - 1, screen.height - 1), render.white)
screen.put_rect(.(0, 0), .(screen.width - 1, screen.height - 1), render.WHITE)
// get input events from drivers via intouch
if false {
key_event := intouch.recieve_key_event()
if key_event != null {
log.info("Key event \0")
log.info("Key event ")
}
}
@ -100,7 +100,7 @@ main := fn(): int {
//
if mouse_event != null {
// log.warn("Mouse event received\0")
// log.warn("Mouse event received")
change_x := @as(i16, mouse_event.x_change)
change_x = change_x << 8
@ -127,18 +127,18 @@ main := fn(): int {
mouse_y -= change_y
if mouse_event.left {
set_label_text(text_label, "LEFT CLICK\0")
set_label_text(text_label, "LEFT CLICK")
}
if mouse_event.middle {
set_label_text(text_label, "MIDDLE CLICK\0")
set_label_text(text_label, "MIDDLE CLICK")
}
if mouse_event.right {
set_label_text(text_label, "RIGHT CLICK\0")
set_label_text(text_label, "RIGHT CLICK")
}
}
render.put_filled_rect(screen, .(mouse_x, mouse_y), .(20, 20), render.black)
render.put_rect(screen, .(mouse_x, mouse_y), .(20, 20), render.white)
screen.put_filled_rect(.(mouse_x, mouse_y), .(20, 20), render.BLACK)
screen.put_rect(.(mouse_x, mouse_y), .(20, 20), render.WHITE)
// Send events to focused window
}
@ -146,7 +146,7 @@ main := fn(): int {
// TODO: Get windows out of a collection and iter through
// Sync the screen
render.sync(screen)
screen.sync()
}
return 0

View file

@ -1,25 +1,25 @@
stn := @use("../../../libraries/stn/src/lib.hb");
stn := @use("stn");
.{string, memory, buffer, log} := stn
horizon_api := @use("../../../libraries/horizon_api/src/lib.hb");
horizon_api := @use("lib:horizon_api");
.{create_window} := horizon_api
ignim := @use("../../../libraries/ignim/src/lib.hb");
ignim := @use("lib:ignim");
.{errors} := ignim
psf := @embed("../../../consolefonts/tamsyn/10x20r.psf")
psf := @embed("sysdata:assets/consolefonts/tamsyn/10x20r.psf")
main := fn(): int {
x := 0
// loop if x > 10000 break else x += 1
windowing_system_buffer := buffer.search("XHorizon\0")
windowing_system_buffer := buffer.search("XHorizon")
// TODO: get WindowID
wid := create_window(windowing_system_buffer)
if false {
program_name := "Horizon Testing Program\0"
program_name := "Horizon Testing Program"
program_version := ignim.version.make_version(0, 1, 0)
engine_name := "None\0"
engine_name := "None"
engine_version := ignim.version.make_version(0, 0, 0)
api_version := ignim.version.make_api_version(0, 1, 0, 0)
@ -32,7 +32,7 @@ main := fn(): int {
// // TODO: recursively follow this https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance
ret := ignim.instance.create_instance(&create_info, 0, &instance)
if ret == errors.IncompatibleDriver {
log.error("Driver Incompatible with Vulkan\0")
log.error("Driver Incompatible with Vulkan")
}
}

View file

@ -0,0 +1 @@
# pcspkr

View file

@ -1,6 +1,6 @@
[package]
name = "sunset_client_2"
authors = ["koniifer"]
name = "pcspkr"
authors = [""]
[dependants.libraries]

View file

@ -0,0 +1,45 @@
stn := @use("stn");
.{memory, buffer, log, string, math} := stn;
.{inb, outb} := memory
$PIT_CLOCK := 1193180
play_sound := fn(frequency: u32): void {
div := 0
div = PIT_CLOCK / frequency
memory.outb(0x43, 0xB6)
memory.outb(0x42, @intcast(div))
memory.outb(0x42, @intcast(div >> 8))
tmp := inb(0x61)
if tmp != (tmp | 3) {
outb(0x61, tmp | 3)
}
}
no_sound := fn(): void {
tmp := memory.inb(0x61) & 0xFC
memory.outb(0x61, tmp)
}
beep := fn(): void {
play_sound(1000)
idx := 0
loop {
if idx >= 1000000 {
idx += 1
} else {
break
}
}
no_sound()
}
main := fn(): int {
no_sound()
beep()
return 0
}

View file

@ -1,7 +0,0 @@
.{log} := @use("../../../libraries/stn/src/lib.hb")
main := fn(): void {
log.info("Hello, World!\0")
loop {
}
}

View file

@ -1,19 +0,0 @@
.{process, log, string, memory} := @use("../../../libraries/stn/src/lib.hb")
exe := @embed("./hello_world_and_spin.hbf")
main := fn(): void {
buf := "\0\0\0\0\0\0\0"
loop {
log.info(
string.display_int(
@bitcast(process.spawn(@bitcast(&exe), 356)),
buf,
10,
),
)
// spin so we don't spawn 10 quattuordecillion processes
i := 0
loop if i == 1000000 break else i += 1
}
}

View file

@ -0,0 +1,23 @@
# Unified PS/2 Driver
Te entire thing is held together inspite
## !!Assumptions!!
Anyone who works on this should work to keep this list as small as possible/remove as many of these as possible.
- Bit 5 of the response form 0x64 indicates which port the data is coming from. (Not true on all systems)
- A parity or timeout error never occurs.
- PS/2 controller exists.
- Both PS/2 ports being broken doesn't need handling.
- One PS/2 port being broken doesn't need special attention.
- PS/2 controller doesn't need to perform a self-check.
- These DeviceIDs never exist:
- 0xFFFD
- 0xFFFE
- 0xFFFF
- 0x01xx
- 0x03xx
- 0x04xx
- Literally all PS/2 keyboards can be handeled the exact same way. We have the capability for detecting different keyboard types, I just don't bother with it because that would litreally take months to get working.
- The device doesn't send any data while we're waiting for an `ACK`.
Supporting mice in the keyboard port and vice versa was a ***bad*** idea, but I do not regret it because it means we're "superior" to real world operating systems.

View file

@ -0,0 +1,11 @@
[package]
name = "ps2_driver"
authors = ["Peony"]
[dependants.libraries]
[dependants.binaries]
hblang.version = "1.0.0"
[build]
command = "hblang src/main.hb"

View file

@ -0,0 +1,26 @@
//Do not question.
$bit0 := fn(value: u8): bool {
return (value & 0x1) > 0
}
$bit1 := fn(value: u8): bool {
return (value & 0x2) > 0
}
$bit2 := fn(value: u8): bool {
return (value & 0x4) > 0
}
$bit3 := fn(value: u8): bool {
return (value & 0x8) > 0
}
$bit4 := fn(value: u8): bool {
return (value & 0x10) > 0
}
$bit5 := fn(value: u8): bool {
return (value & 0x20) > 0
}
$bit6 := fn(value: u8): bool {
return (value & 0x40) > 0
}
$bit7 := fn(value: u8): bool {
return (value & 0x80) > 0
}

View file

@ -0,0 +1,101 @@
.{memory, log} := @use("stn");
.{bit0, bit1, bit5, bit6, bit7} := @use("bits.hb");
.{Port, PORT_AT_STARTUP} := @use("port.hb")
port1 := @as(Port, PORT_AT_STARTUP)
port2 := @as(Port, PORT_AT_STARTUP)
//wiki.osdev.org/"8042"_PS/2_Controller#PS/2_Controller_IO_Ports
$CONTROLLER_PORT := 0x64
$DATA_PORT := 0x60
$disable_port1 := fn(): void memory.outb(CONTROLLER_PORT, 0xAD)
$enable_port1 := fn(): void memory.outb(CONTROLLER_PORT, 0xAE)
$disable_port2 := fn(): void memory.outb(CONTROLLER_PORT, 0xA7)
$enable_port2 := fn(): void memory.outb(CONTROLLER_PORT, 0xA8)
test_port1 := fn(): bool {
memory.outb(CONTROLLER_PORT, 0xAB)
loop if has_input(get_info()) break
input := get_input()
return input == 0x0
}
test_port2 := fn(): bool {
memory.outb(CONTROLLER_PORT, 0xA9)
loop if has_input(get_info()) break
input := get_input()
return input == 0x0
}
get_config_byte := fn(): u8 {
memory.outb(CONTROLLER_PORT, 0x20)
loop if has_input(get_info()) break
return get_input()
}
Info := struct {d: u8}
$get_info := fn(): Info return .(memory.inb(CONTROLLER_PORT))
//inline when can
has_input := fn(info: Info): bool return bit0(info.d)
can_send := fn(info: Info): bool return bit1(info.d) == false
timed_out := fn(info: Info): bool return bit6(info.d)
check_parity := fn(info: Info): bool return bit7(info.d)
get_port := fn(info: Info): ^Port {
if bit5(info.d) {
return &port2
} else {
return &port1
}
}
//T
port2_ptr := &port2
send_byte := fn(port: ^Port, byte: u8): void {
if port == port2_ptr {
memory.outb(CONTROLLER_PORT, 0xD4)
}
loop if can_send(get_info()) break
memory.outb(DATA_PORT, byte)
}
$get_input := fn(): u8 return memory.inb(DATA_PORT)
$write_out := fn(data: u8): void memory.outb(DATA_PORT, data)
flush_input := fn(): void {
loop if has_input(get_info()) == false break else get_info()
}
init := fn(): void {
disable_port1()
disable_port2()
//Disables ports to make sure that they won't interfere with the setup process.
flush_input()
enable_port2()
port2.exists = bit5(@inline(get_config_byte)) == false
disable_port2()
flush_input()
port1.exists = test_port1()
if port2.exists {
port2.exists = test_port2()
}
if (port1.exists | port2.exists) == false {
log.error("No ports detected! No input will be processed! Cannot handle this!")
}
if port1.exists {
log.info("Port 1 exists.")
enable_port1()
}
if port2.exists {
log.info("Port 2 exists.")
enable_port2()
}
}

View file

@ -0,0 +1,15 @@
DeviceID := struct {value: u16}
$MOUSE_3_BUTTON := DeviceID.(0x0)
$MOUSE_SCROLLWHEEL := DeviceID.(0x3)
$MOUSE_5_BUTTON := DeviceID.(0x4)
$KEYBOARD_SPACESAVER := DeviceID.(0x84AB)
$KEYBOARD_122_KEY := DeviceID.(0x86AB)
$KEYBOARD_JAPANESE_G := DeviceID.(0x90AB)
$KEYBOARD_JAPANESE_P := DeviceID.(0x91AB)
$KEYBOARD_JAPANESE_A := DeviceID.(0x92AB)
$KEYBOARD_NCD_SUN := DeviceID.(0xA1AC)
$MOUSE_INIT_1 := DeviceID.(0xFFFD)
$MOUSE_INIT_2 := DeviceID.(0xFFFE)
$NO_DEVICE := DeviceID.(0xFFFF)

View file

@ -0,0 +1,150 @@
.{memory, log, buffer, string} := @use("stn");
.{MouseEvent} := @use("lib:intouch").events;
.{bit0, bit1, bit2, bit3, bit4} := @use("bits.hb")
devices := @use("devices.hb")
controller := @use("controller.hb");
.{Info, Port} := controller
mouse := @use("mouse.hb")
mouse_buffer := 0
keyboard_buffer := 0
info := Info.(0)
send_command := fn(port: ^Port, byte: u8): void {
tries := 3
loop if tries == 0 break else {
controller.send_byte(port, byte)
loop {
info = controller.get_info()
if controller.has_input(info) == false {
continue
}
input := controller.get_input()
if controller.get_port(info) != port {
if check_complete(port) == false {
port.packet[port.packet_length] = input
port.packet_length += 1
}
continue
}
if input == 0xFA {
return
} else {
break
}
}
tries -= 1
}
}
enable_streaming := fn(port: ^Port): void {
@inline(send_command, port, 0xF4)
}
process := fn(port: ^controller.Port): void {
if port.device.value < devices.MOUSE_5_BUTTON.value {
event := MouseEvent.(0, 0, false, false, false)
event.left = bit0(port.packet[0])
event.right = bit1(port.packet[0])
event.middle = bit2(port.packet[0])
event.x_change = @intcast(port.packet[1])
event.y_change = @intcast(port.packet[2])
buffer.write(MouseEvent, mouse_buffer, &event)
} else if port.device == devices.MOUSE_INIT_1 {
port.device.value = port.packet[0]
if port.device != devices.MOUSE_SCROLLWHEEL {
enable_streaming(port)
return
}
port.device = devices.MOUSE_INIT_2
} else if port.device == devices.MOUSE_INIT_2 {
port.device.value = port.packet[0]
} else if port.device == devices.NO_DEVICE {
if port.packet_length == 1 {
port.device.value = port.packet[0]
enable_streaming(port)
//TODO: Upgrade mouse.
} else {
port.device.value = port.packet[1] | port.packet[0] << 8
enable_streaming(port)
}
log.info("Identified device!")
log.print(port.device.value, .{radix: 16})
} else {
log.info("KEY PRESSED")
}
}
check_complete := fn(port: ^controller.Port): bool {
last_value := port.packet[port.packet_length - 1]
if port.device == devices.NO_DEVICE {
if last_value == 0 | last_value == 3 | last_value == 4 {
return true
} else if port.packet_length == 2 {
return true
}
} else if port.device == devices.MOUSE_3_BUTTON {
if port.packet_length == 3 return true
} else if port.device == devices.MOUSE_SCROLLWHEEL | port.device == devices.MOUSE_5_BUTTON {
if port.packet_length == 4 return true
} else {
if port.packet[0] == 0xE1 {
if port.packet_length == 6 {
return true
}
} else if port.packet[0] != 0xE0 {
return true
} else if port.packet_length == 2 & port.packet[1] != 0x2A & port.packet[1] != 0xB7 {
return true
} else if port.packet_length == 4 {
return true
}
}
return false
}
main := fn(): void {
mouse_buffer = buffer.create("PS/2 Mouse")
controller.init()
if controller.port1.exists {
//log.info("Port 1 exists.")
controller.send_byte(@bitcast(0), 0xF4)
}
if controller.port2.exists {
//controller.send_byte(&controller.port2, 0xF4)
}
loop {
info = controller.get_info()
if controller.timed_out(info) {
log.error("Timeout error! Cannot handle these!")
}
if controller.check_parity(info) {
log.error("Parity error! Cannot handle these!")
}
/*
if controller.has_input(info) {
port := controller.get_port(info)
if port.packet_length > 0 & check_complete(port) {
process(port)
}
input := controller.get_input()
/*if input == 0xAA & port.can_hot_plug {
port.device = devices.NO_DEVICE
controller.send_byte(port, 0xF4)
}*/
port.packet[port.packet_length] = input
port.packet_length += 1
if check_complete(port) {
process(port)
port.packet_length = 0
}
}*/
}
}

View file

@ -0,0 +1,21 @@
Button := struct {id: u8}
$LEFT_BUTTON := Button.(1)
$RIGHT_BUTTON := Button.(2)
$MIDDLE_BUTTON := Button.(4)
$BUTTON4 := Button.(8)
$BUTTON5 := Button.(16)
SampleRate := struct {value: u8}
$SR10 := SampleRate.(10)
$SR20 := SampleRate.(20)
$SR40 := SampleRate.(40)
$SR60 := SampleRate.(60)
$SR80 := SampleRate.(80)
$SR100 := SampleRate.(100)
$SR200 := SampleRate.(200)
Resolution := struct {value: u8}
$RES_1COUNT_PER_MM := Resolution.(0)
$RES_2COUNT_PER_MM := Resolution.(1)
$RES_4COUNT_PER_MM := Resolution.(2)
$RES_8COUNT_PER_MM := Resolution.(3)

View file

@ -0,0 +1,21 @@
.{DeviceID, NO_DEVICE} := @use("devices.hb")
State := struct {s: u8}
$Recive := State.(0)
$Reboot := State.(1)
Port := packed struct {
exists: bool,
device: DeviceID,
packet: [8]u8,
packet_length: u8,
can_hot_plug: bool,
}
$PORT_AT_STARTUP := Port.(
true,
NO_DEVICE,
.[0, 0, 0, 0, 0, 0, 0, 0],
0,
true,
)

View file

@ -1,3 +0,0 @@
# PS/2 Driver
This program is a simple driver to read keypresses from a PS/2 Keyboard Also will contain an abstraction for the PS/2 controller in general so the Mouse code will probably also live here...maybe

View file

@ -1,11 +0,0 @@
[package]
name = "ps2_keyboard_driver"
authors = ["Talha Qamar"]
[dependants.libraries]
[dependants.binaries]
hblang.version = "1.0.0"
[build]
command = "hblang src/main.hb"

View file

@ -1,40 +0,0 @@
stn := @use("../../../libraries/stn/src/lib.hb");
.{memory, log, buffer} := stn
intouch := @use("../../../libraries/intouch/src/lib.hb");
.{KeyEvent} := intouch
send_byte := fn(byte: u8): u8 {
memory.outb(96, byte)
return memory.inb(96)
}
main := fn(): int {
buf := buffer.create("PS/2 Keyboard\0")
_ = send_byte(238)
log.info("PS/2 Driver Loaded\0")
if send_byte(238) == 238 {
log.info("PS/2 Keyboard Echoed\0")
}
if send_byte(244) == 250 {
log.info("Enabled scanning\0")
}
prev_input := 250
loop {
loop if (memory.inb(0x64) & 0x20) == 0x20 break
input := memory.inb(96)
if input == prev_input {
continue
}
prev_input = input
kevent := KeyEvent.(false, true, input)
buffer.write(KeyEvent, buf, &kevent)
}
return 0
}

View file

@ -1,7 +1,7 @@
.{memory, buffer, log, string, math} := @use("../../../libraries/stn/src/lib.hb")
.{memory, buffer, log, string, math} := @use("stn")
Vec2 := math.Vec2
intouch := @use("../../../libraries/intouch/src/lib.hb");
intouch := @use("lib:intouch");
.{MouseEvent} := intouch.events
i9 := packed struct {sign: bool, value: u8}
@ -21,7 +21,7 @@ reset_mouse := fn(): void {
@inline(send_byte, 0x64, 0xD4)
@inline(send_byte, 0x60, 0xFF)
loop if memory.inb(0x60) == 0xAA {
log.info("Self check passed.\0")
log.info("Self check passed.")
return
}
}
@ -82,11 +82,11 @@ set_up_mouse := fn(): void {
button_states := @as(u8, 0)
main := fn(): int {
mouse_buffer := buffer.create("PS/2 Mouse\0")
mouse_buffer := buffer.create("PS/2 Mouse")
format_page := memory.alloc(u8, 1024)
send_byte(0x64, 0xA8)
log.info("Aux mouse device enabled.\0")
log.info("Aux mouse device enabled.")
set_up_mouse()
@ -102,7 +102,7 @@ main := fn(): int {
if status == 0xAA {
loop if memory.inb(0x60) == 0 break
log.info("Mouse plugged in!\0")
log.info("Mouse plugged in!")
set_up_mouse()
continue
}

View file

@ -1,4 +1,4 @@
stn := @use("../../../libraries/stn/src/lib.hb")
stn := @use("stn")
main := fn(): int {
stn.log.info("\r
@ -9,7 +9,7 @@ main := fn(): int {
| : '=.:.=' : |\r
| : :'.___.': : |\r
'-:__:__:__:__:-'\r
\0")
")
return 0
}

View file

@ -1,4 +1,4 @@
render := @use("../../../../libraries/render/src/lib.hb")
render := @use("lib:render")
/* expected result:
the impostor travels left and loops around the screen */
@ -7,13 +7,13 @@ example := fn(): void {
screen := render.init(true)
x := 0
loop {
render.put_rect(screen, .(200 - x, 80), .(430, 380), render.red)
render.put_rect(screen, .(630 - x, 120), .(120, 300), render.red)
render.put_rect(screen, .(200 - x, 460), .(160, 270), render.red)
render.put_rect(screen, .(470 - x, 460), .(160, 270), render.red)
render.put_rect(screen, .(140 - x, 140), .(340, 250), render.cyan)
render.sync(screen)
render.clear(screen, render.black)
screen.clear(render.BLACK)
screen.put_rect(.(200 - x, 80), .(430, 380), render.RED)
screen.put_rect(.(630 - x, 120), .(120, 300), render.RED)
screen.put_rect(.(200 - x, 460), .(160, 270), render.RED)
screen.put_rect(.(470 - x, 460), .(160, 270), render.RED)
screen.put_rect(.(140 - x, 140), .(340, 250), render.CYAN)
screen.sync()
x += 1
}
return

View file

@ -1,4 +1,4 @@
render := @use("../../../../libraries/render/src/lib.hb")
render := @use("lib:render")
/* expected result:
the screen fades from cyan to green
@ -7,12 +7,11 @@ render := @use("../../../../libraries/render/src/lib.hb")
example := fn(): void {
screen := render.init(true)
color := render.light_cyan
color := render.LIGHT_CYAN
n := @as(u8, 1)
loop {
// ! dead code elimination bug
render.clear(screen, color)
render.sync(screen)
screen.clear(color)
screen.sync()
if color.b == 255 | color.b == 0 {
n = -n
}

View file

@ -1,25 +1,25 @@
.{log, math, string} := @use("../../../../libraries/stn/src/lib.hb")
render := @use("../../../../libraries/render/src/lib.hb")
.{log, math, string} := @use("stn")
render := @use("lib:render")
/* expected result:
a cute qoi image and a cute bmp image */
example := fn(): void {
screen := render.init(true)
image_qoi := render.image.from(@bitcast(&@embed("../../../../assets/mini.qoi")))
image_bmp := render.image.from(@bitcast(&@embed("../../../../assets/mini.bmp")))
image_qoi := render.image.from(@bitcast(&@embed("sysdata:assets/mini.qoi")))
image_bmp := render.image.from(@bitcast(&@embed("sysdata:assets/mini.bmp")))
if image_qoi == null | image_bmp == null {
log.error("failed to load images for whatever reason\0")
log.error("failed to load images for whatever reason")
return
}
t := 0.0
loop {
render.clear(screen, render.black)
render.put_surface(screen, image_bmp, .(@bitcast(@fti(math.cos(t) * 100.0)) + (screen.width - image_bmp.width * 3) / 2, (screen.height - image_bmp.height) / 2), false)
render.put_surface(screen, image_qoi, .((screen.width + image_qoi.width) / 2, @bitcast(@fti(math.sin(t) * 100.0)) + (screen.height - image_qoi.height) / 2), false)
render.sync(screen)
screen.clear(render.BLACK)
screen.put_surface(image_bmp, .(@bitcast(@fti(math.cos(t) * 100.0)) + (screen.width - image_bmp.width * 3) / 2, (screen.height - image_bmp.height) / 2), false)
screen.put_surface(image_qoi, .((screen.width + image_qoi.width) / 2, @bitcast(@fti(math.sin(t) * 100.0)) + (screen.height - image_qoi.height) / 2), false)
screen.sync()
t += 0.02
}
return

View file

@ -1,5 +1,5 @@
.{Vec2} := @use("../../../../libraries/stn/src/lib.hb").math
render := @use("../../../../libraries/render/src/lib.hb")
.{Vec2} := @use("stn:math")
render := @use("lib:render")
/* expected result:
a 3d-looking set of blue lines
@ -7,15 +7,15 @@ render := @use("../../../../libraries/render/src/lib.hb")
example := fn(): void {
screen := render.init(true)
render.clear(screen, .(100, 50, 0, 255))
screen.clear(.(100, 50, 0, 255))
p0 := Vec2(uint).(0, 0)
p1 := Vec2(uint).(0, screen.height)
loop if p0.y >= screen.height break else {
render.put_line(screen, p0, p1, .(255, 180, 100, 255))
render.put_line(screen, .(screen.width, screen.height) - p0, .(screen.width, screen.height) - p1, .(255, 180, 100, 255))
screen.put_line(p0, p1, .(255, 180, 100, 255))
screen.put_line(.(screen.width, screen.height) - p0, .(screen.width, screen.height) - p1, .(255, 180, 100, 255))
p0.y += screen.height >> 6
p1.x += screen.width >> 6
}
render.sync(screen)
screen.sync()
return
}

View file

@ -0,0 +1,98 @@
render := @use("lib:render")
sunset := @use("lib:sunset_proto");
.{math, log} := @use("stn")
// full mandelbrot
$X_MIN := -2.0
$X_MAX := 0.47
$Y_MIN := -1.12
$Y_MAX := 1.12
// a minibrot
// $X_MIN := -0.94
// $X_MAX := -0.93
// $Y_MIN := 0.31
// $Y_MAX := 0.306
// zoom into that weird curve part of the main cardioid
// $X_MIN := 0.25
// $X_MAX := 0.34
// $Y_MIN := -0.075
// $Y_MAX := 0.075
$MAX_ITERATION := 300
$USE_SUNSET := true
palette := render.Color.[.(50, 0, 60, 0), .(93, 0, 157, 0), .(140, 98, 229, 0), .(191, 190, 255, 0), .(226, 234, 255, 0), .(242, 250, 255, 0), .(226, 234, 255, 0), .(191, 190, 255, 0), .(140, 98, 229, 0), .(93, 0, 157, 0), .(50, 0, 60, 0)]
$LEN_PALETTE := @sizeof(@TypeOf(palette)) / @sizeof(render.Color)
example := fn(): void {
screen := @as(render.Surface, idk)
window := @as(?sunset.Window, null)
if USE_SUNSET {
sunset.client.find_server()
window = sunset.client.new(.(.(450, 140), .(400, 400), "Mandelbrot Set"))
if window == null {
log.error("got no window")
return
}
screen = window.surface
} else {
screen = render.init(false)
}
x_scale := @as(f64, X_MAX - X_MIN) / @itf(@bitcast(screen.width))
y_scale := @as(f64, Y_MAX - Y_MIN) / @itf(@bitcast(screen.height))
py := 0
loop if py == screen.height break else {
px := 0
loop if px >= screen.width break else {
x0 := @as(f64, X_MIN) + @itf(@bitcast(px)) * x_scale
y0 := @as(f64, Y_MIN) + @itf(@bitcast(py)) * y_scale
q := (x0 - 0.25) * (x0 - 0.25) + y0 * y0
if q * (q + x0 - 0.25) <= 0.25 * y0 * y0 | (x0 + 1.0) * (x0 + 1.0) + y0 * y0 <= 0.0625 {
px += 1
continue
}
x := @as(f64, 0.0)
y := @as(f64, 0.0)
iteration := 0
// arbitrary, i cant tell the difference between 32 and 1 << 16
loop if x * x + y * y > 32.0 | iteration == MAX_ITERATION break else {
x_temp := x * x - y * y + x0
y = 2 * x * y + y0
x = x_temp
iteration += 1
}
if iteration < MAX_ITERATION {
log_zn := math.ln(f64, x * x + y * y) / 2
nu := math.ln(f64, log_zn / math.LN_2) / math.LN_2
smoothed := @as(f64, @itf(@bitcast(iteration + 1))) - nu
smoothed_int := @fti(smoothed)
normalised := smoothed - @itf(smoothed_int)
colour0 := palette[@bitcast(smoothed_int) % LEN_PALETTE]
colour1 := palette[@bitcast(smoothed_int + 1) % LEN_PALETTE]
colour := render.Color.{
r: @intcast(@fti(math.lerp(f64, @itf(colour0.r), @itf(colour1.r), normalised))),
g: @intcast(@fti(math.lerp(f64, @itf(colour0.g), @itf(colour1.g), normalised))),
b: @intcast(@fti(math.lerp(f64, @itf(colour0.b), @itf(colour1.b), normalised))),
a: 0,
}
screen.put_pixel(.(px, py), colour)
}
px += 1
}
py += 1
if USE_SUNSET {
_ = sunset.client.send_frame(window)
}
}
if USE_SUNSET loop {
_ = sunset.client.send_frame(window)
}
}

View file

@ -1,8 +1,8 @@
.{Vec2, sin, cos, PI} := @use("../../../../libraries/stn/src/lib.hb").math
render := @use("../../../../libraries/render/src/lib.hb")
.{Vec2, sin, cos, PI} := @use("stn:math")
render := @use("lib:render")
able_bmp := @embed("../../../../assets/able.bmp")
mini_bmp := @embed("../../../../assets/mini.bmp")
able_bmp := @embed("sysdata:assets/able.bmp")
mini_bmp := @embed("sysdata:assets/mini.bmp")
/* expected result:
two textured circles rotating
@ -22,12 +22,12 @@ example := fn(): void {
screen := render.init(true)
loop {
render.clear(screen, render.black)
render.put_filled_circle(screen, .(screen.width / 2, screen.height / 2), 128, render.light_yellow)
render.put_circle(screen, .(screen.width / 2, screen.height / 2), 256, render.light_blue)
render.put_textured_circle(screen, able, .(able.width / 2, able.height / 2), .(screen.width / 2 + @intcast(@fti(sin(angle) * 256)), screen.height / 2 + @intcast(@fti(cos(angle) * 256))), able.width / 2 - 1)
render.put_textured_circle(screen, mini, .(mini.width / 2, mini.height / 2), .(screen.width / 2 + @intcast(@fti(sin(angle + PI) * 256)), screen.height / 2 + @intcast(@fti(cos(angle + PI) * 256))), mini.width / 2 - 1)
render.sync(screen)
screen.clear(render.BLACK)
screen.put_filled_circle(.(screen.width / 2, screen.height / 2), 128, render.LIGHT_YELLOW)
screen.put_circle(.(screen.width / 2, screen.height / 2), 256, render.LIGHT_BLUE)
screen.put_textured_circle(able, .(able.width / 2, able.height / 2), .(screen.width / 2 + @intcast(@fti(sin(angle) * 256)), screen.height / 2 + @intcast(@fti(cos(angle) * 256))), able.width / 2 - 1)
screen.put_textured_circle(mini, .(mini.width / 2, mini.height / 2), .(screen.width / 2 + @intcast(@fti(sin(angle + PI) * 256)), screen.height / 2 + @intcast(@fti(cos(angle + PI) * 256))), mini.width / 2 - 1)
screen.sync()
angle += 0.01
}

View file

@ -0,0 +1,51 @@
math := @use("stn:math")
render := @use("lib:render")
/* expected result:
red tangent graph
*/
$f := fn(x: uint): int {
x_f := @as(f32, @itf(@bitcast(x)))
y_f := math.tan(x_f * 0.03) * 20
return @fti(y_f)
}
y_asymptote := fn(screen: render.Surface, x: uint): void {
y := 0
loop if y >= screen.height break else {
screen.put_pixel(.(x, y), render.GRAY)
y += 4
}
}
example := fn(): void {
screen := render.init(false)
x := 0
height := @as(int, @bitcast(screen.height))
width := @as(int, @bitcast(screen.width))
screen.put_hline(screen.height / 2, 0, screen.width, render.LIGHT_GRAY)
loop if x >= screen.width break else {
y1 := height / 2 - f(x)
y2 := height / 2 - f(x + 1)
if y1 > height y1 = height else if y1 < 0 {
y_asymptote(screen, x)
x += 1
continue
}
if y2 > height {
y_asymptote(screen, x)
x += 1
continue
} else if y2 < 0 y2 = 0
if math.abs(int, y2 - y1) > 1 {
screen.put_vline(x, @bitcast(y1), @bitcast(y2), render.RED)
} else {
screen.put_pixel(.(x, @bitcast(y1)), render.RED)
screen.put_pixel(.(x, @bitcast(y2)), render.RED)
}
x += 1
}
}

View file

@ -1,16 +1,16 @@
.{random} := @use("../../../../libraries/stn/src/lib.hb")
render := @use("../../../../libraries/render/src/lib.hb")
.{random} := @use("stn")
render := @use("lib:render")
example := fn(): void {
screen := render.init(false)
render.clear(screen, render.black)
screen.clear(render.BLACK)
loop {
x := random.range(uint, 0, screen.width)
y := random.range(uint, 0, screen.height)
r := random.range(u8, 0, 255)
g := random.range(u8, 0, 75)
b := random.range(u8, 0, 155)
render.put_pixel(screen, .(x, y), .(b, g, r, 255))
screen.put_pixel(.(x, y), .(b, g, r, 255))
}
return
}

Some files were not shown because too many files have changed in this diff Show more