forked from koniifer/ableos
compiling return stmt
This commit is contained in:
parent
aa77a2f822
commit
68d53544fd
95
hblang/build.rs
Normal file
95
hblang/build.rs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#![feature(iter_next_chunk)]
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed=../hbbytecode/instructions.in");
|
||||||
|
|
||||||
|
let instructions = include_str!("../hbbytecode/instructions.in");
|
||||||
|
|
||||||
|
let mut generated = String::new();
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
|
writeln!(&mut generated, "impl crate::codegen::Func {{")?;
|
||||||
|
|
||||||
|
for line in instructions.lines() {
|
||||||
|
let line = line.strip_suffix(";").unwrap();
|
||||||
|
let [opcode, name, ty, doc] = line.splitn(4, ',').map(str::trim).next_chunk().unwrap();
|
||||||
|
|
||||||
|
writeln!(&mut generated, "/// {}", doc.trim_matches('"'))?;
|
||||||
|
write!(&mut generated, "pub fn {}(&mut self", name.to_lowercase())?;
|
||||||
|
for (i, c) in ty.chars().enumerate() {
|
||||||
|
let (name, ty) = match c {
|
||||||
|
'N' => continue,
|
||||||
|
'R' => ("reg", "u8"),
|
||||||
|
'B' => ("imm", "u8"),
|
||||||
|
'H' => ("imm", "u16"),
|
||||||
|
'W' => ("imm", "u32"),
|
||||||
|
'D' => ("imm", "u64"),
|
||||||
|
'P' => ("offset", "u32"),
|
||||||
|
'O' => ("offset", "u32"),
|
||||||
|
'A' => ("addr", "u64"),
|
||||||
|
_ => panic!("unknown type: {}", c),
|
||||||
|
};
|
||||||
|
write!(&mut generated, ", {name}{i}: {ty}")?;
|
||||||
|
}
|
||||||
|
writeln!(&mut generated, ") {{")?;
|
||||||
|
|
||||||
|
let mut offset = 1;
|
||||||
|
for (i, c) in ty.chars().enumerate() {
|
||||||
|
let width = match c {
|
||||||
|
'N' => 0,
|
||||||
|
'R' => 1,
|
||||||
|
'B' => 1,
|
||||||
|
'H' => 2,
|
||||||
|
'W' => 4,
|
||||||
|
'D' => 8,
|
||||||
|
'A' => 8,
|
||||||
|
'P' => 2,
|
||||||
|
'O' => 4,
|
||||||
|
_ => panic!("unknown type: {}", c),
|
||||||
|
};
|
||||||
|
|
||||||
|
if matches!(c, 'P' | 'O') {
|
||||||
|
writeln!(
|
||||||
|
&mut generated,
|
||||||
|
" self.offset(offset{i}, {offset}, {width});",
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += width;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(
|
||||||
|
&mut generated,
|
||||||
|
" self.extend(crate::as_bytes(&crate::Args({opcode}"
|
||||||
|
)?;
|
||||||
|
for (i, c) in ty.chars().enumerate() {
|
||||||
|
let name = match c {
|
||||||
|
'N' => continue,
|
||||||
|
'R' => "reg",
|
||||||
|
'B' | 'H' | 'W' | 'D' => "imm",
|
||||||
|
'P' => "0u16",
|
||||||
|
'O' => "0u32",
|
||||||
|
'A' => "addr",
|
||||||
|
_ => panic!("unknown type: {}", c),
|
||||||
|
};
|
||||||
|
|
||||||
|
if matches!(c, 'P' | 'O') {
|
||||||
|
write!(&mut generated, ", {name}")?;
|
||||||
|
} else {
|
||||||
|
write!(&mut generated, ", {name}{i}")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _ in ty.len() - (ty == "N") as usize..4 {
|
||||||
|
write!(&mut generated, ", ()")?;
|
||||||
|
}
|
||||||
|
writeln!(&mut generated, ")));")?;
|
||||||
|
|
||||||
|
writeln!(&mut generated, "}}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(&mut generated, "}}")?;
|
||||||
|
|
||||||
|
std::fs::write("src/instrs.rs", generated)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
main := ||: void {
|
main := ||: int {
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
use {crate::parser, std::fmt::Write};
|
use {
|
||||||
|
crate::parser::{self, Expr},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
type LabelId = u32;
|
||||||
type Reg = u8;
|
type Reg = u8;
|
||||||
type MaskElem = u64;
|
type MaskElem = u64;
|
||||||
|
|
||||||
|
@ -8,25 +12,102 @@ const ZERO: Reg = 0;
|
||||||
const RET_ADDR: Reg = 31;
|
const RET_ADDR: Reg = 31;
|
||||||
const ELEM_WIDTH: usize = std::mem::size_of::<MaskElem>() * 8;
|
const ELEM_WIDTH: usize = std::mem::size_of::<MaskElem>() * 8;
|
||||||
|
|
||||||
|
struct Frame {
|
||||||
|
label: LabelId,
|
||||||
|
prev_relocs: usize,
|
||||||
|
offset: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Reloc {
|
||||||
|
id: LabelId,
|
||||||
|
offset: u32,
|
||||||
|
size: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Func {
|
||||||
|
code: Vec<u8>,
|
||||||
|
relocs: Vec<Reloc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Func {
|
||||||
|
pub fn extend(&mut self, bytes: &[u8]) {
|
||||||
|
self.code.extend_from_slice(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset(&mut self, id: LabelId, offset: u32, size: u16) {
|
||||||
|
self.relocs.push(Reloc {
|
||||||
|
id,
|
||||||
|
offset: self.code.len() as u32 + offset,
|
||||||
|
size,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, value: Reg, size: usize) {
|
||||||
|
self.st(value, STACK_PTR, 0, size as _);
|
||||||
|
self.addi64(STACK_PTR, STACK_PTR, size as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self, value: Reg, size: usize) {
|
||||||
|
self.addi64(STACK_PTR, STACK_PTR, (size as u64).wrapping_neg());
|
||||||
|
self.ld(value, STACK_PTR, 0, size as _);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, func: LabelId) {
|
||||||
|
self.jal(RET_ADDR, ZERO, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ret(&mut self) {
|
||||||
|
self.jala(ZERO, RET_ADDR, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prelude(&mut self, entry: LabelId) {
|
||||||
|
self.call(entry);
|
||||||
|
self.tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn relocate(&mut self, labels: &[Label], shift: i64) {
|
||||||
|
for reloc in self.relocs.drain(..) {
|
||||||
|
let label = &labels[reloc.id as usize];
|
||||||
|
let offset = if reloc.size == 8 {
|
||||||
|
reloc.offset as i64
|
||||||
|
} else {
|
||||||
|
label.offset as i64 - reloc.offset as i64
|
||||||
|
} + shift;
|
||||||
|
|
||||||
|
let dest = &mut self.code[reloc.offset as usize..][..reloc.size as usize];
|
||||||
|
match reloc.size {
|
||||||
|
2 => dest.copy_from_slice(&(offset as i16).to_le_bytes()),
|
||||||
|
4 => dest.copy_from_slice(&(offset as i32).to_le_bytes()),
|
||||||
|
8 => dest.copy_from_slice(&(offset as i64).to_le_bytes()),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RegAlloc {
|
pub struct RegAlloc {
|
||||||
free: Vec<Reg>,
|
free: Vec<Reg>,
|
||||||
// TODO:use 256 bit mask instead
|
// TODO:use 256 bit mask instead
|
||||||
used: Vec<std::cmp::Reverse<Reg>>,
|
used: Vec<Reg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegAlloc {
|
impl RegAlloc {
|
||||||
fn callee_general_purpose() -> Self {
|
fn init_caller(&mut self) {
|
||||||
Self {
|
self.clear();
|
||||||
free: (32..=253).collect(),
|
self.free.extend(1..=31);
|
||||||
used: Vec::new(),
|
}
|
||||||
}
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.free.clear();
|
||||||
|
self.used.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate(&mut self) -> Reg {
|
fn allocate(&mut self) -> Reg {
|
||||||
let reg = self.free.pop().expect("TODO: we need to spill");
|
let reg = self.free.pop().expect("TODO: we need to spill");
|
||||||
if self.used.binary_search(&std::cmp::Reverse(reg)).is_err() {
|
if self.used.binary_search_by_key(&!reg, |&r| !r).is_err() {
|
||||||
self.used.push(std::cmp::Reverse(reg));
|
self.used.push(reg);
|
||||||
}
|
}
|
||||||
reg
|
reg
|
||||||
}
|
}
|
||||||
|
@ -36,129 +117,171 @@ impl RegAlloc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Label {
|
||||||
|
offset: u32,
|
||||||
|
// TODO: use different stile of identifier that does not allocate, eg. index + length into a
|
||||||
|
// file
|
||||||
|
name: Rc<str>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Codegen<'a> {
|
pub struct Codegen<'a> {
|
||||||
path: &'a std::path::Path,
|
path: &'a std::path::Path,
|
||||||
gpa: RegAlloc,
|
ret: Expr<'a>,
|
||||||
code: String,
|
gpa: RegAlloc,
|
||||||
data: String,
|
code: Func,
|
||||||
prelude_buf: String,
|
temp: Func,
|
||||||
|
labels: Vec<Label>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Codegen<'a> {
|
impl<'a> Codegen<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
path: std::path::Path::new(""),
|
path: std::path::Path::new(""),
|
||||||
gpa: RegAlloc::callee_general_purpose(),
|
ret: Expr::Return { val: None },
|
||||||
code: String::new(),
|
gpa: Default::default(),
|
||||||
data: String::new(),
|
code: Default::default(),
|
||||||
prelude_buf: String::new(),
|
temp: Default::default(),
|
||||||
|
labels: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file(&mut self, path: &'a std::path::Path, exprs: &[parser::Expr]) -> std::fmt::Result {
|
pub fn file(
|
||||||
|
&mut self,
|
||||||
|
path: &'a std::path::Path,
|
||||||
|
exprs: &'a [parser::Expr<'a>],
|
||||||
|
) -> std::fmt::Result {
|
||||||
self.path = path;
|
self.path = path;
|
||||||
for expr in exprs {
|
for expr in exprs {
|
||||||
self.expr(expr)?;
|
self.expr(expr, None);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr(&mut self, expr: &parser::Expr) -> std::fmt::Result {
|
fn expr(&mut self, expr: &'a parser::Expr<'a>, expeted: Option<Expr<'a>>) -> Option<Value<'a>> {
|
||||||
use parser::Expr as E;
|
use parser::Expr as E;
|
||||||
match *expr {
|
match *expr {
|
||||||
E::Decl {
|
E::Decl {
|
||||||
name,
|
name,
|
||||||
val:
|
val: E::Closure { ret, body },
|
||||||
E::Closure {
|
|
||||||
ret: E::Ident { name: "void" },
|
|
||||||
body,
|
|
||||||
},
|
|
||||||
} => {
|
} => {
|
||||||
writeln!(self.code, "{name}:")?;
|
let frame = self.add_label(name);
|
||||||
let fn_start = self.code.len();
|
self.ret = **ret;
|
||||||
self.expr(body)?;
|
self.expr(body, None);
|
||||||
self.write_fn_prelude(fn_start)
|
self.write_fn_prelude(frame);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
E::Return { val } => {
|
||||||
|
if let Some(val) = val {
|
||||||
|
let val = self.expr(val, Some(self.ret)).unwrap();
|
||||||
|
if val.ty != self.ret {
|
||||||
|
panic!("expected {:?}, got {:?}", self.ret, val.ty);
|
||||||
|
}
|
||||||
|
match val.loc {
|
||||||
|
Loc::Reg(reg) => self.code.cp(1, reg),
|
||||||
|
Loc::Imm(imm) => self.code.li64(1, imm),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.ret();
|
||||||
|
None
|
||||||
}
|
}
|
||||||
E::Return { val: None } => self.ret(),
|
|
||||||
E::Block { stmts } => {
|
E::Block { stmts } => {
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
self.expr(stmt)?;
|
self.expr(stmt, None);
|
||||||
}
|
}
|
||||||
Ok(())
|
None
|
||||||
}
|
}
|
||||||
|
E::Number { value } => Some(Value {
|
||||||
|
ty: expeted.unwrap_or(Expr::Ident { name: "int" }),
|
||||||
|
loc: Loc::Imm(value),
|
||||||
|
}),
|
||||||
ast => unimplemented!("{:?}", ast),
|
ast => unimplemented!("{:?}", ast),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_fn_prelude(&mut self, fn_start: usize) -> std::fmt::Result {
|
fn get_or_reserve_label(&mut self, name: &str) -> LabelId {
|
||||||
self.prelude_buf.clear();
|
if let Some(label) = self.labels.iter().position(|l| l.name.as_ref() == name) {
|
||||||
// TODO: avoid clone here
|
label as u32
|
||||||
for reg in self.gpa.used.clone().iter() {
|
} else {
|
||||||
stack_push(&mut self.prelude_buf, reg.0, 8)?;
|
self.labels.push(Label {
|
||||||
|
offset: 0,
|
||||||
|
name: name.into(),
|
||||||
|
});
|
||||||
|
self.labels.len() as u32 - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
self.code.insert_str(fn_start, &self.prelude_buf);
|
|
||||||
self.gpa = RegAlloc::callee_general_purpose();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ret(&mut self) -> std::fmt::Result {
|
fn add_label(&mut self, name: &str) -> Frame {
|
||||||
|
let offset = self.code.code.len() as u32;
|
||||||
|
let label = if let Some(label) = self.labels.iter().position(|l| l.name.as_ref() == name) {
|
||||||
|
self.labels[label].offset = offset;
|
||||||
|
label as u32
|
||||||
|
} else {
|
||||||
|
self.labels.push(Label {
|
||||||
|
offset,
|
||||||
|
name: name.into(),
|
||||||
|
});
|
||||||
|
self.labels.len() as u32 - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
Frame {
|
||||||
|
label,
|
||||||
|
prev_relocs: self.code.relocs.len(),
|
||||||
|
offset,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_label(&self, name: &str) -> LabelId {
|
||||||
|
self.labels
|
||||||
|
.iter()
|
||||||
|
.position(|l| l.name.as_ref() == name)
|
||||||
|
.unwrap() as _
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_fn_prelude(&mut self, frame: Frame) {
|
||||||
|
for ® in self.gpa.used.clone().iter() {
|
||||||
|
self.temp.push(reg, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
for reloc in &mut self.code.relocs[frame.prev_relocs..] {
|
||||||
|
reloc.offset += self.temp.code.len() as u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.code.code.splice(
|
||||||
|
frame.offset as usize..frame.offset as usize,
|
||||||
|
self.temp.code.drain(..),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ret(&mut self) {
|
||||||
for reg in self.gpa.used.clone().iter().rev() {
|
for reg in self.gpa.used.clone().iter().rev() {
|
||||||
stack_pop(&mut self.code, reg.0, 8)?;
|
self.code.pop(*reg, 8);
|
||||||
}
|
}
|
||||||
ret(&mut self.code)
|
self.code.ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(self, mut out: impl std::fmt::Write) -> std::fmt::Result {
|
pub fn dump(mut self, out: &mut impl std::io::Write) -> std::io::Result<()> {
|
||||||
prelude(&mut out)?;
|
self.temp.prelude(self.get_label("main"));
|
||||||
writeln!(out, "{}", self.code)?;
|
self.temp
|
||||||
writeln!(out, "{}", self.data)
|
.relocate(&self.labels, self.temp.code.len() as i64);
|
||||||
|
|
||||||
|
self.code.relocate(&self.labels, 0);
|
||||||
|
out.write_all(&self.temp.code)?;
|
||||||
|
out.write_all(&self.code.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stack_push(out: &mut impl std::fmt::Write, value: Reg, size: usize) -> std::fmt::Result {
|
pub struct Value<'a> {
|
||||||
writeln!(out, " st r{value}, r{STACK_PTR}, r{ZERO}, {size}")?;
|
ty: Expr<'a>,
|
||||||
writeln!(
|
loc: Loc,
|
||||||
out,
|
|
||||||
" addi{} r{STACK_PTR}, r{STACK_PTR}, {size}",
|
|
||||||
size * 8
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stack_pop(out: &mut impl std::fmt::Write, value: Reg, size: usize) -> std::fmt::Result {
|
pub enum Loc {
|
||||||
writeln!(
|
Reg(Reg),
|
||||||
out,
|
Imm(u64),
|
||||||
" subi{} r{STACK_PTR}, r{STACK_PTR}, {size}",
|
|
||||||
size * 8
|
|
||||||
)?;
|
|
||||||
writeln!(out, " ld r{value}, r{STACK_PTR}, r{ZERO}, {size}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(out: &mut impl std::fmt::Write, func: &str) -> std::fmt::Result {
|
|
||||||
stack_push(out, RET_ADDR, 8)?;
|
|
||||||
jump_label(out, func)?;
|
|
||||||
stack_pop(out, RET_ADDR, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ret(out: &mut impl std::fmt::Write) -> std::fmt::Result {
|
|
||||||
writeln!(out, " jala r{ZERO}, r{RET_ADDR}, 0")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn jump_label(out: &mut impl std::fmt::Write, label: &str) -> std::fmt::Result {
|
|
||||||
writeln!(out, " jal r{RET_ADDR}, r{ZERO}, {label}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prelude(out: &mut impl std::fmt::Write) -> std::fmt::Result {
|
|
||||||
writeln!(out, "start:")?;
|
|
||||||
writeln!(out, " jal r{RET_ADDR}, r{ZERO}, main")?;
|
|
||||||
writeln!(out, " tx")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
struct TestMem;
|
struct TestMem;
|
||||||
|
|
||||||
impl hbvm::mem::Memory for TestMem {
|
impl hbvm::mem::Memory for TestMem {
|
||||||
|
@ -198,55 +321,37 @@ mod tests {
|
||||||
let exprs = parser.file();
|
let exprs = parser.file();
|
||||||
let mut codegen = super::Codegen::new();
|
let mut codegen = super::Codegen::new();
|
||||||
codegen.file(path, &exprs).unwrap();
|
codegen.file(path, &exprs).unwrap();
|
||||||
codegen.dump(&mut *output).unwrap();
|
let mut out = Vec::new();
|
||||||
|
codegen.dump(&mut out).unwrap();
|
||||||
|
|
||||||
let mut proc = std::process::Command::new("/usr/bin/hbas")
|
use std::fmt::Write;
|
||||||
.stdin(std::process::Stdio::piped())
|
|
||||||
.stdout(std::process::Stdio::piped())
|
|
||||||
.spawn()
|
|
||||||
.unwrap();
|
|
||||||
proc.stdin
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.write_all(output.as_bytes())
|
|
||||||
.unwrap();
|
|
||||||
let out = proc.wait_with_output().unwrap();
|
|
||||||
|
|
||||||
if !out.status.success() {
|
let mut stack = [0_u64; 1024];
|
||||||
panic!(
|
|
||||||
"hbas failed with status: {}\n{}",
|
|
||||||
out.status,
|
|
||||||
String::from_utf8_lossy(&out.stderr)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
use std::fmt::Write;
|
|
||||||
|
|
||||||
let mut stack = [0_u64; 1024];
|
for (i, b) in out.iter().enumerate() {
|
||||||
|
write!(output, "{:02x}", b).unwrap();
|
||||||
for b in &out.stdout {
|
if (i + 1) % 4 == 0 {
|
||||||
writeln!(output, "{:02x}", b).unwrap();
|
writeln!(output).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut vm = unsafe {
|
|
||||||
hbvm::Vm::<TestMem, 0>::new(
|
|
||||||
TestMem,
|
|
||||||
hbvm::mem::Address::new(out.stdout.as_ptr() as u64),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
vm.write_reg(super::STACK_PTR, stack.as_mut_ptr() as u64);
|
|
||||||
|
|
||||||
let stat = loop {
|
|
||||||
match vm.run() {
|
|
||||||
Ok(hbvm::VmRunOk::End) => break Ok(()),
|
|
||||||
Ok(ev) => writeln!(output, "ev: {:?}", ev).unwrap(),
|
|
||||||
Err(e) => break Err(e),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
writeln!(output, "ret: {:?}", vm.read_reg(0)).unwrap();
|
|
||||||
writeln!(output, "status: {:?}", stat).unwrap();
|
|
||||||
}
|
}
|
||||||
|
writeln!(output).unwrap();
|
||||||
|
|
||||||
|
let mut vm = unsafe {
|
||||||
|
hbvm::Vm::<TestMem, 0>::new(TestMem, hbvm::mem::Address::new(out.as_ptr() as u64))
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.write_reg(super::STACK_PTR, stack.as_mut_ptr() as u64);
|
||||||
|
|
||||||
|
let stat = loop {
|
||||||
|
match vm.run() {
|
||||||
|
Ok(hbvm::VmRunOk::End) => break Ok(()),
|
||||||
|
Ok(ev) => writeln!(output, "ev: {:?}", ev).unwrap(),
|
||||||
|
Err(e) => break Err(e),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
writeln!(output, "ret: {:?}", vm.read_reg(1)).unwrap();
|
||||||
|
writeln!(output, "status: {:?}", stat).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::run_tests! { generate:
|
crate::run_tests! { generate:
|
||||||
|
|
0
hblang/src/ident.rs
Normal file
0
hblang/src/ident.rs
Normal file
497
hblang/src/instrs.rs
Normal file
497
hblang/src/instrs.rs
Normal file
|
@ -0,0 +1,497 @@
|
||||||
|
impl crate::codegen::Func {
|
||||||
|
/// Cause an unreachable code trap
|
||||||
|
pub fn un(&mut self) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x00, (), (), (), ())));
|
||||||
|
}
|
||||||
|
/// Termiante execution
|
||||||
|
pub fn tx(&mut self) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x01, (), (), (), ())));
|
||||||
|
}
|
||||||
|
/// Do nothing
|
||||||
|
pub fn nop(&mut self) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x02, (), (), (), ())));
|
||||||
|
}
|
||||||
|
/// Addition (8b)
|
||||||
|
pub fn add8(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x03, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Addition (16b)
|
||||||
|
pub fn add16(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x04, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Addition (32b)
|
||||||
|
pub fn add32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x05, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Addition (64b)
|
||||||
|
pub fn add64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x06, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Subtraction (8b)
|
||||||
|
pub fn sub8(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x07, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Subtraction (16b)
|
||||||
|
pub fn sub16(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x08, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Subtraction (32b)
|
||||||
|
pub fn sub32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x09, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Subtraction (64b)
|
||||||
|
pub fn sub64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x0A, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Multiplication (8b)
|
||||||
|
pub fn mul8(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x0B, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Multiplication (16b)
|
||||||
|
pub fn mul16(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x0C, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Multiplication (32b)
|
||||||
|
pub fn mul32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x0D, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Multiplication (64b)
|
||||||
|
pub fn mul64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x0E, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Bitand
|
||||||
|
pub fn and(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x0F, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Bitor
|
||||||
|
pub fn or(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x10, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Bitxor
|
||||||
|
pub fn xor(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x11, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned left bitshift (8b)
|
||||||
|
pub fn slu8(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x12, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned left bitshift (16b)
|
||||||
|
pub fn slu16(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x13, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned left bitshift (32b)
|
||||||
|
pub fn slu32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x14, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned left bitshift (64b)
|
||||||
|
pub fn slu64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x15, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned right bitshift (8b)
|
||||||
|
pub fn sru8(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x16, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned right bitshift (16b)
|
||||||
|
pub fn sru16(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x17, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned right bitshift (32b)
|
||||||
|
pub fn sru32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x18, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned right bitshift (64b)
|
||||||
|
pub fn sru64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x19, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Signed right bitshift (8b)
|
||||||
|
pub fn srs8(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x1A, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Signed right bitshift (16b)
|
||||||
|
pub fn srs16(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x1B, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Signed right bitshift (32b)
|
||||||
|
pub fn srs32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x1C, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Signed right bitshift (64b)
|
||||||
|
pub fn srs64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x1D, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned comparsion
|
||||||
|
pub fn cmpu(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x1E, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Signed comparsion
|
||||||
|
pub fn cmps(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x1F, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Merged divide-remainder (unsigned 8b)
|
||||||
|
pub fn diru8(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x20, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Merged divide-remainder (unsigned 16b)
|
||||||
|
pub fn diru16(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x21, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Merged divide-remainder (unsigned 32b)
|
||||||
|
pub fn diru32(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x22, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Merged divide-remainder (unsigned 64b)
|
||||||
|
pub fn diru64(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x23, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Merged divide-remainder (signed 8b)
|
||||||
|
pub fn dirs8(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x24, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Merged divide-remainder (signed 16b)
|
||||||
|
pub fn dirs16(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x25, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Merged divide-remainder (signed 32b)
|
||||||
|
pub fn dirs32(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x26, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Merged divide-remainder (signed 64b)
|
||||||
|
pub fn dirs64(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x27, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Bit negation
|
||||||
|
pub fn neg(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x28, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Logical negation
|
||||||
|
pub fn not(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x29, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Sign extend 8b to 64b
|
||||||
|
pub fn sxt8(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x2A, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Sign extend 16b to 64b
|
||||||
|
pub fn sxt16(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x2B, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Sign extend 32b to 64b
|
||||||
|
pub fn sxt32(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x2C, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Addition with immediate (8b)
|
||||||
|
pub fn addi8(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x2D, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Addition with immediate (16b)
|
||||||
|
pub fn addi16(&mut self, reg0: u8, reg1: u8, imm2: u16) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x2E, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Addition with immediate (32b)
|
||||||
|
pub fn addi32(&mut self, reg0: u8, reg1: u8, imm2: u32) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x2F, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Addition with immediate (64b)
|
||||||
|
pub fn addi64(&mut self, reg0: u8, reg1: u8, imm2: u64) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x30, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Multiplication with immediate (8b)
|
||||||
|
pub fn muli8(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x31, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Multiplication with immediate (16b)
|
||||||
|
pub fn muli16(&mut self, reg0: u8, reg1: u8, imm2: u16) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x32, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Multiplication with immediate (32b)
|
||||||
|
pub fn muli32(&mut self, reg0: u8, reg1: u8, imm2: u32) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x33, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Multiplication with immediate (64b)
|
||||||
|
pub fn muli64(&mut self, reg0: u8, reg1: u8, imm2: u64) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x34, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Bitand with immediate
|
||||||
|
pub fn andi(&mut self, reg0: u8, reg1: u8, imm2: u64) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x35, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Bitor with immediate
|
||||||
|
pub fn ori(&mut self, reg0: u8, reg1: u8, imm2: u64) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x36, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Bitxor with immediate
|
||||||
|
pub fn xori(&mut self, reg0: u8, reg1: u8, imm2: u64) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x37, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned left bitshift with immedidate (8b)
|
||||||
|
pub fn slui8(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x38, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned left bitshift with immedidate (16b)
|
||||||
|
pub fn slui16(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x39, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned left bitshift with immedidate (32b)
|
||||||
|
pub fn slui32(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x3A, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned left bitshift with immedidate (64b)
|
||||||
|
pub fn slui64(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x3B, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned right bitshift with immediate (8b)
|
||||||
|
pub fn srui8(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x3C, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned right bitshift with immediate (16b)
|
||||||
|
pub fn srui16(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x3D, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned right bitshift with immediate (32b)
|
||||||
|
pub fn srui32(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x3E, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned right bitshift with immediate (64b)
|
||||||
|
pub fn srui64(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x3F, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Signed right bitshift with immediate
|
||||||
|
pub fn srsi8(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x40, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Signed right bitshift with immediate
|
||||||
|
pub fn srsi16(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x41, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Signed right bitshift with immediate
|
||||||
|
pub fn srsi32(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x42, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Signed right bitshift with immediate
|
||||||
|
pub fn srsi64(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x43, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Unsigned compare with immediate
|
||||||
|
pub fn cmpui(&mut self, reg0: u8, reg1: u8, imm2: u64) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x44, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Signed compare with immediate
|
||||||
|
pub fn cmpsi(&mut self, reg0: u8, reg1: u8, imm2: u64) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x45, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Copy register
|
||||||
|
pub fn cp(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x46, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Swap registers
|
||||||
|
pub fn swa(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x47, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Load immediate (8b)
|
||||||
|
pub fn li8(&mut self, reg0: u8, imm1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x48, reg0, imm1, (), ())));
|
||||||
|
}
|
||||||
|
/// Load immediate (16b)
|
||||||
|
pub fn li16(&mut self, reg0: u8, imm1: u16) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x49, reg0, imm1, (), ())));
|
||||||
|
}
|
||||||
|
/// Load immediate (32b)
|
||||||
|
pub fn li32(&mut self, reg0: u8, imm1: u32) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x4A, reg0, imm1, (), ())));
|
||||||
|
}
|
||||||
|
/// Load immediate (64b)
|
||||||
|
pub fn li64(&mut self, reg0: u8, imm1: u64) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x4B, reg0, imm1, (), ())));
|
||||||
|
}
|
||||||
|
/// Load relative address
|
||||||
|
pub fn lra(&mut self, reg0: u8, reg1: u8, offset2: u32) {
|
||||||
|
self.offset(offset2, 3, 4);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x4C, reg0, reg1, 0u32, ())));
|
||||||
|
}
|
||||||
|
/// Load from absolute address
|
||||||
|
pub fn ld(&mut self, reg0: u8, reg1: u8, addr2: u64, imm3: u16) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x4D, reg0, reg1, addr2, imm3)));
|
||||||
|
}
|
||||||
|
/// Store to absolute address
|
||||||
|
pub fn st(&mut self, reg0: u8, reg1: u8, addr2: u64, imm3: u16) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x4E, reg0, reg1, addr2, imm3)));
|
||||||
|
}
|
||||||
|
/// Load from relative address
|
||||||
|
pub fn ldr(&mut self, reg0: u8, reg1: u8, offset2: u32, imm3: u16) {
|
||||||
|
self.offset(offset2, 3, 4);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x4F, reg0, reg1, 0u32, imm3)));
|
||||||
|
}
|
||||||
|
/// Store to relative address
|
||||||
|
pub fn str(&mut self, reg0: u8, reg1: u8, offset2: u32, imm3: u16) {
|
||||||
|
self.offset(offset2, 3, 4);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x50, reg0, reg1, 0u32, imm3)));
|
||||||
|
}
|
||||||
|
/// Copy block of memory
|
||||||
|
pub fn bmc(&mut self, reg0: u8, reg1: u8, imm2: u16) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x51, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Copy register block
|
||||||
|
pub fn brc(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x52, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Relative jump
|
||||||
|
pub fn jmp(&mut self, offset0: u32) {
|
||||||
|
self.offset(offset0, 1, 4);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x53, 0u32, (), (), ())));
|
||||||
|
}
|
||||||
|
/// Linking relative jump
|
||||||
|
pub fn jal(&mut self, reg0: u8, reg1: u8, offset2: u32) {
|
||||||
|
self.offset(offset2, 3, 4);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x54, reg0, reg1, 0u32, ())));
|
||||||
|
}
|
||||||
|
/// Linking absolute jump
|
||||||
|
pub fn jala(&mut self, reg0: u8, reg1: u8, addr2: u64) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x55, reg0, reg1, addr2, ())));
|
||||||
|
}
|
||||||
|
/// Branch on equal
|
||||||
|
pub fn jeq(&mut self, reg0: u8, reg1: u8, offset2: u32) {
|
||||||
|
self.offset(offset2, 3, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x56, reg0, reg1, 0u16, ())));
|
||||||
|
}
|
||||||
|
/// Branch on nonequal
|
||||||
|
pub fn jne(&mut self, reg0: u8, reg1: u8, offset2: u32) {
|
||||||
|
self.offset(offset2, 3, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x57, reg0, reg1, 0u16, ())));
|
||||||
|
}
|
||||||
|
/// Branch on lesser-than (unsigned)
|
||||||
|
pub fn jltu(&mut self, reg0: u8, reg1: u8, offset2: u32) {
|
||||||
|
self.offset(offset2, 3, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x58, reg0, reg1, 0u16, ())));
|
||||||
|
}
|
||||||
|
/// Branch on greater-than (unsigned)
|
||||||
|
pub fn jgtu(&mut self, reg0: u8, reg1: u8, offset2: u32) {
|
||||||
|
self.offset(offset2, 3, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x59, reg0, reg1, 0u16, ())));
|
||||||
|
}
|
||||||
|
/// Branch on lesser-than (signed)
|
||||||
|
pub fn jlts(&mut self, reg0: u8, reg1: u8, offset2: u32) {
|
||||||
|
self.offset(offset2, 3, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x5A, reg0, reg1, 0u16, ())));
|
||||||
|
}
|
||||||
|
/// Branch on greater-than (signed)
|
||||||
|
pub fn jgts(&mut self, reg0: u8, reg1: u8, offset2: u32) {
|
||||||
|
self.offset(offset2, 3, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x5B, reg0, reg1, 0u16, ())));
|
||||||
|
}
|
||||||
|
/// Environment call trap
|
||||||
|
pub fn eca(&mut self) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x5C, (), (), (), ())));
|
||||||
|
}
|
||||||
|
/// Environment breakpoint
|
||||||
|
pub fn ebp(&mut self) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x5D, (), (), (), ())));
|
||||||
|
}
|
||||||
|
/// Floating point addition (32b)
|
||||||
|
pub fn fadd32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x5E, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Floating point addition (64b)
|
||||||
|
pub fn fadd64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x5F, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Floating point subtraction (32b)
|
||||||
|
pub fn fsub32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x60, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Floating point subtraction (64b)
|
||||||
|
pub fn fsub64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x61, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Floating point multiply (32b)
|
||||||
|
pub fn fmul32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x62, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Floating point multiply (64b)
|
||||||
|
pub fn fmul64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x63, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Floating point division (32b)
|
||||||
|
pub fn fdiv32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x64, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Floating point division (64b)
|
||||||
|
pub fn fdiv64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x65, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Float fused multiply-add (32b)
|
||||||
|
pub fn fma32(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x66, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Float fused multiply-add (64b)
|
||||||
|
pub fn fma64(&mut self, reg0: u8, reg1: u8, reg2: u8, reg3: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x67, reg0, reg1, reg2, reg3)));
|
||||||
|
}
|
||||||
|
/// Float reciprocal (32b)
|
||||||
|
pub fn finv32(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x68, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Float reciprocal (64b)
|
||||||
|
pub fn finv64(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x69, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Flaot compare less than (32b)
|
||||||
|
pub fn fcmplt32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x6A, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Flaot compare less than (64b)
|
||||||
|
pub fn fcmplt64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x6B, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Flaot compare greater than (32b)
|
||||||
|
pub fn fcmpgt32(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x6C, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Flaot compare greater than (64b)
|
||||||
|
pub fn fcmpgt64(&mut self, reg0: u8, reg1: u8, reg2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x6D, reg0, reg1, reg2, ())));
|
||||||
|
}
|
||||||
|
/// Int to 32 bit float
|
||||||
|
pub fn itf32(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x6E, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Int to 64 bit float
|
||||||
|
pub fn itf64(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x6F, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Float 32 to int
|
||||||
|
pub fn fti32(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x70, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Float 64 to int
|
||||||
|
pub fn fti64(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x71, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Float 64 to Float 32
|
||||||
|
pub fn fc32t64(&mut self, reg0: u8, reg1: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x72, reg0, reg1, (), ())));
|
||||||
|
}
|
||||||
|
/// Float 32 to Float 64
|
||||||
|
pub fn fc64t32(&mut self, reg0: u8, reg1: u8, imm2: u8) {
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x73, reg0, reg1, imm2, ())));
|
||||||
|
}
|
||||||
|
/// Load relative immediate (16 bit)
|
||||||
|
pub fn lra16(&mut self, reg0: u8, reg1: u8, offset2: u32) {
|
||||||
|
self.offset(offset2, 3, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x74, reg0, reg1, 0u16, ())));
|
||||||
|
}
|
||||||
|
/// Load from relative address (16 bit)
|
||||||
|
pub fn ldr16(&mut self, reg0: u8, reg1: u8, offset2: u32, imm3: u16) {
|
||||||
|
self.offset(offset2, 3, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x75, reg0, reg1, 0u16, imm3)));
|
||||||
|
}
|
||||||
|
/// Store to relative address (16 bit)
|
||||||
|
pub fn str16(&mut self, reg0: u8, reg1: u8, offset2: u32, imm3: u16) {
|
||||||
|
self.offset(offset2, 3, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x76, reg0, reg1, 0u16, imm3)));
|
||||||
|
}
|
||||||
|
/// Relative jump (16 bit)
|
||||||
|
pub fn jmp16(&mut self, offset0: u32) {
|
||||||
|
self.offset(offset0, 1, 2);
|
||||||
|
self.extend(crate::as_bytes(&crate::Args(0x77, 0u16, (), (), ())));
|
||||||
|
}
|
||||||
|
}
|
|
@ -162,6 +162,6 @@ mod tests {
|
||||||
crate::run_tests! { lex:
|
crate::run_tests! { lex:
|
||||||
empty => "";
|
empty => "";
|
||||||
whitespace => " \t\n\r";
|
whitespace => " \t\n\r";
|
||||||
examples => include_str!("../examples/main_fn.hb");
|
example => include_str!("../examples/main_fn.hb");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,19 @@ macro_rules! run_tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
mod ident;
|
||||||
|
mod instrs;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod tests;
|
mod tests;
|
||||||
mod typechk;
|
mod typechk;
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
struct Args<A, B, C, D>(u8, A, B, C, D);
|
||||||
|
fn as_bytes<T>(args: &T) -> &[u8] {
|
||||||
|
unsafe { core::slice::from_raw_parts(args as *const _ as *const u8, core::mem::size_of::<T>()) }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn try_block<R>(f: impl FnOnce() -> R) -> R {
|
pub fn try_block<R>(f: impl FnOnce() -> R) -> R {
|
||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum Expr<'a> {
|
pub enum Expr<'a> {
|
||||||
Decl {
|
Decl {
|
||||||
name: Ptr<'a, str>,
|
name: Ptr<'a, str>,
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
start:
|
541f0005
|
||||||
addi64 r254, r254, 8
|
00000001
|
||||||
jal r0, r0, main
|
4b010100
|
||||||
tx
|
00000000
|
||||||
main:
|
00005500
|
||||||
jala r0, r31, 0
|
1f000000
|
||||||
|
00000000
|
||||||
|
00
|
||||||
|
ret: 1
|
||||||
|
status: Ok(())
|
||||||
|
|
|
@ -2,9 +2,10 @@ Ident "main"
|
||||||
Decl ":="
|
Decl ":="
|
||||||
Or "||"
|
Or "||"
|
||||||
Colon ":"
|
Colon ":"
|
||||||
Ident "void"
|
Ident "int"
|
||||||
LBrace "{"
|
LBrace "{"
|
||||||
Return "return"
|
Return "return"
|
||||||
|
Number "1"
|
||||||
Semi ";"
|
Semi ";"
|
||||||
RBrace "}"
|
RBrace "}"
|
||||||
Eof ""
|
Eof ""
|
|
@ -1,3 +1,3 @@
|
||||||
main := ||: void {
|
main := ||: int {
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue