diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/display.rs | 55 | ||||
-rw-r--r-- | src/lib.rs | 92 |
2 files changed, 113 insertions, 34 deletions
diff --git a/src/display.rs b/src/display.rs index bc3a418..46fd534 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,6 +1,7 @@ use core::fmt; use crate::{Instruction, InstructionPacket, Opcode, Operand}; +use crate::{BranchHint, DomainHint}; impl fmt::Display for InstructionPacket { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -74,11 +75,29 @@ impl fmt::Display for Instruction { // stores put the mnemonic on LHS static STORES: &[Opcode] = &[ - Opcode::StoreMemb, Opcode::StoreMemh, Opcode::StoreMemw, Opcode::StoreMemd + Opcode::StoreMemb, Opcode::StoreMemh, Opcode::StoreMemw, Opcode::StoreMemd, Opcode::MemwRl, Opcode::MemdRl ]; if STORES.contains(&self.opcode) { - write!(f, "{}({}) = {}", + write!(f, "{}({}){} = {}", self.opcode, self.dest.expect("TODO: unreachable; store has a destination"), + match self.flags.threads { + Some(DomainHint::Same) => { ":st" }, + Some(DomainHint::All) => { ":at" }, + None => { "" } + }, + self.sources[0] + )?; + return Ok(()); + } + + static SC_STORES: &[Opcode] = &[ + Opcode::MemwStoreCond, Opcode::MemdStoreCond, + ]; + if SC_STORES.contains(&self.opcode) { + write!(f, "{}({}, {}) = {}", + self.opcode, + self.dest.expect("TODO: unreachable; store has a destination"), + self.alt_dest.expect("TODO: unreachable; store-conditional has a predicate reg"), self.sources[0] )?; return Ok(()); @@ -94,8 +113,6 @@ impl fmt::Display for Instruction { return Ok(()); } - use crate::BranchHint; - static CONDITIONAL_JUMPS: &[Opcode] = &[ Opcode::JumpEq, Opcode::JumpNeq, Opcode::JumpGt, Opcode::JumpLe, Opcode::JumpGtu, Opcode::JumpLeu, Opcode::JumpBitSet, Opcode::JumpBitClear, @@ -179,11 +196,17 @@ impl fmt::Display for Instruction { Some(BranchHint::Taken) => { f.write_str(":t")? }, Some(BranchHint::NotTaken) => { f.write_str(":nt")? }, None => {} - }; + } + + match self.flags.threads { + Some(DomainHint::Same) => { f.write_str(":st")? }, + Some(DomainHint::All) => { f.write_str(":at")? }, + None => {} + } // DeallocateFrame is shown with `:raw` as a suffix, but after the taken/not-taken hint // same for DeallocReturn - if self.opcode == Opcode::DeallocFrame || self.opcode == Opcode::DeallocReturn { + if self.opcode == Opcode::AllocFrame || self.opcode == Opcode::DeallocFrame || self.opcode == Opcode::DeallocReturn { f.write_str(":raw")?; } Ok(()) @@ -328,23 +351,29 @@ impl fmt::Display for Opcode { Opcode::DcInvA => { f.write_str("dcinva") }, Opcode::DcCleanInvA => { f.write_str("dccleaninva") }, Opcode::DcZeroA => { f.write_str("dczeroa") }, - Opcode::L2Fetch => { f.write_str("l2fet_ch") }, - Opcode::DmSyncHt => { f.write_str("dmsyncht_") }, - Opcode::SyncHt => { f.write_str("syncht_") }, + Opcode::L2Fetch => { f.write_str("l2fetch") }, + Opcode::DmSyncHt => { f.write_str("dmsyncht") }, + Opcode::SyncHt => { f.write_str("syncht") }, Opcode::Release => { f.write_str("release") }, Opcode::Barrier => { f.write_str("barrier") }, Opcode::AllocFrame => { f.write_str("allocframe") }, - Opcode::MemwRl => { f.write_str("memwrl") }, - Opcode::MemdRl => { f.write_str("memdrl") }, + Opcode::MemwRl => { f.write_str("memw_rl") }, + Opcode::MemdRl => { f.write_str("memd_rl") }, Opcode::DeallocFrame => { f.write_str("deallocframe") }, Opcode::DeallocReturn => { f.write_str("dealloc_return") }, Opcode::Dcfetch => { f.write_str("dcfetch") }, - Opcode::MemwLocked => { f.write_str("memw_locked") }, + // LL/SC ops are distinguished by where they are in an instruction, not by their + // textual representation + Opcode::MemwLockedLoad => { f.write_str("memw_locked") }, + Opcode::MemwStoreCond => { f.write_str("memw_locked") }, Opcode::MemwAq => { f.write_str("memw_aq") }, - Opcode::MemdLocked => { f.write_str("memd_locked") }, + // LL/SC ops are distinguished by where they are in an instruction, not by their + // textual representation + Opcode::MemdLockedLoad => { f.write_str("memd_locked") }, + Opcode::MemdStoreCond => { f.write_str("memd_locked") }, Opcode::MemdAq => { f.write_str("memd_aq") }, } } @@ -261,11 +261,14 @@ pub struct Instruction { opcode: Opcode, dest: Option<Operand>, // an alternate destination operand for the handful of instructions that write to two - // destinations. in all cases, these are very close to duplex instructions (some operation; + // destinations. in most cases, these are very close to duplex instructions (some operation; // some other related operation), but it's not clear if instruction packets would error if // these instruction cohabitate with three other instructions in a packet. for duplex // instructions, it is simply an error to have duplex + 3 more slots, so duplex can be much // more simply decoded into a series of instrucitons.. + // + // the outliers here are store-conditional, where one operand is a register (address) and the + // other is a predicate register updated to indicate the successfulness of the store. alt_dest: Option<Operand>, flags: InstFlags, @@ -296,6 +299,13 @@ struct InstFlags { saturate: bool, chop: bool, rounded: Option<RoundingMode>, + threads: Option<DomainHint>, +} + +#[derive(Debug, Copy, Clone)] +enum DomainHint { + Same, + All, } impl Default for InstFlags { @@ -307,6 +317,7 @@ impl Default for InstFlags { saturate: false, chop: false, rounded: None, + threads: None, } } } @@ -513,9 +524,11 @@ pub enum Opcode { DeallocReturn, Dcfetch, - MemwLocked, + MemwLockedLoad, + MemwStoreCond, MemwAq, - MemdLocked, + MemdLockedLoad, + MemdStoreCond, MemdAq, } @@ -985,6 +998,7 @@ trait DecodeHandler<T: Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Wor fn negate_result(&mut self) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) } fn saturate(&mut self) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) } fn branch_hint(&mut self, hint_taken: bool) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) } + fn domain_hint(&mut self, domain: DomainHint) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) } fn rounded(&mut self, mode: RoundingMode) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) } fn chop(&mut self) -> Result<(), <Hexagon as Arch>::DecodeError> { Ok(()) } fn on_word_read(&mut self, _word: <Hexagon as Arch>::Word) {} @@ -1048,6 +1062,12 @@ impl<T: yaxpeax_arch::Reader<<Hexagon as Arch>::Address, <Hexagon as Arch>::Word } Ok(()) } + fn domain_hint(&mut self, domain: DomainHint) -> Result<(), <Hexagon as Arch>::DecodeError> { + let mut flags = &mut self.instructions[self.instruction_count as usize].flags; + assert!(flags.threads.is_none()); + flags.threads = Some(domain); + Ok(()) + } fn rounded(&mut self, mode: RoundingMode) -> Result<(), <Hexagon as Arch>::DecodeError> { let mut flags = &mut self.instructions[self.instruction_count as usize].flags; assert!(flags.rounded.is_none()); @@ -1104,8 +1124,8 @@ fn decode_store_ops< handler.on_source_decoded(Operand::gpr_new(srcreg & 0b111))?; let opbits = (srcreg >> 3) & 0b11; static OPS: [Option<Opcode>; 4] = [ - Some(Opcode::StoreMemb), Some(Opcode::StoreMemw), - Some(Opcode::StoreMemd), None, + Some(Opcode::StoreMemb), Some(Opcode::StoreMemh), + Some(Opcode::StoreMemw), None, ]; handler.on_opcode_decoded(decode_opcode!(OPS[opbits as usize]))?; handler.on_dest_decoded(dest_op(opbits))?; @@ -2362,8 +2382,8 @@ fn decode_instruction< opcode_check!(inst & 0b100000_111_00000 == 0); let op_low = (inst >> 11) & 0b11; static OP: [Opcode; 4] = [ - Opcode::MemwLocked, Opcode::MemwAq, - Opcode::MemdLocked, Opcode::MemdAq, + Opcode::MemwLockedLoad, Opcode::MemwAq, + Opcode::MemdLockedLoad, Opcode::MemdAq, ]; handler.on_source_decoded(Operand::gpr(sssss))?; if op_low > 0b01 { @@ -2428,57 +2448,86 @@ fn decode_instruction< } } 0b1010 => { - if inst >> 26 & 1 == 0 { + if inst >> 27 & 1 == 0 { // lower chunk: 1010|0 .... // may also be xxxxx, depends on instruction. let sssss = reg_b16(inst); + let Rs = Operand::gpr(sssss); if inst >> 24 & 1 == 0 { // 1010|0..0... these are semi-special memory operations. - handler.on_source_decoded(Operand::gpr(sssss))?; let opc_upper = inst >> 25 & 0b11; if opc_upper == 0b00 { let opc_lower = (inst >> 21) & 0b111; match opc_lower { 0b000 => { handler.on_opcode_decoded(Opcode::DcCleanA)?; + handler.on_source_decoded(Rs)?; }, 0b001 => { handler.on_opcode_decoded(Opcode::DcInvA)?; + handler.on_source_decoded(Rs)?; }, 0b010 => { handler.on_opcode_decoded(Opcode::DcCleanInvA)?; + handler.on_source_decoded(Rs)?; }, 0b011 => { + opcode_check!(inst & 0b11100 == 0b01100); handler.on_opcode_decoded(Opcode::Release)?; + handler.on_source_decoded(Rs)?; if (inst >> 5) & 1 == 0 { - //TODO: hint :at + handler.domain_hint(DomainHint::All)?; } else { - //TODO: hint :st + handler.domain_hint(DomainHint::Same)?; } }, 0b100 => { handler.on_opcode_decoded(Opcode::AllocFrame)?; + let i11 = inst & 0b111_11111111; + operand_check!(inst & 0b111000_00000000 == 0); + handler.on_source_decoded(Rs)?; + handler.on_source_decoded(Operand::imm_u16((i11 as u16) << 3))?; } 0b101 => { - handler.on_opcode_decoded(Opcode::MemwRl)?; - if (inst >> 5) & 1 == 0 { - //TODO: hint :at + handler.on_dest_decoded(Rs)?; + handler.on_source_decoded(Operand::gpr((inst >> 8) as u8 & 0b11111))?; + if inst & 0b1100 == 0b0000 { + handler.on_opcode_decoded(Opcode::MemwStoreCond)?; + handler.on_dest_decoded(Operand::pred(inst as u8 & 0b11))?; + } else if inst & 0b11100 == 0b01000 { + handler.on_opcode_decoded(Opcode::MemwRl)?; + if (inst >> 5) & 1 == 0 { + handler.domain_hint(DomainHint::All)?; + } else { + handler.domain_hint(DomainHint::Same)?; + } } else { - //TODO: hint :st + return Err(DecodeError::InvalidOpcode); } }, 0b110 => { + opcode_check!((inst >> 13) & 1 == 0); handler.on_opcode_decoded(Opcode::DcZeroA)?; + handler.on_source_decoded(Rs)?; } _ => { // 1010|0000|111 - handler.on_opcode_decoded(Opcode::MemdRl)?; - if (inst >> 5) & 1 == 0 { - //TODO: hint :at + handler.on_dest_decoded(Rs)?; + handler.on_source_decoded(Operand::gprpair((inst >> 8) as u8 & 0b11111)?)?; + if inst & 0b1100 == 0b0000 { + handler.on_opcode_decoded(Opcode::MemdStoreCond)?; + handler.on_dest_decoded(Operand::pred(inst as u8 & 0b11))?; + } else if inst & 0b11100 == 0b01000 { + handler.on_opcode_decoded(Opcode::MemdRl)?; + if (inst >> 5) & 1 == 0 { + handler.domain_hint(DomainHint::All)?; + } else { + handler.domain_hint(DomainHint::Same)?; + } } else { - //TODO: hint :st + return Err(DecodeError::InvalidOpcode); } }, } @@ -2491,6 +2540,7 @@ fn decode_instruction< opcode_check!(opc_lower & 0b11 == 0b00); handler.on_opcode_decoded(Opcode::L2Fetch)?; + handler.on_source_decoded(Rs)?; let ttttt = reg_b8(inst); if opc_lower == 0b100 { handler.on_source_decoded(Operand::gprpair(ttttt)?)?; @@ -2620,14 +2670,14 @@ fn decode_instruction< Operand::RegMemIndexedBrev { base: xxxxx, mu: u as u8 } })?; } else { - // 1010|1011...|.....|PP|1... + // 1010|1111...|.....|PP|1... // predicated store let vv = inst & 0b11; let negated = (inst >> 2) & 1 == 1; let iiii = ((inst >> 3) & 0b1111) as u8; let ii_high = xxxxx & 0b11; let i6 = ((ii_high << 4) | iiii) as i8; - let dotnew = (inst >> 7) & 1 == 1; + let dotnew = (inst >> 13) & 1 == 1; decode_store_ops(handler, minbits, ttttt, |_shamt| { Operand::Absolute { addr: i6 } })?; |