aboutsummaryrefslogtreecommitdiff
path: root/src/armv8/a64.rs
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2021-12-28 12:03:41 -0800
committeriximeow <me@iximeow.net>2021-12-28 12:03:41 -0800
commit9f08e998ed1f0180883e589279ed3081c565f79d (patch)
treed2c62da0cc8c41e6f4a60b5079cdf307242cd748 /src/armv8/a64.rs
parentdab8f49060b94589efecc951f4f74cdf10928afb (diff)
armv8.1 atomic ops
Diffstat (limited to 'src/armv8/a64.rs')
-rw-r--r--src/armv8/a64.rs558
1 files changed, 557 insertions, 1 deletions
diff --git a/src/armv8/a64.rs b/src/armv8/a64.rs
index 14bdebd..6810cb2 100644
--- a/src/armv8/a64.rs
+++ b/src/armv8/a64.rs
@@ -1905,6 +1905,438 @@ impl Display for Instruction {
Opcode::LDRAB => {
write!(fmt, "ldrab");
}
+ Opcode::LDAPRH(ar) => {
+ let inst = if ar == 0 {
+ "ldaprh"
+ } else if ar == 0b01 {
+ "ldaprlh"
+ } else if ar == 0b10 {
+ "ldaprah"
+ } else {
+ "ldapralh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::SWP(ar) => {
+ let inst = if ar == 0 {
+ "swp"
+ } else if ar == 0b01 {
+ "swlp"
+ } else if ar == 0b10 {
+ "swap"
+ } else {
+ "swalp"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::SWPB(ar) => {
+ let inst = if ar == 0 {
+ "swpb"
+ } else if ar == 0b01 {
+ "swplb"
+ } else if ar == 0b10 {
+ "swpab"
+ } else {
+ "swpalb"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::SWPH(ar) => {
+ let inst = if ar == 0 {
+ "swph"
+ } else if ar == 0b01 {
+ "swplh"
+ } else if ar == 0b10 {
+ "swpah"
+ } else {
+ "swpalh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDADDB(ar) => {
+ let inst = if ar == 0 {
+ "ldaddb"
+ } else if ar == 0b01 {
+ "ldaddlb"
+ } else if ar == 0b10 {
+ "ldaddab"
+ } else {
+ "ldaddalb"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDCLRB(ar) => {
+ let inst = if ar == 0 {
+ "ldclrb"
+ } else if ar == 0b01 {
+ "ldclrlb"
+ } else if ar == 0b10 {
+ "ldclrab"
+ } else {
+ "ldclralb"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDEORB(ar) => {
+ let inst = if ar == 0 {
+ "ldeorb"
+ } else if ar == 0b01 {
+ "ldeorlb"
+ } else if ar == 0b10 {
+ "ldeorab"
+ } else {
+ "ldeoralb"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSETB(ar) => {
+ let inst = if ar == 0 {
+ "ldsetb"
+ } else if ar == 0b01 {
+ "ldsetlb"
+ } else if ar == 0b10 {
+ "ldsetab"
+ } else {
+ "ldsetalb"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSMAXB(ar) => {
+ let inst = if ar == 0 {
+ "ldsmaxb"
+ } else if ar == 0b01 {
+ "ldsmaxlb"
+ } else if ar == 0b10 {
+ "ldsmaxab"
+ } else {
+ "ldsmaxalb"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSMINB(ar) => {
+ let inst = if ar == 0 {
+ "ldsminb"
+ } else if ar == 0b01 {
+ "ldsminlb"
+ } else if ar == 0b10 {
+ "ldsminab"
+ } else {
+ "ldsminalb"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDUMAXB(ar) => {
+ let inst = if ar == 0 {
+ "ldumaxb"
+ } else if ar == 0b01 {
+ "ldumaxlb"
+ } else if ar == 0b10 {
+ "ldumaxab"
+ } else {
+ "ldumaxalb"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDUMINB(ar) => {
+ let inst = if ar == 0 {
+ "lduminb"
+ } else if ar == 0b01 {
+ "lduminlb"
+ } else if ar == 0b10 {
+ "lduminab"
+ } else {
+ "lduminalb"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDADDH(ar) => {
+ let inst = if ar == 0 {
+ "ldaddh"
+ } else if ar == 0b01 {
+ "ldaddlh"
+ } else if ar == 0b10 {
+ "ldaddah"
+ } else {
+ "ldaddalh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDCLRH(ar) => {
+ let inst = if ar == 0 {
+ "ldclrh"
+ } else if ar == 0b01 {
+ "ldclrlh"
+ } else if ar == 0b10 {
+ "ldclrah"
+ } else {
+ "ldclralh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDEORH(ar) => {
+ let inst = if ar == 0 {
+ "ldeorh"
+ } else if ar == 0b01 {
+ "ldeorlh"
+ } else if ar == 0b10 {
+ "ldeorah"
+ } else {
+ "ldeoralh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSETH(ar) => {
+ let inst = if ar == 0 {
+ "ldseth"
+ } else if ar == 0b01 {
+ "ldsetlh"
+ } else if ar == 0b10 {
+ "ldsetah"
+ } else {
+ "ldsetalh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSMAXH(ar) => {
+ let inst = if ar == 0 {
+ "ldsmaxh"
+ } else if ar == 0b01 {
+ "ldsmaxlh"
+ } else if ar == 0b10 {
+ "ldsmaxah"
+ } else {
+ "ldsmaxalh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSMINH(ar) => {
+ let inst = if ar == 0 {
+ "ldsminh"
+ } else if ar == 0b01 {
+ "ldsminlh"
+ } else if ar == 0b10 {
+ "ldsminah"
+ } else {
+ "ldsminalh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDUMAXH(ar) => {
+ let inst = if ar == 0 {
+ "ldumaxh"
+ } else if ar == 0b01 {
+ "ldumaxlh"
+ } else if ar == 0b10 {
+ "ldumaxah"
+ } else {
+ "ldumaxalh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDUMINH(ar) => {
+ let inst = if ar == 0 {
+ "lduminh"
+ } else if ar == 0b01 {
+ "lduminlh"
+ } else if ar == 0b10 {
+ "lduminah"
+ } else {
+ "lduminalh"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDADD(ar) => {
+ let inst = if ar == 0 {
+ "ldadd"
+ } else if ar == 0b01 {
+ "ldaddl"
+ } else if ar == 0b10 {
+ "ldadda"
+ } else {
+ "ldaddal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDCLR(ar) => {
+ let inst = if ar == 0 {
+ "ldclr"
+ } else if ar == 0b01 {
+ "ldclrl"
+ } else if ar == 0b10 {
+ "ldclra"
+ } else {
+ "ldclral"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDEOR(ar) => {
+ let inst = if ar == 0 {
+ "ldeor"
+ } else if ar == 0b01 {
+ "ldeorl"
+ } else if ar == 0b10 {
+ "ldeora"
+ } else {
+ "ldeoral"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSET(ar) => {
+ let inst = if ar == 0 {
+ "ldset"
+ } else if ar == 0b01 {
+ "ldsetl"
+ } else if ar == 0b10 {
+ "ldseta"
+ } else {
+ "ldsetal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSMAX(ar) => {
+ let inst = if ar == 0 {
+ "ldsmax"
+ } else if ar == 0b01 {
+ "ldsmaxl"
+ } else if ar == 0b10 {
+ "ldsmaxa"
+ } else {
+ "ldsmaxal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSMIN(ar) => {
+ let inst = if ar == 0 {
+ "ldsmin"
+ } else if ar == 0b01 {
+ "ldsminl"
+ } else if ar == 0b10 {
+ "ldsmina"
+ } else {
+ "ldsminal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDUMAX(ar) => {
+ let inst = if ar == 0 {
+ "ldumax"
+ } else if ar == 0b01 {
+ "ldumaxl"
+ } else if ar == 0b10 {
+ "ldumaxa"
+ } else {
+ "ldumaxal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDUMIN(ar) => {
+ let inst = if ar == 0 {
+ "ldumin"
+ } else if ar == 0b01 {
+ "lduminl"
+ } else if ar == 0b10 {
+ "ldumina"
+ } else {
+ "lduminal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDADD(ar) => {
+ let inst = if ar == 0 {
+ "ldadd"
+ } else if ar == 0b01 {
+ "ldaddl"
+ } else if ar == 0b10 {
+ "ldadda"
+ } else {
+ "ldaddal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDCLR(ar) => {
+ let inst = if ar == 0 {
+ "ldclr"
+ } else if ar == 0b01 {
+ "ldclrl"
+ } else if ar == 0b10 {
+ "ldclra"
+ } else {
+ "ldclral"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDEOR(ar) => {
+ let inst = if ar == 0 {
+ "ldeor"
+ } else if ar == 0b01 {
+ "ldeorl"
+ } else if ar == 0b10 {
+ "ldeora"
+ } else {
+ "ldeoral"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSET(ar) => {
+ let inst = if ar == 0 {
+ "ldset"
+ } else if ar == 0b01 {
+ "ldsetl"
+ } else if ar == 0b10 {
+ "ldseta"
+ } else {
+ "ldsetal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSMAX(ar) => {
+ let inst = if ar == 0 {
+ "ldsmax"
+ } else if ar == 0b01 {
+ "ldsmaxl"
+ } else if ar == 0b10 {
+ "ldsmaxa"
+ } else {
+ "ldsmaxal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDSMIN(ar) => {
+ let inst = if ar == 0 {
+ "ldsmin"
+ } else if ar == 0b01 {
+ "ldsminl"
+ } else if ar == 0b10 {
+ "ldsmina"
+ } else {
+ "ldsminal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDUMAX(ar) => {
+ let inst = if ar == 0 {
+ "ldumax"
+ } else if ar == 0b01 {
+ "ldumaxl"
+ } else if ar == 0b10 {
+ "ldumaxa"
+ } else {
+ "ldumaxal"
+ };
+ fmt.write_str(inst);
+ }
+ Opcode::LDUMIN(ar) => {
+ let inst = if ar == 0 {
+ "ldumin"
+ } else if ar == 0b01 {
+ "lduminl"
+ } else if ar == 0b10 {
+ "ldumina"
+ } else {
+ "lduminal"
+ };
+ fmt.write_str(inst);
+ }
};
if self.operands[0] != Operand::Nothing {
@@ -2414,6 +2846,35 @@ pub enum Opcode {
LDRAA,
LDRAB,
+
+ LDAPRH(u8),
+ SWP(u8),
+ SWPB(u8),
+ SWPH(u8),
+ LDADDB(u8),
+ LDCLRB(u8),
+ LDEORB(u8),
+ LDSETB(u8),
+ LDSMAXB(u8),
+ LDSMINB(u8),
+ LDUMAXB(u8),
+ LDUMINB(u8),
+ LDADDH(u8),
+ LDCLRH(u8),
+ LDEORH(u8),
+ LDSETH(u8),
+ LDSMAXH(u8),
+ LDSMINH(u8),
+ LDUMAXH(u8),
+ LDUMINH(u8),
+ LDADD(u8),
+ LDCLR(u8),
+ LDEOR(u8),
+ LDSET(u8),
+ LDSMAX(u8),
+ LDSMIN(u8),
+ LDUMAX(u8),
+ LDUMIN(u8),
}
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -7826,7 +8287,102 @@ impl Decoder<ARMv8> for InstDecoder {
0b00 => {
// Atomic memory operations
// V==0
- return Err(DecodeError::IncompleteDecoder);
+
+ // A and R bits mean... "acquire" and "release"
+ let sz = (word >> 30) & 0b11;
+ let ar = ((word >> 22) & 0b11) as u8;
+ let o3 = (word >> 15) & 1;
+ let opcode = (word >> 12) & 0b111;
+ let Rs = (word >> 16) & 0b11111;
+
+ let size = if sz == 0b11 {
+ SizeCode::X
+ } else {
+ SizeCode::W
+ };
+
+ if o3 == 0 {
+ let opc = match (sz << 3) | opcode {
+ 0b00_000 => Opcode::LDADDB(ar),
+ 0b00_001 => Opcode::LDCLRB(ar),
+ 0b00_010 => Opcode::LDEORB(ar),
+ 0b00_011 => Opcode::LDSETB(ar),
+ 0b00_100 => Opcode::LDSMAXB(ar),
+ 0b00_101 => Opcode::LDSMINB(ar),
+ 0b00_110 => Opcode::LDUMAXB(ar),
+ 0b00_111 => Opcode::LDUMINB(ar),
+ 0b01_000 => Opcode::LDADDH(ar),
+ 0b01_001 => Opcode::LDCLRH(ar),
+ 0b01_010 => Opcode::LDEORH(ar),
+ 0b01_011 => Opcode::LDSETH(ar),
+ 0b01_100 => Opcode::LDSMAXH(ar),
+ 0b01_101 => Opcode::LDSMINH(ar),
+ 0b01_110 => Opcode::LDUMAXH(ar),
+ 0b01_111 => Opcode::LDUMINH(ar),
+ 0b10_000 => Opcode::LDADD(ar),
+ 0b10_001 => Opcode::LDCLR(ar),
+ 0b10_010 => Opcode::LDEOR(ar),
+ 0b10_011 => Opcode::LDSET(ar),
+ 0b10_100 => Opcode::LDSMAX(ar),
+ 0b10_101 => Opcode::LDSMIN(ar),
+ 0b10_110 => Opcode::LDUMAX(ar),
+ 0b10_111 => Opcode::LDUMIN(ar),
+ 0b11_000 => Opcode::LDADD(ar),
+ 0b11_001 => Opcode::LDCLR(ar),
+ 0b11_010 => Opcode::LDEOR(ar),
+ 0b11_011 => Opcode::LDSET(ar),
+ 0b11_100 => Opcode::LDSMAX(ar),
+ 0b11_101 => Opcode::LDSMIN(ar),
+ 0b11_110 => Opcode::LDUMAX(ar),
+ 0b11_111 => Opcode::LDUMIN(ar),
+ _ => { unreachable!("sz|opc is 5 bits") }
+ };
+ inst.opcode = opc;
+ inst.operands = [
+ Operand::Register(size, Rs as u16),
+ Operand::Register(size, Rt as u16),
+ Operand::RegOffset(Rn, 0),
+ Operand::Nothing,
+ ];
+ } else {
+ if opcode == 0b000 {
+ inst.opcode = if sz == 0b00 {
+ Opcode::SWPB(ar)
+ } else if sz == 0b01 {
+ Opcode::SWPH(ar)
+ } else if sz == 0b10 {
+ Opcode::SWP(ar)
+ } else {
+ Opcode::SWP(ar)
+ };
+
+ inst.operands = [
+ Operand::Register(size, Rs as u16),
+ Operand::Register(size, Rt as u16),
+ Operand::RegOffset(Rn, 0),
+ Operand::Nothing,
+ ];
+ } else if opcode == 0b100 {
+ inst.opcode = if sz == 0b01 {
+ Opcode::LDAPRH(ar)
+ } else if sz == 0b00 {
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ // sz = 1x
+ Opcode::LDAPRH(ar)
+ };
+
+ // TOOD: should_is_must, Rs = 11111
+ inst.operands = [
+ Operand::Register(size, Rt as u16),
+ Operand::RegOffset(Rn, 0),
+ Operand::Nothing,
+ Operand::Nothing,
+ ];
+ } else {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
}
0b01 |
0b11 => {