diff options
| author | Shaked Flur | 2017-12-04 14:54:54 +0000 |
|---|---|---|
| committer | Shaked Flur | 2017-12-04 14:54:54 +0000 |
| commit | 5fa993caef3c48da36f641bf3608a9515ecc40cf (patch) | |
| tree | 1d4e4b9a2bb390744708f4fd4486616fd7d1b4b2 | |
| parent | 748318f8af7b82a01bb151f1bfcb466d0fc8291f (diff) | |
match what rmem expects from sail/arm
29 files changed, 5623 insertions, 262 deletions
diff --git a/arm/Makefile b/arm/Makefile index 18eba393..d7124df6 100644 --- a/arm/Makefile +++ b/arm/Makefile @@ -1,16 +1,5 @@ -BUILDDIR=./build - -SAIL=../sail -ifeq ("$(wildcard $(SAIL))","") - $(warning can not find Sail) -endif - -LEM=../../lem/lem -ifeq ("$(wildcard $(LEM))","") - $(warning can not find Lem) -endif - -LEMINTERPDIR=../src/lem_interp/ +SAIL:=../src/sail.native +LEM:=../../lem/lem # the order of the files is important SOURCES=armV8.h.sail\ @@ -23,39 +12,28 @@ SOURCES=armV8.h.sail\ armV8_A64_lib.sail\ armV8.sail -all: $(BUILDDIR)/armv8.ml - -clean: - rm -rf $(BUILDDIR) - -ocaml: $(BUILDDIR)/armv8_embed.ml +all: armV8.lem armV8.ml armV8_embed.lem -.PHONY: all clean ocaml +armV8.lem: $(SOURCES) + $(SAIL) -lem_ast -o armV8 $(SOURCES) -$(BUILDDIR): - mkdir -p $@ +armV8.ml: armV8.lem ../src/lem_interp/interp_ast.lem + $(LEM) -ocaml -lib ../src/lem_interp/ $< -$(BUILDDIR)/armv8.lem: $(SOURCES) | $(BUILDDIR) - $(SAIL) -lem_ast $(SOURCES) -o $(basename $@) -# sail generates the .lem file in pwd - mv $(notdir $@) $@ -$(BUILDDIR)/armv8.ml: $(BUILDDIR)/armv8.lem - $(LEM) -ocaml -lib $(LEMINTERPDIR) $< - -$(BUILDDIR)/armv8_embed.ml: $(SOURCES) | $(BUILDDIR) - $(SAIL) -ocaml $(SOURCES) -o $(basename $@) -# sail generates the .lem file in pwd - mv $(notdir $@) $@ +armV8_embed.lem: $(SOURCES) ../etc/regfp.sail aarch64_regfp.sail +# also generates armV8_embed_sequential.lem, armV8_embed_types.lem, armV8_toFromInterp.lem + $(SAIL) -lem -lem_lib ArmV8_extras_embed -o armV8 $^ +clean: + rm -f armV8.lem armV8.ml + rm -f armV8_embed*.lem armV8_toFromInterp.lem ###################################################################### ETCDIR=../etc apply_header: - -chmod u+w *.sail headache -c $(ETCDIR)/headache_config -h $(ETCDIR)/arm_header *.sail - chmod a-w *.sail .PHONY: apply_header @@ -63,10 +41,13 @@ apply_header: IDLARM=../../../rsem/idlarm pull_from_idlarm: - svn up $(IDLARM) - $(MAKE) -C $(IDLARM) - -chmod u+w *.sail + $(MAKE) -C $(IDLARM) clean + $(MAKE) -C $(IDLARM) san_sail rm -f *.sail cp -a $(IDLARM)/build/*.sail ./ - chmod a-w *.sail + cp -a $(IDLARM)/armV8_extras_embed.lem ./ + cp -a $(IDLARM)/armV8_extras_embed_sequential.lem ./ + cp -a $(IDLARM)/armV8_extras.lem ./ + mkdir -p gen + cp -a $(IDLARM)/*.hgen gen/ $(MAKE) apply_header diff --git a/arm/aarch64_regfp.sail b/arm/aarch64_regfp.sail new file mode 100644 index 00000000..148f9646 --- /dev/null +++ b/arm/aarch64_regfp.sail @@ -0,0 +1,598 @@ +(*========================================================================*) +(* *) +(* 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. *) +(*========================================================================*) + +function instruction_kind rmem_kind ((AccType) acctype, (bool) exclusive) = + if exclusive then + switch acctype { + case AccType_ATOMIC -> IK_mem_read(Read_exclusive) + case AccType_ORDERED -> IK_mem_read(Read_exclusive_acquire) + case _ -> { not_implemented("unimplemented memory access"); + IK_mem_read(Read_exclusive); } + } + else + switch acctype { + case AccType_NORMAL -> IK_mem_read(Read_plain) + case AccType_ATOMIC -> IK_mem_read(Read_plain) + case AccType_STREAM -> IK_mem_read(Read_stream) + case AccType_UNPRIV -> IK_mem_read(Read_plain) + case AccType_ORDERED -> IK_mem_read(Read_acquire) + } + + +function instruction_kind wmem_kind ((AccType) acctype, (bool) exclusive) = + if exclusive then { + switch acctype { + case AccType_ATOMIC -> IK_mem_write(Write_exclusive) + case AccType_ORDERED -> IK_mem_write(Write_exclusive_release) + case _ -> { not_implemented("unimplemented memory access"); + IK_mem_write(Write_exclusive); } + } + } else { + switch acctype { + case AccType_NORMAL -> IK_mem_write(Write_plain) + case AccType_STREAM -> IK_mem_write(Write_plain) + case AccType_UNPRIV -> IK_mem_write(Write_plain) + case AccType_ORDERED -> IK_mem_write(Write_release) + case _ -> { not_implemented("unimplemented memory access"); + IK_mem_write(Write_plain) } + }; + } + + +let (vector<30,31,dec,string>) _Rs = + ["R30","R29","R28","R27","R26","R25","R24","R23","R22","R21", + "R20","R19","R18","R17","R16","R15","R14","R13","R12","R11", + "R10","R9" ,"R8" ,"R7" ,"R6" ,"R5" ,"R4" ,"R3" ,"R2" ,"R1" , + "R0"] + +let TxNestingLevelfp = RFull("TxNestingLevel") +let TXIDR_EL0_DEPTHfp = RField("TXIDR_EL0","DEPTH") + +let PSTATE_Nfp = RField("NZCV","N") +let PSTATE_Zfp = RField("NZCV","Z") +let PSTATE_Cfp = RField("NZCV","C") +let PSTATE_Vfp = RField("NZCV","V") +let PSTATE_Dfp = RField("DAIF","D") +let PSTATE_Afp = RField("DAIF","A") +let PSTATE_Ifp = RField("DAIF","I") +let PSTATE_Ffp = RField("DAIF","F") +let PSTATE_ELfp = RFull("CurrentEL") +let PSTATE_SPfp = RField("SPSel","SP") +let _PCfp = RFull("_PC") + +let NZCVfp = [|| PSTATE_Nfp, PSTATE_Zfp, PSTATE_Cfp, PSTATE_Vfp ||] + +function regfps xFP((reg_index) n) = + if n != 31 then [||RFull(_Rs[n])||] else [|| ||] + + +(* check if this is still what we want *) +function forall Nat 'N, 'N IN {32,64}. (regfps,regfps) BranchToFP (iR,oR) = + (if UsingAArch32() then iR else PSTATE_ELfp :: iR, _PCfp :: oR) + +function regfps ConditionHoldsIFP((bit[4]) _cond) = + switch _cond[3..1] { + case 0b000 -> [|| PSTATE_Zfp ||] + case 0b001 -> [|| PSTATE_Cfp ||] + case 0b010 -> [|| PSTATE_Nfp ||] + case 0b011 -> [|| PSTATE_Vfp ||] + case 0b100 -> [|| PSTATE_Cfp, PSTATE_Zfp ||] + case 0b101 -> [|| PSTATE_Nfp, PSTATE_Vfp ||] + case 0b110 -> [|| PSTATE_Nfp, PSTATE_Vfp, PSTATE_Zfp ||] + case 0b111 -> [|| ||] + } + +(* for iR if rSPFP, for oR if wSPFP *) +let rSPIFP = + (* TODO: actually this depends on runtime data: PSTATE_SP and PSTATE_EL *) + [|| PSTATE_SPfp, RFull("SP_EL0") ||] + +let wSPFP = + (* TODO: actually this depends on runtime data: PSTATE_SP and PSTATE_EL *) + ([|| PSTATE_SPfp ||], + [|| RFull("SP_EL0") ||]) + + +let CheckSPAlignmentIFP = PSTATE_ELfp :: rSPIFP + +let BigEndianIFP = + if UsingAArch32() then [|| RFull("PSTATE_E") ||] else [|| PSTATE_ELfp ||] + +let wMem'IFP = BigEndianIFP +let wMemIFP = wMem'IFP + +function (regfps,regfps,regfps,niafps,diafp,instruction_kind) effect pure initial_analysis (instr) = { + iR := [|| ||]; + oR := [|| ||]; + aR := [|| ||]; + Nias := [|| NIAFP_successor ||]; + Dia := DIAFP_none; + ik := IK_simple; + + switch instr { + case (TMStart(t)) -> { + iR := TxNestingLevelfp :: TXIDR_EL0_DEPTHfp :: iR; + (* TODO: whether the following applies depends on runtime data: + ~(TxNestingLevel >= TXIDR_EL0.DEPTH) *) + oR := TxNestingLevelfp :: append(oR,xFP(t)); + ik := IK_trans(Transaction_start); + } + case (TMCommit) -> { + iR := TxNestingLevelfp :: iR; + oR := TxNestingLevelfp :: oR; + ik := IK_trans(Transaction_commit); + } + case (TMAbort(retry,reason)) -> { + iR := TxNestingLevelfp :: iR; + ik := IK_trans(Transaction_abort); + } + case (TMTest) -> { + iR := TxNestingLevelfp :: iR; + oR := RFull("NZCV") :: oR; + } + case (CompareAndBranch(t,datasize,iszero,offset)) -> { + iR := append(iR,xFP(t)); + (* TODO: whether the following applies depends on runtime data: + IsZero(operand1) *) + let (i,o) = BranchToFP(iR,oR) in {iR := i; oR := o}; + (bit[64]) nia' := rPC() + offset; + Nias := [|| NIAFP_successor, NIAFP_concrete_address(nia') ||]; + ik := IK_cond_branch; + } + case (BranchConditional(offset,condition)) -> { + iR := append(iR,ConditionHoldsIFP(condition)); + (* TODO: whether the following applies depends on runtime data: + ConditionHolds(condition) *) + let (i,o) = BranchToFP(iR,oR) in {iR := i; oR := o}; + Nias := [|| NIAFP_successor, NIAFP_concrete_address(rPC() + offset) ||]; + ik := IK_cond_branch; + } + case (GenerateExceptionEL1(imm)) -> not_implemented("GenerateExceptionEL1") + case (GenerateExceptionEL2(imm)) -> not_implemented("GenerateExceptionEL2") + case (GenerateExceptionEL3(imm)) -> not_implemented("GenerateExceptionEL3") + case (DebugBreakpoint(comment)) -> not_implemented("DebugBreakpoint") + case (ExternalDebugBreakpoint) -> not_implemented("ExternalDebugBreakpoint") + case (DebugSwitchToExceptionLevel(target_level)) -> not_implemented("DebugSwitchToExceptionLevel") + case (MoveSystemImmediate(operand,field)) -> + switch field { + case PSTATEField_SP -> oR := PSTATE_SPfp :: oR + case PSTATEField_DAIFSet -> { + iR := append(iR, [|| PSTATE_Dfp, PSTATE_Afp, PSTATE_Ifp, PSTATE_Ffp ||]); + oR := append(oR, [|| PSTATE_Dfp, PSTATE_Afp, PSTATE_Ifp, PSTATE_Ffp ||]); + } + case PSTATEField_DAIFClr -> { + iR := append(iR, [|| PSTATE_Dfp, PSTATE_Afp, PSTATE_Ifp, PSTATE_Ffp ||]); + oR := append(oR, [|| PSTATE_Dfp, PSTATE_Afp, PSTATE_Ifp, PSTATE_Ffp ||]); + } + } + case (Hint(op)) -> + switch op { + case SystemHintOp_YIELD -> () + case SystemHintOp_WFE -> { + if EventRegistered() then () (* ClearEventRegister *) + else { + (* the execute code for this case always fails because of + WaitForEvent, declared as extern but not defined *) + not_implemented("Hint(SystemHintOp_WFE);") + } + } + case SystemHintOp_WFI -> { + (* the execute code for this case always fails because of + InterruptPending, declared as extern but not defined *) + not_implemented("Hint(SystemHintOp_WFI);") + } + case SystemHintOp_SEV -> () (*SendEvent*) + case SystemHintOp_SEVL -> + (* the execute code for this case always fails because of + EventRegisterSet, declared as extern but not defined *) + not_implemented("Hint(SystemHintOp_SEVL);") + case _ -> () (* do nothing *) + } + case (ClearExclusiveMonitor(imm)) -> () (*ClearExclusiveLocal*) + case (Barrier(op,domain,types)) -> { + ik := switch op { + case MemBarrierOp_DSB -> + switch types { + case MBReqTypes_Reads -> IK_barrier(Barrier_DSB_LD) + case MBReqTypes_Writes -> IK_barrier(Barrier_DSB_ST) + case MBReqTypes_All -> IK_barrier(Barrier_DSB) + } + case MemBarrierOp_DMB -> + switch types { + case MBReqTypes_Reads -> IK_barrier(Barrier_DMB_LD) + case MBReqTypes_Writes -> IK_barrier(Barrier_DMB_ST) + case MBReqTypes_All -> IK_barrier(Barrier_DMB) + } + case MemBarrierOp_ISB -> + IK_barrier(Barrier_ISB) + }; + } + case (System(t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,has_result)) -> { + oR := append(oR,xFP(t)); + not_implemented("System"); (* because SysOp_R and SysOp_W *) + } + case (MoveSystemRegister(t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read)) -> { + if read then { + oR := append(oR,xFP(t)); + switch (sys_op0,sys_op1,sys_crn,sys_crm,sys_op2) { (* System_Get *) + case (3,3,4,2,0) -> iR := RFull("NZCV") :: iR + case (3,3,4,2,1) -> iR := RFull("DAIF") :: iR + case (3, 3, 13, 0, 2) -> iR := RFull("TPIDR_EL0") :: iR + (* TODO FIXME: higher EL TPIDRs *) + } + } + else { + iR := append(iR,xFP(t)); + switch (sys_op0,sys_op1,sys_crn,sys_crm,sys_op2) { (* System_Put *) + case (3,3,4,2,0) -> oR := RFull("NZCV") :: oR + case (3,3,4,2,1) -> oR := RFull("DAIF") :: oR + case (3, 3, 13, 0, 2) -> oR := RFull("TPIDR_EL0") :: oR + (* TODO FIXME: higher EL TPIDRs *) + } + } + } + case (ImplementationDefinedTestBeginEnd(isEnd)) -> () + case (ImplementationDefinedStopFetching) -> () + case (ImplementationDefinedThreadStart) -> () + case (TestBitAndBranch(t,datasize,bit_pos,bit_val,offset)) -> { + iR := append(xFP(t),iR); + (* TODO: whether the following applies depends on runtime data: + operand[bit_pos] == bit_val *) + let (i,o) = BranchToFP(iR,oR) in {iR := i; oR := o}; + Nias := [|| NIAFP_successor, NIAFP_concrete_address(rPC() + offset) ||]; + ik := IK_cond_branch; + } + case (BranchImmediate(branch_type,offset)) -> { + if branch_type == BranchType_CALL + then {iR := _PCfp :: iR; oR := append(xFP(30),oR)}; + let (i,o) = BranchToFP(iR,oR) in {iR := i; oR := o}; + Nias := [|| NIAFP_concrete_address(rPC() + offset) ||]; + ik := IK_simple (* IK_uncond_branch *) + } + case (BranchRegister(n,branch_type)) -> { + iR := append(iR,xFP(n)); + if branch_type == BranchType_CALL + then {iR := _PCfp :: iR; oR := append(xFP(30),oR)}; + let (i,o) = BranchToFP(iR,oR) in {iR := i; oR := o}; + Nias := if n ==31 + then [|| NIAFP_concrete_address(0) ||] + else [|| NIAFP_register(RFull(_Rs[n]))||]; + ik := IK_simple (* IK_uncond_branch *) + } + case (ExceptionReturn) -> not_implemented("ExceptionReturn") + case (DebugRestorePState) -> not_implemented("DebugRestorePState") + case (LoadLiteral(t,memop,_signed,size,offset,datasize)) -> { + (* assuming rMem doesn't touch other registers *) + iR := _PCfp :: iR; + oR := append(xFP(t),oR); + aR := _PCfp :: aR; + switch memop { + case MemOp_LOAD -> ik := IK_mem_read(Read_plain) + case MemOp_PREFETCH -> {ik := IK_simple; aR := [|| ||]} + } + } + case (LoadStoreAcqExc(n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,datasize)) -> { + (boolean) rt_unknown := false; + (boolean) rn_unknown := false; + if n==31 then { + iR := append(CheckSPAlignmentIFP,iR); + iR := append(rSPIFP,iR); + aR := append(rSPIFP,aR); + } + else if rn_unknown then () + else { + iR := append(xFP(n),iR); + aR := append(xFP(n),aR); + }; + switch memop { + case MemOp_STORE -> { + if rt_unknown then () + else if pair then iR := append(xFP(t),append(xFP(t2),iR)) + else iR := append(xFP(t),iR); + if excl then { + (* TODO: the command below depends on runtime data: + AArch64_ExclusiveMonitorsPass(address, dbytes) *) + iR := append(iR,wMemIFP); + oR := append(xFP(s),oR); + ik := wmem_kind(acctype,true); + } + else { + iR := append(iR,wMemIFP); + ik := wmem_kind(acctype,false); + } + } + case MemOp_LOAD -> { + if pair then { + if rt_unknown then + oR := append(xFP(t),oR) + else if elsize == 32 then { + iR := append(iR,BigEndianIFP); + oR := append(xFP(t),append(xFP(t2),oR)); + } + else { + oR := append(xFP(t),append(xFP(t2),oR)) + }; + ik := rmem_kind(acctype,true); + } + else { + oR := append(xFP(t),oR); + ik := rmem_kind(acctype,excl); + } + + } + case MemOp_PREFETCH -> aR := [|| ||] + } + } + case (LoadStorePairNonTemp(wback,postindex,n,t,t2,acctype,memop,scale,datasize,offset)) -> { + (boolean) rt_unknown := false; + if n == 31 then { + iR := append(CheckSPAlignmentIFP,iR); + iR := append(rSPIFP,iR); + aR := append(rSPIFP,aR); + } + else { + iR := append(xFP(n),iR); + aR := append(xFP(n),aR); + }; + if wback then { + if n == 31 then + let (i,o) = wSPFP in { + iR := append(i,iR); + oR := append(o,oR); + } + else + oR := append(xFP(n),oR); + }; + switch memop { + case MemOp_STORE -> { + if rt_unknown & t == n then () + else iR := append(xFP(t),iR); + if rt_unknown & t2 == n then () + else iR := append(xFP(t2),iR); + iR := append(wMemIFP,iR); + ik := wmem_kind(acctype,false); + } + case MemOp_LOAD -> { + oR := append(xFP(t),append(xFP(t2),oR)); + ik := rmem_kind(acctype,false); + } + } + } + case (LoadImmediate(n,t,acctype,memop,_signed,wback,postindex,offset,regsize,datasize)) -> { + (boolean) wb_unknown := false; + (boolean) rt_unknown := false; + if n == 31 then { + iR := append(CheckSPAlignmentIFP,iR); + iR := append(rSPIFP,iR); + aR := append(rSPIFP,aR); + } + else { + iR := append(xFP(n),iR); + aR := append(xFP(n),aR); + }; + if wback then { + if n == 31 then + let (i,o) = wSPFP in {iR := append(i,iR); oR := append(o,oR)} + else oR := append(xFP(n),oR); + }; + switch memop { + case MemOp_STORE -> { + if rt_unknown then () + else iR := append(xFP(t),iR); + iR := append(wMemIFP,iR); + ik := wmem_kind(acctype,false); + } + case MemOp_LOAD -> { + oR := append(xFP(t),oR); + ik := rmem_kind(acctype,false); + } + case MemOp_PREFETCH -> aR := [|| ||] + } + } + case (LoadRegister(n,t,m,acctype,memop,_signed,wback,postindex,extend_type,shift,regsize,datasize)) -> { + iR := append(xFP(m),iR); + aR := append(xFP(m),aR); + (boolean) wb_unknown := false; + (boolean) rt_unknown := false; + if n == 31 then { + iR := append(CheckSPAlignmentIFP,iR); + iR := append(rSPIFP,iR); + aR := append(rSPIFP,aR); + } + else { + iR := append(xFP(n),iR); + aR := append(xFP(n),aR); + }; + if wback then { + if n == 31 then let (i,o) = wSPFP in {iR := append(i,iR); oR := append(o,oR)} + else oR := append(xFP(n),oR); + }; + switch memop { + case MemOp_STORE -> { + if rt_unknown then () + else iR := append(xFP(t),iR); + iR := append(wMemIFP,iR); + ik := wmem_kind(acctype,false); + } + case MemOp_LOAD -> { + oR := append(xFP(t),oR); + ik := rmem_kind(acctype,false); + } + case MemOp_PREFETCH -> aR := [|| ||] + } + } + case (LoadStorePair(wback,postindex,n,t,t2,acctype,memop,_signed,datasize,offset)) -> { + (boolean) rt_unknown := false; + (boolean) wb_unknown := false; + if n == 31 then { + iR := append(CheckSPAlignmentIFP,iR); + iR := append(rSPIFP,iR); + aR := append(rSPIFP,aR); + } + else { + iR := append(xFP(n),iR); + aR := append(xFP(n),aR); + }; + if wback then { + if n == 31 then let (i,o) = wSPFP in {iR := append(i,iR); oR := append(o,oR)} + else oR := append(xFP(n),oR); + }; + switch memop { + case MemOp_STORE -> { + if rt_unknown & t == n then () + else iR := append(xFP(t),iR); + if rt_unknown & t2 == n then () + else iR := append(xFP(t2),iR); + iR := append(wMemIFP,iR); + ik := wmem_kind(acctype,false); + } + case MemOp_LOAD -> { + oR := append(xFP(t),oR); + oR := append(xFP(t2),oR); + ik := rmem_kind(acctype,false); + } + } + } + case (AddSubImmediate(d,n,datasize,sub_op,setflags,imm)) -> { + iR := append(if n == 31 then rSPIFP else xFP(n),iR); + if setflags then oR := append(NZCVfp,oR); + if d ==31 & ~(setflags) then + let (i,o) = wSPFP in + { iR := append(i,iR); + oR := append(o,oR) } + else oR := append(xFP(d),oR) + } + case (BitfieldMove(d,n,datasize,inzero,extend,R,S,wmask,tmask)) -> { + if inzero then () else iR:= append(xFP(d),iR); + iR := append(xFP(n),iR); + oR := append(xFP(d),oR); + } + case (ExtractRegister(d,n,m,datasize,lsb)) -> { + iR := append(xFP(n),append(xFP(m),iR)); + oR := append(xFP(d),oR); + } + case (LogicalImmediate(d,n,datasize,setflags,op,imm)) -> { + iR := append(xFP(n),iR); + if setflags then oR := append(NZCVfp,oR); + if d ==31 & ~(setflags) then let (i,o) = wSPFP in + { iR := append(i,iR); oR := append(o,oR) } + else oR := append(xFP(d),oR) + } + case (MoveWide(d,datasize,imm,pos,opcode)) -> { + if opcode == MoveWideOp_K then iR := append(xFP(d),iR); + oR := append(xFP(d),oR); + } + case (Address(d,page,imm)) -> { + iR := _PCfp :: iR; + oR := append(xFP(d),oR); + } + case (AddSubExtendRegister(d,n,m,datasize,sub_op,setflags,extend_type,shift)) -> { + iR := append(if n == 31 then rSPIFP else xFP(n),iR); + iR := append(xFP(m),iR); + if setflags then oR := append(NZCVfp,oR); + if d ==31 & ~(setflags) then let (i,o) = wSPFP in + { iR := append(i,iR); oR := append(o,oR) } + else oR := append(xFP(d),oR) + } + case (AddSubShiftedRegister(d,n,m,datasize,sub_op,setflags,shift_type,shift_amount)) -> { + iR := append(xFP(n),append(xFP(m),iR)); + if setflags then oR := append(NZCVfp,oR); + oR := append(xFP(d),oR); + } + case (AddSubCarry(d,n,m,datasize,sub_op,setflags)) -> { + iR := append(xFP(n),append(xFP(m),iR)); + iR := PSTATE_Cfp :: iR; + if setflags then oR := append(NZCVfp,oR); + oR := append(xFP(d),oR); + } + case (ConditionalCompareImmediate(n,datasize,sub_op,condition,flags,imm)) -> { + iR := append(xFP(n),iR); + iR := append(ConditionHoldsIFP(condition),iR); + oR := append(NZCVfp,oR); + } + case (ConditionalCompareRegister(n,m,datasize,sub_op,condition,flags)) -> { + iR := append(xFP(n),append(xFP(m),iR)); + iR := append(ConditionHoldsIFP(condition),iR); + oR := append(NZCVfp,oR); + } + case (ConditionalSelect(d,n,m,datasize,condition,else_inv,else_inc)) -> { + iR := append(xFP(n),append(xFP(m),iR)); + iR := append(ConditionHoldsIFP(condition),iR); + oR := append(xFP(d),oR); + } + case (Reverse(d,n,datasize,op)) -> { + iR := append(xFP(n),iR); + oR := append(xFP(d),oR); + } + case (CountLeading(d,n,datasize,opcode)) -> { + iR := append(xFP(n),iR); + oR := append(xFP(d),oR); + } + case (Division(d,n,m,datasize,_unsigned)) -> { + iR := append(xFP(n),append(xFP(m),iR)); + oR := append(xFP(d),oR); + } + case (Shift(d,n,m,datasize,shift_type)) -> { + iR := append(xFP(m),iR); + iR := append(xFP(n),iR); + oR := append(xFP(d),oR); + } + case (CRC(d,n,m,size,crc32c)) -> { + iR := append(xFP(n),append(xFP(m),iR)); + oR := append(xFP(d),oR); + } + case (MultiplyAddSub(d,n,m,a,destsize,datasize,sub_op)) -> { + iR := append(xFP(n),iR); + iR := append(xFP(m),iR); + iR := append(xFP(a),iR); + oR := append(xFP(d),oR); + } + case (MultiplyAddSubLong(d,n,m,a,destsize,datasize,sub_op,_unsigned)) -> { + iR := append(xFP(n),iR); + iR := append(xFP(m),iR); + iR := append(xFP(a),iR); + oR := append(xFP(d),oR); + } + case (MultiplyHigh(d,n,m,a,destsize,datasize,_unsigned)) -> { + iR := append(xFP(n),append(xFP(m),iR)); + oR := append(xFP(d),oR); + } + case (LogicalShiftedRegister(d,n,m,datasize,setflags,op,shift_type,shift_amount,invert)) -> { + iR := append(xFP(n),append(xFP(m),iR)); + if setflags then oR := append(NZCVfp,oR); + oR := append(xFP(d),oR); + } + }; + (iR,oR,aR,Nias,Dia,ik) +} diff --git a/arm/armV8.h.sail b/arm/armV8.h.sail index c788855a..9105f964 100644 --- a/arm/armV8.h.sail +++ b/arm/armV8.h.sail @@ -43,6 +43,27 @@ typedef SIMD_index = [|32|] register (bit[64]) _PC +(* transactional memory registers *) +register (bit[8]) TxNestingLevel (* same size as TXIDR_EL0.DEPTH *) + +typedef TMSTATUS_type = register bits [63:0] +{ + (*63..17 : RES0;*) + 16 : IMP; + 15 : DBG; + 14 : MEM; + 13 : ERR; + 12 : INV; + 11 : SIZE; + 10 : NEST; + 9 : ABRT; + 8 : RTRY; + (*7..5 : RES0*) + 4..0 : REASON; +} +register (TMSTATUS_type) TMAbortEffect (* we abuse the register write to pass out the status value *) +register (TMSTATUS_type) TMStartEffect (* we abuse the register read to pass in the status value *) + (* General purpose registers *) register (bit[64]) R30 @@ -170,3 +191,6 @@ let IMPLEMENTATION_DEFINED = (* FIXME: ask Kathy what should we do with this *) let UNKNOWN = 0 + + +val extern unit -> bool effect {exmem} speculate_exclusive_success diff --git a/arm/armV8.sail b/arm/armV8.sail index 10c57d1e..2614c7a5 100644 --- a/arm/armV8.sail +++ b/arm/armV8.sail @@ -40,6 +40,12 @@ typedef ast = const union forall Nat 'R, 'R IN {32, 64}, (* register size *) ImplementationDefinedStopFetching; ImplementationDefinedThreadStart; + (* transactional memory, from the pre-alpha document *) + (reg_index) TMStart; + TMCommit; + (boolean,bit[5]) TMAbort; + TMTest; + (reg_index,[:'R:],boolean,bit[64]) CompareAndBranch; (bit[64],bit[4]) BranchConditional; (bit[16]) GenerateExceptionEL1; (* TODO: add to .hgen *) @@ -64,7 +70,7 @@ typedef ast = const union forall Nat 'R, 'R IN {32, 64}, (* register size *) (boolean,boolean,reg_index,reg_index,reg_index,AccType,MemOp,uinteger,[:'D:],bit[64]) LoadStorePairNonTemp; (reg_index,reg_index,AccType,MemOp,boolean,boolean,boolean,bit[64],[:'R:],[:'D:]) LoadImmediate; (reg_index,reg_index,reg_index,AccType,MemOp,boolean,boolean,boolean,ExtendType,uinteger,[:'R:],[:'D:]) LoadRegister; - (boolean,boolean,reg_index,reg_index,reg_index,AccType,MemOp,boolean,uinteger,[:'D:],bit[64]) LoadStorePair; + (boolean,boolean,reg_index,reg_index,reg_index,AccType,MemOp,boolean,[:'D:],bit[64]) LoadStorePair; (reg_index,reg_index,[:'R:],boolean,boolean,bit['R]) AddSubImmediate; (reg_index,reg_index,[:'R:],boolean,boolean,uinteger,uinteger,bit['R],bit['R]) BitfieldMove; (reg_index,reg_index,reg_index,[:'R:],uinteger) ExtractRegister; @@ -86,12 +92,91 @@ typedef ast = const union forall Nat 'R, 'R IN {32, 64}, (* register size *) (reg_index,reg_index,reg_index,reg_index,[:'R:],[:'D:],boolean,boolean) MultiplyAddSubLong; (reg_index,reg_index,reg_index,reg_index,[:'R:],[:'D:],boolean) MultiplyHigh; (reg_index,reg_index,reg_index,[:'R:],boolean,LogicalOp,ShiftType,[|63|],boolean) LogicalShiftedRegister; - } -val forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. ast<'R,'D> -> unit effect {rreg,wreg,rmem,barr,eamem,wmv,escape} execute +val forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. ast<'R,'D> -> unit effect {rreg,wreg,rmem,barr,eamem,wmv,exmem,escape} execute scattered function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. unit execute +(* TSTART - dummy decoding *) +function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. + option<(ast<'R,'D>)> effect pure decodeTMStart ((bit[5]) Rt) = +{ + (reg_index) t := UInt_reg(Rt); + + Some(TMStart(t)); +} + +(* transactional memory, from the pre-alpha document *) +function clause execute (TMStart(t)) = { + (bit[8]) nesting := TxNestingLevel; + + if nesting <_u TXIDR_EL0.DEPTH then { + TxNestingLevel := nesting + 1; + (bit[64]) status := 0; + if nesting == 0 then + status := TMStartEffect; (* fake effect *) + wX(t) := status; + } else { + (bit[64]) status := 0; + status[10] := 1; (* set the NEST bit *) + TMAbortEffect := status; (* fake effect *) + } +} + +val extern unit -> unit effect {barr} TMCommitEffect + +(* TCOMMIT - dummy decoding *) +function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. + option<(ast<'R,'D>)> effect pure decodeTMCommit () = +{ + Some(TMCommit); +} + +(* transactional memory, from the pre-alpha document *) +function clause execute (TMCommit) = { + (bit[8]) nesting := TxNestingLevel; + + if nesting == 1 then + TMCommitEffect() (* fake effect *) + else if nesting == 0 then + AArch64_UndefinedFault(); + + TxNestingLevel := nesting - 1; +} + +(* TTEST - dummy decoding *) +function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. + option<(ast<'R,'D>)> effect pure decodeTMTest () = +{ + Some(TMTest); +} + +(* transactional memory, from the pre-alpha document *) +function clause execute (TMTest) = { + if TxNestingLevel > 0 then + wPSTATE_NZCV() := 0b0000 + else + wPSTATE_NZCV() := 0b0100 +} + +(* TABORT - dummy decoding *) +function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. + option<(ast<'R,'D>)> effect pure decodeTMAbort ([R]:(bit[5]) imm5) = +{ + Some(TMAbort(R,imm5)); +} + +(* transactional memory, from the pre-alpha document *) +function clause execute (TMAbort(retry,reason)) = { + if TxNestingLevel > 0 then { + (bit[64]) status := 0; + status[4..0] := reason; (* REASON *) + status[8] := retry; (* RTRY *) + status[9] := 1; (* ABRT *) + TMAbortEffect := status; (* fake effect *) + }; +} + (* CBNZ *) (* CBZ *) function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. @@ -517,16 +602,16 @@ function clause execute ( TestBitAndBranch(t,datasize,bit_pos,bit_val,offset) ) (* BL *) function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. option<(ast<'R,'D>)> effect {escape} decodeUnconditionalBranchImmediate ([op]:0b00101:(bit[26]) imm26) = { - (BranchType) _branch_type := if op == 1 then BranchType_CALL else BranchType_JMP; + (BranchType) branch_type := if op == 1 then BranchType_CALL else BranchType_JMP; (bit[64]) offset := SignExtend(imm26:0b00); - Some(BranchImmediate(_branch_type,offset)); + Some(BranchImmediate(branch_type,offset)); } -function clause execute (BranchImmediate(_branch_type,offset)) = { - if _branch_type == BranchType_CALL then wX(30) := rPC() + 4; +function clause execute (BranchImmediate(branch_type,offset)) = { + if branch_type == BranchType_CALL then wX(30) := rPC() + 4; - BranchTo(rPC() + offset, _branch_type); + BranchTo(rPC() + offset, branch_type); } @@ -540,24 +625,24 @@ scattered function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. (* RET *) function clause decodeUnconditionalBranchRegister (0b1101011:0b00:op:0b11111:0b000000:Rn:0b00000) = { (reg_index) n := UInt_reg(Rn); - (BranchType) _branch_type := 0; (* ARM: uninitialized *) + (BranchType) branch_type := 0; (* ARM: uninitialized *) switch op { - case 0b00 -> _branch_type := BranchType_JMP - case 0b01 -> _branch_type := BranchType_CALL - case 0b10 -> _branch_type := BranchType_RET + case 0b00 -> branch_type := BranchType_JMP + case 0b01 -> branch_type := BranchType_CALL + case 0b10 -> branch_type := BranchType_RET case _ -> UnallocatedEncoding() }; - Some(BranchRegister(n,_branch_type)); + Some(BranchRegister(n,branch_type)); } -function clause execute (BranchRegister(n,_branch_type)) = +function clause execute (BranchRegister(n,branch_type)) = { (bit[64]) target := rX(n); - if _branch_type == BranchType_CALL then wX(30) := rPC() + 4; - BranchTo(target, _branch_type); + if branch_type == BranchType_CALL then wX(30) := rPC() + 4; + BranchTo(target, branch_type); } (* ERET *) @@ -717,7 +802,7 @@ function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. 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) ) = { +function clause execute ( LoadStoreAcqExc(n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,([:'D:]) datasize) ) = { (bit[64]) address := 0; (* ARM: uninitialized *) (bit['D]) data := 0; (* ARM: uninitialized *) (*constant*) (uinteger) dbytes := datasize quot 8; @@ -760,6 +845,19 @@ function clause execute ( LoadStoreAcqExc(n,t,t2,s,acctype,excl,pair,memop,elsiz }; }; + (* this is a hack to allow the result of store-exclusive to be observed + before anything else *) + (bit) status := 0; + if memop == MemOp_STORE & excl then { + (*(bit)*) status := if speculate_exclusive_success() then 0 else 1; + wX(s) := (bit[32]) (ZeroExtend([status])); + + (* should be: + if status == 1 then return (); + *) + }; + if status == 1 then () else { + if n == 31 then { CheckSPAlignment(); address := rSP(); @@ -781,7 +879,7 @@ function clause execute ( LoadStoreAcqExc(n,t,t2,s,acctype,excl,pair,memop,elsiz (bit['R]) el2 := rX(t2); (* ARM: bit[datasize / 2] see lemma in the decoding *) data := if BigEndian() then el1:el2 else el2:el1; } else - data := rX(t); + (bit['D]) data := rX(t); if excl then { (* store {release} exclusive register|pair (atomic) *) @@ -798,7 +896,9 @@ function clause execute ( LoadStoreAcqExc(n,t,t2,s,acctype,excl,pair,memop,elsiz wMem_exclusive(empty_write_buffer, address, dbytes, acctype, data) ); }; + (* ARM: the following code was moved up, see note there wX(s) := (bit[32]) (ZeroExtend([status])); + *) } else { (* store release register (atomic) *) flush_write_buffer( @@ -860,6 +960,7 @@ function clause execute ( LoadStoreAcqExc(n,t,t2,s,acctype,excl,pair,memop,elsiz }; } }; + }; } (* LDNP *) @@ -885,7 +986,7 @@ function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. 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,offset) ) = { +function clause execute ( LoadStorePairNonTemp(wback,postindex,n,t,t2,acctype,memop,scale,([:'D:]) datasize,offset) ) = { (bit[64]) address := 0; (* ARM: uninitialized *) (bit['D]) data1 := 0; (* ARM: uninitialized *) (bit['D]) data2 := 0; (* ARM: uninitialized *) @@ -930,11 +1031,11 @@ function clause execute ( LoadStorePairNonTemp(wback,postindex,n,t,t2,acctype,me switch memop { case MemOp_STORE -> { if rt_unknown & t == n then - date1 := (bit['D]) UNKNOWN + data1 := (bit['D]) UNKNOWN else data1 := rX(t); if rt_unknown & t2 == n then - date2 := (bit['D]) UNKNOWN + data2 := (bit['D]) UNKNOWN else data2 := rX(t2); @@ -951,7 +1052,7 @@ function clause execute ( LoadStorePairNonTemp(wback,postindex,n,t,t2,acctype,me data2 := read_data[((datasize * 2) - 1)..datasize]; if rt_unknown then { - date1 := (bit['D]) UNKNOWN; + data1 := (bit['D]) UNKNOWN; data2 := (bit['D]) UNKNOWN; }; wX(t) := data1; @@ -1028,7 +1129,7 @@ function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. 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) ) = { +function clause execute ( LoadImmediate(n,t,acctype,memop,_signed,wback,postindex,offset,regsize,([:'D:]) datasize) ) = { (bit[64]) address := 0; (* ARM: uninitialized *) (bit['D]) data := 0; (* ARM: uninitialized *) (boolean) wb_unknown := false; @@ -1191,7 +1292,7 @@ function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. 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) ) = { +function clause execute ( LoadRegister(n,t,m,acctype,memop,_signed,wback,postindex,extend_type,shift,regsize,([:'D:]) datasize) ) = { (bit[64]) offset := ExtendReg(m, extend_type, shift); (bit[64]) address := 0; (* ARM: uninitialized *) (bit['D]) data := 0; (* ARM: uninitialized *) @@ -1352,7 +1453,7 @@ function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. ([:'D:]) datasize := lsl(8, scale); (bit[64]) offset := LSL(SignExtend(imm7), scale); - Some(LoadStorePair(wback,postindex,n,t,t2,acctype,memop,_signed,scale,datasize,offset)); + Some(LoadStorePair(wback,postindex,n,t,t2,acctype,memop,_signed,datasize,offset)); } (* LDP signed offset *) @@ -1367,7 +1468,7 @@ function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. sharedDecodeLoadStorePair(L,opc,imm7,Rn,Rt,Rt2,wback,postindex); } -function clause execute ( LoadStorePair(wback,postindex,n,t,t2,acctype,memop,_signed,scale,datasize,offset) ) = { +function clause execute ( LoadStorePair(wback,postindex,n,t,t2,acctype,memop,_signed,([:'D:])datasize,offset) ) = { (bit[64]) address := 0; (* ARM: uninitialized *) (bit['D]) data1 := 0; (* ARM: uninitialized *) (bit['D]) data2 := 0; (* ARM: uninitialized *) @@ -1616,7 +1717,7 @@ function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. Some(ExtractRegister(d,n,m,datasize,lsb)); } -function clause execute ( ExtractRegister(d,n,m,datasize,lsb) ) = { +function clause execute ( ExtractRegister(d,n,m,([:'R:]) datasize,lsb) ) = { (bit['R]) result := 0; (* ARM: uninitialized *) (bit['R]) operand1 := rX(n); (bit['R]) operand2 := rX(m); @@ -1650,7 +1751,7 @@ function forall Nat 'R, 'R IN {32,64}, Nat 'D, 'D IN {8,16,32,64}. Some(LogicalImmediate(d,n,datasize,setflags,op,imm)); }} -function clause execute (LogicalImmediate(d,n,datasize,setflags,op,imm)) = { +function clause execute (LogicalImmediate(d,n,([:'R:]) datasize,setflags,op,imm)) = { (bit['R]) result := 0; (* ARM: uninitialized *) (bit['R]) operand1 := rX(n); (bit['R]) operand2 := imm; diff --git a/arm/armV8_A64_lib.sail b/arm/armV8_A64_lib.sail index 5a1b6ec3..2aa31d4f 100644 --- a/arm/armV8_A64_lib.sail +++ b/arm/armV8_A64_lib.sail @@ -730,6 +730,8 @@ function bit[64] System_Get((uinteger) op0, (uinteger) op1, (uinteger) crn, (uin switch (op0,op1,crn,crm,op2) { case (3,3,4,2,0) -> ZeroExtend(NZCV) case (3,3,4,2,1) -> ZeroExtend(DAIF) + case (3, 3, 13, 0, 2) -> TPIDR_EL0 + (* TODO FIXME: higher EL TPIDRs *) (* case (3,0,1,0,1) -> ZeroExtend(ACTLR_EL1) *) } @@ -741,6 +743,8 @@ function unit effect {wreg} System_Put((uinteger) op0, (uinteger) op1, (uinteger switch (op0,op1,crn,crm,op2) { case (3,3,4,2,0) -> NZCV := _val[31..0] case (3,3,4,2,1) -> DAIF := _val[31..0] + case (3, 3, 13, 0, 2) -> TPIDR_EL0 := _val[63..0] + (* TODO FIXME: higher EL TPIDRs *) (* case (3,0,1,0,1) -> ACTLR_EL1 := _val[31..0] *) } @@ -756,7 +760,19 @@ function unit AArch64_ExceptionReturn((bit[64]) new_pc, (bit[32]) spsr) = (** ENUMERATE:aarch64/instrs/countop/CountOp *) (** FUNCTION:ExtendType DecodeRegExtend(bits(3) op) *) -function ExtendType DecodeRegExtend ((bit[3]) op) = ([|8|]) op +function ExtendType DecodeRegExtend ((bit[3]) op) = +{ + switch op { + case 0b000 -> ExtendType_UXTB + case 0b001 -> ExtendType_UXTH + case 0b010 -> ExtendType_UXTW + case 0b011 -> ExtendType_UXTX + case 0b100 -> ExtendType_SXTB + case 0b101 -> ExtendType_SXTH + case 0b110 -> ExtendType_SXTW + case 0b111 -> ExtendType_SXTX + } +} (** FUNCTION:aarch64/instrs/extendreg/ExtendReg *) diff --git a/arm/armV8_A64_sys_regs.sail b/arm/armV8_A64_sys_regs.sail index 50c150c6..95b5c710 100644 --- a/arm/armV8_A64_sys_regs.sail +++ b/arm/armV8_A64_sys_regs.sail @@ -35,162 +35,6 @@ (*************************************************************************) (* General system control registers *) -register (bit[32]) ACTLR_EL1 (* Auxiliary Control Register (EL1) *) (* UNUSED *) -register (bit[32]) ACTLR_EL2 (* Auxiliary Control Register (EL2) *) (* UNUSED *) -register (bit[32]) ACTLR_EL3 (* Auxiliary Control Register (EL3) *) (* UNUSED *) -register (bit[32]) AFSR0_EL1 (* Auxiliary Fault Status Register 0 (EL1) *) (* UNUSED *) -register (bit[32]) AFSR0_EL2 (* Auxiliary Fault Status Register 0 (EL2) *) (* UNUSED *) -register (bit[32]) AFSR0_EL3 (* Auxiliary Fault Status Register 0 (EL3) *) (* UNUSED *) -register (bit[32]) AFSR1_EL1 (* Auxiliary Fault Status Register 1 (EL1) *) (* UNUSED *) -register (bit[32]) AFSR1_EL2 (* Auxiliary Fault Status Register 1 (EL2) *) (* UNUSED *) -register (bit[32]) AFSR1_EL3 (* Auxiliary Fault Status Register 1 (EL3) *) (* UNUSED *) -register (bit[32]) AIDR_EL1 (* Auxiliary ID Register *) (* UNUSED *) -register (bit[64]) AMAIR_EL1 (* Auxiliary Memory Attribute Indirection Register (EL1) *) (* UNUSED *) -register (bit[64]) AMAIR_EL2 (* Auxiliary Memory Attribute Indirection Register (EL2) *) (* UNUSED *) -register (bit[64]) AMAIR_EL3 (* Auxiliary Memory Attribute Indirection Register (EL3) *) (* UNUSED *) - -typedef CCSIDR_type = register bits [31:0] -{ - 31 : WT; - 30 : WB; - 29 : RA; - 28 : WA; - 27..13 : NumSets; - 12..3 : Associativity; - 2..0 : LineSize; -} -register (CCSIDR_type) CCSIDR_EL1 (* Current Cache Size ID Register *) (* UNUSED *) - -typedef CLIDR_type = register bits [63:0] -{ - (*63..33 : RES0*) - 32..30 : ICB; - 29..27 : LoUU; - 26..24 : LoC; - 23..21 : LoUIS; - 20..18 : Ctype7; - 17..15 : Ctype6; - 14..12 : Ctype5; - 11..9 : Ctype4; - 8..6 : Ctype3; - 5..3 : Ctype2; - 2..0 : Ctype1; -} -register (CLIDR_type) CLIDR_EL1 (* Cache Level ID Register *) (* UNUSED *) - -typedef CONTEXTIDR_type = register bits [31:0] { 31..0 : PROCID } -register (CONTEXTIDR_type) CONTEXTIDR_EL1 (* Context ID Register *) (* UNUSED *) - -typedef CPACR_type = register bits [31:0] -{ - (*31..29 : RES0;*) - 28 : TTA; - (*27..22 : RES0;*) - 21..20 : FPEN; - (*19..0 : RES0;*) -} -register (CPACR_type) CPACR_EL1 (* Architectural Feature Access Control Register *) (* UNUSED *) - -typedef CPTR_type = register bits [31:0] -{ - (* in EL3 all the RES are RES0 *) - 31 : TCPAC; - (*30..21 : RES0;*) - 20 : TTA; - (*19..14 : RES0;*) - (*13..12 : RES1;*) - (*11 : RES0;*) - 10 : TFP; - (*9..0 : RES1;*) -} -register (CPTR_type) CPTR_EL2 (* Architectural Feature Trap Register (EL2) *) (* UNUSED *) -register (CPTR_type) CPTR_EL3 (* Architectural Feature Trap Register (EL3) *) (* UNUSED *) - -typedef CSSELR_type = register bits [31:0] -{ - (*31..4 : RES0;*) - 3..1 : Level; - 0 : InD; -} -register (CSSELR_type) CSSELR_EL1 (* Cache Size Selection Register *) (* UNUSED *) - -typedef CTR_type = register bits [31:0] -{ - (*31 : RES1;*) - (*30..28 : RES0;*) - 27..24 : CWG; - 23..20 : ERG; - 19..16 : DminLine; - 15..14 : L1Ip; - (*13..4 : RES0;*) - 3..0 : IminLine; -} -register (CTR_type) CTR_EL0 (* Cache Type Register *) (* UNUSED *) - -typedef DACR32_type = register bits [31:0] -{ - 31..30 : D15; - 29..28 : D14; - 27..26 : D13; - 25..24 : D12; - 23..22 : D11; - 21..20 : D10; - 29..18 : D9; - 17..16 : D8; - 15..14 : D7; - 13..12 : D6; - 11..10 : D5; - 9..8 : D4; - 7..6 : D3; - 5..4 : D2; - 3..2 : D1; - 1..0 : D0; -} -register (DACR32_type) DACR32_EL2 (* Domain Access Control Register *) (* UNUSED *) - -typedef DCZID_type = register bits [31:0] -{ - (*31..5 : RES0;*) - 4 : DZP; - 3..0 : BS; -} -register (DCZID_type) DCZID_EL0 (* Data Cache Zero ID register *) (* UNUSED *) - -typedef ESR_type = register bits [31:0] -{ - 31..26 : EC; - 25 : IL; - 24..0 : ISS; -} -register (ESR_type) ESR_EL1 (* Exception Syndrome Register (EL1) *) (* UNUSED *) -register (ESR_type) ESR_EL2 (* Exception Syndrome Register (EL2) *) (* UNUSED *) -register (ESR_type) ESR_EL3 (* Exception Syndrome Register (EL3) *) (* UNUSED *) - -register (bit[64]) FAR_EL1 (* Fault Address Register (EL1) *) (* UNUSED *) -register (bit[64]) FAR_EL2 (* Fault Address Register (EL2) *) (* UNUSED *) -register (bit[64]) FAR_EL3 (* Fault Address Register (EL3) *) (* UNUSED *) - -typedef FPEXC32_type = register bits [31:0] -{ - 31 : EX; - 30 : EN; - 29 : DEX; - 28 : FP2V; - 27 : VV; - 26 : TFV; - (*25..21 : RES0;*) - (*20..11 : IMPLEMENTATION DEFINED*) - 10..8 : VECITR; - 7 : IDF; - (*6..5 : IMPLEMENTATION DEFINED*) - 4 : IXF; - 3 : UFF; - 2 : OFF; - 1 : DZF; - 0 : IOF; -} -register (FPEXC32_type) FPEXC32_EL2 (* Floating-point Exception Control register *) (* UNUSED *) -register (bit[32]) HACR_EL2 (* Hypervisor Auxiliary Control Register *) (* UNUSED *) typedef HCR_type = register bits [63:0] { @@ -231,35 +75,6 @@ typedef HCR_type = register bits [63:0] } register (HCR_type) HCR_EL2 (* Hypervisor Configuration Register *) -typedef HPFAR_type = register bits [63:0] -{ - (*63..40 : RES0;*) - 39..4 : FIPA; (* bits [47:12] of FIPA *) - (*3..0 : RES0;*) -} -register (HPFAR_type) HPFAR_EL2 (* Hypervisor IPA Fault Address Register *) (* UNUSED *) - -typedef HSTR_type = register bits [31:0] -{ - (*31..16 : RES0;*) - 15 : T15; - 14 : T14; - 13 : T13; - 12 : T12; - 11 : T11; - 10 : T10; - 9 : T9; - 8 : T8; - 7 : T7; - 6 : T6; - 5 : T5; - 4 : T4; - 3 : T3; - 2 : T2; - 1 : T1; - 0 : T0; -} -register (HSTR_type) HSTR_EL2 (* Hypervisor System Trap Register *) (* UNUSED *) typedef ID_AA64MMFR0_type = register bits [63:0] { @@ -402,6 +217,11 @@ typedef TCR_type = register bits [31:0] register (TCR_type) TCR_EL2 (* Translation Control Register (EL2) *) register (TCR_type) TCR_EL3 (* Translation Control Register (EL3) *) +register (bit[64]) TPIDR_EL0 (* EL0 Read/Write Software Thread ID Register *) +register (bit[64]) TPIDR_EL1 (* EL1 Read/Write Software Thread ID Register *) +register (bit[64]) TPIDR_EL2 (* EL2 Read/Write Software Thread ID Register *) +register (bit[64]) TPIDR_EL3 (* EL3 Read/Write Software Thread ID Register *) + (*************************************************************************) (* Debug registers *) @@ -458,9 +278,17 @@ typedef EDSCR_type = register bits [31:0] } register (EDSCR_type) EDSCR (* External Debug Status and Control Register *) +(* transactional memory, from the pre-alpha document *) +typedef TXIDR_EL0_type = register bits [63:0] +{ + (*63..8 : RES0;*) + 7..0 : DEPTH; +} +register (TXIDR_EL0_type) TXIDR_EL0 (* Transaction ID Register *) + + function unit effect pure AArch64_ResetControlRegisters((boolean) cold_reset) = { () } - diff --git a/arm/armV8_common_lib.sail b/arm/armV8_common_lib.sail index 3bae8070..9bea1cd1 100644 --- a/arm/armV8_common_lib.sail +++ b/arm/armV8_common_lib.sail @@ -513,8 +513,8 @@ val extern unit -> unit effect {barr} DataMemoryBarrier_All function unit effect {barr} DataMemoryBarrier((MBReqDomain) domain, (MBReqTypes) types) = { - if domain != MBReqDomain_FullSystem then - not_implemented("DataMemoryBarrier: not MBReqDomain_FullSystem"); + if domain != MBReqDomain_FullSystem & domain != MBReqDomain_InnerShareable then + not_implemented("DataMemoryBarrier: not MBReqDomain_FullSystem or _InnerShareable"); switch types { case MBReqTypes_Reads -> DataMemoryBarrier_Reads() @@ -725,10 +725,10 @@ function bool effect {wmv} flush_write_buffer_exclusive((write_buffer_type) writ (** FUNCTION:BranchTo(bits(N) target, BranchType branch_type) *) -function forall Nat 'N, 'N IN {32,64}. unit effect {rreg,wreg} BranchTo((bit['N]) target, (BranchType) _branch_type) = { +function forall Nat 'N, 'N IN {32,64}. unit effect {rreg,wreg} BranchTo((bit['N]) target, (BranchType) branch_type) = { (bit['N]) target' := target; (* Sail does not let you change parameter vector *) - Hint_Branch(_branch_type); + Hint_Branch(branch_type); if length(target) == 32 then { assert( UsingAArch32(), None ); _PC := ZeroExtend(target); @@ -831,7 +831,7 @@ function boolean effect {rreg} ConditionHolds((bit[4]) _cond) = case 0b111 -> result := true (* AL *) }; - (* Condition flag valuesin the set '111x' indicate always true *) + (* Condition flag values in the set '111x' indicate always true *) (* Otherwise, invert condition if necessary. *) if _cond[0] == 1 & _cond != 0b1111 then result := ~(result); diff --git a/arm/armV8_extras.lem b/arm/armV8_extras.lem new file mode 100644 index 00000000..9a187ecb --- /dev/null +++ b/arm/armV8_extras.lem @@ -0,0 +1,77 @@ +open import Pervasives +open import Interp_ast +open import Interp_interface +open import Sail_impl_base +open import Interp_inter_imp +import Set_extra + +let memory_parameter_transformer mode v = + match v with + | Interp_ast.V_tuple [location;length] -> + let (v,loc_regs) = extern_with_track mode extern_vector_value location in + + match length with + | Interp_ast.V_lit (L_aux (L_num len) _) -> + (v,(natFromInteger len),loc_regs) + + | Interp_ast.V_track (Interp_ast.V_lit (L_aux (L_num len) _)) size_regs -> + match loc_regs with + | Nothing -> (v,(natFromInteger len),Just (List.map (fun r -> extern_reg r Nothing) (Set_extra.toList size_regs))) + | Just loc_regs -> (v,(natFromInteger len),Just (loc_regs++(List.map (fun r -> extern_reg r Nothing) (Set_extra.toList size_regs)))) + end + + | _ -> Assert_extra.failwith "expected 'V_lit (L_aux (L_num _) _)' or 'V_track (V_lit (L_aux (L_num len) _)) _'" + end + | _ -> Assert_extra.failwith "expected 'V_tuple [_;_]'" + end + +let aArch64_read_memory_functions : memory_reads = + [ ("rMem_NORMAL", (MR Read_plain memory_parameter_transformer)); + ("rMem_STREAM", (MR Read_stream memory_parameter_transformer)); + ("rMem_ORDERED", (MR Read_acquire memory_parameter_transformer)); + ("rMem_ATOMIC", (MR Read_exclusive memory_parameter_transformer)); + ("rMem_ATOMIC_ORDERED", (MR Read_exclusive_acquire memory_parameter_transformer)); + ] + +let aArch64_memory_writes : memory_writes = [] + (* [ ("wMem_NORMAL", (MW Write_plain memory_parameter_transformer Nothing)); + ("wMem_ORDERED", (MW Write_release memory_parameter_transformer Nothing)); + ("wMem_ATOMIC", (MW Write_exclusive memory_parameter_transformer Nothing)); + ("wMem_ATOMIC_ORDERED", (MW Write_exclusive_release memory_parameter_transformer Nothing)); + ] *) + +let aArch64_memory_eas : memory_write_eas = + [ ("wMem_Addr_NORMAL", (MEA Write_plain memory_parameter_transformer)); + ("wMem_Addr_ORDERED", (MEA Write_release memory_parameter_transformer)); + ("wMem_Addr_ATOMIC", (MEA Write_exclusive memory_parameter_transformer)); + ("wMem_Addr_ATOMIC_ORDERED", (MEA Write_exclusive_release memory_parameter_transformer)); + ] + +let aArch64_memory_vals : memory_write_vals = + [ ("wMem_Val_NORMAL", (MV (fun mode v -> Nothing) Nothing)); + ("wMem_Val_ATOMIC", (MV (fun mode v -> Nothing) + (Just + (fun (IState interp context) b -> + (*ppcmem2 provides true for success and false for failure; but the status for ARM is reversed*) + let bit = Interp_ast.V_lit (L_aux (if b then L_zero else L_one) Interp_ast.Unknown)in + (IState (Interp.add_answer_to_stack interp bit) context))))); + ] + +let aArch64_excl_res : excl_res = + let f = fun (IState interp context) b -> + let bool_res = Interp_ast.V_lit (L_aux (if b then L_one else L_zero) Interp_ast.Unknown) in + IState (Interp.add_answer_to_stack interp bool_res) context + in + Just ("speculate_exclusive_success", (ER (Just f))) + +let aArch64_barrier_functions = + [ ("DataMemoryBarrier_Reads", Barrier_DMB_LD); + ("DataMemoryBarrier_Writes", Barrier_DMB_ST); + ("DataMemoryBarrier_All", Barrier_DMB); + ("DataSynchronizationBarrier_Reads", Barrier_DSB_LD); + ("DataSynchronizationBarrier_Writes", Barrier_DSB_ST); + ("DataSynchronizationBarrier_All", Barrier_DSB); + ("InstructionSynchronizationBarrier", Barrier_ISB); + + ("TMCommitEffect", Barrier_TM_COMMIT); + ] diff --git a/arm/armV8_extras_embed.lem b/arm/armV8_extras_embed.lem new file mode 100644 index 00000000..86570fc4 --- /dev/null +++ b/arm/armV8_extras_embed.lem @@ -0,0 +1,59 @@ +open import Pervasives +open import Sail_impl_base +open import Sail_values +open import Prompt + +val rMem_NORMAL : (vector bitU * integer) -> M (vector bitU) +val rMem_STREAM : (vector bitU * integer) -> M (vector bitU) +val rMem_ORDERED : (vector bitU * integer) -> M (vector bitU) +val rMem_ATOMICL : (vector bitU * integer) -> M (vector bitU) +val rMem_ATOMIC_ORDERED : (vector bitU * integer) -> M (vector bitU) + +let rMem_NORMAL (addr,size) = read_mem false Read_plain addr size +let rMem_STREAM (addr,size) = read_mem false Read_stream addr size +let rMem_ORDERED (addr,size) = read_mem false Read_acquire addr size +let rMem_ATOMIC (addr,size) = read_mem false Read_exclusive addr size +let rMem_ATOMIC_ORDERED (addr,size) = read_mem false Read_exclusive_acquire addr size + +val wMem_Addr_NORMAL : (vector bitU * integer) -> M unit +val wMem_Addr_ORDERED : (vector bitU * integer) -> M unit +val wMem_Addr_ATOMIC : (vector bitU * integer) -> M unit +val wMem_Addr_ATOMIC_ORDERED : (vector bitU * integer) -> M unit + +let wMem_Addr_NORMAL (addr,size) = write_mem_ea Write_plain addr size +let wMem_Addr_ORDERED (addr,size) = write_mem_ea Write_release addr size +let wMem_Addr_ATOMIC (addr,size) = write_mem_ea Write_exclusive addr size +let wMem_Addr_ATOMIC_ORDERED (addr,size) = write_mem_ea Write_exclusive_release addr size + + +val wMem_Val_NORMAL : (integer * vector bitU) -> M unit +val wMem_Val_ATOMIC : (integer * vector bitU) -> M bitU + +let wMem_Val_NORMAL (_,v) = write_mem_val v >>= fun _ -> return () +(* in ARM the status returned is inversed *) +let wMem_Val_ATOMIC (_,v) = write_mem_val v >>= fun b -> return (if b then B0 else B1) + +let speculate_exclusive_success () = excl_result () >>= fun b -> return (if b then B1 else B0) + +val DataMemoryBarrier_Reads : unit -> M unit +val DataMemoryBarrier_Writes : unit -> M unit +val DataMemoryBarrier_All : unit -> M unit +val DataSynchronizationBarrier_Reads : unit -> M unit +val DataSynchronizationBarrier_Writes : unit -> M unit +val DataSynchronizationBarrier_All : unit -> M unit +val InstructionSynchronizationBarrier : unit -> M unit + +let DataMemoryBarrier_Reads () = barrier Barrier_DMB_LD +let DataMemoryBarrier_Writes () = barrier Barrier_DMB_ST +let DataMemoryBarrier_All () = barrier Barrier_DMB +let DataSynchronizationBarrier_Reads () = barrier Barrier_DSB_LD +let DataSynchronizationBarrier_Writes () = barrier Barrier_DSB_ST +let DataSynchronizationBarrier_All () = barrier Barrier_DSB +let InstructionSynchronizationBarrier () = barrier Barrier_ISB + +val TMCommitEffect : unit -> M unit +let TMCommitEffect () = barrier Barrier_TM_COMMIT + +let duplicate_bits (Vector bits start direction,len) = + let bits' = repeat bits len in + Vector bits' start direction diff --git a/arm/armV8_extras_embed_sequential.lem b/arm/armV8_extras_embed_sequential.lem new file mode 100644 index 00000000..d2bb8330 --- /dev/null +++ b/arm/armV8_extras_embed_sequential.lem @@ -0,0 +1,59 @@ +open import Pervasives +open import Sail_impl_base +open import Sail_values +open import State + +val rMem_NORMAL : (vector bitU * integer) -> M (vector bitU) +val rMem_STREAM : (vector bitU * integer) -> M (vector bitU) +val rMem_ORDERED : (vector bitU * integer) -> M (vector bitU) +val rMem_ATOMICL : (vector bitU * integer) -> M (vector bitU) +val rMem_ATOMIC_ORDERED : (vector bitU * integer) -> M (vector bitU) + +let rMem_NORMAL (addr,size) = read_mem false Read_plain addr size +let rMem_STREAM (addr,size) = read_mem false Read_stream addr size +let rMem_ORDERED (addr,size) = read_mem false Read_acquire addr size +let rMem_ATOMIC (addr,size) = read_mem false Read_exclusive addr size +let rMem_ATOMIC_ORDERED (addr,size) = read_mem false Read_exclusive_acquire addr size + +val wMem_Addr_NORMAL : (vector bitU * integer) -> M unit +val wMem_Addr_ORDERED : (vector bitU * integer) -> M unit +val wMem_Addr_ATOMIC : (vector bitU * integer) -> M unit +val wMem_Addr_ATOMIC_ORDERED : (vector bitU * integer) -> M unit + +let wMem_Addr_NORMAL (addr,size) = write_mem_ea Write_plain addr size +let wMem_Addr_ORDERED (addr,size) = write_mem_ea Write_release addr size +let wMem_Addr_ATOMIC (addr,size) = write_mem_ea Write_exclusive addr size +let wMem_Addr_ATOMIC_ORDERED (addr,size) = write_mem_ea Write_exclusive_release addr size + + +val wMem_Val_NORMAL : (integer * vector bitU) -> M unit +val wMem_Val_ATOMIC : (integer * vector bitU) -> M bitU + +let wMem_Val_NORMAL (_,v) = write_mem_val v >>= fun _ -> return () +(* in ARM the status returned is inversed *) +let wMem_Val_ATOMIC (_,v) = write_mem_val v >>= fun b -> return (if b then B0 else B1) + +let speculate_exclusive_success () = excl_result () >>= fun b -> return (if b then B1 else B0) + +val DataMemoryBarrier_Reads : unit -> M unit +val DataMemoryBarrier_Writes : unit -> M unit +val DataMemoryBarrier_All : unit -> M unit +val DataSynchronizationBarrier_Reads : unit -> M unit +val DataSynchronizationBarrier_Writes : unit -> M unit +val DataSynchronizationBarrier_All : unit -> M unit +val InstructionSynchronizationBarrier : unit -> M unit + +let DataMemoryBarrier_Reads () = barrier Barrier_DMB_LD +let DataMemoryBarrier_Writes () = barrier Barrier_DMB_ST +let DataMemoryBarrier_All () = barrier Barrier_DMB +let DataSynchronizationBarrier_Reads () = barrier Barrier_DSB_LD +let DataSynchronizationBarrier_Writes () = barrier Barrier_DSB_ST +let DataSynchronizationBarrier_All () = barrier Barrier_DSB +let InstructionSynchronizationBarrier () = barrier Barrier_ISB + +val TMCommitEffect : unit -> M unit +let TMCommitEffect () = barrier Barrier_TM_COMMIT + +let duplicate_bits (Vector bits start direction,len) = + let bits' = repeat bits len in + Vector bits' start direction diff --git a/arm/armV8_lib.h.sail b/arm/armV8_lib.h.sail index 849472e1..d52cc5d5 100644 --- a/arm/armV8_lib.h.sail +++ b/arm/armV8_lib.h.sail @@ -187,9 +187,8 @@ typedef CountOp = enumerate {CountOp_CLZ; CountOp_CLS; CountOp_CNT} typedef ExtendType = - (* the oreder is important for decoding *) - enumerate { ExtendType_UXTB; ExtendType_UXTH; ExtendType_UXTW; ExtendType_UXTX; - ExtendType_SXTB; ExtendType_SXTH; ExtendType_SXTW; ExtendType_SXTX } + enumerate { ExtendType_SXTB; ExtendType_SXTH; ExtendType_SXTW; ExtendType_SXTX; + ExtendType_UXTB; ExtendType_UXTH; ExtendType_UXTW; ExtendType_UXTX } typedef RevOp = enumerate {RevOp_RBIT; RevOp_REV16; RevOp_REV32; RevOp_REV64} diff --git a/arm/gen/ast.hgen b/arm/gen/ast.hgen new file mode 100644 index 00000000..60f130d7 --- /dev/null +++ b/arm/gen/ast.hgen @@ -0,0 +1,44 @@ + | `AArch64TMStart of inst_reg (* t *) + | `AArch64TMCommit + | `AArch64TMAbort of boolean*bit5 (* retry,reason *) + | `AArch64TMTest + + | `AArch64ImplementationDefinedTestBeginEnd of boolean (* isEnd *) + | `AArch64ImplementationDefinedStopFetching + | `AArch64ImplementationDefinedThreadStart + | `AArch64AddSubCarry of inst_reg*inst_reg*inst_reg*reg_size*boolean*boolean (* d,n,m,datasize,sub_op,setflags *) + | `AArch64AddSubExtendRegister of inst_reg*inst_reg*inst_reg*reg_size*boolean*boolean*extendType*range0_7 (* d,n,m,datasize,sub_op,setflags,extend_type,shift *) + | `AArch64AddSubShiftedRegister of inst_reg*inst_reg*inst_reg*reg_size*boolean*boolean*shiftType*range0_63 (* d,n,m,datasize,sub_op,setflags,shift_type,shift_amount *) + | `AArch64AddSubImmediate of inst_reg*inst_reg*reg_size*boolean*boolean*reg_size_bits (* d,n,datasize,sub_op,setflags,imm *) + | `AArch64Address of inst_reg*boolean*bit64 (* d,page,imm *) + | `AArch64LogicalImmediate of inst_reg*inst_reg*reg_size*boolean*logicalOp*reg_size_bits (* d,n,datasize,setflags,op,imm *) + | `AArch64LogicalShiftedRegister of inst_reg*inst_reg*inst_reg*reg_size*boolean*logicalOp*shiftType*range0_63*boolean (* d,n,m,datasize,setflags,op,shift_type,shift_amount,invert *) + | `AArch64Shift of inst_reg*inst_reg*inst_reg*reg_size*shiftType (* d,n,m,datasize,shift_type *) + | `AArch64BranchConditional of bit64*bit4 (* offset,condition *) + | `AArch64BranchImmediate of branchType*bit64 (* branch_type,offset *) + | `AArch64BitfieldMove of inst_reg*inst_reg*reg_size*boolean*boolean*uinteger*uinteger*reg_size_bits*reg_size_bits (* d,n,datasize,inzero,extend,R,S,wmask,tmask *) + | `AArch64BranchRegister of inst_reg*branchType (* n,branch_type *) + | `AArch64CompareAndBranch of inst_reg*reg_size*boolean*bit64 (* t,datasize,iszero,offset *) + | `AArch64ConditionalCompareImmediate of inst_reg*reg_size*boolean*bit4*bit4*reg_size_bits (* n,datasize,sub_op,condition,flags,imm *) + | `AArch64ConditionalCompareRegister of inst_reg*inst_reg*reg_size*boolean*bit4*bit4 (* n,m,datasize,sub_op,condition,flags *) + | `AArch64ClearExclusiveMonitor of uinteger (* imm *) + | `AArch64CountLeading of inst_reg*inst_reg*reg_size*countOp (* d,n,datasize,opcode *) + | `AArch64CRC of inst_reg*inst_reg*inst_reg*data_size*boolean (* d,n,m,size,crc32c *) + | `AArch64ConditionalSelect of inst_reg*inst_reg*inst_reg*reg_size*bit4*boolean*boolean (* d,n,m,datasize,condition,else_inv,else_inc *) + | `AArch64Barrier of memBarrierOp*mBReqDomain*mBReqTypes (* op,domain,types *) + | `AArch64ExtractRegister of inst_reg*inst_reg*inst_reg*reg_size*uinteger (* d,n,m,datasize,lsb *) + | `AArch64Hint of systemHintOp (* op *) + | `AArch64LoadStoreAcqExc of inst_reg*inst_reg*inst_reg*inst_reg*accType*boolean*boolean*memOp*uinteger*reg_size*data_size (* n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,datasize *) + | `AArch64LoadStorePair of boolean*boolean*inst_reg*inst_reg*inst_reg*accType*memOp*boolean*data_size*bit64 (* wback,postindex,n,t,t2,acctype,memop,signed,datasize,offset *) + | `AArch64LoadImmediate of inst_reg*inst_reg*accType*memOp*boolean*boolean*boolean*bit64*reg_size*data_size (* n,t,acctype,memop,signed,wback,postindex,offset,regsize,datasize *) + | `AArch64LoadLiteral of inst_reg*memOp*boolean*uinteger*bit64*data_size (* t,memop,signed,size,offset,datasize *) + | `AArch64LoadRegister of inst_reg*inst_reg*inst_reg*accType*memOp*boolean*boolean*boolean*extendType*uinteger*reg_size*data_size (* n,t,m,acctype,memop,signed,wback,postindex,extend_type,shift,regsize,datasize *) + | `AArch64MultiplyAddSub of inst_reg*inst_reg*inst_reg*inst_reg*reg_size*data_size*boolean (* d,n,m,a,destsize,datasize,sub_op *) + | `AArch64MoveWide of inst_reg*reg_size*bit16*uinteger*moveWideOp (* d,datasize,imm,pos,opcode *) + | `AArch64Reverse of inst_reg*inst_reg*reg_size*revOp (* d,n,datasize,op *) + | `AArch64Division of inst_reg*inst_reg*inst_reg*reg_size*boolean (* d,n,m,datasize,unsigned *) + | `AArch64MultiplyAddSubLong of inst_reg*inst_reg*inst_reg*inst_reg*reg_size*data_size*boolean*boolean (* d,n,m,a,destsize,datasize,sub_op,unsigned *) + | `AArch64MultiplyHigh of inst_reg*inst_reg*inst_reg*inst_reg*reg_size*data_size*boolean (* d,n,m,a,destsize,datasize,unsigned *) + | `AArch64TestBitAndBranch of inst_reg*reg_size*uinteger*bit*bit64 (* t,datasize,bit_pos,bit_val,offset *) + | `AArch64MoveSystemRegister of inst_reg*uinteger*uinteger*uinteger*uinteger*uinteger*boolean (* t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read *) + | `AArch64MoveSystemImmediate of bit4*pSTATEField (* operand,field *) diff --git a/arm/gen/fold.hgen b/arm/gen/fold.hgen new file mode 100644 index 00000000..4062d8e6 --- /dev/null +++ b/arm/gen/fold.hgen @@ -0,0 +1,44 @@ +| `AArch64TMStart t -> fold_reg t (y_reg, y_sreg) +| `AArch64TMCommit -> (y_reg, y_sreg) +| `AArch64TMAbort (retry,reason) -> (y_reg, y_sreg) +| `AArch64TMTest -> (y_reg, y_sreg) + +| `AArch64ImplementationDefinedStopFetching -> (y_reg, y_sreg) +| `AArch64ImplementationDefinedThreadStart -> (y_reg, y_sreg) +| `AArch64ImplementationDefinedTestBeginEnd (isEnd) -> (y_reg, y_sreg) +| `AArch64AddSubCarry (d,n,m,datasize,sub_op,setflags) -> fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg))) +| `AArch64AddSubExtendRegister (d,n,m,datasize,sub_op,setflags,extend_type,shift) -> fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg))) +| `AArch64AddSubShiftedRegister (d,n,m,datasize,sub_op,setflags,shift_type,shift_amount) -> fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg))) +| `AArch64AddSubImmediate (d,n,datasize,sub_op,setflags,imm) -> fold_reg n (fold_reg d (y_reg, y_sreg)) +| `AArch64Address (d,page,imm) -> fold_reg d (y_reg, y_sreg) +| `AArch64LogicalImmediate (d,n,datasize,setflags,op,imm) -> fold_reg n (fold_reg d (y_reg, y_sreg)) +| `AArch64LogicalShiftedRegister (d,n,m,datasize,setflags,op,shift_type,shift_amount,invert) -> fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg))) +| `AArch64Shift (d,n,m,datasize,shift_type) -> fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg))) +| `AArch64BranchConditional (offset,condition) -> (y_reg, y_sreg) +| `AArch64BranchImmediate (branch_type,offset) -> (y_reg, y_sreg) +| `AArch64BitfieldMove (d,n,datasize,inzero,extend,_R,_S,wmask,tmask) -> fold_reg n (fold_reg d (y_reg, y_sreg)) +| `AArch64BranchRegister (n,branch_type) -> fold_reg n (y_reg, y_sreg) +| `AArch64CompareAndBranch (t,datasize,iszero,offset) -> fold_reg t (y_reg, y_sreg) +| `AArch64ConditionalCompareImmediate (n,datasize,sub_op,condition,flags,imm) -> fold_reg n (y_reg, y_sreg) +| `AArch64ConditionalCompareRegister (n,m,datasize,sub_op,condition,flags) -> fold_reg m (fold_reg n (y_reg, y_sreg)) +| `AArch64ClearExclusiveMonitor (imm) -> (y_reg, y_sreg) +| `AArch64CountLeading (d,n,datasize,opcode) -> fold_reg n (fold_reg d (y_reg, y_sreg)) +| `AArch64CRC (d,n,m,size,crc32c) -> fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg))) +| `AArch64ConditionalSelect (d,n,m,datasize,condition,else_inv,else_inc) -> fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg))) +| `AArch64Barrier (op,domain,types) -> (y_reg, y_sreg) +| `AArch64ExtractRegister (d,n,m,datasize,lsb) -> fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg))) +| `AArch64Hint (op) -> (y_reg, y_sreg) +| `AArch64LoadStoreAcqExc (n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,datasize) -> fold_reg s (fold_reg t2 (fold_reg t (fold_reg n (y_reg, y_sreg)))) +| `AArch64LoadStorePair (wback,postindex,n,t,t2,acctype,memop,signed,datasize,offset) -> fold_reg t2 (fold_reg t (fold_reg n (y_reg, y_sreg))) +| `AArch64LoadImmediate (n,t,acctype,memop,signed,wback,postindex,offset,regsize,datasize) -> fold_reg t (fold_reg n (y_reg, y_sreg)) +| `AArch64LoadLiteral (t,memop,signed,size,offset,datasize) -> fold_reg t (y_reg, y_sreg) +| `AArch64LoadRegister (n,t,m,acctype,memop,signed,wback,postindex,extend_type,shift,regsize,datasize) -> fold_reg m (fold_reg t (fold_reg n (y_reg, y_sreg))) +| `AArch64MultiplyAddSub (d,n,m,a,destsize,datasize,sub_op) -> fold_reg a (fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg)))) +| `AArch64MoveWide (d,datasize,imm,pos,opcode) -> fold_reg d (y_reg, y_sreg) +| `AArch64Reverse (d,n,datasize,op) -> fold_reg n (fold_reg d (y_reg, y_sreg)) +| `AArch64Division (d,n,m,datasize,unsigned) -> fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg))) +| `AArch64MultiplyAddSubLong (d,n,m,a,destsize,datasize,sub_op,unsigned) -> fold_reg a (fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg)))) +| `AArch64MultiplyHigh (d,n,m,a,destsize,datasize,unsigned) -> fold_reg a (fold_reg m (fold_reg n (fold_reg d (y_reg, y_sreg)))) +| `AArch64TestBitAndBranch (t,datasize,bit_pos,bit_val,offset) -> fold_reg t (y_reg, y_sreg) +| `AArch64MoveSystemRegister (t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read) -> fold_reg t (y_reg, y_sreg) +| `AArch64MoveSystemImmediate (operand,field) -> (y_reg, y_sreg) diff --git a/arm/gen/herdtools_ast_to_shallow_ast.hgen b/arm/gen/herdtools_ast_to_shallow_ast.hgen new file mode 100644 index 00000000..5a19e483 --- /dev/null +++ b/arm/gen/herdtools_ast_to_shallow_ast.hgen @@ -0,0 +1,335 @@ +| `AArch64TMStart t -> TMStart (translate_reg "t" t) + +| `AArch64TMCommit -> TMCommit + +| `AArch64TMAbort (retry,reason) -> + TMAbort + (translate_boolean "retry" retry, + translate_bit5 "reason" reason) + +| `AArch64TMTest -> TMTest + +| `AArch64ImplementationDefinedStopFetching -> + ImplementationDefinedStopFetching + +| `AArch64ImplementationDefinedThreadStart -> + ImplementationDefinedThreadStart + +| `AArch64ImplementationDefinedTestBeginEnd(isEnd) -> + ImplementationDefinedTestBeginEnd + (translate_boolean "isEnd" isEnd) + +| `AArch64AddSubCarry(d,n,m,datasize,sub_op,setflags) -> + AddSubCarry + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg_size "datasize" datasize, + translate_boolean "sub_op" sub_op, + translate_boolean "setflags" setflags) + +| `AArch64AddSubExtendRegister (d,n,m,datasize,sub_op,setflags,extend_type,shift) -> + AddSubExtendRegister + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg_size "datasize" datasize, + translate_boolean "sub_op" sub_op, + translate_boolean "setflags" setflags, + translate_extendType "extend_type" extend_type, + translate_range0_7 "shift" shift) + +| `AArch64AddSubShiftedRegister (d,n,m,datasize,sub_op,setflags,shift_type,shift_amount) -> + AddSubShiftedRegister + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg_size "datasize" datasize, + translate_boolean "sub_op" sub_op, + translate_boolean "setflags" setflags, + translate_shiftType "shift_type" shift_type, + translate_range0_63 "shift_amount" shift_amount) + +| `AArch64AddSubImmediate (d,n,datasize,sub_op,setflags,imm) -> + AddSubImmediate + (translate_reg "d" d, + translate_reg "n" n, + translate_reg_size "datasize" datasize, + translate_boolean "sub_op" sub_op, + translate_boolean "setflags" setflags, + translate_reg_size_bits "imm" imm) + +| `AArch64Address (d,page,imm) -> + Address0 + (translate_reg "d" d, + translate_boolean "page" page, + translate_bit64 "imm" imm) + +| `AArch64LogicalImmediate (d,n,datasize,setflags,op,imm) -> + LogicalImmediate + (translate_reg "d" d, + translate_reg "n" n, + translate_reg_size "datasize" datasize, + translate_boolean "setflags" setflags, + translate_logicalOp "op" op, + translate_reg_size_bits "imm" imm) + +| `AArch64LogicalShiftedRegister (d,n,m,datasize,setflags,op,shift_type,shift_amount,invert) -> + LogicalShiftedRegister + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg_size "datasize" datasize, + translate_boolean "setflags" setflags, + translate_logicalOp "op" op, + translate_shiftType "shift_type" shift_type, + translate_range0_63 "shift_amount" shift_amount, + translate_boolean "invert" invert) + +| `AArch64Shift (d,n,m,datasize,shift_type) -> + Shift + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg_size "datasize" datasize, + translate_shiftType "shift_type" shift_type) + +| `AArch64BranchConditional (offset,condition) -> + BranchConditional + (translate_bit64 "offset" offset, + translate_bit4 "condition" condition) + +| `AArch64BranchImmediate (branch_type,offset) -> + BranchImmediate + (translate_branchType "branch_type" branch_type, + translate_bit64 "offset" offset) + +| `AArch64BitfieldMove (d,n,datasize,inzero,extend,_R,_S,wmask,tmask) -> + BitfieldMove + (translate_reg "d" d, + translate_reg "n" n, + translate_reg_size "datasize" datasize, + translate_boolean "inzero" inzero, + translate_boolean "extend" extend, + translate_uinteger "_R" _R, + translate_uinteger "_S" _S, + translate_reg_size_bits "wmask" wmask, + translate_reg_size_bits "tmask" tmask) + +| `AArch64BranchRegister (n,branch_type) -> + BranchRegister + (translate_reg "n" n, + translate_branchType "branch_type" branch_type) + +| `AArch64CompareAndBranch (t,datasize,iszero,offset) -> + CompareAndBranch + (translate_reg "t" t, + translate_reg_size "datasize" datasize, + translate_boolean "iszero" iszero, + translate_bit64 "offset" offset) + +| `AArch64ConditionalCompareImmediate (n,datasize,sub_op,condition,flags,imm) -> + ConditionalCompareImmediate + (translate_reg "n" n, + translate_reg_size "datasize" datasize, + translate_boolean "sub_op" sub_op, + translate_bit4 "condition" condition, + translate_bit4 "flags" flags, + translate_reg_size_bits "imm" imm) + +| `AArch64ConditionalCompareRegister (n,m,datasize,sub_op,condition,flags) -> + ConditionalCompareRegister + (translate_reg "n" n, + translate_reg "m" m, + translate_reg_size "datasize" datasize, + translate_boolean "sub_op" sub_op, + translate_bit4 "condition" condition, + translate_bit4 "flags" flags) + +| `AArch64ClearExclusiveMonitor (imm) -> + ClearExclusiveMonitor + (translate_uinteger "imm" imm) + +| `AArch64CountLeading (d,n,datasize,opcode) -> + CountLeading + (translate_reg "d" d, + translate_reg "n" n, + translate_reg_size "datasize" datasize, + translate_countOp "opcode" opcode) + +| `AArch64CRC (d,n,m,size,crc32c) -> + CRC + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_data_size "size" size, + translate_boolean "crc32c" crc32c) + +| `AArch64ConditionalSelect (d,n,m,datasize,condition,else_inv,else_inc) -> + ConditionalSelect + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg_size "datasize" datasize, + translate_bit4 "condition" condition, + translate_boolean "else_inv" else_inv, + translate_boolean "else_inc" else_inc) + +| `AArch64Barrier (op,domain,types) -> + Barrier2 + (translate_memBarrierOp "op" op, + translate_mBReqDomain "domain" domain, + translate_mBReqTypes "types" types) + +| `AArch64ExtractRegister (d,n,m,datasize,lsb) -> + ExtractRegister + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg_size "datasize" datasize, + translate_uinteger "lsb" lsb) + +| `AArch64Hint (op) -> + Hint + (translate_systemHintOp "op" op) + +| `AArch64LoadStoreAcqExc (n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,datasize) -> + LoadStoreAcqExc + (translate_reg "n" n, + translate_reg "t" t, + translate_reg "t2" t2, + translate_reg "s" s, + translate_accType "acctype" acctype, + translate_boolean "excl" excl, + translate_boolean "pair" pair, + translate_memOp "memop" memop, + translate_uinteger "elsize" elsize, + translate_reg_size "regsize" regsize, + translate_data_size "datasize" datasize) + +| `AArch64LoadStorePair (wback,postindex,n,t,t2,acctype,memop,signed,datasize,offset) -> + LoadStorePair + (translate_boolean "wback" wback, + translate_boolean "postindex" postindex, + translate_reg "n" n, + translate_reg "t" t, + translate_reg "t2" t2, + translate_accType "acctype" acctype, + translate_memOp "memop" memop, + translate_boolean "signed" signed, + translate_data_size "datasize" datasize, + translate_bit64 "offset" offset) + +| `AArch64LoadImmediate (n,t,acctype,memop,signed,wback,postindex,offset,regsize,datasize) -> + LoadImmediate + (translate_reg "n" n, + translate_reg "t" t, + translate_accType "acctype" acctype, + translate_memOp "memop" memop, + translate_boolean "signed" signed, + translate_boolean "wback" wback, + translate_boolean "postindex" postindex, + translate_bit64 "offset" offset, + translate_reg_size "regsize" regsize, + translate_data_size "datasize" datasize) + +| `AArch64LoadLiteral (t,memop,signed,size,offset,datasize) -> + LoadLiteral + (translate_reg "t" t, + translate_memOp "memop" memop, + translate_boolean "signed" signed, + translate_uinteger "size" size, + translate_bit64 "offset" offset, + translate_data_size "datasize" datasize) + +| `AArch64LoadRegister (n,t,m,acctype,memop,signed,wback,postindex,extend_type,shift,regsize,datasize) -> + LoadRegister + (translate_reg "n" n, + translate_reg "t" t, + translate_reg "m" m, + translate_accType "acctype" acctype, + translate_memOp "memop" memop, + translate_boolean "signed" signed, + translate_boolean "wback" wback, + translate_boolean "postindex" postindex, + translate_extendType "extend_type" extend_type, + translate_uinteger "shift" shift, + translate_reg_size "regsize" regsize, + translate_data_size "datasize" datasize) + +| `AArch64MultiplyAddSub (d,n,m,a,destsize,datasize,sub_op) -> + MultiplyAddSub + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg "a" a, + translate_reg_size "destsize" destsize, + translate_data_size "datasize" datasize, + translate_boolean "sub_op" sub_op) + +| `AArch64MoveWide (d,datasize,imm,pos,opcode) -> + MoveWide + (translate_reg "d" d, + translate_reg_size "datasize" datasize, + translate_bit16 "imm" imm, + translate_uinteger "pos" pos, + translate_moveWideOp "opcode" opcode) + +| `AArch64Reverse (d,n,datasize,op) -> + Reverse + (translate_reg "d" d, + translate_reg "n" n, + translate_reg_size "datasize" datasize, + translate_revOp "op" op) + +| `AArch64Division (d,n,m,datasize,unsigned) -> + Division + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg_size "datasize" datasize, + translate_boolean "unsigned" unsigned) + +| `AArch64MultiplyAddSubLong (d,n,m,a,destsize,datasize,sub_op,unsigned) -> + MultiplyAddSubLong + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg "a" a, + translate_reg_size "destsize" destsize, + translate_data_size "datasize" datasize, + translate_boolean "sub_op" sub_op, + translate_boolean "unsigned" unsigned) + +| `AArch64MultiplyHigh (d,n,m,a,destsize,datasize,unsigned) -> + MultiplyHigh + (translate_reg "d" d, + translate_reg "n" n, + translate_reg "m" m, + translate_reg "a" a, + translate_reg_size "destsize" destsize, + translate_data_size "datasize" datasize, + translate_boolean "unsigned" unsigned) + +| `AArch64TestBitAndBranch (t,datasize,bit_pos,bit_val,offset) -> + TestBitAndBranch + (translate_reg "t" t, + translate_reg_size "datasize" datasize, + translate_uinteger "bit_pos" bit_pos, + translate_bit "bit_val" bit_val, + translate_bit64 "offset" offset) + +| `AArch64MoveSystemRegister (t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read) -> + MoveSystemRegister + (translate_reg "t" t, + translate_uinteger "sys_op0" sys_op0, + translate_uinteger "sys_op1" sys_op1, + translate_uinteger "sys_op2" sys_op2, + translate_uinteger "sys_crn" sys_crn, + translate_uinteger "sys_crm" sys_crm, + translate_boolean "read" read) + +| `AArch64MoveSystemImmediate (operand,field) -> + MoveSystemImmediate + (translate_bit4 "operand" operand, + translate_pSTATEField "field" field) diff --git a/arm/gen/herdtools_types_to_shallow_types.hgen b/arm/gen/herdtools_types_to_shallow_types.hgen new file mode 100644 index 00000000..e14a37e3 --- /dev/null +++ b/arm/gen/herdtools_types_to_shallow_types.hgen @@ -0,0 +1,153 @@ +open Sail_values + +let is_inc = false + +let translate_big_int bits (name : string) value = + (name, Range0 (Some bits), IInt.bit_list_of_integer bits value) + +let translate_big_bit bits (name:string) value = + Sail_values.to_vec0 is_inc (Nat_big_num.of_int bits,value) + +let translate_int (size : int) (name:string) value = (Nat_big_num.of_int value) + +let translate_bits bits (name:string) value = + Sail_values.to_vec0 is_inc (Nat_big_num.of_int bits,Nat_big_num.of_int value) + +let translate_bool _ = function + | true -> B1 + | false -> B0 + +let translate_reg_size name value = + match value with + | Set32 -> (Nat_big_num.of_int 32) + | Set64 -> (Nat_big_num.of_int 64) + +let translate_reg name value = + (Nat_big_num.of_int (inst_reg_to_int value)) + + +let translate_reg_size_bits name value = + match value with + | R32Bits value -> translate_bits 32 name value + | R64Bits value -> translate_big_bit 64 name value + +let translate_data_size name value = + match value with + | DataSize8 -> (Nat_big_num.of_int 8) + | DataSize16 -> (Nat_big_num.of_int 16) + | DataSize32 -> (Nat_big_num.of_int 32) + | DataSize64 -> (Nat_big_num.of_int 64) + +let translate_reg_index = translate_int 5 + +let translate_boolean = translate_bool + +let translate_range0_7 = translate_int 3 + +let translate_range0_63 = translate_int 6 + +let translate_bit64 = translate_big_bit 64 + +let translate_bit4 = translate_bits 4 +let translate_bit5 = translate_bits 5 +let translate_bit16 = translate_bits 16 + +let translate_bit = translate_bool + +let translate_range8_64 = translate_int 7 + +let translate_uinteger = translate_int 63 + +let translate_extendType _ = function + | ExtendType_UXTB -> ArmV8_embed_types.ExtendType_UXTB + | ExtendType_UXTH -> ArmV8_embed_types.ExtendType_UXTH + | ExtendType_UXTW -> ArmV8_embed_types.ExtendType_UXTW + | ExtendType_UXTX -> ArmV8_embed_types.ExtendType_UXTX + | ExtendType_SXTB -> ArmV8_embed_types.ExtendType_SXTB + | ExtendType_SXTH -> ArmV8_embed_types.ExtendType_SXTH + | ExtendType_SXTW -> ArmV8_embed_types.ExtendType_SXTW + | ExtendType_SXTX -> ArmV8_embed_types.ExtendType_SXTX + +let translate_shiftType _ = function + | ShiftType_LSL -> ArmV8_embed_types.ShiftType_LSL + | ShiftType_LSR -> ArmV8_embed_types.ShiftType_LSR + | ShiftType_ASR -> ArmV8_embed_types.ShiftType_ASR + | ShiftType_ROR -> ArmV8_embed_types.ShiftType_ROR + +let translate_logicalOp _ = function + | LogicalOp_AND -> ArmV8_embed_types.LogicalOp_AND + | LogicalOp_EOR -> ArmV8_embed_types.LogicalOp_EOR + | LogicalOp_ORR -> ArmV8_embed_types.LogicalOp_ORR + +let translate_branchType _ = function + | BranchType_CALL -> ArmV8_embed_types.BranchType_CALL + | BranchType_ERET -> ArmV8_embed_types.BranchType_ERET + | BranchType_DBGEXIT -> ArmV8_embed_types.BranchType_DBGEXIT + | BranchType_RET -> ArmV8_embed_types.BranchType_RET + | BranchType_JMP -> ArmV8_embed_types.BranchType_JMP + | BranchType_EXCEPTION -> ArmV8_embed_types.BranchType_EXCEPTION + | BranchType_UNKNOWN -> ArmV8_embed_types.BranchType_UNKNOWN + +let translate_countOp _ = function + | CountOp_CLZ -> ArmV8_embed_types.CountOp_CLZ + | CountOp_CLS -> ArmV8_embed_types.CountOp_CLS + | CountOp_CNT -> ArmV8_embed_types.CountOp_CNT + +let translate_memBarrierOp _ = function + | MemBarrierOp_DSB -> ArmV8_embed_types.MemBarrierOp_DSB + | MemBarrierOp_DMB -> ArmV8_embed_types.MemBarrierOp_DMB + | MemBarrierOp_ISB -> ArmV8_embed_types.MemBarrierOp_ISB + +let translate_mBReqDomain _ = function + | MBReqDomain_Nonshareable -> ArmV8_embed_types.MBReqDomain_Nonshareable + | MBReqDomain_InnerShareable -> ArmV8_embed_types.MBReqDomain_InnerShareable + | MBReqDomain_OuterShareable -> ArmV8_embed_types.MBReqDomain_OuterShareable + | MBReqDomain_FullSystem -> ArmV8_embed_types.MBReqDomain_FullSystem + +let translate_mBReqTypes _ = function + | MBReqTypes_Reads -> ArmV8_embed_types.MBReqTypes_Reads + | MBReqTypes_Writes -> ArmV8_embed_types.MBReqTypes_Writes + | MBReqTypes_All -> ArmV8_embed_types.MBReqTypes_All + +let translate_systemHintOp _ = function + | SystemHintOp_NOP -> ArmV8_embed_types.SystemHintOp_NOP + | SystemHintOp_YIELD -> ArmV8_embed_types.SystemHintOp_YIELD + | SystemHintOp_WFE -> ArmV8_embed_types.SystemHintOp_WFE + | SystemHintOp_WFI -> ArmV8_embed_types.SystemHintOp_WFI + | SystemHintOp_SEV -> ArmV8_embed_types.SystemHintOp_SEV + | SystemHintOp_SEVL -> ArmV8_embed_types.SystemHintOp_SEVL + +let translate_accType _ = function + | AccType_NORMAL -> ArmV8_embed_types.AccType_NORMAL + | AccType_VEC -> ArmV8_embed_types.AccType_VEC + | AccType_STREAM -> ArmV8_embed_types.AccType_STREAM + | AccType_VECSTREAM -> ArmV8_embed_types.AccType_VECSTREAM + | AccType_ATOMIC -> ArmV8_embed_types.AccType_ATOMIC + | AccType_ORDERED -> ArmV8_embed_types.AccType_ORDERED + | AccType_UNPRIV -> ArmV8_embed_types.AccType_UNPRIV + | AccType_IFETCH -> ArmV8_embed_types.AccType_IFETCH + | AccType_PTW -> ArmV8_embed_types.AccType_PTW + | AccType_DC -> ArmV8_embed_types.AccType_DC + | AccType_IC -> ArmV8_embed_types.AccType_IC + | AccType_AT -> ArmV8_embed_types.AccType_AT + +let translate_memOp _ = function + | MemOp_LOAD -> ArmV8_embed_types.MemOp_LOAD + | MemOp_STORE -> ArmV8_embed_types.MemOp_STORE + | MemOp_PREFETCH -> ArmV8_embed_types.MemOp_PREFETCH + +let translate_moveWideOp _ = function + | MoveWideOp_N -> ArmV8_embed_types.MoveWideOp_N + | MoveWideOp_Z -> ArmV8_embed_types.MoveWideOp_Z + | MoveWideOp_K -> ArmV8_embed_types.MoveWideOp_K + +let translate_revOp _ = function + | RevOp_RBIT -> ArmV8_embed_types.RevOp_RBIT + | RevOp_REV16 -> ArmV8_embed_types.RevOp_REV16 + | RevOp_REV32 -> ArmV8_embed_types.RevOp_REV32 + | RevOp_REV64 -> ArmV8_embed_types.RevOp_REV64 + +let translate_pSTATEField _ = function + | PSTATEField_DAIFSet -> ArmV8_embed_types.PSTATEField_DAIFSet + | PSTATEField_DAIFClr -> ArmV8_embed_types.PSTATEField_DAIFClr + | PSTATEField_SP -> ArmV8_embed_types.PSTATEField_SP diff --git a/arm/gen/lexer.hgen b/arm/gen/lexer.hgen new file mode 100644 index 00000000..6ff24317 --- /dev/null +++ b/arm/gen/lexer.hgen @@ -0,0 +1,309 @@ +(* instructions: *) + + "TSTART" , TSTART {txt="TSTART"} ; + "TCOMMIT", TCOMMIT {txt="TCOMMIT"} ; + "TABORT" , TABORT {txt="TABORT"} ; + "TTEST" , TTEST {txt="TTEST"} ; + + "ADC" , ADCSBC {txt="ADC"; sub_op = false; setflags = false} ; + "SBC" , ADCSBC {txt="SBC"; sub_op = true; setflags = false} ; + "ADCS" , ADCSBC {txt="ADCS"; sub_op = false; setflags = true} ; + "SBCS" , ADCSBC {txt="SBCS"; sub_op = true; setflags = true} ; + + "ADD" , ADDSUB {txt="ADD"; sub_op=false; setflags=false} ; + "SUB" , ADDSUB {txt="SUB"; sub_op=true; setflags=false} ; + "ADDS" , ADDSUB {txt="ADDS"; sub_op=false; setflags=true} ; + "SUBS" , ADDSUB {txt="SUBS"; sub_op=true; setflags=true} ; + + "ADR" , ADR {txt="ADR"; page=false} ; + "ADRP" , ADR {txt="ADRP"; page=true} ; + + "AND" , LOGOP {txt="AND"; op = LogicalOp_AND; setflags = false; invert = false} ; + "ANDS" , LOGOP {txt="ANDS"; op = LogicalOp_AND; setflags = true; invert = false} ; + "EOR" , LOGOP {txt="EOR"; op = LogicalOp_EOR; setflags = false; invert = false} ; + "ORR" , LOGOP {txt="ORR"; op = LogicalOp_ORR; setflags = false; invert = false} ; + "BIC" , LOGOP {txt="BIC"; op = LogicalOp_AND; setflags = false; invert = true} ; + "BICS" , LOGOP {txt="BICS"; op = LogicalOp_AND; setflags = true; invert = true} ; + "EON" , LOGOP {txt="EON"; op = LogicalOp_EOR; setflags = false; invert = true} ; + "ORN" , LOGOP {txt="ORN"; op = LogicalOp_ORR; setflags = false; invert = true} ; + + "ASRV" , SHIFTOP {txt="ASRV"; shift_type=ShiftType_ASR} ; + "LSLV" , SHIFTOP {txt="LSLV"; shift_type=ShiftType_LSL} ; + "LSRV" , SHIFTOP {txt="LSRV"; shift_type=ShiftType_LSR} ; + "RORV" , SHIFTOP {txt="RORV"; shift_type=ShiftType_ROR} ; + + "B.EQ" , BCOND {txt="B.EQ"; condition=0b0000} ; + "B.NE" , BCOND {txt="B.NE"; condition=0b0001} ; + "B.CS" , BCOND {txt="B.CS"; condition=0b0010} ; + "B.HS" , BCOND {txt="B.CS"; condition=0b0010} ; + "B.CC" , BCOND {txt="B.CC"; condition=0b0011} ; + "B.LO" , BCOND {txt="B.CC"; condition=0b0011} ; + "B.MI" , BCOND {txt="B.MI"; condition=0b0100} ; + "B.PL" , BCOND {txt="B.PL"; condition=0b0101} ; + "B.VS" , BCOND {txt="B.VS"; condition=0b0110} ; + "B.VC" , BCOND {txt="B.VC"; condition=0b0111} ; + "B.HI" , BCOND {txt="B.HI"; condition=0b1000} ; + "B.LS" , BCOND {txt="B.LS"; condition=0b1001} ; + "B.GE" , BCOND {txt="B.GE"; condition=0b1010} ; + "B.LT" , BCOND {txt="B.LT"; condition=0b1011} ; + "B.GT" , BCOND {txt="B.GT"; condition=0b1100} ; + "B.LE" , BCOND {txt="B.LE"; condition=0b1101} ; + "B.AL" , BCOND {txt="B.AL"; condition=0b1110} ; + "B.NV" , BCOND {txt="B.NV"; condition=0b1111} ; (* ARM: exists only to provide a valid disassembly + of the 0b1111 encoding, otherwise its + behavior is identical to AL *) + + "B" , B {txt="B"; branch_type=BranchType_JMP} ; + "BL" , B {txt="BL"; branch_type=BranchType_CALL} ; + + "BR" , BR {txt="BR"; branch_type=BranchType_JMP} ; + "BLR" , BR {txt="BLR"; branch_type=BranchType_CALL} ; + + "CBZ" , CBZ {txt="CBZ"; iszero=true} ; + "CBNZ" , CBZ {txt="CBNZ"; iszero=false} ; + + "BFM" , BFM {txt="BFM"; inzero=false; extend=false} ; + "SBFM" , BFM {txt="SBFM"; inzero=true; extend=true} ; + "UBFM" , BFM {txt="UBFM"; inzero=true; extend=false} ; + + "CCMN" , CCM {txt="CCMN"; sub_op=false} ; + "CCMP" , CCM {txt="CCMP"; sub_op=true} ; + + "CMN" , CM {txt="CMN"; sub_op=false} ; + "CMP" , CM {txt="CMP"; sub_op=true} ; + + "CLS" , CL {txt="CLS"; opcode=CountOp_CLS} ; + "CLZ" , CL {txt="CLZ"; opcode=CountOp_CLZ} ; + + "CRC32B" , CRC {txt="CRC32B"; size = DataSize8; crc32c = false} ; + "CRC32H" , CRC {txt="CRC32H"; size = DataSize16; crc32c = false} ; + "CRC32W" , CRC {txt="CRC32W"; size = DataSize32; crc32c = false} ; + "CRC32CB" , CRC {txt="CRC32CB"; size = DataSize8; crc32c = true} ; + "CRC32CH" , CRC {txt="CRC32CH"; size = DataSize16; crc32c = true} ; + "CRC32CW" , CRC {txt="CRC32CW"; size = DataSize32; crc32c = true} ; + + "CRC32X" , CRC32X {txt="CRC32X"; crc32c=false} ; + "CRC32CX" , CRC32X {txt="CRC32CX"; crc32c=true} ; + + "CSEL" , CSEL {txt="CSEL"; else_inv = false; else_inc = false} ; + "CSINC" , CSEL {txt="CSINC"; else_inv = false; else_inc = true} ; + "CSINV" , CSEL {txt="CSINV"; else_inv = true; else_inc = false} ; + "CSNEG" , CSEL {txt="CSNEG"; else_inv = true; else_inc = true} ; + + "CSET" , CSET {txt="CSET"; else_inv = false; else_inc = true} ; + "CSETM" , CSETM {txt="CSETM"; else_inv = true; else_inc = false} ; + + "CINC" , CON {txt="CINC"; else_inv = false; else_inc = true} ; + "CINV" , CON {txt="CINV"; else_inv = true; else_inc = false} ; + "CNEG" , CON {txt="CNEG"; else_inv = true; else_inc = true} ; + + "DMB" , MEMBARR {txt="DMB"; op=MemBarrierOp_DMB} ; + "DSB" , MEMBARR {txt="DSB"; op=MemBarrierOp_DSB} ; + + "LDAR" , LDAXR {txt="LDAR"; acctype=AccType_ORDERED; excl=false; memop=MemOp_LOAD; var32={elsize=32; datasize=DataSize32}; var64=true} ; + "LDARB" , LDAXR {txt="LDARB"; acctype=AccType_ORDERED; excl=false; memop=MemOp_LOAD; var32={elsize=8; datasize=DataSize8}; var64=false} ; + "LDARH" , LDAXR {txt="LDARH"; acctype=AccType_ORDERED; excl=false; memop=MemOp_LOAD; var32={elsize=16; datasize=DataSize16}; var64=false} ; + "LDAXR" , LDAXR {txt="LDAXR"; acctype=AccType_ORDERED; excl=true; memop=MemOp_LOAD; var32={elsize=32; datasize=DataSize32}; var64=true} ; + "LDAXRB" , LDAXR {txt="LDAXRB"; acctype=AccType_ORDERED; excl=true; memop=MemOp_LOAD; var32={elsize=8; datasize=DataSize8}; var64=false} ; + "LDAXRH" , LDAXR {txt="LDAXRH"; acctype=AccType_ORDERED; excl=true; memop=MemOp_LOAD; var32={elsize=16; datasize=DataSize16}; var64=false} ; + "LDXR" , LDAXR {txt="LDXR"; acctype=AccType_ATOMIC; excl=true; memop=MemOp_LOAD; var32={elsize=32; datasize=DataSize32}; var64=true} ; + "LDXRB" , LDAXR {txt="LDXRB"; acctype=AccType_ATOMIC; excl=true; memop=MemOp_LOAD; var32={elsize=8; datasize=DataSize8}; var64=false} ; + "LDXRH" , LDAXR {txt="LDXRH"; acctype=AccType_ATOMIC; excl=true; memop=MemOp_LOAD; var32={elsize=16; datasize=DataSize16}; var64=false} ; + "STLR" , LDAXR {txt="STLR"; acctype=AccType_ORDERED; excl=false; memop=MemOp_STORE; var32={elsize=32; datasize=DataSize32}; var64=true} ; + "STLRB" , LDAXR {txt="STLRB"; acctype=AccType_ORDERED; excl=false; memop=MemOp_STORE; var32={elsize=8; datasize=DataSize8}; var64=false} ; + "STLRH" , LDAXR {txt="STLRH"; acctype=AccType_ORDERED; excl=false; memop=MemOp_STORE; var32={elsize=16; datasize=DataSize16}; var64=false} ; + + "STLXR" , STLXR {txt="STLXR"; acctype=AccType_ORDERED; var32={elsize=32; datasize=DataSize32}; var64=true} ; + "STLXRB" , STLXR {txt="STLXRB"; acctype=AccType_ORDERED; var32={elsize=8; datasize=DataSize8}; var64=false} ; + "STLXRH" , STLXR {txt="STLXRH"; acctype=AccType_ORDERED; var32={elsize=16; datasize=DataSize16}; var64=false} ; + "STXR" , STLXR {txt="STXR"; acctype=AccType_ATOMIC; var32={elsize=32; datasize=DataSize32}; var64=true} ; + "STXRB" , STLXR {txt="STXRB"; acctype=AccType_ATOMIC; var32={elsize=8; datasize=DataSize8}; var64=false} ; + "STXRH" , STLXR {txt="STXRH"; acctype=AccType_ATOMIC; var32={elsize=16; datasize=DataSize16}; var64=false} ; + + + "LDAXP" , LDXP {txt="LDAXP"; acctype=AccType_ORDERED} ; + "LDXP" , LDXP {txt="LDXP"; acctype=AccType_ATOMIC} ; + + "STLXP" , STXP {txt="STLXP"; acctype=AccType_ORDERED} ; + "STXP" , STXP {txt="STXP"; acctype=AccType_ATOMIC} ; + + "LDR" , LDSTR {txt="LDR"; memop=MemOp_LOAD; signed=false; lit32=true; var32=Some {datasize=DataSize32}; var64=Some {datasize=DataSize64}; lit64=Some {datasize=DataSize64; size=8}} ; + "LDRB" , LDSTR {txt="LDRB"; memop=MemOp_LOAD; signed=false; lit32=false; var32=Some {datasize=DataSize8}; var64=None; lit64=None} ; + "LDRH" , LDSTR {txt="LDRH"; memop=MemOp_LOAD; signed=false; lit32=false; var32=Some {datasize=DataSize16}; var64=None; lit64=None} ; + "LDRSB" , LDSTR {txt="LDRSB"; memop=MemOp_LOAD; signed=true; lit32=false; var32=Some {datasize=DataSize8}; var64=Some {datasize=DataSize8}; lit64=None} ; + "LDRSH" , LDSTR {txt="LDRSH"; memop=MemOp_LOAD; signed=true; lit32=false; var32=Some {datasize=DataSize16}; var64=Some {datasize=DataSize16}; lit64=None} ; + "LDRSW" , LDSTR {txt="LDRSW"; memop=MemOp_LOAD; signed=true; lit32=false; var32=None; var64=Some {datasize=DataSize32}; lit64=Some {datasize=DataSize32; size=4}} ; + "STR" , LDSTR {txt="STR"; memop=MemOp_STORE; signed=false; lit32=false; var32=Some {datasize=DataSize32}; var64=Some {datasize=DataSize64}; lit64=None} ; + "STRB" , LDSTR {txt="STRB"; memop=MemOp_STORE; signed=false; lit32=false; var32=Some {datasize=DataSize8}; var64=None; lit64=None} ; + "STRH" , LDSTR {txt="STRH"; memop=MemOp_STORE; signed=false; lit32=false; var32=Some {datasize=DataSize16}; var64=None; lit64=None} ; + + "LDTR" , LDSTTUR {txt="LDTR"; memop=MemOp_LOAD; acctype=AccType_UNPRIV; signed=false; off32=Some {datasize=DataSize32}; off64=Some {datasize=DataSize64}} ; + "LDTRB" , LDSTTUR {txt="LDTRB"; memop=MemOp_LOAD; acctype=AccType_UNPRIV; signed=false; off32=Some {datasize=DataSize8}; off64=None} ; + "LDTRH" , LDSTTUR {txt="LDTRH"; memop=MemOp_LOAD; acctype=AccType_UNPRIV; signed=false; off32=Some {datasize=DataSize16}; off64=None} ; + "LDTRSB" , LDSTTUR {txt="LDTRSB"; memop=MemOp_LOAD; acctype=AccType_UNPRIV; signed=true; off32=Some {datasize=DataSize8}; off64=Some {datasize=DataSize8}} ; + "LDTRSH" , LDSTTUR {txt="LDTRSH"; memop=MemOp_LOAD; acctype=AccType_UNPRIV; signed=true; off32=Some {datasize=DataSize16}; off64=Some {datasize=DataSize16}} ; + "LDTRSW" , LDSTTUR {txt="LDTRSW"; memop=MemOp_LOAD; acctype=AccType_UNPRIV; signed=true; off32=None; off64=Some {datasize=DataSize32}} ; + "LDUR" , LDSTTUR {txt="LDUR"; memop=MemOp_LOAD; acctype=AccType_NORMAL; signed=false; off32=Some {datasize=DataSize32}; off64=Some {datasize=DataSize64}} ; + "LDURB" , LDSTTUR {txt="LDURB"; memop=MemOp_LOAD; acctype=AccType_NORMAL; signed=false; off32=Some {datasize=DataSize8}; off64=None} ; + "LDURH" , LDSTTUR {txt="LDURH"; memop=MemOp_LOAD; acctype=AccType_NORMAL; signed=false; off32=Some {datasize=DataSize16}; off64=None} ; + "LDURSB" , LDSTTUR {txt="LDURSB"; memop=MemOp_LOAD; acctype=AccType_NORMAL; signed=true; off32=Some {datasize=DataSize8}; off64=Some {datasize=DataSize8}} ; + "LDURSH" , LDSTTUR {txt="LDURSH"; memop=MemOp_LOAD; acctype=AccType_NORMAL; signed=true; off32=Some {datasize=DataSize16}; off64=Some {datasize=DataSize16}} ; + "LDURSW" , LDSTTUR {txt="LDURSW"; memop=MemOp_LOAD; acctype=AccType_NORMAL; signed=true; off32=None; off64=Some {datasize=DataSize32}} ; + "STTR" , LDSTTUR {txt="STTR"; memop=MemOp_STORE; acctype=AccType_UNPRIV; signed=false; off32=Some {datasize=DataSize32}; off64=Some {datasize=DataSize64}} ; + "STTRB" , LDSTTUR {txt="STTRB"; memop=MemOp_STORE; acctype=AccType_UNPRIV; signed=false; off32=Some {datasize=DataSize8}; off64=None} ; + "STTRH" , LDSTTUR {txt="STTRH"; memop=MemOp_STORE; acctype=AccType_UNPRIV; signed=false; off32=Some {datasize=DataSize16}; off64=None} ; + "STUR" , LDSTTUR {txt="STUR"; memop=MemOp_STORE; acctype=AccType_NORMAL; signed=false; off32=Some {datasize=DataSize32}; off64=Some {datasize=DataSize64}} ; + "STURB" , LDSTTUR {txt="STURB"; memop=MemOp_STORE; acctype=AccType_NORMAL; signed=false; off32=Some {datasize=DataSize8}; off64=None} ; + "STURH" , LDSTTUR {txt="STURH"; memop=MemOp_STORE; acctype=AccType_NORMAL; signed=false; off32=Some {datasize=DataSize16}; off64=None} ; + + "MADD" , MADDSUB {txt="MADD"; sub_op=false} ; + "MSUB" , MADDSUB {txt="MSUB"; sub_op=true} ; + + "MUL" , MUL {txt="MUL"; sub_op=false} ; + "MNEG" , MUL {txt="MNEG"; sub_op=true} ; + + "MOVK" , MOVWIDE {txt="MOVK"; opcode=MoveWideOp_K} ; + "MOVN" , MOVWIDE {txt="MOVN"; opcode=MoveWideOp_N} ; + "MOVZ" , MOVWIDE {txt="MOVZ"; opcode=MoveWideOp_Z} ; + + "NEG" , NEG {txt="NEG"; setflags=false} ; + "NEGS" , NEG {txt="NEGS"; setflags=true} ; + + "NGC" , NGC {txt="NGC"; setflags=false} ; + "NGCS" , NGC {txt="NGCS"; setflags=true} ; + + "RBIT" , REV {txt="RBIT"; op32=Some RevOp_RBIT; op64=RevOp_RBIT} ; + "REV" , REV {txt="REV"; op32=Some RevOp_REV32; op64=RevOp_REV64} ; + "REV16" , REV {txt="REV16"; op32=Some RevOp_REV16; op64=RevOp_REV16} ; + "REV32" , REV {txt="REV32"; op32=None; op64=RevOp_REV32} ; + + "SDIV" , DIV {txt="SDIV"; unsigned=false} ; + "UDIV" , DIV {txt="UDIV"; unsigned=true} ; + + "SMADDL" , MADDSUBL {txt="SMADDL"; sub_op=false; unsigned=false} ; + "SMSUBL" , MADDSUBL {txt="SMSUBL"; sub_op=true; unsigned=false} ; + "UMADDL" , MADDSUBL {txt="UMADDL"; sub_op=false; unsigned=true} ; + "UMSUBL" , MADDSUBL {txt="UMSUBL"; sub_op=true; unsigned=true} ; + + "SMULH" , MULH {txt="SMULH"; unsigned=false} ; + "UMULH" , MULH {txt="UMULH"; unsigned=true} ; + + "SMULL" , MULL {txt="SMULL"; unsigned=false} ; + "UMULL" , MULL {txt="UMULL"; unsigned=true} ; + + "LDP" , LDSTP {txt="LDP"; memop=MemOp_LOAD} ; + "STP" , LDSTP {txt="STP"; memop=MemOp_STORE} ; + + "TBZ" , TBZ {txt="TBZ"; bit_val=false} ; + "TBNZ" , TBZ {txt="TBNZ"; bit_val=true} ; + + "SBFIZ" , BFIZ {txt="SBFIZ"; extend=true} ; + "UBFIZ" , BFIZ {txt="UBFIZ"; extend=false} ; + + "SBFX" , BFX {txt="SBFX"; extend=true} ; + "UBFX" , BFX {txt="UBFX"; extend=false} ; + + "SMNEGL" , MNEGL {txt="SMNEGL"; unsigned=false} ; + "UMNEGL" , MNEGL {txt="UMNEGL"; unsigned=true} ; + + "BFI" , BFI {txt="BFI"} ; + "BFXIL" , BFXIL {txt="BFXIL"} ; + "CLREX" , CLREX {txt="CLREX"} ; + "EXTR" , EXTR {txt="EXTR"} ; + "HINT" , HINT {txt="HINT"} ; + "ISB" , ISB {txt="ISB"} ; + "LDPSW" , LDPSW {txt="LDPSW"} ; + "MOV" , MOV {txt="MOV"} ; + "MVN" , MVN {txt="MVN"} ; + "NOP" , NOP {txt="NOP"} ; + "PRFM" , PRFM {txt="PRFM"} ; + "PRFUM" , PRFUM {txt="PRFUM"} ; + "RET" , RET {txt="RET"} ; + "TST" , TST {txt="TST"} ; + "MRS" , MRS {txt="MRS"} ; + "MSR" , MSR {txt="MSR"} ; + + +(*** instructions/operands ***) + + "LSL" , SHIFT {txt="LSL"; shift_type=ShiftType_LSL} ; + "LSR" , SHIFT {txt="LSR"; shift_type=ShiftType_LSR} ; + "ASR" , SHIFT {txt="ASR"; shift_type=ShiftType_ASR} ; + "ROR" , SHIFT {txt="ROR"; shift_type=ShiftType_ROR} ; + + "UXTB" , EXTEND {txt="UXTB"; _type=ExtendType_UXTB; inst=Some {extend=false; imms=7}} ; + "UXTH" , EXTEND {txt="UXTH"; _type=ExtendType_UXTH; inst=Some {extend=false; imms=15}} ; + "UXTW" , EXTEND {txt="UXTW"; _type=ExtendType_UXTW; inst=None} ; + "UXTX" , EXTEND {txt="UXTX"; _type=ExtendType_UXTX; inst=None} ; + "SXTB" , EXTEND {txt="SXTB"; _type=ExtendType_SXTB; inst=Some {extend=true; imms=7}} ; + "SXTH" , EXTEND {txt="SXTH"; _type=ExtendType_SXTH; inst=Some {extend=true; imms=15}} ; + "SXTW" , EXTEND {txt="SXTW"; _type=ExtendType_SXTW; inst=Some {extend=true; imms=31}} ; + "SXTX" , EXTEND {txt="SXTX"; _type=ExtendType_SXTX; inst=None} ; + +(*** operands: ***) + + "EQ" , COND 0b0000 ; + "NE" , COND 0b0001 ; + "CS" , COND 0b0010 ; + "HS" , COND 0b0010 ; + "CC" , COND 0b0011 ; + "LO" , COND 0b0011 ; + "MI" , COND 0b0100 ; + "PL" , COND 0b0101 ; + "VS" , COND 0b0110 ; + "VC" , COND 0b0111 ; + "HI" , COND 0b1000 ; + "LS" , COND 0b1001 ; + "GE" , COND 0b1010 ; + "LT" , COND 0b1011 ; + "GT" , COND 0b1100 ; + "LE" , COND 0b1101 ; + "AL" , COND 0b1110 ; + "NV" , COND 0b1111 ; (* ARM: exists only to provide a valid disassembly + of the 0b1111 encoding, otherwise its + behavior is identical to AL *) + + "OSHLD" , BARROP {domain=MBReqDomain_OuterShareable; types=MBReqTypes_Reads} ; + "OSHST" , BARROP {domain=MBReqDomain_OuterShareable; types=MBReqTypes_Writes} ; + "OSH" , BARROP {domain=MBReqDomain_OuterShareable; types=MBReqTypes_All} ; + "NSHLD" , BARROP {domain=MBReqDomain_Nonshareable; types=MBReqTypes_Reads} ; + "NSHST" , BARROP {domain=MBReqDomain_Nonshareable; types=MBReqTypes_Writes} ; + "NSH" , BARROP {domain=MBReqDomain_Nonshareable; types=MBReqTypes_All} ; + "ISHLD" , BARROP {domain=MBReqDomain_InnerShareable; types=MBReqTypes_Reads} ; + "ISHST" , BARROP {domain=MBReqDomain_InnerShareable; types=MBReqTypes_Writes} ; + "ISH" , BARROP {domain=MBReqDomain_InnerShareable; types=MBReqTypes_All} ; + "LD" , BARROP {domain=MBReqDomain_FullSystem; types=MBReqTypes_Reads} ; + "ST" , BARROP {domain=MBReqDomain_FullSystem; types=MBReqTypes_Writes} ; + "SY" , BARROP {domain=MBReqDomain_FullSystem; types=MBReqTypes_All} ; + + "PLDL1KEEP" , PRFOP (X (Ireg R0)) ; + "PLDL1STRM" , PRFOP (X (Ireg R1)) ; + "PLDL2KEEP" , PRFOP (X (Ireg R2)) ; + "PLDL2STRM" , PRFOP (X (Ireg R3)) ; + "PLDL3KEEP" , PRFOP (X (Ireg R4)) ; + "PLDL3STRM" , PRFOP (X (Ireg R5)) ; + + "PLIL1KEEP" , PRFOP (X (Ireg R8)) ; + "PLIL1STRM" , PRFOP (X (Ireg R9)) ; + "PLIL2KEEP" , PRFOP (X (Ireg R10)) ; + "PLIL2STRM" , PRFOP (X (Ireg R11)) ; + "PLIL3KEEP" , PRFOP (X (Ireg R12)) ; + "PLIL3STRM" , PRFOP (X (Ireg R13)) ; + + "PSTL1KEEP" , PRFOP (X (Ireg R16)) ; + "PSTL1STRM" , PRFOP (X (Ireg R17)) ; + "PSTL2KEEP" , PRFOP (X (Ireg R18)) ; + "PSTL2STRM" , PRFOP (X (Ireg R19)) ; + "PSTL3KEEP" , PRFOP (X (Ireg R20)) ; + "PSTL3STRM" , PRFOP (X (Ireg R21)) ; + + "NZCV" , SYSREG {sys_op0=0b11; sys_op1=0b011; sys_op2=0b000; sys_crn=0b0100; sys_crm=0b0010} ; + "DAIF" , SYSREG {sys_op0=0b11; sys_op1=0b011; sys_op2=0b001; sys_crn=0b0100; sys_crm=0b0010} ; + "TPIDR_EL0" , SYSREG {sys_op0=0b11; sys_op1=0b011; sys_op2=0b010; sys_crn=0b1101; sys_crm=0b0000} ; + "TPIDR_EL1" , SYSREG {sys_op0=0b11; sys_op1=0b000; sys_op2=0b100; sys_crn=0b1101; sys_crm=0b0000} ; + "TPIDR_EL2" , SYSREG {sys_op0=0b11; sys_op1=0b100; sys_op2=0b010; sys_crn=0b1101; sys_crm=0b0000} ; + "TPIDR_EL3" , SYSREG {sys_op0=0b11; sys_op1=0b011; sys_op2=0b011; sys_crn=0b1101; sys_crm=0b0000} ; + + "SPSel" , PSTATEFIELD (PSTATEField_SP) ; + "DAIFSet" , PSTATEFIELD (PSTATEField_DAIFSet) ; + "DAIFClr" , PSTATEFIELD (PSTATEField_DAIFClr) ; diff --git a/arm/gen/map.hgen b/arm/gen/map.hgen new file mode 100644 index 00000000..62899c91 --- /dev/null +++ b/arm/gen/map.hgen @@ -0,0 +1,44 @@ +| `AArch64TMStart t -> `AArch64TMStart (map_reg t) +| `AArch64TMCommit -> `AArch64TMCommit +| `AArch64TMAbort (retry,reason) -> `AArch64TMAbort (retry,reason) +| `AArch64TMTest -> `AArch64TMTest + +| `AArch64ImplementationDefinedStopFetching -> `AArch64ImplementationDefinedStopFetching +| `AArch64ImplementationDefinedThreadStart -> `AArch64ImplementationDefinedThreadStart +| `AArch64ImplementationDefinedTestBeginEnd (isEnd) -> `AArch64ImplementationDefinedTestBeginEnd (isEnd) +| `AArch64AddSubCarry (d,n,m,datasize,sub_op,setflags) -> `AArch64AddSubCarry (map_reg d,map_reg n,map_reg m,datasize,sub_op,setflags) +| `AArch64AddSubExtendRegister (d,n,m,datasize,sub_op,setflags,extend_type,shift) -> `AArch64AddSubExtendRegister (map_reg d,map_reg n,map_reg m,datasize,sub_op,setflags,extend_type,shift) +| `AArch64AddSubShiftedRegister (d,n,m,datasize,sub_op,setflags,shift_type,shift_amount) -> `AArch64AddSubShiftedRegister (map_reg d,map_reg n,map_reg m,datasize,sub_op,setflags,shift_type,shift_amount) +| `AArch64AddSubImmediate (d,n,datasize,sub_op,setflags,imm) -> `AArch64AddSubImmediate (map_reg d,map_reg n,datasize,sub_op,setflags,imm) +| `AArch64Address (d,page,imm) -> `AArch64Address (map_reg d,page,imm) +| `AArch64LogicalImmediate (d,n,datasize,setflags,op,imm) -> `AArch64LogicalImmediate (map_reg d,map_reg n,datasize,setflags,op,imm) +| `AArch64LogicalShiftedRegister (d,n,m,datasize,setflags,op,shift_type,shift_amount,invert) -> `AArch64LogicalShiftedRegister (map_reg d,map_reg n,map_reg m,datasize,setflags,op,shift_type,shift_amount,invert) +| `AArch64Shift (d,n,m,datasize,shift_type) -> `AArch64Shift (map_reg d,map_reg n,map_reg m,datasize,shift_type) +| `AArch64BranchConditional (offset,condition) -> `AArch64BranchConditional (offset,condition) +| `AArch64BranchImmediate (branch_type,offset) -> `AArch64BranchImmediate (branch_type,offset) +| `AArch64BitfieldMove (d,n,datasize,inzero,extend,_R,_S,wmask,tmask) -> `AArch64BitfieldMove (map_reg d,map_reg n,datasize,inzero,extend,_R,_S,wmask,tmask) +| `AArch64BranchRegister (n,branch_type) -> `AArch64BranchRegister (map_reg n,branch_type) +| `AArch64CompareAndBranch (t,datasize,iszero,offset) -> `AArch64CompareAndBranch (map_reg t,datasize,iszero,offset) +| `AArch64ConditionalCompareImmediate (n,datasize,sub_op,condition,flags,imm) -> `AArch64ConditionalCompareImmediate (map_reg n,datasize,sub_op,condition,flags,imm) +| `AArch64ConditionalCompareRegister (n,m,datasize,sub_op,condition,flags) -> `AArch64ConditionalCompareRegister (map_reg n,map_reg m,datasize,sub_op,condition,flags) +| `AArch64ClearExclusiveMonitor (imm) -> `AArch64ClearExclusiveMonitor (imm) +| `AArch64CountLeading (d,n,datasize,opcode) -> `AArch64CountLeading (map_reg d,map_reg n,datasize,opcode) +| `AArch64CRC (d,n,m,size,crc32c) -> `AArch64CRC (map_reg d,map_reg n,map_reg m,size,crc32c) +| `AArch64ConditionalSelect (d,n,m,datasize,condition,else_inv,else_inc) -> `AArch64ConditionalSelect (map_reg d,map_reg n,map_reg m,datasize,condition,else_inv,else_inc) +| `AArch64Barrier (op,domain,types) -> `AArch64Barrier (op,domain,types) +| `AArch64ExtractRegister (d,n,m,datasize,lsb) -> `AArch64ExtractRegister (map_reg d,map_reg n,map_reg m,datasize,lsb) +| `AArch64Hint (op) -> `AArch64Hint (op) +| `AArch64LoadStoreAcqExc (n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,datasize) -> `AArch64LoadStoreAcqExc (map_reg n,map_reg t,map_reg t2,map_reg s,acctype,excl,pair,memop,elsize,regsize,datasize) +| `AArch64LoadStorePair (wback,postindex,n,t,t2,acctype,memop,signed,datasize,offset) -> `AArch64LoadStorePair (wback,postindex,map_reg n,map_reg t,map_reg t2,acctype,memop,signed,datasize,offset) +| `AArch64LoadImmediate (n,t,acctype,memop,signed,wback,postindex,offset,regsize,datasize) -> `AArch64LoadImmediate (map_reg n,map_reg t,acctype,memop,signed,wback,postindex,offset,regsize,datasize) +| `AArch64LoadLiteral (t,memop,signed,size,offset,datasize) -> `AArch64LoadLiteral (map_reg t,memop,signed,size,offset,datasize) +| `AArch64LoadRegister (n,t,m,acctype,memop,signed,wback,postindex,extend_type,shift,regsize,datasize) -> `AArch64LoadRegister (map_reg n,map_reg t,map_reg m,acctype,memop,signed,wback,postindex,extend_type,shift,regsize,datasize) +| `AArch64MultiplyAddSub (d,n,m,a,destsize,datasize,sub_op) -> `AArch64MultiplyAddSub (map_reg d,map_reg n,map_reg m,map_reg a,destsize,datasize,sub_op) +| `AArch64MoveWide (d,datasize,imm,pos,opcode) -> `AArch64MoveWide (map_reg d,datasize,imm,pos,opcode) +| `AArch64Reverse (d,n,datasize,op) -> `AArch64Reverse (map_reg d,map_reg n,datasize,op) +| `AArch64Division (d,n,m,datasize,unsigned) -> `AArch64Division (map_reg d,map_reg n,map_reg m,datasize,unsigned) +| `AArch64MultiplyAddSubLong (d,n,m,a,destsize,datasize,sub_op,unsigned) -> `AArch64MultiplyAddSubLong (map_reg d,map_reg n,map_reg m,map_reg a,destsize,datasize,sub_op,unsigned) +| `AArch64MultiplyHigh (d,n,m,a,destsize,datasize,unsigned) -> `AArch64MultiplyHigh (map_reg d,map_reg n,map_reg m,map_reg a,destsize,datasize,unsigned) +| `AArch64TestBitAndBranch (t,datasize,bit_pos,bit_val,offset) -> `AArch64TestBitAndBranch (map_reg t,datasize,bit_pos,bit_val,offset) +| `AArch64MoveSystemRegister (t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read) -> `AArch64MoveSystemRegister (map_reg t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read) +| `AArch64MoveSystemImmediate (operand,field) -> `AArch64MoveSystemImmediate (operand,field) diff --git a/arm/gen/parser.hgen b/arm/gen/parser.hgen new file mode 100644 index 00000000..94ce6fcf --- /dev/null +++ b/arm/gen/parser.hgen @@ -0,0 +1,1396 @@ + /* TSTART */ + | TSTART xreg + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xt>") + else `AArch64TMStart $2 } + + /* TCOMMIT */ + | TCOMMIT + { `AArch64TMCommit } + + /* TABORT */ + | TABORT imm + { if not (iskbituimm 6 $2) then error_arg "<imm> must be in the range 0 to 63" + else `AArch64TMAbort (($2 lsr 5) <> 0, $2 mod 32) } + + /* TTEST */ + | TTEST + {`AArch64TMTest} + + | ADCSBC wreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>") + else `AArch64AddSubCarry ($2,$4,$6,Set32,$1.sub_op,$1.setflags) } + | ADCSBC xreg COMMA xreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>") + else `AArch64AddSubCarry ($2,$4,$6,Set64,$1.sub_op,$1.setflags) } + + /* ADC/ADCS/SBC/SBCS */ + + | ADCSBC wreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>") + else `AArch64AddSubCarry ($2,$4,$6,Set32,$1.sub_op,$1.setflags) } + | ADCSBC xreg COMMA xreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>") + else `AArch64AddSubCarry ($2,$4,$6,Set64,$1.sub_op,$1.setflags) } + + /* ADD/SUB/ADDS/SUBS (extended register), and when noted (shifted register) */ + + | ADDSUB wreg COMMA wreg COMMA wreg + { (* ambiguous with (shifted register) *) + if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then + error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then + error_registers ("expected " ^ $1.txt ^ " <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else `AArch64AddSubExtendRegister ($2,$4,$6,Set32,$1.sub_op,$1.setflags,ExtendType_UXTW,0) } + | ADDSUB wreg COMMA wreg COMMA wreg COMMA EXTEND + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then + error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then + error_registers ("expected " ^ $1.txt ^ " <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else `AArch64AddSubExtendRegister ($2,$4,$6,Set32,$1.sub_op,$1.setflags,$8._type,0) } + | ADDSUB wreg COMMA wreg COMMA wreg COMMA SHIFT + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if (not $1.setflags) && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not ($8.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else `AArch64AddSubExtendRegister ($2,$4,$6,Set32,$1.sub_op,$1.setflags,ExtendType_UXTW,0) } + | ADDSUB wreg COMMA wreg COMMA wreg COMMA EXTEND imm + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not (0 <= $9 && $9 <= 4) then error_arg "<amount> must be in the range 0 to 4" + else `AArch64AddSubExtendRegister ($2,$4,$6,Set32,$1.sub_op,$1.setflags,$8._type,$9) } + | ADDSUB wreg COMMA wreg COMMA wreg COMMA SHIFT imm + { if (issp $2 || issp $4) then + begin + (* (extended register) *) + if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd|WSP>, <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not ($8.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else if not (0 <= $9 && $9 <= 4) then error_arg "<amount> must be in the range 0 to 4" + else `AArch64AddSubExtendRegister ($2,$4,$6,Set32,$1.sub_op,$1.setflags,ExtendType_UXTW,$9) + end + else + begin + (* (shifted register) *) + if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>{, <shift> #<amount>}") + else if $8.shift_type = ShiftType_ROR then error_arg "<shift> must be one of LSL,LSR,ASR" + else if not (0 <= $9 && $9 <= 31) then error_arg "<amount> must be in the range 0 to 31" + else `AArch64AddSubShiftedRegister ($2,$4,$6,Set32,$1.sub_op,$1.setflags,$8.shift_type,$9) + end } + + | ADDSUB xreg COMMA xreg COMMA xreg + { (* ambiguous with (shifted register) *) + if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else `AArch64AddSubExtendRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,ExtendType_UXTX,0) } + | ADDSUB xreg COMMA xreg COMMA wreg COMMA EXTEND + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if $8._type = ExtendType_UXTX || $8._type = ExtendType_SXTX then error_arg "<R> doesn't match <extend>" + else `AArch64AddSubExtendRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,$8._type,0) } + | ADDSUB xreg COMMA xreg COMMA wreg COMMA SHIFT + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not ($8.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else `AArch64AddSubExtendRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,ExtendType_UXTX,0) } + | ADDSUB xreg COMMA xreg COMMA wreg COMMA EXTEND imm + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not (0 <= $9 && $9 <= 4) then error_arg "<amount> must be in the range 0 to 4." + else if $8._type = ExtendType_UXTX || $8._type = ExtendType_SXTX then error_arg "<R> doesn't match <extend>" + else `AArch64AddSubExtendRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,$8._type,$9) } + | ADDSUB xreg COMMA xreg COMMA wreg COMMA SHIFT imm + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not ($8.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else if not (0 <= $9 && $9 <= 4) then error_arg "<amount> must be in the range 0 to 4." + else `AArch64AddSubExtendRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,ExtendType_UXTX,$9) } + | ADDSUB xreg COMMA xreg COMMA xreg COMMA EXTEND + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not ($8._type = ExtendType_UXTX || $8._type = ExtendType_SXTX) then error_arg "<R> doesn't match <extend>" + else `AArch64AddSubExtendRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,$8._type,0) } + | ADDSUB xreg COMMA xreg COMMA xreg COMMA SHIFT + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not ($8.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else `AArch64AddSubExtendRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,ExtendType_UXTX,0) } + | ADDSUB xreg COMMA xreg COMMA xreg COMMA EXTEND imm + { if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not (0 <= $9 && $9 <= 4) then error_arg "<amount> must be in the range 0 to 4." + else if not ($8._type = ExtendType_UXTX || $8._type = ExtendType_SXTX) then error_arg "<R> doesn't match <extend>" + else `AArch64AddSubExtendRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,$8._type,$9) } + | ADDSUB xreg COMMA xreg COMMA xreg COMMA SHIFT imm + { if (issp $2 || issp $4) then + begin + (* (extended register) *) + if $1.setflags && not (isregzr $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not $1.setflags && not (isregsp $2 && isregsp $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not ($8.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else if not (0 <= $9 && $9 <= 4) then error_arg "<amount> must be in the range 0 to 4." + else `AArch64AddSubExtendRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,ExtendType_UXTX,$9) + end + else + begin + (* (shifted register) *) + if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>{, <shift> #<amount>}") + else if $8.shift_type = ShiftType_ROR then error_arg "<shift> must be one of LSL,LSR,ASR" + else if not (0 <= $9 && $9 <= 63) then error_arg "<amount> must be in the range 0 to 63" + else `AArch64AddSubShiftedRegister ($2,$4,$6,Set64,$1.sub_op,$1.setflags,$8.shift_type,$9) + end } + + /* ADD/SUB/ADDS/SUBS (immediate) */ + + | ADDSUB wreg COMMA wreg COMMA imm + { if $1.setflags && not (isregzr $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn|WSP>, #<imm>{, <shift>}") + else if not $1.setflags && not (isregsp $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Wd|WSP>, <Wn|WSP>, #<imm>{, <shift>}") + else if not (0 <= $6 && $6 <= 4095) then error_arg "<imm> must be in the range 0 to 4095" + else `AArch64AddSubImmediate ($2,$4,Set32,$1.sub_op,$1.setflags,reg_size_bits_R32_of_int $6) } + | ADDSUB wreg COMMA wreg COMMA imm COMMA SHIFT imm + { if $1.setflags && not (isregzr $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn|WSP>, #<imm>{, <shift>}") + else if not $1.setflags && not (isregsp $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Wd|WSP>, <Wn|WSP>, #<imm>{, <shift>}") + else if not (0 <= $6 && $6 <= 4095) then error_arg "<imm> must be in the range 0 to 4095" + else if not ($8.shift_type = ShiftType_LSL && ($9 = 0 || $9 = 12)) then error_arg "<shift> must be 'LSL #0' or 'LSL #12'" + else `AArch64AddSubImmediate ($2,$4,Set32,$1.sub_op,$1.setflags,reg_size_bits_R32_of_int ($6 lsl $9)) } + | ADDSUB xreg COMMA xreg COMMA imm + { if $1.setflags && not (isregzr $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, #<imm>{, <shift>}") + else if not $1.setflags && not (isregsp $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}") + else if not (0 <= $6 && $6 <= 4095) then error_arg "<imm> must be in the range 0 to 4095" + else `AArch64AddSubImmediate ($2,$4,Set64,$1.sub_op,$1.setflags,reg_size_bits_R64_of_int $6) } + | ADDSUB xreg COMMA xreg COMMA imm COMMA SHIFT imm + { if $1.setflags && not (isregzr $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn|SP>, #<imm>{, <shift>}") + else if not $1.setflags && not (isregsp $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>, #<imm>{, <shift>}") + else if not (0 <= $6 && $6 <= 4095) then error_arg "<imm> must be in the range 0 to 4095" + else if not ($8.shift_type = ShiftType_LSL && ($9 = 0 || $9 = 12)) then error_arg "<shift> must be 'LSL #0' or 'LSL #12'" + else `AArch64AddSubImmediate ($2,$4,Set64,$1.sub_op,$1.setflags,reg_size_bits_R64_of_int ($6 lsl $9)) } + + /* ADR/ADRP */ +/* + | ADR xreg COMMA NAME + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <label>") + else `AArch64Address ($2,$1.page,(* FIXME: label *)) } +*/ + + /* AND/ANDS/EOR/ORR (immediate) */ + + | LOGOP wreg COMMA wreg COMMA big_imm + { if $1.invert then error_arg "bad logical operator" + else if not $1.setflags && not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd|WSP>, <Wn>, #<imm>") + else if $1.setflags && not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, #<imm>") + else + match encodeBitMasks 32 $6 with + | None -> error_arg "<imm> can not be encoded as bitmask" + | _ -> `AArch64LogicalImmediate($2,$4,Set32,$1.setflags,$1.op,reg_size_bits_R32_of_big_int $6) } + | LOGOP xreg COMMA xreg COMMA big_imm + { if $1.invert then error_arg "bad logical operator" + else if not $1.setflags && not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn>, #<imm>") + else if $1.setflags && not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, #<imm>") + else + match encodeBitMasks 64 $6 with + | None -> error_arg "<imm> can not be encoded as bitmask" + | _ -> `AArch64LogicalImmediate($2,$4,Set64,$1.setflags,$1.op,reg_size_bits_R64_of_big_int $6) } + + /* AND/ANDS/EOR/ORR/BIC/BICS/EON/ORN (shifted register) */ + + | LOGOP wreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>{, <shift> #<amount>}") + else `AArch64LogicalShiftedRegister($2,$4,$6,Set32,$1.setflags,$1.op,ShiftType_LSL,0,$1.invert) } + | LOGOP wreg COMMA wreg COMMA wreg COMMA SHIFT imm + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>{, <shift> #<amount>}") + else if not (0 <= $9 && $9 <= 31) then error_arg "<amount> must be in the range 0 to 31" + else `AArch64LogicalShiftedRegister($2,$4,$6,Set32,$1.setflags,$1.op,$8.shift_type,$9,$1.invert) } + + | LOGOP xreg COMMA xreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>{, <shift> #<amount>}") + else `AArch64LogicalShiftedRegister($2,$4,$6,Set64,$1.setflags,$1.op,ShiftType_LSL,0,$1.invert) } + | LOGOP xreg COMMA xreg COMMA xreg COMMA SHIFT imm + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>{, <shift> #<amount>}") + else if not (0 <= $9 && $9 <= 63) then error_arg "<amount> must be in the range 0 to 63" + else `AArch64LogicalShiftedRegister($2,$4,$6,Set64,$1.setflags,$1.op,$8.shift_type,$9,$1.invert) } + + + /* LSL/LSR/ASR/ROR (register) alias of LSLV/LSRV/ASRV/RORV */ + + | SHIFT wreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>") + else `AArch64Shift($2,$4,$6,Set32,$1.shift_type) } + | SHIFT xreg COMMA xreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>") + else `AArch64Shift($2,$4,$6,Set64,$1.shift_type) } + + /* LSL/LSR/ASR/ROR (immediate) alias of UBFM/UBFM/SBFM/EXTR */ + + | SHIFT wreg COMMA wreg COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, #<shift>") + else if not (0 <= $6 && $6 <= 31) then error_arg "<shift> must be in the range 0 to 31" + else match $1.shift_type with + | ShiftType_ASR -> + let (wmask,tmask) = decodeBitMasks 32 0 31 $6 false in + `AArch64BitfieldMove($2,$4,Set32,true,true,$6,31,reg_size_bits_R32_of_big_int wmask,reg_size_bits_R32_of_big_int tmask) + | ShiftType_LSL -> + let (wmask,tmask) = decodeBitMasks 32 0 (31-$6) (-$6 mod 32) false in + `AArch64BitfieldMove($2,$4,Set32,true,false,-$6 mod 32,31-$6,reg_size_bits_R32_of_big_int wmask,reg_size_bits_R32_of_big_int tmask) + | ShiftType_LSR -> + let (wmask,tmask) = decodeBitMasks 32 0 31 $6 false in + `AArch64BitfieldMove($2,$4,Set32,true,false,$6,31,reg_size_bits_R32_of_big_int wmask,reg_size_bits_R32_of_big_int tmask) + | ShiftType_ROR -> + `AArch64ExtractRegister($2,$4,$4,Set32,$6) } + | SHIFT xreg COMMA xreg COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, #<shift>") + else if not (0 <= $6 && $6 <= 63) then error_arg "<shift> must be in the range 0 to 64" + else match $1.shift_type with + | ShiftType_ASR -> + let (wmask,tmask) = decodeBitMasks 64 1 63 $6 false in + `AArch64BitfieldMove($2,$4,Set64,true,true,$6,63,reg_size_bits_R64_of_big_int wmask,reg_size_bits_R64_of_big_int tmask) + | ShiftType_LSL -> + let (wmask,tmask) = decodeBitMasks 64 1 (63-$6) ((64-$6) mod 64) false in + `AArch64BitfieldMove($2,$4,Set64,true,false,(64-$6) mod 64,63-$6,reg_size_bits_R64_of_big_int wmask,reg_size_bits_R64_of_big_int tmask) + | ShiftType_LSR -> + let (wmask,tmask) = decodeBitMasks 64 1 63 $6 false in + `AArch64BitfieldMove($2,$4,Set64,true,false,$6,63,reg_size_bits_R64_of_big_int wmask,reg_size_bits_R64_of_big_int tmask) + | ShiftType_ROR -> + `AArch64ExtractRegister($2,$4,$4,Set64,$6) } + + /* ASRV/LSLV/LSRV/RORV */ + + | SHIFTOP wreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>") + else `AArch64Shift($2,$4,$6,Set32,$1.shift_type) } + | SHIFTOP xreg COMMA xreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>") + else `AArch64Shift($2,$4,$6,Set64,$1.shift_type) } + + /* B.cond */ +/* + | BCOND NAME + { `AArch64BranchConditional((* FIXME: label *),$1.condition) } +*/ + /* B/BL */ +/* + | B NAME + { `AArch64BranchImmediate($1.branch_type,(* FIXME: label *)) } +*/ + /* BFI alias of BFM */ + + | BFI wreg COMMA wreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, #<lsb>, #<width>") + else if not (0 <= $6 && $6 <= 31) then error_arg "<lsb> must be in the range 0 to 31" + else if not (1 <= $8 && $8 <= 32-$6) then error_arg "<width> must be in the range 1 to 32-<lsb>" + else + let (wmask,tmask) = decodeBitMasks 32 0 ($8 - 1) (-$6 mod 32) false in + `AArch64BitfieldMove($2,$4,Set32,false,false,(-$6 mod 32),($8 - 1),reg_size_bits_R32_of_big_int wmask,reg_size_bits_R32_of_big_int tmask) } + | BFI xreg COMMA xreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, #<lsb>, #<width>") + else if not (0 <= $6 && $6 <= 63) then error_arg "<lsb> must be in the range 0 to 63" + else if not (1 <= $8 && $8 <= 64-$6) then error_arg "<width> must be in the range 1 to 64-<lsb>" + else + let (wmask,tmask) = decodeBitMasks 64 1 ($8 - 1) (-$6 mod 64) false in + `AArch64BitfieldMove($2,$4,Set64,false,false,(-$6 mod 64),($8 - 1),reg_size_bits_R64_of_big_int wmask,reg_size_bits_R64_of_big_int tmask) } + + /* BFM/SBFM/UBFM */ + + | BFM wreg COMMA wreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, #<immr>, #<imms>") + else if not (0 <= $6 && $6 <= 31) then error_arg "<immr> must be in the range 0 to 31" + else if not (0 <= $8 && $8 <= 31) then error_arg "<imms> must be in the range 0 to 31" + else + let (wmask,tmask) = decodeBitMasks 32 0 $8 $6 false in + `AArch64BitfieldMove($2,$4,Set32,$1.inzero,$1.extend,$6,$8,reg_size_bits_R32_of_big_int wmask,reg_size_bits_R32_of_big_int tmask) } + | BFM xreg COMMA xreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, #<immr>, #<imms>") + else if not (0 <= $6 && $6 <= 63) then error_arg "<immr> must be in the range 0 to 63" + else if not (0 <= $8 && $8 <= 63) then error_arg "<imms> must be in the range 0 to 63" + else + let (wmask,tmask) = decodeBitMasks 64 1 $8 $6 false in + `AArch64BitfieldMove($2,$4,Set64,$1.inzero,$1.extend,$6,$8,reg_size_bits_R64_of_big_int wmask,reg_size_bits_R64_of_big_int tmask) } + + /* BFXIL alias of BFM */ + + | BFXIL wreg COMMA wreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, #<lsb>, #<width>") + else if not (0 <= $6 && $6 <= 31) then error_arg "<immr> must be in the range 0 to 31" + else if not (1 <= $8 && $8 <= 32-$6) then error_arg "<imms> must be in the range 1 to 32-<lsb>" + else + let (wmask,tmask) = decodeBitMasks 32 0 ($6+$8-1) $6 false in + `AArch64BitfieldMove($2,$4,Set32,false,false,$6,$6+$8-1,reg_size_bits_R32_of_big_int wmask,reg_size_bits_R32_of_big_int tmask) } + | BFXIL xreg COMMA xreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, #<lsb>, #<width>") + else if not (0 <= $6 && $6 <= 63) then error_arg "<immr> must be in the range 0 to 63" + else if not (1 <= $8 && $8 <= 64-$6) then error_arg "<imms> must be in the range 1 to 64-<lsb>" + else + let (wmask,tmask) = decodeBitMasks 64 1 ($6+$8-1) $6 false in + `AArch64BitfieldMove($2,$4,Set64,false,false,$6,$6+$8-1,reg_size_bits_R64_of_big_int wmask,reg_size_bits_R64_of_big_int tmask) } + + /* BR/BLR */ + + | BR xreg + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xn>") + else `AArch64BranchRegister($2,$1.branch_type) } + + /* CBZ/CBNZ */ +/* + | CBZ wreg COMMA NAME + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Wt>, <label>") + else `AArch64CompareAndBranch($2,Set32,$1.iszero,(* FIXME: label *)) } + | CBZ xreg COMMA NAME + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xt>, <label>") + else `AArch64CompareAndBranch($2,Set64,$1.iszero,(* FIXME: label *)) } +*/ + + /* CCMN/CCMP (immediate) */ + + | CCM wreg COMMA imm COMMA imm COMMA COND + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Wn>, #<imm>, #<nzcv>, <cond>") + else if not (iskbituimm 5 $4) then error_arg "<imm> must be in the range 0 to 31" + else if not (0 <= $6 && $6 <= 15) then error_arg "<nzcv> must be in the range 0 to 15" + else `AArch64ConditionalCompareImmediate($2,Set32,$1.sub_op,$8,$6,reg_size_bits_R32_of_int $4) } + | CCM xreg COMMA imm COMMA imm COMMA COND + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xn>, #<imm>, #<nzcv>, <cond>") + else if not (iskbituimm 5 $4) then error_arg "<imm> must be in the range 0 to 31" + else if not (0 <= $6 && $6 <= 15) then error_arg "<nzcv> must be in the range 0 to 15" + else `AArch64ConditionalCompareImmediate($2,Set64,$1.sub_op,$8,$6,reg_size_bits_R64_of_int $4) } + + /* CCMN/CCMP (register) */ + + | CCM wreg COMMA wreg COMMA imm COMMA COND + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wn>, <Wm>, #<nzcv>, <cond>") + else if not (0 <= $6 && $6 <= 15) then error_arg "<nzcv> must be in the range 0 to 15" + else `AArch64ConditionalCompareRegister($2,$4,Set32,$1.sub_op,$8,$6) } + | CCM xreg COMMA xreg COMMA imm COMMA COND + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn>, <Xm>, #<nzcv>, <cond>") + else if not (0 <= $6 && $6 <= 15) then error_arg "<nzcv> must be in the range 0 to 15" + else `AArch64ConditionalCompareRegister($2,$4,Set64,$1.sub_op,$8,$6) } + + /* CINC/CINV/CNEG alias of CSINC/CSINV/CSNEG */ + + | CON wreg COMMA wreg COMMA COND + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <cond>") + else if ($6 = 0b1110 || $6 = 0b1111) then error_arg "<cond> must not be AL or NV" + else `AArch64ConditionalSelect($2,$4,$4,Set32,invert $6,$1.else_inv,$1.else_inc) } + | CON xreg COMMA xreg COMMA COND + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <cond>") + else if ($6 = 0b1110 || $6 = 0b1111) then error_arg "<cond> must not be AL or NV" + else `AArch64ConditionalSelect($2,$4,$4,Set64,invert $6,$1.else_inv,$1.else_inc) } + + /* CLREX */ + + | CLREX + { `AArch64ClearExclusiveMonitor(15) } + | CLREX imm + { if not (iskbituimm 4 $2) then error_arg "<imm> must be in the range 0 to 15" + else `AArch64ClearExclusiveMonitor($2) } + + /* CLS/CLZ */ + + | CL wreg COMMA wreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>") + else `AArch64CountLeading($2,$4,Set32,$1.opcode) } + | CL xreg COMMA xreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>") + else `AArch64CountLeading($2,$4,Set64,$1.opcode) } + + /* CMN/CMP (extended register) alias of ADDS/SUBS (extended register) */ + + | CM wreg COMMA wreg + { (* ambiguous with (shifted register) *) + if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else `AArch64AddSubExtendRegister (W ZR,$2,$4,Set32,$1.sub_op,true,ExtendType_UXTW,0) } + | CM wreg COMMA wreg COMMA EXTEND + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else `AArch64AddSubExtendRegister (W ZR,$2,$4,Set32,$1.sub_op,true,$6._type,0) } + | CM wreg COMMA wreg COMMA SHIFT + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not ($6.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else `AArch64AddSubExtendRegister (W ZR,$2,$4,Set32,$1.sub_op,true,ExtendType_UXTW,0) } + | CM wreg COMMA wreg COMMA EXTEND imm + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not (0 <= $7 && $7 <= 4) then error_arg "<amount> must be in the range 0 to 4" + else `AArch64AddSubExtendRegister (W ZR,$2,$4,Set32,$1.sub_op,true,$6._type,$7) } + | CM wreg COMMA wreg COMMA SHIFT imm + { if issp $2 then + begin + (* (extended register) *) + if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wn|WSP>, <Wm>{, <extend> {#<amount>}}") + else if not ($6.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else if not (0 <= $7 && $7 <= 4) then error_arg "<amount> must be in the range 0 to 4" + else `AArch64AddSubExtendRegister (W ZR,$2,$4,Set32,$1.sub_op,true,ExtendType_UXTW,$7) + end + else + begin + (* (shifted register) *) + if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wn>, <Wm>{, <shift> #<amount>}") + else if $6.shift_type = ShiftType_ROR then error_arg "<shift> must be one of LSL,LSR,ASR" + else if not (0 <= $7 && $7 <= 31) then error_arg "<amount> must be in the range 0 to 31" + else `AArch64AddSubShiftedRegister (W ZR,$2,$4,Set32,$1.sub_op,true,$6.shift_type,$7) + end } + + | CM xreg COMMA xreg + { (* ambiguous with (shifted register) *) + if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else `AArch64AddSubExtendRegister (X ZR,$2,$4,Set64,$1.sub_op,true,ExtendType_UXTX,0) } + | CM xreg COMMA wreg COMMA EXTEND + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if $6._type = ExtendType_UXTX || $6._type = ExtendType_SXTX then error_arg "<R> doesn't match <extend>" + else `AArch64AddSubExtendRegister (X ZR,$2,$4,Set64,$1.sub_op,true,$6._type,0) } + | CM xreg COMMA wreg COMMA SHIFT + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not ($6.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else `AArch64AddSubExtendRegister (X ZR,$2,$4,Set64,$1.sub_op,true,ExtendType_UXTX,0) } + | CM xreg COMMA wreg COMMA EXTEND imm + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not (0 <= $7 && $7 <= 4) then error_arg "<amount> must be in the range 0 to 4." + else if $6._type = ExtendType_UXTX || $6._type = ExtendType_SXTX then error_arg "<R> doesn't match <extend>" + else `AArch64AddSubExtendRegister (X ZR,$2,$4,Set64,$1.sub_op,true,$6._type,$7) } + | CM xreg COMMA wreg COMMA SHIFT imm + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not ($6.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else if not (0 <= $7 && $7 <= 4) then error_arg "<amount> must be in the range 0 to 4." + else `AArch64AddSubExtendRegister (X ZR,$2,$4,Set64,$1.sub_op,true,ExtendType_UXTX,$7) } + | CM xreg COMMA xreg COMMA EXTEND + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not ($6._type = ExtendType_UXTX || $6._type = ExtendType_SXTX) then error_arg "<R> doesn't match <extend>" + else `AArch64AddSubExtendRegister (X ZR,$2,$4,Set64,$1.sub_op,true,$6._type,0) } + | CM xreg COMMA xreg COMMA SHIFT + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not ($6.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else `AArch64AddSubExtendRegister (X ZR,$2,$4,Set64,$1.sub_op,true,ExtendType_UXTX,0) } + | CM xreg COMMA xreg COMMA EXTEND imm + { if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, <R><m>{, <extend> {#<amount>}}") + else if not (0 <= $7 && $7 <= 4) then error_arg "<amount> must be in the range 0 to 4." + else if not ($6._type = ExtendType_UXTX || $6._type = ExtendType_SXTX) then error_arg "<R> doesn't match <extend>" + else `AArch64AddSubExtendRegister (X ZR,$2,$4,Set64,$1.sub_op,true,$6._type,$7) } + | CM xreg COMMA xreg COMMA SHIFT imm + { if issp $2 then + begin + (* (extended register) *) + if not (isregsp $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, <X ZR>") + else if not ($6.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of UXTB,UXTH,UXTW,UXTX,SXTB,SXTH,SXTW,SXTX,LSL" + else if not (0 <= $7 && $7 <= 4) then error_arg "<amount> must be in the range 0 to 4." + else `AArch64AddSubExtendRegister (X ZR,$2,$4,Set64,$1.sub_op,true,ExtendType_UXTX,$7) + end + else + begin + (* (shifted register) *) + if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn>, <Xm>{, <shift> #<amount>}") + else if $6.shift_type = ShiftType_ROR then error_arg "<shift> must be one of LSL,LSR,ASR" + else if not (0 <= $7 && $7 <= 63) then error_arg "<amount> must be in the range 0 to 63" + else `AArch64AddSubShiftedRegister (X ZR,$2,$4,Set64,$1.sub_op,true,$6.shift_type,$7) + end } + + /* CMN/CMP (immediate) alias of ADDS/SUBS (immediate) */ + + | CM wreg COMMA imm + { if not (isregsp $2) then error_registers ("expected " ^ $1.txt ^ " <Wn|WSP>, #<imm>{, <shift>}") + else if not (0 <= $4 && $4 <= 4095) then error_arg "<imm> must be in the range 0 to 4095" + else `AArch64AddSubImmediate (W ZR,$2,Set32,$1.sub_op,true,reg_size_bits_R32_of_int $4) } + | CM wreg COMMA imm COMMA SHIFT imm + { if not (isregsp $2) then error_registers ("expected " ^ $1.txt ^ " <Wn|WSP>, #<imm>{, <shift>}") + else if not (0 <= $4 && $4 <= 4095) then error_arg "<imm> must be in the range 0 to 4095" + else if not ($6.shift_type = ShiftType_LSL && ($7 = 0 || $7 = 12)) then error_arg "<shift> must be 'LSL #0' or 'LSL #12'" + else `AArch64AddSubImmediate (W ZR,$2,Set32,$1.sub_op,true,reg_size_bits_R32_of_int ($4 lsl $7)) } + | CM xreg COMMA imm + { if not (isregsp $2) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, #<imm>{, <shift>}") + else if not (0 <= $4 && $4 <= 4095) then error_arg "<imm> must be in the range 0 to 4095" + else `AArch64AddSubImmediate (X ZR,$2,Set64,$1.sub_op,true,reg_size_bits_R64_of_int $4) } + | CM xreg COMMA imm COMMA SHIFT imm + { if not (isregsp $2) then error_registers ("expected " ^ $1.txt ^ " <Xn|SP>, #<imm>{, <shift>}") + else if not (0 <= $4 && $4 <= 4095) then error_arg "<imm> must be in the range 0 to 4095" + else if not ($6.shift_type = ShiftType_LSL && ($7 = 0 || $7 = 12)) then error_arg "<shift> must be 'LSL #0' or 'LSL #12'" + else `AArch64AddSubImmediate (X ZR,$2,Set64,$1.sub_op,true,reg_size_bits_R64_of_int ($4 lsl $7)) } + + /* CRC32B/CRC32H/CRC32W */ + /* CRC32CB/CRC32CH/CRC32CW */ + + | CRC wreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>") + else `AArch64CRC($2,$4,$6,$1.size,$1.crc32c) } + + /* CRC32X/CRC32CX */ + + | CRC32X wreg COMMA wreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Xm>") + else `AArch64CRC($2,$4,$6,DataSize64,$1.crc32c) } + + /* CSEL/CSINV/CSINC/CSNEG */ + + | CSEL wreg COMMA wreg COMMA wreg COMMA COND + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>, <cond>") + else `AArch64ConditionalSelect($2,$4,$6,Set32,$8,$1.else_inv,$1.else_inc) } + | CSEL xreg COMMA xreg COMMA xreg COMMA COND + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>, <cond>") + else `AArch64ConditionalSelect($2,$4,$6,Set64,$8,$1.else_inv,$1.else_inc) } + + /* CSET/CSETM alias of CSINC/CSINV */ + + | CSET wreg COMMA COND + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <cond>") + else if ($4 = 0b1110 || $4 = 0b1111) then error_arg "<cond> must not be AL or NV" + else `AArch64ConditionalSelect($2,W ZR,W ZR,Set32,$4,$1.else_inv,$1.else_inc) } + | CSET xreg COMMA COND + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <cond>") + else if ($4 = 0b1110 || $4 = 0b1111) then error_arg "<cond> must not be AL or NV" + else `AArch64ConditionalSelect($2,X ZR,X ZR,Set64,$4,$1.else_inv,$1.else_inc) } + + /* DMB/DSB */ + + | MEMBARR BARROP + { `AArch64Barrier($1.op,$2.domain,$2.types) } + | MEMBARR imm + { if not (0 <= $2 && $2 <= 15) then error_arg "<imm> must be in the range 0 to 15" + else + let domain = + match $2 / 4 with + | 0b00 -> MBReqDomain_OuterShareable + | 0b01 -> MBReqDomain_Nonshareable + | 0b10 -> MBReqDomain_InnerShareable + | 0b11 -> MBReqDomain_FullSystem + | _ -> assert false + in + let (domain,types) = + match $2 mod 4 with + | 0b01 -> (domain,MBReqTypes_Reads) + | 0b10 -> (domain,MBReqTypes_Writes) + | 0b11 -> (domain,MBReqTypes_All) + | _ -> (MBReqDomain_FullSystem,MBReqTypes_All) + in + `AArch64Barrier($1.op,domain,types) } + + /* EXTR */ + + | EXTR wreg COMMA wreg COMMA wreg COMMA imm + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>, #<lsb>") + else if not (0 <= $8 && $8 <= 31) then error_arg "<lsb> must be in the range 0 to 31" + else `AArch64ExtractRegister($2,$4,$6,Set32,$8) } + | EXTR xreg COMMA xreg COMMA xreg COMMA imm + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>, #<lsb>") + else if not (0 <= $8 && $8 <= 63) then error_arg "<lsb> must be in the range 0 to 63" + else `AArch64ExtractRegister($2,$4,$6,Set64,$8) } + + /* HINT */ + + | HINT imm + { if not (0 <= $2 && $2 <= 127) then error_arg "<imm> must be in the range 0 to 127" + else + match $2 with + | 0 -> `AArch64Hint(SystemHintOp_NOP) + | 1 -> `AArch64Hint(SystemHintOp_YIELD) + | 2 -> `AArch64Hint(SystemHintOp_WFE) + | 3 -> `AArch64Hint(SystemHintOp_WFI) + | 4 -> `AArch64Hint(SystemHintOp_SEV) + | 5 -> `AArch64Hint(SystemHintOp_SEVL) + | _ -> `AArch64Hint(SystemHintOp_NOP) } + + /* ISB */ + + | ISB + { `AArch64Barrier(MemBarrierOp_ISB,MBReqDomain_FullSystem,MBReqTypes_All) } + | ISB BARROP + { if not ($2 = {domain=MBReqDomain_FullSystem; types=MBReqTypes_All}) then error_arg "<option> must be SY" + else `AArch64Barrier(MemBarrierOp_ISB,MBReqDomain_FullSystem,MBReqTypes_All) } + | ISB imm + { (* FIXME: this seems like an ARM bug, why do we let this be anything other then 15 *) + if not (0 <= $2 && $2 <= 15) then error_arg "<imm> must be in the range 0 to 15" + else + let domain = + match $2 / 4 with + | 0b00 -> MBReqDomain_OuterShareable + | 0b01 -> MBReqDomain_Nonshareable + | 0b10 -> MBReqDomain_InnerShareable + | 0b11 -> MBReqDomain_FullSystem + | _ -> assert false + in + let (domain,types) = + match $2 mod 4 with + | 0b01 -> (domain,MBReqTypes_Reads) + | 0b10 -> (domain,MBReqTypes_Writes) + | 0b11 -> (domain,MBReqTypes_All) + | _ -> (MBReqDomain_FullSystem,MBReqTypes_All) + in + `AArch64Barrier(MemBarrierOp_ISB,domain,types) } + + /* LDAR/LDARB/LDARH + LDAXR/LDAXRB/LDAXRH + LDXR/LDXRB/LDXRH + STLR/STLRB/STLRH */ + + | LDAXR wreg COMMA LBRK xreg RBRK + { if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($5,$2,W ZR (* ARM: 0b11111 *),W ZR (* ARM: 0b11111 *),$1.acctype,$1.excl,false,$1.memop,$1.var32.elsize,Set32,$1.var32.datasize) } + | LDAXR wreg COMMA LBRK xreg COMMA imm RBRK + { if not (isregzr $2 && isregsp $5 && $7 = 0) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($5,$2,W ZR (* ARM: 0b11111 *),W ZR (* ARM: 0b11111 *),$1.acctype,$1.excl,false,$1.memop,$1.var32.elsize,Set32,$1.var32.datasize) } + | LDAXR xreg COMMA LBRK xreg RBRK + { if not $1.var64 then error_arg "unrecognised instruction" + else if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($5,$2,X ZR (* ARM: 0b11111 *),W ZR (* ARM: 0b11111 *),$1.acctype,$1.excl,false,$1.memop,64,Set64,DataSize64) } + | LDAXR xreg COMMA LBRK xreg COMMA imm RBRK + { if not $1.var64 then error_arg "unrecognised instruction" + else if not (isregzr $2 && isregsp $5 && $7 = 0) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($5,$2,X ZR (* ARM: 0b11111 *),W ZR (* ARM: 0b11111 *),$1.acctype,$1.excl,false,$1.memop,64,Set64,DataSize64) } + + /* STXR/STXRB/STXRH */ + /* STLXR/STLXRB/STLXRH */ + + | STLXR wreg COMMA wreg COMMA LBRK xreg RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Ws>, <Wt>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($7,$4,W ZR (* ARM: 0b11111 *),$2,$1.acctype,true,false,MemOp_STORE,$1.var32.elsize,Set32,$1.var32.datasize) } + | STLXR wreg COMMA wreg COMMA LBRK xreg COMMA imm RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7 && $9 = 0) then error_registers ("expected " ^ $1.txt ^ " <Ws>, <Wt>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($7,$4,W ZR (* ARM: 0b11111 *),$2,$1.acctype,true,false,MemOp_STORE,$1.var32.elsize,Set32,$1.var32.datasize) } + | STLXR wreg COMMA xreg COMMA LBRK xreg RBRK + { if not $1.var64 then error_arg "unrecognised instruction" + else if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Ws>, <Xt>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($7,$4,X ZR (* ARM: 0b11111 *),$2,$1.acctype,true,false,MemOp_STORE,64,Set64,DataSize64) } + | STLXR wreg COMMA xreg COMMA LBRK xreg COMMA imm RBRK + { if not $1.var64 then error_arg "unrecognised instruction" + else if not (isregzr $2 && isregzr $4 && isregsp $7 && $9 = 0) then error_registers ("expected " ^ $1.txt ^ " <Ws>, <Xt>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($7,$4,X ZR (* ARM: 0b11111 *),$2,$1.acctype,true,false,MemOp_STORE,64,Set64,DataSize64) } + + /* LDAXP/LDXP */ + + | LDXP wreg COMMA wreg COMMA LBRK xreg RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Wt1>, <Wt2>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($7,$2,$4,W ZR (* ARM: 0b11111 *),$1.acctype,true,true,MemOp_LOAD,32,Set32,DataSize32) } + | LDXP wreg COMMA wreg COMMA LBRK xreg COMMA imm RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7 && $9 = 0) then error_registers ("expected " ^ $1.txt ^ " <Wt1>, <Wt2>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($7,$2,$4,W ZR (* ARM: 0b11111 *),$1.acctype,true,true,MemOp_LOAD,32,Set32,DataSize32) } + | LDXP xreg COMMA xreg COMMA LBRK xreg RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($7,$2,$4,W ZR (* ARM: 0b11111 *),$1.acctype,true,true,MemOp_LOAD,64,Set64,DataSize64) } + | LDXP xreg COMMA xreg COMMA LBRK xreg COMMA imm RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7 && $9 = 0) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($7,$2,$4,W ZR (* ARM: 0b11111 *),$1.acctype,true,true,MemOp_LOAD,64,Set64,DataSize64) } + + /* STLXP/STXP */ + + | STXP wreg COMMA wreg COMMA wreg COMMA LBRK xreg RBRK + { if not (isregzr $2 && isregzr $4 && isregzr $6 && isregsp $9) then error_registers ("expected " ^ $1.txt ^ " <Ws>, <Wt1>, <Wt2>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($9,$4,$6,$2,$1.acctype,true,true,MemOp_STORE,32,Set32,DataSize32) } + | STXP wreg COMMA wreg COMMA wreg COMMA LBRK xreg COMMA imm RBRK + { if not (isregzr $2 && isregzr $4 && isregzr $6 && isregsp $9 && $11 = 0) then error_registers ("expected " ^ $1.txt ^ " <Ws>, <Wt1>, <Wt2>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($9,$4,$6,$2,$1.acctype,true,true,MemOp_STORE,32,Set32,DataSize32) } + | STXP wreg COMMA xreg COMMA xreg COMMA LBRK xreg RBRK + { if not (isregzr $2 && isregzr $4 && isregzr $6 && isregsp $9) then error_registers ("expected " ^ $1.txt ^ " <Ws>, <Xt1>, <Xt2>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($9,$4,$6,$2,$1.acctype,true,true,MemOp_STORE,64,Set64,DataSize64) } + | STXP wreg COMMA xreg COMMA xreg COMMA LBRK xreg COMMA imm RBRK + { if not (isregzr $2 && isregzr $4 && isregzr $6 && isregsp $9 && $11 = 0) then error_registers ("expected " ^ $1.txt ^ " <Ws>, <Xt1>, <Xt2>, [<Xn|SP>{,#0}]") + else `AArch64LoadStoreAcqExc($9,$4,$6,$2,$1.acctype,true,true,MemOp_STORE,64,Set64,DataSize64) } + + /* LDP/STP (post-index) */ + + | LDSTP wreg COMMA wreg COMMA LBRK xreg RBRK COMMA imm + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Wt1>, <Wt2>, [<Xn|SP>], #<imm>") + else if not (-256 <= $10 && $10 <= 252) then error_arg "<imm> must be in the range -256 to 252" + else if not ($10 mod 4 = 0) then error_arg "<imm> must be a multiple of 4" + else `AArch64LoadStorePair (true,true,$7,$2,$4,AccType_NORMAL,$1.memop,false,DataSize32,bit64_of_int $10) } + | LDSTP xreg COMMA xreg COMMA LBRK xreg RBRK COMMA imm + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>], #<imm>") + else if not (-512 <= $10 && $10 <= 504) then error_arg "<imm> must be in the range -512 to 504" + else if not ($10 mod 8 = 0) then error_arg "<imm> must be a multiple of 8" + else `AArch64LoadStorePair (true,true,$7,$2,$4,AccType_NORMAL,$1.memop,false,DataSize64,bit64_of_int $10) } + + /* LDP/STP (pre-index) */ + + | LDSTP wreg COMMA wreg COMMA LBRK xreg COMMA imm RBRK EXCL + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!") + else if not (-256 <= $9 && $9 <= 252) then error_arg "<imm> must be in the range -256 to 252" + else if not ($9 mod 4 = 0) then error_arg "<imm> must be a multiple of 4" + else `AArch64LoadStorePair (true,false,$7,$2,$4,AccType_NORMAL,$1.memop,false,DataSize32,bit64_of_int $9) } + | LDSTP xreg COMMA xreg COMMA LBRK xreg COMMA imm RBRK EXCL + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!") + else if not (-512 <= $9 && $9 <= 504) then error_arg "<imm> must be in the range -512 to 504" + else if not ($9 mod 8 = 0) then error_arg "<imm> must be a multiple of 8" + else `AArch64LoadStorePair (true,false,$7,$2,$4,AccType_NORMAL,$1.memop,false,DataSize64,bit64_of_int $9) } + + /* LDP/STP (signed offset) */ + + | LDSTP wreg COMMA wreg COMMA LBRK xreg RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Wt1>, <Wt2>, [<Xn|SP>{, #<imm>}]") + else `AArch64LoadStorePair (false,false,$7,$2,$4,AccType_NORMAL,$1.memop,false,DataSize32,bit64_of_int 0) } + | LDSTP wreg COMMA wreg COMMA LBRK xreg COMMA imm RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Wt1>, <Wt2>, [<Xn|SP>{, #<imm>}]") + else if not (-256 <= $9 && $9 <= 252) then error_arg "<imm> must be in the range -256 to 252" + else if not ($9 mod 4 = 0) then error_arg "<imm> must be a multiple of 4" + else `AArch64LoadStorePair (false,false,$7,$2,$4,AccType_NORMAL,$1.memop,false,DataSize32,bit64_of_int $9) } + | LDSTP xreg COMMA xreg COMMA LBRK xreg RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}]") + else `AArch64LoadStorePair (false,false,$7,$2,$4,AccType_NORMAL,$1.memop,false,DataSize64,bit64_of_int 0) } + | LDSTP xreg COMMA xreg COMMA LBRK xreg COMMA imm RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}]") + else if not (-512 <= $9 && $9 <= 504) then error_arg "<imm> must be in the range -512 to 504" + else if not ($9 mod 8 = 0) then error_arg "<imm> must be a multiple of 8" + else `AArch64LoadStorePair (false,false,$7,$2,$4,AccType_NORMAL,$1.memop,false,DataSize64,bit64_of_int $9) } + + /* LDPSW (post-index) */ + + | LDPSW xreg COMMA xreg COMMA LBRK xreg RBRK COMMA imm + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>], #<imm>") + else if not (-256 <= $10 && $10 <= 252) then error_arg "<imm> must be in the range -256 to 252" + else if not ($10 mod 4 = 0) then error_arg "<imm> must be a multiple of 4" + else `AArch64LoadStorePair (true,true,$7,$2,$4,AccType_NORMAL,MemOp_LOAD,true,DataSize32,bit64_of_int $10) } + + /* LDPSW (pre-index) */ + + | LDPSW xreg COMMA xreg COMMA LBRK xreg COMMA imm RBRK EXCL + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!") + else if not (-256 <= $9 && $9 <= 252) then error_arg "<imm> must be in the range -256 to 252" + else if not ($9 mod 4 = 0) then error_arg "<imm> must be a multiple of 4" + else `AArch64LoadStorePair (true,false,$7,$2,$4,AccType_NORMAL,MemOp_LOAD,true,DataSize32,bit64_of_int $9) } + + /* LDPSW (signed offset) */ + + | LDPSW xreg COMMA xreg COMMA LBRK xreg RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}]") + else `AArch64LoadStorePair (false,false,$7,$2,$4,AccType_NORMAL,MemOp_LOAD,true,DataSize32,bit64_of_int 0) } + | LDPSW xreg COMMA xreg COMMA LBRK xreg COMMA imm RBRK + { if not (isregzr $2 && isregzr $4 && isregsp $7) then error_registers ("expected " ^ $1.txt ^ " <Xt1>, <Xt2>, [<Xn|SP>{, #<imm>}]") + else if not (-256 <= $9 && $9 <= 252) then error_arg "<imm> must be in the range -256 to 252" + else if not ($9 mod 4 = 0) then error_arg "<imm> must be a multiple of 4" + else `AArch64LoadStorePair (false,false,$7,$2,$4,AccType_NORMAL,MemOp_LOAD,true,DataSize32,bit64_of_int $9) } + + /* LDR/LDRB/LDRH/LDRSB/LDRSH/LDRSW/STR/STRB/STRH (immediate) (post-index) */ + + | LDSTR wreg COMMA LBRK xreg RBRK COMMA imm + { match $1.var32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>], #<simm>") + | Some var32 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>]") + else if not (-256 <= $8 && $8 <= 255) then error_arg "<simm> must be in the range -256 to 255" + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,$1.memop,$1.signed,true,true,bit64_of_int $8,Set32,var32.datasize) } + | LDSTR xreg COMMA LBRK xreg RBRK COMMA imm + { match $1.var64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>], #<simm>") + | Some var64 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>]") + else if not (-256 <= $8 && $8 <= 255) then error_arg "<simm> must be in the range -256 to 255" + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,$1.memop,$1.signed,true,true,bit64_of_int $8,Set64,var64.datasize) } + + /* LDR/LDRB/LDRH/LDRSB/LDRSH/LDRSW/STR/STRB/STRH (immediate) (pre-index) */ + + | LDSTR wreg COMMA LBRK xreg COMMA imm RBRK EXCL + { match $1.var32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, #<simm>]!") + | Some var32 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, #<simm>]!") + else if not (-256 <= $7 && $7 <= 255) then error_arg "<simm> must be in the range -256 to 255" + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,$1.memop,$1.signed,true,false,bit64_of_int $7,Set32,var32.datasize) } + | LDSTR xreg COMMA LBRK xreg COMMA imm RBRK EXCL + { match $1.var64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, #<simm>]!") + | Some var64 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, #<simm>]!") + else if not (-256 <= $7 && $7 <= 255) then error_arg "<simm> must be in the range -256 to 255" + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,$1.memop,$1.signed,true,false,bit64_of_int $7,Set64,var64.datasize) } + + /* LDR/LDRB/LDRH/LDRSB/LDRSH/LDRSW/STR/STRB/STRH (immediate) (unsigned offset) */ + + | LDSTR wreg COMMA LBRK xreg RBRK + { match $1.var32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{, #<pimm>}]") + | Some var32 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{, #<pimm>}]") + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,$1.memop,$1.signed,false,false,bit64_of_int 0,Set32,var32.datasize) } + | LDSTR wreg COMMA LBRK xreg COMMA imm RBRK + { match $1.var32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{, #<pimm>}]") + | Some var32 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{, #<pimm>}]") + else if var32.datasize = DataSize8 && not (0 <= $7 && $7 <= 4095) then error_arg "<pimm> must be in the range 0 to 4095" + else if var32.datasize = DataSize16 && not (0 <= $7 && $7 <= 8190) then error_arg "<pimm> must be in the range 0 to 8190" + else if var32.datasize = DataSize16 && not ($7 mod 2 = 0) then error_arg "<pimm> must be a multiple of 2" + else if var32.datasize = DataSize32 && not (0 <= $7 && $7 <= 16380) then error_arg "<pimm> must be in the range 0 to 16380" + else if var32.datasize = DataSize32 && not ($7 mod 4 = 0) then error_arg "<pimm> must be a multiple of 4" + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,$1.memop,$1.signed,false,false,bit64_of_int $7,Set32,var32.datasize) } + | LDSTR xreg COMMA LBRK xreg RBRK + { match $1.var64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{, #<pimm>}]") + | Some var64 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{, #<pimm>}]") + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,$1.memop,$1.signed,false,false,bit64_of_int 0,Set64,var64.datasize) } + | LDSTR xreg COMMA LBRK xreg COMMA imm RBRK + { match $1.var64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{, #<pimm>}]") + | Some var64 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{, #<pimm>}]") + else if var64.datasize = DataSize8 && not (0 <= $7 && $7 <= 4095) then error_arg "<pimm> must be in the range 0 to 4095" + else if var64.datasize = DataSize16 && not (0 <= $7 && $7 <= 8190) then error_arg "<pimm> must be in the range 0 to 8190" + else if var64.datasize = DataSize16 && not ($7 mod 2 = 0) then error_arg "<pimm> must be a multiple of 2" + else if var64.datasize = DataSize32 && not (0 <= $7 && $7 <= 16380) then error_arg "<pimm> must be in the range 0 to 16380" + else if var64.datasize = DataSize32 && not ($7 mod 4 = 0) then error_arg "<pimm> must be a multiple of 4" + else if var64.datasize = DataSize64 && not (0 <= $7 && $7 <= 32760) then error_arg "<pimm> must be in the range 0 to 32760" + else if var64.datasize = DataSize64 && not ($7 mod 8 = 0) then error_arg "<pimm> must be a multiple of 8" + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,$1.memop,$1.signed,false,false,bit64_of_int $7,Set64,var64.datasize) } + + /* LDR/LDRSW (literal) */ +/* + | LDSTR wreg COMMA NAME + { if not $1.lit32 then error_arg "unrecognised instruction" + else if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Wt>, <label>") + else `AArch64LoadLiteral($2,MemOp_LOAD,$1.signed,4,(* FIXME: label *),DataSize32) } + | LDSTR xreg COMMA NAME + { match $1.lit64 with + | None -> error_arg "unrecognised instruction" + | Some lit64 -> + if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xt>, <label>") + else `AArch64LoadLiteral($2,MemOp_LOAD,$1.signed,lit64.size,(* FIXME: label *),lit64.datasize) } +*/ + + /* LDR/LDRB/LDRH/LDRSB/LDRSH/LDRSW/STR/STRB/STRH (register) */ /* FIXME: the combination of extend and amount is not clear in ARM */ + + | LDSTR wreg COMMA LBRK xreg COMMA wreg COMMA EXTEND RBRK + { match $1.var32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + | Some var32 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9._type = ExtendType_UXTW || $9._type = ExtendType_SXTW) then error_arg "<extend> must be one of UXTW,SXTW" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,$9._type,0,Set32,var32.datasize) } + | LDSTR wreg COMMA LBRK xreg COMMA xreg RBRK + { match $1.var32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + | Some var32 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>]") + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,ExtendType_UXTX,0,Set32,var32.datasize) } + | LDSTR wreg COMMA LBRK xreg COMMA xreg COMMA EXTEND RBRK + { match $1.var32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + | Some var32 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9._type = ExtendType_SXTX) then error_arg "<extend> must be one of LSL,SXTX" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,$9._type,0,Set32,var32.datasize) } + | LDSTR wreg COMMA LBRK xreg COMMA xreg COMMA SHIFT RBRK + { match $1.var32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + | Some var32 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of LSL,SXTX" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,ExtendType_UXTX,0,Set32,var32.datasize) } + | LDSTR wreg COMMA LBRK xreg COMMA xreg COMMA SHIFT imm RBRK + { match $1.var32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + | Some var32 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of LSL,SXTX" + else if var32.datasize = DataSize8 && not ($10 = 0) then error_arg "<amount> must be 0" + else if var32.datasize = DataSize16 && not ($10 = 0 || $10 = 1) then error_arg "<amount> must be one of 0,1" + else if var32.datasize = DataSize32 && not ($10 = 0 || $10 = 2) then error_arg "<amount> must be one of 0,2" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,ExtendType_UXTX,$10,Set32,var32.datasize) } + + | LDSTR xreg COMMA LBRK xreg COMMA wreg COMMA EXTEND RBRK + { match $1.var64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + | Some var64 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9._type = ExtendType_UXTW || $9._type = ExtendType_SXTW) then error_arg "<extend> must be one of UXTW,SXTW" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,$9._type,0,Set64,var64.datasize) } + | LDSTR xreg COMMA LBRK xreg COMMA xreg RBRK + { match $1.var64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>]") + | Some var64 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>]") + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,ExtendType_UXTX,0,Set64,var64.datasize) } + | LDSTR xreg COMMA LBRK xreg COMMA xreg COMMA EXTEND RBRK + { match $1.var64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + | Some var64 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9._type = ExtendType_SXTX) then error_arg "<extend> must be one of LSL,SXTX" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,$9._type,0,Set64,var64.datasize) } + | LDSTR xreg COMMA LBRK xreg COMMA xreg COMMA SHIFT RBRK + { match $1.var64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + | Some var64 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of LSL,SXTX" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,ExtendType_UXTX,0,Set64,var64.datasize) } + | LDSTR xreg COMMA LBRK xreg COMMA xreg COMMA SHIFT imm RBRK + { match $1.var64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + | Some var64 -> + if not (isregzr $2 && isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of LSL,SXTX" + else if var64.datasize = DataSize8 && not ($10 = 0) then error_arg "<amount> must be 0" + else if var64.datasize = DataSize16 && not ($10 = 0 || $10 = 1) then error_arg "<amount> must be one of 0,1" + else if var64.datasize = DataSize32 && not ($10 = 0 || $10 = 2) then error_arg "<amount> must be one of 0,2" + else if var64.datasize = DataSize64 && not ($10 = 0 || $10 = 3) then error_arg "<amount> must be one of 0,3" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,$1.memop,$1.signed,false,false,ExtendType_UXTX,$10,Set64,var64.datasize) } + + /* LDTR/LDTRB/LDTRH/LDTRSB/LDTRSH/LDTRSW + LDUR/LDURB/LDURH/LDURSB/LDURSH/LDURSW + STTR/STTRB/STTRH + STUR/STURB/STURH */ + + | LDSTTUR wreg COMMA LBRK xreg RBRK + { match $1.off32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{, #<simm>}]") + | Some off32 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{, #<simm>}]") + else `AArch64LoadImmediate($5,$2,$1.acctype,$1.memop,$1.signed,false,false,bit64_of_int 0,Set32,off32.datasize) } + | LDSTTUR wreg COMMA LBRK xreg COMMA imm RBRK + { match $1.off32 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{, #<simm>}]") + | Some off32 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{, #<simm>}]") + else if not (-256 <= $7 && $7 <= 255) then error_arg "<simm> must be in the range -256 to 255" + else `AArch64LoadImmediate($5,$2,$1.acctype,$1.memop,$1.signed,false,false,bit64_of_int $7,Set32,off32.datasize) } + | LDSTTUR xreg COMMA LBRK xreg RBRK + { match $1.off64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{, #<simm>}]") + | Some off64 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{, #<simm>}]") + else `AArch64LoadImmediate($5,$2,$1.acctype,$1.memop,$1.signed,false,false,bit64_of_int 0,Set64,off64.datasize) } + | LDSTTUR xreg COMMA LBRK xreg COMMA imm RBRK + { match $1.off64 with + | None -> error_registers ("expected " ^ $1.txt ^ " <Wt>, [<Xn|SP>{, #<simm>}]") + | Some off64 -> + if not (isregzr $2 && isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <Xt>, [<Xn|SP>{, #<simm>}]") + else if not (-256 <= $7 && $7 <= 255) then error_arg "<simm> must be in the range -256 to 255" + else `AArch64LoadImmediate($5,$2,$1.acctype,$1.memop,$1.signed,false,false,bit64_of_int $7,Set64,off64.datasize) } + + /* MADD/MSUB */ + + | MADDSUB wreg COMMA wreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6 && isregzr $8) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>, <Wa>") + else `AArch64MultiplyAddSub($2,$4,$6,$8,Set32,DataSize32,$1.sub_op) } + | MADDSUB xreg COMMA xreg COMMA xreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6 && isregzr $8) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>, <Xa>") + else `AArch64MultiplyAddSub($2,$4,$6,$8,Set64,DataSize64,$1.sub_op) } + + /* MUL/MNEG alias of MADD/MSUB */ + + | MUL wreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>") + else `AArch64MultiplyAddSub($2,$4,$6,W ZR,Set32,DataSize32,$1.sub_op) } + | MUL xreg COMMA xreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>") + else `AArch64MultiplyAddSub($2,$4,$6,X ZR,Set64,DataSize64,$1.sub_op) } + + /* MOV (to/from SP) alias of ADD (immediate) */ + + | MOV wreg COMMA wreg + { if not (isregsp $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Wd|WSP>, <Wn|WSP>") + else `AArch64AddSubImmediate($2,$4,Set32,false,false,reg_size_bits_R32_of_int 0) } + | MOV xreg COMMA xreg + { if not (isregsp $2 && isregsp $4) then error_registers ("expected " ^ $1.txt ^ " <Xd|SP>, <Xn|SP>") + else `AArch64AddSubImmediate($2,$4,Set64,false,false,reg_size_bits_R64_of_int 0) } + + /* MOV (... immediate) alias of MOVZ/MOVN/ORR */ + + | MOV wreg COMMA imm + { if issp $2 then + begin + (* bitmask immediate *) + match encodeBitMasks 32 (Nat_big_num.of_int $4) with + | Some _ -> `AArch64LogicalImmediate($2,W ZR,Set32,false,LogicalOp_ORR,reg_size_bits_R32_of_int $4) + | None -> error_arg "<imm> can not be encoded" + end + else if not (iskbituimm 32 $4) then error_arg "<imm> must be a 32-bit unsigned immediate" + else if $4 land 0xffff0000 = 0 then + (* wide immediate *) + `AArch64MoveWide($2,Set32,$4,0,MoveWideOp_Z) + else if $4 land 0x0000ffff = 0 then + (* wide immediate *) + `AArch64MoveWide($2,Set32,$4 lsr 16,16,MoveWideOp_Z) + else if (lnot $4) land 0xffff0000 = 0 then + (* inverted wide immediate *) + `AArch64MoveWide($2,Set32,lnot $4,0,MoveWideOp_N) + else if (lnot $4) land 0x0000ffff = 0 then + (* inverted wide immediate *) + `AArch64MoveWide($2,Set32,(lnot $4) lsr 16,16,MoveWideOp_N) + else + (* bitmask immediate *) + match encodeBitMasks 32 (Nat_big_num.of_int $4) with + | Some _ -> `AArch64LogicalImmediate($2,W ZR,Set32,false,LogicalOp_ORR,reg_size_bits_R32_of_int $4) + | None -> error_arg "<imm> can not be encoded" } + | MOV xreg COMMA big_imm + { if issp $2 then + begin + (* bitmask immediate *) + match encodeBitMasks 64 $4 with + | Some _ -> `AArch64LogicalImmediate($2,X ZR,Set64,false,LogicalOp_ORR,reg_size_bits_R64_of_big_int $4) + | None -> error_arg "<imm> can not be encoded" + end + else if not (big_iskbituimm 64 $4) then error_arg "<imm> must be a 64-bit unsigned immediate" + else if check_bits $4 0 16 then + (* wide immediate *) + `AArch64MoveWide($2,Set64,Nat_big_num.to_int $4,0,MoveWideOp_Z) + else if check_bits $4 16 16 then + (* wide immediate *) + `AArch64MoveWide($2,Set64,Nat_big_num.to_int (Nat_big_num.extract_num $4 16 16),16,MoveWideOp_Z) + else if check_bits $4 32 16 then + (* wide immediate *) + `AArch64MoveWide($2,Set64,Nat_big_num.to_int (Nat_big_num.extract_num $4 32 16),32,MoveWideOp_Z) + else if check_bits $4 48 16 then + (* wide immediate *) + `AArch64MoveWide($2,Set64,Nat_big_num.to_int (Nat_big_num.extract_num $4 48 16),48,MoveWideOp_Z) + else + begin + let not_imm = (* the following should negate the first 64 bits of $4 + by doing 0xffffffffffffffff - $4 *) + Nat_big_num.sub + (Nat_big_num.pred (Nat_big_num.shift_left (Nat_big_num.of_int 1) 64)) + $4 in + if check_bits not_imm 0 16 then + (* inverted wide immediate *) + `AArch64MoveWide($2,Set64,Nat_big_num.to_int not_imm,0,MoveWideOp_N) + else if check_bits not_imm 16 16 then + (* inverted wide immediate *) + `AArch64MoveWide($2,Set64,Nat_big_num.to_int (Nat_big_num.extract_num not_imm 16 16),16,MoveWideOp_N) + else if check_bits not_imm 32 16 then + (* inverted wide immediate *) + `AArch64MoveWide($2,Set64,Nat_big_num.to_int (Nat_big_num.extract_num not_imm 32 16),32,MoveWideOp_N) + else if check_bits not_imm 48 16 then + (* inverted wide immediate *) + `AArch64MoveWide($2,Set64,Nat_big_num.to_int (Nat_big_num.extract_num not_imm 48 16),48,MoveWideOp_N) + else + (* bitmask immediate *) + match encodeBitMasks 64 $4 with + | Some _ -> `AArch64LogicalImmediate($2,X ZR,Set64,false,LogicalOp_ORR,reg_size_bits_R64_of_big_int $4) + | None -> error_arg "<imm> can not be encoded" + end} + + /* MOV (register) alias of ORR (shifted register) */ + + | MOV wreg COMMA wreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wm>") + else `AArch64LogicalShiftedRegister($2,W ZR,$4,Set32,false,LogicalOp_ORR,ShiftType_LSL,0,false) } + | MOV xreg COMMA xreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xm>") + else `AArch64LogicalShiftedRegister($2,X ZR,$4,Set64,false,LogicalOp_ORR,ShiftType_LSL,0,false) } + + /* MOVK/MOVN/MOVZ */ + + | MOVWIDE wreg COMMA imm + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Wd>, #<imm>{, LSL #<shift>}") + else if not (0 <= $4 && $4 <= 65535) then error_arg "<imm> must be in the range 0 to 65535" + else `AArch64MoveWide($2,Set32,$4,0,$1.opcode) } + | MOVWIDE wreg COMMA imm COMMA SHIFT imm + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Wd>, #<imm>{, LSL #<shift>}") + else if not (0 <= $4 && $4 <= 65535) then error_arg "<imm> must be in the range 0 to 65535" + else if not ($6.shift_type = ShiftType_LSL) then error_arg "must be LSL" + else if not ($7 = 0 || $7 = 16) then error_arg "<shift> must be one of 0,16" + else `AArch64MoveWide($2,Set32,$4,$7,$1.opcode) } + | MOVWIDE xreg COMMA imm + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xd>, #<imm>{, LSL #<shift>}") + else if not (0 <= $4 && $4 <= 65535) then error_arg "<imm> must be in the range 0 to 65535" + else `AArch64MoveWide($2,Set64,$4,0,$1.opcode) } + | MOVWIDE xreg COMMA imm COMMA SHIFT imm + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xd>, #<imm>{, LSL #<shift>}") + else if not (0 <= $4 && $4 <= 65535) then error_arg "<imm> must be in the range 0 to 65535" + else if not ($6.shift_type = ShiftType_LSL) then error_arg "must be LSL" + else if not ($7 = 0 || $7 = 16 || $7 = 32 || $7 = 48) then error_arg "<shift> must be one of 0,16,32,48" + else `AArch64MoveWide($2,Set64,$4,$7,$1.opcode) } + + /* MVN alias of ORN (shifted register) */ + + | MVN wreg COMMA wreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wm>{, <shift> #<amount>}") + else `AArch64LogicalShiftedRegister($2,W ZR,$4,Set32,false,LogicalOp_ORR,ShiftType_LSL,0,true) } + | MVN wreg COMMA wreg COMMA SHIFT imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wm>{, <shift> #<amount>}") + else if not (0 <= $7 && $7 <= 31) then error_arg "<amount> must be in the range 0 to 31" + else `AArch64LogicalShiftedRegister($2,W ZR,$4,Set32,false,LogicalOp_ORR,$6.shift_type,$7,true) } + | MVN xreg COMMA xreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xm>{, <shift> #<amount>}") + else `AArch64LogicalShiftedRegister($2,X ZR,$4,Set64,false,LogicalOp_ORR,ShiftType_LSL,0,true) } + | MVN xreg COMMA xreg COMMA SHIFT imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xm>{, <shift> #<amount>}") + else if not (0 <= $7 && $7 <= 63) then error_arg "<amount> must be in the range 0 to 63" + else `AArch64LogicalShiftedRegister($2,X ZR,$4,Set64,false,LogicalOp_ORR,$6.shift_type,$7,true) } + + /* NEG/NEGS (shifted register) alias of SUB/SUBS (shifted register) */ + + | NEG wreg COMMA wreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wm>{, <shift> #<amount>}") + else `AArch64AddSubShiftedRegister($2,W ZR,$4,Set32,true,$1.setflags,ShiftType_LSL,0) } + | NEG wreg COMMA wreg COMMA SHIFT imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wm>{, <shift> #<amount>}") + else if $6.shift_type = ShiftType_ROR then error_arg "<shift> must be one of LSL,LSR,ASR" + else if not (0 <= $7 && $7 <= 31) then error_arg "<amount> must be in the range 0 to 31" + else `AArch64AddSubShiftedRegister($2,W ZR,$4,Set32,true,$1.setflags,$6.shift_type,0) } + | NEG xreg COMMA xreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xm>{, <shift> #<amount>}") + else `AArch64AddSubShiftedRegister($2,X ZR,$4,Set64,true,$1.setflags,ShiftType_LSL,0) } + | NEG xreg COMMA xreg COMMA SHIFT imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xm>{, <shift> #<amount>}") + else if $6.shift_type = ShiftType_ROR then error_arg "<shift> must be one of LSL,LSR,ASR" + else if not (0 <= $7 && $7 <= 63) then error_arg "<amount> must be in the range 0 to 63" + else `AArch64AddSubShiftedRegister($2,X ZR,$4,Set64,true,$1.setflags,$6.shift_type,$7) } + + /* NGC/NGCS alias of SBC/SBCS */ + + | NGC wreg COMMA wreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wm>") + else `AArch64AddSubCarry ($2,W ZR,$4,Set32,true,$1.setflags) } + | NGC xreg COMMA xreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xm>") + else `AArch64AddSubCarry ($2,X ZR,$4,Set64,true,$1.setflags) } + + /* NOP alias of HINT */ + + | NOP + { `AArch64Hint(SystemHintOp_NOP) } + + /* PRFM (immediate) */ + + | PRFM PRFOP COMMA LBRK xreg RBRK + { if not (isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>{, #<pimm>}]") + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,MemOp_PREFETCH,false,false,false,bit64_of_int 0,Set64,DataSize64) } + | PRFM PRFOP COMMA LBRK xreg COMMA imm RBRK + { if not (isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>{, #<pimm>}]") + else if not (0 <= $7 && $7 <= 32760) then error_arg "<pimm> must be in the range 0 to 32760" + else if not ($7 mod 8 = 0) then error_arg "<pimm> must be a multiple of 8" + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,MemOp_PREFETCH,false,false,false,bit64_of_int $7,Set64,DataSize64) } + | PRFM imm COMMA LBRK xreg RBRK + { if not (isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>{, #<pimm>}]") + else if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else `AArch64LoadImmediate($5,X (Ireg (ireg_of_int $2)),AccType_NORMAL,MemOp_PREFETCH,false,false,false,bit64_of_int 0,Set64,DataSize64) } + | PRFM imm COMMA LBRK xreg COMMA imm RBRK + { if not (isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>{, #<pimm>}]") + else if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else if not (0 <= $7 && $7 <= 32760) then error_arg "<pimm> must be in the range 0 to 32760" + else if not ($7 mod 8 = 0) then error_arg "<pimm> must be a multiple of 8" + else `AArch64LoadImmediate($5,X (Ireg (ireg_of_int $2)),AccType_NORMAL,MemOp_PREFETCH,false,false,false,bit64_of_int $7,Set64,DataSize64) } + + /* PRFM (literal) */ +/* + | PRFM PRFOP COMMA NAME + { `AArch64LoadLiteral($2,MemOp_PREFETCH,false,0,(* FIXME: label *),DataSize32) } + | PRFM imm COMMA NAME + { if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else `AArch64LoadLiteral(X (Ireg (ireg_of_int $2)),MemOp_PREFETCH,false,0,(* FIXME: label *),DataSize32) } +*/ + + /* PRFM (register) */ + + | PRFM PRFOP COMMA LBRK xreg COMMA wreg COMMA EXTEND RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9._type = ExtendType_UXTW || $9._type = ExtendType_SXTW) then error_arg "<extend> must be one of UXTW,SXTW" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,$9._type,0,Set32,DataSize64) } + | PRFM PRFOP COMMA LBRK xreg COMMA xreg RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,ExtendType_UXTX,0,Set32,DataSize64) } + | PRFM PRFOP COMMA LBRK xreg COMMA xreg COMMA EXTEND RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9._type = ExtendType_SXTX) then error_arg "<extend> must be one of LSL,SXTX" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,$9._type,0,Set32,DataSize64) } + | PRFM PRFOP COMMA LBRK xreg COMMA xreg COMMA SHIFT RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of LSL,SXTX" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,ExtendType_UXTX,0,Set32,DataSize64) } + | PRFM PRFOP COMMA LBRK xreg COMMA xreg COMMA SHIFT imm RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($9.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of LSL,SXTX" + else if not ($10 = 0 || $10 = 3) then error_arg "<amount> must be one of 0,3" + else `AArch64LoadRegister($5,$2,$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,ExtendType_UXTX,$10,Set32,DataSize64) } + + | PRFM imm COMMA LBRK xreg COMMA wreg COMMA EXTEND RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else if not ($9._type = ExtendType_UXTW || $9._type = ExtendType_SXTW) then error_arg "<extend> must be one of UXTW,SXTW" + else `AArch64LoadRegister($5,X (Ireg (ireg_of_int $2)),$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,$9._type,0,Set32,DataSize64) } + | PRFM imm COMMA LBRK xreg COMMA xreg RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else `AArch64LoadRegister($5,X (Ireg (ireg_of_int $2)),$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,ExtendType_UXTX,0,Set32,DataSize64) } + | PRFM imm COMMA LBRK xreg COMMA xreg COMMA EXTEND RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else if not ($9._type = ExtendType_SXTX) then error_arg "<extend> must be one of LSL,SXTX" + else `AArch64LoadRegister($5,X (Ireg (ireg_of_int $2)),$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,$9._type,0,Set32,DataSize64) } + | PRFM imm COMMA LBRK xreg COMMA xreg COMMA SHIFT RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else if not ($9.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of LSL,SXTX" + else `AArch64LoadRegister($5,X (Ireg (ireg_of_int $2)),$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,ExtendType_UXTX,0,Set32,DataSize64) } + | PRFM imm COMMA LBRK xreg COMMA xreg COMMA SHIFT imm RBRK + { if not (isregsp $5 && isregzr $7) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>, <R><m>{, <extend> {<amount>}}]") + else if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else if not ($9.shift_type = ShiftType_LSL) then error_arg "<extend> must be one of LSL,SXTX" + else if not ($10 = 0 || $10 = 3) then error_arg "<amount> must be one of 0,3" + else `AArch64LoadRegister($5,X (Ireg (ireg_of_int $2)),$7,AccType_NORMAL,MemOp_PREFETCH,false,false,false,ExtendType_UXTX,$10,Set32,DataSize64) } + + /* PRFUM */ + + | PRFUM PRFOP COMMA LBRK xreg RBRK + { if not (isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>{, #<simm>}]") + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,MemOp_PREFETCH,false,false,false,bit64_of_int 0,Set64,DataSize64) } + | PRFUM PRFOP COMMA LBRK xreg COMMA imm RBRK + { if not (isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>{, #<simm>}]") + else if not (-256 <= $7 && $7 <= 255) then error_arg "<simm> must be in the range -256 to 255" + else `AArch64LoadImmediate($5,$2,AccType_NORMAL,MemOp_PREFETCH,false,false,false,bit64_of_int $7,Set64,DataSize64) } + | PRFUM imm COMMA LBRK xreg RBRK + { if not (isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>{, #<simm>}]") + else if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else `AArch64LoadImmediate($5,X (Ireg (ireg_of_int $2)),AccType_NORMAL,MemOp_PREFETCH,false,false,false,bit64_of_int 0,Set64,DataSize64) } + | PRFUM imm COMMA LBRK xreg COMMA imm RBRK + { if not (isregsp $5) then error_registers ("expected " ^ $1.txt ^ " <prfop>, [<Xn|SP>{, #<simm>}]") + else if not ($2 = 6 || $2 = 7 || $2 = 14 || $2 = 15 || (22 <= $2 && $2 <= 31)) then error_arg "<prfop> must be one of 6,7,14,15,22-31" + else if not (-256 <= $7 && $7 <= 255) then error_arg "<simm> must be in the range -256 to 255" + else `AArch64LoadImmediate($5,X (Ireg (ireg_of_int $2)),AccType_NORMAL,MemOp_PREFETCH,false,false,false,bit64_of_int $7,Set64,DataSize64) } + + /* RET */ + + | RET + { `AArch64BranchRegister(X (Ireg R30),BranchType_RET) } + | RET xreg + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " {<Xn>}") + else `AArch64BranchRegister($2,BranchType_RET) } + + /* RBIT/REV/REV16/REV32 */ + + | REV wreg COMMA wreg + { match $1.op32 with + | None -> error_arg "unrecognised instruction" + | Some op -> + if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>") + else `AArch64Reverse($2,$4,Set32,op) } + | REV xreg COMMA xreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>") + else `AArch64Reverse($2,$4,Set64,$1.op64) } + + /* SBFIZ/UBFIZ alias of SBFM/UBFM */ + + | BFIZ wreg COMMA wreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, #<lsb>, #<width>") + else if not (0 <= $6 && $6 <= 31) then error_arg "<lsb> must be in the range 0 to 31" + else if not (1 <= $8 && $8 <= (32 - $6)) then error_arg "<width> must be in the range 1 to 32-<lsb>" + else + let (wmask,tmask) = decodeBitMasks 32 0 ($8 - 1) (-$6 mod 32) false in + `AArch64BitfieldMove($2,$4,Set32,true,$1.extend,-$6 mod 32,$8 - 1,reg_size_bits_R32_of_big_int wmask,reg_size_bits_R32_of_big_int tmask) } + | BFIZ xreg COMMA xreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, #<lsb>, #<width>") + else if not (0 <= $6 && $6 <= 63) then error_arg "<lsb> must be in the range 0 to 63" + else if not (1 <= $8 && $8 <= (64 - $6)) then error_arg "<width> must be in the range 1 to 64-<lsb>" + else + let (wmask,tmask) = decodeBitMasks 64 1 ($8 - 1) (-$6 mod 64) false in + `AArch64BitfieldMove($2,$4,Set64,true,$1.extend,-$6 mod 64,$8 - 1,reg_size_bits_R64_of_big_int wmask,reg_size_bits_R64_of_big_int tmask) } + + /* SBFX/UBFX alias of SBFM/UBFM */ + + | BFX wreg COMMA wreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, #<lsb>, #<width>") + else if not (0 <= $6 && $6 <= 31) then error_arg "<lsb> must be in the range 0 to 31" + else if not (1 <= $8 && $8 <= (32 - $6)) then error_arg "<width> must be in the range 1 to 32-<lsb>" + else + let (wmask,tmask) = decodeBitMasks 32 0 ($6 + $8 - 1) $6 false in + `AArch64BitfieldMove($2,$4,Set32,true,$1.extend,$6,$6 + $8 - 1,reg_size_bits_R32_of_big_int wmask,reg_size_bits_R32_of_big_int tmask) } + | BFX xreg COMMA xreg COMMA imm COMMA imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, #<lsb>, #<width>") + else if not (0 <= $6 && $6 <= 63) then error_arg "<lsb> must be in the range 0 to 63" + else if not (1 <= $8 && $8 <= (64 - $6)) then error_arg "<width> must be in the range 1 to 64-<lsb>" + else + let (wmask,tmask) = decodeBitMasks 64 1 ($6 + $8 - 1) $6 false in + `AArch64BitfieldMove($2,$4,Set64,true,$1.extend,$6,$6 + $8 - 1,reg_size_bits_R64_of_big_int wmask,reg_size_bits_R64_of_big_int tmask) } + + /* SDIV/UDIV */ + + | DIV wreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>, <Wm>") + else `AArch64Division($2,$4,$6,Set32,$1.unsigned) } + | DIV xreg COMMA xreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>") + else `AArch64Division($2,$4,$6,Set64,$1.unsigned) } + + /* SMADDL/SMSUBL/UMADDL/UMSUBL */ + + | MADDSUBL xreg COMMA wreg COMMA wreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6 && isregzr $8) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Wn>, <Wm>, <Xa>") + else `AArch64MultiplyAddSubLong($2,$4,$6,$8,Set64,DataSize32,$1.sub_op,$1.unsigned) } + + /* SMNEGL/UMNEGL alias of SMSUBL/UMSUBL */ + + | MNEGL xreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Wn>, <Wm>") + else `AArch64MultiplyAddSubLong($2,$4,$6,X ZR,Set64,DataSize32,true,$1.unsigned) } + + /* SMULH/UMULH */ + + | MULH xreg COMMA xreg COMMA xreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Xn>, <Xm>") + else `AArch64MultiplyHigh($2,$4,$6,X ZR,Set64,DataSize64,$1.unsigned) } + + /* SMULL/UMULL alias of SMADDL/UMADDL */ + + | MULL xreg COMMA wreg COMMA wreg + { if not (isregzr $2 && isregzr $4 && isregzr $6) then error_registers ("expected " ^ $1.txt ^ " <Xd>, <Wn>, <Wm>") + else `AArch64MultiplyAddSubLong($2,$4,$6,X ZR,Set64,DataSize32,false,$1.unsigned) } + + /* SXTB/SXTH/SXTW alias of SBFM + UXTB/UXTH alias of UBFM */ + + | EXTEND wreg COMMA wreg + { match $1.inst with + | None -> error_not_instruction $1.txt + | Some inst -> + if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>") + else + let (wmask,tmask) = decodeBitMasks 32 0 7 0 false in + `AArch64BitfieldMove($2,$4,Set32,true,inst.extend,0,7,reg_size_bits_R32_of_big_int wmask,reg_size_bits_R32_of_big_int tmask) } + | EXTEND xreg COMMA wreg + { match $1.inst with + | None -> error_not_instruction $1.txt + | Some inst -> + if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wd>, <Wn>") + else + let (wmask,tmask) = decodeBitMasks 64 1 7 0 false in + `AArch64BitfieldMove($2,$4,Set64,true,inst.extend,0,7,reg_size_bits_R64_of_big_int wmask,reg_size_bits_R64_of_big_int tmask) } + + /* TBZ/TBNZ */ +/* + | TBZ wreg COMMA imm COMMA NAME + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <R><t>, #<imm>, <label>") + else if not (0 <= $4 && $4 <= 31) then error_arg "<imm> must be in the range 0 to 31" + else `AArch64TestBitAndBranch($2,Set32,$4,$1.bit_val,(* FIXME: label *)) } + | TBZ xreg COMMA imm COMMA NAME + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <R><t>, #<imm>, <label>") + else if not (0 <= $4 && $4 <= 63) then error_arg "<imm> must be in the range 0 to 63" + else `AArch64TestBitAndBranch($2,Set64,$4,$1.bit_val,(* FIXME: label *)) } +*/ + + /* TST (immediate) alias of ANDS (immediate) */ + + | TST wreg COMMA big_imm + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Wd>, #<imm>") + else match encodeBitMasks 32 $4 with + | None -> error_arg "<imm> can not be encoded as bitmask" + | _ -> `AArch64LogicalImmediate(W ZR,$2,Set32,true,LogicalOp_AND,reg_size_bits_R32_of_big_int $4) } + | TST xreg COMMA big_imm + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xd>, #<imm>") + else match encodeBitMasks 64 $4 with + | None -> error_arg "<imm> can not be encoded as bitmask" + | _ -> `AArch64LogicalImmediate(X ZR,$2,Set64,true,LogicalOp_AND,reg_size_bits_R64_of_big_int $4) } + + /* TST (shifted register) alias of ANDS (shifted register) */ + + | TST wreg COMMA wreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wn>, <Wm>{, <shift> #<amount>}") + else `AArch64LogicalShiftedRegister(W ZR,$2,$4,Set32,true,LogicalOp_AND,ShiftType_LSL,0,false) } + | TST wreg COMMA wreg COMMA SHIFT imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Wn>, <Wm>{, <shift> #<amount>}") + else if not (0 <= $7 && $7 <= 31) then error_arg "<amount> must be in the range 0 to 31" + else `AArch64LogicalShiftedRegister(W ZR,$2,$4,Set32,true,LogicalOp_AND,$6.shift_type,$7,false) } + + | TST xreg COMMA xreg + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn>, <Xm>{, <shift> #<amount>}") + else `AArch64LogicalShiftedRegister(X ZR,$2,$4,Set64,true,LogicalOp_AND,ShiftType_LSL,0,false) } + | TST xreg COMMA xreg COMMA SHIFT imm + { if not (isregzr $2 && isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <Xn>, <Xm>{, <shift> #<amount>}") + else if not (0 <= $7 && $7 <= 63) then error_arg "<amount> must be in the range 0 to 63" + else `AArch64LogicalShiftedRegister(X ZR,$2,$4,Set64,true,LogicalOp_AND,$6.shift_type,$7,false) } + + /* MRS */ + + | MRS xreg COMMA SYSREG + { if not (isregzr $2) then error_registers ("expected " ^ $1.txt ^ " <Xt>, <systemreg>") + else `AArch64MoveSystemRegister($2,$4.sys_op0,$4.sys_op1,$4.sys_op2,$4.sys_crn,$4.sys_crm,true) } + + /* MSR (immediate) */ + + | MSR PSTATEFIELD COMMA imm + { if not (0 <= $4 && $4 <= 15) then error_arg "<imm> must be in the range 0 to 15" + else `AArch64MoveSystemImmediate($4,$2) } + + /* MSR (register) */ + + | MSR SYSREG COMMA xreg + { if not (isregzr $4) then error_registers ("expected " ^ $1.txt ^ " <systemreg>, <Xt>") + else `AArch64MoveSystemRegister($4,$2.sys_op0,$2.sys_op1,$2.sys_op2,$2.sys_crn,$2.sys_crm,false) } diff --git a/arm/gen/pretty.hgen b/arm/gen/pretty.hgen new file mode 100644 index 00000000..2bbf7af7 --- /dev/null +++ b/arm/gen/pretty.hgen @@ -0,0 +1,393 @@ +| `AArch64TMStart t -> + sprintf "TSTART %s" (pp_regzr Set64 t) + +| `AArch64TMCommit -> "TCOMMIT" + +| `AArch64TMAbort (retry,reason) -> + sprintf "TABORT %s" (pp_imm (if retry then 32 + reason else reason)) + +| `AArch64TMTest -> "TTEST" + +| `AArch64ImplementationDefinedStopFetching -> + "_STOP_FETCHING" + +| `AArch64ImplementationDefinedThreadStart -> + "_THREAD_START" + +| `AArch64ImplementationDefinedTestBeginEnd (isEnd) -> + if isEnd then + "_TEST_ENDS" + else + "_TEST_BEGINS" + +| `AArch64AddSubCarry (d,n,m,datasize,sub_op,setflags) -> + if sub_op && is_zero_reg n then + sprintf "%s %s,%s" (pp_withflags "NGC" setflags) (pp_regzr datasize d) (pp_regzr datasize m) + else if sub_op then + sprintf "%s %s,%s,%s" (pp_withflags "SBC" setflags) (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) + else + sprintf "%s %s,%s,%s" (pp_withflags "ADC" setflags) (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) + +| `AArch64AddSubExtendRegister (d,n,m,datasize,sub_op,setflags,extend_type,shift) -> + if setflags && is_zero_reg d then + begin + if (is_sp_reg n) && ((datasize = Set32 && extend_type = ExtendType_UXTW) || (datasize = Set64 && extend_type = ExtendType_UXTX)) then + sprintf "%s %s,%s%s" (if sub_op then "CMP" else "CMN") (pp_regsp datasize n) (pp_regzrbyext datasize extend_type m) + (if shift = 0 then "" else (",LSL " ^ (pp_imm shift))) + else + sprintf "%s %s,%s%s" (if sub_op then "CMP" else "CMN") (pp_regsp datasize n) (pp_regzrbyext datasize extend_type m) (pp_addsub_regext datasize extend_type shift) + end + else if (is_sp_reg d || is_sp_reg n) && ((datasize = Set32 && extend_type = ExtendType_UXTW) || (datasize = Set64 && extend_type = ExtendType_UXTX)) then + sprintf "%s %s,%s,%s%s" (pp_addsub sub_op setflags) (if setflags then pp_regzr datasize d else pp_regsp datasize d) (pp_regsp datasize n) (pp_regzrbyext datasize extend_type m) + (if shift = 0 then "" else (",LSL " ^ (pp_imm shift))) + else + sprintf "%s %s,%s,%s%s" (pp_addsub sub_op setflags) (if setflags then pp_regzr datasize d else pp_regsp datasize d) (pp_regsp datasize n) (pp_regzrbyext datasize extend_type m) (pp_addsub_regext datasize extend_type shift) + +| `AArch64AddSubImmediate (d,n,datasize,sub_op,setflags,imm) -> + let (imm12,shift) = + if reg_size_bits_iskbituimm 12 imm then (reg_size_bits_to_int imm, 0) + else (reg_size_bits_to_int (reg_size_bits_shift_right imm 12), 12) + in + if (sub_op,setflags) = (false,false) && (is_sp_reg d || is_sp_reg n) && (shift = 0 && imm12 = 0) then + sprintf "MOV %s,%s" (pp_regsp datasize d) (pp_regsp datasize n) + else if setflags && is_zero_reg d then + sprintf "%s %s,%s%s" (if sub_op then "CMP" else "CMN") (pp_regsp datasize n) (pp_imm imm12) (if shift = 0 then "" else ",LSL #12") + else + sprintf "%s %s,%s,%s%s" (pp_addsub sub_op setflags) (if setflags then pp_regzr datasize d else pp_regsp datasize d) (pp_regsp datasize n) (pp_imm imm12) (if shift = 0 then "" else ",LSL #12") + +| `AArch64AddSubShiftedRegister (d,n,m,datasize,sub_op,setflags,shift_type,shift_amount) -> + if setflags && is_zero_reg d then + begin + if shift_type = ShiftType_LSL && shift_amount = 0 then + sprintf "%s %s,%s" (if sub_op then "CMP" else "CMN") (pp_regzr datasize n) (pp_regzr datasize m) + else + sprintf "%s %s,%s,%s %s" (if sub_op then "CMP" else "CMN") (pp_regzr datasize n) (pp_regzr datasize m) (pp_shift shift_type) (pp_imm shift_amount) + end + else if sub_op && is_zero_reg n then + begin + if shift_type = ShiftType_LSL && shift_amount = 0 then + sprintf "%s %s,%s" (pp_withflags "NEG" setflags) (pp_regzr datasize d) (pp_regzr datasize m) + else + sprintf "%s %s,%s,%s %s" (pp_withflags "NEG" setflags) (pp_regzr datasize d) (pp_regzr datasize m) (pp_shift shift_type) (pp_imm shift_amount) + end + else if shift_type = ShiftType_LSL && shift_amount = 0 then + sprintf "%s %s,%s,%s" (pp_addsub sub_op setflags) (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) + else + sprintf "%s %s,%s,%s,%s %s" (pp_addsub sub_op setflags) (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) (pp_shift shift_type) (pp_imm shift_amount) + +| `AArch64Address (d,page,imm) -> + sprintf "%s %s,%s" (if page then "ADRP" else "ADR") (pp_regzr Set64 d) (pp_offset page imm) + +| `AArch64LogicalImmediate (d,n,datasize,setflags,op,imm) -> + if op = LogicalOp_AND && setflags && is_zero_reg d then + sprintf "TST %s,%s" (pp_regzr datasize n) (pp_reg_size_imm imm) + else if op = LogicalOp_ORR && not setflags && is_zero_reg n && not (moveWidePreferred datasize imm) then (* ARM: missing the check of n=ZR *) + sprintf "MOV %s,%s" (pp_regsp datasize d) (pp_reg_size_imm imm) + else sprintf "%s %s,%s,%s" (pp_logop op setflags false) (if setflags then pp_regzr datasize d else pp_regsp datasize d) (pp_regzr datasize n) (pp_reg_size_imm imm) + +| `AArch64LogicalShiftedRegister (d,n,m,datasize,setflags,op,shift_type,shift_amount,invert) -> + if op = LogicalOp_AND && setflags && not invert && is_zero_reg d then + begin + if shift_type = ShiftType_LSL && shift_amount = 0 then + sprintf "TST %s,%s" (pp_regzr datasize n) (pp_regzr datasize m) + else + sprintf "TST %s,%s,%s %s" (pp_regzr datasize n) (pp_regzr datasize m) (pp_shift shift_type) (pp_imm shift_amount) + end + else if op = LogicalOp_ORR && not setflags && invert && is_zero_reg n then + begin + if shift_type = ShiftType_LSL && shift_amount = 0 then + sprintf "MVN %s,%s" (pp_regzr datasize d) (pp_regzr datasize m) + else + sprintf "MVN %s,%s,%s %s" (pp_regzr datasize d) (pp_regzr datasize m) (pp_shift shift_type) (pp_imm shift_amount) + end + else if op = LogicalOp_ORR && not setflags && not invert && is_zero_reg n && shift_type = ShiftType_LSL && shift_amount = 0 then + sprintf "MOV %s,%s" (pp_regzr datasize d) (pp_regzr datasize m) + else + begin + if shift_type = ShiftType_LSL && shift_amount = 0 then + sprintf "%s %s,%s,%s" (pp_logop op setflags invert) (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) + else + sprintf "%s %s,%s,%s,%s %s" (pp_logop op setflags invert) (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) (pp_shift shift_type) (pp_imm shift_amount) + end + +| `AArch64Shift (d,n,m,datasize,shift_type) -> + sprintf "%s %s,%s,%s" (pp_shiftop shift_type) (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) + +| `AArch64BranchConditional (offset,condition) -> + sprintf "B.%s %s" (pp_cond condition) (pp_offset false offset) + +| `AArch64BranchImmediate (branch_type,offset) -> + sprintf "%s %s" (pp_branchimmediate branch_type) (pp_offset false offset) + +| `AArch64BitfieldMove (d,n,datasize,inzero,extend,_R,_S,wmask,tmask) -> + if (inzero,extend) = (false,false) && _S < _R then + sprintf "BFI %s,%s,%s,%s" (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm _R) (pp_imm (_S+1)) (* FIXME: I'm not sure this is the right translation of imms and immr *) + else if (inzero,extend) = (false,false) && _S >= _R then + sprintf "BFXIL %s,%s,%s,%s" (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm _R) (pp_imm (_S-_R+1)) + else if (inzero,extend) = (true,false) && datasize = Set32 && _S <> 0b011111 && _S+1 = _R then + sprintf "LSL %s,%s,%s" (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm (31-_S)) + else if (inzero,extend) = (true,false) && datasize = Set64 && _S <> 0b111111 && _S+1 = _R then + sprintf "LSL %s,%s,%s" (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm (63-_S)) + else if inzero && datasize = Set32 && _S = 0b011111 then + sprintf "%s %s,%s,%s" (if extend then "ASR" else "LSR") (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm _R) + else if inzero && datasize = Set64 && _S = 0b111111 then + sprintf "%s %s,%s,%s" (if extend then "ASR" else "LSR") (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm _R) + else if inzero && _S < _R then + sprintf "%s %s,%s,%s,%s" (if extend then "SBFIZ" else "UBFIZ") (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm _R) (pp_imm (_S+1)) (* FIXME: -<lsb> MOD 32/64 *) + else if inzero && bFXPreferred datasize (if extend then 0 else 1) _S _R then + sprintf "%s %s,%s,%s,%s" (if extend then "SBFX" else "UBFX") (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm _R) (pp_imm (_S - _R + 1)) + else if inzero && _R = 0 && _S = 0b000111 then + sprintf "%s %s,%s" (if extend then "SXTB" else "UXTB") (pp_regzr datasize d) (pp_regzr Set32 n) + else if inzero && _R = 0 && _S = 0b001111 then + sprintf "%s %s,%s" (if extend then "SXTH" else "UXTH") (pp_regzr datasize d) (pp_regzr Set32 n) + else if (inzero,extend) = (true,true) && _R = 0 && _S = 0b011111 then (* implicitly datasize = Set64 *) + sprintf "SXTW %s,%s" (pp_regzr datasize d) (pp_regzr Set32 n) + else + sprintf "%s %s,%s,%s,%s" (pp_bfm inzero extend) (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm _R) (pp_imm _S) + +| `AArch64BranchRegister (n,branch_type) -> + if branch_type = BranchType_RET && n = X (Ireg R30) then + "RET" + else + sprintf "%s %s" (pp_branchregister branch_type) (pp_regzr Set64 n) + +| `AArch64CompareAndBranch (t,datasize,iszero,offset) -> + sprintf "%s %s,%s" (if iszero then "CBZ" else "CBNZ") (pp_regzr datasize t) (pp_offset false offset) + +| `AArch64ConditionalCompareImmediate (n,datasize,sub_op,condition,flags,imm) -> + sprintf "%s %s,%s,%s,%s" (if sub_op then "CCMP" else "CCMN") (pp_regzr datasize n) (pp_reg_size_imm imm) (pp_imm flags) (pp_cond condition) + +| `AArch64ConditionalCompareRegister (n,m,datasize,sub_op,condition,flags) -> + sprintf "%s %s,%s,%s,%s" (if sub_op then "CCMP" else "CCMN") (pp_regzr datasize n) (pp_regzr datasize m) (pp_imm flags) (pp_cond condition) + +| `AArch64ClearExclusiveMonitor (imm) -> + if imm = 15 then + sprintf "CLREX" + else + sprintf "CLREX %s" (pp_imm imm) + +| `AArch64CountLeading (d,n,datasize,opcode) -> + sprintf "%s %s,%s" (pp_countop opcode) (pp_regzr datasize d) (pp_regzr datasize n) + +| `AArch64CRC (d,n,m,size,crc32c) -> + sprintf "%s %s,%s,%s" (pp_crc size crc32c) (pp_regzr Set32 d) (pp_regzr Set32 n) (pp_regzr (if size = DataSize64 then Set64 else Set32) m) + +| `AArch64ConditionalSelect (d,n,m,datasize,condition,else_inv,else_inc) -> + if not else_inv && else_inc && n = m && not (is_zero_reg n) && not (condition = 0b1110 || condition = 0b1111) then + sprintf "CINC %s,%s,%s" (pp_regzr datasize d) (pp_regzr datasize n) (pp_cond condition) + else if not else_inv && else_inc && n = m && is_zero_reg n && not (condition = 0b1110 || condition = 0b1111) then + sprintf "CSET %s,%s" (pp_regzr datasize d) (pp_cond condition) + else if else_inv && not else_inc && n = m && not (is_zero_reg n) && not (condition = 0b1110 || condition = 0b1111) then + sprintf "CINV %s,%s,%s" (pp_regzr datasize d) (pp_regzr datasize n) (pp_cond condition) + else if else_inv && not else_inc && n = m && is_zero_reg n && not (condition = 0b1110 || condition = 0b1111) then + sprintf "CSETM %s,%s" (pp_regzr datasize d) (pp_cond condition) + else if else_inv && else_inc && n = m && not (condition = 0b1110 || condition = 0b1111) then + sprintf "CNEG %s,%s,%s" (pp_regzr datasize d) (pp_regzr datasize n) (pp_cond condition) + else + sprintf "%s %s,%s,%s,%s" (pp_csel else_inv else_inc) (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) (pp_cond condition) + +| `AArch64Barrier (op,domain,types) -> + if op = MemBarrierOp_ISB && domain = MBReqDomain_FullSystem && types = MBReqTypes_All then + pp_barr op + else + sprintf "%s %s" (pp_barr op) (pp_barroption domain types) + +| `AArch64ExtractRegister (d,n,m,datasize,lsb) -> + if n = m then + sprintf "ROR %s,%s,%s" (pp_regzr datasize d) (pp_regzr datasize n) (pp_imm lsb) + else + sprintf "EXTR %s,%s,%s,%s" (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) (pp_imm lsb) + +| `AArch64Hint (op) -> + begin + match op with + | SystemHintOp_NOP -> "NOP" + | SystemHintOp_YIELD -> "YIELD" + | SystemHintOp_WFE -> "WFE" + | SystemHintOp_WFI -> "WFI" + | SystemHintOp_SEV -> "SEV" + | SystemHintOp_SEVL -> "SEVL" + end + +| `AArch64LoadStoreAcqExc (n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,datasize) -> + if pair && memop = MemOp_LOAD then + sprintf "%s %s,%s,[%s]" (pp_ldaxstlxp memop acctype excl pair datasize) (pp_regzr regsize t) (pp_regzr regsize t2) (pp_regsp Set64 n) + else if pair && memop = MemOp_STORE then + sprintf "%s %s,%s,%s,[%s]" (pp_ldaxstlxp memop acctype excl pair datasize) (pp_regzr Set32 s) (pp_regzr regsize t) (pp_regzr regsize t2) (pp_regsp Set64 n) + else if not pair && memop = MemOp_STORE && excl then + sprintf "%s %s,%s,[%s]" (pp_ldaxstlxp memop acctype excl pair datasize) (pp_regzr Set32 s) (pp_regzr regsize t) (pp_regsp Set64 n) + else + sprintf "%s %s,[%s]" (pp_ldaxstlxp memop acctype excl pair datasize) (pp_regzr regsize t) (pp_regsp Set64 n) + +| `AArch64LoadStorePair (wback,postindex,n,t,t2,acctype,memop,signed,datasize,offset) -> + begin + let inst = if signed then "LDPSW" else if memop = MemOp_LOAD then "LDP" else "STP" in + let regsize = if signed then Set64 else (match datasize with DataSize32 -> Set32 | DataSize64 -> Set64 | DataSize16 | DataSize8 -> failwith "unexpected value") in + match (wback,postindex) with + | (true,true) -> + sprintf "%s %s,%s,[%s],%s" inst (pp_regzr regsize t) (pp_regzr regsize t2) (pp_regsp Set64 n) (pp_big_imm offset) + | (true,false) -> + sprintf "%s %s,%s,[%s,%s]!" inst (pp_regzr regsize t) (pp_regzr regsize t2) (pp_regsp Set64 n) (pp_big_imm offset) + | (false,false) -> + if eq_bit64 offset (bit64_of_int 0) then + sprintf "%s %s,%s,[%s]" inst (pp_regzr regsize t) (pp_regzr regsize t2) (pp_regsp Set64 n) + else + sprintf "%s %s,%s,[%s,%s]" inst (pp_regzr regsize t) (pp_regzr regsize t2) (pp_regsp Set64 n) (pp_big_imm offset) + | (false,true) -> failwith "unexpected value" + end + +| `AArch64LoadImmediate (n,t,acctype,memop,signed,wback,postindex,offset,regsize,datasize) -> + begin + if memop = MemOp_PREFETCH then + begin + (* the ast does not hold enough information to distinguish PRFM and PRFUM in some cases. + PRFM: <pimm> is a multiple of 8 in the range 0 to 32760 + PRFUM: <simm> is in the range -256 to 255 *) + if eq_bit64 offset (bit64_of_int 0) then + sprintf "PRFM %s,[%s]" (pp_prfop (inst_reg_to_int t)) (pp_regsp Set64 n) + else if big_in_range offset (-256) 255 then + sprintf "PRFUM %s,[%s,%s]" (pp_prfop (inst_reg_to_int t)) (pp_regsp Set64 n) (pp_big_imm offset) + else + sprintf "PRFM %s,[%s,%s]" (pp_prfop (inst_reg_to_int t)) (pp_regsp Set64 n) (pp_big_imm offset) + end + else + let inst = + (if memop = MemOp_LOAD then "LD" else "ST") ^ + (if not wback && not postindex && + not begin match datasize with + | DataSize8 -> + Nat_big_num.less_equal Nat_big_num.zero offset && + Nat_big_num.less_equal offset (Nat_big_num.of_int 4095) + | DataSize16 -> + Nat_big_num.less_equal Nat_big_num.zero offset && + Nat_big_num.less_equal offset (Nat_big_num.of_int 8190) && + Nat_big_num.equal + (Nat_big_num.modulus offset (Nat_big_num.of_int 2)) + Nat_big_num.zero + | DataSize32 -> + Nat_big_num.less_equal Nat_big_num.zero offset && + Nat_big_num.less_equal offset (Nat_big_num.of_int 16380) && + Nat_big_num.equal + (Nat_big_num.modulus offset (Nat_big_num.of_int 4)) + Nat_big_num.zero + | DataSize64 -> + Nat_big_num.less_equal Nat_big_num.zero offset && + Nat_big_num.less_equal offset (Nat_big_num.of_int 32760) && + Nat_big_num.equal + (Nat_big_num.modulus offset (Nat_big_num.of_int 8)) + Nat_big_num.zero + end + then + begin + if acctype=AccType_UNPRIV then "TR" + else "UR" + end + else "R") ^ + (if signed then "S" else "") ^ + (match datasize with + | DataSize8 -> "B" + | DataSize16 -> "H" + | DataSize32 -> if regsize = Set32 then "" else "W" + | DataSize64 -> "") in + match (wback,postindex) with + | (true,true) -> + sprintf "%s %s,[%s],%s" inst (pp_regzr regsize t) (pp_regsp Set64 n) (pp_big_imm offset) + | (true,false) -> + sprintf "%s %s,[%s,%s]!" inst (pp_regzr regsize t) (pp_regsp Set64 n) (pp_big_imm offset) + | (false,false) -> + if eq_bit64 offset (bit64_of_int 0) then + sprintf "%s %s,[%s]" inst (pp_regzr regsize t) (pp_regsp Set64 n) + else + sprintf "%s %s,[%s,%s]" inst (pp_regzr regsize t) (pp_regsp Set64 n) (pp_big_imm offset) + | (false,true) -> failwith "unexpected value" + end + +| `AArch64LoadLiteral (t,memop,signed,size,offset,datasize) -> + if memop = MemOp_PREFETCH then + sprintf "PRFM %s,%s" (pp_prfop (inst_reg_to_int t)) (pp_offset false offset) + else + let datasize = + if signed then Set64 + else + begin match datasize with + | DataSize64 -> Set64 + | DataSize32 -> Set32 + | DataSize16 | DataSize8 -> failwith "unexpected value" + end + in + sprintf "%s %s,%s" (if signed then "LDRSW" else "LDR") (pp_regzr datasize t) (pp_offset false offset) + +| `AArch64LoadRegister (n,t,m,acctype,memop,signed,wback,postindex,extend_type,shift,regsize,datasize) -> + begin + if memop = MemOp_PREFETCH then + begin + if extend_type = ExtendType_UXTX && shift = 0 then + sprintf "PRFM %s,[%s,%s]" (pp_prfop (inst_reg_to_int t)) (pp_regsp Set64 n) (pp_regzrbyext Set64 extend_type m) + else if extend_type = ExtendType_UXTX (* && shift <> 0 *) then + sprintf "PRFM %s,[%s,%s,LSL %s]" (pp_prfop (inst_reg_to_int t)) (pp_regsp Set64 n) (pp_regzrbyext Set64 extend_type m) (pp_imm shift) + else + sprintf "PRFM %s,[%s,%s%s]" (pp_prfop (inst_reg_to_int t)) (pp_regsp Set64 n) (pp_regzrbyext Set64 extend_type m) (pp_ldrstr_regext extend_type shift) + end + else + let inst = + (if memop = MemOp_LOAD then "LDR" else "STR") ^ + (if signed then "S" else "") ^ + (match datasize with + | DataSize8 -> "B" + | DataSize16 -> "H" + | DataSize32 -> if regsize = Set32 then "" else "W" + | DataSize64 -> "") in + if extend_type = ExtendType_UXTX && shift = 0 then + sprintf "%s %s,[%s,%s]" inst (pp_regzr regsize t) (pp_regsp Set64 n) (pp_regzrbyext Set64 extend_type m) + else if extend_type = ExtendType_UXTX (* && shift <> 0 *) then + sprintf "%s %s,[%s,%s,LSL %s]" inst (pp_regzr regsize t) (pp_regsp Set64 n) (pp_regzrbyext Set64 extend_type m) (pp_imm shift) + else + sprintf "%s %s,[%s,%s%s]" inst (pp_regzr regsize t) (pp_regsp Set64 n) (pp_regzrbyext Set64 extend_type m) (pp_ldrstr_regext extend_type shift) + end + +| `AArch64MultiplyAddSub (d,n,m,a,destsize,datasize,sub_op) -> + if is_zero_reg a then + sprintf "%s %s,%s,%s" (if sub_op then "MNEG" else "MUL") (pp_regzr destsize d) (pp_regzr destsize n) (pp_regzr destsize m) + else + sprintf "%s %s,%s,%s,%s" (if sub_op then "MSUB" else "MADD") (pp_regzr destsize d) (pp_regzr destsize n) (pp_regzr destsize m) (pp_regzr destsize a) + +| `AArch64MoveWide (d,datasize,imm,pos,opcode) -> + if opcode = MoveWideOp_N && datasize = Set32 && (not (imm = 0 && pos <> 0)) && not (imm = 0xffff) then + sprintf "MOV %s,%s" (pp_regzr datasize d) (pp_imm (lnot (imm lsl (pos*16)))) + else if opcode = MoveWideOp_N && datasize = Set64 && (not (imm = 0 && pos <> 0)) then + sprintf "MOV %s,%s" (pp_regzr datasize d) (pp_imm (lnot (imm lsl (pos*16)))) + else if opcode = MoveWideOp_Z && (not (imm = 0 && pos <> 0)) then + sprintf "MOV %s,%s" (pp_regzr datasize d) (pp_imm (imm lsl (pos*16))) + else if pos = 0 then + sprintf "%s %s,%s" (pp_movwide opcode) (pp_regzr datasize d) (pp_imm imm) + else + sprintf "%s %s,%s,LSL %s" (pp_movwide opcode) (pp_regzr datasize d) (pp_imm imm) (pp_imm pos) + +| `AArch64Reverse (d,n,datasize,op) -> + sprintf "%s %s,%s" (pp_reverse datasize op) (pp_regzr datasize d) (pp_regzr datasize n) + +| `AArch64Division (d,n,m,datasize,unsigned) -> + sprintf "%s %s,%s,%s" (if unsigned then "UDIV" else "SDIV") (pp_regzr datasize d) (pp_regzr datasize n) (pp_regzr datasize m) + +| `AArch64MultiplyAddSubLong (d,n,m,a,destsize,datasize,sub_op,unsigned) -> + if sub_op && is_zero_reg a then + sprintf "%s %s,%s,%s" (if unsigned then "UMNEGL" else "SMNEGL") (pp_regzr Set64 d) (pp_regzr Set32 n) (pp_regzr Set32 m) + else if not sub_op && is_zero_reg a then + sprintf "%s %s,%s,%s" (if unsigned then "UMULL" else "SMULL") (pp_regzr Set64 d) (pp_regzr Set32 n) (pp_regzr Set32 m) + else + sprintf "%s %s,%s,%s,%s" (pp_maddsubl sub_op unsigned) (pp_regzr Set64 d) (pp_regzr Set32 n) (pp_regzr Set32 m) (pp_regzr Set64 a) + +| `AArch64MultiplyHigh (d,n,m,a,destsize,datasize,unsigned) -> + sprintf "%s %s,%s,%s" (if unsigned then "UMULH" else "SMULH") (pp_regzr Set64 d) (pp_regzr Set64 n) (pp_regzr Set64 m) + +| `AArch64TestBitAndBranch (t,datasize,bit_pos,bit_val,offset) -> + sprintf "%s %s,%s,%s" (if bit_pos = 1 then "TBNZ" else "TBZ") (pp_regzr datasize t) (pp_imm bit_pos) (pp_offset false offset) + +| `AArch64MoveSystemRegister (t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read) -> + if read then + sprintf "MRS %s,%s" (pp_regzr Set64 t) (pp_sysreg (sys_op0,sys_op1,sys_op2,sys_crn,sys_crm)) + else + sprintf "MSR %s,%s" (pp_sysreg (sys_op0,sys_op1,sys_op2,sys_crn,sys_crm)) (pp_regzr Set64 t) + +| `AArch64MoveSystemImmediate (operand,field) -> + sprintf "MSR %s,%s" (pp_pstatefield field) (pp_imm operand) diff --git a/arm/gen/regs_out_in.hgen b/arm/gen/regs_out_in.hgen new file mode 100644 index 00000000..724a574b --- /dev/null +++ b/arm/gen/regs_out_in.hgen @@ -0,0 +1,155 @@ +(* for each instruction instance, identify the role of the registers + and possible branching: (outputs, inputs, voidstars, branch) *) + +| `AArch64TMStart t -> failwith "TSTART is not implemented" +| `AArch64TMCommit -> failwith "TCOMMIT is not implemented" +| `AArch64TMAbort (retry,reason) -> failwith "TABORT is not implemented" +| `AArch64TMTest -> failwith "TTEST is not implemented" + +| `AArch64AddSubCarry (d,n,m,_datasize,_sub_op,_setflags) -> + ([d], [n; m], [], [Next]) + +| `AArch64AddSubExtendRegister (d,n,m,_datasize,_sub_op,_setflags,_extend_type,_shift) -> + ([d], [n; m], [], [Next]) + +| `AArch64AddSubShiftedRegister (d,n,m,_datasize,_sub_op,_setflags,_shift_type,_shift_amount) -> + ([d], [n; m], [], [Next]) + +| `AArch64AddSubImmediate (d,n,_datasize,_sub_op,_setflags,_imm) -> + ([d], [n], [], [Next]) + +| `AArch64Address (d,_page,_imm) -> + ([d], [], [], [Next]) + +| `AArch64LogicalImmediate (d,n,_datasize,_setflags,_op,_imm) -> + ([d], [n], [], [Next]) + +| `AArch64LogicalShiftedRegister (d,n,m,_datasize,_setflags,_op,_shift_type,_shift_amount,_invert) -> + ([d], [n; m], [], [Next]) + +| `AArch64Shift (d,n,m,_datasize,_shift_type) -> + ([d], [n; m], [], [Next]) + +| `AArch64BranchConditional (__offset,_condition) -> + ([], [], [], [Next]) + +| `AArch64BranchImmediate (branch_type,__offset) -> + ([], [], [], [Next]) + +| `AArch64BitfieldMove (d,n,_datasize,_inzero,_extend,_R,_S,_wmask,_tmask) -> + ([d], [n], [], [Next]) + +| `AArch64BranchRegister (n,branch_type) -> + ([], [n], [], [Next]) + +| `AArch64CompareAndBranch (t,_datasize,_iszero,__offset) -> + ([], [t], [], [Next]) + +| `AArch64ConditionalCompareImmediate (n,_datasize,_sub_op,_condition,_flags,_imm) -> + ([], [n], [], [Next]) + +| `AArch64ConditionalCompareRegister (n,m,_datasize,_sub_op,_condition,_flags) -> + ([], [n; m], [], [Next]) + +| `AArch64ClearExclusiveMonitor (_imm) -> + ([], [], [], [Next]) + +| `AArch64CountLeading (d,n,_datasize,__opcode) -> + ([d], [n], [], [Next]) + +| `AArch64CRC (d,n,m,_size,_crc32c) -> + ([d], [n; m], [], [Next]) + +| `AArch64ConditionalSelect (d,n,m,_datasize,_condition,_else_inv,_else_inc) -> + ([d], [n; m], [], [Next]) + +| `AArch64Barrier (_op,_domain,_types) -> + ([], [], [], [Next]) + +| `AArch64ExtractRegister (d,n,m,_datasize,_lsb) -> + ([d], [n; m], [], [Next]) + +| `AArch64Hint (_op) -> + ([], [], [], [Next]) + +| `AArch64LoadStoreAcqExc (n,t,t2,s,_acctype,false,false,MemOp_STORE,_elsize,_regsize,_datasize) -> + ([], [t; n], [n], [Next]) +| `AArch64LoadStoreAcqExc (n,t,t2,s,_acctype,true,false,MemOp_STORE,_elsize,_regsize,_datasize) -> + ([s], [t; n], [n], [Next]) +| `AArch64LoadStoreAcqExc (n,t,t2,s,_acctype,true,true,MemOp_STORE,_elsize,_regsize,_datasize) -> + ([s], [t; t2; n], [n], [Next]) + +| `AArch64LoadStoreAcqExc (n,t,t2,s,_acctype,false,false,MemOp_LOAD,_elsize,_regsize,_datasize) -> + ([t], [n], [n], [Next]) +| `AArch64LoadStoreAcqExc (n,t,t2,s,_acctype,true,false,MemOp_LOAD,_elsize,_regsize,_datasize) -> + ([t], [n], [n], [Next]) +| `AArch64LoadStoreAcqExc (n,t,t2,s,_acctype,true,true,MemOp_LOAD,_elsize,_regsize,_datasize) -> + ([t; t2], [n], [n], [Next]) + +| `AArch64LoadStorePair (false,_postindex,n,t,t2,_acctype,MemOp_STORE,_signed,_datasize,_offset) -> + ([], [n; t; t2], [n], [Next]) +| `AArch64LoadStorePair (true,_postindex,n,t,t2,_acctype,MemOp_STORE,_signed,_datasize,_offset) -> + ([n], [n; t; t2], [n], [Next]) + +| `AArch64LoadStorePair (false,_postindex,n,t,t2,_acctype,MemOp_LOAD,_signed,_datasize,_offset) -> + ([t; t2], [n], [n], [Next]) +| `AArch64LoadStorePair (true,_postindex,n,t,t2,_acctype,MemOp_LOAD,_signed,_datasize,_offset) -> + ([t; t2; n], [n], [n], [Next]) + +| `AArch64LoadImmediate (n,t,_acctype,MemOp_STORE,_signed,false,_postindex,_offset,_regsize,_datasize) -> + ([], [n; t], [n], [Next]) +| `AArch64LoadImmediate (n,t,_acctype,MemOp_STORE,_signed,true,_postindex,_offset,_regsize,_datasize) -> + ([n], [n; t], [n], [Next]) + +| `AArch64LoadImmediate (n,t,_acctype,MemOp_LOAD,_signed,false,_postindex,_offset,_regsize,_datasize) -> + ([t], [n], [n], [Next]) +| `AArch64LoadImmediate (n,t,_acctype,MemOp_LOAD,_signed,true,_postindex,_offset,_regsize,_datasize) -> + ([t; n], [n], [n], [Next]) + +| `AArch64LoadLiteral (t,MemOp_STORE,_signed,_size,_offset,_datasize) -> + ([], [t], [], [Next]) + +| `AArch64LoadLiteral (t,MemOp_LOAD,_signed,_size,_offset,_datasize) -> + ([t], [], [], [Next]) + +| `AArch64LoadRegister (n,t,m,_acctype,MemOp_STORE,_signed,false,_postindex,_extend_type,_shift,_regsize,_datasize) -> + ([], [n; t; m], [n], [Next]) +| `AArch64LoadRegister (n,t,m,_acctype,MemOp_STORE,_signed,true,_postindex,_extend_type,_shift,_regsize,_datasize) -> + ([n], [n; t; m], [n], [Next]) + +| `AArch64LoadRegister (n,t,m,_acctype,MemOp_LOAD,_signed,false,_postindex,_extend_type,_shift,_regsize,_datasize) -> + ([t], [n; m], [n], [Next]) +| `AArch64LoadRegister (n,t,m,_acctype,MemOp_LOAD,_signed,true,_postindex,_extend_type,_shift,_regsize,_datasize) -> + ([t; n], [n; m], [n], [Next]) + +| `AArch64LoadRegister (n,t,m,_acctype,MemOp_PREFETCH,_signed,_wback,_postindex,_extend_type,_shift,_regsize,_datasize) -> + ([], [n; m], [n], [Next]) + +| `AArch64MultiplyAddSub (d,n,m,a,_destsize,_datasize,_sub_op) -> + ([d], [n; m; a], [], [Next]) + +| `AArch64MoveWide (d,_datasize,_imm,_pos,_opcode) -> + ([d], [], [], [Next]) + +| `AArch64Reverse (d,n,_datasize,_op) -> + ([d], [n], [], [Next]) + +| `AArch64Division (d,n,m,_datasize,_unsigned) -> + ([d], [n; m], [], [Next]) + +| `AArch64MultiplyAddSubLong (d,n,m,a,_destsize,_datasize,_sub_op,_unsigned) -> + ([d], [n; m; a], [], [Next]) + +| `AArch64MultiplyHigh (d,n,m,a,_destsize,_datasize,_unsigned) -> + ([d], [n; m; a], [], [Next]) + +| `AArch64TestBitAndBranch (t,_datasize,_bit_pos,_bit_val,_offset) -> + ([], [t], [], [Next]) + +| `AArch64MoveSystemRegister (t,_sys_op0,_sys_op1,_sys_op2,_sys_crn,_sys_crm,true) -> + ([t], [], [], [Next]) +| `AArch64MoveSystemRegister (t,_sys_op0,_sys_op1,_sys_op2,_sys_crn,_sys_crm,false) -> + ([], [t], [], [Next]) + +| `AArch64MoveSystemImmediate (_operand,_field) -> + ([], [], [], [Next]) diff --git a/arm/gen/sail_trans_out.hgen b/arm/gen/sail_trans_out.hgen new file mode 100644 index 00000000..9595f00c --- /dev/null +++ b/arm/gen/sail_trans_out.hgen @@ -0,0 +1,326 @@ +| ("TMStart", [t]) -> + `AArch64TMStart (translate_out_regzr Set64 t) + +| ("TMCommit", []) -> `AArch64TMCommit + +| ("TMAbort", [retry; reason]) -> + `AArch64TMAbort ( translate_out_bool retry, + translate_out_bits reason) + +| ("TMTest", []) -> `AArch64TMTest + +| ("ImplementationDefinedStopFetching",[]) -> + `AArch64ImplementationDefinedStopFetching + +| ("ImplementationDefinedThreadStart",[]) -> + `AArch64ImplementationDefinedThreadStart + +| ("ImplementationDefinedTestBeginEnd" , [isEnd]) -> + `AArch64ImplementationDefinedTestBeginEnd (translate_out_bool isEnd) + +| ("AddSubCarry", [d; n; m; datasize; sub_op; setflags]) -> + let datasize' = translate_out_reg_size datasize in + `AArch64AddSubCarry ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool sub_op, + translate_out_bool setflags) + +| "AddSubExtendRegister", [d; n; m; datasize; sub_op; setflags; extend_type; shift] -> + let setflags' = translate_out_bool setflags in + let datasize' = translate_out_reg_size datasize in + let extend_type' = translate_out_extendType extend_type in + `AArch64AddSubExtendRegister ((if setflags' then translate_out_regzr datasize' d else translate_out_regsp datasize' d), + translate_out_regsp datasize' n, + translate_out_regzrbyext datasize' extend_type' m, + datasize', + translate_out_bool sub_op, + setflags', + extend_type', + translate_out_int shift) + +| "AddSubShiftedRegister", [d; n; m; datasize; sub_op; setflags; shift_type; shift_amount] -> + let datasize' = translate_out_reg_size datasize in + `AArch64AddSubShiftedRegister ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool sub_op, + translate_out_bool setflags, + translate_out_shiftType shift_type, + translate_out_int shift_amount) + +| "AddSubImmediate", [d; n; datasize; sub_op; setflags; imm] -> + let setflags' = translate_out_bool setflags in + let datasize' = translate_out_reg_size datasize in + `AArch64AddSubImmediate ( (if setflags' then translate_out_regzr datasize' d else translate_out_regsp datasize' d), + translate_out_regsp datasize' n, + datasize', + translate_out_bool sub_op, + setflags', + translate_out_reg_size_bits imm) + +| "Address", [d; page; imm] -> + `AArch64Address ( translate_out_regzr Set64 d, + translate_out_bool page, + translate_out_big_bit imm) + +| "LogicalImmediate", [d; n; datasize; setflags; op; imm] -> + let setflags' = translate_out_bool setflags in + let datasize' = translate_out_reg_size datasize in + `AArch64LogicalImmediate ((if setflags' then translate_out_regzr datasize' d else translate_out_regsp datasize' d), + translate_out_regzr datasize' n, + datasize', + setflags', + translate_out_logicalOp op, + translate_out_reg_size_bits imm) + +| "LogicalShiftedRegister", [d; n; m; datasize; setflags; op; shift_type; shift_amount; invert] -> + let datasize' = translate_out_reg_size datasize in + `AArch64LogicalShiftedRegister (translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool setflags, + translate_out_logicalOp op, + translate_out_shiftType shift_type, + translate_out_int shift_amount, + translate_out_bool invert) + +| "Shift", [d; n; m; datasize; shift_type] -> + let datasize' = translate_out_reg_size datasize in + `AArch64Shift ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_shiftType shift_type) + +| "BranchConditional", [offset; condition] -> + `AArch64BranchConditional ( translate_out_signed_big_bit offset, + translate_out_bits condition) + +| "BranchImmediate", [branch_type; offset] -> + `AArch64BranchImmediate ( translate_out_branchType branch_type, + translate_out_signed_big_bit offset) + +| "BitfieldMove", [d; n; datasize; inzero; extend; _R; _S; wmask; tmask] -> + let datasize' = translate_out_reg_size datasize in + `AArch64BitfieldMove (translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + datasize', + translate_out_bool inzero, + translate_out_bool extend, + translate_out_int _R, + translate_out_int _S, + translate_out_reg_size_bits wmask, + translate_out_reg_size_bits wmask) + +| "BranchRegister", [n; branch_type] -> + `AArch64BranchRegister (translate_out_regzr Set64 n, + translate_out_branchType branch_type) + +| "CompareAndBranch", [t; datasize; iszero; offset] -> + let datasize' = translate_out_reg_size datasize in + `AArch64CompareAndBranch (translate_out_regzr datasize' t, + datasize', + translate_out_bool iszero, + translate_out_signed_big_bit offset) + +| "ConditionalCompareImmediate", [n; datasize; sub_op; condition; flags; imm] -> + let datasize' = translate_out_reg_size datasize in + `AArch64ConditionalCompareImmediate ( translate_out_regzr datasize' n, + datasize', + translate_out_bool sub_op, + translate_out_bits condition, + translate_out_bits flags, + translate_out_reg_size_bits imm) + +| "ConditionalCompareRegister", [n; m; datasize; sub_op; condition; flags] -> + let datasize' = translate_out_reg_size datasize in + `AArch64ConditionalCompareRegister (translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool sub_op, + translate_out_bits condition, + translate_out_bits flags) + +| "ClearExclusiveMonitor", [imm] -> `AArch64ClearExclusiveMonitor (translate_out_int imm) + +| "CountLeading", [d; n; datasize; opcode] -> + let datasize' = translate_out_reg_size datasize in + `AArch64CountLeading (translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + datasize', + translate_out_countOp opcode) + +| "CRC", [d; n; m; size; crc32c] -> + let size' = translate_out_data_size size in + `AArch64CRC ( translate_out_regzr Set32 d, + translate_out_regzr Set32 n, + translate_out_regzr (if size' = DataSize64 then Set64 else Set32) m, + size', + translate_out_bool crc32c) + +| "ConditionalSelect", [d; n; m; datasize; condition; else_inf; else_inc] -> + let datasize' = translate_out_reg_size datasize in + `AArch64ConditionalSelect ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bits condition, + translate_out_bool else_inf, + translate_out_bool else_inc) + +| "Barrier", [op; domain; types] -> + `AArch64Barrier ( translate_out_memBarrierOp op, + translate_out_mBReqDomain domain, + translate_out_mBReqTypes types) + +| "ExtractRegister", [d; n; m; datasize; lsb] -> + let datasize' = translate_out_reg_size datasize in + `AArch64ExtractRegister ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_int lsb) + +| "Hint", [op] -> `AArch64Hint (translate_out_systemHintOp op) + +| "LoadStoreAcqExc", [n; t; t2; s; acctype; excl; pair; memop; elsize; regsize; datasize] -> + let regsize' = translate_out_reg_size regsize in + `AArch64LoadStoreAcqExc ( translate_out_regsp Set64 n, + translate_out_regzr regsize' t, + translate_out_regzr regsize' t2, + translate_out_regzr Set32 s, + translate_out_accType acctype, + translate_out_bool excl, + translate_out_bool pair, + translate_out_memOp memop, + translate_out_int elsize, + regsize', + translate_out_data_size datasize) + +| "LoadStorePair",[wback; postindex; n; t; t2; acctype; memop; signed; datasize; offset] -> + let signed' = translate_out_bool signed in + let regsize = if signed' then Set64 else translate_out_reg_size datasize in + `AArch64LoadStorePair ( translate_out_bool wback, + translate_out_bool postindex, + translate_out_regsp Set64 n, + translate_out_regzr regsize t, + translate_out_regzr regsize t2, + translate_out_accType acctype, + translate_out_memOp memop, + signed', + translate_out_data_size datasize, + translate_out_signed_big_bit offset) + +| "LoadImmediate",[n; t; acctype; memop; signed; wback; postindex; offset; regsize; datasize] -> + let regsize' = translate_out_reg_size regsize in + `AArch64LoadImmediate ( translate_out_regsp Set64 n, + translate_out_regzr regsize' t, + translate_out_accType acctype, + translate_out_memOp memop, + translate_out_bool signed, + translate_out_bool wback, + translate_out_bool postindex, + translate_out_signed_big_bit offset, + translate_out_reg_size regsize, + translate_out_data_size datasize) + +| "LoadLiteral",[t; memop; signed; size; offset; datasize] -> + `AArch64LoadLiteral ( translate_out_regzr (translate_out_reg_size datasize) t, + translate_out_memOp memop, + translate_out_bool signed, + translate_out_int size, + translate_out_signed_big_bit offset, + translate_out_data_size datasize) + +| "LoadRegister",[n; t; m; acctype; memop; signed; wback; postindex; extend_type; shift; regsize; datasize] -> + let regsize' = translate_out_reg_size regsize in + let extend_type' = translate_out_extendType extend_type in + `AArch64LoadRegister (translate_out_regsp Set64 n, + translate_out_regzr regsize' t, + translate_out_regzrbyext Set64 extend_type' m, + translate_out_accType acctype, + translate_out_memOp memop, + translate_out_bool signed, + translate_out_bool wback, + translate_out_bool postindex, + extend_type', + translate_out_int shift, + translate_out_reg_size regsize , + translate_out_data_size datasize) + +| "MultiplyAddSub", [d; n; m; a; destsize; datasize; sub_op] -> + let destsize' = translate_out_reg_size destsize in + `AArch64MultiplyAddSub (translate_out_regzr destsize' d, + translate_out_regzr destsize' n, + translate_out_regzr destsize' m, + translate_out_regzr destsize' a, + destsize', + translate_out_data_size datasize, + translate_out_bool sub_op) + +| "MoveWide", [d; datasize; imm; pos; opcode] -> + let datasize' = translate_out_reg_size datasize in + `AArch64MoveWide (translate_out_regzr datasize' d, + datasize', + translate_out_bits imm, + translate_out_int pos, + translate_out_moveWideOp opcode) + +| "Reverse", [d; n; datasize; op] -> + let datasize' = translate_out_reg_size datasize in + `AArch64Reverse ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + datasize', + translate_out_revOp op) + +| "Division", [d; n; m; datasize; unsigned] -> + let datasize' = translate_out_reg_size datasize in + `AArch64Division (translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool unsigned) + +| "MultiplyAddSubLong", [d; n; m; a; destsize; datasize; sub_op; unsigned] -> + `AArch64MultiplyAddSubLong (translate_out_regzr Set64 d, + translate_out_regzr Set32 n, + translate_out_regzr Set32 m, + translate_out_regzr Set64 a, + translate_out_reg_size destsize, + translate_out_data_size datasize, + translate_out_bool sub_op, + translate_out_bool unsigned) + +| "MultiplyHigh", [d; n; m; a; destsize; datasize; unsigned] -> + `AArch64MultiplyHigh (translate_out_regzr Set64 d, + translate_out_regzr Set64 n, + translate_out_regzr Set64 m, + translate_out_regzr Set64 a, + translate_out_reg_size destsize, + translate_out_data_size datasize, + translate_out_bool unsigned) + +| "TestBitAndBranch", [t; datasize; bit_pos; bit_val; offset] -> + let datasize' = translate_out_reg_size datasize in + `AArch64TestBitAndBranch (translate_out_regzr datasize' t, + datasize', + translate_out_int bit_pos, + translate_out_bool bit_val, + translate_out_signed_big_bit offset) + +| "MoveSystemRegister", [t; sys_op0; sys_op1; sys_op2; sys_crn; sys_crm; read] -> + `AArch64MoveSystemRegister (translate_out_regzr Set64 t, + translate_out_int sys_op0, + translate_out_int sys_op1, + translate_out_int sys_op2, + translate_out_int sys_crn, + translate_out_int sys_crm, + translate_out_bool read) + +| "MoveSystemImmediate", [operand; field] -> + `AArch64MoveSystemImmediate ( translate_out_int operand, + translate_out_pSTATEField field) diff --git a/arm/gen/shallow_ast_to_herdtools_ast.hgen b/arm/gen/shallow_ast_to_herdtools_ast.hgen new file mode 100644 index 00000000..aa989e95 --- /dev/null +++ b/arm/gen/shallow_ast_to_herdtools_ast.hgen @@ -0,0 +1,326 @@ +| TMStart t -> + `AArch64TMStart (translate_out_regzr Set64 t) + +| TMCommit -> `AArch64TMCommit + +| TMAbort (retry, reason) -> + `AArch64TMAbort ( translate_out_bool retry, + translate_out_bits reason) + +| TMTest -> `AArch64TMTest + +| ImplementationDefinedStopFetching -> + `AArch64ImplementationDefinedStopFetching + +| ImplementationDefinedThreadStart -> + `AArch64ImplementationDefinedThreadStart + +| ImplementationDefinedTestBeginEnd (isEnd) -> + `AArch64ImplementationDefinedTestBeginEnd (translate_out_bool isEnd) + +| AddSubCarry (d, n, m, datasize, sub_op, setflags) -> + let datasize' = translate_out_reg_size datasize in + `AArch64AddSubCarry ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool sub_op, + translate_out_bool setflags) + +| AddSubExtendRegister (d, n, m, datasize, sub_op, setflags, extend_type, shift) -> + let setflags' = translate_out_bool setflags in + let datasize' = translate_out_reg_size datasize in + let extend_type' = translate_out_extendType extend_type in + `AArch64AddSubExtendRegister ((if setflags' then translate_out_regzr datasize' d else translate_out_regsp datasize' d), + translate_out_regsp datasize' n, + translate_out_regzrbyext datasize' extend_type' m, + datasize', + translate_out_bool sub_op, + setflags', + extend_type', + translate_out_int shift) + +| AddSubShiftedRegister (d, n, m, datasize, sub_op, setflags, shift_type, shift_amount) -> + let datasize' = translate_out_reg_size datasize in + `AArch64AddSubShiftedRegister ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool sub_op, + translate_out_bool setflags, + translate_out_shiftType shift_type, + translate_out_int shift_amount) + +| AddSubImmediate (d, n, datasize, sub_op, setflags, imm) -> + let setflags' = translate_out_bool setflags in + let datasize' = translate_out_reg_size datasize in + `AArch64AddSubImmediate ( (if setflags' then translate_out_regzr datasize' d else translate_out_regsp datasize' d), + translate_out_regsp datasize' n, + datasize', + translate_out_bool sub_op, + setflags', + translate_out_reg_size_bits imm) + +| Address0 (d, page, imm) -> + `AArch64Address ( translate_out_regzr Set64 d, + translate_out_bool page, + translate_out_big_bit imm) + +| LogicalImmediate (d, n, datasize, setflags, op, imm) -> + let setflags' = translate_out_bool setflags in + let datasize' = translate_out_reg_size datasize in + `AArch64LogicalImmediate ((if setflags' then translate_out_regzr datasize' d else translate_out_regsp datasize' d), + translate_out_regzr datasize' n, + datasize', + setflags', + translate_out_logicalOp op, + translate_out_reg_size_bits imm) + +| LogicalShiftedRegister (d, n, m, datasize, setflags, op, shift_type, shift_amount, invert) -> + let datasize' = translate_out_reg_size datasize in + `AArch64LogicalShiftedRegister (translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool setflags, + translate_out_logicalOp op, + translate_out_shiftType shift_type, + translate_out_int shift_amount, + translate_out_bool invert) + +| Shift (d, n, m, datasize, shift_type) -> + let datasize' = translate_out_reg_size datasize in + `AArch64Shift ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_shiftType shift_type) + +| BranchConditional (offset, condition) -> + `AArch64BranchConditional ( translate_out_signed_big_bit offset, + translate_out_bits condition) + +| BranchImmediate (branch_type, offset) -> + `AArch64BranchImmediate ( translate_out_branchType branch_type, + translate_out_signed_big_bit offset) + +| BitfieldMove (d, n, datasize, inzero, extend, _R, _S, wmask, tmask) -> + let datasize' = translate_out_reg_size datasize in + `AArch64BitfieldMove (translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + datasize', + translate_out_bool inzero, + translate_out_bool extend, + translate_out_int _R, + translate_out_int _S, + translate_out_reg_size_bits wmask, + translate_out_reg_size_bits wmask) + +| BranchRegister (n, branch_type) -> + `AArch64BranchRegister (translate_out_regzr Set64 n, + translate_out_branchType branch_type) + +| CompareAndBranch (t, datasize, iszero, offset) -> + let datasize' = translate_out_reg_size datasize in + `AArch64CompareAndBranch (translate_out_regzr datasize' t, + datasize', + translate_out_bool iszero, + translate_out_signed_big_bit offset) + +| ConditionalCompareImmediate (n, datasize, sub_op, condition, flags, imm) -> + let datasize' = translate_out_reg_size datasize in + `AArch64ConditionalCompareImmediate ( translate_out_regzr datasize' n, + datasize', + translate_out_bool sub_op, + translate_out_bits condition, + translate_out_bits flags, + translate_out_reg_size_bits imm) + +| ConditionalCompareRegister (n, m, datasize, sub_op, condition, flags) -> + let datasize' = translate_out_reg_size datasize in + `AArch64ConditionalCompareRegister (translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool sub_op, + translate_out_bits condition, + translate_out_bits flags) + +| ClearExclusiveMonitor (imm) -> `AArch64ClearExclusiveMonitor (translate_out_int imm) + +| CountLeading (d, n, datasize, opcode) -> + let datasize' = translate_out_reg_size datasize in + `AArch64CountLeading (translate_out_regzr datasize' d, + translate_out_regzr datasize' d, + datasize', + translate_out_countOp opcode) + +| CRC (d, n, m, size, crc32c) -> + let size' = translate_out_data_size size in + `AArch64CRC ( translate_out_regzr Set32 d, + translate_out_regzr Set32 n, + translate_out_regzr (if size' = DataSize64 then Set64 else Set32) m, + size', + translate_out_bool crc32c) + +| ConditionalSelect (d, n, m, datasize, condition, else_inf, else_inc) -> + let datasize' = translate_out_reg_size datasize in + `AArch64ConditionalSelect ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bits condition, + translate_out_bool else_inf, + translate_out_bool else_inc) + +| Barrier2 (op, domain, types) -> + `AArch64Barrier ( translate_out_memBarrierOp op, + translate_out_mBReqDomain domain, + translate_out_mBReqTypes types) + +| ExtractRegister (d, n, m, datasize, lsb) -> + let datasize' = translate_out_reg_size datasize in + `AArch64ExtractRegister ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_int lsb) + +| Hint (op) -> `AArch64Hint (translate_out_systemHintOp op) + +| LoadStoreAcqExc (n, t, t2, s, acctype, excl, pair, memop, elsize, regsize, datasize) -> + let regsize' = translate_out_reg_size regsize in + `AArch64LoadStoreAcqExc ( translate_out_regsp Set64 n, + translate_out_regzr regsize' t, + translate_out_regzr regsize' t2, + translate_out_regzr Set32 s, + translate_out_accType acctype, + translate_out_bool excl, + translate_out_bool pair, + translate_out_memOp memop, + translate_out_int elsize, + regsize', + translate_out_data_size datasize) + +| LoadStorePair(wback, postindex, n, t, t2, acctype, memop, signed, datasize, offset) -> + let signed' = translate_out_bool signed in + let regsize = if signed' then Set64 else translate_out_reg_size datasize in + `AArch64LoadStorePair ( translate_out_bool wback, + translate_out_bool postindex, + translate_out_regsp Set64 n, + translate_out_regzr regsize t, + translate_out_regzr regsize t2, + translate_out_accType acctype, + translate_out_memOp memop, + signed', + translate_out_data_size datasize, + translate_out_signed_big_bit offset) + +| LoadImmediate(n, t, acctype, memop, signed, wback, postindex, offset, regsize, datasize) -> + let regsize' = translate_out_reg_size regsize in + `AArch64LoadImmediate ( translate_out_regsp Set64 n, + translate_out_regzr regsize' t, + translate_out_accType acctype, + translate_out_memOp memop, + translate_out_bool signed, + translate_out_bool wback, + translate_out_bool postindex, + translate_out_signed_big_bit offset, + translate_out_reg_size regsize, + translate_out_data_size datasize) + +| LoadLiteral(t, memop, signed, size, offset, datasize) -> + `AArch64LoadLiteral ( translate_out_regzr (translate_out_reg_size datasize) t, + translate_out_memOp memop, + translate_out_bool signed, + translate_out_int size, + translate_out_signed_big_bit offset, + translate_out_data_size datasize) + +| LoadRegister(n, t, m, acctype, memop, signed, wback, postindex, extend_type, shift, regsize, datasize) -> + let regsize' = translate_out_reg_size regsize in + let extend_type' = translate_out_extendType extend_type in + `AArch64LoadRegister (translate_out_regsp Set64 n, + translate_out_regzr regsize' t, + translate_out_regzrbyext Set64 extend_type' m, + translate_out_accType acctype, + translate_out_memOp memop, + translate_out_bool signed, + translate_out_bool wback, + translate_out_bool postindex, + extend_type', + translate_out_int shift, + translate_out_reg_size regsize , + translate_out_data_size datasize) + +| MultiplyAddSub (d, n, m, a, destsize, datasize, sub_op) -> + let destsize' = translate_out_reg_size destsize in + `AArch64MultiplyAddSub (translate_out_regzr destsize' d, + translate_out_regzr destsize' n, + translate_out_regzr destsize' m, + translate_out_regzr destsize' a, + destsize', + translate_out_data_size datasize, + translate_out_bool sub_op) + +| MoveWide (d, datasize, imm, pos, opcode) -> + let datasize' = translate_out_reg_size datasize in + `AArch64MoveWide (translate_out_regzr datasize' d, + datasize', + translate_out_bits imm, + translate_out_int pos, + translate_out_moveWideOp opcode) + +| Reverse (d, n, datasize, op) -> + let datasize' = translate_out_reg_size datasize in + `AArch64Reverse ( translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + datasize', + translate_out_revOp op) + +| Division (d, n, m, datasize, unsigned) -> + let datasize' = translate_out_reg_size datasize in + `AArch64Division (translate_out_regzr datasize' d, + translate_out_regzr datasize' n, + translate_out_regzr datasize' m, + datasize', + translate_out_bool unsigned) + +| MultiplyAddSubLong (d, n, m, a, destsize, datasize, sub_op, unsigned) -> + `AArch64MultiplyAddSubLong (translate_out_regzr Set64 d, + translate_out_regzr Set32 n, + translate_out_regzr Set32 m, + translate_out_regzr Set64 a, + translate_out_reg_size destsize, + translate_out_data_size datasize, + translate_out_bool sub_op, + translate_out_bool unsigned) + +| MultiplyHigh (d, n, m, a, destsize, datasize, unsigned) -> + `AArch64MultiplyHigh (translate_out_regzr Set64 d, + translate_out_regzr Set64 n, + translate_out_regzr Set64 m, + translate_out_regzr Set64 a, + translate_out_reg_size destsize, + translate_out_data_size datasize, + translate_out_bool unsigned) + +| TestBitAndBranch (t, datasize, bit_pos, bit_val, offset) -> + let datasize' = translate_out_reg_size datasize in + `AArch64TestBitAndBranch (translate_out_regzr datasize' t, + datasize', + translate_out_int bit_pos, + translate_out_bool bit_val, + translate_out_signed_big_bit offset) + +| MoveSystemRegister (t, sys_op0, sys_op1, sys_op2, sys_crn, sys_crm, read) -> + `AArch64MoveSystemRegister (translate_out_regzr Set64 t, + translate_out_int sys_op0, + translate_out_int sys_op1, + translate_out_int sys_op2, + translate_out_int sys_crn, + translate_out_int sys_crm, + translate_out_bool read) + +| MoveSystemImmediate (operand, field) -> + `AArch64MoveSystemImmediate ( translate_out_bits operand, + translate_out_pSTATEField field) diff --git a/arm/gen/shallow_types_to_herdtools_types.hgen b/arm/gen/shallow_types_to_herdtools_types.hgen new file mode 100644 index 00000000..771f52ac --- /dev/null +++ b/arm/gen/shallow_types_to_herdtools_types.hgen @@ -0,0 +1,154 @@ +let translate_out_big_int_bits x = Sail_values.unsigned x + +let translate_out_big_bit = Sail_values.unsigned + +let translate_out_signed_big_bit = Sail_values.signed + +let translate_out_int inst = (Nat_big_num.to_int inst) + +let translate_out_bits bits = Nat_big_num.to_int (Sail_values.unsigned bits) + +let translate_out_bool = function + | Sail_values.B1 -> true + | Sail_values.B0 -> false + | Sail_values.BU -> failwith "translate_out_bool Undef" + +let translate_out_enum (name,_,bits) = + Nat_big_num.to_int (IInt.integer_of_bit_list bits) + +let translate_out_reg_size inst = + match translate_out_int inst with + | 32 -> Set32 + | 64 -> Set64 + | _ -> assert false + +let translate_out_regzr regsize reg = + begin match (regsize, translate_out_int reg) with + | (Set32, 31) -> W ZR + | (Set32, reg) -> W (Ireg (ireg_of_int reg)) + | (Set64, 31) -> X ZR + | (Set64, reg) -> X (Ireg (ireg_of_int reg)) + end + +let translate_out_regsp regsize reg = + begin match (regsize, translate_out_int reg) with + | (Set32, 31) -> W SP + | (Set32, reg) -> W (Ireg (ireg_of_int reg)) + | (Set64, 31) -> X SP + | (Set64, reg) -> X (Ireg (ireg_of_int reg)) + end + +let translate_out_regzrbyext regsize extend_type reg = begin match extend_type with + | ExtendType_UXTX | ExtendType_SXTX -> translate_out_regzr regsize reg + | _ -> translate_out_regzr Set32 reg + end + +let translate_out_reg_size_bits bits = + match Nat_big_num.to_int (Sail_values.length bits) with + | 32 -> R32Bits (translate_out_bits bits) + | 64 -> R64Bits (translate_out_big_bit bits) + | _ -> assert false + +let translate_out_data_size inst = + match (translate_out_int inst) with + | 8 -> DataSize8 + | 16 -> DataSize16 + | 32 -> DataSize32 + | 64 -> DataSize64 + | _ -> assert false + +let translate_out_extendType = function + | ArmV8_embed_types.ExtendType_UXTB -> ExtendType_UXTB + | ArmV8_embed_types.ExtendType_UXTH -> ExtendType_UXTH + | ArmV8_embed_types.ExtendType_UXTW -> ExtendType_UXTW + | ArmV8_embed_types.ExtendType_UXTX -> ExtendType_UXTX + | ArmV8_embed_types.ExtendType_SXTB -> ExtendType_SXTB + | ArmV8_embed_types.ExtendType_SXTH -> ExtendType_SXTH + | ArmV8_embed_types.ExtendType_SXTW -> ExtendType_SXTW + | ArmV8_embed_types.ExtendType_SXTX -> ExtendType_SXTX + +let translate_out_shiftType = function + | ArmV8_embed_types.ShiftType_LSL -> ShiftType_LSL + | ArmV8_embed_types.ShiftType_LSR -> ShiftType_LSR + | ArmV8_embed_types.ShiftType_ASR -> ShiftType_ASR + | ArmV8_embed_types.ShiftType_ROR -> ShiftType_ROR + +let translate_out_logicalOp = function + | ArmV8_embed_types.LogicalOp_AND -> LogicalOp_AND + | ArmV8_embed_types.LogicalOp_EOR -> LogicalOp_EOR + | ArmV8_embed_types.LogicalOp_ORR -> LogicalOp_ORR + +let translate_out_branchType = function + | ArmV8_embed_types.BranchType_CALL -> BranchType_CALL + | ArmV8_embed_types.BranchType_ERET -> BranchType_ERET + | ArmV8_embed_types.BranchType_DBGEXIT -> BranchType_DBGEXIT + | ArmV8_embed_types.BranchType_RET -> BranchType_RET + | ArmV8_embed_types.BranchType_JMP -> BranchType_JMP + | ArmV8_embed_types.BranchType_EXCEPTION -> BranchType_EXCEPTION + | ArmV8_embed_types.BranchType_UNKNOWN -> BranchType_UNKNOWN + +let translate_out_countOp = function + | ArmV8_embed_types.CountOp_CLZ -> CountOp_CLZ + | ArmV8_embed_types.CountOp_CLS -> CountOp_CLS + | ArmV8_embed_types.CountOp_CNT -> CountOp_CNT + +let translate_out_memBarrierOp = function + | ArmV8_embed_types.MemBarrierOp_DSB -> MemBarrierOp_DSB + | ArmV8_embed_types.MemBarrierOp_DMB -> MemBarrierOp_DMB + | ArmV8_embed_types.MemBarrierOp_ISB -> MemBarrierOp_ISB + +let translate_out_mBReqDomain = function + | ArmV8_embed_types.MBReqDomain_Nonshareable -> MBReqDomain_Nonshareable + | ArmV8_embed_types.MBReqDomain_InnerShareable -> MBReqDomain_InnerShareable + | ArmV8_embed_types.MBReqDomain_OuterShareable -> MBReqDomain_OuterShareable + | ArmV8_embed_types.MBReqDomain_FullSystem -> MBReqDomain_FullSystem + +let translate_out_mBReqTypes = function + | ArmV8_embed_types.MBReqTypes_Reads -> MBReqTypes_Reads + | ArmV8_embed_types.MBReqTypes_Writes -> MBReqTypes_Writes + | ArmV8_embed_types.MBReqTypes_All -> MBReqTypes_All + +let translate_out_systemHintOp = function + | ArmV8_embed_types.SystemHintOp_NOP -> SystemHintOp_NOP + | ArmV8_embed_types.SystemHintOp_YIELD -> SystemHintOp_YIELD + | ArmV8_embed_types.SystemHintOp_WFE -> SystemHintOp_WFE + | ArmV8_embed_types.SystemHintOp_WFI -> SystemHintOp_WFI + | ArmV8_embed_types.SystemHintOp_SEV -> SystemHintOp_SEV + | ArmV8_embed_types.SystemHintOp_SEVL -> SystemHintOp_SEVL + +let translate_out_accType = function + | ArmV8_embed_types.AccType_NORMAL -> AccType_NORMAL + | ArmV8_embed_types.AccType_VEC -> AccType_VEC + | ArmV8_embed_types.AccType_STREAM -> AccType_STREAM + | ArmV8_embed_types.AccType_VECSTREAM -> AccType_VECSTREAM + | ArmV8_embed_types.AccType_ATOMIC -> AccType_ATOMIC + | ArmV8_embed_types.AccType_ORDERED -> AccType_ORDERED + | ArmV8_embed_types.AccType_UNPRIV -> AccType_UNPRIV + | ArmV8_embed_types.AccType_IFETCH -> AccType_IFETCH + | ArmV8_embed_types.AccType_PTW -> AccType_PTW + | ArmV8_embed_types.AccType_DC -> AccType_DC + | ArmV8_embed_types.AccType_IC -> AccType_IC + | ArmV8_embed_types.AccType_AT -> AccType_AT + +let translate_out_memOp = function + | ArmV8_embed_types.MemOp_LOAD -> MemOp_LOAD + | ArmV8_embed_types.MemOp_STORE -> MemOp_STORE + | ArmV8_embed_types.MemOp_PREFETCH -> MemOp_PREFETCH + + +let translate_out_moveWideOp = function + | ArmV8_embed_types.MoveWideOp_N -> MoveWideOp_N + | ArmV8_embed_types.MoveWideOp_Z -> MoveWideOp_Z + | ArmV8_embed_types.MoveWideOp_K -> MoveWideOp_K + +let translate_out_revOp = function + | ArmV8_embed_types.RevOp_RBIT -> RevOp_RBIT + | ArmV8_embed_types.RevOp_REV16 -> RevOp_REV16 + | ArmV8_embed_types.RevOp_REV32 -> RevOp_REV32 + | ArmV8_embed_types.RevOp_REV64 -> RevOp_REV64 + +let translate_out_pSTATEField = function + | ArmV8_embed_types.PSTATEField_DAIFSet -> PSTATEField_DAIFSet + | ArmV8_embed_types.PSTATEField_DAIFClr -> PSTATEField_DAIFClr + | ArmV8_embed_types.PSTATEField_SP -> PSTATEField_SP + diff --git a/arm/gen/token_types.hgen b/arm/gen/token_types.hgen new file mode 100644 index 00000000..411dddf9 --- /dev/null +++ b/arm/gen/token_types.hgen @@ -0,0 +1,85 @@ +(*** instructions ***) + +type token_TSTART = {txt : string} +type token_TCOMMIT = {txt : string} +type token_TABORT = {txt : string} +type token_TTEST = {txt : string} + +type token_ADCSBC = {txt : string; sub_op : boolean; setflags : boolean} +type token_ADDSUB = {txt : string; sub_op : boolean; setflags : boolean} +type token_ADR = {txt : string; page : boolean} +type token_LOGOP = {txt : string; op : logicalOp; setflags : boolean; invert : boolean} +type token_SHIFTOP = {txt : string; shift_type : shiftType} +type token_BCOND = {txt : string; condition : int} +type token_B = {txt : string; branch_type : branchType} +type token_BR = {txt : string; branch_type : branchType} +type token_CBZ = {txt : string; iszero : boolean} +type token_BFM = {txt : string; inzero : boolean; extend : boolean} +type token_CCM = {txt : string; sub_op : boolean} +type token_CM = {txt : string; sub_op : boolean} +type token_CL = {txt : string; opcode : countOp} +type token_CRC = {txt : string; size : data_size; crc32c : boolean} +type token_CRC32X = {txt : string; crc32c : boolean} +type token_CSEL = {txt : string; else_inv : boolean; else_inc : boolean} +type token_CSET = {txt : string; else_inv : boolean; else_inc : boolean} +type token_CSETM = {txt : string; else_inv : boolean; else_inc : boolean} +type token_CON = {txt : string; else_inv : boolean; else_inc : boolean} +type token_MEMBARR = {txt : string; op : memBarrierOp} +type token_LDAXR_var32 = {elsize : int; datasize : data_size} +type token_LDAXR = {txt : string; acctype : accType; excl : boolean; memop : memOp; var32 : token_LDAXR_var32; var64 : boolean} +type token_STLXR_var32 = {elsize : int; datasize : data_size} +type token_STLXR = {txt : string; acctype : accType; var32 : token_STLXR_var32; var64 : boolean} +type token_LDXP = {txt : string; acctype : accType} +type token_STXP = {txt : string; acctype : accType} +type token_LDSTR_var32 = {datasize : data_size} +type token_LDSTR_var64 = {datasize : data_size} +type token_LDSTR_lit64 = {datasize : data_size; size : int} +type token_LDSTR = {txt : string; memop : memOp; signed : boolean; lit32 : boolean; var32 : token_LDSTR_var32 option; var64 : token_LDSTR_var64 option; lit64 : token_LDSTR_lit64 option} +type token_LDSTTUR_off32 = {datasize : data_size} +type token_LDSTTUR_off64 = {datasize : data_size} +type token_LDSTTUR = {txt : string; memop : memOp; acctype : accType; signed : boolean; off32 : token_LDSTTUR_off32 option; off64 : token_LDSTTUR_off64 option} +type token_MADDSUB = {txt : string; sub_op : boolean} +type token_MUL = {txt : string; sub_op : boolean} +type token_MOVWIDE = {txt : string; opcode : moveWideOp} +type token_NEG = {txt : string; setflags : boolean} +type token_NGC = {txt : string; setflags : boolean} +type token_REV = {txt : string; op32 : revOp option; op64 : revOp} +type token_DIV = {txt : string; unsigned : boolean} +type token_MADDSUBL = {txt : string; sub_op : boolean; unsigned : boolean} +type token_MULH = {txt : string; unsigned : boolean} +type token_MULL = {txt : string; unsigned : boolean} +type token_LDSTP = {txt : string; memop : memOp} +type token_TBZ = {txt : string; bit_val : bit} +type token_BFIZ = {txt : string; extend : boolean} +type token_BFX = {txt : string; extend : boolean} +type token_MNEGL = {txt : string; unsigned : boolean} +type token_BFI = {txt : string} +type token_BFXIL = {txt : string} +type token_CLREX = {txt : string} +type token_EXTR = {txt : string} +type token_HINT = {txt : string} +type token_ISB = {txt : string} +type token_LDPSW = {txt : string} +type token_MOV = {txt : string} +type token_MVN = {txt : string} +type token_NOP = {txt : string} +type token_PRFM = {txt : string} +type token_PRFUM = {txt : string} +type token_RET = {txt : string} +type token_TST = {txt : string} +type token_MRS = {txt : string} +type token_MSR = {txt : string} + +(*** instructions/operands ***) + +type token_SHIFT = {txt : string; shift_type : shiftType} +type token_EXTEND_inst = {extend : boolean; imms : int} +type token_EXTEND = {txt : string; _type : extendType; inst : token_EXTEND_inst option} + +(*** operands: ***) + +type token_COND = int +type token_BARROP = {domain : mBReqDomain; types : mBReqTypes} +type token_PRFOP = inst_reg (* this is an int that is encoded in a reg field *) +type token_SYSREG = {sys_op0 : uinteger; sys_op1 : uinteger; sys_op2 : uinteger; sys_crn : uinteger; sys_crm : uinteger} +type token_PSTATEFIELD = pSTATEField diff --git a/arm/gen/tokens.hgen b/arm/gen/tokens.hgen new file mode 100644 index 00000000..bf49e463 --- /dev/null +++ b/arm/gen/tokens.hgen @@ -0,0 +1,78 @@ +/*** instructions ***/ + +%token <AArch64HGenBase.token_TSTART> TSTART +%token <AArch64HGenBase.token_TCOMMIT> TCOMMIT +%token <AArch64HGenBase.token_TABORT> TABORT +%token <AArch64HGenBase.token_TTEST> TTEST + +%token <AArch64HGenBase.token_ADCSBC> ADCSBC +%token <AArch64HGenBase.token_ADDSUB> ADDSUB +%token <AArch64HGenBase.token_ADR> ADR +%token <AArch64HGenBase.token_LOGOP> LOGOP +%token <AArch64HGenBase.token_SHIFTOP> SHIFTOP +%token <AArch64HGenBase.token_BCOND> BCOND +%token <AArch64HGenBase.token_B> B +%token <AArch64HGenBase.token_BR> BR +%token <AArch64HGenBase.token_CBZ> CBZ +%token <AArch64HGenBase.token_BFM> BFM +%token <AArch64HGenBase.token_CCM> CCM +%token <AArch64HGenBase.token_CM> CM +%token <AArch64HGenBase.token_CL> CL +%token <AArch64HGenBase.token_CRC> CRC +%token <AArch64HGenBase.token_CRC32X> CRC32X +%token <AArch64HGenBase.token_CSEL> CSEL +%token <AArch64HGenBase.token_CSET> CSET +%token <AArch64HGenBase.token_CSETM> CSETM +%token <AArch64HGenBase.token_CON> CON +%token <AArch64HGenBase.token_MEMBARR> MEMBARR +%token <AArch64HGenBase.token_LDAXR> LDAXR +%token <AArch64HGenBase.token_STLXR> STLXR +%token <AArch64HGenBase.token_LDXP> LDXP +%token <AArch64HGenBase.token_STXP> STXP +%token <AArch64HGenBase.token_LDSTR> LDSTR +%token <AArch64HGenBase.token_LDSTTUR> LDSTTUR +%token <AArch64HGenBase.token_MADDSUB> MADDSUB +%token <AArch64HGenBase.token_MUL> MUL +%token <AArch64HGenBase.token_MOVWIDE> MOVWIDE +%token <AArch64HGenBase.token_NEG> NEG +%token <AArch64HGenBase.token_NGC> NGC +%token <AArch64HGenBase.token_REV> REV +%token <AArch64HGenBase.token_DIV> DIV +%token <AArch64HGenBase.token_MADDSUBL> MADDSUBL +%token <AArch64HGenBase.token_MULH> MULH +%token <AArch64HGenBase.token_MULL> MULL +%token <AArch64HGenBase.token_LDSTP> LDSTP +%token <AArch64HGenBase.token_TBZ> TBZ +%token <AArch64HGenBase.token_BFIZ> BFIZ +%token <AArch64HGenBase.token_BFX> BFX +%token <AArch64HGenBase.token_MNEGL> MNEGL +%token <AArch64HGenBase.token_BFI> BFI +%token <AArch64HGenBase.token_BFXIL> BFXIL +%token <AArch64HGenBase.token_CLREX> CLREX +%token <AArch64HGenBase.token_EXTR> EXTR +%token <AArch64HGenBase.token_HINT> HINT +%token <AArch64HGenBase.token_ISB> ISB +%token <AArch64HGenBase.token_LDPSW> LDPSW +%token <AArch64HGenBase.token_MOV> MOV +%token <AArch64HGenBase.token_MVN> MVN +%token <AArch64HGenBase.token_NOP> NOP +%token <AArch64HGenBase.token_PRFM> PRFM +%token <AArch64HGenBase.token_PRFUM> PRFUM +%token <AArch64HGenBase.token_RET> RET +%token <AArch64HGenBase.token_TST> TST +%token <AArch64HGenBase.token_MRS> MRS +%token <AArch64HGenBase.token_MSR> MSR + +/*** instructions/operands ***/ + +%token <AArch64HGenBase.token_SHIFT> SHIFT +%token <AArch64HGenBase.token_EXTEND> EXTEND + +/*** operands: ***/ + +%token <AArch64HGenBase.token_COND> COND +%token <AArch64HGenBase.token_BARROP> BARROP +%token <AArch64HGenBase.token_PRFOP> PRFOP +%token <AArch64HGenBase.token_SYSREG> SYSREG +%token <AArch64HGenBase.token_PSTATEFIELD> PSTATEFIELD + diff --git a/arm/gen/trans_sail.hgen b/arm/gen/trans_sail.hgen new file mode 100644 index 00000000..2b176308 --- /dev/null +++ b/arm/gen/trans_sail.hgen @@ -0,0 +1,379 @@ +| `AArch64TMStart t -> + ("TMStart", [translate_reg "t" t], []) + +| `AArch64TMCommit -> ("TMCommit", [], []) + +| `AArch64TMAbort (retry,reason) -> + ("TMAbort", + [ translate_boolean "retry" retry; + translate_bit5 "reason" reason], + []) + +| `AArch64TMTest -> ("TMTest", [], []) + + +| `AArch64ImplementationDefinedStopFetching -> + ("ImplementationDefinedStopFetching", + [], + []) + +| `AArch64ImplementationDefinedThreadStart -> + ("ImplementationDefinedThreadStart", + [], + []) + +| `AArch64ImplementationDefinedTestBeginEnd(isEnd) -> + ("ImplementationDefinedTestBeginEnd", + [translate_boolean "isEnd" isEnd], + []) + +| `AArch64AddSubCarry(d,n,m,datasize,sub_op,setflags) -> + ("AddSubCarry", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg_size "datasize" datasize; + translate_boolean "sub_op" sub_op; + translate_boolean "setflags" setflags], + []) + +| `AArch64AddSubExtendRegister (d,n,m,datasize,sub_op,setflags,extend_type,shift) -> + ("AddSubExtendRegister", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg_size "datasize" datasize; + translate_boolean "sub_op" sub_op; + translate_boolean "setflags" setflags; + translate_extendType "extend_type" extend_type; + translate_range0_7 "shift" shift], + []) + +| `AArch64AddSubShiftedRegister (d,n,m,datasize,sub_op,setflags,shift_type,shift_amount) -> + ("AddSubShiftedRegister", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg_size "datasize" datasize; + translate_boolean "sub_op" sub_op; + translate_boolean "setflags" setflags; + translate_shiftType "shift_type" shift_type; + translate_range0_63 "shift_amount" shift_amount], + []) + +| `AArch64AddSubImmediate (d,n,datasize,sub_op,setflags,imm) -> + ("AddSubImmediate", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg_size "datasize" datasize; + translate_boolean "sub_op" sub_op; + translate_boolean "setflags" setflags; + translate_reg_size_bits "imm" imm], + []) + +| `AArch64Address (d,page,imm) -> + ("Address", + [translate_reg "d" d; + translate_boolean "page" page; + translate_bit64 "imm" imm], + []) + +| `AArch64LogicalImmediate (d,n,datasize,setflags,op,imm) -> + ("LogicalImmediate", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg_size "datasize" datasize; + translate_boolean "setflags" setflags; + translate_logicalOp "op" op; + translate_reg_size_bits "imm" imm], + []) + +| `AArch64LogicalShiftedRegister (d,n,m,datasize,setflags,op,shift_type,shift_amount,invert) -> + ("LogicalShiftedRegister", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg_size "datasize" datasize; + translate_boolean "setflags" setflags; + translate_logicalOp "op" op; + translate_shiftType "shift_type" shift_type; + translate_range0_63 "shift_amount" shift_amount; + translate_boolean "invert" invert], + []) + +| `AArch64Shift (d,n,m,datasize,shift_type) -> + ("Shift", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg_size "datasize" datasize; + translate_shiftType "shift_type" shift_type], + []) + +| `AArch64BranchConditional (offset,condition) -> + ("BranchConditional", + [translate_bit64 "offset" offset; + translate_bit4 "condition" condition], + []) + +| `AArch64BranchImmediate (branch_type,offset) -> + ("BranchImmediate", + [translate_branchType "branch_type" branch_type; + translate_bit64 "offset" offset], + []) + +| `AArch64BitfieldMove (d,n,datasize,inzero,extend,_R,_S,wmask,tmask) -> + ("BitfieldMove", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg_size "datasize" datasize; + translate_boolean "inzero" inzero; + translate_boolean "extend" extend; + translate_uinteger "_R" _R; + translate_uinteger "_S" _S; + translate_reg_size_bits "wmask" wmask; + translate_reg_size_bits "tmask" tmask], + []) + +| `AArch64BranchRegister (n,branch_type) -> + ("BranchRegister", + [translate_reg "n" n; + translate_branchType "branch_type" branch_type], + []) + +| `AArch64CompareAndBranch (t,datasize,iszero,offset) -> + ("CompareAndBranch", + [translate_reg "t" t; + translate_reg_size "datasize" datasize; + translate_boolean "iszero" iszero; + translate_bit64 "offset" offset], + []) + +| `AArch64ConditionalCompareImmediate (n,datasize,sub_op,condition,flags,imm) -> + ("ConditionalCompareImmediate", + [translate_reg "n" n; + translate_reg_size "datasize" datasize; + translate_boolean "sub_op" sub_op; + translate_bit4 "condition" condition; + translate_bit4 "flags" flags; + translate_reg_size_bits "imm" imm], + []) + +| `AArch64ConditionalCompareRegister (n,m,datasize,sub_op,condition,flags) -> + ("ConditionalCompareRegister", + [translate_reg "n" n; + translate_reg "m" m; + translate_reg_size "datasize" datasize; + translate_boolean "sub_op" sub_op; + translate_bit4 "condition" condition; + translate_bit4 "flags" flags], + []) + +| `AArch64ClearExclusiveMonitor (imm) -> + ("ClearExclusiveMonitor", + [translate_uinteger "imm" imm], + []) + +| `AArch64CountLeading (d,n,datasize,opcode) -> + ("CountLeading", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg_size "datasize" datasize; + translate_countOp "opcode" opcode], + []) + +| `AArch64CRC (d,n,m,size,crc32c) -> + ("CRC", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_data_size "size" size; + translate_boolean "crc32c" crc32c], + []) + +| `AArch64ConditionalSelect (d,n,m,datasize,condition,else_inv,else_inc) -> + ("ConditionalSelect", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg_size "datasize" datasize; + translate_bit4 "condition" condition; + translate_boolean "else_inv" else_inv; + translate_boolean "else_inc" else_inc], + []) + +| `AArch64Barrier (op,domain,types) -> + ("Barrier", + [translate_memBarrierOp "op" op; + translate_mBReqDomain "domain" domain; + translate_mBReqTypes "types" types], + []) + +| `AArch64ExtractRegister (d,n,m,datasize,lsb) -> + ("ExtractRegister", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg_size "datasize" datasize; + translate_uinteger "lsb" lsb], + []) + +| `AArch64Hint (op) -> + ("Hint", + [translate_systemHintOp "op" op], + []) + +| `AArch64LoadStoreAcqExc (n,t,t2,s,acctype,excl,pair,memop,elsize,regsize,datasize) -> + ("LoadStoreAcqExc", + [translate_reg "n" n; + translate_reg "t" t; + translate_reg "t2" t2; + translate_reg "s" s; + translate_accType "acctype" acctype; + translate_boolean "excl" excl; + translate_boolean "pair" pair; + translate_memOp "memop" memop; + translate_uinteger "elsize" elsize; + translate_reg_size "regsize" regsize; + translate_data_size "datasize" datasize], + []) + +| `AArch64LoadStorePair (wback,postindex,n,t,t2,acctype,memop,signed,datasize,offset) -> + ("LoadStorePair", + [translate_boolean "wback" wback; + translate_boolean "postindex" postindex; + translate_reg "n" n; + translate_reg "t" t; + translate_reg "t2" t2; + translate_accType "acctype" acctype; + translate_memOp "memop" memop; + translate_boolean "signed" signed; + translate_data_size "datasize" datasize; + translate_bit64 "offset" offset], + []) + +| `AArch64LoadImmediate (n,t,acctype,memop,signed,wback,postindex,offset,regsize,datasize) -> + ("LoadImmediate", + [translate_reg "n" n; + translate_reg "t" t; + translate_accType "acctype" acctype; + translate_memOp "memop" memop; + translate_boolean "signed" signed; + translate_boolean "wback" wback; + translate_boolean "postindex" postindex; + translate_bit64 "offset" offset; + translate_reg_size "regsize" regsize; + translate_data_size "datasize" datasize], + []) + +| `AArch64LoadLiteral (t,memop,signed,size,offset,datasize) -> + ("LoadLiteral", + [translate_reg "t" t; + translate_memOp "memop" memop; + translate_boolean "signed" signed; + translate_uinteger "size" size; + translate_bit64 "offset" offset; + translate_data_size "datasize" datasize;], + []) + +| `AArch64LoadRegister (n,t,m,acctype,memop,signed,wback,postindex,extend_type,shift,regsize,datasize) -> + ("LoadRegister", + [translate_reg "n" n; + translate_reg "t" t; + translate_reg "m" m; + translate_accType "acctype" acctype; + translate_memOp "memop" memop; + translate_boolean "signed" signed; + translate_boolean "wback" wback; + translate_boolean "postindex" postindex; + translate_extendType "extend_type" extend_type; + translate_uinteger "shift" shift; + translate_reg_size "regsize" regsize; + translate_data_size "datasize" datasize], + []) + +| `AArch64MultiplyAddSub (d,n,m,a,destsize,datasize,sub_op) -> + ("MultiplyAddSub", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg "a" a; + translate_reg_size "destsize" destsize; + translate_data_size "datasize" datasize; + translate_boolean "sub_op" sub_op], + []) + +| `AArch64MoveWide (d,datasize,imm,pos,opcode) -> + ("MoveWide", + [translate_reg "d" d; + translate_reg_size "datasize" datasize; + translate_bit16 "imm" imm; + translate_uinteger "pos" pos; + translate_moveWideOp "opcode" opcode], + []) + +| `AArch64Reverse (d,n,datasize,op) -> + ("Reverse", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg_size "datasize" datasize; + translate_revOp "op" op], + []) + +| `AArch64Division (d,n,m,datasize,unsigned) -> + ("Division", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg_size "datasize" datasize; + translate_boolean "unsigned" unsigned], + []) + +| `AArch64MultiplyAddSubLong (d,n,m,a,destsize,datasize,sub_op,unsigned) -> + ("MultiplyAddSubLong", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg "a" a; + translate_reg_size "destsize" destsize; + translate_data_size "datasize" datasize; + translate_boolean "sub_op" sub_op; + translate_boolean "unsigned" unsigned], + []) + +| `AArch64MultiplyHigh (d,n,m,a,destsize,datasize,unsigned) -> + ("MultiplyHigh", + [translate_reg "d" d; + translate_reg "n" n; + translate_reg "m" m; + translate_reg "a" a; + translate_reg_size "destsize" destsize; + translate_data_size "datasize" datasize; + translate_boolean "unsigned" unsigned], + []) + +| `AArch64TestBitAndBranch (t,datasize,bit_pos,bit_val,offset) -> + ("TestBitAndBranch", + [translate_reg "t" t; + translate_reg_size "datasize" datasize; + translate_uinteger "bit_pos" bit_pos; + translate_bit "bit_val" bit_val; + translate_bit64 "offset" offset], + []) + +| `AArch64MoveSystemRegister (t,sys_op0,sys_op1,sys_op2,sys_crn,sys_crm,read) -> + ("MoveSystemRegister", + [translate_reg "t" t; + translate_uinteger "sys_op0" sys_op0; + translate_uinteger "sys_op1" sys_op1; + translate_uinteger "sys_op2" sys_op2; + translate_uinteger "sys_crn" sys_crn; + translate_uinteger "sys_crm" sys_crm; + translate_boolean "read" read], + []) + +| `AArch64MoveSystemImmediate (operand,field) -> + ("MoveSystemImmediate", + [translate_bit4 "operand" operand; + translate_pSTATEField "field" field], + []) diff --git a/arm/gen/types.hgen b/arm/gen/types.hgen new file mode 100644 index 00000000..d581a233 --- /dev/null +++ b/arm/gen/types.hgen @@ -0,0 +1,90 @@ +type reg_size = Set64 | Set32 + +type reg_size_bits = R32Bits of int | R64Bits of Nat_big_num.num +let reg_size_bits_R32_of_int value = R32Bits value +let reg_size_bits_R64_of_int value = R64Bits (Nat_big_num.of_int value) +let reg_size_bits_R32_of_big_int value = R32Bits (Nat_big_num.to_int value) +let reg_size_bits_R64_of_big_int value = R64Bits value +let eq_reg_size_bits = function + | (R32Bits lhs, R32Bits rhs) -> lhs = rhs + | (R64Bits lhs, R64Bits rhs) -> Nat_big_num.equal lhs rhs + | (R32Bits _, R64Bits _) -> false + | (R64Bits _, R32Bits _) -> false +let reg_size_bits_iskbituimm k value = + match value with + | R32Bits value -> iskbituimm k value + | R64Bits value -> big_iskbituimm k value +let reg_size_bits_shift_right value n = + match value with + | R32Bits value -> R32Bits (value lsr n) + | R64Bits value -> R64Bits (Nat_big_num.shift_right value n) +let reg_size_bits_to_int value = + match value with + | R32Bits value -> value + | R64Bits value -> Nat_big_num.to_int value + +type data_size = DataSize64 | DataSize32 | DataSize16 | DataSize8 + +type reg_index = int + +type boolean = bool + +type range0_7 = int + +type range0_63 = int + +type bit64 = Nat_big_num.num +let bit64_of_int = Nat_big_num.of_int +let bit64_to_int = Nat_big_num.to_int +let eq_bit64 = Nat_big_num.equal + +type bit4 = int + +type bit5 = int + +type bit16 = int + +type bit = bool + +type range8_64 = int + +type uinteger = int + +type extendType = ExtendType_SXTB | ExtendType_SXTH | ExtendType_SXTW | ExtendType_SXTX | + ExtendType_UXTB | ExtendType_UXTH | ExtendType_UXTW | ExtendType_UXTX + + +type shiftType = ShiftType_LSL | ShiftType_LSR | ShiftType_ASR | ShiftType_ROR + +type logicalOp = LogicalOp_AND | LogicalOp_EOR | LogicalOp_ORR + +type branchType = BranchType_CALL | BranchType_ERET | BranchType_DBGEXIT | + BranchType_RET | BranchType_JMP | BranchType_EXCEPTION | + BranchType_UNKNOWN + +type countOp = CountOp_CLZ | CountOp_CLS | CountOp_CNT + +type memBarrierOp = MemBarrierOp_DSB | MemBarrierOp_DMB | MemBarrierOp_ISB + +type mBReqDomain = MBReqDomain_Nonshareable | MBReqDomain_InnerShareable | + MBReqDomain_OuterShareable | MBReqDomain_FullSystem + +type mBReqTypes = MBReqTypes_Reads | MBReqTypes_Writes | MBReqTypes_All + +type systemHintOp = SystemHintOp_NOP | SystemHintOp_YIELD | + SystemHintOp_WFE | SystemHintOp_WFI | + SystemHintOp_SEV | SystemHintOp_SEVL + +type accType = AccType_NORMAL | AccType_VEC | AccType_STREAM | + AccType_VECSTREAM | AccType_ATOMIC | AccType_ORDERED | + AccType_UNPRIV | AccType_IFETCH | AccType_PTW | + AccType_DC | AccType_IC | AccType_AT + +type memOp = MemOp_LOAD | MemOp_STORE | MemOp_PREFETCH + +type moveWideOp = MoveWideOp_N | MoveWideOp_Z | MoveWideOp_K + +type revOp = RevOp_RBIT | RevOp_REV16 | RevOp_REV32 | RevOp_REV64 + +type pSTATEField = PSTATEField_DAIFSet | PSTATEField_DAIFClr | + PSTATEField_SP diff --git a/arm/gen/types_sail_trans_out.hgen b/arm/gen/types_sail_trans_out.hgen new file mode 100644 index 00000000..082a5464 --- /dev/null +++ b/arm/gen/types_sail_trans_out.hgen @@ -0,0 +1,189 @@ +let translate_out_big_int_bits = function + | (name, Range0 _, bits) -> IInt.integer_of_bit_list bits + | _ -> assert false + +let translate_out_big_bit = function + | (name, Bvector _, bits) -> IInt.integer_of_bit_list bits + | _ -> assert false + +let translate_out_signed_big_bit = function + | (name, Bvector _, bits) -> IInt.signed_integer_of_bit_list bits + | _ -> assert false + +let translate_out_int inst = (Nat_big_num.to_int (translate_out_big_int_bits inst)) + +let translate_out_bits = function + | (name, Bvector _, bits) -> Nat_big_num.to_int (IInt.integer_of_bit_list bits) + | _ -> assert false + +let translate_out_bool = function + | (name, Bit, [Bitc_one]) -> true + | (name, Bit, [Bitc_zero]) -> false + | _ -> assert false + +let translate_out_enum (name,_,bits) = + Nat_big_num.to_int (IInt.integer_of_bit_list bits) + +let translate_out_reg_size inst = + match translate_out_int inst with + | 32 -> Set32 + | 64 -> Set64 + | _ -> assert false + +let translate_out_regzr regsize reg = + begin match (regsize, translate_out_int reg) with + | (Set32, 31) -> W ZR + | (Set32, reg) -> W (Ireg (ireg_of_int reg)) + | (Set64, 31) -> X ZR + | (Set64, reg) -> X (Ireg (ireg_of_int reg)) + end + +let translate_out_regsp regsize reg = + begin match (regsize, translate_out_int reg) with + | (Set32, 31) -> W SP + | (Set32, reg) -> W (Ireg (ireg_of_int reg)) + | (Set64, 31) -> X SP + | (Set64, reg) -> X (Ireg (ireg_of_int reg)) + end + +let translate_out_regzrbyext regsize extend_type reg = + begin match extend_type with + | ExtendType_UXTX | ExtendType_SXTX -> translate_out_regzr regsize reg + | _ -> translate_out_regzr Set32 reg + end + +let translate_out_reg_size_bits ((name,_,bits) as inst) = + match List.length bits with + | 32 -> R32Bits (translate_out_bits inst) + | 64 -> R64Bits (translate_out_big_bit inst) + | _ -> assert false + +let translate_out_data_size inst = + match (translate_out_int inst) with + | 8 -> DataSize8 + | 16 -> DataSize16 + | 32 -> DataSize32 + | 64 -> DataSize64 + | _ -> assert false + +let translate_out_extendType inst = + match translate_out_enum inst with + | 0 -> ExtendType_SXTB + | 1 -> ExtendType_SXTH + | 2 -> ExtendType_SXTW + | 3 -> ExtendType_SXTX + | 4 -> ExtendType_UXTB + | 5 -> ExtendType_UXTH + | 6 -> ExtendType_UXTW + | 7 -> ExtendType_UXTX + | _ -> assert false + +let translate_out_shiftType inst = + match translate_out_enum inst with + | 0 -> ShiftType_LSL + | 1 -> ShiftType_LSR + | 2 -> ShiftType_ASR + | 3 -> ShiftType_ROR + | _ -> assert false + +let translate_out_logicalOp inst = + match translate_out_enum inst with + | 0 -> LogicalOp_AND + | 1 -> LogicalOp_EOR + | 2 -> LogicalOp_ORR + | _ -> assert false + +let translate_out_branchType inst = + match translate_out_enum inst with + | 0 -> BranchType_CALL + | 1 -> BranchType_ERET + | 2 -> BranchType_DBGEXIT + | 3 -> BranchType_RET + | 4 -> BranchType_JMP + | 5 -> BranchType_EXCEPTION + | 6 -> BranchType_UNKNOWN + | _ -> assert false + +let translate_out_countOp inst = + match translate_out_enum inst with + | 0 -> CountOp_CLZ + | 1 -> CountOp_CLS + | 2 -> CountOp_CNT + | _ -> assert false + +let translate_out_memBarrierOp inst = + match translate_out_enum inst with + | 0 -> MemBarrierOp_DSB + | 1 -> MemBarrierOp_DMB + | 2 -> MemBarrierOp_ISB + | _ -> assert false + +let translate_out_mBReqDomain inst = + match translate_out_enum inst with + | 0 -> MBReqDomain_Nonshareable + | 1 -> MBReqDomain_InnerShareable + | 2 -> MBReqDomain_OuterShareable + | 3 -> MBReqDomain_FullSystem + | _ -> assert false + +let translate_out_mBReqTypes inst = + match translate_out_enum inst with + | 0 -> MBReqTypes_Reads + | 1 -> MBReqTypes_Writes + | 2 -> MBReqTypes_All + | _ -> assert false + +let translate_out_systemHintOp inst = + match translate_out_enum inst with + | 0 -> SystemHintOp_NOP + | 1 -> SystemHintOp_YIELD + | 2 -> SystemHintOp_WFE + | 3 -> SystemHintOp_WFI + | 4 -> SystemHintOp_SEV + | 5 -> SystemHintOp_SEVL + | _ -> assert false + +let translate_out_accType inst = + match translate_out_enum inst with + | 0 -> AccType_NORMAL + | 1 -> AccType_VEC + | 2 -> AccType_STREAM + | 3 -> AccType_VECSTREAM + | 4 -> AccType_ATOMIC + | 5 -> AccType_ORDERED + | 6 -> AccType_UNPRIV + | 7 -> AccType_IFETCH + | 8 -> AccType_PTW + | 9 -> AccType_DC + | 10 -> AccType_IC + | 11 -> AccType_AT + | _ -> assert false + +let translate_out_memOp inst = + match translate_out_enum inst with + | 0 -> MemOp_LOAD + | 1 -> MemOp_STORE + | 2 -> MemOp_PREFETCH + | _ -> assert false + +let translate_out_moveWideOp inst = + match translate_out_enum inst with + | 0 -> MoveWideOp_N + | 1 -> MoveWideOp_Z + | 2 -> MoveWideOp_K + | _ -> assert false + +let translate_out_revOp inst = + match translate_out_enum inst with + | 0 -> RevOp_RBIT + | 1 -> RevOp_REV16 + | 2 -> RevOp_REV32 + | 3 -> RevOp_REV64 + | _ -> assert false + +let translate_out_pSTATEField inst = + match translate_out_enum inst with + | 0 -> PSTATEField_DAIFSet + | 1 -> PSTATEField_DAIFClr + | 2 -> PSTATEField_SP + | _ -> assert false diff --git a/arm/gen/types_trans_sail.hgen b/arm/gen/types_trans_sail.hgen new file mode 100644 index 00000000..7f2d5fe7 --- /dev/null +++ b/arm/gen/types_trans_sail.hgen @@ -0,0 +1,119 @@ +let translate_big_int bits (name : string) value = + (name, Range0 (Some bits), IInt.bit_list_of_integer bits value) + +let translate_big_bit bits (name:string) value = + (name, Bvector (Some bits), IInt.bit_list_of_integer bits value) + +let translate_int bits name value = + translate_big_int bits name (Nat_big_num.of_int value) + +let translate_bits bits (name:string) value = + (name, Bvector (Some bits), IInt.bit_list_of_integer bits (Nat_big_num.of_int value)) + +let translate_bool name value = + (name, Bit, [if value then Bitc_one else Bitc_zero]) + +let translate_enum enum_values (name: string) value = + let rec bit_count n = + if n = 0 then 0 + else 1 + (bit_count (n lsr 1)) in + let rec find_index element = function + | h::tail -> if h = element then 0 else 1 + (find_index element tail) + | _ -> failwith "translate_enum could not find value" + in + let size = bit_count (List.length enum_values) in + let index = find_index value enum_values in + (name, Range0 (Some size), IInt.bit_list_of_integer size (Nat_big_num.of_int index)) + +(* the following are tightly coupled with types.hgen. As it is not relevant + to herdtools I put it here and not in types.hgen *) + +let translate_reg_size name value = + match value with + | Set32 -> (name, Range0 (Some 7), IInt.bit_list_of_integer 7 (Nat_big_num.of_int 32)) + | Set64 -> (name, Range0 (Some 7), IInt.bit_list_of_integer 7 (Nat_big_num.of_int 64)) + +let translate_reg name value = + (name, Range0 (Some 5), bit_list_of_integer 5 (Nat_big_num.of_int (inst_reg_to_int value))) + +let translate_reg_size_bits name value = + match value with + | R32Bits value -> translate_bits 32 name value + | R64Bits value -> translate_big_bit 64 name value + +let translate_data_size name value = + match value with + | DataSize8 -> (name, Range0 (Some 7), IInt.bit_list_of_integer 7 (Nat_big_num.of_int 8)) + | DataSize16 -> (name, Range0 (Some 7), IInt.bit_list_of_integer 7 (Nat_big_num.of_int 16)) + | DataSize32 -> (name, Range0 (Some 7), IInt.bit_list_of_integer 7 (Nat_big_num.of_int 32)) + | DataSize64 -> (name, Range0 (Some 7), IInt.bit_list_of_integer 7 (Nat_big_num.of_int 64)) + +let translate_reg_index = translate_int 5 + +let translate_boolean = translate_bool + +let translate_range0_7 = translate_int 3 + +let translate_range0_63 = translate_int 6 + +let translate_bit64 = translate_big_bit 64 + +let translate_bit4 = translate_bits 4 +let translate_bit5 = translate_bits 5 +let translate_bit16 = translate_bits 16 + +let translate_bit = translate_bool + +let translate_range8_64 = translate_int 7 + +let translate_uinteger = translate_int 63 + +let translate_extendType = + translate_enum [ExtendType_SXTB; ExtendType_SXTH; ExtendType_SXTW; ExtendType_SXTX; + ExtendType_UXTB; ExtendType_UXTH; ExtendType_UXTW; ExtendType_UXTX] + +let translate_shiftType = + translate_enum [ShiftType_LSL; ShiftType_LSR; ShiftType_ASR; ShiftType_ROR] + +let translate_logicalOp = + translate_enum [LogicalOp_AND; LogicalOp_EOR; LogicalOp_ORR] + +let translate_branchType = + translate_enum [BranchType_CALL; BranchType_ERET; BranchType_DBGEXIT; + BranchType_RET; BranchType_JMP; BranchType_EXCEPTION; + BranchType_UNKNOWN] + +let translate_countOp = + translate_enum [CountOp_CLZ;CountOp_CLS;CountOp_CNT] + +let translate_memBarrierOp= + translate_enum [MemBarrierOp_DSB; MemBarrierOp_DMB; MemBarrierOp_ISB] + +let translate_mBReqDomain = + translate_enum [MBReqDomain_Nonshareable; MBReqDomain_InnerShareable; + MBReqDomain_OuterShareable; MBReqDomain_FullSystem] + +let translate_mBReqTypes = + translate_enum [MBReqTypes_Reads; MBReqTypes_Writes; MBReqTypes_All] + +let translate_systemHintOp = + translate_enum [SystemHintOp_NOP; SystemHintOp_YIELD; SystemHintOp_WFE; + SystemHintOp_WFI; SystemHintOp_SEV; SystemHintOp_SEVL] + +let translate_accType = + translate_enum [AccType_NORMAL; AccType_VEC; AccType_STREAM; + AccType_VECSTREAM; AccType_ATOMIC; AccType_ORDERED; + AccType_UNPRIV; AccType_IFETCH; AccType_PTW; + AccType_DC; AccType_IC; AccType_AT] + +let translate_memOp = + translate_enum [MemOp_LOAD; MemOp_STORE; MemOp_PREFETCH] + +let translate_moveWideOp = + translate_enum [MoveWideOp_N; MoveWideOp_Z; MoveWideOp_K] + +let translate_revOp = + translate_enum [RevOp_RBIT; RevOp_REV16; RevOp_REV32; RevOp_REV64] + +let translate_pSTATEField = + translate_enum [PSTATEField_DAIFSet; PSTATEField_DAIFClr; PSTATEField_SP] |
