summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/display.rs87
-rw-r--r--src/lib.rs712
2 files changed, 785 insertions, 14 deletions
diff --git a/src/display.rs b/src/display.rs
index dbf4e44..ecd9a26 100644
--- a/src/display.rs
+++ b/src/display.rs
@@ -71,6 +71,15 @@ impl fmt::Display for Instruction {
return write!(f, "{} = or({}, or({}, !{}))", self.dest.as_ref().unwrap(),
self.sources[0], self.sources[1], self.sources[2]);
}
+ Opcode::AddClb => {
+ return write!(f, "{} = add(clb({}), {})", self.dest.as_ref().unwrap(),
+ self.sources[0], self.sources[1]);
+ }
+ Opcode::SfInvsqrta => {
+ return write!(f, "{}, {} = {}({})",
+ self.dest.as_ref().unwrap(), self.alt_dest.as_ref().unwrap(),
+ self.opcode, self.sources[0]);
+ }
_ => {
unreachable!("TODO: should be exhaustive for opcodes with special display rules");
}
@@ -404,6 +413,7 @@ impl fmt::Display for Opcode {
Opcode::Asr => { f.write_str("asr") },
Opcode::Lsr => { f.write_str("lsr") },
Opcode::Asl => { f.write_str("asl") },
+ Opcode::Lsl => { f.write_str("lsl") },
Opcode::Rol => { f.write_str("rol") },
Opcode::Vsathub => { f.write_str("vsathub") },
Opcode::Vsatwuh => { f.write_str("vsatwuh") },
@@ -428,12 +438,8 @@ impl fmt::Display for Opcode {
Opcode::Interleave => { f.write_str("interleave") },
Opcode::Brev => { f.write_str("brev") },
- Opcode::ConvertDf2d => { f.write_str("convert_df2d") },
- Opcode::ConvertDf2ud => { f.write_str("convert_df2ud") },
- Opcode::ConvertUd2df => { f.write_str("convert_ud2df") },
- Opcode::ConvertD2df => { f.write_str("convert_d2df") },
-
Opcode::Extractu => { f.write_str("extractu") },
+ Opcode::Extract => { f.write_str("extract") },
Opcode::Insert => { f.write_str("insert") },
Opcode::TransferRegisterJump => { f.write_str("transferregisterjump") }
@@ -507,8 +513,79 @@ impl fmt::Display for Opcode {
Opcode::OrAndNot => { f.write_str("orandnot") },
Opcode::OrNot => { f.write_str("ornot") },
Opcode::OrOrNot => { f.write_str("orornot") },
+ Opcode::AddClb => { f.write_str("addclb") },
Opcode::Any8 => { f.write_str("any8") },
Opcode::All8 => { f.write_str("all8") },
+ Opcode::Valignb => { f.write_str("valignb") },
+ Opcode::Vspliceb => { f.write_str("vspliceb") },
+ Opcode::Vsxtbh => { f.write_str("vsxtbh") },
+ Opcode::Vzxtbh => { f.write_str("vzxtbh") },
+ Opcode::Vsxthw => { f.write_str("vsxthw") },
+ Opcode::Vzxthw => { f.write_str("vzxthw") },
+ Opcode::Vsplatb => { f.write_str("vsplatb") },
+ Opcode::Vsplath => { f.write_str("vsplath") },
+ Opcode::Vrcrotate => { f.write_str("vrcrotate") },
+ Opcode::Vrmaxh => { f.write_str("vrmaxh") },
+ Opcode::Vrmaxw => { f.write_str("vrmaxw") },
+ Opcode::Vrminh => { f.write_str("vrminh") },
+ Opcode::Vrminw => { f.write_str("vrminw") },
+ Opcode::Vrmaxuh => { f.write_str("vrmaxuh") },
+ Opcode::Vrmaxuw => { f.write_str("vrmaxuw") },
+ Opcode::Vrminuh => { f.write_str("vrminuh") },
+ Opcode::Vrminuw => { f.write_str("vrminuw") },
+ Opcode::Vrcnegh => { f.write_str("vrcnegh") },
+ Opcode::ConvertDf2D => { f.write_str("convert_df2d") },
+ Opcode::ConvertDf2Ud => { f.write_str("convert_df2ud") },
+ Opcode::ConvertUd2Df => { f.write_str("convert_ud2df") },
+ Opcode::ConvertD2Df => { f.write_str("convert_d2df") },
+ Opcode::ConvertD2Sf => { f.write_str("convert_d2sf") },
+ Opcode::ConvertSf2Df => { f.write_str("convert_sf2df") },
+ Opcode::ConvertDf2Sf => { f.write_str("convert_df2sf") },
+ Opcode::ConvertUw2Sf => { f.write_str("convert_uw2sf") },
+ Opcode::ConvertUw2Df => { f.write_str("convert_uw2df") },
+ Opcode::ConvertUd2Sf => { f.write_str("convert_ud2sf") },
+ Opcode::ConvertW2Sf => { f.write_str("convert_w2sf") },
+ Opcode::ConvertW2Df => { f.write_str("convert_w2df") },
+ Opcode::ConvertSf2Uw => { f.write_str("convert_sf2uw") },
+ Opcode::ConvertSf2Ud => { f.write_str("convert_sf2ud") },
+ Opcode::ConvertSf2W => { f.write_str("convert_sf2w") },
+ Opcode::ConvertSf2D => { f.write_str("convert_sf2d") },
+ Opcode::Mask => { f.write_str("mask") },
+ Opcode::Setbit => { f.write_str("setbit") },
+ Opcode::Clrbit => { f.write_str("clrbit") },
+ Opcode::Tstbit => { f.write_str("tstbit") },
+ Opcode::Togglebit => { f.write_str("togglebit") },
+ Opcode::Bitsclr => { f.write_str("bitsclr") },
+ Opcode::Sfclass => { f.write_str("sfclass") },
+ Opcode::Tableidxb => { f.write_str("tableidxb") },
+ Opcode::Tableidxh => { f.write_str("tableidxh") },
+ Opcode::Tableidxw => { f.write_str("tableidxw") },
+ Opcode::Tableidxd => { f.write_str("tableidxd") },
+ Opcode::Vasrhub => { f.write_str("vasrhub") },
+ Opcode::Vrndwh => { f.write_str("vrndwh") },
+ Opcode::Vtrunohb => { f.write_str("vtrunohb") },
+ Opcode::Vtrunehb => { f.write_str("vtrunehb") },
+ Opcode::Normamt => { f.write_str("normamt") },
+ Opcode::Popcount => { f.write_str("popcount") },
+ Opcode::Sat => { f.write_str("sat") },
+ Opcode::Satb => { f.write_str("satb") },
+ Opcode::Sath => { f.write_str("sath") },
+ Opcode::Satub => { f.write_str("satub") },
+ Opcode::Satuh => { f.write_str("satuh") },
+ Opcode::Round => { f.write_str("round") },
+ Opcode::Cround => { f.write_str("cround") },
+ Opcode::Bitsplit => { f.write_str("bitsplit") },
+ Opcode::Clip => { f.write_str("clip") },
+ Opcode::Vclip => { f.write_str("vclip") },
+ Opcode::Clb => { f.write_str("clb") },
+ Opcode::Cl0 => { f.write_str("cl0") },
+ Opcode::Cl1 => { f.write_str("cl1") },
+ Opcode::Ct0 => { f.write_str("ct0") },
+ Opcode::Ct1 => { f.write_str("ct1") },
+ Opcode::Vitpack => { f.write_str("vitpack") },
+ Opcode::SfFixupr => { f.write_str("sffixupr") },
+ Opcode::SfInvsqrta => { f.write_str("sfinvsqrta") },
+ Opcode::Swiz => { f.write_str("swiz") },
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 7a255f8..c225ed1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -489,6 +489,8 @@ pub enum Opcode {
Asr,
Lsr,
Asl,
+ /// logical left shift. is this different from arithmetic left shift? who knows?!
+ Lsl,
Rol,
Vsathub,
Vsatwuh,
@@ -513,12 +515,8 @@ pub enum Opcode {
Interleave,
Brev,
- ConvertDf2d,
- ConvertDf2ud,
- ConvertUd2df,
- ConvertD2df,
-
Extractu,
+ Extract,
Insert,
Trap0,
@@ -581,6 +579,78 @@ pub enum Opcode {
Any8,
All8,
+ Valignb,
+ Vspliceb,
+ Vsxtbh,
+ Vzxtbh,
+ Vsxthw,
+ Vzxthw,
+ Vsplath,
+ Vsplatb,
+ Vrcrotate,
+ Vrmaxh,
+ Vrmaxw,
+ Vrminh,
+ Vrminw,
+ Vrmaxuh,
+ Vrmaxuw,
+ Vrminuh,
+ Vrminuw,
+ Vrcnegh,
+
+ ConvertDf2D,
+ ConvertDf2Ud,
+ ConvertSf2W,
+ ConvertSf2D,
+ ConvertSf2Df,
+ ConvertDf2Sf,
+ ConvertSf2Uw,
+ ConvertSf2Ud,
+ ConvertUd2Df,
+ ConvertUd2Sf,
+ ConvertUw2Sf,
+ ConvertUw2Df,
+ ConvertW2Sf,
+ ConvertW2Df,
+ ConvertD2Df,
+ ConvertD2Sf,
+ Mask,
+ Setbit,
+ Clrbit,
+ Togglebit,
+ Tstbit,
+ Bitsclr,
+ Sfclass,
+ Tableidxb,
+ Tableidxh,
+ Tableidxw,
+ Tableidxd,
+
+ Vasrhub,
+ Vrndwh,
+ Vtrunohb,
+ Vtrunehb,
+ Normamt,
+ Popcount,
+ Sat,
+ Sath,
+ Satb,
+ Satuh,
+ Satub,
+ Round,
+ Cround,
+ Bitsplit,
+ Clip,
+ Vclip,
+ Clb,
+ Cl0,
+ Cl1,
+ Ct0,
+ Ct1,
+ Vitpack,
+ SfFixupr,
+ Swiz,
+
AndAnd = 0x8000,
AndOr,
OrAnd,
@@ -591,6 +661,8 @@ pub enum Opcode {
OrAndNot,
OrNot,
OrOrNot,
+ AddClb,
+ SfInvsqrta,
}
impl Opcode {
@@ -2919,8 +2991,8 @@ fn decode_instruction<
debug_assert!(other == 0b111);
static OPS: [Option<Opcode>; 8] = [
- Some(ConvertDf2d), Some(ConvertDf2ud), Some(ConvertUd2df), Some(ConvertD2df),
- None, None, Some(ConvertDf2d), Some(ConvertDf2ud),
+ Some(ConvertDf2D), Some(ConvertDf2Ud), Some(ConvertUd2Df), Some(ConvertD2Df),
+ None, None, Some(ConvertDf2D), Some(ConvertDf2Ud),
];
handler.on_opcode_decoded(decode_opcode!(OPS[op_low as usize]))?;
opcode_check!(inst & 0x2000 == 0);
@@ -2996,6 +3068,534 @@ fn decode_instruction<
handler.on_source_decoded(Operand::imm_u8(iiiiii as u8))?;
handler.on_source_decoded(Operand::imm_u8(llllll as u8))?;
}
+ 0b0100 => {
+ let ddddd = reg_b0(inst);
+ let sssss = reg_b16(inst);
+
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+
+ let opc_lo = (inst >> 5) & 0b111;
+ let opc_hi = (inst >> 21) & 0b111;
+
+ if opc_hi >= 0b100 {
+ // convert...
+ static CONVERT_OPS: [Option<(Opcode, bool)>; 8] = [
+ Some((ConvertSf2Df, false)), Some((ConvertUw2Df, false)),
+ Some((ConvertW2Df, false)), Some((ConvertSf2Ud, true)),
+ Some((ConvertSf2D, true)), Some((ConvertSf2Ud, true)),
+ Some((ConvertSf2D, true)), None,
+ ];
+ let (opc, check_b13_zero) = decode_opcode!(CONVERT_OPS[opc_lo as usize]);
+ opcode_check!(!check_b13_zero || (inst & 0b0010_0000_0000_0000) == 0);
+ handler.on_opcode_decoded(opc)?;
+
+ if opc_lo > 0b100 {
+ handler.chop()?;
+ }
+ } else if opc_hi >= 0b010 {
+ // vsplat
+ if opc_lo == 0b010 || opc_lo == 0b011 {
+ handler.on_opcode_decoded(Opcode::Vsplath)?;
+ } else if opc_lo == 0b100 || opc_lo == 0b101 {
+ handler.on_opcode_decoded(Opcode::Vsplatb)?;
+ } else {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ } else {
+ static EXT_OPS: [Opcode; 4] = [
+ Vsxtbh, Vzxtbh, Vsxthw, Vzxthw
+ ];
+ handler.on_opcode_decoded(EXT_OPS[(opc_lo >> 1) as usize])?;
+ }
+ }
+ 0b0101 => {
+ let opc_hi = (inst >> 21) & 0b111;
+ let i6 = (inst >> 8) & 0b111111;
+ let dd = inst & 0b11;
+ let sssss = reg_b16(inst);
+
+ handler.on_dest_decoded(Operand::pred(dd as u8))?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+
+ match opc_hi {
+ 0b000 => {
+ handler.on_opcode_decoded(Opcode::Tstbit)?;
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ }
+ 0b001 => {
+ handler.on_opcode_decoded(Opcode::Tstbit)?;
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ handler.negate_result()?;
+ }
+ 0b010 => {
+ handler.on_opcode_decoded(Opcode::TransferRegister)?;
+ }
+ 0b100 => {
+ handler.on_opcode_decoded(Opcode::Bitsclr)?;
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ }
+ 0b101 => {
+ handler.on_opcode_decoded(Opcode::Bitsclr)?;
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ handler.negate_result()?;
+ }
+ 0b111 => {
+ handler.on_opcode_decoded(Opcode::Sfclass)?;
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ 0b0110 => {
+ handler.on_opcode_decoded(Opcode::Mask)?;
+ handler.on_dest_decoded(Operand::gprpair(reg_b0(inst))?)?;
+ handler.on_source_decoded(Operand::pred(reg_b8(inst) & 0b11))?;
+ }
+ 0b0111 => {
+ let l6 = (inst >> 8) & 0b111111;
+ let l6 = ((l6 as i8) << 2) >> 2;
+ let i3 = (inst >> 5) & 0b111;
+ let i_hi = (inst >> 21) & 0b1;
+ let i4 = (i_hi << 3) | i3;
+ let opc = (inst >> 22) & 0b11;
+ static TABLEIDX_OPS: [Opcode; 4] = [
+ Opcode::Tableidxb, Opcode::Tableidxh,
+ Opcode::Tableidxw, Opcode::Tableidxd
+ ];
+
+ handler.on_opcode_decoded(TABLEIDX_OPS[opc as usize])?;
+ handler.on_dest_decoded(Operand::gpr(reg_b0(inst)))?;
+ handler.on_source_decoded(Operand::gpr(reg_b16(inst)))?;
+ handler.on_source_decoded(Operand::imm_u8(i4 as u8))?;
+ handler.on_source_decoded(Operand::imm_i8(l6))?;
+ handler.rounded(RoundingMode::Raw)?;
+ }
+ 0b1000 => {
+ // 1000|1000...
+ let ddddd = reg_b0(inst);
+ let sssss = reg_b16(inst);
+ let opc_lo = (inst >> 5) & 0b111;
+ let opc_hi = (inst >> 21) & 0b111;
+ let opc = opc_lo | (opc_hi << 3);
+
+ static OPCODES: [Option<Opcode>; 64] = [
+ // 000
+ Some(Vsathub), Some(ConvertDf2Sf), Some(Vsatwh), None, Some(Vsatwuh), None, Some(Vsathb), None,
+ // 001
+ None, Some(ConvertUd2Sf), None, None, None, None, None, None,
+ // 010
+ Some(Clb), Some(ConvertD2Sf), Some(Cl0), None, Some(Cl1), None, None, None,
+ // 011
+ Some(Normamt), Some(ConvertSf2Ud), Some(AddClb), Some(Popcount), Some(Vasrhub), Some(Vasrhub), None, None,
+ // 100
+ Some(Vtrunohb), Some(ConvertSf2D), Some(Vtrunehb), None, Some(Vrndwh), None, Some(Vrndwh), None,
+ // 101
+ None, Some(ConvertSf2Ud), None, None, None, None, None, None,
+ // 110
+ Some(Sat), Some(Round), Some(Vasrw), None, Some(Bitsplit), Some(Clip), Some(Vclip), None,
+ // 111
+ None, Some(ConvertSf2D), Some(Ct0), None, Some(Ct1), None, None, None,
+ ];
+
+ let op = decode_opcode!(OPCODES[opc as usize]);
+ handler.on_opcode_decoded(op)?;
+
+ let i6 = (inst >> 8) & 0b111111;
+
+ match opc {
+ 0b100110 |
+ 0b110001 => {
+ operand_check!(i6 < 0b100000);
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.saturate()?;
+ }
+ 0b110101 => {
+ operand_check!(i6 < 0b100000);
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ }
+ 0b110110 => {
+ operand_check!(i6 < 0b100000);
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ }
+ 0b110010 => {
+ operand_check!(i6 < 0b100000);
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ let i6 = (i6 as i8) << 3 >> 3;
+ handler.on_source_decoded(Operand::imm_i8(i6))?;
+ }
+ 0b011001 => {
+ operand_check!(i6 < 0b100000);
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ }
+ 0b011010 => {
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::imm_i8((i6 as i8) << 2 >> 2))?;
+ }
+ 0b011100 => {
+ operand_check!(i6 < 0b10000);
+ handler.rounded(RoundingMode::Raw)?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ }
+ 0b011101 => {
+ operand_check!(i6 < 0b10000);
+ handler.saturate()?;
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ }
+ 0b110100 => {
+ operand_check!(i6 < 0b10000);
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ }
+ 0b100001 |
+ 0b110110 => {
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ }
+ 0b101001 |
+ 0b111001 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.chop();
+ }
+ _ => {
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ }
+ }
+ }
+ 0b1001 => {
+ // 1000|1001...
+ let opc_hi = (inst >> 21) & 0b111;
+
+ let ddddd = reg_b0(inst);
+ let tt = reg_b8(inst) & 0b11;
+ let ss = reg_b16(inst) & 0b11;
+
+ if opc_hi & 0b011 == 0b000 {
+ // vitpack
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::pred(ss))?;
+ handler.on_source_decoded(Operand::pred(tt))?;
+ handler.on_opcode_decoded(Opcode::Vitpack)?;
+ } else if opc_hi & 0b010 == 0b010 {
+ // mov?
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::pred(ss))?;
+ handler.on_opcode_decoded(Opcode::TransferRegister)?;
+ } else {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ 0b1010 => {
+ // 1000|1010...
+ let ddddd = reg_b0(inst);
+ let ttttt = reg_b8(inst);
+ let sssss = reg_b16(inst);
+ let l_lo = (inst >> 5) & 0b111;
+ let l_hi = (inst >> 21) & 0b111;
+ let l6 = l_lo | (l_hi << 3);
+ let i6 = (inst >> 8) & 0b111111;
+
+ handler.on_opcode_decoded(Extract)?;
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::imm_u8(i6 as u8))?;
+ handler.on_source_decoded(Operand::imm_u8(l6 as u8))?;
+ }
+ 0b1011 => {
+ // 1000|1011...
+ let ddddd = reg_b0(inst);
+ let sssss = reg_b16(inst);
+ let op_lo = (inst >> 5) & 0b111;
+ let op_hi = (inst >> 21) & 0b111;
+ let i6 = (inst >> 8) & 0b111111;
+
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+
+ match (op_hi, op_lo) {
+ (0b001, 0b000) => {
+ handler.on_opcode_decoded(Opcode::ConvertUw2Sf)?;
+ }
+ (0b010, 0b000) => {
+ handler.on_opcode_decoded(Opcode::ConvertW2Sf)?;
+ }
+ (0b011, 0b000) => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::ConvertSf2Uw)?;
+ }
+ (0b011, 0b001) => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::ConvertSf2Uw)?;
+ handler.chop()?;
+ }
+ (0b100, 0b010) => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::ConvertSf2W)?;
+ }
+ (0b100, 0b011) => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::ConvertSf2W)?;
+ handler.chop()?;
+ }
+ (0b101, 0b000) => {
+ handler.on_opcode_decoded(Opcode::SfFixupr)?;
+ }
+ (0b111, low) => {
+ operand_check!(low & 0b100 == 0);
+ let ee = (low & 0b11) as u8;
+ handler.on_opcode_decoded(Opcode::SfInvsqrta)?;
+ handler.on_dest_decoded(Operand::pred(ee))?;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ 0b1100 => {
+ let opc_lo = (inst >> 5) & 0b111;
+ let opc_hi = (inst >> 21) & 0b111;
+ let opc = opc_lo | (opc_hi << 3);
+ let ddddd = reg_b0(inst);
+ let sssss = reg_b16(inst);
+ let i6 = ((inst >> 8) & 0b11_1111) as u8;
+
+ if opc & 0b111110 == 0b111010 {
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ } else {
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ }
+
+ match opc {
+ 0b000_000 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Asr)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b000_001 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Lsr)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b000_010 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Asl)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b000_011 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Rol)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b000_100 => {
+ handler.on_opcode_decoded(Opcode::Clb)?;
+ }
+ 0b000_101 => {
+ handler.on_opcode_decoded(Opcode::Cl0)?;
+ }
+ 0b000_110 => {
+ handler.on_opcode_decoded(Opcode::Cl1)?;
+ }
+ 0b000_111 => {
+ handler.on_opcode_decoded(Opcode::Normamt)?;
+ }
+ 0b001_000 => {
+ handler.on_opcode_decoded(Opcode::AddClb)?;
+ handler.on_source_decoded(Operand::imm_i8((i6 as i8) << 2 >> 2))?;
+ }
+ 0b010_000 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Asr)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ handler.rounded(RoundingMode::Round)?;
+ }
+ 0b010_010 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Asl)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ handler.saturate()?;
+ }
+ 0b010_100 => {
+ handler.on_opcode_decoded(Opcode::Ct0)?;
+ }
+ 0b010_101 => {
+ handler.on_opcode_decoded(Opcode::Ct1)?;
+ }
+ 0b010_110 => {
+ handler.on_opcode_decoded(Opcode::Brev)?;
+ }
+ 0b010_111 => {
+ handler.on_opcode_decoded(Opcode::Vsplatb)?;
+ }
+ _ if opc & 0b110_110 == 0b100_000 => {
+ handler.on_opcode_decoded(Opcode::Vsathb)?;
+ }
+ _ if opc & 0b110_110 == 0b100_010 => {
+ handler.on_opcode_decoded(Opcode::Vsathub)?;
+ }
+ 0b100_100 => {
+ handler.on_opcode_decoded(Opcode::Abs)?;
+ }
+ 0b100_101 => {
+ handler.on_opcode_decoded(Opcode::Abs)?;
+ handler.saturate()?;
+ }
+ 0b100_110 => {
+ handler.on_opcode_decoded(Opcode::Neg)?;
+ handler.saturate()?;
+ }
+ 0b100_111 => {
+ handler.on_opcode_decoded(Opcode::Swiz)?;
+ }
+ 0b110_000 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Setbit)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b110_001 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Clrbit)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b110_010 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Togglebit)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b110_100 => {
+ handler.on_opcode_decoded(Opcode::Sath)?;
+ }
+ 0b110_101 => {
+ handler.on_opcode_decoded(Opcode::Satuh)?;
+ }
+ 0b110_110 => {
+ handler.on_opcode_decoded(Opcode::Satub)?;
+ }
+ 0b110_111 => {
+ handler.on_opcode_decoded(Opcode::Satb)?;
+ }
+ 0b111_000 | 0b111_001 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Cround)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b111_010 | 0b111_011 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Cround)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b111_100 | 0b111_101 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Round)?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ 0b111_110 | 0b111_111 => {
+ operand_check!(i6 & 0b10_0000 == 0);
+ handler.on_opcode_decoded(Opcode::Round)?;
+ handler.saturate()?;
+ handler.on_source_decoded(Operand::imm_u8(i6))?;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ 0b1101 => {
+ let ddddd = reg_b0(inst);
+ let sssss = reg_b16(inst);
+ let iiiii = reg_b8(inst);
+ let lll = (inst >> 5) & 0b111;
+ let ll = (inst >> 21) & 0b11;
+ let lllll = (lll | (ll << 3)) as u8;
+ let opc_lo = (inst >> 13) & 1;
+ let opc_hi = (inst >> 23) & 1;
+ let opc = opc_lo | (opc_hi << 1);
+
+ handler.on_dest_decoded(Operand::gpr(ddddd))?;
+
+ match opc {
+ 0b00 => {
+ handler.on_opcode_decoded(Opcode::Extractu)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ }
+ 0b01 => {
+ handler.on_opcode_decoded(Opcode::Mask)?;
+ }
+ 0b10 => {
+ handler.on_opcode_decoded(Opcode::Extract)?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+
+ handler.on_source_decoded(Operand::imm_u8(iiiii))?;
+ handler.on_source_decoded(Operand::imm_u8(lllll))?;
+ }
+ 0b1110 => {
+ let opc_hi = (inst >> 22) & 0b11;
+ let opc_lo = (inst >> 5) & 0b111;
+ let opc = (opc_hi << 3) | opc_lo;
+ let sssss = reg_b16(inst);
+ let xxxxx = reg_b0(inst);
+ let iiiiii = ((inst >> 8) & 0b111111) as u8;
+
+ let assign_mode_bits = (opc >> 2) & 0b111;
+ let shift_op_bits = opc & 0b11;
+
+ let assign_mode = match assign_mode_bits {
+ 0b000 => AssignMode::SubAssign,
+ 0b001 => AssignMode::AddAssign,
+ 0b010 => AssignMode::AndAssign,
+ 0b011 => AssignMode::OrAssign,
+ 0b100 => AssignMode::XorAssign,
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ };
+ let opc = match shift_op_bits {
+ 0b00 => Opcode::Asr,
+ 0b01 => Opcode::Lsr,
+ 0b10 => Opcode::Asl,
+ _ => Opcode::Rol,
+ };
+ handler.on_opcode_decoded(opc)?;
+ handler.assign_mode(assign_mode)?;
+
+ if assign_mode_bits < 0b010 {
+ handler.on_dest_decoded(Operand::gprpair(xxxxx)?)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::imm_u8(iiiiii))?;
+ } else {
+ operand_check!(iiiiii & 0b10_0000 == 0);
+ handler.on_dest_decoded(Operand::gpr(xxxxx))?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_source_decoded(Operand::imm_u8(iiiiii))?;
+ }
+ }
0b1111 => {
opcode_check!(inst & 0x00102000 == 0);
handler.on_source_decoded(Operand::gpr(sssss))?;
@@ -3009,7 +3609,7 @@ fn decode_instruction<
handler.on_source_decoded(Operand::imm_u8(llllll))?;
}
_ => {
- // todo!("the rest");
+ unreachable!("impossible bit pattern");
}
}
}
@@ -3611,7 +4211,24 @@ fn decode_instruction<
0b0000 => {
// 1100|0000|...
let op = (inst >> 23) & 1;
- todo!("valignb, vspliaceb");
+
+ let ddddd = reg_b0(inst);
+ let ttttt = reg_b8(inst);
+ let sssss = reg_b16(inst);
+ let iii = (inst >> 5) & 0b111;
+
+ handler.on_dest_decoded(Operand::gprpair(ddddd)?)?;
+
+ if op == 0 {
+ handler.on_opcode_decoded(Opcode::Valignb)?;
+ handler.on_source_decoded(Operand::gprpair(ttttt)?)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ } else {
+ handler.on_opcode_decoded(Opcode::Vspliceb)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::gprpair(ttttt)?)?;
+ }
+ handler.on_source_decoded(Operand::imm_u8(iii as u8))?;
}
0b0001 => {
let minbits = (inst >> 22) & 0b11;
@@ -3657,9 +4274,86 @@ fn decode_instruction<
}
0b1011 => {
let minbits = (inst >> 21) & 0b111;
+ let op_bits = (inst >> 5) & 0b111;
+ let xxxxx = reg_b0(inst);
+ let ttttt = reg_b8(inst);
+ let sssss = reg_b16(inst);
+
+ handler.on_dest_decoded(Operand::gprpair(xxxxx)?)?;
+ handler.on_source_decoded(Operand::gprpair(sssss)?)?;
+ handler.on_source_decoded(Operand::gpr(ttttt))?;
+
+ if minbits == 0b001 {
+ static OPS: [Option<Opcode>; 16] = [
+ None, Some(Opcode::Vrmaxh), Some(Opcode::Vrmaxw), None,
+ None, Some(Opcode::Vrminh), Some(Opcode::Vrminw), None,
+ None, Some(Opcode::Vrmaxuh), Some(Opcode::Vrmaxuw), None,
+ None, Some(Opcode::Vrminuh), Some(Opcode::Vrminuw), Some(Opcode::Vrcnegh),
+ ];
+ let op_hi = (inst >> 13) & 1;
+ let op = op_bits | (op_hi << 3);
+ let op = decode_opcode!(OPS[op as usize]);
+ handler.on_opcode_decoded(op);
+ if op == Opcode::Vrcnegh {
+ handler.assign_mode(AssignMode::AddAssign)?;
+ }
+ return Ok(());
+ } else if minbits == 0b101 {
+ handler.on_opcode_decoded(Opcode::Vrcrotate)?;
+ handler.assign_mode(AssignMode::AddAssign)?;
+ let i_lo = (inst >> 5) & 1;
+ let i_hi = (inst >> 13) & 1;
+ let ii = i_lo | (i_hi << 1);
+ handler.on_source_decoded(Operand::imm_u8(ii as u8))?;
+ return Ok(());
+ }
+
+ let assign_mode = match minbits {
+ 0b000 => AssignMode::OrAssign,
+ 0b010 => AssignMode::AndAssign,
+ 0b011 => AssignMode::XorAssign,
+ 0b100 => AssignMode::SubAssign,
+ 0b110 => AssignMode::AddAssign,
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ };
+ let opc = match op_bits >> 1 {
+ 0b00 => Opcode::Asr,
+ 0b01 => Opcode::Lsr,
+ 0b10 => Opcode::Asl,
+ _ => Opcode::Lsl,
+ };
+ handler.on_opcode_decoded(opc)?;
+ handler.assign_mode(assign_mode)?;
}
0b1100 => {
let minbits = (inst >> 22) & 0b11;
+ let op_bits = (inst >> 6) & 0b11;
+ let xxxxx = reg_b0(inst);
+ let ttttt = reg_b8(inst);
+ let sssss = reg_b16(inst);
+
+ let assign_mode = match minbits {
+ 0b00 => AssignMode::OrAssign,
+ 0b01 => AssignMode::AndAssign,
+ 0b10 => AssignMode::SubAssign,
+ 0b11 => AssignMode::AddAssign,
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ };
+ let opc = match op_bits {
+ 0b00 => Opcode::Asr,
+ 0b01 => Opcode::Lsr,
+ 0b10 => Opcode::Asl,
+ _ => Opcode::Lsl,
+ };
+ handler.on_opcode_decoded(opc)?;
+ handler.assign_mode(assign_mode)?;
+ handler.on_dest_decoded(Operand::gpr(xxxxx))?;
+ handler.on_source_decoded(Operand::gpr(sssss))?;
+ handler.on_source_decoded(Operand::gpr(ttttt))?;
}
0b1101 |
0b1110 |