diff --git a/hbbytecode/src/lib.rs b/hbbytecode/src/lib.rs index 21a29c6..40be3c8 100644 --- a/hbbytecode/src/lib.rs +++ b/hbbytecode/src/lib.rs @@ -5,8 +5,8 @@ use core::convert::TryFrom; type OpR = u8; type OpA = u64; -type OpO = u32; -type OpP = u16; +type OpO = i32; +type OpP = i16; type OpB = u8; type OpH = u16; diff --git a/hbvm/src/mem/addr.rs b/hbvm/src/mem/addr.rs index 0191417..fc7b57b 100644 --- a/hbvm/src/mem/addr.rs +++ b/hbvm/src/mem/addr.rs @@ -112,11 +112,20 @@ pub trait AddressOp { fn cast_u64(self) -> u64; } -macro_rules! impl_address_ops(($($ty:ty),* $(,)?) => { +macro_rules! impl_address_ops_u(($($ty:ty),* $(,)?) => { $(impl AddressOp for $ty { #[inline(always)] fn cast_u64(self) -> u64 { self as _ } })* }); -impl_address_ops!(u8, u16, u32, u64, usize); +macro_rules! impl_address_ops_i(($($ty:ty),* $(,)?) => { + $(impl AddressOp for $ty { + #[inline(always)] + fn cast_u64(self) -> u64 { self as i64 as u64 } + })* +}); + + +impl_address_ops_u!(u8, u16, u32, u64, usize); +impl_address_ops_i!(i8, i16, i32, i64, isize); diff --git a/hbvm/src/vmrun.rs b/hbvm/src/vmrun.rs index 98e549c..8abc3b9 100644 --- a/hbvm/src/vmrun.rs +++ b/hbvm/src/vmrun.rs @@ -4,6 +4,8 @@ use hbbytecode::RoundingMode; +use crate::mem::addr::AddressOp; + use { super::{ bmc::BlockCopier, @@ -201,10 +203,12 @@ where LI16 => handler!(self, |OpsRH(tg, imm)| self.write_reg(tg, imm)), LI32 => handler!(self, |OpsRW(tg, imm)| self.write_reg(tg, imm)), LI64 => handler!(self, |OpsRD(tg, imm)| self.write_reg(tg, imm)), - LRA => handler!(self, |OpsRRO(tg, reg, imm)| { + LRA => handler!(self, |OpsRRO(tg, reg, off)| { self.write_reg( tg, - (self.pc + self.read_reg(reg).cast::() + imm + 3_u16).get(), + self.pcrel(off, 3) + .wrapping_add(self.read_reg(reg).cast::()) + .get(), ); }), LD => handler!(self, |OpsRRAH(dst, base, off, count)| { @@ -216,20 +220,10 @@ where self.store(dst, base, off, count)?; }), LDR => handler!(self, |OpsRROH(dst, base, off, count)| { - self.load( - dst, - base, - u64::from(off).wrapping_add((self.pc + 3_u64).get()), - count, - )?; + self.load(dst, base, self.pcrel(off, 3).get(), count)?; }), STR => handler!(self, |OpsRROH(dst, base, off, count)| { - self.store( - dst, - base, - u64::from(off).wrapping_add((self.pc + 3_u64).get()), - count, - )?; + self.store(dst, base, self.pcrel(off, 3).get(), count)?; }), BMC => { // Block memory copy @@ -278,14 +272,13 @@ where ); }), JMP => handler!(self, |OpsO(off)| self.pc = self.pc.wrapping_add(off)), - JAL => handler!(self, |OpsRRW(save, reg, offset)| { + JAL => handler!(self, |OpsRRO(save, reg, offset)| { // Jump and link. Save PC after this instruction to // specified register and jump to reg + relative offset. self.write_reg(save, self.pc.get()); self.pc = self - .pc - .wrapping_add(self.read_reg(reg).cast::()) - .wrapping_add(offset); + .pcrel(offset, 3) + .wrapping_add(self.read_reg(reg).cast::()); }), JALA => handler!(self, |OpsRRW(save, reg, offset)| { // Jump and link. Save PC after this instruction to @@ -387,12 +380,12 @@ where ); }), LDR16 => handler!(self, |OpsRRPH(dst, base, off, count)| { - self.load(dst, base, u64::from(off).wrapping_add(self.pc.get()), count)?; + self.load(dst, base, self.pcrel(off, 3).get(), count)?; }), STR16 => handler!(self, |OpsRRPH(dst, base, off, count)| { - self.store(dst, base, u64::from(off).wrapping_add(self.pc.get()), count)?; + self.store(dst, base, self.pcrel(off, 3).get(), count)?; }), - JMP16 => handler!(self, |OpsP(off)| self.pc = self.pc.wrapping_add(off)), + JMP16 => handler!(self, |OpsP(off)| self.pc = self.pcrel(off, 1)), op => return Err(VmRunError::InvalidOpcode(op)), } } @@ -537,6 +530,12 @@ where }); } + /// Calculate pc-relative address + #[inline(always)] + fn pcrel(&self, offset: impl AddressOp, pos: u8) -> Address { + self.pc.wrapping_add(pos).wrapping_add(offset) + } + /// Jump at `PC + #3` if ordering on `#0 <=> #1` is equal to expected #[inline(always)] unsafe fn cond_jmp(&mut self, expected: Ordering) { @@ -547,7 +546,7 @@ where .cmp(&self.read_reg(a1).cast::()) == expected { - self.pc = Address::new(((self.pc.get() as i64).wrapping_add(ja as i64)) as u64); + self.pc = self.pcrel(ja, 3); } self.bump_pc::();