Added assembler

- its a bit cursed, prolly broken, but at least something
This commit is contained in:
Erin 2023-10-22 15:08:45 +02:00 committed by ondra05
parent c8371c0532
commit 5cbd032fe4
12 changed files with 792 additions and 11 deletions

312
Cargo.lock generated
View file

@ -17,6 +17,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "argh" name = "argh"
version = "0.1.12" version = "0.1.12"
@ -48,6 +57,12 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.69" version = "0.3.69"
@ -69,6 +84,16 @@ version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "bstr"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019"
dependencies = [
"memchr",
"serde",
]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.83" version = "1.0.83"
@ -111,6 +136,22 @@ dependencies = [
"tracing-error", "tracing-error",
] ]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "errno"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
dependencies = [
"libc",
"windows-sys",
]
[[package]] [[package]]
name = "eyre" name = "eyre"
version = "0.6.8" version = "0.6.8"
@ -127,6 +168,15 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "hbasm"
version = "0.1.0"
dependencies = [
"mlua",
"paste",
"with_builtin_macros",
]
[[package]] [[package]]
name = "hbbytecode" name = "hbbytecode"
version = "0.1.0" version = "0.1.0"
@ -149,12 +199,30 @@ dependencies = [
"nix", "nix",
] ]
[[package]]
name = "home"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
dependencies = [
"windows-sys",
]
[[package]] [[package]]
name = "indenter" name = "indenter"
version = "0.3.3" version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]]
name = "itertools"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@ -167,6 +235,31 @@ version = "0.2.149"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
[[package]]
name = "linux-raw-sys"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
[[package]]
name = "lua-src"
version = "546.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c26d4af78361e025a3d03a2b964cd1592aff7495f4d4f7947218c084c6fdca8"
dependencies = [
"cc",
]
[[package]]
name = "luajit-src"
version = "210.4.8+resty107baaf"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05167e8b2a2185758d83ed23541e5bd8bce37072e4204e0ef2c9b322bc87c4e"
dependencies = [
"cc",
"which",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.6.4" version = "2.6.4"
@ -182,6 +275,48 @@ dependencies = [
"adler", "adler",
] ]
[[package]]
name = "mlua"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c3a7a7ff4481ec91b951a733390211a8ace1caba57266ccb5f4d4966704e560"
dependencies = [
"bstr",
"mlua-sys",
"mlua_derive",
"num-traits",
"once_cell",
"rustc-hash",
]
[[package]]
name = "mlua-sys"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ec8b54eddb76093069cce9eeffb4c7b3a1a0fe66962d7bd44c4867928149ca3"
dependencies = [
"cc",
"cfg-if",
"lua-src",
"luajit-src",
"pkg-config",
]
[[package]]
name = "mlua_derive"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f359220f24e6452dd82a3f50d7242d4aab822b5594798048e953d7a9e0314c6"
dependencies = [
"itertools",
"once_cell",
"proc-macro-error",
"proc-macro2",
"quote",
"regex",
"syn 2.0.38",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.27.1" version = "0.27.1"
@ -193,6 +328,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "object" name = "object"
version = "0.32.1" version = "0.32.1"
@ -214,12 +358,48 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.13" version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "pkg-config"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.69" version = "1.0.69"
@ -238,12 +418,60 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]] [[package]]
name = "rustc-demangle" name = "rustc-demangle"
version = "0.1.23" version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.189" version = "1.0.189"
@ -358,6 +586,90 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "with_builtin_macros" name = "with_builtin_macros"
version = "0.0.3" version = "0.0.3"

View file

@ -1,3 +1,3 @@
[workspace] [workspace]
resolver = "2" resolver = "2"
members = ["hbbytecode", "hbvm", "hbxrt", "xtask"] members = ["hbasm", "hbbytecode", "hbvm", "hbxrt", "xtask"]

12
hbasm/Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "hbasm"
version = "0.1.0"
edition = "2021"
[dependencies]
paste = "1.0"
with_builtin_macros = "0.0.3"
[dependencies.mlua]
version = "0.9"
features = ["luajit52", "macros", "vendored"]

3
hbasm/assets/exit.lua Normal file
View file

@ -0,0 +1,3 @@
li8(r1, 60)
li8(r2, 69)
eca()

8
hbasm/assets/label.lua Normal file
View file

@ -0,0 +1,8 @@
label "label" -- set named label
local a = label {} -- unassigned label
jmp16("label")
a:here() -- assign label
jmp16(a)
addi8(r3, r4, 5)

53
hbasm/src/arraylist.rs Normal file
View file

@ -0,0 +1,53 @@
use mlua::prelude::*;
#[derive(Clone, Debug, Default, FromLua)]
pub struct ArrayList<T>(pub Vec<T>);
impl<T> LuaUserData for ArrayList<T>
where
T: for<'lua> FromLua<'lua> + for<'lua> IntoLua<'lua> + Clone + std::fmt::Debug,
{
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(
LuaMetaMethod::Index,
|lua, this, index: LuaInteger| match this.0.get(
(index as usize)
.checked_sub(1)
.ok_or_else(|| mlua::Error::runtime("Invalid index: 0"))?,
) {
Some(i) => i.clone().into_lua(lua),
None => Ok(LuaValue::Nil),
},
);
methods.add_meta_method_mut(
LuaMetaMethod::NewIndex,
|_, this, (index, val): (LuaInteger, T)| match this.0.get_mut(
(index as usize)
.checked_sub(1)
.ok_or_else(|| mlua::Error::runtime("Invalid index: 0"))?,
) {
Some(x) => {
*x = val;
Ok(())
}
None => Err(mlua::Error::runtime(format!(
"Index out of bounds: length = {}, index = {index}",
this.0.len()
))),
},
);
methods.add_meta_method(LuaMetaMethod::Len, |_, this, ()| Ok(this.0.len()));
methods.add_meta_method(LuaMetaMethod::ToString, |_, this, ()| {
Ok(format!("{this:?}"))
});
methods.add_method_mut("push", |_, this, val: T| {
this.0.push(val);
Ok(())
});
methods.add_method_mut("pop", |lua, this, ()| match this.0.pop() {
Some(val) => val.into_lua(lua),
None => Ok(LuaValue::Nil),
});
}
}

194
hbasm/src/ins.rs Normal file
View file

@ -0,0 +1,194 @@
use {
crate::arraylist::ArrayList,
mlua::{prelude::*, Result, Scope},
};
mod opsty {
pub type R = i8;
pub type B = i8;
pub type H = i16;
pub type W = i32;
pub type D = i64;
pub type A = i64;
pub type O<'lua> = super::LuaValue<'lua>;
pub type P<'lua> = super::LuaValue<'lua>;
}
macro_rules! gen_insert {
($($plain:ident),* $(,)?) => {
macro_rules! insert {
$(
($label:expr, $lua:expr, $symrt:expr, $code:expr, $plain) => {
$code.0.extend($label.to_le_bytes());
};
)*
($label:expr, $lua:expr, $symrt:expr, $code:expr, O) => {
insert_label_ref::<4>(
$label,
$lua,
&$symrt,
&mut $code.0,
)?;
};
($label:expr, $lua:expr, $symrt:expr, $code:expr, P) => {
insert_label_ref::<2>(
$label,
$lua,
&$symrt,
&mut $code.0,
)?;
};
}
};
}
gen_insert!(R, B, H, W, D, A);
macro_rules! generic_ins {
{
($lua:expr, $scope:expr);
$($name:ident($($param_i:ident : $param_ty:ident),*);)*
} => {{
let lua = $lua;
let scope = $scope;
let code = $lua.globals()
.get::<_, LuaTable>("_CODE")?
.get::<_, LuaAnyUserData>("text")?;
let symrt = $lua.globals()
.get::<_, LuaTable>("_SYM_REPLS")?;
lua.globals().set(
"_GENERIC",
lua.create_table_from([$((
stringify!($name),
#[allow(unused)]
{
let code = code.clone();
let symrt = symrt.clone();
scope.create_function_mut(move |lua, (opcode, $($param_i),*): (u8, $(opsty::$param_ty),*)| {
let mut code = code.borrow_mut::<ArrayList<u8>>()?;
code.0.push(opcode);
$(insert!($param_i, lua, symrt, code, $param_ty);)*
Ok(())
})?
}
)),*])?
)?;
}};
}
macro_rules! ins {
{
$lua:expr;
{$($opcode:expr, $mnemonic:ident, $ty:ident, $_doc:literal;)*}
} => {{
use std::fmt::Write;
let lua = $lua;
let mut code = String::new();
$({
paste::paste! {
let name = match stringify!([<$mnemonic:lower>]) {
"and" => "and_",
"or" => "or_",
"not" => "not_",
name => name,
};
}
writeln!(
code,
"function {name}(...) _GENERIC.{ty}({opcode}, ...) end",
ty = stringify!($ty).to_lowercase(),
opcode = $opcode,
).unwrap();
})*
lua.load(code).exec()?;
}};
}
pub fn setup<'lua, 'scope>(lua: &'lua Lua, scope: &Scope<'lua, 'scope>) -> Result<()>
where
'lua: 'scope,
{
generic_ins! {
(lua, scope);
rr (o0: R, o1: R);
rrr (o0: R, o1: R, o2: R);
rrrr(o0: R, o1: R, o2: R, o3: R);
rrb (o0: R, o1: R, o2: B);
rrh (o0: R, o1: R, o2: H);
rrw (o0: R, o1: R, o2: W);
rrd (o0: R, o1: R, o2: D);
rb (o0: R, o1: B);
rh (o0: R, o1: H);
rw (o0: R, o1: W);
rd (o0: R, o1: D);
rrah(o0: R, o1: R, o2: A, o3: H);
rroh(o0: R, o1: R, o2: O, o3: H);
rrph(o0: R, o1: R, o2: P, o3: H);
rro (o0: R, o1: R, o2: O);
rrp (o0: R, o1: R, r2: P);
o (o0: O);
p (o0: P);
n ();
}
with_builtin_macros::with_builtin! {
let $spec = include_from_root!("../hbbytecode/instructions.in") in {
ins!(lua; { $spec });
}
}
Ok(())
}
fn insert_label_ref<const SIZE: usize>(
label: LuaValue,
lua: &Lua,
symrt: &LuaTable,
code: &mut Vec<u8>,
) -> Result<()> {
match label {
LuaValue::Integer(offset) => {
if match SIZE {
2 => i16::try_from(offset).map(|o| code.extend(o.to_le_bytes())),
4 => i32::try_from(offset).map(|o| code.extend(o.to_le_bytes())),
s => {
return Err(mlua::Error::runtime(format!(
"Invalid offset size (expected 2 or 4 bytes, got {s})"
)));
}
}
.is_err()
{
return Err(mlua::Error::runtime("Failed to cast offset"));
}
return Ok(());
}
LuaValue::UserData(ud) => {
symrt.set(
code.len() + 1,
lua.create_table_from([("label", ud.get("id")?), ("size", SIZE)])?,
)?;
code.extend([0; SIZE]);
}
LuaValue::String(_) => {
symrt.set(
code.len() + 1,
lua.create_table_from([("label", label), ("size", SIZE.into_lua(lua)?)])?,
)?;
code.extend([0; SIZE]);
}
_ => return Err(mlua::Error::runtime("Invalid label type")),
}
Ok(())
}

91
hbasm/src/label.rs Normal file
View file

@ -0,0 +1,91 @@
use {
crate::{arraylist::ArrayList, Labels},
mlua::{Result, prelude::*},
};
#[derive(Clone, Copy, Debug, PartialEq, Eq, FromLua)]
pub struct UnassignedLabel(pub usize);
impl LuaUserData for UnassignedLabel {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("id", |_, this| Ok(this.0));
}
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_method("here", |lua, this, ()| {
match lua
.globals()
.get::<_, LuaUserDataRefMut<Labels>>("_LABELS")?
.0
.get_mut(
this.0
.checked_sub(1)
.ok_or_else(|| mlua::Error::runtime("Invalid label"))?,
) {
Some(entry) => {
*entry = Some(
lua.globals()
.get::<_, LuaTable>("_CODE")?
.get::<_, LuaUserDataRef<ArrayList<u8>>>("text")?
.0
.len(),
);
Ok(())
}
None => Err(mlua::Error::runtime("Invalid label")),
}
});
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, FromLua)]
pub struct Label(pub usize);
impl LuaUserData for Label {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("id", |_, this| Ok(this.0));
}
}
pub fn label<'lua>(lua: &'lua Lua, val: LuaValue<'lua>) -> Result<LuaValue<'lua>> {
let globals = lua.globals();
let mut labels = globals.get::<_, LuaUserDataRefMut<Labels>>("_LABELS")?;
let code_ix = globals
.get::<_, LuaTable>("_CODE")?
.get::<_, LuaUserDataRefMut<ArrayList<u8>>>("text")?
.0
.len();
match val {
LuaValue::Table(_) => {
labels.0.push(None);
Ok(LuaValue::UserData(
lua.create_userdata(UnassignedLabel(labels.0.len()))?,
))
}
LuaValue::String(str) => {
labels.0.push(Some(code_ix + 1));
globals
.get::<_, LuaTable>("_SYM_TABLE")?
.set(str, labels.0.len())?;
Ok(LuaValue::UserData(
lua.create_userdata(Label(labels.0.len()))?,
))
}
LuaNil => {
labels.0.push(Some(code_ix + 1));
Ok(LuaValue::UserData(
lua.create_userdata(Label(labels.0.len()))?,
))
}
_ => Err(mlua::Error::BadArgument {
to: Some("label".into()),
pos: 1,
name: None,
cause: std::sync::Arc::new(mlua::Error::runtime(
"Unsupported type (nil and string are only supported)",
)),
}),
}
}

44
hbasm/src/linker.rs Normal file
View file

@ -0,0 +1,44 @@
use mlua::prelude::*;
pub fn link(
symrt: LuaTable,
symtab: LuaTable,
labels: &[Option<usize>],
code: &mut [u8],
out: &mut impl std::io::Write,
) -> mlua::Result<()> {
for item in symrt.pairs::<usize, LuaTable>() {
let (loc, val) = item?;
let size: usize = val.get("size")?;
let dest = labels
.get(
match val.get::<_, LuaValue>("label")? {
LuaValue::Integer(i) => i,
LuaValue::String(s) => symtab.get(s)?,
_ => {
return Err(mlua::Error::runtime(
"Invalid symbol type (int or string expected)",
))
}
} as usize
- 1,
)
.copied()
.flatten()
.ok_or_else(|| mlua::Error::runtime("Invalid label"))?;
let loc = loc - 1;
let dest = dest - 1;
let offset = dest.wrapping_sub(loc);
match size {
4 => code[loc..loc + size].copy_from_slice(&(offset as u32).to_le_bytes()),
2 => code[loc..loc + size].copy_from_slice(&(offset as u16).to_le_bytes()),
_ => return Err(mlua::Error::runtime("Invalid symbol")),
}
}
dbg!(&code);
out.write_all(code)?;
Ok(())
}

54
hbasm/src/main.rs Normal file
View file

@ -0,0 +1,54 @@
mod arraylist;
mod ins;
mod label;
mod linker;
use {arraylist::ArrayList, mlua::{Result, prelude::*}, std::io::Read};
pub type Labels = ArrayList<Option<usize>>;
fn main() -> Result<()> {
let mut code = vec![];
std::io::stdin().read_to_end(&mut code)?;
let lua = Lua::new();
lua.scope(|scope| {
// Global values
let globals = lua.globals();
globals.set(
"_CODE",
lua.create_table_from([
("text", ArrayList::<u8>::default()),
("data", ArrayList::<u8>::default()),
])?,
)?;
globals.set("_LABELS", Labels::default())?;
globals.set("_SYM_TABLE", lua.create_table()?)?;
globals.set("_SYM_REPLS", lua.create_table()?)?;
// Functions
globals.set("label", lua.create_function(label::label)?)?;
ins::setup(&lua, scope)?;
// Register symbols
for n in 0..255 {
globals.set(format!("r{n}"), n)?;
}
lua.load(code).exec()?;
linker::link(
globals.get("_SYM_REPLS")?,
globals.get("_SYM_TABLE")?,
&globals.get::<_, Labels>("_LABELS")?.0,
&mut globals
.get::<_, LuaTable>("_CODE")?
.get::<_, LuaUserDataRefMut<ArrayList<u8>>>("text")?
.0,
&mut std::io::stdout(),
)
})?;
Ok(())
}

View file

@ -39,6 +39,7 @@ define_items! {
OpsRW (OpR, OpW ), OpsRW (OpR, OpW ),
OpsRD (OpR, OpD ), OpsRD (OpR, OpD ),
OpsRRD (OpR, OpR, OpD ), OpsRRD (OpR, OpR, OpD ),
OpsRRA (OpR, OpR, OpA ),
OpsRRAH (OpR, OpR, OpA, OpH), OpsRRAH (OpR, OpR, OpA, OpH),
OpsRROH (OpR, OpR, OpO, OpH), OpsRROH (OpR, OpR, OpO, OpH),
OpsRRPH (OpR, OpR, OpP, OpH), OpsRRPH (OpR, OpR, OpP, OpH),

View file

@ -2,7 +2,7 @@
//! //!
//! Have fun //! Have fun
use hbbytecode::RoundingMode; use hbbytecode::{OpsRRA, RoundingMode};
use crate::mem::addr::AddressOp; use crate::mem::addr::AddressOp;
@ -271,23 +271,29 @@ where
usize::from(count), usize::from(count),
); );
}), }),
JMP => handler!(self, |OpsO(off)| self.pc = self.pc.wrapping_add(off)), JMP => {
JAL => handler!(self, |OpsRRO(save, reg, offset)| { let OpsO(off) = self.decode();
self.pc = self.pc.wrapping_add(off);
}
JAL => {
// Jump and link. Save PC after this instruction to // Jump and link. Save PC after this instruction to
// specified register and jump to reg + relative offset. // specified register and jump to reg + relative offset.
let OpsRRO(save, reg, offset) = self.decode();
self.write_reg(save, self.pc.get()); self.write_reg(save, self.pc.get());
self.pc = self self.pc = self
.pcrel(offset, 3) .pcrel(offset, 3)
.wrapping_add(self.read_reg(reg).cast::<i64>()); .wrapping_add(self.read_reg(reg).cast::<i64>());
}), }
JALA => handler!(self, |OpsRRW(save, reg, offset)| { JALA => {
// Jump and link. Save PC after this instruction to // Jump and link. Save PC after this instruction to
// specified register and jump to reg // specified register and jump to reg
let OpsRRA(save, reg, offset) = self.decode();
self.write_reg(save, self.pc.get()); self.write_reg(save, self.pc.get());
self.pc = Address::new( self.pc =
self.read_reg(reg).cast::<u64>().wrapping_add(offset.into()), Address::new(self.read_reg(reg).cast::<u64>().wrapping_add(offset));
); }
}),
// Conditional jumps, jump only to immediates // Conditional jumps, jump only to immediates
JEQ => self.cond_jmp::<u64>(Ordering::Equal), JEQ => self.cond_jmp::<u64>(Ordering::Equal),
JNE => handler!(self, |OpsRRP(a0, a1, ja)| { JNE => handler!(self, |OpsRRP(a0, a1, ja)| {
@ -385,7 +391,10 @@ where
STR16 => handler!(self, |OpsRRPH(dst, base, off, count)| { STR16 => handler!(self, |OpsRRPH(dst, base, off, count)| {
self.store(dst, base, self.pcrel(off, 3).get(), count)?; self.store(dst, base, self.pcrel(off, 3).get(), count)?;
}), }),
JMP16 => handler!(self, |OpsP(off)| self.pc = self.pcrel(off, 1)), JMP16 => {
let OpsP(off) = self.decode();
self.pc = self.pcrel(off, 1);
}
op => return Err(VmRunError::InvalidOpcode(op)), op => return Err(VmRunError::InvalidOpcode(op)),
} }
} }