From 6d184b08460452619dfffda282db6c713c78a6dc Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 3 Feb 2020 00:21:04 -0800 Subject: clean up incorrect handling of jump displacements, bit operands also snuck in: display for Operand::RegList, RegDerefDisp20Abs (for particularly wide instructions) selected the wrong operands, generally behaving as if it were decoding 16-bit rather than 32-bit operands. --- src/lib.rs | 168 +++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 113 insertions(+), 55 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 67968a8..32baa40 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,8 +82,7 @@ pub enum Opcode { JPZ, JSRI, JSRS, - JSR_A, - JSR_W, + JSR(Size), LDC, LDCTX, LDE, @@ -208,8 +207,7 @@ impl fmt::Display for Opcode { Opcode::JPZ => write!(f, "jpz"), Opcode::JSRI => write!(f, "jsri"), Opcode::JSRS => write!(f, "jsrs"), - Opcode::JSR_A => write!(f, "jsr_a"), - Opcode::JSR_W => write!(f, "jsr_w"), + Opcode::JSR(size) => write!(f, "jsr.{}", size), Opcode::LDC => write!(f, "ldc"), Opcode::LDCTX => write!(f, "ldctx"), Opcode::LDE => write!(f, "lde"), @@ -322,20 +320,50 @@ pub enum Operand { RegisterBit(Register, u8), ImmediateI16(i16), ImmediateU16(u16), - RegDerefBit(Register, i16), + RegDerefBit(Register), + A0A1DispBit(Register, u16), + RegDispBit(Register, u16, u8), RegDeref(Register, i16), AbsoluteBit(u16), Absolute(u32), + JmpAbsolute(u32), Displacement(i16), + JmpDisplacement(i16), RegList(u8), } impl fmt::Display for Operand { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use Operand::*; match self { - Register(reg) => write!(f, "{}", reg), - ImmediateI16(imm) => { + Operand::RegList(list) => { + let regs = [ + Register::FB, + Register::SB, + Register::A1, + Register::A0, + Register::R3, + Register::R2, + Register::R1, + Register::R0, + ]; + + let mut printed = false; + + for i in 0..8 { + if list & (1 << i) != 0 { + if printed { + write!(f, ", ")?; + } else { + printed = true; + } + write!(f, "{}", regs[i as usize])?; + } + } + + Ok(()) + } + Operand::Register(reg) => write!(f, "{}", reg), + Operand::ImmediateI16(imm) => { if *imm == core::i16::MIN { write!(f, "#-8000h") } else if *imm < 0 { @@ -344,8 +372,17 @@ impl fmt::Display for Operand { write!(f, "#{:02x}h", *imm) } }, - ImmediateU16(imm) => write!(f, "#{:02x}h", imm), - RegDeref(reg, offset) => { + Operand::ImmediateU16(imm) => write!(f, "#{:02x}h", imm), + Operand::RegDerefBit(reg) => { + write!(f, "bit,[{}]", reg) + } + Operand::A0A1DispBit(reg, offset) => { + write!(f, "{}[{}]", offset, reg) + } + Operand::RegDispBit(reg, offset, bit) => { + write!(f, "{},{}[{}]", bit, offset, reg) + } + Operand::RegDeref(reg, offset) => { if *offset == core::i16::MIN { write!(f, "#-8000h") } else if *offset == 0 { @@ -356,7 +393,7 @@ impl fmt::Display for Operand { write!(f, "{}[{}]", offset, reg) } } - Displacement(offset) => { + Operand::JmpDisplacement(offset) => { if *offset == core::i16::MIN { write!(f, "$-32768") } else if *offset < 0 { @@ -365,6 +402,21 @@ impl fmt::Display for Operand { write!(f, "$+{}", *offset) } } + Operand::Displacement(offset) => { + if *offset == core::i16::MIN { + write!(f, "[$-32768]") + } else if *offset < 0 { + write!(f, "[$-{}]", -*offset) + } else { + write!(f, "[$+{}]", *offset) + } + } + Operand::Absolute(addr) => { + write!(f, "[#{:x}h]", addr) + } + Operand::JmpAbsolute(addr) => { + write!(f, "#{:x}h", addr) + } _ => Ok(()) } } @@ -440,8 +492,10 @@ enum OperandSpec { Disp2_16_SB, Abs2_16, Abs20, + JmpAbs20, Disp8, - Disp16, + JmpDisp8, + JmpDisp16, RegList, INTBL, INTBH, @@ -540,15 +594,15 @@ impl Instruction { Bit_R3 => Operand::RegisterBit(Register::R3, self.dispabs as u8), Bit_A0 => Operand::RegisterBit(Register::A0, self.dispabs as u8), Bit_A1 => Operand::RegisterBit(Register::A1, self.dispabs as u8), - Bit_Deref_A0 => Operand::RegDerefBit(Register::A0, 0), - Bit_Deref_A1 => Operand::RegDerefBit(Register::A1, 0), - Bit_Disp8_A0 => Operand::RegDerefBit(Register::A0, self.dispabs as i16), - Bit_Disp8_A1 => Operand::RegDerefBit(Register::A1, self.dispabs as i16), - Bit_Disp8_SB => Operand::RegDerefBit(Register::SB, self.dispabs as i16), - Bit_Disp8_FB => Operand::RegDerefBit(Register::FB, self.dispabs as i16), - Bit_Disp16_A0 => Operand::RegDerefBit(Register::A0, self.dispabs as i16), - Bit_Disp16_A1 => Operand::RegDerefBit(Register::A1, self.dispabs as i16), - Bit_Disp16_SB => Operand::RegDerefBit(Register::SB, self.dispabs as i16), + Bit_Deref_A0 => Operand::RegDerefBit(Register::A0), + Bit_Deref_A1 => Operand::RegDerefBit(Register::A1), + Bit_Disp8_A0 => Operand::A0A1DispBit(Register::A0, self.dispabs as u8 as u16), + Bit_Disp8_A1 => Operand::A0A1DispBit(Register::A1, self.dispabs as u8 as u16), + Bit_Disp8_SB => Operand::RegDispBit(Register::SB, (self.dispabs as u8 >> 3) as u16, self.dispabs as u8 & 0b111), + Bit_Disp8_FB => Operand::RegDispBit(Register::FB, (self.dispabs as u8 >> 3) as u16, self.dispabs as u8 & 0b111), + Bit_Disp16_A0 => Operand::A0A1DispBit(Register::A0, self.dispabs as u16), + Bit_Disp16_A1 => Operand::A0A1DispBit(Register::A1, self.dispabs as u16), + Bit_Disp16_SB => Operand::RegDispBit(Register::SB, self.dispabs as u16 >> 4, self.dispabs as u8 & 0b1111), Bit_Abs16 => Operand::AbsoluteBit(self.dispabs), Disp8_A0 => Operand::RegDeref(Register::A0, self.dispabs as i8 as i16), Disp8_A1 => Operand::RegDeref(Register::A1, self.dispabs as i8 as i16), @@ -573,8 +627,10 @@ impl Instruction { Disp2_16_SB => Operand::RegDeref(Register::SB, self.imm_wide as i16), Abs2_16 => Operand::Absolute(self.imm_wide), Abs20 => Operand::Absolute(self.imm_wide), + JmpAbs20 => Operand::JmpAbsolute(self.imm_wide), Disp8 => Operand::Displacement(self.dispabs as u8 as i8 as i16), - Disp16 => Operand::Displacement(self.dispabs as i16), + JmpDisp8 => Operand::JmpDisplacement(self.dispabs as u8 as i8 as i16), + JmpDisp16 => Operand::JmpDisplacement(self.dispabs as i16), RegList => Operand::RegList(self.imm_wide as u8), INTBL => Operand::Register(Register::INTBL), INTBH => Operand::Register(Register::INTBH), @@ -701,7 +757,7 @@ enum OperandCategory { OpEB, SrcDestRegOrDeref, Imm4Dest, - DispOpcodeLow3, + JmpDispOpcodeLow3, } enum OperandInterpretation { @@ -816,22 +872,22 @@ fn decode>(_decoder: &InstDecoder, inst: &mut Instruction, 0b0101_1101 => (Opcode::BTST, Just([OperandSpec::Bit5, OperandSpec::Disp8_SB, OperandSpec::Nothing])), 0b0101_1110 => (Opcode::BTST, Just([OperandSpec::Bit6, OperandSpec::Disp8_SB, OperandSpec::Nothing])), 0b0101_1111 => (Opcode::BTST, Just([OperandSpec::Bit7, OperandSpec::Disp8_SB, OperandSpec::Nothing])), - 0b0110_0000 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::DispOpcodeLow3)), - 0b0110_0001 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::DispOpcodeLow3)), - 0b0110_0010 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::DispOpcodeLow3)), - 0b0110_0011 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::DispOpcodeLow3)), - 0b0110_0100 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::DispOpcodeLow3)), - 0b0110_0101 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::DispOpcodeLow3)), - 0b0110_0110 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::DispOpcodeLow3)), - 0b0110_0111 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::DispOpcodeLow3)), - 0b0110_1000 => (Opcode::JGEU, Just([OperandSpec::Disp8, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b0110_1001 => (Opcode::JGTU, Just([OperandSpec::Disp8, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b0110_1010 => (Opcode::JEQ, Just([OperandSpec::Disp8, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b0110_1011 => (Opcode::JN, Just([OperandSpec::Disp8, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b0110_1100 => (Opcode::JLTU, Just([OperandSpec::Disp8, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b0110_1101 => (Opcode::JLEU, Just([OperandSpec::Disp8, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b0110_1110 => (Opcode::JNE, Just([OperandSpec::Disp8, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b0110_1111 => (Opcode::JPZ, Just([OperandSpec::Disp8, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b0110_0000 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::JmpDispOpcodeLow3)), + 0b0110_0001 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::JmpDispOpcodeLow3)), + 0b0110_0010 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::JmpDispOpcodeLow3)), + 0b0110_0011 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::JmpDispOpcodeLow3)), + 0b0110_0100 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::JmpDispOpcodeLow3)), + 0b0110_0101 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::JmpDispOpcodeLow3)), + 0b0110_0110 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::JmpDispOpcodeLow3)), + 0b0110_0111 => (Opcode::JMP(Size::S), Reinterpret(OperandCategory::JmpDispOpcodeLow3)), + 0b0110_1000 => (Opcode::JGEU, Just([OperandSpec::JmpDisp8, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b0110_1001 => (Opcode::JGTU, Just([OperandSpec::JmpDisp8, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b0110_1010 => (Opcode::JEQ, Just([OperandSpec::JmpDisp8, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b0110_1011 => (Opcode::JN, Just([OperandSpec::JmpDisp8, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b0110_1100 => (Opcode::JLTU, Just([OperandSpec::JmpDisp8, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b0110_1101 => (Opcode::JLEU, Just([OperandSpec::JmpDisp8, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b0110_1110 => (Opcode::JNE, Just([OperandSpec::JmpDisp8, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b0110_1111 => (Opcode::JPZ, Just([OperandSpec::JmpDisp8, OperandSpec::Nothing, OperandSpec::Nothing])), 0b0111_0000 => (Opcode::MULU(size), Reinterpret(OperandCategory::SrcDestRegOrDeref)), 0b0111_0001 => (Opcode::MULU(size), Reinterpret(OperandCategory::SrcDestRegOrDeref)), 0b0111_0010 => (Opcode::MOV(size), Reinterpret(OperandCategory::SrcDestRegOrDeref)), @@ -964,17 +1020,17 @@ fn decode>(_decoder: &InstDecoder, inst: &mut Instruction, 0b1111_0001 => (Opcode::SHA(size), Reinterpret(OperandCategory::Imm4Dest)), 0b1111_0010 => (Opcode::DEC(Size::W), Just([OperandSpec::A0, OperandSpec::Nothing, OperandSpec::Nothing])), 0b1111_0011 => (Opcode::RTS, Just([OperandSpec::Nothing, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b1111_0100 => (Opcode::JMP(Size::W), Just([OperandSpec::Disp16, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b1111_0101 => (Opcode::JSR_W, Just([OperandSpec::Disp16, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b1111_0100 => (Opcode::JMP(Size::W), Just([OperandSpec::JmpDisp16, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b1111_0101 => (Opcode::JSR(Size::W), Just([OperandSpec::JmpDisp16, OperandSpec::Nothing, OperandSpec::Nothing])), 0b1111_0110 => (Opcode::INTO, Just([OperandSpec::Nothing, OperandSpec::Nothing, OperandSpec::Nothing])), 0b1111_0111 => { return Err(DecodeError::InvalidOperand); }, 0b1111_1000 => (Opcode::ADJNZ(size), Reinterpret(OperandCategory::ADJNZ)), 0b1111_1001 => (Opcode::ADJNZ(size), Reinterpret(OperandCategory::ADJNZ)), 0b1111_1010 => (Opcode::DEC(Size::W), Just([OperandSpec::A1, OperandSpec::Nothing, OperandSpec::Nothing])), 0b1111_1011 => (Opcode::REIT, Just([OperandSpec::Nothing, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b1111_1100 => (Opcode::JMP(Size::A), Just([OperandSpec::Abs20, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b1111_1101 => (Opcode::JSR_A, Just([OperandSpec::Abs20, OperandSpec::Nothing, OperandSpec::Nothing])), - 0b1111_1110 => (Opcode::JMP(Size::B), Just([OperandSpec::Disp8, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b1111_1100 => (Opcode::JMP(Size::A), Just([OperandSpec::JmpAbs20, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b1111_1101 => (Opcode::JSR(Size::A), Just([OperandSpec::JmpAbs20, OperandSpec::Nothing, OperandSpec::Nothing])), + 0b1111_1110 => (Opcode::JMP(Size::B), Just([OperandSpec::JmpDisp8, OperandSpec::Nothing, OperandSpec::Nothing])), 0b1111_1111 => (Opcode::UND, Just([OperandSpec::Nothing, OperandSpec::Nothing, OperandSpec::Nothing])), }; inst.opcode = opcode; @@ -1001,6 +1057,7 @@ fn decode>(_decoder: &InstDecoder, inst: &mut Instruction, inst.imm_wide = read_imm(bytes, 1)? as u32; inst.length += 1; }, + JmpDisp8 | Disp8 | Disp8_FB | Disp8_SB => { @@ -1008,13 +1065,14 @@ fn decode>(_decoder: &InstDecoder, inst: &mut Instruction, inst.dispabs = read_imm(bytes, 1)? as i8 as i16 as u16; inst.length += 1; } - Disp16 | + JmpDisp16 | Abs16 => { inst.dispabs = read_imm(bytes, 2)? as u16; inst.length += 2; } + JmpAbs20 | Abs20 => { - inst.dispabs = read_imm(bytes, 3)? as u16; + inst.imm_wide = read_imm(bytes, 3)? as u32 & 0x0f_ff_ff; inst.length += 3; } Disp8_A0 | @@ -1094,7 +1152,7 @@ fn decode>(_decoder: &InstDecoder, inst: &mut Instruction, inst.operands[1] = Operand_RegDerefDispAbs(operands & 0b1111, size, inst, bytes)?; inst.operands[2] = OperandSpec::Nothing; } - Reinterpret(OperandCategory::DispOpcodeLow3) => { + Reinterpret(OperandCategory::JmpDispOpcodeLow3) => { inst.dispabs = (byte & 0b111) as u16; inst.operands[0] = OperandSpec::Disp8; inst.operands[1] = OperandSpec::Nothing; @@ -1589,7 +1647,7 @@ fn decode_op7D>(inst: &mut Instruction, size: Size, bytes: Opcode::JMPI, Opcode::JSRI, Opcode::JMPI, Opcode::JSRI, ][op as usize]; - inst.operands[0] = Operand_RegDerefDisp20Abs(byte & 0b1111, size, inst, bytes)?; + inst.operands[0] = Operand_RegDerefDisp20Abs(byte & 0b1111, inst, bytes)?; inst.operands[1] = OperandSpec::Nothing; } 0b0100 => { @@ -2027,15 +2085,15 @@ fn Operand_second_RegDerefDispAbs>(code: u8, size: Size, in Ok(spec) } -fn Operand_RegDerefDisp20Abs>(code: u8, size: Size, inst: &mut Instruction, bytes: &mut T) -> Result { +fn Operand_RegDerefDisp20Abs>(code: u8, inst: &mut Instruction, bytes: &mut T) -> Result { use OperandSpec::*; let (imm_size, spec) = match code { - 0b0000 => (0, { if size == Size::B { R0L } else { R0 } }), - 0b0001 => (0, { if size == Size::B { R0H } else { R1 } }), - 0b0010 => (0, { if size == Size::B { R1L } else { R2 } }), - 0b0011 => (0, { if size == Size::B { R1H } else { R3 } }), - 0b0100 => (0, A0), - 0b0101 => (0, A1), + 0b0000 => (0, R2R0), + 0b0001 => (0, R3R1), + 0b0010 => { return Err(DecodeError::InvalidOperand); }, + 0b0011 => { return Err(DecodeError::InvalidOperand); }, + 0b0100 => (0, A1A0), + 0b0101 => { return Err(DecodeError::InvalidOperand); }, 0b0110 => (0, Deref_A0), 0b0111 => (0, Deref_A1), 0b1000 => (1, Disp8_A0), -- cgit v1.1