Maybe fixed relative addressing bugs

This commit is contained in:
Erin 2023-10-22 14:46:45 +02:00 committed by ondra05
parent f064e23b89
commit c8371c0532
3 changed files with 34 additions and 26 deletions

View file

@ -5,8 +5,8 @@ use core::convert::TryFrom;
type OpR = u8; type OpR = u8;
type OpA = u64; type OpA = u64;
type OpO = u32; type OpO = i32;
type OpP = u16; type OpP = i16;
type OpB = u8; type OpB = u8;
type OpH = u16; type OpH = u16;

View file

@ -112,11 +112,20 @@ pub trait AddressOp {
fn cast_u64(self) -> u64; fn cast_u64(self) -> u64;
} }
macro_rules! impl_address_ops(($($ty:ty),* $(,)?) => { macro_rules! impl_address_ops_u(($($ty:ty),* $(,)?) => {
$(impl AddressOp for $ty { $(impl AddressOp for $ty {
#[inline(always)] #[inline(always)]
fn cast_u64(self) -> u64 { self as _ } 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);

View file

@ -4,6 +4,8 @@
use hbbytecode::RoundingMode; use hbbytecode::RoundingMode;
use crate::mem::addr::AddressOp;
use { use {
super::{ super::{
bmc::BlockCopier, bmc::BlockCopier,
@ -201,10 +203,12 @@ where
LI16 => handler!(self, |OpsRH(tg, imm)| self.write_reg(tg, imm)), LI16 => handler!(self, |OpsRH(tg, imm)| self.write_reg(tg, imm)),
LI32 => handler!(self, |OpsRW(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)), 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( self.write_reg(
tg, tg,
(self.pc + self.read_reg(reg).cast::<u64>() + imm + 3_u16).get(), self.pcrel(off, 3)
.wrapping_add(self.read_reg(reg).cast::<i64>())
.get(),
); );
}), }),
LD => handler!(self, |OpsRRAH(dst, base, off, count)| { LD => handler!(self, |OpsRRAH(dst, base, off, count)| {
@ -216,20 +220,10 @@ where
self.store(dst, base, off, count)?; self.store(dst, base, off, count)?;
}), }),
LDR => handler!(self, |OpsRROH(dst, base, off, count)| { LDR => handler!(self, |OpsRROH(dst, base, off, count)| {
self.load( self.load(dst, base, self.pcrel(off, 3).get(), count)?;
dst,
base,
u64::from(off).wrapping_add((self.pc + 3_u64).get()),
count,
)?;
}), }),
STR => handler!(self, |OpsRROH(dst, base, off, count)| { STR => handler!(self, |OpsRROH(dst, base, off, count)| {
self.store( self.store(dst, base, self.pcrel(off, 3).get(), count)?;
dst,
base,
u64::from(off).wrapping_add((self.pc + 3_u64).get()),
count,
)?;
}), }),
BMC => { BMC => {
// Block memory copy // Block memory copy
@ -278,14 +272,13 @@ where
); );
}), }),
JMP => handler!(self, |OpsO(off)| self.pc = self.pc.wrapping_add(off)), 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 // 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.
self.write_reg(save, self.pc.get()); self.write_reg(save, self.pc.get());
self.pc = self self.pc = self
.pc .pcrel(offset, 3)
.wrapping_add(self.read_reg(reg).cast::<u64>()) .wrapping_add(self.read_reg(reg).cast::<i64>());
.wrapping_add(offset);
}), }),
JALA => handler!(self, |OpsRRW(save, reg, offset)| { JALA => handler!(self, |OpsRRW(save, reg, offset)| {
// Jump and link. Save PC after this instruction to // Jump and link. Save PC after this instruction to
@ -387,12 +380,12 @@ where
); );
}), }),
LDR16 => handler!(self, |OpsRRPH(dst, base, off, count)| { 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)| { 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)), 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 /// Jump at `PC + #3` if ordering on `#0 <=> #1` is equal to expected
#[inline(always)] #[inline(always)]
unsafe fn cond_jmp<T: ValueVariant + Ord>(&mut self, expected: Ordering) { unsafe fn cond_jmp<T: ValueVariant + Ord>(&mut self, expected: Ordering) {
@ -547,7 +546,7 @@ where
.cmp(&self.read_reg(a1).cast::<T>()) .cmp(&self.read_reg(a1).cast::<T>())
== expected == 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::<OpsRRP, true>(); self.bump_pc::<OpsRRP, true>();