aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/armv8/a64.rs166
-rw-r--r--test/armv8/a64.rs20
2 files changed, 177 insertions, 9 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs
index b698f6c..af52bf4 100644
--- a/src/armv8/a64.rs
+++ b/src/armv8/a64.rs
@@ -3089,26 +3089,174 @@ impl Decoder<ARMv8> for InstDecoder {
return Err(DecodeError::InvalidOpcode);
}
0b0_0000 => {
- if size < 0b10 {
+ // FMLAL
+ if size != 0b10 {
return Err(DecodeError::InvalidOpcode);
}
- // FMLAL
+ if (word >> 29 & 1) == 0 {
+ inst.opcode = Opcode::FMLAL;
+ } else {
+ inst.opcode = Opcode::FMLAL2;
+ }
+
+ let index = (H << 2) | (L << 1) | M;
+
+ let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D };
+
+ inst.operands = [
+ Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S),
+ Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::H),
+ Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, SIMDSizeCode::H, index as u8),
+ Operand::Nothing,
+ ];
+ }
+ 0b0_0100 => {
+ // FMLSL
+ if size != 0b10 {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ if (word >> 29 & 1) == 0 {
+ inst.opcode = Opcode::FMLSL;
+ } else {
+ inst.opcode = Opcode::FMLSL2;
+ }
+
+ let index = (H << 2) | (L << 1) | M;
+
+ let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D };
+
+ inst.operands = [
+ Operand::SIMDRegisterElements(datasize, Rd as u16, SIMDSizeCode::S),
+ Operand::SIMDRegisterElements(datasize, Rn as u16, SIMDSizeCode::H),
+ Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, SIMDSizeCode::H, index as u8),
+ Operand::Nothing,
+ ];
}
0b0_0001 => {
- // TODO:
// FMLA (not size=0b01)
- }
- 0b0_0100 => {
- // TODO:
- // FMLSL (not size<0b10)
+ if size == 0b01 {
+ return Err(DecodeError::InvalidOpcode);
+ }
+
+ inst.opcode = Opcode::FMLA;
+
+ let sz = size & 1;
+
+ if sz == 1 && L == 1 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ if sz == 1 && Q == 0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let (index, Rm, size) = if size == 0b00 {
+ let index = (H << 2) | (L << 1) | M;
+ (index, Rm, SIMDSizeCode::H)
+ } else if size == 0b10 {
+ // `sz == 0`
+ let index = (H << 1) | L;
+ let Rm = (M << 4) | Rm;
+ (index, Rm, SIMDSizeCode::S)
+ } else {
+ // `sz == 1`
+ let index = H;
+ let Rm = (M << 4) | Rm;
+ (index, Rm, SIMDSizeCode::D)
+ };
+
+ let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D };
+
+ inst.operands = [
+ Operand::SIMDRegisterElements(datasize, Rd as u16, size),
+ Operand::SIMDRegisterElements(datasize, Rn as u16, size),
+ Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, size, index as u8),
+ Operand::Nothing,
+ ];
}
0b0_0101 => {
- // TODO:
// FMLS (not size=0b01)
+ if size == 0b01 {
+ return Err(DecodeError::InvalidOpcode);
+ }
+
+ inst.opcode = Opcode::FMLS;
+
+ let sz = size & 1;
+
+ if sz == 1 && L == 1 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ if sz == 1 && Q == 0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let (index, Rm, size) = if size == 0b00 {
+ let index = (H << 2) | (L << 1) | M;
+ (index, Rm, SIMDSizeCode::H)
+ } else if size == 0b10 {
+ // `sz == 0`
+ let index = (H << 1) | L;
+ let Rm = (M << 4) | Rm;
+ (index, Rm, SIMDSizeCode::S)
+ } else {
+ // `sz == 1`
+ let index = H;
+ let Rm = (M << 4) | Rm;
+ (index, Rm, SIMDSizeCode::D)
+ };
+
+ let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D };
+
+ inst.operands = [
+ Operand::SIMDRegisterElements(datasize, Rd as u16, size),
+ Operand::SIMDRegisterElements(datasize, Rn as u16, size),
+ Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, size, index as u8),
+ Operand::Nothing,
+ ];
}
0b0_1001 => {
- // TODO:
// FMUL (not size=0b01)
+ if size == 0b01 {
+ return Err(DecodeError::InvalidOpcode);
+ }
+
+ inst.opcode = Opcode::FMUL;
+
+ let sz = size & 1;
+
+ if sz == 1 && L == 1 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ if sz == 1 && Q == 0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let (index, Rm, size) = if size == 0b00 {
+ let index = (H << 2) | (L << 1) | M;
+ (index, Rm, SIMDSizeCode::H)
+ } else if size == 0b10 {
+ // `sz == 0`
+ let index = (H << 1) | L;
+ let Rm = (M << 4) | Rm;
+ (index, Rm, SIMDSizeCode::S)
+ } else {
+ // `sz == 1`
+ let index = H;
+ let Rm = (M << 4) | Rm;
+ (index, Rm, SIMDSizeCode::D)
+ };
+
+ let datasize = if Q == 1 { SIMDSizeCode::Q } else { SIMDSizeCode::D };
+
+ inst.operands = [
+ Operand::SIMDRegisterElements(datasize, Rd as u16, size),
+ Operand::SIMDRegisterElements(datasize, Rn as u16, size),
+ Operand::SIMDRegisterElementsLane(SIMDSizeCode::Q, Rm as u16, size, index as u8),
+ Operand::Nothing,
+ ];
}
0b1_0000 => {
if size == 0b00 || size == 0b11 {
diff --git a/test/armv8/a64.rs b/test/armv8/a64.rs
index 6f43c22..593dcbf 100644
--- a/test/armv8/a64.rs
+++ b/test/armv8/a64.rs
@@ -4283,3 +4283,23 @@ fn test_ext() {
assert!(errs.is_empty());
}
+
+#[test]
+fn test_indexed() {
+ const TESTS: &[([u8; 4], &'static str)] = &[
+ ([0x10, 0x11, 0x80, 0x0f], "fmla v16.2s, v8.2s, v0.s[0]"),
+ ([0x39, 0x58, 0x88, 0x0f], "fmls v25.2s, v1.2s, v8.s[2]"),
+ ([0x08, 0x92, 0x8a, 0x0f], "fmul v8.2s, v16.2s, v10.s[0]"),
+ ([0x01, 0x12, 0x8b, 0x0f], "fmla v1.2s, v16.2s, v11.s[0]"),
+ ([0x8c, 0x12, 0x8e, 0x0f], "fmla v12.2s, v20.2s, v14.s[0]"),
+ ([0xc6, 0x12, 0x8e, 0x0f], "fmla v6.2s, v22.2s, v14.s[0]"),
+ ([0x3c, 0x58, 0xa9, 0x0f], "fmls v28.2s, v1.2s, v9.s[3]"),
+ ];
+ let errs = run_tests(TESTS);
+
+ for err in errs.iter() {
+ println!("{}", err);
+ }
+
+ assert!(errs.is_empty());
+}