diff options
Diffstat (limited to 'aarch64_small/armV8.sail')
| -rw-r--r-- | aarch64_small/armV8.sail | 2457 |
1 files changed, 2457 insertions, 0 deletions
diff --git a/aarch64_small/armV8.sail b/aarch64_small/armV8.sail new file mode 100644 index 00000000..a3082261 --- /dev/null +++ b/aarch64_small/armV8.sail @@ -0,0 +1,2457 @@ +/*========================================================================*/ +/* */ +/* Copyright (c) 2015-2017 Shaked Flur */ +/* Copyright (c) 2015-2017 Kathyrn Gray */ +/* All rights reserved. */ +/* */ +/* This software was developed by the University of Cambridge Computer */ +/* Laboratory as part of the Rigorous Engineering of Mainstream Systems */ +/* (REMS) project, funded by EPSRC grant EP/K008528/1. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions */ +/* are met: */ +/* 1. Redistributions of source code must retain the above copyright */ +/* notice, this list of conditions and the following disclaimer. */ +/* 2. Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in */ +/* the documentation and/or other materials provided with the */ +/* distribution. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' */ +/* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED */ +/* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A */ +/* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR */ +/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF */ +/* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND */ +/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, */ +/* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT */ +/* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF */ +/* SUCH DAMAGE. */ +/*========================================================================*/ + + + +union ast ('R : Int, /* register size */ + 'D : Int), /* data size */ + 'R in {32, 64} & 'D in {8,16,32,64} + = +{ + Unallocated : unit, + ImplementationDefinedTestBeginEnd : boolean, + ImplementationDefinedStopFetching : unit, + ImplementationDefinedThreadStart : unit, + + /* transactional memory, not part of the official spec */ + TMStart : reg_index, + TMCommit : unit, + TMAbort : (boolean,bits(5)), + TMTest : unit, + + CompareAndBranch : (reg_index, atom('R), boolean, bits(64)), + BranchConditional : (bits(64), bits(4)), + GenerateExceptionEL1 : (bits(16)), /* TODO: add to .hgen */ + GenerateExceptionEL2 : (bits(16)), /* TODO: add to .hgen */ + GenerateExceptionEL3 : (bits(16)), /* TODO: add to .hgen */ + DebugBreakpoint : (bits(16)), /* TODO: add to .hgen */ + ExternalDebugBreakpoint : unit, /* TODO: add to .hgen */ + DebugSwitchToExceptionLevel : (bits(2)), /* TODO: add to .hgen */ + MoveSystemImmediate : (bits(4),PSTATEField), + Hint : (SystemHintOp), + ClearExclusiveMonitor : (uinteger), + Barrier : (MemBarrierOp,MBReqDomain,MBReqTypes), + System : (reg_index,uinteger,uinteger,uinteger,uinteger,uinteger,boolean), + MoveSystemRegister : (reg_index,uinteger,uinteger,uinteger,uinteger,uinteger,boolean), + TestBitAndBranch : (reg_index,atom('R),uinteger,bit,bits(64)), + BranchImmediate : (BranchType,bits(64)), + BranchRegister : (reg_index,BranchType), + ExceptionReturn : unit, /* TODO: add to .hgen */ + DebugRestorePState : unit, /* TODO: add to .hgen */ + LoadLiteral : (reg_index,MemOp,boolean,uinteger,bits(64),atom('D)), + LoadStoreAcqExc : (reg_index,reg_index,reg_index,reg_index,AccType,boolean,boolean,MemOp,uinteger,atom('R),atom('D)), + LoadStorePairNonTemp : (boolean,boolean,reg_index,reg_index,reg_index,AccType,MemOp,uinteger,atom('D),bits(64)), + LoadImmediate : (reg_index,reg_index,AccType,MemOp,boolean,boolean,boolean,bits(64),atom('R),atom('D)), + LoadRegister : (reg_index,reg_index,reg_index,AccType,MemOp,boolean,boolean,boolean,ExtendType,uinteger,atom('R),atom('D)), + LoadStorePair : (boolean,boolean,reg_index,reg_index,reg_index,AccType,MemOp,boolean,atom('D),bits(64)), + AddSubImmediate : (reg_index,reg_index,atom('R),boolean,boolean,bits('R)), + BitfieldMove : (reg_index,reg_index,atom('R),boolean,boolean,uinteger,uinteger,bits('R),bits('R)), + ExtractRegister : (reg_index,reg_index,reg_index,('R),uinteger), + LogicalImmediate : (reg_index,reg_index,('R),boolean,LogicalOp,bits('R)), + MoveWide : (reg_index,('R),bits(16),uinteger,MoveWideOp), + Address : (reg_index,boolean,bits(64)), + AddSubExtendRegister : (reg_index,reg_index,reg_index,atom('R),boolean,boolean,ExtendType,range(0,7)), + AddSubShiftedRegister : (reg_index,reg_index,reg_index,atom('R),boolean,boolean,ShiftType,range(0,63)), + AddSubCarry : (reg_index,reg_index,reg_index,atom('R),boolean,boolean), + ConditionalCompareImmediate : (reg_index,atom('R),boolean,bits(4),bits(4),bits('R)), + ConditionalCompareRegister : (reg_index,reg_index,atom('R),boolean,bits(4),bits(4)), + ConditionalSelect : (reg_index,reg_index,reg_index,atom('R),bits(4),boolean,boolean), + Reverse : (reg_index,reg_index,atom('R),RevOp), + CountLeading : (reg_index,reg_index,atom('R),CountOp), + Division : (reg_index,reg_index,reg_index,atom('R),boolean), + Shift : (reg_index,reg_index,reg_index,atom('R),ShiftType), + CRC : (reg_index,reg_index,reg_index,atom('D),boolean), + MultiplyAddSub : (reg_index,reg_index,reg_index,reg_index,atom('R),atom('D),boolean), + MultiplyAddSubLong : (reg_index,reg_index,reg_index,reg_index,atom('R),atom('D),boolean,boolean), + MultiplyHigh : (reg_index,reg_index,reg_index,reg_index,atom('R),atom('D),boolean), + LogicalShiftedRegister : (reg_index,reg_index,reg_index,atom('R),boolean,LogicalOp,ShiftType,range(0,63),boolean), +} + +val execute : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. ast('R,'D) -> unit effect {rreg,wreg,rmem,barr,eamem,wmv,exmem,escape} +scattered function execute + +/* TSTART - dummy decoding */ +val decodeTMStart : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. bits(5) -> option (ast('R,'D)) +function decodeTMStart (Rt) = { + t : reg_index = UInt_reg(Rt); + Some(TMStart(t)); +} + +/* transactional memory, not part of the official spec */ +function clause execute (TMStart(t)) = { + nesting : bits(8) = TxNestingLevel; + + if nesting <_u TXIDR_EL0.DEPTH then { + TxNestingLevel = nesting + 1; + status : bits(64) = 0; + if nesting == 0 then + status = TMStartEffect; /* fake effect */ + wX(t) = status; + } else { + status : bits(64) = 0; + status[10] = 1; /* set the NEST bit */ + TMAbortEffect = status; /* fake effect */ + } +} + +/* external */ val TMCommitEffect : unit -> unit effect {barr} + +/* TCOMMIT - dummy decoding */ +val decodeTMCommit : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + unit -> option(ast('R,'D)) effect pure +function decodeTMCommit () = { + Some(TMCommit); +} + +/* transactional memory, not part of the official spec */ +function clause execute (TMCommit) = { + nesting : bits(8) = TxNestingLevel; + + if nesting == 1 then + TMCommitEffect() /* fake effect */ + else if nesting == 0 then + AArch64_UndefinedFault(); + + TxNestingLevel = nesting - 1; +} + +/* TTEST - dummy decoding */ +val decodeTMTest : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + unit -> option(ast('R,'D)) effect pure +function decodeTMTest () = { + Some(TMTest); +} + +/* transactional memory, not part of the official spec */ +function clause execute (TMTest) = { + if TxNestingLevel > 0 then + wPSTATE_NZCV() = 0b0000 + else + wPSTATE_NZCV() = 0b0100 +} + +/* TABORT - dummy decoding */ +val decodeTMAbort : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(6) -> option(ast('R,'D)) effect pure +function decodeTMAbort ([R] @ (imm5 : bits(5))) = { + Some(TMAbort(R,imm5)); +} + +/* transactional memory, not part of the official spec */ +function clause execute (TMAbort(retry,reason)) = { + if TxNestingLevel > 0 then { + status : bits(64) = 0; + status[4..0] = reason; /* REASON */ + status[8] = retry; /* RTRY */ + status[9] = 1; /* ABRT */ + TMAbortEffect = status; /* fake effect */ + }; +} + +/* CBNZ */ +/* CBZ */ +val decodeCompareBranchImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeCompareBranchImmediate ([sf]@0b011010@[op]@(imm19:bits(19))@Rt) = { + t : reg_index = UInt_reg(Rt); + datasize : atom('R) = if sf == 1 then 64 else 32; + iszero : boolean = (op == 0); + offset : bits(64) = SignExtend(imm19@0b00); + + Some(CompareAndBranch(t,datasize,iszero,offset)); +} + +function clause execute (CompareAndBranch(t,datasize,iszero,offset)) = { + operand1 : bits('R) = rX(t); + if IsZero(operand1) == iszero then + BranchTo(rPC() + offset, BranchType_JMP); +} + +/* B.cond */ +val decodeConditionalBranchImmediate: forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeConditionalBranchImmediate (0b0101010@0b0@(imm19 : bits(19))@0b0@ _cond) = +{ + offset : bits(64) = SignExtend(imm19@0b00); + condition : bits(4) = _cond; + + Some(BranchConditional(offset,condition)); +} + +function clause execute (BranchConditional(offset,condition)) = { + if ConditionHolds(condition) then + BranchTo(rPC() + offset, BranchType_JMP); +} + + +val decodeExceptionGeneration : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +scattered function decodeExceptionGeneration + +/* SVC */ +function clause decodeExceptionGeneration (0b11010100@0b000@(imm16 : bits(16))@0b000@0b01) = { + imm : bits(16) = imm16; + Some(GenerateExceptionEL1(imm)) +} + +function clause execute (GenerateExceptionEL1(imm)) = { + AArch64_CallSupervisor(imm); +} + +/* HVC */ +function clause decodeExceptionGeneration (0b11010100@0b000@(imm16 : bits(16))@0b000@0b10) = { + imm : bits(16) = imm16; + Some(GenerateExceptionEL2(imm)) +} + +function clause execute (GenerateExceptionEL2(imm)) = +{ + if ~(HaveEL(EL2)) | PSTATE_EL == EL0 | (PSTATE_EL == EL1 & IsSecure()) then + UnallocatedEncoding(); + + hvc_enable : bit = if HaveEL(EL3) then SCR_EL3.HCE else NOT'(HCR_EL2.HCD); + if hvc_enable == 0 then + AArch64_UndefinedFault() + else + AArch64_CallHypervisor(imm); +} + +/* SMC */ +function clause decodeExceptionGeneration (0b11010100@0b000@(imm16 : bits(16))@0b000@0b11) = { + imm : bits(16) = imm16; + Some(GenerateExceptionEL3(imm)) +} + +function clause execute (GenerateExceptionEL3(imm)) = { + if ~(HaveEL(EL3)) | PSTATE_EL == EL0 then + UnallocatedEncoding(); + + AArch64_CheckForSMCTrap(imm); + + if SCR_EL3.SMD == 1 then + /* SMC disabled */ + AArch64_UndefinedFault() + else + AArch64_CallSecureMonitor(imm); +} + +/* BRK */ +function clause decodeExceptionGeneration (0b11010100@0b001@(imm16 : bits(16))@0b000@0b00) = { + comment : bits(16) = imm16; + Some(DebugBreakpoint(comment)) +} + +function clause execute (DebugBreakpoint(comment)) = { + AArch64_SoftwareBreakpoint(comment); +} + +/* HLT */ +function clause decodeExceptionGeneration (0b11010100@0b010@(imm16 : bits(16))@0b000@0b00) = { + /* FIXME: we don't allow register reads in the decoding, but we probably should */ + /* ARM: if EDSCR.HDE == 0 | ~(HaltingAllowed()) then AArch64_UndefinedFault(); /* ARM: UndefinedFault() */ */ + + Some(ExternalDebugBreakpoint); +} + + +function clause execute (ExternalDebugBreakpoint) = { + Halt(DebugHalt_HaltInstruction); +} + +/* DCPS1 LL=0b01*/ +/* DCPS2 LL=0b10*/ +/* DCPS3 LL=0b11*/ +function clause decodeExceptionGeneration (0b11010100@0b101@(imm16 : bits(16))@0b000@(LL : bits(2))) = { + target_level : bits(2) = LL; + if LL == 0b00 then UnallocatedEncoding(); + /* FIXME: we don't allow register reads in the decoding */ + /* ARM: if ~(Halted()) then AArch64_UndefinedFault(); */ + + Some(DebugSwitchToExceptionLevel(target_level)); +} + +function clause execute (DebugSwitchToExceptionLevel(target_level)) = { + DCPSInstruction(target_level); +} + +end decodeExceptionGeneration + +val decodeSystem : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +scattered function decodeSystem + +/* MSR (immediate) */ +function clause decodeSystem (0b1101010100@[0]@0b00@(op1 : bits(3))@0b0100@CRm@(op2 : bits(3))@0b11111) = { + /* FIXME: we don't allow register reads in the decoding */ + /* ARM: CheckSystemAccess(0b00, op1, 0b0100, CRm, op2, 0b11111, 0); */ + + operand : bits(4) = CRm; + field : PSTATEField = 0; /* ARM: uninitialized */ + match op1@op2 { + (0b000@0b101) => field = PSTATEField_SP, + (0b011@0b110) => field = PSTATEField_DAIFSet, + (0b011@0b111) => field = PSTATEField_DAIFClr, + _ => UnallocatedEncoding() + }; + + /* FIXME: we don't allow register reads in the decoding */ + /* FIXME: it is not clear why this check is here. How is it different + than the CheckSystemAccess above? */ + /*Check that an AArch64 MSR/MRS access to the DAIF flags is permitted*/ + /* ARM: if op1 == 0b011 & PSTATE_EL == EL0 & SCTLR_EL1.UMA == 0 then + AArch64_SystemRegisterTrap(EL1, 0b00, op2, op1, 0b0100, 0b11111, CRm, 0);*/ + + Some(MoveSystemImmediate(operand,field)); +} + +function clause execute ( MoveSystemImmediate(operand,field) ) = { + match field { + PSTATEField_SP => PSTATE_SP = operand[0], + PSTATEField_DAIFSet => { + PSTATE_D = (PSTATE_D | operand[3]); + PSTATE_A = (PSTATE_A | operand[2]); + PSTATE_I = (PSTATE_I | operand[1]); + PSTATE_F = (PSTATE_F | operand[0]); + }, + PSTATEField_DAIFClr => { + PSTATE_D = (PSTATE_D & NOT'(operand[3])); + PSTATE_A = (PSTATE_A & NOT'(operand[2])); + PSTATE_I = (PSTATE_I & NOT'(operand[1])); + PSTATE_F = (PSTATE_F & NOT'(operand[0])); + } + } +} + +/* HINT */ +function clause decodeSystem (0b1101010100@[0]@0b00@0b011@0b0010@(CRm : bits(4))@(op2 : bits(3))@0b11111) = { + op : SystemHintOp = 0; /* ARM: uninitialized */ + + match CRm@op2 { + (0b0000@0b000) => op = SystemHintOp_NOP, + (0b0000@0b001) => op = SystemHintOp_YIELD, + (0b0000@0b010) => op = SystemHintOp_WFE, + (0b0000@0b011) => op = SystemHintOp_WFI, + (0b0000@0b100) => op = SystemHintOp_SEV, + (0b0000@0b101) => op = SystemHintOp_SEVL, + _ => op = SystemHintOp_NOP + }; + + Some(Hint(op)); +} + +function clause execute ( Hint(op) ) = { + match op { + SystemHintOp_YIELD => + Hint_Yield(), + + SystemHintOp_WFE => { + if EventRegistered() then + ClearEventRegister() + else { + if PSTATE_EL == EL0 then + AArch64_CheckForWFxTrap(EL1, true); + if HaveEL(EL2) & ~(IsSecure()) & (PSTATE_EL == EL0 | PSTATE_EL == EL1) then + AArch64_CheckForWFxTrap(EL2, true); + if HaveEL(EL3) & PSTATE_EL != EL3 then + AArch64_CheckForWFxTrap(EL3, true); + WaitForEvent(); + } + }, + + SystemHintOp_WFI => { + if ~(InterruptPending()) then { + if PSTATE_EL == EL0 then + AArch64_CheckForWFxTrap(EL1, false); + if HaveEL(EL2) & ~(IsSecure()) & (PSTATE_EL == EL0 | PSTATE_EL == EL1) then + AArch64_CheckForWFxTrap(EL2, false); + if HaveEL(EL3) & PSTATE_EL != EL3 then + AArch64_CheckForWFxTrap(EL3, false); + WaitForInterrupt(); + }; + }, + + SystemHintOp_SEV => + SendEvent(), + + SystemHintOp_SEVL => + EventRegisterSet(), + + _ => () /* do nothing */ + } +} + +/* CLREX */ +function clause decodeSystem (0b1101010100@[0]@0b00@0b011@0b0011@(CRm : bits(4))@0b010@0b11111) = { + /* ARM: // CRm field is ignored */ + imm : uinteger = CRm; /* we need CRm for pretty printing */ + Some(ClearExclusiveMonitor(imm)); +} + +function clause execute (ClearExclusiveMonitor(imm)) = { + ClearExclusiveLocal(ProcessorID()); +} + +/* DMB opc=0b01*/ +/* DSB opc=0b00*/ +/* ISB opc=0b10*/ +function clause decodeSystem (0b1101010100@[0]@0b00@0b011@0b0011@(CRm : bits(4))@[1]@opc@0b11111) = { + /* TODO: according to ARM, HCR_EL2.BSU affect the domain, but the pseudo + code doesn't show any signs of that */ + op : MemBarrierOp = 0; /* ARM: uninitialized */ + domain : MBReqDomain = 0; /* ARM: uninitialized */ + types : MBReqTypes = 0; /* ARM: uninitialized */ + + match opc { + 0b00 => op = MemBarrierOp_DSB, + 0b01 => op = MemBarrierOp_DMB, + 0b10 => op = MemBarrierOp_ISB, + _ => UnallocatedEncoding() + }; + + match CRm[3..2] { + 0b00 => domain = MBReqDomain_OuterShareable, + 0b01 => domain = MBReqDomain_Nonshareable, + 0b10 => domain = MBReqDomain_InnerShareable, + 0b11 => domain = MBReqDomain_FullSystem + }; + + match CRm[1..0] { + 0b01 => types = MBReqTypes_Reads, + 0b10 => types = MBReqTypes_Writes, + 0b11 => types = MBReqTypes_All, + _ => { + types = MBReqTypes_All; + domain = MBReqDomain_FullSystem; + } + }; + + Some(Barrier(op,domain,types)); +} + +function clause execute ( Barrier(op,domain,types) ) = { + match op { + MemBarrierOp_DSB => + DataSynchronizationBarrier(domain, types), + MemBarrierOp_DMB => + DataMemoryBarrier(domain, types), + MemBarrierOp_ISB => + InstructionSynchronizationBarrier() + }; +} + +/* SYS L=0b0 */ +/* SYSL L=0b1 */ +function clause decodeSystem (0b1101010100@[L]@0b01@(op1 : bits(3))@(CRn : bits(4))@(CRm : bits(4))@(op2 : bits(3))@Rt) = { + /* FIXME: we don't allow register reads in the decoding */ + /* ARM: CheckSystemAccess(0b01, op1, CRn, CRm, op2, Rt, L);*/ + + t : reg_index = UInt_reg(Rt); + + sys_op0 : uinteger = 1; + sys_op1 : uinteger = UInt(op1); + sys_op2 : uinteger = UInt(op2); + sys_crn : uinteger = UInt(CRn); + sys_crm : uinteger = UInt(CRm); + has_result : boolean = (L == 1); + + Some(System(t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,has_result)); +} + +function clause execute ( System(t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,has_result) ) = +{ + if has_result then + wX(t) = SysOp_R(sys_op0, sys_op1, sys_crn, sys_crm, sys_op2) + else + SysOp_W(sys_op0, sys_op1, sys_crn, sys_crm, sys_op2, rX(t)); +} + +/* MRS L=1 */ +/* MSR (register) L=0 */ +function clause decodeSystem (0b1101010100@[L]@[1]@[o0]@(op1 : bits(3))@(CRn : bits(4))@(CRm : bits(4))@(op2 : bits(3))@Rt) = { + /* FIXME: we don't allow register reads in the decoding */ + /* ARM: CheckSystemAccess([0b1]:[o0], op1, CRn, CRm, op2, Rt, L); */ + + t : reg_index = UInt_reg(Rt); + + sys_op0 : uinteger = 2 + UInt([o0]); + sys_op1 : uinteger = UInt(op1); + sys_op2 : uinteger = UInt(op2); + sys_crn : uinteger = UInt(CRn); + sys_crm : uinteger = UInt(CRm); + read : boolean = (L == 1); + + Some(MoveSystemRegister(t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read)); +} + +function clause execute ( MoveSystemRegister(t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read) ) = { + if read then + wX(t) = System_Get(sys_op0, sys_op1, sys_crn, sys_crm, sys_op2) + else + System_Put(sys_op0, sys_op1, sys_crn, sys_crm, sys_op2, rX(t)); +} + +end decodeSystem + +val decodeImplementationDefined : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +scattered function decodeImplementationDefined + +/* instructions to signal to Sail that test begins/ends */ +function clause decodeImplementationDefined (0b1101010100@[0]@0b01@0b011@[1]@[_]@0b11@0b0000@0b000@0b0000@[isEnd]) = { + Some(ImplementationDefinedTestBeginEnd(isEnd)); +} + +function clause execute ( ImplementationDefinedTestBeginEnd(isEnd) ) = { + if isEnd then + info("test ends") + else + info("test begins"); +} + +/* instructions to signal ppcmem to stop fetching */ +function clause decodeImplementationDefined (0b1101010100@[0]@0b01@0b011@[1]@[_]@0b11@0b0000@0b000@0b00010) = { + Some(ImplementationDefinedStopFetching) +} + +function clause execute ( ImplementationDefinedStopFetching ) = { + info("stop fetching instructions"); +} + +/* instructions to signal ppcmem to start a thread */ +function clause decodeImplementationDefined (0b1101010100@[0]@0b01@0b011@[1]@[_]@0b11@0b0000@0b000@0b00011) = { + Some(ImplementationDefinedThreadStart) +} + +function clause execute ( ImplementationDefinedThreadStart ) = { + info("thread start"); +} + +end decodeImplementationDefined + +/* TBNZ */ +/* TBZ */ +val decodeTestBranchImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +function decodeTestBranchImmediate ([b5]@0b011011@[op]@(b40 : bits(5))@(imm14 : bits(14))@Rt) = { + t : reg_index = UInt_reg(Rt); + + datasize : atom('R) = if b5 == 1 then 64 else 32; + bit_pos : uinteger = UInt([b5]:b40); + bit_val : bit = op; + offset : bits(64) = SignExtend(imm14@0b00); + + Some(TestBitAndBranch(t,datasize,bit_pos,bit_val,offset)); +} + +function clause execute ( TestBitAndBranch(t,datasize,bit_pos,bit_val,offset) ) = { + operand : bits('R) = rX(t); + + if operand[bit_pos] == bit_val then + BranchTo(rPC() + offset, BranchType_JMP); +} + +/* B */ +/* BL */ +val decodeUnconditionalBranchImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +function decodeUnconditionalBranchImmediate ([op]@0b00101@(imm26 : bits(26))) = { + branch_type : BranchType = if op == 1 then BranchType_CALL else BranchType_JMP; + offset : bits(64) = SignExtend(imm26@0b00); + + Some(BranchImmediate(branch_type,offset)); +} + +function clause execute (BranchImmediate(branch_type,offset)) = { + if branch_type == BranchType_CALL then wX(30) = rPC() + 4; + + BranchTo(rPC() + offset, branch_type); +} + + +val decodeUnconditionalBranchRegister : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +scattered function decodeUnconditionalBranchRegister + +/* BLR */ +/* BR */ +/* RET */ +function clause decodeUnconditionalBranchRegister (0b1101011@0b00@op@0b11111@0b000000@Rn@0b00000) = { + n : reg_index = UInt_reg(Rn); + branch_type : BranchType = 0; /* ARM: uninitialized */ + + match op { + 0b00 => branch_type = BranchType_JMP, + 0b01 => branch_type = BranchType_CALL, + 0b10 => branch_type = BranchType_RET, + _ => UnallocatedEncoding() + }; + + Some(BranchRegister(n,branch_type)); +} + +function clause execute (BranchRegister(n,branch_type)) = { + target : bits(64) = rX(n); + + if branch_type == BranchType_CALL then wX(30) = rPC() + 4; + BranchTo(target, branch_type); +} + +/* ERET */ +function clause decodeUnconditionalBranchRegister (0b1101011@0b0100@0b11111@0b000000@0b11111@0b00000) = { + /* FIXME: we don't allow register reads in the decoding */ + /* ARM: if PSTATE_EL == EL0 then UnallocatedEncoding(); */ + + Some(ExceptionReturn); +} + +function clause execute (ExceptionReturn) = { + AArch64_ExceptionReturn(rELR'(), rSPSR()); +} + +/* DRPS */ +function clause decodeUnconditionalBranchRegister (0b1101011@0b0101@0b11111@0b000000@0b11111@0b00000) = { + /* FIXME: we don't allow register reads in the decoding */ + /* ARM: if ~(Halted()) | PSTATE_EL == EL0 then UnallocatedEncoding(); */ + + Some(DebugRestorePState); +} + +function clause execute (DebugRestorePState) = { + DRPSInstruction(); +} + +end decodeUnconditionalBranchRegister + +val decodeAdvSIMDLoadStoreMultiStruct : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +function decodeAdvSIMDLoadStoreMultiStruct (machineCode) = { + not_implemented("decodeAdvSIMDLoadStoreMultiStruct"); + Some(Unallocated); +} + +val decodeAdvSIMDLoadStoreMultiStructPostIndexed : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +function decodeAdvSIMDLoadStoreMultiStructPostIndexed (machineCode) = { + not_implemented("decodeAdvSIMDLoadStoreMultiStructPostIndexed"); + Some(Unallocated); +} + +val decodeAdvSIMDLoadStoreSingleStruct : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +function decodeAdvSIMDLoadStoreSingleStruct (machineCode) = { + not_implemented("decodeAdvSIMDLoadStoreSingleStruct"); + Some(Unallocated); +} + +val decodeAdvSIMDLoadStoreSingleStructPostIndexed : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +function decodeAdvSIMDLoadStoreSingleStructPostIndexed (machineCode) = { + not_implemented("decodeAdvSIMDLoadStoreSingleStructPostIndexed"); + Some(Unallocated); +} + +/* LDR (literal) opc=0b0_ */ +/* LDRSW (literal) opc=0b10 */ +/* PRFM (literal) opc=0b11 */ +val decodeLoadRegisterLiteral : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) +function decodeLoadRegisterLiteral ((opc : bits(2))@0b011@[0]@0b00@(imm19 : bits(19))@Rt) = { + t : reg_index = UInt_reg(Rt); + memop : MemOp = MemOp_LOAD; + _signed : boolean = false; + size : uinteger = 0; /* ARM: uninitialized */ + offset : bits(64) = 4; /* ARM: uninitialized */ + + match opc { + 0b00 => + size = 4, /* LDR (literal) 32 */ + 0b01 => + size = 8, /* LDR (literal) 64 */ + 0b10 => { /* LDRSW (literal) */ + size = 4; + _signed = true; + }, + 0b11 => /* PRFM (literal) */ + memop = MemOp_PREFETCH + }; + + offset = SignExtend(imm19@0b00); + + datasize : atom('D) = size*8; /* not in ARM ARM */ + + Some(LoadLiteral(t,memop,_signed,size,offset,datasize)); +} + +function clause execute ( LoadLiteral(t,memop,_signed,size,offset,(datasize : atom('D))) ) = { + address : bits(64) = rPC() + offset; + data : bits('D) = 0; /* ARM: uninitialized */ + + match memop { + MemOp_LOAD => { + data = flush_read_buffer( + rMem(empty_read_buffer, address, size, AccType_NORMAL), + size + ); + if _signed then + wX(t) = SignExtend(data) : bits(64) + else + wX(t) = data; + }, + MemOp_PREFETCH => + Prefetch(address,t : bits(5)) + }; +} + +/* LDAR size=0b1_,o2=1,L=1,o1=0,o0=1,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* LDARB size=0b00,o2=1,L=1,o1=0,o0=1,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* LDARH size=0b01,o2=1,L=1,o1=0,o0=1,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* LDAXP size=0b1_,o2=0,L=1,o1=1,o0=1,rs=(1)(1)(1)(1)(1) */ +/* LDAXR size=0b1_,o2=0,L=1,o1=0,o0=1,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* LDAXRB size=0b00,o2=0,L=1,o1=0,o0=1,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* LDAXRH size=0b01,o2=0,L=1,o1=0,o0=1,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* LDXP size=0b1_,o2=0,L=1,o1=1,o0=0,rs=(1)(1)(1)(1)(1) */ +/* LDXR size=0b1_,o2=0,L=1,o1=0,o0=0,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* LDXRB size=0b00,o2=0,L=1,o1=0,o0=0,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* LDXRH size=0b01,o2=0,L=1,o1=0,o0=0,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* STLR size=0b1_,o2=1,L=0,o1=0,o0=1,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* STLRB size=0b00,o2=1,L=0,o1=0,o0=1,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* STLRH size=0b01,o2=1,L=0,o1=0,o0=1,rs=(1)(1)(1)(1)(1),rt2=(1)(1)(1)(1)(1) */ +/* STLXP size=0b1_,o2=0,L=0,o1=1,o0=1 */ +/* STLXR size=0b1_,o2=0,L=0,o1=0,o0=1, rt2=(1)(1)(1)(1)(1) */ +/* STLXRB size=0b00,o2=0,L=0,o1=0,o0=1, rt2=(1)(1)(1)(1)(1) */ +/* STLXRH size=0b01,o2=0,L=0,o1=0,o0=1, rt2=(1)(1)(1)(1)(1) */ +/* STXP size=0b1_,o2=0,L=0,o1=1,o0=0 */ +/* STXR size=0b1_,o2=0,L=0,o1=0,o0=0, rt2=(1)(1)(1)(1)(1) */ +/* STXRB size=0b00,o2=0,L=0,o1=0,o0=0, rt2=(1)(1)(1)(1)(1) */ +/* STXRH size=0b01,o2=0,L=0,o1=0,o0=0, rt2=(1)(1)(1)(1)(1) */ +val decodeLoadStoreExclusive : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreExclusive ((size : bits(2))@0b001000@[o2]@[L]@[o1]@Rs@[o0]@Rt2@Rn@Rt) = { + n : reg_index = UInt_reg(Rn); + t : reg_index = UInt_reg(Rt); + t2 : reg_index = UInt_reg(Rt2); /* ignored by load/store single register */ + s : reg_index= UInt_reg(Rs); /* ignored by all loads and store-release */ + + if ([o2,o1,o0]) == 0b100 | ([o2,o1] == 0b11) then UnallocatedEncoding(); + if o1 == 1 & size[1] == 0 then UnallocatedEncoding(); + + acctype : AccType = if o0 == 1 then AccType_ORDERED else AccType_ATOMIC; + excl : boolean = (o2 == 0); + pair : boolean = (o1 == 1); + memop : MemOp = if L == 1 then MemOp_LOAD else MemOp_STORE; + elsize = lsl(8, UInt(size)); + regsize : atom('R) = if elsize == 64 then 64 else 32; + datasize : atom('D) = if pair then elsize * 2 else elsize; + + /* lemma: pair --> datasize = 2*regsize */ + /* follows from "if o1 == 1 & size[1] == 0 then UnallocatedEncoding();" */ + + Some(LoadStoreAcqExc(n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,datasize)); +} + +function clause execute ( LoadStoreAcqExc(n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,(datasize :atom('D)) )) = { + address : bits(64) = 0; /* ARM: uninitialized */ + data : bits('D) = 0; /* ARM: uninitialized */ + /*constant*/ dbytes : uinteger = quot (datasize,8); + rt_unknown : boolean = false; + rn_unknown : boolean = false; + + if memop == MemOp_LOAD & pair & t == t2 then { + UnallocatedEncoding(); /* ARM: + (Constraint) c = ConstrainUnpredictable(); + assert( vIN(c, [Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP]) ); + switch c { + Constraint_UNKNOWN => rt_unknown =: true /* result is UNKNOWN */ + Constraint_UNDEF => UnallocatedEncoding() + Constraint_NOP => EndOfInstruction() + };*/ + }; + + if memop == MemOp_STORE & excl then { + if s == t | (pair & s == t2) then { + UnallocatedEncoding(); /* ARM: + (Constraint) c = ConstrainUnpredictable(); + assert( vIN(c, [Constraint_UNKNOWN, Constraint_NONE, Constraint_UNDEF, Constraint_NOP]) ); + switch c { + Constraint_UNKNOWN => rt_unknown = true /* store UNKNOWN value */ + Constraint_NONE => rt_unknown = false /* store original value */ + Constraint_UNDEF => UnallocatedEncoding() + Constraint_NOP => EndOfInstruction() + };*/ + }; + if s == n & n != 31 then { + UnallocatedEncoding(); /* ARM: + (Constraint) c = ConstrainUnpredictable(); + assert( vIN(c, [Constraint_UNKNOWN, Constraint_NONE, Constraint_UNDEF, Constraint_NOP]) ); + switch c { + Constraint_UNKNOWN => rn_unknown = true /* address is UNKNOWN */ + Constraint_NONE => rn_unknown = false /* address is original base */ + Constraint_UNDEF => UnallocatedEncoding() + Constraint_NOP => EndOfInstruction() + };*/ + }; + }; + + /* this is a hack to allow the result of store-exclusive to be observed + before anything else */ + status : bit = 0; + if memop == MemOp_STORE & excl then { + /*(bit)*/ status = if speculate_exclusive_success() then 0 else 1; + wX(s) = ZeroExtend([status]) : bits(32); + + /* should be: + if status == 1 then return (); + */ + }; + if status == 1 then () else { + + if n == 31 then { + CheckSPAlignment(); + address = rSP(); + } else if rn_unknown then + address = UNKNOWN : bits(64) + else + address = rX(n); + + match memop { + MemOp_STORE => { + /* anounce the address */ + wMem_Addr(address, dbytes, acctype, excl); + + if rt_unknown then + data = UNKNOWN : bits('D) + else if pair then { + assert( excl, None ); + el1 : bits('R) = rX(t); /* ARM: bits(datasize / 2) see lemma in the decoding */ + el2 : bits('R) = rX(t2); /* ARM: bits(datasize / 2) see lemma in the decoding */ + data = if BigEndian() then el1:el2 else el2:el1; + } else + data : bits('D) = rX(t); + + if excl then { + /* store {release} exclusive register|pair (atomic) */ + status : bit = 1; + /* Check whether the Exclusive Monitors are set to include the */ + /* physical memory locations corresponding to virtual address */ + /* range [address, address+dbytes-1]. */ + if AArch64_ExclusiveMonitorsPass(address, dbytes) then { + /* This atomic write will be rejected if it does not refer */ + /* to the same physical locations after address translation. */ + /* ARM: wMem(address, dbytes, acctype) = data; + status = ExclusiveMonitorsStatus(); */ + status = flush_write_buffer_exclusive( + wMem_exclusive(empty_write_buffer, address, dbytes, acctype, data) + ); + }; + /* ARM: the following code was moved up, see note there + wX(s) = (bits(32)) (ZeroExtend([status])); + */ + } else { + /* store release register (atomic) */ + flush_write_buffer( + wMem(empty_write_buffer, address, dbytes, acctype, data) + ); + }; + }, + + MemOp_LOAD => { + if excl then { + /* Tell the Exclusive Monitors to record a sequence of one or more atomic */ + /* memory reads from virtual address range [address, address+dbytes-1]. */ + /* The Exclusive Monitor will only be set if all the reads are from the */ + /* same dbytes-aligned physical address, to allow for the possibility of */ + /* an atomicity break if the translation is changed between reads. */ + AArch64_SetExclusiveMonitors(address, dbytes); + }; + + if pair then { + /* load exclusive pair */ + assert( excl, None ); + if rt_unknown then + /* ConstrainedUNPREDICTABLE case */ + wX(t) = UNKNOWN : bits('D) + else if elsize == 32 then { + /* 32-bit load exclusive pair (atomic) */ + data = flush_read_buffer( + rMem_exclusive(empty_read_buffer, address, dbytes, acctype), + dbytes + ); + if BigEndian() then { + wX(t) = data[(datasize - 1)..elsize]; + wX(t2) = data[(elsize - 1)..0]; + } else { + wX(t) = data[(elsize - 1)..0]; + wX(t2) = data[(datasize - 1)..elsize]; + }; + } else { /* elsize == 64 */ + /* 64-bit load exclusive pair (not atomic), */ + /* but must be 128-bit aligned */ + if address != Align(address, dbytes) then { + iswrite : boolean = false; + secondstage : boolean = false; + AArch64_Abort(address, AArch64_AlignmentFault(acctype, iswrite, secondstage)); + }; + read_buffer : read_buffer_type = rMem_exclusive(empty_read_buffer, address + 0, 8, acctype); + read_buffer = rMem_exclusive(read_buffer, address + 8, 8, acctype); + value : bits(128) = flush_read_buffer(read_buffer, 8*2); + wX(t) = value[63..0]; + wX(t2) = value[127..64]; + }; + } else { + /* load {acquire} {exclusive} single register */ + data = flush_read_buffer( + rMem'(empty_read_buffer, address, dbytes, acctype, excl), + dbytes + ); + wX(t) = ZeroExtend(data) : bits('R); + }; + } + }; + }; +} + +/* LDNP */ +/* STNP */ +val decodeLoadStoreNoAllocatePairOffset : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreNoAllocatePairOffset ((opc : bits(2))@0b101@[0]@0b000@[L]@(imm7 : bits(7))@Rt2@Rn@Rt) = { + wback : boolean = false; + postindex : boolean = false; + + /* Shared decode */ + + n : reg_index = UInt_reg(Rn); + t : reg_index = UInt_reg(Rt); + t2 : reg_index = UInt_reg(Rt2); + acctype : AccType = AccType_STREAM; + memop : MemOp = if L == 1 then MemOp_LOAD else MemOp_STORE; + if opc[0] == 1 then UnallocatedEncoding(); + scale : uinteger = 2 + UInt([opc[1]]); + datasize : atom('D) = lsl(8, scale); + offset : bits(64) = LSL(SignExtend(imm7), scale); + + Some(LoadStorePairNonTemp(wback,postindex,n,t,t2,acctype,memop,scale,datasize,offset)); +} + +function clause execute ( LoadStorePairNonTemp(wback,postindex,n,t,t2,acctype,memop,scale,(datasize : atom('D)),offset) ) = { + address : bits(64) = 0; /* ARM: uninitialized */ + data1 : bits('D) = 0; /* ARM: uninitialized */ + data2 : bits('D) = 0; /* ARM: uninitialized */ + /*constant*/ dbytes : uinteger = quot(datasize,8); + rt_unknown : boolean = false; + + if memop == MemOp_LOAD & t == t2 then { + UnallocatedEncoding(); /* ARM: + Constraint c = ConstrainUnpredictable(); + assert c IN {Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP}; + + case c of + when Constraint_UNKNOWN rt_unknown = TRUE; // result is UNKNOWN + when Constraint_UNDEF UnallocatedEncoding(); + when Constraint_NOP EndOfInstruction(); + };*/ + }; + + if n == 31 then { + CheckSPAlignment(); + address = rSP(); + } else + address = rX(n); + + if ~(postindex) then + address = address + offset; + + if memop == MemOp_STORE then + /* anounce the address */ + wMem_Addr(address, dbytes * 2, acctype, false); + + /* this is a hack to allow the address write back to be observed + before the memory access */ + if wback then { + let address' = (if ~(postindex) then address else (address + offset)) : bits(64) in + if n == 31 then + wSP() = address' + else + wX(n) = address' + }; + + match memop { + MemOp_STORE => { + if rt_unknown & t == n then + data1 = UNKNOWN : bits('D) + else + data1 = rX(t); + if rt_unknown & t2 == n then + data2 = UNKNOWN : bits('D) + else + data2 = rX(t2); + + write_buffer : write_buffer_type = wMem(empty_write_buffer, address + 0, dbytes, acctype, data1); + write_buffer = wMem(write_buffer, address + dbytes, dbytes, acctype, data2); + flush_write_buffer(write_buffer); + }, + + MemOp_LOAD => { + read_buffer : read_buffer_type = rMem(empty_read_buffer, address + 0 , dbytes, acctype); + read_buffer = rMem(read_buffer, address + dbytes, dbytes, acctype); + read_data : bits('D*2) = flush_read_buffer(read_buffer, dbytes*2); + data1 = read_data[(datasize - 1)..0]; + data2 = read_data[((datasize * 2) - 1)..datasize]; + + if rt_unknown then { + data1 = UNKNOWN : bits('D); + data2 = UNKNOWN : bits('D); + }; + wX(t) = data1; + wX(t2) = data2; + } + }; + +/* ARM: the following code was moved up, see note there + if wback then { + if postindex then + address = address + offset; + if n == 31 then + wSP() = address + else + wX(n) = address; + }; +*/ +} + +function sharedDecodeLoadImmediate forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + (opc : bits(2),size : bits(2),Rn,Rt,wback,postindex,scale : uinteger,offset,acctype,prefetchAllowed : bool) -> option(ast('R,'D)) + = { + n : reg_index = UInt_reg(Rn); + t : reg_index = UInt_reg(Rt); + /* ARM: inorder to unify the decoding acctype was moved out. + AccType_UNPRIV for LDT* / STT* and AccType_NORMAL for the rest. + acctype : AccType = AccType_NORMAL/AccType_UNPRIV; */ + memop : MemOp = 0; /* ARM: uninitialized */ + _signed : boolean = false; /* ARM: uninitialized */ + regsize : atom('R) = 64; /* ARM: uninitialized */ + + if opc[1] == 0 then { + /* store or zero-extending load */ + memop = if opc[0] == 1 then MemOp_LOAD else MemOp_STORE; + regsize = if size == 0b11 then 64 else 32; + _signed = false; + } else { + if size == 0b11 then { + /* ARM: we use the following if/else to unify the decoding */ + if prefetchAllowed then { + memop = MemOp_PREFETCH; + if opc[0] == 1 then UnallocatedEncoding(); + } else { + /* no unprivileged prefetch */ + UnallocatedEncoding(); + }; + } else { + /* sign-extending load */ + memop = MemOp_LOAD; + if size == 0b10 & opc[0] == 1 then UnallocatedEncoding(); + regsize = if opc[0] == 1 then 32 else 64; + _signed = true; + }; + }; + + datasize : atom('D) = lsl(8, scale); + + Some(LoadImmediate(n,t,acctype,memop,_signed,wback,postindex,offset,regsize,datasize)); +} + +/* LDR/STR (immediate) post-index */ +/* LDRB/STRB (immediate) post-index */ +/* LDRH/STRH (immediate) post-index */ +/* LDRSB (immediate) post-index */ +/* LDRSH (immediate) post-index */ +/* LDRSW (immediate) post-index */ +val decodeLoadStoreRegisterImmediatePostIndexed : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreRegisterImmediatePostIndexed (size@0b111@[0]@0b00@opc@[0]@(imm9 : bits(9))@0b01@Rn@Rt) = { + wback : boolean = true; + postindex : boolean = true; + scale : uinteger = UInt(size); + offset : bits(64) = SignExtend(imm9); + + sharedDecodeLoadImmediate(opc,size,Rn,Rt,wback,postindex,scale,offset,AccType_NORMAL,false); +} + +function clause execute ( LoadImmediate(n,t,acctype,memop,_signed,wback,postindex,offset,regsize,datasize : atom('D)) ) = { + address : bits(64) = 0; /* ARM: uninitialized */ + data : bits('D) = 0; /* ARM: uninitialized */ + wb_unknown : boolean = false; + rt_unknown : boolean = false; + + if memop == MemOp_LOAD & wback & n == t & n != 31 then { + UnallocatedEncoding(); /* ARM: + Constraint c = ConstrainUnpredictable(); + assert( c vIN [Constraint_WBSUPPRESS, Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP] ); + switch c { + Constraint_WBSUPPRESS => wback = false /* writeback is suppressed */ + Constraint_UNKNOWN => wb_unknown = true /* writeback is UNKNOWN */ + Constraint_UNDEF => UnallocatedEncoding() + Constraint_NOP => EndOfInstruction() + };*/ + }; + + if memop == MemOp_STORE & wback & n == t & n != 31 then { + UnallocatedEncoding(); /* ARM: + Constraint c = ConstrainUnpredictable(); + assert( c vIN [Constraint_NONE, Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP] ); + switch c { + Constraint_NONE => rt_unknown = false (* value stored is original value *) + Constraint_UNKNOWN => rt_unknown = true (* value stored is UNKNOWN *) + Constraint_UNDEF => UnallocatedEncoding() + Constraint_NOP => EndOfInstruction() + };*/ + }; + + if n == 31 then { + if memop != MemOp_PREFETCH then CheckSPAlignment(); + address = rSP(); + } else + address = rX(n); + + if ~(postindex) then + address = address + offset; + + if memop == MemOp_STORE then + /* anounce the address */ + wMem_Addr(address, quot (datasize,8), acctype, false); + + /* this is a hack to allow the address write back to be observed + before the memory access */ + if wback then { + let address' = (if ~(postindex) then address else (address + offset)) : bits(64) in + if n == 31 then + wSP() = address' + else + wX(n) = address' + }; + + match memop { + MemOp_STORE => { + if rt_unknown then + data = UNKNOWN : bits('D) + else + data = rX(t); + + flush_write_buffer( + wMem(empty_write_buffer, address, quot(datasize,8), acctype, data) + ); + }, + + MemOp_LOAD => { + data = flush_read_buffer( + rMem(empty_read_buffer, address, quot(datasize,8), acctype), + quot(datasize, 8) + ); + if _signed then + wX(t) = SignExtend(data) : bits('R) /* ARM: regsize */ + else + wX(t) = ZeroExtend(data) : bits('R); /* ARM: regsize */ + }, + + MemOp_PREFETCH => + Prefetch(address,t : bits(5)) + }; + +/* ARM: the following code was moved up, see note there + if wback then { + if wb_unknown then + address = (bits(64)) UNKNOWN + else if postindex then + address = address + offset; + if n == 31 then + wSP() = address + else + wX(n) = address; + }; +*/ +} + +/* LDR/STR (immediate) pre-index */ +/* LDRB/STRB (immediate) pre-index */ +/* LDRH/STRH (immediate) pre-index */ +/* LDRSB (immediate) pre-index */ +/* LDRSH (immediate) pre-index */ +/* LDRSW (immediate) pre-index */ +val decodeLoadStoreRegisterImmediatePraeIndexed : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreRegisterImmediatePreIndexed (size@0b111@[0]@0b00@opc@[0]@(imm9 : bits(9))@0b11@Rn@Rt) = { + wback : boolean = true; + postindex : boolean = false; + scale : uinteger = UInt(size); + offset : bits(64) = SignExtend(imm9); + + sharedDecodeLoadImmediate(opc,size,Rn,Rt,wback,postindex,scale,offset,AccType_NORMAL,false); +} + +val sharedDecodeLoadRegister : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) +function sharedDecodeLoadRegister(Rn,Rt,Rm,opc : bits(2),size : bits(2),wback,postindex,scale : uinteger,extend_type,shift) = { + n : reg_index = UInt_reg(Rn); + t : reg_index = UInt_reg(Rt); + m : reg_index = UInt_reg(Rm); + acctype : AccType = AccType_NORMAL; + memop : MemOp = 0; /* ARM: uninitialized */ + _signed : boolean = 0; /* ARM: uninitialized */ + regsize : atom('R) = 64; /* ARM: uninitialized */ + + if opc[1] == 0 then { + /* store or zero-extending load */ + memop = if opc[0] == 1 then MemOp_LOAD else MemOp_STORE; + regsize = if size == 0b11 then 64 else 32; + _signed = false; + } else { + if size == 0b11 then { + memop = MemOp_PREFETCH; + if opc[0] == 1 then UnallocatedEncoding(); + } else { + /* sign-extending load */ + memop = MemOp_LOAD; + if size == 0b10 & opc[0] == 1 then UnallocatedEncoding(); + regsize = if opc[0] == 1 then 32 else 64; + _signed = true; + }; + }; + + datasize : atom('D) = lsl(8, scale); + + Some(LoadRegister(n,t,m,acctype,memop,_signed,wback,postindex,extend_type,shift,regsize,datasize)); +} + +/* LDR/STR (register) */ +/* LDRB/STRB (register) */ +/* LDRH/STRH (register) */ +/* LDRSB (register) */ +/* LDRSH (register) */ +/* LDRSW (register) */ +/* PRFM (register) */ + +val decodeLoadStoreRegisterRegisterOffset : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) +function decodeLoadStoreRegisterRegisterOffset (size@0b111@[0]@0b00@opc@[1]@Rm@option_v@[S]@0b10@Rn@Rt) = { + wback : boolean = false; + postindex : boolean = false; + scale : uinteger = UInt(size); + if option_v[1] == 0 then UnallocatedEncoding(); /* sub-word index */ + extend_type : ExtendType = DecodeRegExtend(option_v); + shift : uinteger = if S == 1 then scale else 0; + + sharedDecodeLoadRegister(Rn,Rt,Rm,opc,size,wback,postindex,scale,extend_type,shift); +} + +function clause execute ( LoadRegister(n,t,m,acctype,memop,_signed,wback,postindex,extend_type,shift,regsize,datasize : atom('D)) ) = { + offset : bits(64) = ExtendReg(m, extend_type, shift); + address : bits(64) = 0; /* ARM: uninitialized */ + data : bits('D) = 0; /* ARM: uninitialized */ + wb_unknown : boolean = false; + rt_unknown : boolean = false; + + if memop == MemOp_LOAD & wback & n == t & n != 31 then { + UnallocatedEncoding(); /* ARM: + Constraint c = ConstrainUnpredictable(); + assert( c vIN [Constraint_WBSUPPRESS, Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP] ); + switch c { + Constraint_WBSUPPRESS => wback = false (* writeback is suppressed *) + Constraint_UNKNOWN => wb_unknown = true (* writeback is UNKNOWN *) + Constraint_UNDEF => UnallocatedEncoding() + Constraint_NOP => EndOfInstruction() + };*/ + }; + + if memop == MemOp_STORE & wback & n == t & n != 31 then { + UnallocatedEncoding(); /* ARM: + Constraint c = ConstrainUnpredictable(); + assert( c vIN [Constraint_NONE, Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP] ); + switch c { + Constraint_NONE => rt_unknown = false (* value stored is original value *) + Constraint_UNKNOWN => rt_unknown = true (* value stored is UNKNOWN *) + Constraint_UNDEF => UnallocatedEncoding() + Constraint_NOP => EndOfInstruction() + };*/ + }; + + if n == 31 then { + if memop != MemOp_PREFETCH then CheckSPAlignment(); + address = rSP(); + } else + address = rX(n); + + if ~(postindex) then + address = address + offset; + + if memop == MemOp_STORE then + /* anounce the address */ + wMem_Addr(address, quot (datasize,8), acctype, false); + + /* this is a hack to allow the address write back to be observed + before the memory access */ + if wback then { + let address' = (if ~(postindex) then address else (address + offset)) : bits(64) in + if n == 31 then + wSP() = address' + else + wX(n) = address' + }; + + match memop { + MemOp_STORE => { + if rt_unknown then + data = UNKNOWN : bits('D) + else + data = rX(t); + + flush_write_buffer( + wMem(empty_write_buffer, address, quot(datasize,8), acctype, data) + ); + }, + + MemOp_LOAD => { + data = flush_read_buffer( + rMem(empty_read_buffer, address, quot(datasize,8), acctype), + quot(datasize,8) + ); + if _signed then + wX(t) = SignExtend(data) : bits('R) + else + wX(t) = ZeroExtend(data) : bits('R); + }, + + MemOp_PREFETCH => + Prefetch(address,t : bits(5)) + }; + +/* ARM: the following code was moved up, see note there + if wback then { + if wb_unknown then + address = (bits(64)) UNKNOWN + else if postindex then + address = address + offset; + if n == 31 then + wSP() = address + else + wX(n) = address; + }; +*/ +} + +/* LDTR/STTR */ +/* LDTRB/STTRB */ +/* LDTRH/STTRH */ +/* LDTRSB */ +/* LDTRSH */ +/* LDTRSW */ + +val decodeLoadStoreRegisterUnprivileged : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreRegisterUnprivileged (size@0b111@[0]@0b00@opc@[0]@(imm9 : bits(9))@0b10@Rn@Rt) = { + wback : boolean = false; + postindex : boolean = false; + scale : uinteger = UInt(size); + offset : bits(64) = SignExtend(imm9); + + sharedDecodeLoadImmediate(opc,size,Rn,Rt,wback,postindex,scale,offset,AccType_UNPRIV,false); +} + +/* LDUR/STRUR */ +/* LDURB/STURB */ +/* LDURH/STURH */ +/* LDURSB */ +/* LDURSH */ +/* LDURSW */ +/* PRFUM */ +val decodeLoadStoreRegisterUnscaledImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreRegisterUnscaledImmediate (size@0b111@[0]@0b00@opc@[0]@(imm9 : bits(9))@0b00@Rn@Rt) = { + wback : boolean = false; + postindex : boolean = false; + scale : uinteger = UInt(size); + offset : bits(64) = SignExtend(imm9); + + sharedDecodeLoadImmediate(opc,size,Rn,Rt,wback,postindex,scale,offset,AccType_NORMAL,true); +} + +/* LDR/STR (immediate) Unsigned offset */ +/* LDRB/STRB (immediate) Unsigned offset */ +/* LDRH/STRH (immediate) Unsigned offset */ +/* LDRSB (immediate) Unsigned offset */ +/* LDRSH (immediate) Unsigned offset */ +/* LDRSW (immediate) Unsigned offset */ +/* PRFM (immediate) Unsigned offset */ +val decodeLoadStoreRegisterUnsignedImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreRegisterUnsignedImmediate (size@0b111@[0]@0b01@opc@(imm12 : bits(12))@Rn@Rt) = { + wback : boolean = false; + postindex : boolean = false; + scale : uinteger = UInt(size); + offset : bits(64) = LSL(ZeroExtend(imm12), scale); + + sharedDecodeLoadImmediate(opc,size,Rn,Rt,wback,postindex,scale,offset,AccType_NORMAL,true); +} + +function sharedDecodeLoadStorePair forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + (L,opc : bits(2),imm7,Rn,Rt,Rt2,wback,postindex) -> option(ast('R,'D)) = { + n : (reg_index) = UInt_reg(Rn); + t : (reg_index) = UInt_reg(Rt); + t2 : (reg_index) = UInt_reg(Rt2); + acctype : (AccType) = AccType_NORMAL; + memop : (MemOp) = if L == 1 then MemOp_LOAD else MemOp_STORE; + if [L,opc[0]] == 0b01 | opc == 0b11 then UnallocatedEncoding(); + _signed : (boolean) = (opc[0] != 0); + scale : (uinteger) = 2 + UInt([opc[1]]); + datasize : atom('D) = lsl(8, scale); + offset : (bits(64)) = LSL(SignExtend(imm7), scale); + + Some(LoadStorePair(wback,postindex,n,t,t2,acctype,memop,_signed,datasize,offset)); +} + +/* LDP signed offset */ +/* LDPSW signed offset */ +/* STP signed offset */ +val decodeLoadStoreRegisterPairOffset : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreRegisterPairOffset (opc@0b101@[0]@0b010@[L]@(imm7 : bits(7))@Rt2@Rn@Rt) = { + wback : boolean = false; + postindex : boolean = false; + + sharedDecodeLoadStorePair(L,opc,imm7,Rn,Rt,Rt2,wback,postindex); +} + +function clause execute ( LoadStorePair(wback,postindex,n,t,t2,acctype,memop,_signed,datasize : atom('D),offset) ) = { + address : bits(64) = 0; /* ARM: uninitialized */ + data1 : (bits('D)) = 0; /* ARM: uninitialized */ + data2 : (bits('D)) = 0; /* ARM: uninitialized */ + /*constant*/ dbytes : (uinteger) = quot (datasize,8); + rt_unknown : (boolean) = false; + wb_unknown : (boolean) = false; + + if memop == MemOp_LOAD & wback & (t == n | t2 == n) & n != 31 then { + UnallocatedEncoding(); /* ARM: + Constraint c = ConstrainUnpredictable(); + assert( c vIN [Constraint_WBSUPPRESS, Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP] ); + switch c { + Constraint_WBSUPPRESS => wback = false (* writeback is suppressed *) + Constraint_UNKNOWN => wb_unknown = true, (* writeback is UNKNOWN *) + Constraint_UNDEF => UnallocatedEncoding(), + Constraint_NOP => EndOfInstruction() + };*/ + }; + + if memop == MemOp_STORE & wback & (t == n | t2 == n) & n != 31 then { + UnallocatedEncoding(); /* ARM: + Constraint c = ConstrainUnpredictable(); + assert( c vIN [Constraint_NONE, Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP] ); + switch c { + Constraint_NONE => rt_unknown = false (* value stored is pre-writeback *) + Constraint_UNKNOWN => rt_unknown = true (* value stored is UNKNOWN *) + Constraint_UNDEF => UnallocatedEncoding() + Constraint_NOP => EndOfInstruction() + };*/ + }; + + if memop == MemOp_LOAD & t == t2 then { + UnallocatedEncoding(); /* ARM + Constraint c = ConstrainUnpredictable(); + assert( c vIN [Constraint_UNKNOWN, Constraint_UNDEF, Constraint_NOP] ); + switch c { + Constraint_UNKNOWN => rt_unknown = true (* result is UNKNOWN *) + Constraint_UNDEF => UnallocatedEncoding() + Constraint_NOP => EndOfInstruction() + };*/ + }; + + if n == 31 then { + CheckSPAlignment(); + address = rSP(); + } else + address = rX(n); + + if ~(postindex) then + address = address + offset; + + if memop == MemOp_STORE then + /* anounce the address */ + wMem_Addr(address, dbytes * 2, acctype, false); + + /* this is a hack to allow the address write back to be observed + before the memory access */ + if wback then { + let address' = (if ~(postindex) then address else (address + offset)) : (bits(64)) in + if n == 31 then + wSP() = address' + else + wX(n) = address' + }; + + match memop { + MemOp_STORE => { + if rt_unknown & t == n then + data1 = UNKNOWN : (bits('D)) + else + data1 = rX(t); + if rt_unknown & t2 == n then + data2 = UNKNOWN : (bits('D)) + else + data2 = rX(t2); + + write_buffer : write_buffer_type = wMem(empty_write_buffer, address + 0, dbytes, acctype, data1); + write_buffer = wMem(write_buffer, address + dbytes, dbytes, acctype, data2); + flush_write_buffer(write_buffer); + }, + + MemOp_LOAD => { + read_buffer : read_buffer_type = rMem(empty_read_buffer, address + 0, dbytes, acctype); + read_buffer = rMem(read_buffer, address + dbytes, dbytes, acctype); + read_data : bits('D*2) = flush_read_buffer(read_buffer, dbytes*2); + data1 = read_data[(datasize - 1) .. 0]; + data2 = read_data[((datasize * 2) - 1) .. datasize]; + if rt_unknown then { + data1 = UNKNOWN : bits('D); + data2 = UNKNOWN : bits('D); + }; + if _signed then { + wX(t) = (SignExtend(data1)) : (bits(64)); + wX(t2) = (SignExtend(data2)) : (bits(64)); + } else { + wX(t) = data1; + wX(t2) = data2; + }; + } + }; + +/* ARM: the following code was moved up, see note there + if wback then { + if wb_unknown then + address = (bits(64)) UNKNOWN + else if postindex then + address = address + offset; + if n == 31 then + wSP() = address + else + wX(n) = address; + }; +*/ +} + +/* LDP post-index */ +/* LDPSW post-index */ +/* STP post-index */ +val decodeLoadStoreRegisterPairPostIndexed : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreRegisterPairPostIndexed (opc@0b101@[0]@0b001@[L]@(imm7 : bits(7))@Rt2@Rn@Rt) = { + wback : boolean = true; + postindex : boolean = true; + + sharedDecodeLoadStorePair(L,opc,imm7,Rn,Rt,Rt2,wback,postindex); +} + +/* LDP pre-index */ +/* LDPSW pre-index */ +/* STP pre-index */ +val decodeLoadStoreRegisterPairPreIndexed : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadStoreRegisterPairPreIndexed (opc@0b101@[0]@0b011@[L]@(imm7 : bits(7))@Rt2@Rn@Rt) = { + wback : boolean = true; + postindex : boolean = false; + + sharedDecodeLoadStorePair(L,opc,imm7,Rn,Rt,Rt2,wback,postindex); +} + +/* ADD/ADDS (immediate) */ +/* SUB/SUBS (immediate) */ +val decodeAddSubtractImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeAddSubtractImmediate ([sf]@[op]@[S]@0b10001@shift@(imm12 : bits(12))@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + datasize : atom('R) = if sf == 1 then 64 else 32; + sub_op : (boolean) = (op == 1); + setflags : (boolean) = (S == 1); + imm : (bits('R)) = 0; /* ARM: uninitialized */ + + match shift { + 0b00 => imm = ZeroExtend(imm12), + 0b01 => imm = ZeroExtend(imm12 @ (0b0 ^^ 12)), + [1,_] => ReservedValue() + }; + + Some(AddSubImmediate(d,n,datasize,sub_op,setflags,imm)); +} + +function clause execute (AddSubImmediate(d,n,datasize,sub_op,setflags,imm)) = { + operand1 : (bits('R)) = if n == 31 then rSP() else rX(n); + operand2 : (bits('R)) = imm; + carry_in : (bit) = 0; /* ARM: uninitialized */ + + if sub_op then { + operand2 = NOT(operand2); + carry_in = 1; + } + else + carry_in = 0; + + let (result,nzcv) = AddWithCarry (operand1, operand2, carry_in) in { + + if setflags then + wPSTATE_NZCV() = nzcv; + + if (d == 31 & ~(setflags)) then + wSP() = result + else + wX(d) = result; + } +} + +/* BFM */ +/* SBFM */ +/* UBFM */ +val decodeBitfield : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeBitfield ([sf]@opc@0b100110@[N]@(immr : bits(6))@(imms : bits(6))@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + datasize : atom('R) = if sf == 1 then 64 else 32; + + inzero : (boolean) = false; /* ARM: uninitialized */ + extend : (boolean) = false; /* ARM: uninitialized */ + R : (uinteger) = 0; /* ARM: uninitialized */ + S : (uinteger) = 0; /* ARM: uninitialized */ + + match opc { + 0b00 => {inzero = true; extend = true}, /* SBFM */ + 0b01 => {inzero = false; extend = false}, /* BFM */ + 0b10 => {inzero = true; extend = false}, /* UBFM */ + 0b11 => UnallocatedEncoding() + }; + + if sf == 1 & N != 1 then ReservedValue(); + if sf == 0 & (N != 0 | immr[5] != 0 | imms[5] != 0) then ReservedValue(); + + R = UInt(immr); + S = UInt(imms); + + let (wmask : bits('R), tmask : bits('R)) = (DecodeBitMasks(N, imms, immr, false)) in { + + Some(BitfieldMove(d,n,datasize,inzero,extend,R,S,wmask,tmask)); +}} + + +function clause execute (BitfieldMove(d,n,datasize,inzero,extend,R,S,wmask,tmask)) = { + dst : bits('R) = if inzero then Zeros() else rX(d); + src : bits('R) = rX(n); + + /* perform bitfield move on low bits */ + bot : (bits('R)) = ((dst & NOT(wmask)) | (ROR(src, R) & wmask)); + + /* determine extension bits (sign, zero or dest register) */ + top : (bits('R)) = if extend then Replicate([src[S]]) else dst; + + /* combine extension bits and result bits */ + wX(d) = ((top & NOT(tmask)) | (bot & tmask)); +} + +/* EXTR */ +val decodeExtract : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeExtract ([sf]@0b00@0b100111@[N]@0b0@Rm@(imms : bits(6))@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + datasize : atom('R) = if sf == 1 then 64 else 32; + lsb : (uinteger) = 0; /* ARM: uninitialized */ + + if N != sf then UnallocatedEncoding(); + if sf == 0 & imms[5] == 1 then ReservedValue(); + lsb = UInt(imms); + + Some(ExtractRegister(d,n,m,datasize,lsb)); +} + +function clause execute ( ExtractRegister(d,n,m,datasize : atom('R),lsb) ) = { + result : (bits('R)) = 0; /* ARM: uninitialized */ + operand1 : (bits('R)) = rX(n); + operand2 : (bits('R)) = rX(m); + + concat : (bits(2*'R)) = operand1:operand2; + result = concat[(lsb + datasize - 1)..lsb]; + wX(d) = result; +} + +/* AND/ANDS (immediate) */ +/* EOR (immediate) */ +/* ORR (immediate) */ +val decodeLogicalImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLogicalImmediate ([sf]@opc@0b100100@[N]@(immr : bits(6))@(imms : bits(6))@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + datasize : atom('R) = if sf == 1 then 64 else 32; + setflags : (boolean) = false; /* ARM: uninitialized */ + op : (LogicalOp) = LogicalOp_AND; /* ARM: uninitialized */ + match opc { + 0b00 => {op = LogicalOp_AND; setflags = false}, + 0b01 => {op = LogicalOp_ORR; setflags = false}, + 0b10 => {op = LogicalOp_EOR; setflags = false}, + 0b11 => {op = LogicalOp_AND; setflags = true} + }; + + if sf == 0 & N != 0 then ReservedValue(); + let (imm,_) = (DecodeBitMasks(N, imms, immr, true)) in { + + Some(LogicalImmediate(d,n,datasize,setflags,op,imm)); +}} + +function clause execute (LogicalImmediate(d,n,datasize : atom('R),setflags,op,imm)) = { + result : (bits('R)) = 0; /* ARM: uninitialized */ + operand1 : (bits('R)) = rX(n); + operand2 : (bits('R)) = imm; + + match op { + LogicalOp_AND => result = (operand1 & operand2), + LogicalOp_ORR => result = (operand1 | operand2), + LogicalOp_EOR => result = (operand1 ^ operand2) + }; + + if setflags then + wPSTATE_NZCV() = ([result[length(result) - 1]]@[IsZeroBit(result)]@0b00); + + if d == 31 & ~(setflags) then + wSP() = result + else + wX(d) = result; +} + +/* MOVK */ +/* MOVN */ +/* MOVZ */ +val decodeMoveWideImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeMoveWideImmediate ([sf]@opc@0b100101@(hw : bits(2))@(imm16 : bits(16))@Rd) = { + d : (reg_index) = UInt_reg(Rd); + datasize : atom('R) = if sf == 1 then 64 else 32; + imm : (bits(16)) = imm16; + pos : (uinteger) = 0; /* ARM: uninitialized */ + opcode : (MoveWideOp) = 0; /* ARM: uninitialized */ + + match opc { + 0b00 => opcode = MoveWideOp_N, + 0b10 => opcode = MoveWideOp_Z, + 0b11 => opcode = MoveWideOp_K, + _ => UnallocatedEncoding() + }; + + if sf == 0 & hw[1] == 1 then UnallocatedEncoding(); + pos = UInt(hw@0b0000); + + Some(MoveWide(d,datasize,imm,pos,opcode)); +} + +function clause execute ( MoveWide(d,datasize,imm,pos,opcode) ) = { + result : (bits('R)) = 0; /* ARM: uninitialized */ + + if opcode == MoveWideOp_K then + result = rX(d) + else + result = Zeros(); + + result[(pos+15)..pos] = imm; + if opcode == MoveWideOp_N then + result = NOT(result); + wX(d) = result; +} + +/* ADR */ +/* ADRP */ +val decodePCRelAddressing : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodePCRelAddressing ([op]@(immlo : bits(2))@0b10000@(immhi : bits(19))@Rd) = { + d : (reg_index) = UInt_reg(Rd); + page : (boolean) = (op == 1); + imm :(bits(64)) = 0; /* ARM: uninitialized */ + + if page then + imm = SignExtend(immhi@immlo@(0b0 ^^ 12)) + else + imm = SignExtend(immhi@immlo); + + Some(Address(d,page,imm)) +} + +function clause execute (Address(d,page,imm)) = { + base : (bits(64)) = rPC(); + + if page then + base[11..0] = (Zeros()) @ (bits(12)); + + wX(d) = base + imm; +} + +/* ADD/ADDS (extended register) */ +/* SUB/SUBS (extended register) */ +val decodeAddSubtractExtendedRegister : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeAddSubtractExtendedRegister ([sf]@[op]@[S]@0b01011@0b00@0b1@Rm@option_v@(imm3 : bits(3))@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + datasize : atom('R) = if sf == 1 then 64 else 32; + sub_op : (boolean) = (op == 1); + setflags : (boolean) = (S == 1); + extend_type : (ExtendType) = DecodeRegExtend(option_v); + shift : range(0,7) = UInt(imm3); + if shift > 4 then ReservedValue(); + + Some(AddSubExtendRegister(d,n,m,datasize,sub_op,setflags,extend_type,shift)); +} + +function clause execute (AddSubExtendRegister(d,n,m,datasize,sub_op,setflags,extend_type,shift)) = { + operand1 : (bits('R)) = if n == 31 then rSP() else rX(n); + operand2 : (bits('R)) = ExtendReg(m, extend_type, shift); + carry_in : (bit) = 0; /* ARM: uninitialized */ + + if sub_op then { + operand2 = NOT(operand2); + carry_in = 1; + } else + carry_in = 0; + + let (result,nzcv) = (AddWithCarry(operand1, operand2, carry_in)) in { + + if setflags then + wPSTATE_NZCV() = nzcv; + + if (d == 31 & ~(setflags)) then + wSP() = result + else + wX(d) = result; + } +} + +/* ADD/ADDS (shifted register) */ +/* SUB/SUBS (shifted register) */ +val decodeAddSubtractShiftedRegister : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeAddSubtractShiftedRegister ([sf]@[op]@[S]@0b01011@shift@0b0@Rm@(imm6 : bits(6))@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + datasize : atom('R) = if sf == 1 then 64 else 32; + sub_op : (boolean) = (op == 1); + setflags : (boolean) = (S == 1); + + if shift == 0b11 then ReservedValue(); + if sf == 0 & imm6[5] == 1 then ReservedValue(); + + shift_type : (ShiftType) = DecodeShift(shift); + shift_amount : range(0,63) = UInt(imm6); + + Some(AddSubShiftedRegister(d,n,m,datasize,sub_op,setflags,shift_type,shift_amount)); +} + +function clause execute (AddSubShiftedRegister(d,n,m,datasize,sub_op,setflags,shift_type,shift_amount)) = { + operand1 : (bits('R)) = rX(n); + operand2 : (bits('R)) = ShiftReg(m, shift_type, shift_amount); + carry_in : (bit) = 0; /* ARM: uninitialized */ + + if sub_op then { + operand2 = NOT(operand2); + carry_in = 1; + } + else + carry_in = 0; + + let (result,nzcv) = AddWithCarry(operand1, operand2, carry_in) in { + + if setflags then + wPSTATE_NZCV() = nzcv; + + wX(d) = result; + } +} + +/* ADC/ADCS */ +/* SBC/SBCS */ + + +val decodeAddSubtractWithCarry : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeAddSubtractWithCarry ([sf]@[op]@[S]@0b11010000@Rm@0b000000@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + datasize : (atom('R)) = if sf == 1 then 64 else 32; + sub_op : (boolean) = (op == 1); + setflags : (boolean) = (S == 1); + + Some(AddSubCarry(d,n,m,datasize,sub_op,setflags)); +} + +function clause execute( AddSubCarry(d,n,m,datasize,sub_op,setflags)) = { + operand1 : (bits('R)) = rX(n); + operand2 : (bits('R)) = rX(m); + + if sub_op then + operand2 = NOT(operand2); + + let (result,nzcv) = AddWithCarry (operand1, operand2, PSTATE_C) in { + + if setflags then + wPSTATE_NZCV() = nzcv; + + wX(d) = result; +}} + +/* CCMN (immediate) */ +/* CCMP (immediate) */ +val decodeConditionalCompareImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeConditionalCompareImmediate ([sf]@[op]@[1]@0b11010010@(imm5 : bits(5))@ _cond@[1]@[0]@Rn@[0]@nzcv) = { + n : (reg_index) = UInt_reg(Rn); + datasize : atom('R) = if sf == 1 then 64 else 32; + sub_op : boolean = (op ==1); + condition : bits(4) = _cond; + flags : bits(4) = nzcv; + imm : bits('R) = ZeroExtend(imm5); + + Some(ConditionalCompareImmediate(n,datasize,sub_op,condition,flags,imm)); +} + +function clause execute (ConditionalCompareImmediate(n,datasize,sub_op,condition,flags,imm)) = { + operand1 : (bits('R)) = rX(n); + operand2 : (bits('R)) = imm; + carry_in : (bit) = 0; + + flags' : (bits(4)) = flags; + if ConditionHolds(condition) then { + if sub_op then { + operand2 = NOT(operand2); + carry_in = 1; + }; + let (_,nzcv) = AddWithCarry(operand1, operand2, carry_in) in {flags' = nzcv}; + }; + wPSTATE_NZCV() = flags'; +} + +/* CCMN (register) */ +/* CCMP (register) */ +val decodeConditionalCompareRegister : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeConditionalCompareRegister ([sf]@[op]@[1]@0b11010010@Rm@ _cond@[0]@[0]@Rn@[0]@nzcv) = { + n : reg_index = UInt_reg(Rn); + m : reg_index = UInt_reg(Rm); + datasize : atom('R) = if sf == 1 then 64 else 32; + sub_op : boolean = (op ==1); + condition : bits(4) = _cond; + flags : bits(4) = nzcv; + + Some(ConditionalCompareRegister(n,m,datasize,sub_op,condition,flags)); +} + +function clause execute (ConditionalCompareRegister(n,m,datasize,sub_op,condition,flags)) = { + operand1 : bits('R) = rX(n); + operand2 : bits('R) = rX(m); + carry_in : bit = 0; + + flags' : bits(4) = flags; + if ConditionHolds(condition) then { + if sub_op then { + operand2 = NOT(operand2); + carry_in = 1; + }; + let (_,nzcv) = AddWithCarry (operand1, operand2, carry_in) in {flags' = nzcv}; + }; + wPSTATE_NZCV() = flags'; +} + +/* CSEL op=0,o2=0 */ +/* CSINC op=0,o2=1 */ +/* CSINV op=1,o2=0 */ +/* CSNEG op=1,o2=1 */ +val decodeConditionalSelect : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeConditionalSelect ([sf]@[op]@[0]@0b11010100@Rm@ _cond@[0]@[o2]@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + datasize : (atom('R)) = if sf == 1 then 64 else 32; + condition : (bits(4)) = _cond; + else_inv : (boolean) = (op == 1); + else_inc : (boolean) = (o2 == 1); + + Some(ConditionalSelect(d,n,m,datasize,condition,else_inv,else_inc)); +} + +function clause execute ( ConditionalSelect(d,n,m,datasize,condition,else_inv,else_inc) ) = { + result : (bits('R)) = 0; /* ARM: uninitialized */ + operand1 : (bits('R)) = rX(n); + operand2 : (bits('R)) = rX(m); + + if ConditionHolds(condition) then + result = operand1 + else { + result = operand2; + if else_inv then result = NOT(result); + if else_inc then result = result + 1; + }; + + wX(d) = result; +} + +val decodeData1Source : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +scattered function decodeData1Source + +/* RBIT */ +/* REV */ +/* REV16 */ +/* REV32 */ +function clause decodeData1Source ([sf]@[1]@[0]@0b11010110@0b00000@0b0000@opc@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + + datasize : (atom('R)) = if sf == 1 then 64 else 32; + + op : (RevOp) = 0; /* ARM: uninitialized */ + match opc { + 0b00 => + op = RevOp_RBIT, + 0b01 => + op = RevOp_REV16, + 0b10 => + op = RevOp_REV32, + 0b11 => { + if sf == 0 then UnallocatedEncoding(); + op = RevOp_REV64; + } + }; + + Some(Reverse(d,n,datasize,op)); +} + +function clause execute ( Reverse(d,n,datasize,op) ) = { + result : (bits('R)) = 0; /* ARM uninitialized */ + V : (bits(6)) = 0; /* ARM uninitialized */ + + match op { + RevOp_REV16 => V = 0b001000, + RevOp_REV32 => V = 0b011000, + RevOp_REV64 => V = 0b111000, + RevOp_RBIT => V = if datasize == 64 then 0b111111 else 0b011111 + }; + + result = rX(n); + + foreach (vbit from 0 to 5) { + /* Swap pairs of 2^vbit bits in result */ + if V[vbit] == 1 then { + tmp : (bits('R)) = result; + vsize : (uinteger) = lsl(1, vbit); + foreach (base from 0 to (datasize - 1) by (2 * vsize)) { /* ARM: while base < datasize do */ + result[((base+vsize) - 1)..base] = tmp[(base+(2*vsize) - 1)..(base+vsize)]; + result[(base+(2*vsize) - 1)..(base+vsize)] = tmp[(base+vsize - 1)..base]; + /* ARM: base = base + (2 * vsize); */ + }; + }; + }; + wX(d) = result; +} + +/* CLS */ +/* CLZ */ +function clause decodeData1Source ([sf]@[1]@[0]@0b11010110@0b00000@0b00010@[op]@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + datasize : (atom('R)) = if sf == 1 then 64 else 32; + opcode : (CountOp) = if op == 0 then CountOp_CLZ else CountOp_CLS; + + Some(CountLeading(d,n,datasize,opcode)); +} + +function clause execute (CountLeading(d,n,datasize,opcode)) = { + result : (uinteger) = 0; /* ARM: uninitialized */ + operand1 : (bits('R)) = rX(n); + + if opcode == CountOp_CLZ then + result = CountLeadingZeroBits(operand1) + else + result = CountLeadingSignBits(operand1); + + wX(d) = result : bits('R); +} + +end decodeData1Source + +val decodeData2Source : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +scattered function decodeData2Source + +/* SDIV o1=1 */ +/* UDIV o1=0 */ +function clause decodeData2Source ([sf]@[0]@[0]@0b11010110@Rm@0b00001@[o1]@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + datasize : (atom('R)) = if sf == 1 then 64 else 32; + _unsigned : (boolean) = (o1 == 0); + + Some(Division(d,n,m,datasize,_unsigned)); +} + +function clause execute ( Division(d,n,m,datasize,_unsigned) ) = { + operand1 : (bits('R)) = rX(n); + operand2 : (bits('R)) = rX(m); + result : (integer) = 0; /* ARM: uninitialized */ + + if IsZero(operand2) then + result = 0 + else + result = /* ARM: RoundTowardsZero*/ quot (_Int(operand1, _unsigned), _Int(operand2, _unsigned)); /* FIXME: does quot round towards zero? */ + + wX(d) = result : (bits('R)) ; /* ARM: result[(datasize-1)..0] */ +} + +/* ASRV */ +/* LSLV */ +/* LSRV */ +/* RORV */ +function clause decodeData2Source ([sf]@[0]@[0]@0b11010110@Rm@0b0010@op2@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + datasize : (atom('R)) = if sf == 1 then 64 else 32; + shift_type : (ShiftType) = DecodeShift(op2); + + Some(Shift(d,n,m,datasize,shift_type)); +} + +function clause execute (Shift(d,n,m,datasize,shift_type)) = { + result : (bits('R)) = 0; /* ARM: uninitialized */ + operand2 : (bits('R)) = rX(m); + + result = ShiftReg(n, shift_type, mod (UInt(operand2), datasize)); + wX(d) = result; +} + +/* CRC32B/CRC32H/CRC32W/CRC32X C=0 */ +/* CRC32CB/CRC32CH/CRC32CW/CRC32CX C=1 */ +function clause decodeData2Source ([sf]@[0]@[0]@0b11010110@Rm@0b010@[C]@sz@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + if sf == 1 & sz != 0b11 then UnallocatedEncoding(); + if sf == 0 & sz == 0b11 then UnallocatedEncoding(); + size : (atom('D)) = lsl(8, UInt(sz)); /* 2-bit size field -> 8, 16, 32, 64 */ + crc32c : (boolean) = (C == 1); + + Some(CRC(d,n,m,size,crc32c)); +} + +function clause execute ( CRC(d,n,m,size,crc32c) ) = { + if ~(HaveCRCExt()) then + UnallocatedEncoding(); + + acc : (bits(32)) = rX(n); /* accumulator */ + _val : (bits('D)) = rX(m); /* input value */ + poly : (bits(32)) = if crc32c then 0x1EDC6F41 else 0x04C11DB7; + + tempacc : (bits(32+'D)) = BitReverse(acc) @ (Zeros(): bits('D)); + tempval : (bits('D+32)) = BitReverse(_val) @ (Zeros() : bits(32)); + + /* Poly32Mod2 on a bitstring does a polynomial Modulus over {0,1} operation */ + wX(d) = BitReverse(Poly32Mod2(tempacc ^ tempval, poly)); +} + +end decodeData2Source + +val decodeData3Source : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +scattered function decodeData3Source + +/* MADD o0=0 */ +/* MSUB o0=1 */ +function clause decodeData3Source ([sf]@0b00@0b11011@0b000@Rm@[o0]@Ra@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + a : (reg_index) = UInt_reg(Ra); + destsize : (atom('R)) = if sf == 1 then 64 else 32; + datasize : (atom('D)) = destsize; + sub_op : (boolean) = (o0 == 1); + + Some(MultiplyAddSub(d,n,m,a,destsize,datasize,sub_op)); +} + +function clause execute ( MultiplyAddSub(d,n,m,a,destsize,datasize,sub_op) ) = { + operand1 : (bits('D)) = rX(n); + operand2 : (bits('D)) = rX(m); + operand3 : (bits('R)) = rX(a); + + result : (integer) = 0; /* ARM: uninitialized */ + + if sub_op then + result = UInt(operand3) - (UInt(operand1) * UInt(operand2)) + else + result = UInt(operand3) + (UInt(operand1) * UInt(operand2)); + + wX(d) = result : (bits('R)); +} + +/* SMADDL */ +/* SMSUBL */ +/* UMADDL */ +/* UMSUBL */ +function clause decodeData3Source ([1]@0b00@0b11011@[U]@0b01@Rm@[o0]@Ra@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + a : (reg_index) = UInt_reg(Ra); + destsize : (atom('R)) = 64; + datasize : (atom('D)) = 32; + sub_op : (boolean) = (o0 == 1); + _unsigned : (boolean) = (U == 1); + + Some(MultiplyAddSubLong(d,n,m,a,destsize,datasize,sub_op,_unsigned)); +} + +function clause execute ( MultiplyAddSubLong(d,n,m,a,destsize,datasize,sub_op,_unsigned) ) = { + operand1 : (bits('D)) = rX(n); + operand2 : (bits('D)) = rX(m); + operand3 : (bits('R)) = rX(a); + + result : (integer) = 0; /* ARM: uninitialized */ + + if sub_op then + result = _Int(operand3, _unsigned) - (_Int(operand1, _unsigned) * _Int(operand2, _unsigned)) + else + result = _Int(operand3, _unsigned) + (_Int(operand1, _unsigned) * _Int(operand2, _unsigned)); + + wX(d) = result : (bits(64)); +} + +/* SMULH */ +/* UMULH */ +function clause decodeData3Source ([1]@0b00@0b11011@[U]@0b10@Rm@[0]@Ra@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + a : (reg_index) = UInt_reg(Ra); /* ignored by UMULH/SMULH */ + destsize : (atom('R)) = 64; + datasize : (atom('D)) = destsize; + _unsigned : (boolean) = (U == 1); + + Some(MultiplyHigh(d,n,m,a,destsize,datasize,_unsigned)); +} + +function clause execute ( MultiplyHigh(d,n,m,a,destsize,datasize,_unsigned) ) = { + operand1 : (bits('R)) = rX(n); + operand2 : (bits('R)) = rX(m); + + result : (integer) = 0; /* ARM: uninitialized */ + + result = _Int(operand1, _unsigned) * _Int(operand2, _unsigned); + + wX(d) = (result : bits(128))[127..64]; +} + +end decodeData3Source + +/* AND/ANDS (shifted register) */ +/* EON (shifted register) */ +/* EOR (shifted register) */ +/* ORN (shifted register) */ +/* ORR (shifted register) */ +/* BIC/BICS (shifted register) */ +val decodeLogicalShiftedRegister : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLogicalShiftedRegister ([sf]@opc@0b01010@shift@[N]@Rm@(imm6 : bits(6))@Rn@Rd) = { + d : (reg_index) = UInt_reg(Rd); + n : (reg_index) = UInt_reg(Rn); + m : (reg_index) = UInt_reg(Rm); + datasize : (atom('R)) = if sf == 1 then 64 else 32; + setflags : (boolean) = false; /* ARM: uninitialized */ + op : (LogicalOp) = LogicalOp_AND; /* ARM: uninitialized */ + match opc { + 0b00 => {op = LogicalOp_AND; setflags = false}, + 0b01 => {op = LogicalOp_ORR; setflags = false}, + 0b10 => {op = LogicalOp_EOR; setflags = false}, + 0b11 => {op = LogicalOp_AND; setflags = true} + }; + + if sf == 0 & imm6[5] == 1 then ReservedValue(); + + shift_type : (ShiftType) = DecodeShift(shift); + shift_amount : range(0,63) = UInt(imm6); + invert : (boolean) = (N == 1); + + Some(LogicalShiftedRegister(d,n,m,datasize,setflags,op,shift_type,shift_amount,invert)) +} + +function clause execute (LogicalShiftedRegister(d,n,m,datasize,setflags,op,shift_type,shift_amount,invert)) = { + + operand1 : (bits('R)) = rX(n); + operand2 : (bits('R)) = ShiftReg(m, shift_type, shift_amount); + + if invert then operand2 = NOT(operand2); + + result : (bits('R)) = 0; /* ARM: uninitialized */ + match op { + LogicalOp_AND => result = (operand1 & operand2), + LogicalOp_ORR => result = (operand1 | operand2), + LogicalOp_EOR => result = (operand1 ^ operand2) + }; + + if setflags then + wPSTATE_NZCV() = ([result[datasize - 1]]@[IsZeroBit(result)]@0b00); + + wX(d) = result; +} + +val decodeDataSIMDFPoint1 : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +function decodeDataSIMDFPoint1 (machineCode) = { + not_implemented("decodeDataSIMDFPoint1"); + Some(Unallocated); +} + +val decodeDataSIMDFPoint2 : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +function decodeDataSIMDFPoint2 ( machineCode) = { + not_implemented("decodeDataSIMDFPoint2"); + Some(Unallocated); +} + +val decodeDataRegister : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeDataRegister (machineCode) = { + match machineCode { + ([_]@[_]@[_]@[0]@ [1]@[0]@[1]@[0]@ [_]@[_]@[_]@ (_ : bits(9)) @[_]@(_ : bits(11))) => decodeLogicalShiftedRegister(machineCode), + ([_]@[_]@[_]@[0]@ [1]@[0]@[1]@[1]@ [_]@[_]@[0]@ (_ : bits(9)) @[_]@(_ : bits(11))) => decodeAddSubtractShiftedRegister(machineCode), + ([_]@[_]@[_]@[0]@ [1]@[0]@[1]@[1]@ [_]@[_]@[1]@ (_ : bits(9)) @[_]@(_ : bits(11))) => decodeAddSubtractExtendedRegister(machineCode), + ([_]@[_]@[_]@[1]@ [1]@[0]@[1]@[0]@ [0]@[0]@[0]@ (_ : bits(9)) @[_]@(_ : bits(11))) => decodeAddSubtractWithCarry(machineCode), + ([_]@[_]@[_]@[1]@ [1]@[0]@[1]@[0]@ [0]@[1]@[0]@ (_ : bits(9)) @[0]@(_ : bits(11))) => decodeConditionalCompareRegister(machineCode), + ([_]@[_]@[_]@[1]@ [1]@[0]@[1]@[0]@ [0]@[1]@[0]@ (_ : bits(9)) @[1]@(_ : bits(11))) => decodeConditionalCompareImmediate(machineCode), + ([_]@[_]@[_]@[1]@ [1]@[0]@[1]@[0]@ [1]@[0]@[0]@ (_ : bits(9)) @[_]@(_ : bits(11))) => decodeConditionalSelect(machineCode), + ([_]@[_]@[_]@[1]@ [1]@[0]@[1]@[1]@ [_]@[_]@[_]@ (_ : bits(9)) @[_]@(_ : bits(11))) => decodeData3Source(machineCode), + ([_]@[0]@[_]@[1]@ [1]@[0]@[1]@[0]@ [1]@[1]@[0]@ (_ : bits(9)) @[_]@(_ : bits(11))) => decodeData2Source(machineCode), + ([_]@[1]@[_]@[1]@ [1]@[0]@[1]@[0]@ [1]@[1]@[0]@ (_ : bits(9)) @[_]@(_ : bits(11))) => decodeData1Source(machineCode) + } +} + +val decodeDataImmediate : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeDataImmediate (machineCode) = { + match machineCode { + ((_ : bits(3))@[1]@[0]@[0]@[0]@[0]@[_]@(_ : bits(23))) => decodePCRelAddressing(machineCode), + ((_ : bits(3))@[1]@[0]@[0]@[0]@[1]@[_]@(_ : bits(23))) => decodeAddSubtractImmediate(machineCode), + ((_ : bits(3))@[1]@[0]@[0]@[1]@[0]@[0]@(_ : bits(23))) => decodeLogicalImmediate(machineCode), + ((_ : bits(3))@[1]@[0]@[0]@[1]@[0]@[1]@(_ : bits(23))) => decodeMoveWideImmediate(machineCode), + ((_ : bits(3))@[1]@[0]@[0]@[1]@[1]@[0]@(_ : bits(23))) => decodeBitfield(machineCode), + ((_ : bits(3))@[1]@[0]@[0]@[1]@[1]@[1]@(_ : bits(23))) => decodeExtract(machineCode) + } +} + +val decodeLoadsStores : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeLoadsStores (machineCode) = { + match machineCode { + ([_]@[_]@[0]@[0]@ [1]@[0]@[0]@[0]@ [_]@[_]@[_]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeLoadStoreExclusive(machineCode), + ([_]@[_]@[0]@[1]@ [1]@[_]@[0]@[0]@ [_]@[_]@[_]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeLoadRegisterLiteral(machineCode), + ([_]@[_]@[1]@[0]@ [1]@[_]@[0]@[0]@ [0]@[_]@[_]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeLoadStoreNoAllocatePairOffset(machineCode), + ([_]@[_]@[1]@[0]@ [1]@[_]@[0]@[0]@ [1]@[_]@[_]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeLoadStoreRegisterPairPostIndexed(machineCode), + ([_]@[_]@[1]@[0]@ [1]@[_]@[0]@[1]@ [0]@[_]@[_]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeLoadStoreRegisterPairOffset(machineCode), + ([_]@[_]@[1]@[0]@ [1]@[_]@[0]@[1]@ [1]@[_]@[_]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeLoadStoreRegisterPairPreIndexed(machineCode), + ([_]@[_]@[1]@[1]@ [1]@[_]@[0]@[0]@ [_]@[_]@[0]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[0]@[0]@ (_ : bits(10)) ) => decodeLoadStoreRegisterUnscaledImmediate(machineCode), + ([_]@[_]@[1]@[1]@ [1]@[_]@[0]@[0]@ [_]@[_]@[0]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[0]@[1]@ (_ : bits(10)) ) => decodeLoadStoreRegisterImmediatePostIndexed(machineCode), + ([_]@[_]@[1]@[1]@ [1]@[_]@[0]@[0]@ [_]@[_]@[0]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[1]@[0]@ (_ : bits(10)) ) => decodeLoadStoreRegisterUnprivileged(machineCode), + ([_]@[_]@[1]@[1]@ [1]@[_]@[0]@[0]@ [_]@[_]@[0]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[1]@[1]@ (_ : bits(10)) ) => decodeLoadStoreRegisterImmediatePreIndexed(machineCode), + ([_]@[_]@[1]@[1]@ [1]@[_]@[0]@[0]@ [_]@[_]@[1]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[1]@[0]@ (_ : bits(10)) ) => decodeLoadStoreRegisterRegisterOffset(machineCode), + ([_]@[_]@[1]@[1]@ [1]@[_]@[0]@[1]@ [_]@[_]@[_]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeLoadStoreRegisterUnsignedImmediate(machineCode), + ([0]@[_]@[0]@[0]@ [1]@[1]@[0]@[0]@ [0]@[_]@[0]@[0]@ [0]@[0]@[0]@[0]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeAdvSIMDLoadStoreMultiStruct(machineCode), + ([0]@[_]@[0]@[0]@ [1]@[1]@[0]@[0]@ [1]@[_]@[0]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeAdvSIMDLoadStoreMultiStructPostIndexed(machineCode), + ([0]@[_]@[0]@[0]@ [1]@[1]@[0]@[1]@ [0]@[_]@[_]@[0]@ [0]@[0]@[0]@[0]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeAdvSIMDLoadStoreSingleStruct(machineCode), + ([0]@[_]@[0]@[0]@ [1]@[1]@[0]@[1]@ [1]@[_]@[_]@[_]@ [_]@[_]@[_]@[_]@ (_ : bits(4)) @[_]@[_]@ (_ : bits(10)) ) => decodeAdvSIMDLoadStoreSingleStructPostIndexed(machineCode) + } +} + +val decodeSystemImplementationDefined : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeSystemImplementationDefined (machineCode) = { + match machineCode { + ((_ : bits(11)) @[0]@[1]@[_]@[_]@[_]@[1]@[_]@[1]@[1]@(_ : bits(12))) => decodeImplementationDefined(machineCode), + ((_ : bits(11)) @[1]@[1]@[_]@[_]@[_]@[1]@[_]@[1]@[1]@(_ : bits(12))) => decodeImplementationDefined(machineCode), + ((_ : bits(11)) @[_]@[_]@[_]@[_]@[_]@[_]@[_]@[_]@[_]@(_ : bits(12))) => decodeSystem(machineCode) + } +} + + +val decodeBranchesExceptionSystem : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect pure +function decodeBranchesExceptionSystem (machineCode) = { + match machineCode { + ([_]@[0]@[0]@[1]@[0]@[1]@[_]@[_]@[_]@[_]@(_ : bits(22))) => decodeUnconditionalBranchImmediate(machineCode), + ([_]@[0]@[1]@[1]@[0]@[1]@[0]@[_]@[_]@[_]@(_ : bits(22))) => decodeCompareBranchImmediate(machineCode), + ([_]@[0]@[1]@[1]@[0]@[1]@[1]@[_]@[_]@[_]@(_ : bits(22))) => decodeTestBranchImmediate(machineCode), + ([0]@[1]@[0]@[1]@[0]@[1]@[0]@[_]@[_]@[_]@(_ : bits(22))) => decodeConditionalBranchImmediate(machineCode), + ([1]@[1]@[0]@[1]@[0]@[1]@[0]@[0]@[_]@[_]@(_ : bits(22))) => decodeExceptionGeneration(machineCode), + ([1]@[1]@[0]@[1]@[0]@[1]@[0]@[1]@[0]@[0]@(_ : bits(22))) => decodeSystemImplementationDefined(machineCode), + ([1]@[1]@[0]@[1]@[0]@[1]@[1]@[_]@[_]@[_]@(_ : bits(22))) => decodeUnconditionalBranchRegister(machineCode) + } +} + +val decode : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. + bits(32) -> option(ast('R,'D)) effect {escape} +function decode (machineCode) = { + match machineCode { + ((_ : bits(3)) @[0]@[0]@[_]@[_]@(_ : bits(25))) => Some(Unallocated), + ((_ : bits(3)) @[1]@[0]@[0]@[_]@(_ : bits(25))) => decodeDataImmediate(machineCode), + ((_ : bits(3)) @[1]@[0]@[1]@[_]@(_ : bits(25))) => decodeBranchesExceptionSystem(machineCode), + ((_ : bits(3)) @[_]@[1]@[_]@[0]@(_ : bits(25))) => decodeLoadsStores(machineCode), + ((_ : bits(3)) @[_]@[1]@[0]@[1]@(_ : bits(25))) => decodeDataRegister(machineCode), + ((_ : bits(3)) @[0]@[1]@[1]@[1]@(_ : bits(25))) => decodeDataSIMDFPoint1(machineCode), + ((_ : bits(3)) @[1]@[1]@[1]@[1]@(_ : bits(25))) => decodeDataSIMDFPoint2(machineCode), + _ => None + } +} + +end execute + +val supported_instructions : forall 'R 'D, 'R in {32,64} & 'D in {8,16,32,64}. ast('R,'D) -> option(ast('R,'D)) effect pure +function supported_instructions (instr) = { + match instr { + _ => Some(instr) + } +} |
