From 7f315862ad9d88fefff0d420c93a34ece0cc9eb2 Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 21 Mar 2025 23:42:52 -0700 Subject: assign-merge is recorded now, 0100.. is decoded --- src/lib.rs | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 176 insertions(+), 21 deletions(-) (limited to 'src/lib.rs') diff --git a/src/lib.rs b/src/lib.rs index 6537bfd..a046abd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -292,6 +292,17 @@ impl RoundingMode { } #[derive(Debug, Copy, Clone)] +enum AssignMode { + AddAssign, + SubAssign, + AndAssign, + OrAssign, + XorAssign, + ClrBit, + SetBit, +} + +#[derive(Debug, Copy, Clone)] struct InstFlags { predicate: Option, branch_hint: Option, @@ -300,6 +311,7 @@ struct InstFlags { chop: bool, rounded: Option, threads: Option, + assign_mode: Option, } #[derive(Debug, Copy, Clone)] @@ -318,6 +330,7 @@ impl Default for InstFlags { chop: false, rounded: None, threads: None, + assign_mode: None, } } } @@ -994,6 +1007,7 @@ trait DecodeHandler::Address, ::Wor fn on_opcode_decoded(&mut self, _opcode: Opcode) -> Result<(), ::DecodeError> { Ok(()) } fn on_source_decoded(&mut self, _operand: Operand) -> Result<(), ::DecodeError> { Ok(()) } fn on_dest_decoded(&mut self, _operand: Operand) -> Result<(), ::DecodeError> { Ok(()) } + fn assign_mode(&mut self, _assign_mode: AssignMode) -> Result<(), ::DecodeError> { Ok(()) } fn inst_predicated(&mut self, num: u8, negated: bool, pred_new: bool) -> Result<(), ::DecodeError> { Ok(()) } fn negate_result(&mut self) -> Result<(), ::DecodeError> { Ok(()) } fn saturate(&mut self) -> Result<(), ::DecodeError> { Ok(()) } @@ -1033,6 +1047,11 @@ impl::Address, ::Word } Ok(()) } + fn assign_mode(&mut self, assign_mode: AssignMode) -> Result<(), ::DecodeError> { + let mut inst = &mut self.instructions[self.instruction_count as usize]; + inst.flags.assign_mode = Some(assign_mode); + Ok(()) + } fn inst_predicated(&mut self, num: u8, negated: bool, pred_new: bool) -> Result<(), ::DecodeError> { let mut flags = &mut self.instructions[self.instruction_count as usize].flags; assert!(flags.predicate.is_none()); @@ -1164,6 +1183,52 @@ fn decode_store_ops< Ok(()) } +// very much like `decode_store_ops`, except for some instructions the strategy is for loads +// instead. +fn decode_load_ops< + T: Reader<::Address, ::Word>, + H: DecodeHandler, +>(handler: &mut H, opbits: u8, dstreg: u8, src_op: impl Fn(u8) -> Operand) -> Result<(), DecodeError> { + // for loads, there's none of the carveout for `R.new` or high register halves. + // just mem{b,ub,h,uh,w,d} + match opbits { + 0b000 => { + handler.on_opcode_decoded(Opcode::LoadMemb)?; + handler.on_dest_decoded(Operand::gpr(dstreg))?; + handler.on_source_decoded(src_op(0))?; + } + 0b001 => { + handler.on_opcode_decoded(Opcode::LoadMemub)?; + handler.on_dest_decoded(Operand::gpr(dstreg))?; + handler.on_source_decoded(src_op(0))?; + } + 0b010 => { + handler.on_opcode_decoded(Opcode::LoadMemh)?; + handler.on_dest_decoded(Operand::gpr(dstreg))?; + handler.on_source_decoded(src_op(1))?; + } + 0b011 => { + handler.on_opcode_decoded(Opcode::LoadMemuh)?; + handler.on_dest_decoded(Operand::gpr(dstreg))?; + handler.on_source_decoded(src_op(1))?; + } + 0b100 => { + handler.on_opcode_decoded(Opcode::LoadMemw)?; + handler.on_dest_decoded(Operand::gpr(dstreg))?; + handler.on_source_decoded(src_op(2))?; + } + 0b110 => { + handler.on_opcode_decoded(Opcode::LoadMemd)?; + handler.on_dest_decoded(Operand::gprpair(dstreg)?)?; + handler.on_source_decoded(src_op(3))?; + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + Ok(()) +} + fn decode_packet< T: Reader<::Address, ::Word>, H: DecodeHandler, @@ -1640,6 +1705,7 @@ fn decode_instruction< let opc_upper = opc_bits >> 3; let opc_lower = opc_bits & 0b11; let uuuuuu = (inst >> 7) & 0b111111; + let sssss = (inst >> 16) & 0b11111; match opc_upper { 0b00 | @@ -1648,25 +1714,81 @@ fn decode_instruction< let i_hi = ((inst >> 13) & 0b1) << 7; let i = i_hi | i7; - (match opc_upper { + handler.on_opcode_decoded(match opc_lower { 0b00 => { - handler.on_opcode_decoded(Opcode::StoreMemb)?; + Opcode::StoreMemb } 0b01 => { - Ok(Opcode::StoreMemh), + Opcode::StoreMemh } 0b10 => { - Ok(Opcode::StoreMemd), + Opcode::StoreMemw } - _ => Err(DecodeError::InvalidOpcode) - }?)?; + _ => { return Err(DecodeError::InvalidOpcode); } + })?; handler.on_source_decoded(Operand::imm_i8(i as i8))?; + handler.on_dest_decoded(Operand::RegOffset { + base: sssss as u8, + offset: (uuuuuu as u32) << opc_lower, + })?; }, 0b10 => { + opcode_check!(inst & 0b0010_0000_0000_0000 == 0); + let ttttt = inst & 0b11111; + let assign_mode = (inst >> 5) & 0b11; + handler.on_opcode_decoded(match opc_lower { + 0b00 => { + Opcode::StoreMemb + } + 0b01 => { + Opcode::StoreMemh + } + 0b10 => { + Opcode::StoreMemw + } + _ => { return Err(DecodeError::InvalidOpcode); } + })?; + handler.assign_mode(match assign_mode { + 0b00 => AssignMode::AddAssign, + 0b01 => AssignMode::SubAssign, + 0b10 => AssignMode::AndAssign, + _ => AssignMode::OrAssign, + })?; + handler.on_source_decoded(Operand::gpr(ttttt as u8))?; + handler.on_dest_decoded(Operand::RegOffset { + base: sssss as u8, + offset: (uuuuuu as u32) << opc_lower, + })?; }, _ => { - panic!("TODO: other: {}", other); + opcode_check!(inst & 0b0010_0000_0000_0000 == 0); + let ttttt = inst & 0b11111; + let assign_mode = (inst >> 5) & 0b11; + + handler.on_opcode_decoded(match opc_lower { + 0b00 => { + Opcode::StoreMemb + } + 0b01 => { + Opcode::StoreMemh + } + 0b10 => { + Opcode::StoreMemw + } + _ => { return Err(DecodeError::InvalidOpcode); } + })?; + handler.assign_mode(match assign_mode { + 0b00 => AssignMode::AddAssign, + 0b01 => AssignMode::SubAssign, + 0b10 => AssignMode::ClrBit, + _ => AssignMode::SetBit, + })?; + handler.on_source_decoded(Operand::imm_u8(ttttt as u8))?; + handler.on_dest_decoded(Operand::RegOffset { + base: sssss as u8, + offset: (uuuuuu as u32) << opc_lower, + })?; } } } @@ -1676,34 +1798,67 @@ fn decode_instruction< // 0 1 0 0|... // loads and stores with large (6b+) offsets let predicated = (inst >> 27) & 1 == 0; - let load = (inst >> 24) & 1 == 0; + let store = (inst >> 24) & 1 == 0; if predicated { - let dotnew = (inst >> 23) & 0b1 == 1; - let negated = (inst >> 22) & 0b1 == 0; - let pred_reg = (inst >> 11) & 0b11; - handler.inst_predicated(pred_reg as u8, negated, dotnew)?; + let dotnew = (inst >> 26) & 0b1 == 1; + let negated = (inst >> 25) & 0b1 == 1; + + let opbits = (inst >> 21) & 0b111; + let sssss = reg_b16(inst); + + if store { + let pred_reg = inst & 0b11; + handler.inst_predicated(pred_reg as u8, negated, dotnew)?; - if load { + let srcreg = reg_b8(inst); + let i5 = (inst >> 3) & 0b11111; + let i = ((inst >> 13) & 1) << 5; + let iiiiii = i | i5; + + decode_store_ops(handler, opbits as u8, srcreg as u8, |shamt| { + Operand::RegOffset { + base: sssss as u8, + offset: iiiiii << shamt + } + })?; } else { + let pred_reg = (inst >> 11) & 0b11; + handler.inst_predicated(pred_reg as u8, negated, dotnew)?; + + let dstreg = reg_b0(inst); + let iiiiii = (inst >> 5) & 0b111111; + + decode_load_ops(handler, opbits as u8, dstreg as u8, |shamt| { + Operand::RegOffset { + base: sssss as u8, + offset: iiiiii << shamt + } + })?; } } else { let i14 = (inst >> 25) & 0b11; let i9 = (inst >> 16) & 0b11111; let i_8 = (inst >> 13) & 0b1; - if load { - let i_lo = (inst >> 5) & 0b11111111; + let opbits = ((inst >> 21) & 0b111) as u8; + + if store { + let i_lo = inst & 0b1111_1111; let i = (i14 << 14) | (i9 << 9) | (i_8 << 8) | i_lo; - let ddddd = reg_b0(inst); - let opc = (inst >> 21) & 0b111; + let ttttt = reg_b8(inst); + + decode_store_ops(handler, opbits, ttttt, |shamt| { + Operand::GpOffset { + offset: i << shamt + } + })?; } else { - let i_lo = inst & 0b11111111; + let i_lo = (inst >> 5) & 0b1111_1111; let i = (i14 << 14) | (i9 << 9) | (i_8 << 8) | i_lo; - let ttttt = reg_b8(inst); - let opc = ((inst >> 21) & 0b111) as u8; + let ddddd = reg_b0(inst); - decode_store_ops(handler, opc, ttttt, |shamt| { + decode_load_ops(handler, opbits, ddddd, |shamt| { Operand::GpOffset { offset: i << shamt } })?; } -- cgit v1.1