diff options
author | iximeow <me@iximeow.net> | 2021-10-24 19:29:48 -0700 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2021-10-24 19:29:54 -0700 |
commit | b55e519458d8f01be0dbe205de4f7f9aeb8a3ca2 (patch) | |
tree | 77fc01c08ff256d4dece8767bd828ba0e29a5a7d /src/armv8 | |
parent | bd0be59eb6ed363faba14adf9ab04efe8a714316 (diff) |
constify more of ld/st code, fix incorrect shift size
extended register forms of ld*/st* instructions do not shift by 0 or 1,
they are an instruction/operand-size-dependent shift amount.
Diffstat (limited to 'src/armv8')
-rw-r--r-- | src/armv8/a64.rs | 441 |
1 files changed, 132 insertions, 309 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs index 6bce61e..5dd3d1c 100644 --- a/src/armv8/a64.rs +++ b/src/armv8/a64.rs @@ -2454,196 +2454,107 @@ impl Decoder<ARMv8> for InstDecoder { let category = (word >> 10) & 0x03; // println!("load/store: size_opc: {:#b}, category: {:#b}", size_opc, category); if word & 0x200000 != 0 { - if category != 0b10 { - inst.opcode = Opcode::Invalid; - return Err(DecodeError::InvalidOpcode); - } else { - // Load/store register (register offset) - // C3.3.10 - let size = match size_opc { - 0b0000 => { - inst.opcode = Opcode::STRB; - SizeCode::W - }, - 0b0001 => { - inst.opcode = Opcode::LDRB; - SizeCode::W - }, - 0b0010 => { - inst.opcode = Opcode::LDRSB; - SizeCode::X - }, - 0b0011 => { - inst.opcode = Opcode::LDRSB; - SizeCode::W - }, - 0b0100 => { - inst.opcode = Opcode::STRH; - SizeCode::W - }, - 0b0101 => { - inst.opcode = Opcode::LDRH; - SizeCode::W - }, - 0b0110 => { - inst.opcode = Opcode::LDRSH; - SizeCode::X - }, - 0b0111 => { - inst.opcode = Opcode::LDRSH; - SizeCode::W - }, - 0b1000 => { - inst.opcode = Opcode::STR; - SizeCode::W - }, - 0b1001 => { - inst.opcode = Opcode::LDR; - SizeCode::W - }, - 0b1010 => { - inst.opcode = Opcode::LDRSW; - SizeCode::X - }, - 0b1011 => { - inst.opcode = Opcode::Invalid; - SizeCode::X - }, - 0b1100 => { - inst.opcode = Opcode::STR; - SizeCode::X - }, - 0b1101 => { - inst.opcode = Opcode::LDR; - SizeCode::X - }, - 0b1110 => { - // eprintln!("PRFM is not supported yet"); - return Err(DecodeError::IncompleteDecoder); -// inst.opcode = Opcode::PRFM; -// SizeCode::X - }, - 0b1111 => { - inst.opcode = Opcode::Invalid; - SizeCode::X - }, - _ => { unreachable!("size and opc are four bits"); } - }; + match category { + 0b00 => { + // Atomic memory operations + // V==1 + return Err(DecodeError::IncompleteDecoder); + } + 0b01 | + 0b11 => { + // Load/store register (pac) + // V==1 + return Err(DecodeError::IncompleteDecoder); + } + 0b10 => { + // Load/store register (register offset) + // C3.3.10 + const OPCODES: &[Result<(Opcode, SizeCode, u8), DecodeError>] = &[ + Ok((Opcode::STRB, SizeCode::W, 1)), + Ok((Opcode::LDRB, SizeCode::W, 1)), + Ok((Opcode::LDRSB, SizeCode::X, 1)), + Ok((Opcode::LDRSB, SizeCode::W, 1)), + Ok((Opcode::STRH, SizeCode::W, 1)), + Ok((Opcode::LDRH, SizeCode::W, 1)), + Ok((Opcode::LDRSH, SizeCode::X, 1)), + Ok((Opcode::LDRSH, SizeCode::W, 1)), + Ok((Opcode::STR, SizeCode::W, 2)), + Ok((Opcode::LDR, SizeCode::W, 2)), + Ok((Opcode::LDRSW, SizeCode::X, 2)), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::STR, SizeCode::X, 3)), + Ok((Opcode::LDR, SizeCode::X, 3)), + Err(DecodeError::IncompleteDecoder), // PRFM is not supported yet + Err(DecodeError::InvalidOpcode), + ]; - let S = ((word >> 12) & 0x1) as u8; - let option = ((word >> 13) & 0x07) as u8; - let Rm = ((word >> 16) & 0x1f) as u16; + let (opcode, size, shamt) = OPCODES[size_opc as usize]?; + inst.opcode = opcode; - let index_size = match option & 0x3 { - 0b00 | - 0b01 => { - inst.opcode = Opcode::Invalid; - return Err(DecodeError::InvalidOpcode); - }, - 0b10 => { SizeCode::W } - 0b11 => { SizeCode::X } - _ => { unreachable!("option is two bits"); } - }; + let S = ((word >> 12) & 0x1) as u8; + let option = ((word >> 13) & 0x07) as u8; + let Rm = ((word >> 16) & 0x1f) as u16; - let shift_style = match option { - 0b000 | - 0b001 => { - inst.opcode = Opcode::Invalid; - return Err(DecodeError::InvalidOpcode); - }, - 0b010 => { ShiftStyle::UXTW }, - 0b011 => { ShiftStyle::LSL }, - 0b100 | - 0b101 => { - inst.opcode = Opcode::Invalid; - return Err(DecodeError::InvalidOpcode); - }, - 0b110 => { ShiftStyle::SXTW }, - 0b111 => { ShiftStyle::SXTX }, - _ => { unreachable!("option is three bits"); } - }; + let index_size = match option & 0x3 { + 0b00 | + 0b01 => { + inst.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + }, + 0b10 => { SizeCode::W } + 0b11 => { SizeCode::X } + _ => { unreachable!("option is two bits"); } + }; - inst.operands = [ - Operand::Register(size, Rt), - Operand::RegRegOffset(Rn, index_size, Rm, shift_style, S), - Operand::Nothing, - Operand::Nothing, - ]; + const SHIFT_STYLES: &[Result<ShiftStyle, DecodeError>] = &[ + Err(DecodeError::InvalidOperand), + Err(DecodeError::InvalidOperand), + Ok(ShiftStyle::UXTW), + Ok(ShiftStyle::LSL), + Err(DecodeError::InvalidOperand), + Err(DecodeError::InvalidOperand), + Ok(ShiftStyle::SXTW), + Ok(ShiftStyle::SXTX), + ]; + let shift_style = SHIFT_STYLES[option as usize]?; + + inst.operands = [ + Operand::Register(size, Rt), + Operand::RegRegOffset(Rn, index_size, Rm, shift_style, S * shamt), + Operand::Nothing, + Operand::Nothing, + ]; + } + _ => { + unreachable!("category is two bits"); + } } } else { let imm9 = ((((word >> 12) & 0x1ff) as i16) << 7) >> 7; match category { 0b00 => { // Load/store register (unscaled immediate) - let size = match size_opc { - 0b0000 => { - inst.opcode = Opcode::STURB; - SizeCode::W - } - 0b0001 => { - inst.opcode = Opcode::LDURB; - SizeCode::W - } - 0b0010 => { - inst.opcode = Opcode::LDURSB; - SizeCode::X - } - 0b0011 => { - inst.opcode = Opcode::LDURSB; - SizeCode::W - } - 0b0100 => { - inst.opcode = Opcode::STURH; - SizeCode::W - } - 0b0101 => { - inst.opcode = Opcode::LDURH; - SizeCode::W - } - 0b0110 => { - inst.opcode = Opcode::LDURSH; - SizeCode::X - } - 0b0111 => { - inst.opcode = Opcode::LDURSH; - SizeCode::W - } - 0b1000 => { - inst.opcode = Opcode::STUR; - SizeCode::W - } - 0b1001 => { - inst.opcode = Opcode::LDUR; - SizeCode::W - } - 0b1010 => { - inst.opcode = Opcode::LDURSW; - SizeCode::X - } - 0b1011 => { - inst.opcode = Opcode::Invalid; - SizeCode::W - } - 0b1100 => { - inst.opcode = Opcode::STUR; - SizeCode::X - } - 0b1101 => { - inst.opcode = Opcode::LDUR; - SizeCode::X - } - 0b1110 => { - // eprintln!("PRFUM not handled yet"); - return Err(DecodeError::IncompleteDecoder); - }, - 0b1111 => { - inst.opcode = Opcode::Invalid; - SizeCode::W - } - _ => { - unreachable!("size and opc are four bits"); - } - }; + const OPCODES: &[Result<(Opcode, SizeCode), DecodeError>] = &[ + Ok((Opcode::STURB, SizeCode::W)), + Ok((Opcode::LDURB, SizeCode::W)), + Ok((Opcode::LDURSB, SizeCode::X)), + Ok((Opcode::LDURSB, SizeCode::W)), + Ok((Opcode::STURH, SizeCode::W)), + Ok((Opcode::LDURH, SizeCode::W)), + Ok((Opcode::LDURSH, SizeCode::X)), + Ok((Opcode::LDURSH, SizeCode::W)), + Ok((Opcode::STUR, SizeCode::W)), + Ok((Opcode::LDUR, SizeCode::W)), + Ok((Opcode::LDURSW, SizeCode::X)), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::STUR, SizeCode::X)), + Ok((Opcode::LDUR, SizeCode::X)), + Err(DecodeError::IncompleteDecoder), // PRFM is not supported yet + Err(DecodeError::InvalidOpcode), + ]; + + let (opcode, size) = OPCODES[size_opc as usize]?; + inst.opcode = opcode; inst.operands = [ Operand::Register(size, Rt), @@ -2654,73 +2565,27 @@ impl Decoder<ARMv8> for InstDecoder { } 0b10 => { // Load/store register (unprivileged) + const OPCODES: &[Result<(Opcode, SizeCode), DecodeError>] = &[ + Ok((Opcode::STTRB, SizeCode::W)), + Ok((Opcode::LDTRB, SizeCode::W)), + Ok((Opcode::LDTRSB, SizeCode::X)), + Ok((Opcode::LDTRSB, SizeCode::W)), + Ok((Opcode::STTRH, SizeCode::W)), + Ok((Opcode::LDTRH, SizeCode::W)), + Ok((Opcode::LDTRSH, SizeCode::X)), + Ok((Opcode::LDTRSH, SizeCode::W)), + Ok((Opcode::STTR, SizeCode::W)), + Ok((Opcode::LDTR, SizeCode::W)), + Ok((Opcode::LDTRSW, SizeCode::X)), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::STUR, SizeCode::X)), + Ok((Opcode::LDTR, SizeCode::X)), + Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), + ]; - let size = match size_opc { - 0b0000 => { - inst.opcode = Opcode::STTRB; - SizeCode::W - } - 0b0001 => { - inst.opcode = Opcode::LDTRB; - SizeCode::W - } - 0b0010 => { - inst.opcode = Opcode::LDTRSB; - SizeCode::X - } - 0b0011 => { - inst.opcode = Opcode::LDTRSB; - SizeCode::W - } - 0b0100 => { - inst.opcode = Opcode::STTRH; - SizeCode::W - } - 0b0101 => { - inst.opcode = Opcode::LDTRH; - SizeCode::W - } - 0b0110 => { - inst.opcode = Opcode::LDTRSH; - SizeCode::X - } - 0b0111 => { - inst.opcode = Opcode::LDTRSH; - SizeCode::W - } - 0b1000 => { - inst.opcode = Opcode::STTR; - SizeCode::W - } - 0b1001 => { - inst.opcode = Opcode::LDTR; - SizeCode::W - } - 0b1010 => { - inst.opcode = Opcode::LDTRSW; - SizeCode::X - } - 0b1011 => { - inst.opcode = Opcode::Invalid; - SizeCode::W - } - 0b1100 => { - inst.opcode = Opcode::STTR; - SizeCode::X - } - 0b1101 => { - inst.opcode = Opcode::LDTR; - SizeCode::X - } - 0b1110 | - 0b1111 => { - inst.opcode = Opcode::Invalid; - SizeCode::W - } - _ => { - unreachable!("size and opc are four bits"); - } - }; + let (opcode, size) = OPCODES[size_opc as usize]?; + inst.opcode = opcode; inst.operands = [ Operand::Register(size, Rt), @@ -2731,69 +2596,27 @@ impl Decoder<ARMv8> for InstDecoder { } 0b01 | 0b11 => { - let size = match size_opc { - 0b0000 => { - inst.opcode = Opcode::STRB; - SizeCode::W - }, - 0b0001 => { - inst.opcode = Opcode::LDRB; - SizeCode::W - } - 0b0010 => { - inst.opcode = Opcode::LDRSB; - SizeCode::X - } - 0b0011 => { - inst.opcode = Opcode::LDRSB; - SizeCode::W - } - 0b0100 => { - inst.opcode = Opcode::STRH; - SizeCode::W - } - 0b0101 => { - inst.opcode = Opcode::LDRH; - SizeCode::W - } - 0b0110 => { - inst.opcode = Opcode::LDRSH; - SizeCode::X - } - 0b0111 => { - inst.opcode = Opcode::LDRSH; - SizeCode::W - } - 0b1000 => { - inst.opcode = Opcode::STR; - SizeCode::W - } - 0b1001 => { - inst.opcode = Opcode::LDR; - SizeCode::W - } - 0b1010 | - 0b1011 => { - inst.opcode = Opcode::Invalid; - SizeCode::W - } - 0b1100 => { - inst.opcode = Opcode::STR; - SizeCode::X - } - 0b1101 => { - inst.opcode = Opcode::LDR; - SizeCode::X - } - 0b1110 | - 0b1111 => { - inst.opcode = Opcode::Invalid; - SizeCode::X - } - _ => { - unreachable!("size and opc are four bits"); - } - }; + const OPCODES: &[Result<(Opcode, SizeCode), DecodeError>] = &[ + Ok((Opcode::STRB, SizeCode::W)), + Ok((Opcode::LDRB, SizeCode::W)), + Ok((Opcode::LDRSB, SizeCode::X)), + Ok((Opcode::LDRSB, SizeCode::W)), + Ok((Opcode::STRH, SizeCode::W)), + Ok((Opcode::LDRH, SizeCode::W)), + Ok((Opcode::LDRSH, SizeCode::X)), + Ok((Opcode::LDRSH, SizeCode::W)), + Ok((Opcode::STR, SizeCode::W)), + Ok((Opcode::LDR, SizeCode::W)), + Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), + Ok((Opcode::STR, SizeCode::X)), + Ok((Opcode::LDR, SizeCode::X)), + Err(DecodeError::InvalidOpcode), + Err(DecodeError::InvalidOpcode), + ]; + + let (opcode, size) = OPCODES[size_opc as usize]?; + inst.opcode = opcode; inst.operands = [ Operand::Register(size, Rt), |