diff --git a/hbasm/src/lib.rs b/hbasm/src/lib.rs index 121927a8..f9398388 100644 --- a/hbasm/src/lib.rs +++ b/hbasm/src/lib.rs @@ -62,7 +62,8 @@ tokendef![ "nop", "add", "sub", "mul", "and", "or", "xor", "sl", "sr", "srs", "cmp", "cmpu", "dir", "neg", "not", "addi", "muli", "andi", "ori", "xori", "sli", "sri", "srsi", "cmpi", "cmpui", "cp", "swa", "li", "ld", "st", "bmc", "brc", "jmp", "jeq", "jne", - "jlt", "jgt", "jltu", "jgtu", "ecall", "addf", "mulf", "dirf", "addfi", "mulfi", + "jlt", "jgt", "jltu", "jgtu", "ecall", "addf", "subf", "mulf", "dirf", "fma", "negf", + "itf", "fti", "addfi", "mulfi", ]; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -161,7 +162,7 @@ pub fn assembly(code: &str, buf: &mut Vec) -> Result<(), Error> { ]); Ok(()) } - NEG..=NOT | CP..=SWA => { + NEG..=NOT | CP..=SWA | NEGF..=FTI => { expect_matches!( self, Token::Register(r0), diff --git a/hbbytecode/hbbytecode.h b/hbbytecode/hbbytecode.h index 14471cec..10eebacc 100644 --- a/hbbytecode/hbbytecode.h +++ b/hbbytecode/hbbytecode.h @@ -10,13 +10,15 @@ static_assert(CHAR_BIT == 8, "Cursed architectures are not supported"); enum hbbc_Opcode: uint8_t { - hbbc_Op_NOP, hbbc_Op_ADD, hbbc_Op_MUL, hbbc_Op_AND, hbbc_Op_OR, hbbc_Op_XOR, hbbc_Op_SL, - hbbc_Op_SR, hbbc_Op_SRS, hbbc_Op_CMP, hbbc_Op_CMPU, hbbc_Op_DIR, hbbc_Op_NEG, hbbc_Op_NOT, - hbbc_Op_ADDI, hbbc_Op_MULI, hbbc_Op_ANDI, hbbc_Op_ORI, hbbc_Op_XORI, hbbc_Op_SLI, hbbc_Op_SRI, - hbbc_Op_SRSI, hbbc_Op_CMPI, hbbc_Op_CMPUI, hbbc_Op_CP, hbbc_Op_SWA, hbbc_Op_LI, hbbc_Op_LD, - hbbc_Op_ST, hbbc_Op_BMC, hbbc_Op_BRC, hbbc_Op_JMP, hbbc_Op_JEQ, hbbc_Op_JNE, hbbc_Op_JLT, - hbbc_Op_JGT, hbbc_Op_JLTU, hbbc_Op_JGTU, hbbc_Op_ECALL, hbbc_Op_ADDF, hbbc_Op_MULF, - hbbc_Op_DIRF, hbbc_Op_ADDFI, hbbc_Op_MULFI, + hbbc_Op_NOP , hbbc_Op_ADD , hbbc_Op_SUB , hbbc_Op_MUL , hbbc_Op_AND , hbbc_Op_OR , + hbbc_Op_XOR , hbbc_Op_SL , hbbc_Op_SR , hbbc_Op_SRS , hbbc_Op_CMP , hbbc_Op_CMPU , + hbbc_Op_DIR , hbbc_Op_NEG , hbbc_Op_NOT , hbbc_Op_ADDI , hbbc_Op_MULI , hbbc_Op_ANDI , + hbbc_Op_ORI , hbbc_Op_XORI , hbbc_Op_SLI , hbbc_Op_SRI , hbbc_Op_SRSI , hbbc_Op_CMPI , + hbbc_Op_CMPUI , hbbc_Op_CP , hbbc_Op_SWA , hbbc_Op_LI , hbbc_Op_LD , hbbc_Op_ST , + hbbc_Op_BMC , hbbc_Op_BRC , hbbc_Op_JMP , hbbc_Op_JEQ , hbbc_Op_JNE , hbbc_Op_JLT , + hbbc_Op_JGT , hbbc_Op_JLTU , hbbc_Op_JGTU , hbbc_Op_ECALL , hbbc_Op_ADDF , hbbc_Op_SUBF , + hbbc_Op_MULF , hbbc_Op_DIRF , hbbc_Op_FMA , hbbc_Op_NEGF , hbbc_Op_ITF , hbbc_Op_FTI , + hbbc_Op_ADDFI , hbbc_Op_MULFI , } typedef hbbc_Opcode; static_assert(sizeof(hbbc_Opcode) == 1); diff --git a/hbbytecode/src/lib.rs b/hbbytecode/src/lib.rs index 8a937b15..6e857972 100644 --- a/hbbytecode/src/lib.rs +++ b/hbbytecode/src/lib.rs @@ -32,7 +32,7 @@ constmod!(pub opcode(u8) { CMP = 10, "BBB; #0 ← #1 <=> #2"; CMPU = 11, "BBB; #0 ← #1 <=> #2 (unsigned)"; DIR = 12, "BBBB; #0 ← #2 / #3, #1 ← #2 % #3"; - NEG = 13, "BB; #0 ← ~#1"; + NEG = 13, "BB; #0 ← -#1"; NOT = 14, "BB; #0 ← !#1"; ADDI = 15, "BBD; #0 ← #1 + imm #2"; @@ -63,12 +63,17 @@ constmod!(pub opcode(u8) { JGTU = 38, "BBD; if #0 > #1 → jump imm #2 (unsigned)"; ECALL = 39, "N; Issue system call"; - ADDF = 40, "BBB; #0 ← #1 +. #2"; - MULF = 41, "BBB; #0 ← #1 +. #2"; - DIRF = 42, "BBBB; #0 ← #2 / #3, #1 ← #2 % #3"; + ADDF = 40, "BBB; #0 ← #1 +. #2"; + SUBF = 41, "BBB; #0 ← #1 -. #2"; + MULF = 42, "BBB; #0 ← #1 +. #2"; + DIRF = 43, "BBBB; #0 ← #2 / #3, #1 ← #2 % #3"; + FMA = 44, "BBBB; #0 ← (#1 * #2) + #3"; + NEGF = 45, "BB; #0 ← -#1"; + ITF = 46, "BB; #0 ← #1 as float"; + FTI = 47, "BB; #0 ← #1 as int"; - ADDFI = 43, "BBD; #0 ← #1 +. imm #2"; - MULFI = 44, "BBD; #0 ← #1 *. imm #2"; + ADDFI = 48, "BBD; #0 ← #1 +. imm #2"; + MULFI = 49, "BBD; #0 ← #1 *. imm #2"; }); #[repr(packed)] diff --git a/hbvm/src/validate.rs b/hbvm/src/validate.rs index e1c6cbdc..52f726ff 100644 --- a/hbvm/src/validate.rs +++ b/hbvm/src/validate.rs @@ -15,7 +15,7 @@ pub enum ErrorKind { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Error { /// Kind - pub kind: ErrorKind, + pub kind: ErrorKind, /// Location in bytecode pub index: usize, } @@ -34,7 +34,7 @@ pub fn validate(mut program: &[u8]) -> Result<(), Error> { if usize::from(*reg) * 8 + usize::from(*count) > 2048 => { return Err(Error { - kind: ErrorKind::RegisterArrayOverflow, + kind: ErrorKind::RegisterArrayOverflow, index: (program.as_ptr() as usize) - (start.as_ptr() as usize), }) } @@ -42,20 +42,20 @@ pub fn validate(mut program: &[u8]) -> Result<(), Error> { if src.checked_add(*count).is_none() || dst.checked_add(*count).is_none() => { return Err(Error { - kind: ErrorKind::RegisterArrayOverflow, + kind: ErrorKind::RegisterArrayOverflow, index: (program.as_ptr() as usize) - (start.as_ptr() as usize), }) } [NOP | ECALL, rest @ ..] | [DIR | DIRF, _, _, _, _, rest @ ..] | [ADD..=CMPU | BRC | ADDF..=MULF, _, _, _, rest @ ..] - | [NEG..=NOT | CP..=SWA, _, _, rest @ ..] + | [NEG..=NOT | CP..=SWA | NEGF..=FTI, _, _, rest @ ..] | [LI | JMP, _, _, _, _, _, _, _, _, _, rest @ ..] | [ADDI..=CMPUI | BMC | JEQ..=JGTU | ADDFI..=MULFI, _, _, _, _, _, _, _, _, _, _, rest @ ..] | [LD..=ST, _, _, _, _, _, _, _, _, _, _, _, _, rest @ ..] => rest, _ => { return Err(Error { - kind: ErrorKind::InvalidInstruction, + kind: ErrorKind::InvalidInstruction, index: (program.as_ptr() as usize) - (start.as_ptr() as usize), }) } diff --git a/hbvm/src/vm/mod.rs b/hbvm/src/vm/mod.rs index 3e3f0ae2..83757062 100644 --- a/hbvm/src/vm/mod.rs +++ b/hbvm/src/vm/mod.rs @@ -50,8 +50,7 @@ macro_rules! binary_op { $handler( Value::$ty(&$self.read_reg(a0)), Value::$ty(&$self.read_reg(a1)), - ) - .into(), + ), ); }}; } @@ -62,7 +61,7 @@ macro_rules! binary_op_imm { let ParamBBD(tg, a0, imm) = param!($self, ParamBBD); $self.write_reg( tg, - $handler(Value::$ty(&$self.read_reg(a0)), Value::$ty(&imm.into())).into(), + $handler(Value::$ty(&$self.read_reg(a0)), Value::$ty(&imm.into())), ); }}; } @@ -148,21 +147,19 @@ impl<'a, T: HandleTrap> Vm<'a, T> { let ParamBBB(tg, a0, a1) = param!(self, ParamBBB); self.write_reg( tg, - (self.read_reg(a0).as_i64().cmp(&self.read_reg(a1).as_i64()) as i64) - .into(), + self.read_reg(a0).as_i64().cmp(&self.read_reg(a1).as_i64()) as i64, ); } CMPU => { let ParamBBB(tg, a0, a1) = param!(self, ParamBBB); self.write_reg( tg, - (self.read_reg(a0).as_u64().cmp(&self.read_reg(a1).as_u64()) as i64) - .into(), + self.read_reg(a0).as_u64().cmp(&self.read_reg(a1).as_u64()) as i64, ); } NOT => { let param = param!(self, ParamBB); - self.write_reg(param.0, (!self.read_reg(param.1).as_u64()).into()); + self.write_reg(param.0, !self.read_reg(param.1).as_u64()); } NEG => { let param = param!(self, ParamBB); @@ -171,16 +168,15 @@ impl<'a, T: HandleTrap> Vm<'a, T> { match self.read_reg(param.1).as_u64() { 0 => 1_u64, _ => 0, - } - .into(), + }, ); } DIR => { let ParamBBBB(dt, rt, a0, a1) = param!(self, ParamBBBB); let a0 = self.read_reg(a0).as_u64(); let a1 = self.read_reg(a1).as_u64(); - self.write_reg(dt, (a0.checked_div(a1).unwrap_or(u64::MAX)).into()); - self.write_reg(rt, (a0.checked_rem(a1).unwrap_or(u64::MAX)).into()); + self.write_reg(dt, a0.checked_div(a1).unwrap_or(u64::MAX)); + self.write_reg(rt, a0.checked_rem(a1).unwrap_or(u64::MAX)); } ADDI => binary_op_imm!(self, as_u64, ops::Add::add), MULI => binary_op_imm!(self, as_u64, ops::Mul::mul), @@ -194,13 +190,12 @@ impl<'a, T: HandleTrap> Vm<'a, T> { let ParamBBD(tg, a0, imm) = param!(self, ParamBBD); self.write_reg( tg, - (self.read_reg(a0).as_i64().cmp(&Value::from(imm).as_i64()) as i64) - .into(), + self.read_reg(a0).as_i64().cmp(&Value::from(imm).as_i64()) as i64, ); } CMPUI => { let ParamBBD(tg, a0, imm) = param!(self, ParamBBD); - self.write_reg(tg, (self.read_reg(a0).as_u64().cmp(&imm) as i64).into()); + self.write_reg(tg, self.read_reg(a0).as_u64().cmp(&imm) as i64); } CP => { let param = param!(self, ParamBB); @@ -217,7 +212,7 @@ impl<'a, T: HandleTrap> Vm<'a, T> { } LI => { let param = param!(self, ParamBD); - self.write_reg(param.0, param.1.into()); + self.write_reg(param.0, param.1); } LD => { let ParamBBDH(dst, base, off, count) = param!(self, ParamBBDH); @@ -280,13 +275,34 @@ impl<'a, T: HandleTrap> Vm<'a, T> { .ecall(&mut self.registers, &mut self.pc, &mut self.memory); } ADDF => binary_op!(self, as_f64, ops::Add::add), + SUBF => binary_op!(self, as_f64, ops::Sub::sub), MULF => binary_op!(self, as_f64, ops::Mul::mul), DIRF => { let ParamBBBB(dt, rt, a0, a1) = param!(self, ParamBBBB); let a0 = self.read_reg(a0).as_f64(); let a1 = self.read_reg(a1).as_f64(); - self.write_reg(dt, (a0 / a1).into()); - self.write_reg(rt, (a0 % a1).into()); + self.write_reg(dt, a0 / a1); + self.write_reg(rt, a0 % a1); + } + FMA => { + let ParamBBBB(dt, a0, a1, a2) = param!(self, ParamBBBB); + self.write_reg( + dt, + self.read_reg(a0).as_f64() * self.read_reg(a1).as_f64() + + self.read_reg(a2).as_f64(), + ); + } + NEGF => { + let ParamBB(dt, a0) = param!(self, ParamBB); + self.write_reg(dt, -self.read_reg(a0).as_f64()); + } + ITF => { + let ParamBB(dt, a0) = param!(self, ParamBB); + self.write_reg(dt, self.read_reg(a0).as_i64() as f64); + } + FTI => { + let ParamBB(dt, a0) = param!(self, ParamBB); + self.write_reg(dt, self.read_reg(a0).as_f64() as i64); } ADDFI => binary_op_imm!(self, as_f64, ops::Add::add), MULFI => binary_op_imm!(self, as_f64, ops::Mul::mul), @@ -314,9 +330,9 @@ impl<'a, T: HandleTrap> Vm<'a, T> { /// Write a register. /// Writing to register 0 is no-op. #[inline] - unsafe fn write_reg(&mut self, n: u8, value: Value) { + unsafe fn write_reg(&mut self, n: u8, value: impl Into) { if n != 0 { - *self.registers.get_unchecked_mut(n as usize) = value; + *self.registers.get_unchecked_mut(n as usize) = value.into(); } } } diff --git a/rustfmt.toml b/rustfmt.toml index 3807d4c6..90a36c78 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ hex_literal_case = "Upper" imports_granularity = "One" struct_field_align_threshold = 5 +enum_discrim_align_threshold = 5 \ No newline at end of file diff --git a/spec.md b/spec.md index c32e6eb0..4dc2291d 100644 --- a/spec.md +++ b/spec.md @@ -199,14 +199,38 @@ | Opcode | Name | Action | |:------:|:----:|:--------------:| | 40 | ADDF | Addition | -| 41 | MULF | Multiplication | +| 41 | SUBF | Subtraction | +| 42 | MULF | Multiplication | ### Division-remainder - Type BBBB -| Opcode | Name | Action | -|:------:|:----:|:--------------------------------------:| -| 42 | DIRF | Same flow applies as for integer `DIR` | +| Opcode | Name | Action | +|:------:|:----:|:-------------------------:| +| 43 | DIRF | Same as for integer `DIR` | + +### Fused Multiply-Add +- Type BBBB + +| Opcode | Name | Action | +|:------:|:----:|:---------------------:| +| 44 | FMA | `#0 ← (#1 * #2) + #3` | + +### Negation +- Type BB +| Opcode | Name | Action | +|:------:|:----:|:----------:| +| 45 | NEGF | `#0 ← -#1` | + +### Conversion +- Type BB +- Signed +- `#0 ← #1 as _` + +| Opcode | Name | Action | +|:------:|:----:|:------------:| +| 46 | ITF | Int to Float | +| 47 | FTI | Float to Int | ## Floating point immediate operations - Type BBD @@ -214,8 +238,8 @@ | Opcode | Name | Action | |:------:|:-----:|:--------------:| -| 43 | ADDFI | Addition | -| 44 | MULFI | Multiplication | +| 48 | ADDFI | Addition | +| 49 | MULFI | Multiplication | # Registers - There is 255 registers + one zero register (with index 0)