emu: make string ops generic over operand size

After many attempts, it turns out this is as easy as remembering that
where clauses can bound non-parameter types
This commit is contained in:
2021-03-28 14:46:35 -07:00
parent a183a5ad38
commit 7c7f74a65b
2 changed files with 78 additions and 126 deletions

View File

@@ -190,6 +190,14 @@ macro_rules! step {
step!(@arg $cookie, &mut $cpu.flags)
};
(@form=nullary_byte $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
step!(@form $cookie, form=(u8));
};
(@form=nullary_word $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
step!(@form $cookie, form=(u16));
};
(@form=ternary_byte $cookie:tt, $cpu:expr, $bus:expr, $prefix:tt, $modrm:tt) => {
step!(@form $cookie, form=(u8, _, _, _));
};
@@ -496,16 +504,16 @@ impl i8088 {
0xA1 => mov[reg=a, addr] / 14,
0xA2 => mov[addr, reglo=a] / 14,
0xA3 => mov[addr, reg=a] / 14,
0xA4 => movsb[flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "18/9+17n",
0xA5 => movsw[flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "26/9+25n",
0xA6 => cmpsb[flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "22/9+22n",
0xA7 => cmpsw[flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "30/9+30n",
0xAA => stosb[flags, bus, rep, reg=c, reg=es, reg=di, reglo=a] / "11/9+10n",
0xAB => stosw[flags, bus, rep, reg=c, reg=es, reg=di, reg=a] / "15/9+14n",
0xAC => lodsb[flags, bus, rep, reg=c, seg=ds, seg, reg=si, reglo=a] / "12/9+13n",
0xAD => lodsw[flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=a] / "16/9+17n",
0xAE => scasb[flags, bus, rep, reg=c, reg=es, reg=di, reglo=a] / "15/9+15n",
0xAF => scasw[flags, bus, rep, reg=c, reg=es, reg=di, reg=a] / "19/9+19n",
0xA4 => movs[form=nullary_byte, flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "18/9+17n",
0xA5 => movs[form=nullary_word, flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "26/9+25n",
0xA6 => cmps[form=nullary_byte, flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "22/9+22n",
0xA7 => cmps[form=nullary_word, flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=es, reg=di] / "30/9+30n",
0xAA => stos[flags, bus, rep, reg=c, reg=es, reg=di, reglo=a] / "11/9+10n",
0xAB => stos[flags, bus, rep, reg=c, reg=es, reg=di, reg=a] / "15/9+14n",
0xAC => lods[flags, bus, rep, reg=c, seg=ds, seg, reg=si, reglo=a] / "12/9+13n",
0xAD => lods[flags, bus, rep, reg=c, seg=ds, seg, reg=si, reg=a] / "16/9+17n",
0xAE => scas[flags, bus, rep, reg=c, reg=es, reg=di, reglo=a] / "15/9+15n",
0xAF => scas[flags, bus, rep, reg=c, reg=es, reg=di, reg=a] / "19/9+19n",
0xB0 => mov[reglo=a, d8] / 4,
0xB1 => mov[reglo=c, d8] / 4,
0xB2 => mov[reglo=d, d8] / 4,

View File

@@ -80,33 +80,20 @@ pub fn cmp<T: Operand>(flags: &mut Flags, dst: impl RValue<T>, src: impl RValue<
flags.update(FlagOp::SUB, dst.into(), src.into(), res.into(), T::WIDTH);
}
pub fn cmpsb(flags: &mut Flags,
pub fn cmps<T>(flags: &mut Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
seg: u16,
mut si: Reg,
es: Reg,
mut di: Reg) {
string_op!((u8, flags, rep, cx, si=si, di=di, zf=flags.zf()), {
let src = <FarPtr as RValue<u8>>::read(&FarPtr { bus: bus, segment: seg, offset: si.read() });
let dst = <FarPtr as RValue<u8>>::read(&FarPtr { bus: bus, segment: es.read(), offset: di.read() });
cmp(flags, dst, src);
});
}
pub fn cmpsw(flags: &mut Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
seg: u16,
mut si: Reg,
es: Reg,
mut di: Reg) {
string_op!((u16, flags, rep, cx, si=si, di=di, zf=flags.zf()), {
let src = <FarPtr as RValue<u16>>::read(&FarPtr { bus: bus, segment: seg, offset: si.read() });
let dst = <FarPtr as RValue<u16>>::read(&FarPtr { bus: bus, segment: es.read(), offset: di.read() });
mut di: Reg)
where T: Operand + RValue<T>,
for<'a> FarPtr<'a>: RValue<T>
{
string_op!((T, flags, rep, cx, si=si, di=di, zf=flags.zf()), {
let src = <FarPtr as RValue<T>>::read(&FarPtr { bus: bus, segment: seg, offset: si.read() });
let dst = <FarPtr as RValue<T>>::read(&FarPtr { bus: bus, segment: es.read(), offset: di.read() });
cmp(flags, dst, src);
});
@@ -244,26 +231,16 @@ pub fn lea(mut dst: Reg, addr: FarPtr) {
dst.write(addr.offset)
}
pub fn lodsb(flags: &Flags,
pub fn lods<T>(flags: &Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
seg: u16,
mut si: Reg,
mut al: impl LValue<u8>) {
string_op!((u8, flags, rep, cx, si=si), {
al.write(FarPtr { bus: bus, segment: seg, offset: si.read() }.read());
});
}
pub fn lodsw(flags: &Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
seg: u16,
mut si: Reg,
mut ax: impl LValue<u16>) {
string_op!((u16, flags, rep, cx, si=si), {
mut ax: impl LValue<T>)
where for<'a> FarPtr<'a>: RValue<T>
{
string_op!((T, flags, rep, cx, si=si), {
ax.write(FarPtr { bus: bus, segment: seg, offset: si.read() }.read());
});
}
@@ -272,33 +249,20 @@ pub fn mov<T>(mut dst: impl LValue<T>, src: impl RValue<T>) {
dst.write(src.read());
}
pub fn movsb(flags: &Flags,
pub fn movs<T>(flags: &Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
seg: u16,
mut si: Reg,
es: Reg,
mut di: Reg) {
string_op!((u8, flags, rep, cx, si=si, di=di), {
let src = <FarPtr as RValue<u8>>::read(&FarPtr { bus: bus, segment: seg, offset: si.read() });
mut di: Reg)
where for<'a> FarPtr<'a>: RValue<T> + LValue<T>
{
string_op!((T, flags, rep, cx, si=si, di=di), {
let src = <FarPtr as RValue<T>>::read(&FarPtr { bus: bus, segment: seg, offset: si.read() });
let mut dst = FarPtr { bus: bus, segment: es.read(), offset: di.read() };
<FarPtr as LValue<u8>>::write(&mut dst, src);
});
}
pub fn movsw(flags: &Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
seg: u16,
mut si: Reg,
es: Reg,
mut di: Reg) {
string_op!((u16, flags, rep, cx, si=si, di=di), {
let src = <FarPtr as RValue<u16>>::read(&FarPtr { bus: bus, segment: seg, offset: si.read() });
let mut dst = FarPtr { bus: bus, segment: es.read(), offset: di.read() };
<FarPtr as LValue<u16>>::write(&mut dst, src);
<FarPtr as LValue<T>>::write(&mut dst, src);
});
}
@@ -407,29 +371,19 @@ where T: Operand,
flags.update(FlagOp::SHIFT, dst_before.into(), src_before.into(), res.into(), T::WIDTH);
}
pub fn scasb(flags: &mut Flags,
pub fn scas<T, RVal>(flags: &mut Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
es: Reg,
mut di: Reg,
needle: impl RValue<u8>) {
needle: RVal)
where RVal: RValue<T>,
T: Operand + RValue<T>,
for<'a> FarPtr<'a>: RValue<T>
{
let needle = needle.read();
string_op!((u8, flags, rep, cx, di=di, zf=flags.zf()), {
let elem = FarPtr { bus: bus, segment: es.read(), offset: di.read() };
cmp(flags, elem, needle);
});
}
pub fn scasw(flags: &mut Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
es: Reg,
mut di: Reg,
needle: impl RValue<u16>) {
let needle = needle.read();
string_op!((u16, flags, rep, cx, di=di, zf=flags.zf()), {
string_op!((T, flags, rep, cx, di=di, zf=flags.zf()), {
let elem = FarPtr { bus: bus, segment: es.read(), offset: di.read() };
cmp(flags, elem, needle);
});
@@ -481,27 +435,17 @@ where T: Operand,
flags.update(FlagOp::SHIFT, dst_before.into(), src_before.into(), res.into(), T::WIDTH);
}
pub fn stosb(flags: &Flags,
pub fn stos<T, RVal>(flags: &Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
es: Reg,
mut di: Reg,
val: impl RValue<u8>) {
string_op!((u8, flags, rep, cx, di=di), {
let mut dst = FarPtr { bus: bus, segment: es.read(), offset: di.read() };
dst.write(val.read());
});
}
pub fn stosw(flags: &Flags,
bus: &mut Bus,
rep: RepPrefix,
mut cx: Reg,
es: Reg,
mut di: Reg,
val: impl RValue<u16>) {
string_op!((u16, flags, rep, cx, di=di), {
val: RVal)
where RVal: RValue<T>,
for<'a> FarPtr<'a>: LValue<T>
{
string_op!((T, flags, rep, cx, di=di), {
let mut dst = FarPtr { bus: bus, segment: es.read(), offset: di.read() };
dst.write(val.read());
});