MODULE FoxARMInstructionSet; (** AUTHOR ""; PURPOSE ""; *) IMPORT D := Debugging, Commands, Streams, Files, BinaryCode := FoxBinaryCode, Disassembler := FoxDisassembler, BitSets, Options, Strings, ObjectFile; CONST TraceDecode= FALSE; None*= -1; (* condition codes, values refer to encoding, do not modify *) conditionEQ*= 0; conditionNE*= 1; conditionCS*= 2; conditionHS*= 2; conditionCC*= 3; conditionLO*= 3; conditionMI*= 4; conditionPL*= 5; conditionVS*= 6; conditionVC*= 7; conditionHI*= 8; conditionLS*= 9; conditionGE*= 10; conditionLT*= 11; conditionGT*= 12; conditionLE*= 13; conditionAL*= 14; unconditional*= conditionAL; conditionNV*= 15; NumberConditionEntries*= 18; (* indexing flags, values have no meaning in encoding *) Increment*= 0; Decrement*= 1; PostIndexed*= 2; PreIndexed*= 3; (* mnemonics, values have no meaning for encoding FoxProgTools.Enum -l=4 opADC opADD opAND opB opBIC opBKPT opBL opBLX opBX opCDP opCDP2 opCLZ opCMN opCMP opEOR opFABSD opFABSS opFADDD opFADDS opFCMPD opFCMPED opFCMPES opFCMPEZD opFCMPEZS opFCMPS opFCMPZD opFCMPZS opFCPYD opFCPYS opFCVTDS opFCVTSD opFDIVD opFDIVS opFLDD opFLDMIAD opFLDMIAS opFLDMIAX opFLDMDBD opFLDMDBS opFLDMDBX opFLDS opFMACD opFMACS opFMDHR opFMDLR opFMRDH opFMRDL opFMRS opFMRX opFMSCD opFMSCS opFMSR opFMSTAT opFMULD opFMULS opFMXR opFNEGD opFNEGS opFNMACD opFNMACS opFNMSCD opFNMSCS opFNMULD opFNMULS opFSITOD opFSITOS opFSQRTD opFSQRTS opFSTD opFSTMIAD opFSTMIAS opFSTMIAX opFSTMDBD opFSTMDBS opFSTMDBX opFSTS opFSUBD opFSUBS opFTOSID opFTOSIZD opFTOSIS opFTOSIZS opFTOUID opFTOUIZD opFTOUIS opFTOUIZS opFUITOD opFUITOS opLDC opLDC2 opLDM opLDR opMCR opMCR2 opMCRR opMLA opMOV opMRC opMRC2 opMRRC opMRS opMSR opMUL opMVN opORR opPLD opQADD opQDADD opQDSUB opQSUB opRSB opRSC opSBC opSMLABB opSMLABT opSMLAL opSMLATB opSMLATT opSMLALBB opSMLALBT opSMLALTB opSMLALTT opSMLAWB opSMLAWT opSMULBB opSMULBT opSMULTB opSMULTT opSMULWB opSMULWT opSMULL opSTC opSTC2 opSTM opSTR opSUB opSWI opSWP opTEQ opTST opUMLAL opUMULL NumberMnemonics ~ *) opADC*= 0; opADD*= 1; opAND*= 2; opB*= 3; opBIC*= 4; opBKPT*= 5; opBL*= 6; opBLX*= 7; opBX*= 8; opCDP*= 9; opCDP2*= 10; opCLZ*= 11; opCMN*= 12; opCMP*= 13; opEOR*= 14; opFABSD*= 15; opFABSS*= 16; opFADDD*= 17; opFADDS*= 18; opFCMPD*= 19; opFCMPED*= 20; opFCMPES*= 21; opFCMPEZD*= 22; opFCMPEZS*= 23; opFCMPS*= 24; opFCMPZD*= 25; opFCMPZS*= 26; opFCPYD*= 27; opFCPYS*= 28; opFCVTDS*= 29; opFCVTSD*= 30; opFDIVD*= 31; opFDIVS*= 32; opFLDD*= 33; opFLDMIAD*= 34; opFLDMIAS*= 35; opFLDMIAX*= 36; opFLDMDBD*= 37; opFLDMDBS*= 38; opFLDMDBX*= 39; opFLDS*= 40; opFMACD*= 41; opFMACS*= 42; opFMDHR*= 43; opFMDLR*= 44; opFMRDH*= 45; opFMRDL*= 46; opFMRS*= 47; opFMRX*= 48; opFMSCD*= 49; opFMSCS*= 50; opFMSR*= 51; opFMSTAT*= 52; opFMULD*= 53; opFMULS*= 54; opFMXR*= 55; opFNEGD*= 56; opFNEGS*= 57; opFNMACD*= 58; opFNMACS*= 59; opFNMSCD*= 60; opFNMSCS*= 61; opFNMULD*= 62; opFNMULS*= 63; opFSITOD*= 64; opFSITOS*= 65; opFSQRTD*= 66; opFSQRTS*= 67; opFSTD*= 68; opFSTMIAD*= 69; opFSTMIAS*= 70; opFSTMIAX*= 71; opFSTMDBD*= 72; opFSTMDBS*= 73; opFSTMDBX*= 74; opFSTS*= 75; opFSUBD*= 76; opFSUBS*= 77; opFTOSID*= 78; opFTOSIZD*= 79; opFTOSIS*= 80; opFTOSIZS*= 81; opFTOUID*= 82; opFTOUIZD*= 83; opFTOUIS*= 84; opFTOUIZS*= 85; opFUITOD*= 86; opFUITOS*= 87; opLDC*= 88; opLDC2*= 89; opLDM*= 90; opLDR*= 91; opMCR*= 92; opMCR2*= 93; opMCRR*= 94; opMLA*= 95; opMOV*= 96; opMRC*= 97; opMRC2*= 98; opMRRC*= 99; opMRS*= 100; opMSR*= 101; opMUL*= 102; opMVN*= 103; opORR*= 104; opPLD*= 105; opQADD*= 106; opQDADD*= 107; opQDSUB*= 108; opQSUB*= 109; opRSB*= 110; opRSC*= 111; opSBC*= 112; opSMLABB*= 113; opSMLABT*= 114; opSMLAL*= 115; opSMLATB*= 116; opSMLATT*= 117; opSMLALBB*= 118; opSMLALBT*= 119; opSMLALTB*= 120; opSMLALTT*= 121; opSMLAWB*= 122; opSMLAWT*= 123; opSMULBB*= 124; opSMULBT*= 125; opSMULTB*= 126; opSMULTT*= 127; opSMULWB*= 128; opSMULWT*= 129; opSMULL*= 130; opSTC*= 131; opSTC2*= 132; opSTM*= 133; opSTR*= 134; opSUB*= 135; opSWI*= 136; opSWP*= 137; opTEQ*= 138; opTST*= 139; opUMLAL*= 140; opUMULL*= 141; (* Usual mnemonics, cont'd *) opISB* = 142; (* NEON mnemonics *) opVADD* = 143; opVADDL* = 144; opVADDW* = 145; opVMUL* = 146; opVMULL* = 147; opVMSR* = 148; opVMRS* = 149; opVLDR* = 150; opVSTR* = 151; opVDIV* = 152; opVMLA* = 153; opVMLS* = 154; opVMIN* = 155; opVMAX* = 156; opVSUB* = 157; opVABS* = 158; opVABD* = 159; (* Usual shifts *) opLSL* = 160; opLSR* = 161; (* More NEON *) opVLD1* = 162; opVST1* = 163; opVPADD* = 164; opVMOV* = 165; (* Non NEON Instructions *) opSEV* = 166; opDSB* = 167; opLDREX* = 168; opSTREX* = 169; opADR* = 170; opLDREXB* = 171; opSTREXB* = 172; opDMB* = 173; opCLREX* = 174; opREV* = 175; opREV16* = 176; opUXTH* = 177; opWFE* = 178; opWFI* = 179; opMOVW* = 180; NumberMnemonics*= 181; MaxOperands* = 6; (* flags values have no meaning for encoding FoxProgTools.Enum -l= 4 flagB flagBT flagD flagDA flagDB flagH flagIA flagIB flagL flagS flagSB flagSH flagT NumberFlags flagCondition flagUserMode flagBaseRegisterUpdate ~ *) flagB*= 0; flagBT*= 1; flagD*= 2; flagDA*= 3; flagDB*= 4; flagH*= 5; flagIA*= 6; flagIB*= 7; flagL*= 8; flagS*= 9; flagSB*= 10; flagSH*= 11; flagT*= 12; (*NumberFlags*= 13;*) (* NEON data type flags *) flagNEON8bits = 13; flagNEON16bits = 14; flagNEON32bits = 15; flagNEON64bits = 16; flagNEONInt = 17; flagNEONSigned = 18; flagNEONUnsigned = 19; flagNEONFloat = 20; flagNEONPoly = 21; flagNEONUndef = 22; NumberFlags* = 23; (* Flags not used *) flagCondition*= 23; flagUserMode*= 24; flagBaseRegisterUpdate*= 25; NumberInstructions= NumberMnemonics + 19; (* encoding types, values have no meaning for encoding FoxProgTools.Enum -l=4 encodingR16 encodingR12 encodingR8 encodingR0 encodingAddressingMode1 encodingAddressingMode2 encodingAddressingMode3 encodingAddressingMode5 encodingCoprocessor encodingCR0 encodingCR12 encodingCR16 encodingOpcode20 encodingOpcode21 encodingOpcode5 encodingOpcode4 encodingSignedImm24 encodingImm24 encodingImm16 encodingRotImm8 encodingRegisterList encodingPSR encodingFields encodingDR0 encodingDR12 encodingDR16 encodingFR0 encodingFR12 encodingFR16 encodingDRegisterList encodingFRegisterList encodingAddressingMode5V ~ *) encodingR16= 0; encodingR12= 1; encodingR8= 2; encodingR0= 3; encodingAddressingMode1= 4; encodingAddressingMode2= 5; encodingAddressingMode3= 6; encodingAddressingMode5= 7; encodingCoprocessor= 8; encodingCR0= 9; encodingCR12= 10; encodingCR16= 11; encodingOpcode20= 12; encodingOpcode21= 13; encodingOpcode5= 14; encodingOpcode4= 15; encodingSignedImm24= 16; encodingImm24= 17; encodingImm16= 18; encodingRotImm8= 19; encodingRegisterList= 20; encodingPSR= 21; encodingFields= 22; encodingDR0= 23; encodingDR12= 24; encodingDR16= 25; encodingFR0= 26; encodingFR12= 27; encodingFR16= 28; encodingDRegisterList= 29; encodingFRegisterList= 30; encodingAddressingMode5V= 31; (* NEON operand encoding. *) encodingNEONQd = 32; encodingNEONQn = 33; encodingNEONQm = 34; encodingNEONDd = 35; encodingNEONDn = 36; encodingNEONDm = 37; encodingNEONSd = 38; encodingNEONSn = 39; encodingNEONSm = 40; encodingNEONImmAndSize = 41; encodingNEON8bitImm = 42; (*at bit 0 *) encodingNEON3bitImm = 43; encodingNEONQorDd = 44; encodingNEONQorDn = 45; encodingNEONQorDm = 46; encodingNEONDorSd = 47; encodingNEONDorSn = 48; encodingNEONDorSm = 49; encodingNEONDRegList = 50; encodingNEONSysReg = 51; encodingNEONSigned8bitImm = 52; encodingImm7to11 = 53; encodingImm12a0imm4a16 = 54; (* immediate encoded 19...16, 11..0 *) (* NEON instruction mode encoding. These modes are used in EnterNEONInstruction. Values do not matter for encoding. The values mean (see the ARM manual): encodeNEON... ...3RegSame: 3 registers of the same type ...3RegDiff: 3 registers of different types ...2RegScalar: 2 registers and a scalar ...2RegShift: 2 registers and a shift ...2RegMisc: 2 registers miscellanous ...1RegImm: 1 register and an immediate ...VFP: VFP operation ...LS: load and stores ...Tx32: transfers up to 32bits ...Tx64: transfers of 64bits encodeNEON3RegSame = 0; encodeNEON3RegLong = 1; encodeNEON3RegNarrow = 2; encodeNEON3RegWide = 3; encodeNEON2RegScalar = 4; encodeNEON2RegScalarLong = 5; encodeNEON2RegShift = 6; encodeNEON2RegShiftNarrow = 7; encodeNEON2RegShiftLong = 8; encodeNEON2RegMisc = 9; encodeNEON2RegMiscNarrow = 10; encodeNEON2RegMiscLong = 11; encodeNEONVFP = 12; encodeNEONVFP2Reg = 13; encodeNEONVFP1Reg = 14;*) (* operand modes FoxProgTools.Enum -l= 4 modeImmediate modeRegister modeMemory modeOpcode modeCoprocessor modeRegisterList modeFields modeOption ~ *) modeImmediate*= 0; modeRegister*= 1; modeMemory*= 2; modeOpcode*= 3; modeCoprocessor*= 4; modeRegisterList*= 5; modeRegisterWithFields*= 6; modeOption*= 7; (* registers, values have no meaning for encoding *) (* regular registers: *) R0*= 0; R1*= R0+1; R2*= R0+2; R3*= R0+3; R4*= R0+4; R5*= R0+5; R6*= R0+6; R7*= R0+7; R8*= R0+8; R9*= R0+9; R10*= R0+10; R11*= R0+11; R12*= R0+12; R13*= R0+13; R14*= R0+14; R15*= R0+15; (* coprocessor registers: *) CR0*= 16; CR1*= CR0+1; CR2*= CR0+2; CR3*= CR0+3; CR4*= CR0+4; CR5*= CR0+5; CR6*= CR0+6; CR7*= CR0+7; CR8*= CR0+8; CR9*= CR0+9; CR10*= CR0+10; CR11*= CR0+11; CR12*= CR0+12; CR13*= CR0+13; CR14*= CR0+14; CR15*= CR0+15; (* VFP double-precision registers: *) DR0*= 32; DR1*= DR0+1; DR2*= DR0+2; DR3*= DR0+3; DR4*= DR0+4; DR5*= DR0+5; DR6*= DR0+6; DR7*= DR0+7; DR8*= DR0+8; DR9*= DR0+9; DR10*= DR0+10; DR11*= DR0+11; DR12*= DR0+12; DR13*= DR0+13; DR14*= DR0+14; DR15*= DR0+15; (* Advanced SIMD doubleword registers *) DR16*= DR0+16; DR17*= DR0+17; DR18*= DR0+18; DR19*= DR0+19; DR20*= DR0+20; DR21*= DR0+21; DR22*= DR0+22; DR23*= DR0+23; DR24*= DR0+24; DR25*= DR0+25; DR26*= DR0+26; DR27*= DR0+27; DR28*= DR0+28; DR29*= DR0+29; DR30*= DR0+30; DR31*= DR0+31; (* VFP single-precision registers: *) SR0*= 64; SR1*= SR0+1; SR2*= SR0+2; SR3*= SR0+3; SR4*= SR0+4; SR5*= SR0+5; SR6*= SR0+6; SR7*= SR0+7; SR8*= SR0+8; SR9*= SR0+9; SR10*= SR0+10; SR11*= SR0+11; SR12*= SR0+12; SR13*= SR0+13; SR14*= SR0+14; SR15*= SR0+15; (* progran status registers *) CPSR*= 80; SPSR*= 81; (* Continue at 82 to skip CPSR and SPSR *) SR16*= 82; SR17*= SR0+17; SR18*= SR0+18; SR19*= SR0+19; SR20*= SR0+20; SR21*= SR0+21; SR22*= SR0+22; SR23*= SR0+23; SR24*= SR0+24; SR25*= SR0+25; SR26*= SR0+26; SR27*= SR0+27; SR28*= SR0+28; SR29*= SR0+29; SR30*= SR0+30; SR31*= SR0+31; (* NEON SIMD quadword registers *) QR0* = 98; QR1* = QR0 + 1; QR2* = QR0 + 2;QR3* = QR0 + 3; QR4* = QR0 + 4; QR5* = QR0 + 5; QR6* = QR0 + 6; QR7* = QR0 + 7; QR8* = QR0 + 8; QR9* = QR0 + 9; QR10* = QR0 + 10; QR11* = QR0 + 11; QR12* = QR0 + 12; QR13* = QR0 + 13; QR14* = QR0 + 14; QR15* = QR0 + 15; (* NEON System Registers *) FPSID* = 114; FPSCR* = 115; FPEXC* = 116; (* register aliases *) PC*= R15; LR*= R14; SP*= R13; FP*= R12; RESHI*= R1; RES*= R0; RESFS*= SR0; RESFD*= DR0; NumberRegisters*= 117; (* the number of physical registers *) NumberRegisterEntries*= 123; (* the number of register names *) (* shifts, do not modify: nunbers as in encoding*) shiftLSL*= 0; shiftLSR*= 1; shiftASR*= 2; shiftROR*= 3; shiftRRX*= 4; NumberShifts*= 5; (* coprocessors, do not modify: number as in encoding *) CP0* = 0; CP1* = 1; CP2* = 2; CP3* = 3; CP4* = 4; CP5* = 5; CP6* = 6; CP7* = 7; CP8* = 8; CP9* = 9; CP10* = 10; CP11* = 11; CP12* = 12; CP13* = 13; CP14* = 14; CP15* = 15; NumberCoprocessors* = 16; (* fields, do not modify: number order as in encoding *) fieldC* = 0; fieldX* = 1; fieldS* = 2; fieldF* = 3; Bits12*=4096; Bits10*=1024; Bits7*=128; Bits5*=32; (* ArmEncoding* = 0; ThumbEncoding* = 1; *) TYPE Name = ARRAY 10 OF CHAR; Entry = RECORD name: Name; number: LONGINT END; Mnemonic= RECORD name: Name; number: INTEGER; firstInstructionFormat, lastInstructionFormat: LONGINT; (* instructionFormats *) END; InstructionFormat= RECORD mnemonic: INTEGER; opcode, mask: SET; flags: SET; operands: ARRAY MaxOperands OF INTEGER; (* NEON specific *) isNEON: BOOLEAN; Unsigned, Quadword, Length, Float, Operation: SET; SizeH: INTEGER; (* The lower bit is SizeH - 1 *) END; Instruction*= RECORD format: LONGINT; condition: LONGINT; flags: SET; operands: ARRAY MaxOperands OF Operand; END; Operand*= RECORD mode*: INTEGER; register*: LONGINT; immediate*, shiftImmediate: LONGINT; shiftRegister: LONGINT; shiftMode: INTEGER; offsetImmediate: LONGINT; offsetRegister: LONGINT; indexing: SET; (* Increment, Decrement, PostIndexed PreIndexed*) registerList: SET; coprocessor: INTEGER; opcode: LONGINT; fields: SET; option: LONGINT; fixup-: BinaryCode.Fixup; END; VAR mnemonics: ARRAY NumberMnemonics OF Mnemonic; registerEntries: ARRAY NumberRegisterEntries OF Entry; conditionEntries: ARRAY NumberConditionEntries OF Entry; flagNames: ARRAY NumberFlags OF Name; shiftNames: ARRAY NumberShifts OF Name; coprocessorNames: ARRAY NumberCoprocessors OF Name; instructionFormats : ARRAY NumberInstructions OF InstructionFormat; (** get the number of a register by its name - 'None' is returned if no such register exists **) PROCEDURE RegisterNumberFromName*(registerName: ARRAY OF CHAR): LONGINT; VAR result, i: LONGINT; BEGIN Strings.UpperCase(registerName); result := None; (* go through all registers *) FOR i := 0 TO NumberRegisterEntries - 1 DO IF registerEntries[i].name = registerName THEN result := registerEntries[i].number END END; RETURN result END RegisterNumberFromName; (** get the number of a coprocessor by its name - 'None' is returned if no such mode exists **) PROCEDURE CoprocessorNumberFromName*(coprocessorName: ARRAY OF CHAR): LONGINT; VAR result, i: LONGINT; BEGIN Strings.UpperCase(coprocessorName); result := None; (* go through all coprocessors *) FOR i := 0 TO NumberCoprocessors - 1 DO IF coprocessorNames[i] = coprocessorName THEN result := i END END; RETURN result END CoprocessorNumberFromName; (** get the number of a shift mode by its name - 'None' is returned if no such mode exists **) PROCEDURE ShiftModeNumberFromName*(shiftModeName: ARRAY OF CHAR): LONGINT; VAR result, i: LONGINT; BEGIN Strings.UpperCase(shiftModeName); result := None; (* go through all shift modes *) FOR i := 0 TO NumberShifts - 1 DO IF shiftNames[i] = shiftModeName THEN result := i END END; RETURN result END ShiftModeNumberFromName; PROCEDURE FindMnemonic*(CONST name: ARRAY OF CHAR; VAR mnemonic, condition: LONGINT; VAR flags: SET): BOOLEAN; VAR i, pos, flagPos, format: LONGINT; PROCEDURE Contains(CONST this: ARRAY OF CHAR): BOOLEAN; VAR i: LONGINT; BEGIN ASSERT(this # ""); i := 0; WHILE (name[pos+i] # 0X) & (this[i] # 0X) & (CAP(name[i+pos])= this[i]) DO INC(i) END; IF this[i]= 0X THEN INC(pos, i); RETURN TRUE ELSE RETURN FALSE END; END Contains; BEGIN ASSERT(name # ""); mnemonic := NumberMnemonics; REPEAT DEC(mnemonic); flags := {}; pos := 0; (* find matching mnemonic, not necessarily unique! *) WHILE (mnemonic >= 0) & ~Contains(mnemonics[mnemonic].name) DO DEC(mnemonic) END; IF mnemonic >= 0 THEN flagPos := pos; format := mnemonics[mnemonic].firstInstructionFormat; (* found mnemonic, check if flags match with at least one format *) REPEAT ASSERT(instructionFormats[format].mnemonic = mnemonic); pos := flagPos; (* conditions *) IF flagCondition IN instructionFormats[format].flags THEN (* read condition *) i := NumberConditionEntries-1; WHILE (i>= 0) &~Contains(conditionEntries[i].name) DO DEC(i) END; IF i # -1 THEN INCL(flags, flagCondition); condition := conditionEntries[i].number ELSE condition := conditionAL (* no condition: always execute *) END; ELSE condition := conditionAL END; (* read flags, have to go downward because of name inclusions *) i := NumberFlags-1; WHILE (i>=0) & (name[pos] # 0X) DO IF (i IN instructionFormats[format].flags) & Contains(flagNames[i]) THEN INCL(flags, i) END; DEC(i); END; INC(format); UNTIL (format > mnemonics[mnemonic].lastInstructionFormat) OR (name[pos] = 0X) END; UNTIL (mnemonic = None) OR (name[pos] = 0X); RETURN (mnemonic # None) END FindMnemonic; PROCEDURE InitInstruction*(VAR instruction: Instruction); VAR i : LONGINT; BEGIN instruction.format := None; instruction.condition := None; instruction.flags := {}; FOR i := 0 TO LEN(instruction.operands)-1 DO InitOperand(instruction.operands[i]); END; END InitInstruction; (* generate immediate operand with fixup *) PROCEDURE InitFixup*(VAR operand: Operand; bits: SHORTINT; fixup: BinaryCode.Fixup (*symbol: Sections.Section; offset, displacement: LONGINT *)); BEGIN operand.mode := modeImmediate; operand.immediate := 0; operand.fixup := fixup; (* operand.fixup := BinaryCode.NewFixup(BinaryCode.Absolute, 0, symbol, offset, displacement, 0, NIL); *) (* operand.symbol := symbol; operand.symbolOffset := offset; operand.displacement := displacement; *) END InitFixup; PROCEDURE AddFixup*(VAR operand: Operand; fixup: BinaryCode.Fixup); BEGIN ASSERT(operand.mode IN {modeImmediate, modeMemory}); operand.fixup := fixup END AddFixup; PROCEDURE InitOperand*(VAR operand: Operand); BEGIN operand.mode := None; operand.register := None; operand.immediate := 0; operand.shiftImmediate := 0; operand.shiftRegister := None; operand.offsetRegister := None; operand.shiftMode := None; operand.offsetImmediate := 0; operand.indexing := {}; operand.registerList := {}; operand.coprocessor := None; operand.opcode := 0; operand.fields := {}; operand.fixup := NIL; END InitOperand; PROCEDURE InitRegister*(VAR operand: Operand; registerNumber: LONGINT; shiftMode: LONGINT; shiftAmountRegisterNumber: LONGINT; shiftImmediate: LONGINT); BEGIN InitOperand(operand); operand.mode := modeRegister; operand.register := SHORT(registerNumber); operand.shiftMode := SHORT(shiftMode); operand.shiftRegister := SHORT(shiftAmountRegisterNumber); operand.shiftImmediate := shiftImmediate END InitRegister; PROCEDURE InitImmediate*(VAR operand: Operand; immediate: LONGINT); BEGIN InitOperand(operand); operand.mode := modeImmediate; operand.immediate := immediate; END InitImmediate; (* note that this is a memory operand to be used in a load/store instruction *) PROCEDURE InitImmediateOffsetMemory*(VAR operand: Operand; register: LONGINT; offset: LONGINT; indexing: SET); BEGIN InitOperand(operand); operand.mode := modeMemory; operand.register := SHORT(register); operand.offsetImmediate := offset; operand.indexing := indexing; END InitImmediateOffsetMemory; (* note that this is a memory operand to be used in a load/store instruction *) PROCEDURE InitRegisterOffsetMemory*(VAR operand: Operand; register, offsetRegister: LONGINT; shiftMode: LONGINT; shiftImmediate: LONGINT; indexing: SET); BEGIN InitOperand(operand); operand.mode := modeMemory; operand.register := SHORT(register); operand.offsetRegister := SHORT(offsetRegister); operand.indexing := indexing; IF operand.shiftImmediate < 0 THEN operand.shiftImmediate := -operand.shiftImmediate; INCL(operand.indexing, Decrement); EXCL(operand.indexing, Increment); END; operand.shiftMode := SHORT(shiftMode); operand.shiftImmediate := shiftImmediate; END InitRegisterOffsetMemory; PROCEDURE NewRegister*(registerNumber: LONGINT; shiftMode: LONGINT; shiftAmountRegisterNumber: LONGINT; shiftImmediate: LONGINT): Operand; VAR result: Operand; BEGIN InitRegister(result, registerNumber, shiftMode, shiftAmountRegisterNumber, shiftImmediate); RETURN result END NewRegister; PROCEDURE NewImmediate*(immediate: LONGINT): Operand; VAR result: Operand; BEGIN InitImmediate(result, immediate); RETURN result END NewImmediate; PROCEDURE NewImmediateOffsetMemory*(register: LONGINT; offset: LONGINT; indexing: SET): Operand; VAR result: Operand; BEGIN InitImmediateOffsetMemory(result, register, offset, indexing); RETURN result END NewImmediateOffsetMemory; PROCEDURE NewRegisterOffsetMemory*(register, offsetRegister: LONGINT; shiftMode: LONGINT; shiftImmediate: LONGINT; indexing: SET): Operand; VAR result: Operand; BEGIN InitRegisterOffsetMemory(result, register, offsetRegister, shiftMode, shiftImmediate, indexing); RETURN result END NewRegisterOffsetMemory; PROCEDURE NewRegisterList*(registerBase: LONGINT; registerList: SET): Operand; VAR result: Operand; BEGIN InitRegisterList(result, registerBase, registerList); RETURN result END NewRegisterList; PROCEDURE InitOption*(VAR operand: Operand; register: LONGINT; option: LONGINT); BEGIN InitOperand(operand); operand.mode := modeOption; operand.register := SHORT(register); operand.option := option; END InitOption; PROCEDURE InitCoprocessor*(VAR operand: Operand; coprocessor: LONGINT); BEGIN InitOperand(operand); operand.mode := modeCoprocessor; operand.coprocessor := SHORT(coprocessor); END InitCoprocessor; PROCEDURE InitOpcode*(VAR operand: Operand; opcode: LONGINT); BEGIN InitOperand(operand); operand.mode := modeOpcode; operand.opcode := opcode; END InitOpcode; PROCEDURE InitRegisterList*(VAR operand: Operand; registerBase: LONGINT; registerList: SET); BEGIN InitOperand(operand); operand.mode := modeRegisterList; operand.register := SHORT(registerBase); operand.registerList := registerList; END InitRegisterList; PROCEDURE InitRegisterWithFields*(VAR operand: Operand; registerNumber: LONGINT; fields: SET); BEGIN ASSERT((registerNumber = CPSR) OR (registerNumber = SPSR)); InitOperand(operand); operand.mode := modeRegisterWithFields; operand.register := registerNumber; operand.fields := fields END InitRegisterWithFields; PROCEDURE NewRegisterWithFields*(registerNumber: LONGINT; fields: SET): Operand; VAR result: Operand; BEGIN InitRegisterWithFields(result, registerNumber, fields); RETURN result END NewRegisterWithFields; PROCEDURE MakeInstruction*(VAR instruction: Instruction; mnemonic, condition: LONGINT; flags: SET; CONST operands: ARRAY OF Operand): BOOLEAN; VAR format: InstructionFormat; i, dummyEncoding: LONGINT; result: BOOLEAN; PROCEDURE OperandMatches(encoding: LONGINT; CONST operand: Operand): BOOLEAN; BEGIN CASE encoding OF |None: RETURN operand.mode = None |encodingR16, encodingR12, encodingR8, encodingR0: RETURN (operand.mode = modeRegister) & (R0 <= operand.register) & (operand.register <= R15) |encodingFR0, encodingFR12, encodingFR16: RETURN (operand.mode = modeRegister) & (SR0 <= operand.register) & (operand.register <= SR31) |encodingDR0,encodingDR12, encodingDR16: RETURN (operand.mode = modeRegister) & (DR0 <= operand.register) & (operand.register <= DR15) |encodingCR0, encodingCR12, encodingCR16: RETURN (operand.mode = modeRegister) & (CR0 <= operand.register) & (operand.register <= CR15) |encodingAddressingMode1: RETURN (operand.mode = modeRegister) & (R0 <= operand.register) & (operand.register <= R15) OR (operand.mode = modeImmediate) |encodingAddressingMode2: RETURN (operand.mode = modeMemory) |encodingAddressingMode3: RETURN (operand.mode = modeMemory) |encodingAddressingMode5: RETURN (operand.mode = modeMemory) OR (operand.mode = modeOption) |encodingAddressingMode5V: RETURN (operand.mode = modeMemory) |encodingCoprocessor: RETURN (operand.mode = modeCoprocessor) |encodingFields: RETURN operand.mode = modeRegisterWithFields |encodingImm16,encodingSignedImm24,encodingImm24,encodingRotImm8, encodingImm7to11, encodingImm12a0imm4a16: RETURN operand.mode = modeImmediate |encodingOpcode20,encodingOpcode21,encodingOpcode5,encodingOpcode4: RETURN (operand.mode = modeOpcode) OR (operand.mode = None) (* note: missing opcode operand means opcode = 0 *) |encodingRegisterList, encodingDRegisterList, encodingFRegisterList: RETURN operand.mode = modeRegisterList |encodingPSR: RETURN (operand.mode = modeRegister) & ((operand.register = CPSR) OR (operand.register = SPSR)) |encodingNEONQd, encodingNEONQm, encodingNEONQn: RETURN (operand.mode = modeRegister) & (QR0 <= operand.register) & (operand.register <= QR15) |encodingNEONDd, encodingNEONDm, encodingNEONDn: RETURN (operand.mode = modeRegister) & (DR0 <= operand.register) & (operand.register <= DR31) |encodingNEONSd, encodingNEONSm, encodingNEONSn: RETURN (operand.mode = modeRegister) & (SR0 <= operand.register) & (operand.register <= SR31) |encodingNEONQorDd, encodingNEONQorDm, encodingNEONQorDn: RETURN (operand.mode = modeRegister) & (((DR0 <= operand.register) & (operand.register <= DR31)) OR ((QR0 <= operand.register) & (operand.register <= QR15))) |encodingNEONDorSd, encodingNEONDorSm, encodingNEONDorSn: RETURN (operand.mode = modeRegister) & (((DR0 <= operand.register) & (operand.register <= DR15)) OR ((SR0 <= operand.register) & (operand.register <= SR31))) |encodingNEONImmAndSize, encodingNEON8bitImm, encodingNEON3bitImm, encodingNEONSigned8bitImm: RETURN operand.mode = modeImmediate |encodingNEONDRegList: RETURN operand.mode = modeRegisterList |encodingNEONSysReg: RETURN (operand.mode = modeRegister) & (FPSID <= operand.register) & (operand.register <= FPEXC) ELSE RETURN FALSE END; END OperandMatches; PROCEDURE Matches(CONST format: InstructionFormat): BOOLEAN; VAR i: LONGINT; BEGIN IF mnemonic # format.mnemonic THEN RETURN FALSE END; (* different mnemonic *) IF (instruction.condition # conditionAL) & (instruction.condition # None) & ~(flagCondition IN format.flags) THEN (* not always case for encoding problems of BLX which comes in two forms *) RETURN FALSE END; (* unpermitted condition *) IF instruction.flags * format.flags # instruction.flags THEN RETURN FALSE END; (* unpermitted flags*) i := 0; WHILE (i= 31); set := {}; FOR i := 0 TO 31 DO IF ODD(code) THEN INCL(set, i) END; code := code DIV 2; END; RETURN set END NumberToSet; PROCEDURE SetToNumber(set: SET): LONGINT; VAR i, num: LONGINT; BEGIN ASSERT(MAX(SET) >= 31); num := 0; FOR i := 0 TO 31 DO IF i IN set THEN INC(num, ASH(1, i)) END; END; RETURN num END SetToNumber; PROCEDURE RotateRight(val, rot: LONGINT): LONGINT; VAR set: SET; i, dest: LONGINT; BEGIN set := NumberToSet(val); dest := 0; FOR i := 0 TO 31 DO IF i IN set THEN INC(dest, ASH(1, (i-rot) MOD 32)); END; END; RETURN dest END RotateRight; PROCEDURE EncodeImmediate*(imm: LONGINT; VAR val,rot: LONGINT): BOOLEAN; VAR immSet: SET; i: LONGINT; PROCEDURE RotateLeft(set: SET; rot: LONGINT): SET; VAR i: LONGINT; result: SET; BEGIN result := {}; FOR i := 0 TO 31 DO IF i IN set THEN INCL(result,(i+rot) MOD 32) END; END; RETURN result END RotateLeft; BEGIN immSet := NumberToSet(imm); rot := 0; WHILE (rot<16) & (immSet*{8..31} # {}) DO INC(rot,1); immSet := RotateLeft(immSet,2); END; val := 0; FOR i := 7 TO 0 BY -1 DO val := val*2; IF i IN immSet THEN INC(val) END; END; RETURN rot <16 END EncodeImmediate; PROCEDURE Encode(CONST instruction: Instruction; VAR code: LONGINT): BOOLEAN; VAR format: InstructionFormat; codeSet: SET; i: LONGINT; error: BOOLEAN; flags: SET; CONST P=24; U=23; B=22; W=21; L=20; S=6; H=5; PROCEDURE Unsigned(val: LONGINT; from,to: LONGINT); VAR i: LONGINT; BEGIN FOR i := from TO to DO IF ODD(val) THEN INCL(codeSet,i) END; val := val DIV 2; END; IF val # 0 THEN error := TRUE END; IF error THEN D.TraceBack END END Unsigned; (* Encode an unsigned value on a non-contiguous set of bits, specifying the order. val: value to encode positions: array of bit positions, from the lowest to the highest. The end of the encoding region is signaled by: end of the array a position has value 32 *) PROCEDURE SplittedUnsigned(val: LONGINT; positions: ARRAY OF INTEGER); VAR i, len: LONGINT; BEGIN ASSERT(LEN(positions) <= 32); FOR i := 0 TO LEN(positions) - 1 DO ASSERT(positions[i] <= 32); ASSERT(positions[i] >= 0) END; i := 0; WHILE (i < LEN(positions)) & (positions[i] # 32) DO INC(i) END; len := i; (*D.String("Splitted unsigned length: "); D.Int(i, 0); D.Ln;*) FOR i := 0 TO len - 1 DO IF ODD(val) THEN INCL(codeSet, positions[i]) END; val := val DIV 2; END; IF val # 0 THEN error := TRUE; D.TraceBack END END SplittedUnsigned; PROCEDURE Bits(val: SET; from,to: LONGINT); VAR i: LONGINT; BEGIN FOR i := from TO to DO IF i-from IN val THEN INCL(codeSet,i) END; END; IF val * {to-from+1..31} # {} THEN error := TRUE END; END Bits; PROCEDURE Signed(val: LONGINT; from,to: LONGINT); VAR i: LONGINT; negate: BOOLEAN; BEGIN negate := val < 0; IF negate THEN val := -val -1 END; FOR i := from TO to-1 DO IF ODD(val) THEN IF ~negate THEN INCL(codeSet,i) END; ELSIF negate THEN INCL(codeSet,i) END; val := val DIV 2; END; IF negate THEN INCL(codeSet, to) END; IF (val # 0) THEN error := TRUE END; END Signed; PROCEDURE Range(set: SET; VAR first, num: LONGINT): BOOLEAN; BEGIN i := 0; WHILE (i<32) & ~(i IN set) DO INC(i) END; first := i; WHILE (i<32) & (i IN set) DO INC(i) END; num := i-first; WHILE (i<32) & ~(i IN set) DO INC(i) END; IF i<32 THEN RETURN FALSE ELSE RETURN TRUE END; END Range; (** check immediate shifts and adopt special rules **) PROCEDURE CheckImmediateShifts(VAR shiftMode, shiftImmediate: LONGINT); BEGIN CASE shiftMode OF | None: (* no shift -> encode as LSL 0 *) shiftMode := shiftLSL; shiftImmediate := 0 | shiftLSL: IF shiftImmediate < 0 THEN error := TRUE ELSIF shiftImmediate > 31 THEN D.String("LSL with more than 31 bits"); D.Ln; (* note that LSL 32 is disallowed *) error := TRUE END | shiftLSR, shiftASR: IF (shiftImmediate < 0) OR (shiftImmediate > 32) THEN error := TRUE ELSIF shiftImmediate = 0 THEN shiftMode := shiftLSL; (* note that LSR 0, ASR 0 are disallowed -> encode as LSL 0 *) shiftImmediate := 0 ELSIF shiftImmediate = 32 THEN shiftImmediate := 0 (* 32 is encoded as 0 in this case! *) END | shiftROR: IF (shiftImmediate < 0) OR (shiftImmediate > 32) THEN error := TRUE ELSIF (shiftImmediate = 0) OR (shiftImmediate = 32) THEN shiftMode := shiftLSL; (* note that ROR 0 has a different meaning -> encode as LSL 0 *) shiftImmediate := 0 END | shiftRRX: IF shiftImmediate = 1 THEN (* RRX is encoded as ROR 0 *) shiftMode := shiftROR; shiftImmediate := 0 ELSE (* note that only shifts by 1 are allowed *) error := TRUE END ELSE HALT(100) END END CheckImmediateShifts; PROCEDURE EncodeOperand(operandEncoding: LONGINT; CONST operand: Operand); VAR imm, rot, firstRegister, num, shiftMode, shiftImmediate: LONGINT; NEONRegisterPos: ARRAY 5 OF INTEGER; PROCEDURE Fixup(from, to: LONGINT); VAR patterns: ObjectFile.FixupPatterns; displacement: LONGINT; mode: SHORTINT; BEGIN NEW(patterns, 1); patterns[0].offset := from; patterns[0].bits := to-from+1; (*ASSERT(format.mnemonic = opBL); currently only implemented for this case *) (* IF (opBL <= instructionFormat.mnemonic) & (instructionFormat.mnemonic <= opBF) THEN *) IF (format.mnemonic = opB) OR (format.mnemonic = opBL) THEN mode := BinaryCode.Relative; displacement := operand.fixup.displacement - 8; ELSE mode := BinaryCode.Relative; displacement := operand.fixup.displacement; END; (* ELSE mode := BinaryCode.Absolute; displacement := op.fixup.displacement; END; *) operand.fixup.InitFixup(mode, 0, operand.fixup.symbol, operand.fixup.symbolOffset, displacement, -2, patterns); END Fixup; BEGIN CASE operandEncoding OF |None: error := operand.mode # None; |encodingR16, encodingR12,encodingR8, encodingR0: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE ELSIF (operand.register < R0) OR (operand.register > R15) THEN error := TRUE END; CASE operandEncoding OF |encodingR16: Unsigned(operand.register-R0,16,19); |encodingR12: Unsigned(operand.register-R0,12,15); |encodingR8: Unsigned(operand.register-R0,8,11); |encodingR0: Unsigned(operand.register-R0,0,3); END; |encodingCR0, encodingCR12, encodingCR16: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE ELSIF (operand.register < CR0) OR (operand.register > CR15) THEN error := TRUE END; CASE operandEncoding OF |encodingCR16: Unsigned(operand.register - CR0,16,19); |encodingCR12: Unsigned(operand.register - CR0,12,15); |encodingCR0: Unsigned(operand.register - CR0,0,3); END; |encodingDR0, encodingDR12, encodingDR16: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE ELSIF (operand.register < DR0) OR (operand.register > DR15) THEN error := TRUE END; CASE operandEncoding OF |encodingDR16: Unsigned((operand.register-DR0) MOD 16,16,19); Unsigned((operand.register-DR0) DIV 16,7,7); |encodingDR12: Unsigned((operand.register-DR0) MOD 16,12,15); Unsigned((operand.register-DR0) DIV 16,22,22); |encodingDR0: Unsigned((operand.register-DR0) MOD 16,0,3); Unsigned((operand.register-DR0) DIV 16,5,5); END; |encodingFR0, encodingFR12, encodingFR16: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE ELSIF (operand.register < SR0) OR (operand.register > SR31) THEN error := TRUE END; CASE operandEncoding OF |encodingFR16: Unsigned((operand.register-SR0) DIV 2,16,19); Unsigned((operand.register-SR0) MOD 2,7,7); |encodingFR12: Unsigned((operand.register-SR0) DIV 2,12,15); Unsigned((operand.register-SR0) MOD 2,22,22); |encodingFR0: Unsigned((operand.register-SR0) DIV 2,0,3);Unsigned((operand.register-SR0) MOD 2,5,5); END; |encodingAddressingMode1: IF operand.mode = modeImmediate THEN INCL(codeSet,25); IF ~EncodeImmediate(operand.immediate, imm,rot) THEN (*HALT(201);*) error := TRUE END; Unsigned(imm,0,7); Unsigned(rot,8,11); ELSIF (operand.mode = modeRegister) & (operand.shiftRegister # None) THEN INCL(codeSet,4); Unsigned(operand.register-R0,0,3); ASSERT(operand.shiftMode # None); Unsigned(operand.shiftMode,5,6); Unsigned(operand.shiftRegister-R0,8,11); ELSIF operand.mode = modeRegister THEN shiftMode := operand.shiftMode; shiftImmediate := operand.shiftImmediate; CheckImmediateShifts(shiftMode, shiftImmediate); Unsigned(shiftMode,5,6); Unsigned(shiftImmediate,7,11); Unsigned(operand.register-R0,0,3) ELSE error := TRUE END; |encodingAddressingMode2: IF operand.mode = modeMemory THEN IF Increment IN operand.indexing THEN INCL(codeSet,U) ELSE ASSERT(Decrement IN operand.indexing) END; IF PreIndexed IN operand.indexing THEN INCL(codeSet,W); INCL(codeSet,P) ELSIF PostIndexed IN operand.indexing THEN (* P bit remains cleared *) ELSE INCL(codeSet,P) END; Unsigned(operand.register-R0,16,19); IF operand.offsetRegister = None THEN Unsigned(operand.offsetImmediate,0,11); ELSE INCL(codeSet,25); shiftMode := operand.shiftMode; shiftImmediate := operand.shiftImmediate; CheckImmediateShifts(shiftMode, shiftImmediate); Unsigned(shiftMode,5,6); Unsigned(shiftImmediate,7,11); Unsigned(operand.offsetRegister-R0,0,3) END; ELSE error := TRUE END; |encodingAddressingMode3: IF Increment IN operand.indexing THEN INCL(codeSet,U) ELSE ASSERT(Decrement IN operand.indexing) END; IF PreIndexed IN operand.indexing THEN INCL(codeSet,W); INCL(codeSet,P) ELSIF PostIndexed IN operand.indexing THEN (* P = 0, W= 0 : post indexed addressing *) ELSE INCL(codeSet, P); (* P=1, W= 0: offset addressing *) END; Unsigned(operand.register-R0,16,19); IF operand.offsetRegister = None THEN INCL(codeSet,B); Unsigned(operand.offsetImmediate MOD 16,0,3); Unsigned(operand.offsetImmediate DIV 16,8,11); ELSE Unsigned(operand.offsetRegister-R0,0,3); END |encodingAddressingMode5: IF Increment IN operand.indexing THEN INCL(codeSet,U) ELSE ASSERT(Decrement IN operand.indexing) END; IF PreIndexed IN operand.indexing THEN INCL(codeSet,P); INCL(codeSet,W); ELSIF PostIndexed IN operand.indexing THEN INCL(codeSet,W) END; IF operand.mode = modeMemory THEN IF ~(W IN codeSet) THEN INCL(codeSet,U) END; Unsigned(operand.register-R0,16,19); Unsigned(operand.offsetImmediate DIV 4,0,7); ELSIF operand.mode = modeOption THEN Unsigned(operand.register-R0,16,18); Unsigned(operand.mode,0,7); ELSE error := TRUE END; |encodingAddressingMode5V: IF Increment IN operand.indexing THEN INCL(codeSet,U) ELSE ASSERT(Decrement IN operand.indexing) END; Unsigned(operand.register-R0,16,19); Unsigned(operand.offsetImmediate DIV 4,0,7); |encodingCoprocessor: IF operand.mode # modeCoprocessor THEN error := TRUE END; Unsigned(operand.coprocessor,8,11); |encodingOpcode20, encodingOpcode21, encodingOpcode5, encodingOpcode4: IF operand.mode # modeOpcode THEN IF operand.mode = None THEN (* note: missing opcode operand means opcode = 0 *) ASSERT(operand.opcode = 0) ELSE error := TRUE END END; CASE operandEncoding OF encodingOpcode20: Unsigned(operand.opcode,20,23); |encodingOpcode21: Unsigned(operand.opcode,21,23); |encodingOpcode5: Unsigned(operand.opcode,5,7); |encodingOpcode4: Unsigned(operand.opcode,4,7); END; |encodingSignedImm24: IF operand.mode # modeImmediate THEN error := TRUE END; IF operand.immediate MOD 4 # 0 THEN error := TRUE END; Signed(operand.immediate DIV 4,0,23); IF operand.fixup # NIL THEN Fixup(0, 23) END; |encodingImm24: IF operand.mode # modeImmediate THEN error := TRUE END; Unsigned(operand.immediate,0,23); |encodingImm12a0imm4a16: IF operand.mode # modeImmediate THEN error := TRUE END; Unsigned(operand.immediate MOD ASH(1,12),0,11); Unsigned(operand.immediate DIV ASH(1,12),16,19); |encodingImm16: IF operand.mode # modeImmediate THEN error := TRUE END; Unsigned(operand.immediate MOD 16,0,3); Unsigned(operand.immediate DIV 16,9,19); |encodingRotImm8: IF operand.mode # modeImmediate THEN error := TRUE ELSIF ~EncodeImmediate(operand.immediate, imm,rot) THEN error := TRUE END; Unsigned(imm,0,7); Unsigned(rot,8,11); |encodingRegisterList: IF operand.mode # modeRegisterList THEN error := TRUE ELSIF operand.register # R0 THEN error := TRUE END; Bits(operand.registerList,0,15); |encodingPSR: IF (operand.mode # modeRegister) THEN error := TRUE ELSIF ~((operand.mode # CPSR) & (operand.mode # SPSR)) THEN error := TRUE END; IF operand.register = SPSR THEN INCL(codeSet,22); END; |encodingFields: IF operand.mode # modeRegisterWithFields THEN error := TRUE END; IF operand.register = SPSR THEN INCL(codeSet,22) ELSIF operand.register # CPSR THEN error := TRUE END; Bits(operand.fields,16,19); |encodingDRegisterList: IF operand.mode # modeRegisterList THEN error := TRUE ELSIF operand.register # DR0 THEN error := TRUE ELSIF ~Range(operand.registerList,firstRegister, num) THEN error := TRUE END; Unsigned(firstRegister,12,15); Unsigned(num*2,0,7); |encodingFRegisterList: IF operand.mode # modeRegisterList THEN error := TRUE ELSIF operand.register # DR0 THEN error := TRUE ELSIF ~Range(operand.registerList,firstRegister, num) THEN error := TRUE END; Unsigned(firstRegister MOD 2,22,22); Unsigned(num,0,7); Unsigned(firstRegister DIV 2,12,15); Unsigned(num,0,7); |encodingImm7to11: IF operand.mode # modeImmediate THEN error := TRUE END; Unsigned(operand.immediate, 7, 11); (* NEON specific operand encodings *) |encodingNEONQd, encodingNEONQm, encodingNEONQn: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE (* Check register type for each subcase *) ELSIF (operand.register < QR0) OR (operand.register > QR15) THEN error := TRUE END; CASE operandEncoding OF encodingNEONQd: NEONRegisterPos[0] := 13; NEONRegisterPos[1] := 14; NEONRegisterPos[2] := 15; NEONRegisterPos[3] := 22; |encodingNEONQm: NEONRegisterPos[0] := 1; NEONRegisterPos[1] := 2; NEONRegisterPos[2] := 3; NEONRegisterPos[3] := 5; |encodingNEONQn: NEONRegisterPos[0] := 17; NEONRegisterPos[1] := 18; NEONRegisterPos[2] := 19; NEONRegisterPos[3] := 7; END; NEONRegisterPos[4] := 32; (* end of encoding *) SplittedUnsigned(operand.register - QR0, NEONRegisterPos) |encodingNEONDd, encodingNEONDm, encodingNEONDn: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE ELSIF (operand.register < DR0) OR (operand.register > DR31) THEN error := TRUE END; CASE operandEncoding OF encodingNEONDd: NEONRegisterPos[0] := 12; NEONRegisterPos[1] := 13; NEONRegisterPos[2] := 14; NEONRegisterPos[3] := 15; NEONRegisterPos[4] := 22; |encodingNEONDm: NEONRegisterPos[0] := 0; NEONRegisterPos[1] := 1; NEONRegisterPos[2] := 2; NEONRegisterPos[3] := 3; NEONRegisterPos[4] := 5; |encodingNEONDn: NEONRegisterPos[0] := 16; NEONRegisterPos[1] := 17; NEONRegisterPos[2] := 18; NEONRegisterPos[3] := 19; NEONRegisterPos[4] := 7; END; SplittedUnsigned(operand.register - DR0, NEONRegisterPos) |encodingNEONSd, encodingNEONSm, encodingNEONSn: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE ELSIF (operand.register < SR0) OR (operand.register > SR31) THEN error := TRUE END; CASE operandEncoding OF encodingNEONSd: NEONRegisterPos[0] := 22; NEONRegisterPos[1] := 12; NEONRegisterPos[2] := 13; NEONRegisterPos[3] := 14; NEONRegisterPos[4] := 15; |encodingNEONSm: NEONRegisterPos[0] := 5; NEONRegisterPos[1] := 0; NEONRegisterPos[2] := 1; NEONRegisterPos[3] := 2; NEONRegisterPos[4] := 3; |encodingNEONSn: NEONRegisterPos[0] := 7; NEONRegisterPos[1] := 16; NEONRegisterPos[2] := 17; NEONRegisterPos[3] := 18; NEONRegisterPos[4] := 19; END; SplittedUnsigned(operand.register - SR0, NEONRegisterPos) |encodingNEONQorDd, encodingNEONQorDm, encodingNEONQorDn: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE ELSIF (DR0 <= operand.register) & (operand.register <= DR31) THEN CASE operandEncoding OF encodingNEONQorDd: NEONRegisterPos[0] := 12; NEONRegisterPos[1] := 13; NEONRegisterPos[2] := 14; NEONRegisterPos[3] := 15; NEONRegisterPos[4] := 22; |encodingNEONQorDm: NEONRegisterPos[0] := 0; NEONRegisterPos[1] := 1; NEONRegisterPos[2] := 2; NEONRegisterPos[3] := 3; NEONRegisterPos[4] := 5; |encodingNEONQorDn: NEONRegisterPos[0] := 16; NEONRegisterPos[1] := 17; NEONRegisterPos[2] := 18; NEONRegisterPos[3] := 19; NEONRegisterPos[4] := 7; END; SplittedUnsigned(operand.register - DR0, NEONRegisterPos); ELSIF (QR0 <= operand.register) & (operand.register <= QR15) THEN CASE operandEncoding OF encodingNEONQorDd: NEONRegisterPos[0] := 13; NEONRegisterPos[1] := 14; NEONRegisterPos[2] := 15; NEONRegisterPos[3] := 22; |encodingNEONQorDm: NEONRegisterPos[0] := 1; NEONRegisterPos[1] := 2; NEONRegisterPos[2] := 3; NEONRegisterPos[3] := 5; |encodingNEONQorDn: NEONRegisterPos[0] := 17; NEONRegisterPos[1] := 18; NEONRegisterPos[2] := 19; NEONRegisterPos[3] := 7; END; NEONRegisterPos[4] := 32; SplittedUnsigned(operand.register - QR0, NEONRegisterPos); ELSE error := TRUE END |encodingNEONDorSd, encodingNEONDorSm, encodingNEONDorSn: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE ELSIF (DR0 <= operand.register) & (operand.register <= DR15) THEN CASE operandEncoding OF encodingNEONDorSd: NEONRegisterPos[0] := 12; NEONRegisterPos[1] := 13; NEONRegisterPos[2] := 14; NEONRegisterPos[3] := 15; NEONRegisterPos[4] := 22; |encodingNEONDorSm: NEONRegisterPos[0] := 0; NEONRegisterPos[1] := 1; NEONRegisterPos[2] := 2; NEONRegisterPos[3] := 3; NEONRegisterPos[4] := 5; |encodingNEONDorSn: NEONRegisterPos[0] := 16; NEONRegisterPos[1] := 17; NEONRegisterPos[2] := 18; NEONRegisterPos[3] := 19; NEONRegisterPos[4] := 7; END; SplittedUnsigned(operand.register - DR0, NEONRegisterPos) ELSIF (SR0 <= operand.register) & (operand.register <= SR31) THEN CASE operandEncoding OF encodingNEONDorSd: NEONRegisterPos[0] := 22; NEONRegisterPos[1] := 12; NEONRegisterPos[2] := 13; NEONRegisterPos[3] := 14; NEONRegisterPos[4] := 15; |encodingNEONDorSm: NEONRegisterPos[0] := 5; NEONRegisterPos[1] := 0; NEONRegisterPos[2] := 1; NEONRegisterPos[3] := 2; NEONRegisterPos[4] := 3; |encodingNEONDorSn: NEONRegisterPos[0] := 7; NEONRegisterPos[1] := 16; NEONRegisterPos[2] := 17; NEONRegisterPos[3] := 18; NEONRegisterPos[4] := 19; END; SplittedUnsigned(operand.register - SR0, NEONRegisterPos) ELSE error := TRUE END |encodingNEON8bitImm: IF operand.mode # modeImmediate THEN error := TRUE END; Unsigned(operand.immediate DIV 4, 0, 7); |encodingNEONDRegList: IF operand.mode # modeRegisterList THEN error := TRUE ELSIF operand.register # DR0 THEN error := TRUE ELSIF ~Range(operand.registerList, firstRegister, num) THEN error := TRUE END; (* First register is encoded as Dd *) NEONRegisterPos[0] := 12; NEONRegisterPos[1] := 13; NEONRegisterPos[2] := 14; NEONRegisterPos[3] := 15; NEONRegisterPos[4] := 22; SplittedUnsigned(DR0 + firstRegister, NEONRegisterPos); (* bits 8 to 11 specify the length of the list *) CASE num OF 1: Unsigned(7H, 8, 11) |2: Unsigned(0AH, 8, 11) |3: Unsigned(6H, 8, 11) |4: Unsigned(2H, 8, 11) ELSE D.String("Register list too long"); error := TRUE END |encodingNEONSysReg: IF operand.mode # modeRegister THEN error := TRUE ELSIF operand.shiftMode # None THEN error := TRUE ELSIF (operand.register < FPSID) & (operand.register > FPEXC) THEN error := TRUE END; CASE operand.register OF (* FPSID - 0b0; FPSCR - 0b1; FPEXC - 0b1000 at bits 19:16 *) FPSCR: INCL(codeSet, 16) |FPEXC: INCL(codeSet, 19) END |encodingNEONSigned8bitImm: IF operand.mode # modeImmediate THEN error := TRUE END; Unsigned(operand.immediate DIV 4,0,7) END; (* TODO: remove later on: *) IF error THEN D.String("cannot encode operand:"); D.Ln; DumpOperand(D.Log, operand); D.Ln; D.String("expected operand encoding: "); D.Int(operandEncoding, 0); D.Ln END END EncodeOperand; (** Manages the encoding of the types and sizes of a NEON instruction. *) PROCEDURE EncodeNEONTypes(format: InstructionFormat; instruction: Instruction); VAR normalSizeEncoding: BOOLEAN; i, immOperand: INTEGER; BEGIN IF ~format.isNEON THEN RETURN END; (* Set the Unsigned bit *) IF flagNEONUnsigned IN instruction.flags THEN codeSet := codeSet + format.Unsigned END; (* We also set the unsigned bit for positive immediates encoded by encodingNEONSigned8bitimm *) FOR i := 0 TO MaxOperands -1 DO IF (format.operands[i] = encodingNEONSigned8bitImm) & (instruction.operands[i].immediate >= 0) THEN codeSet := codeSet + format.Unsigned END END; (* Set the Float bit *) IF flagNEONFloat IN instruction.flags THEN codeSet := codeSet + format.Float END; (* Set the Q bit *) FOR i := 0 TO MaxOperands - 1 DO CASE format.operands[i] OF encodingNEONQorDd, encodingNEONQorDm, encodingNEONQorDn: IF (QR0 <= instruction.operands[i].register) & (instruction.operands[i].register <= QR15) THEN codeSet := codeSet + format.Quadword END |encodingNEONDorSd, encodingNEONDorSm, encodingNEONDorSn: IF (DR0 <= instruction.operands[i].register) & (instruction.operands[i].register <= DR15) THEN codeSet := codeSet + format.Quadword END ELSE END END; (* Check the type of size encoding *) normalSizeEncoding := TRUE; FOR i := 0 TO MaxOperands - 1 DO IF (format.operands[i] = encodingNEONImmAndSize) THEN immOperand := i; normalSizeEncoding := FALSE END END; IF normalSizeEncoding THEN IF format.SizeH # 32 THEN (* Set the size bit for usual encoding *) IF flagNEON16bits IN instruction.flags THEN INCL(codeSet, format.SizeH - 1) ELSIF flagNEON32bits IN instruction.flags THEN INCL(codeSet, format.SizeH) ELSIF flagNEON64bits IN instruction.flags THEN INCL(codeSet, format.SizeH); INCL(codeSet, format.SizeH - 1); (* for floating-points *) codeSet := codeSet + format.Operation; END END ELSE (* size and imm encoding done here *) IF flagNEON8bits IN instruction.flags THEN INCL(codeSet, 19); ELSIF flagNEON16bits IN instruction.flags THEN INCL(codeSet, 18); ELSIF flagNEON32bits IN instruction.flags THEN INCL(codeSet, 17); ELSIF flagNEON64bits IN instruction.flags THEN codeSet := codeSet + format.Length END END; END EncodeNEONTypes; BEGIN error := FALSE; IF instruction.format = None THEN error := TRUE ELSE format := instructionFormats[instruction.format]; codeSet := format.opcode; (* D.String(mnemonics[format.mnemonic].name); D.Ln; D.String("encoding "); D.Int(instruction.format,1); D.Ln; D.Set(codeSet); D.Ln; *) EncodeNEONTypes(format, instruction); IF flagCondition IN format.flags THEN Unsigned(instruction.condition,28,31); END; flags := format.flags * instruction.flags; IF flagB IN flags THEN INCL(codeSet,B) END; IF flagBT IN flags THEN INCL(codeSet,B); INCL(codeSet,W) END; IF flagD IN flags THEN INCL(codeSet,S) END; IF flagDA IN flags THEN END; IF flagDB IN flags THEN INCL(codeSet,P) END; IF flagH IN flags THEN INCL(codeSet,H) END; IF flagIA IN flags THEN INCL(codeSet,U) END; IF flagIB IN flags THEN INCL(codeSet,U); INCL(codeSet,P) END; IF flagL IN flags THEN INCL(codeSet,22) END; IF flagS IN flags THEN INCL(codeSet,20) END; IF flagSB IN flags THEN INCL(codeSet,S) END; IF flagSH IN flags THEN INCL(codeSet,S); INCL(codeSet,H) END; IF flagT IN flags THEN END; IF flagUserMode IN flags THEN INCL(codeSet,22) END; IF flagBaseRegisterUpdate IN flags THEN INCL(codeSet,21) END; i := 0; WHILE (i < LEN(instruction.operands)) & ~error DO EncodeOperand(format.operands[i], instruction.operands[i]); (* D.Set(codeSet); D.Ln; *) INC(i); END; END; code := SetToNumber(codeSet); IF error THEN D.String("cannot encode instruction"); D.Ln END; RETURN ~error END Encode; PROCEDURE Decode(code: LONGINT; VAR instruction: Instruction): BOOLEAN; VAR instrNr, operandNr: LONGINT; format: InstructionFormat; codeSet: SET; P, U, B, W, L, S, H: BOOLEAN; done: BOOLEAN; PROCEDURE Match(CONST format: InstructionFormat): BOOLEAN; BEGIN RETURN codeSet*format.mask= format.opcode*format.mask END Match; PROCEDURE Bits(from, to: LONGINT): SET; VAR i: LONGINT; val: SET; BEGIN val := {}; FOR i := from TO to DO IF i IN codeSet THEN INCL(val, i-from) END; END; RETURN val END Bits; PROCEDURE Unsigned(from, to: LONGINT): LONGINT; VAR val, i: LONGINT; BEGIN val := 0; FOR i := to TO from BY -1 DO val := val*2; IF i IN codeSet THEN INC(val) END; END; RETURN val END Unsigned; PROCEDURE Signed(from, to: LONGINT): LONGINT; VAR val, i: LONGINT; negative:BOOLEAN; BEGIN val := 0; negative := to IN codeSet; (* two's complement negate *) FOR i := to-1 TO from BY -1 DO val := val*2; IF (i IN codeSet) THEN IF ~negative THEN INC(val) END; ELSIF negative THEN INC(val) END; END; IF negative THEN INC(val); val := -val; END; RETURN val END Signed; PROCEDURE DecodeOperand(encoding: LONGINT; VAR operand: Operand): BOOLEAN; VAR imm, rot, register, shift, shiftRegister, shiftImm, offsetRegister: LONGINT; indexing: SET; firstRegister, lastRegister: LONGINT; BEGIN CASE encoding OF |None: InitOperand(operand); |encodingR16: InitRegister(operand, R0+Unsigned(16, 19), None, None, 0); |encodingR12: InitRegister(operand, R0+Unsigned(12, 15), None, None, 0); |encodingR8: InitRegister(operand, R0+Unsigned(8, 11), None, None, 0); |encodingR0: InitRegister(operand, R0+Unsigned(0, 3), None, None, 0); |encodingFR0: InitRegister(operand, SR0+2*Unsigned(0, 3)+Unsigned(5,5), None, None, 0); |encodingFR12: InitRegister(operand, SR0+2*Unsigned(12, 15)+Unsigned(22,22), None, None, 0); |encodingFR16: InitRegister(operand, SR0+2*Unsigned(16, 19)+Unsigned(7,7), None, None, 0); |encodingDR0: InitRegister(operand, DR0+Unsigned(0, 3) + 16*Unsigned(5,5), None, None, 0); |encodingDR12: InitRegister(operand, DR0+Unsigned(12, 15) + 16*Unsigned(7,7), None, None, 0); |encodingDR16: InitRegister(operand, DR0+Unsigned(16, 19) + 16*Unsigned(5,5), None, None, 0); |encodingCR0: InitRegister(operand, CR0+Unsigned(0, 3), None, None, 0); |encodingCR12: InitRegister(operand, CR0+Unsigned(12, 15), None, None, 0); |encodingCR16: InitRegister(operand, CR0+Unsigned(16, 19), None, None, 0); |encodingAddressingMode1: IF 25 IN codeSet THEN (* rotate immediate *) imm := Unsigned(0, 7); rot := Unsigned(8, 11); imm := RotateRight(imm, rot*2); InitImmediate(operand, imm); ELSIF 4 IN codeSet THEN (* register register shift *) IF 7 IN codeSet THEN RETURN FALSE END; (* ASSERT(~(7 IN codeSet)); *) shift := Unsigned(5, 6); register := Unsigned(0, 3); shiftRegister := Unsigned(8, 11); imm := 0; InitRegister(operand, register, shift, shiftRegister, imm); ELSE (* register immediate shift *) shiftRegister := None; shift := Unsigned(5, 6); register := Unsigned(0, 3); imm := Unsigned(7, 11); IF (shift= 0) & (imm= 0) THEN shift := None END; IF (shift= 3) & (imm= 0) THEN shift := shiftRRX END; InitRegister(operand, register, shift, shiftRegister, imm); END; |encodingAddressingMode2: IF TraceDecode THEN D.String("AddressMode2"); D.Ln; END; indexing := {}; IF U THEN INCL(indexing, Increment) ELSE INCL(indexing, Decrement) END; IF ~P THEN INCL(indexing, PostIndexed) ELSIF W THEN INCL(indexing, PreIndexed) END; register := Unsigned(16, 19); IF ~(25 IN codeSet) THEN (* immediate offset *) IF TraceDecode THEN D.String("ImmediateOffset"); D.Ln; END; imm := Unsigned(0, 11); InitImmediateOffsetMemory(operand, register, imm, indexing); ELSE (* register offset / scaled register offset *) IF (4 IN codeSet) THEN RETURN FALSE END; IF TraceDecode THEN D.String("RegisterOffset"); D.Ln; END; offsetRegister := Unsigned(0, 3); shift := Unsigned(5, 6); shiftImm := Unsigned(7, 11); IF (shift= 0) & (shiftImm= 0) THEN shift := None END; IF (shiftImm = 0) & (shift IN {shiftLSR, shiftASR}) THEN shiftImm := 32 END; IF (shift= shiftROR) & (shiftImm = 0) THEN shift := shiftRRX; shiftImm := 1 END; InitRegisterOffsetMemory(operand, register, offsetRegister, shift, shiftImm, indexing); END; |encodingAddressingMode3: indexing := {}; IF ~S & ~H THEN RETURN FALSE END; IF S & ~L THEN RETURN FALSE END; (* IF ~P & ~W THEN unpredictable instruction END; *) IF U THEN INCL(indexing, Increment) ELSE INCL(indexing, Decrement) END; IF ~P THEN INCL(indexing, PostIndexed) ELSIF W THEN INCL(indexing, PreIndexed) END; register := Unsigned(16, 19); IF B THEN (* immediate offset *) imm := Unsigned(0, 3)+16*Unsigned(8, 11); InitImmediateOffsetMemory(operand, register, imm, indexing); ELSE (* register offset *) offsetRegister := Unsigned(0, 3); InitRegisterOffsetMemory(operand, register, offsetRegister, None, 0, indexing); END; |encodingAddressingMode5: IF U THEN INCL(indexing, Increment) ELSE INCL(indexing, Decrement) END; IF P THEN IF W THEN INCL(indexing, PreIndexed) END; ELSE IF W THEN INCL(indexing, PostIndexed) END; END; IF U OR W THEN InitImmediateOffsetMemory(operand, Unsigned(16, 19), Unsigned(0, 7)*4, indexing); ELSE InitOption(operand, Unsigned(16, 19), Unsigned(0, 7)); END; |encodingAddressingMode5V: IF U THEN INCL(indexing,Increment) ELSE INCL(indexing, Decrement) END; InitImmediateOffsetMemory(operand,Unsigned(16,19),Unsigned(0,7)*4,indexing); |encodingCoprocessor: InitCoprocessor(operand, Unsigned(8, 11)); |encodingFields: IF 22 IN codeSet THEN register := SPSR ELSE register := CPSR END; InitRegisterWithFields(operand, register,Bits(16, 19)); |encodingImm16: imm := Unsigned(0, 3)+Unsigned(8, 19)*16; InitImmediate(operand, imm); |encodingImm12a0imm4a16: imm := Unsigned(0, 11)+Unsigned(16, 19)*ASH(1,12); InitImmediate(operand, imm); |encodingSignedImm24: imm := Signed(0, 23); InitImmediate(operand, imm*4); |encodingImm24: imm := Unsigned(0, 23); InitImmediate(operand, imm); |encodingRotImm8: imm := Unsigned(0, 7); rot := Unsigned(8, 11); imm := RotateRight(imm, rot*2); InitImmediate(operand, imm); |encodingOpcode20: InitOpcode(operand, Unsigned(20, 23)); |encodingOpcode21: InitOpcode(operand, Unsigned(21, 23)); |encodingOpcode5: InitOpcode(operand, Unsigned(5, 7)); |encodingOpcode4: InitOpcode(operand,Unsigned(4,6)); |encodingRegisterList: InitRegisterList(operand, R0, Bits(0, 15)); |encodingDRegisterList: firstRegister := Unsigned(12,15); lastRegister := firstRegister + Unsigned(0,7) DIV 2 -1; IF (firstRegister >= 0) & (lastRegister >= 0) & (firstRegister < 32) & (lastRegister < 32) THEN InitRegisterList(operand, DR0, {firstRegister .. lastRegister}); END; |encodingFRegisterList: firstRegister := Unsigned(12,15)*2+Unsigned(22,22); lastRegister := firstRegister + Unsigned(0,7) -1; IF lastRegister >= 32 THEN RETURN FALSE END; InitRegisterList(operand, SR0, {firstRegister .. lastRegister}); |encodingPSR: InitRegister(operand, CPSR+Unsigned(22, 22), None, None, 0); ELSE (*! should trap *) RETURN FALSE END; RETURN TRUE END DecodeOperand; BEGIN codeSet := NumberToSet(code); IF TraceDecode THEN D.String("decoding:"); D.Hex(code, -8); D.String(":"); D.Set(codeSet); D.Ln; END; P := 24 IN codeSet; U := 23 IN codeSet; B := 22 IN codeSet; W := 21 IN codeSet; L := 20 IN codeSet; S := 6 IN codeSet; H := 5 IN codeSet; instrNr := 0; done := FALSE; WHILE (instrNr mnemonics[mnemonic].lastInstructionFormat THEN mnemonics[mnemonic].lastInstructionFormat := instructionCount END; INC(instructionCount); END EnterInstruction; PROCEDURE EnterCondition(number: LONGINT; CONST name: ARRAY OF CHAR); BEGIN COPY(name, conditionEntries[conditionEntryCount].name); conditionEntries[conditionEntryCount].number := number; INC(conditionEntryCount); END EnterCondition; PROCEDURE EnterFlag(number: LONGINT; CONST name: ARRAY OF CHAR); BEGIN COPY(name, flagNames[number]); END EnterFlag; (** Parse an instruction format string. The format is a string representation of the encoding bits. Each bit can be represented by 0, 1 or X: - 0 means that the bit can be used to identify this instruction and it is not set - 1 means that the bit can be used to identify this instruction and it is set - X means that the bit cannot be used to identify the instruction. - U, S, L, F, o for the corresponding bits Whitespaces are ignored. The output sets are filled according to the parsing results. *) PROCEDURE ParseInstructionFormat(CONST format: ARRAY OF CHAR; VAR setBits, diffBits, U, Q, S, L, F, o: SET); VAR curr, len, count: LONGINT; BEGIN len := Strings.Length(format) - 1; count := 0; setBits := {}; diffBits := {}; U := {}; Q :={}; S := {}; F := {}; L := {}; F := {}; o := {}; FOR curr := len TO 0 BY -1 DO ASSERT((format[curr] = " ") OR (format[curr] = "1") OR (format[curr] = "0") OR (format[curr] = "X") OR (format[curr] = "U") OR (format[curr] = "Q") OR (format[curr] = "F") OR (format[curr] = "L") OR (format[curr] = "S") OR (format[curr] = "o")); CASE format[curr] OF " ": |"0": INCL(diffBits, count); INC(count) |"1": INCL(setBits, count); INCL(diffBits, count); INC(count) |"X": INC(count) |"U": INCL(U, count); INC(count) |"Q": INCL(Q, count); INC(count) |"S": INCL(S, count); INC(count) |"L": INCL(L, count); INC(count) |"F": INCL(F, count); INC(count) |"o": INCL(o, count); INC(count) END END; (* Only allow 32 elements wide formats *) ASSERT(count = 32); (* DEBUG *) (*D.String("Parsing results:"); D.Ln; D.String(" "); D.String(format); D.Ln; D.String("opcode: "); D.Set(setBits); D.Ln; D.String("mask: "); D.Set(diffBits); D.Ln; D.String("U: "); D.Set(U); D.Ln; D.String("Q: "); D.Set(Q); D.Ln; D.String("S: "); D.Set(S); D.Ln; D.String("F: "); D.Set(F); D.Ln; D.String("L: "); D.Set(L); D.Ln; D.String("o: "); D.Set(o); D.Ln;*) END ParseInstructionFormat; (** Adds the given sets to the corresponding record fields of the last entered instruction. Sets the instruction to be a NEON instruction. *) PROCEDURE UpdateNEONInstruction(U, Q, S, L, F, O: SET); VAR last: LONGINT; i: INTEGER; BEGIN (*ASSERT(instructionCount # 0);*) last := instructionCount - 1; instructionFormats[last].isNEON := TRUE; instructionFormats[last].Unsigned := U; instructionFormats[last].Quadword := Q; (*instructionFormats[last].Size := S;*) instructionFormats[last].Length := L; instructionFormats[last].Float := F; instructionFormats[last].Operation := O; FOR i := 0 TO 31 DO IF i IN S THEN instructionFormats[last].SizeH := i END END END UpdateNEONInstruction; (** Enter a NEON Instruction, using a string format descriptor. *) PROCEDURE EnterNEONInstruction(mnemonic: INTEGER; CONST format: ARRAY OF CHAR; flags: SET; op0, op1, op2, op3, op4, op5: INTEGER); VAR opcode, mask, U, Q, S, L, F, o: SET; last: LONGINT; i: INTEGER; BEGIN (* Enter instruction *) ParseInstructionFormat(format, opcode, mask, U, Q, S, L, F, o); EnterInstruction(mnemonic, opcode, mask, flags, op0, op1, op2, op3, op4, op5); (* Add NEON specific information *) last := instructionCount - 1; instructionFormats[last].isNEON := TRUE; instructionFormats[last].Unsigned := U; instructionFormats[last].Quadword := Q; instructionFormats[last].Length := L; instructionFormats[last].Float := F; instructionFormats[last].Operation := o; instructionFormats[last].SizeH := 32; FOR i := 0 TO 31 DO IF i IN S THEN instructionFormats[last].SizeH := i END END END EnterNEONInstruction; BEGIN EnterShift(shiftLSL, "LSL"); EnterShift(shiftLSR, "LSR"); EnterShift(shiftASR, "ASR"); EnterShift(shiftROR, "ROR"); EnterShift(shiftRRX, "RRX"); FOR i := 0 TO NumberShifts-1 DO ASSERT(shiftNames[i] # "") END; EnterCoprocessor(CP0, "P0"); EnterCoprocessor(CP1, "P1"); EnterCoprocessor(CP2, "P2"); EnterCoprocessor(CP3, "P3"); EnterCoprocessor(CP4, "P4"); EnterCoprocessor(CP5, "P5"); EnterCoprocessor(CP6, "P6"); EnterCoprocessor(CP7, "P7"); EnterCoprocessor(CP8, "P8"); EnterCoprocessor(CP9, "P9"); EnterCoprocessor(CP10, "P10"); EnterCoprocessor(CP11, "P11"); EnterCoprocessor(CP12, "P12"); EnterCoprocessor(CP13, "P13"); EnterCoprocessor(CP14, "P14"); EnterCoprocessor(CP15, "P15"); FOR i := 0 TO NumberCoprocessors - 1 DO ASSERT(coprocessorNames[i] # "") END; (* enter register names (note that the preferred name, i.e. alias, is entered after the other variants) *) registerEntryCount := 0; EnterRegister(R0, "RES"); EnterRegister(R0, "R0"); EnterRegister(R1, "RESHI"); EnterRegister(R1, "R1"); EnterRegister(R2, "R2"); EnterRegister(R3, "R3"); EnterRegister(R4, "R4"); EnterRegister(R5, "R5"); EnterRegister(R6, "R6"); EnterRegister(R7, "R7"); EnterRegister(R8, "R8"); EnterRegister(R9, "R9"); EnterRegister(R10, "R10"); EnterRegister(R11, "R11"); EnterRegister(R12, "R12"); EnterRegister(R12, "FP"); EnterRegister(R13, "R13"); EnterRegister(R13, "SP"); EnterRegister(R14, "R14"); EnterRegister(R14, "LR"); EnterRegister(R15, "R15"); EnterRegister(R15, "PC"); EnterRegister(CR0, "C0"); EnterRegister(CR1, "C1"); EnterRegister(CR2, "C2"); EnterRegister(CR3, "C3"); EnterRegister(CR4, "C4"); EnterRegister(CR5, "C5"); EnterRegister(CR6, "C6"); EnterRegister(CR7, "C7"); EnterRegister(CR8, "C8"); EnterRegister(CR9, "C9"); EnterRegister(CR10, "C10"); EnterRegister(CR11, "C11"); EnterRegister(CR12, "C12"); EnterRegister(CR13, "C13"); EnterRegister(CR14, "C14"); EnterRegister(CR15, "C15"); EnterRegister(DR0, "D0"); EnterRegister(DR1, "D1"); EnterRegister(DR2, "D2"); EnterRegister(DR3, "D3"); EnterRegister(DR4, "D4"); EnterRegister(DR5, "D5"); EnterRegister(DR6, "D6"); EnterRegister(DR7, "D7"); EnterRegister(DR8, "D8"); EnterRegister(DR9, "D9"); EnterRegister(DR10, "D10"); EnterRegister(DR11, "D11"); EnterRegister(DR12, "D12"); EnterRegister(DR13, "D13"); EnterRegister(DR14, "D14"); EnterRegister(DR15, "D15"); EnterRegister(SR0, "S0"); EnterRegister(SR1, "S1"); EnterRegister(SR2, "S2"); EnterRegister(SR3, "S3"); EnterRegister(SR4, "S4"); EnterRegister(SR5, "S5"); EnterRegister(SR6, "S6"); EnterRegister(SR7, "S7"); EnterRegister(SR8, "S8"); EnterRegister(SR9, "S9"); EnterRegister(SR10, "S10"); EnterRegister(SR11, "S11"); EnterRegister(SR12, "S12"); EnterRegister(SR13, "S13"); EnterRegister(SR14, "S14"); EnterRegister(SR15, "S15"); EnterRegister(SR16, "S16"); EnterRegister(SR17, "S17"); EnterRegister(SR18, "S18"); EnterRegister(SR19, "S19"); EnterRegister(SR20, "S20"); EnterRegister(SR21, "S21"); EnterRegister(SR22, "S22"); EnterRegister(SR23, "S23"); EnterRegister(SR24, "S24"); EnterRegister(SR25, "S25"); EnterRegister(SR26, "S26"); EnterRegister(SR27, "S27"); EnterRegister(SR28, "S28"); EnterRegister(SR29, "S29"); EnterRegister(SR30, "S30"); EnterRegister(SR31, "S31"); EnterRegister(CPSR, "CPSR"); EnterRegister(SPSR, "SPSR"); (* NEON Registers *) EnterRegister(DR16, "D16"); EnterRegister(DR17, "D17"); EnterRegister(DR18, "D18"); EnterRegister(DR19, "D19"); EnterRegister(DR20, "D20"); EnterRegister(DR21, "D21"); EnterRegister(DR22, "D22"); EnterRegister(DR23, "D23"); EnterRegister(DR24, "D24"); EnterRegister(DR25, "D25"); EnterRegister(DR26, "D26"); EnterRegister(DR27, "D27"); EnterRegister(DR28, "D28"); EnterRegister(DR29, "D29"); EnterRegister(DR30, "D30"); EnterRegister(DR31, "D31"); EnterRegister(QR0, "Q0"); EnterRegister(QR1, "Q1"); EnterRegister(QR2, "Q2"); EnterRegister(QR3, "Q3"); EnterRegister(QR4, "Q4"); EnterRegister(QR5, "Q5"); EnterRegister(QR6, "Q6"); EnterRegister(QR7, "Q7"); EnterRegister(QR8, "Q8"); EnterRegister(QR9, "Q9"); EnterRegister(QR10, "Q10"); EnterRegister(QR11, "Q11"); EnterRegister(QR12, "Q12"); EnterRegister(QR13, "Q13"); EnterRegister(QR14, "Q14"); EnterRegister(QR15, "Q15"); EnterRegister(FPSID, "FPSID"); EnterRegister(FPSCR, "FPSCR"); EnterRegister(FPEXC, "FPEXC"); FOR i := 0 TO NumberRegisterEntries-1 DO ASSERT(registerEntries[i].name # "") END; (* enter condition names (note that the preferred name, i.e. alias, is entered after the other variants) *) conditionEntryCount := 0; EnterCondition(conditionEQ, "EQ"); EnterCondition(conditionNE, "NE"); EnterCondition(conditionCS, "CS"); EnterCondition(conditionHS, "HS"); EnterCondition(conditionCC, "CC"); EnterCondition(conditionLO, "LO"); EnterCondition(conditionMI, "MI"); EnterCondition(conditionPL, "PL"); EnterCondition(conditionVS, "VS"); EnterCondition(conditionVC, "VC"); EnterCondition(conditionHI, "HI"); EnterCondition(conditionLS, "LS"); EnterCondition(conditionGE, "GE"); EnterCondition(conditionLT, "LT"); EnterCondition(conditionGT, "GT"); EnterCondition(conditionLE, "LE"); EnterCondition(conditionAL, "AL"); EnterCondition(conditionNV, "NV"); FOR i := 0 TO NumberConditionEntries-1 DO ASSERT(conditionEntries[i].name # "") END; EnterFlag(flagB, "B"); EnterFlag(flagBT, "BT"); EnterFlag(flagD, "D"); EnterFlag(flagDA, "DA"); EnterFlag(flagDB, "DB"); EnterFlag(flagH, "H"); EnterFlag(flagIA, "IA"); EnterFlag(flagIB, "IB"); EnterFlag(flagL, "L"); EnterFlag(flagS, "S"); EnterFlag(flagSB, "SB"); EnterFlag(flagSH, "SH"); EnterFlag(flagT, "T"); (* NEON flags *) EnterFlag(flagNEON8bits, "8"); EnterFlag(flagNEON16bits, "16"); EnterFlag(flagNEON32bits, "32"); EnterFlag(flagNEON64bits, "64"); EnterFlag(flagNEONInt, ".I"); EnterFlag(flagNEONSigned, ".S"); EnterFlag(flagNEONUnsigned, ".U"); EnterFlag(flagNEONFloat, ".F"); EnterFlag(flagNEONPoly, ".P"); EnterFlag(flagNEONUndef, ".X"); FOR i := 0 TO NumberFlags-1 DO ASSERT(flagNames[i] # "") END; EnterMnemonic(opADC, "ADC"); EnterMnemonic(opADD, "ADD"); EnterMnemonic(opAND, "AND"); EnterMnemonic(opB, "B"); EnterMnemonic(opBIC, "BIC"); EnterMnemonic(opBKPT, "BKPT"); EnterMnemonic(opBL, "BL"); EnterMnemonic(opBLX, "BLX"); EnterMnemonic(opBX, "BX"); EnterMnemonic(opCDP, "CDP"); EnterMnemonic(opCDP2, "CDP2"); EnterMnemonic(opCLZ, "CLZ"); EnterMnemonic(opCMN, "CMN"); EnterMnemonic(opCMP, "CMP"); EnterMnemonic(opEOR, "EOR"); EnterMnemonic(opFABSD, "FABSD"); EnterMnemonic(opFABSS, "FABSS"); EnterMnemonic(opFADDD, "FADDD"); EnterMnemonic(opFADDS, "FADDS"); EnterMnemonic(opFCMPD, "FCMPD"); EnterMnemonic(opFCMPED, "FCMPED"); EnterMnemonic(opFCMPES, "FCMPED"); EnterMnemonic(opFCMPEZD, "FCMPEZD"); EnterMnemonic(opFCMPEZS, "FCMPEZS"); EnterMnemonic(opFCMPS, "FCMPS"); EnterMnemonic(opFCMPZD, "FCMPZED"); EnterMnemonic(opFCMPZS, "FCMPZS"); EnterMnemonic(opFCPYD, "FCPYD"); EnterMnemonic(opFCPYS, "FCPYS"); EnterMnemonic(opFCVTDS, "FCVTDS"); EnterMnemonic(opFCVTSD, "FCVTSD"); EnterMnemonic(opFDIVD, "FDIVD"); EnterMnemonic(opFDIVS, "FDIVS"); EnterMnemonic(opFLDD, "FLDD"); EnterMnemonic(opFLDMIAD, "FLDMIAD"); EnterMnemonic(opFLDMIAS, "FLDMIAS"); EnterMnemonic(opFLDMIAX, "FLDMIAX"); EnterMnemonic(opFLDMDBD, "FLDMIAD"); EnterMnemonic(opFLDMDBS, "FLDMIAS"); EnterMnemonic(opFLDMDBX, "FLDMIAX"); EnterMnemonic(opFLDS, "FLDS"); EnterMnemonic(opFMACD, "FMACD"); EnterMnemonic(opFMACS, "FMACS"); EnterMnemonic(opFMDHR, "FMDHR"); EnterMnemonic(opFMDLR, "FMDLR"); EnterMnemonic(opFMRDH, "FMRDH"); EnterMnemonic(opFMRDL, "FMRDL"); EnterMnemonic(opFMRS, "FMRS"); EnterMnemonic(opFMRX, "FMRX"); EnterMnemonic(opFMSCD, "FMSCD"); EnterMnemonic(opFMSCS, "FMSCS"); EnterMnemonic(opFMSR, "FMSR"); EnterMnemonic(opFMSTAT, "FMSTAT"); EnterMnemonic(opFMULD, "FMULD"); EnterMnemonic(opFMULS, "FMULS"); EnterMnemonic(opFMXR, "FMXR"); EnterMnemonic(opFNEGD, "FNEGD"); EnterMnemonic(opFNEGS, "FNEGS"); EnterMnemonic(opFNMACD, "FNMACD"); EnterMnemonic(opFNMACS, "FNMACS"); EnterMnemonic(opFNMSCD, "FNMSCD"); EnterMnemonic(opFNMSCS, "FNMSCS"); EnterMnemonic(opFNMULD, "FNMULD"); EnterMnemonic(opFNMULS, "FNMULS"); EnterMnemonic(opFSITOD, "FSITOD"); EnterMnemonic(opFSITOS, "FSITOS"); EnterMnemonic(opFSQRTD, "FSQRTD"); EnterMnemonic(opFSQRTS, "FSQRTS"); EnterMnemonic(opFSTD, "FSTD"); EnterMnemonic(opFSTMIAD, "FSTMIAD"); EnterMnemonic(opFSTMIAS, "FSTMIAS"); EnterMnemonic(opFSTMIAX, "FSTMIAX"); EnterMnemonic(opFSTMDBD, "FSTMDBD"); EnterMnemonic(opFSTMDBS, "FSTMDBS"); EnterMnemonic(opFSTMDBX, "FSTMDBX"); EnterMnemonic(opFSTS, "FSTS"); EnterMnemonic(opFSUBD, "FSUBD"); EnterMnemonic(opFSUBS, "FSUBS"); EnterMnemonic(opFTOSID, "FTOSID"); EnterMnemonic(opFTOSIZD, "FTOSIZD"); EnterMnemonic(opFTOSIS, "FTOSIS"); EnterMnemonic(opFTOSIZS, "FTOSIZS"); EnterMnemonic(opFTOUID, "FTOUID"); EnterMnemonic(opFTOUIZD, "FTOUIZD"); EnterMnemonic(opFTOUIS, "FTOUIS"); EnterMnemonic(opFTOUIZS, "FTOUIZS"); EnterMnemonic(opFUITOD, "FUITOD"); EnterMnemonic(opFUITOS, "FUITOS"); EnterMnemonic(opLDC, "LDC"); EnterMnemonic(opLDC2, "LDC2"); EnterMnemonic(opLDM, "LDM"); EnterMnemonic(opLDR, "LDR"); EnterMnemonic(opMCR, "MCR"); EnterMnemonic(opMCR2, "MCR2"); EnterMnemonic(opMCRR, "MCRR"); EnterMnemonic(opMLA, "MLA"); EnterMnemonic(opMOV, "MOV"); EnterMnemonic(opMOVW, "MOVW"); EnterMnemonic(opMRC, "MRC"); EnterMnemonic(opMRC2, "MRC2"); EnterMnemonic(opMRRC, "MRRC"); EnterMnemonic(opMRS, "MRS"); EnterMnemonic(opMSR, "MSR"); EnterMnemonic(opMUL, "MUL"); EnterMnemonic(opMVN, "MVN"); EnterMnemonic(opORR, "ORR"); EnterMnemonic(opPLD, "PLD"); EnterMnemonic(opQADD, "QADD"); EnterMnemonic(opQDADD, "QDADD"); EnterMnemonic(opQDSUB, "QDSUB"); EnterMnemonic(opQSUB, "QSUB"); EnterMnemonic(opRSB, "RSB"); EnterMnemonic(opRSC, "RSC"); EnterMnemonic(opSBC, "SBC"); EnterMnemonic(opSMLABB, "SMLABB"); EnterMnemonic(opSMLABT, "SMLABT"); EnterMnemonic(opSMLATB, "SMLATB"); EnterMnemonic(opSMLATT, "SMLATT"); EnterMnemonic(opSMLAL, "SMLAL"); EnterMnemonic(opSMLALBB, "SMLALBB"); EnterMnemonic(opSMLALBT, "SMLALBT"); EnterMnemonic(opSMLALTB, "SMLALTB"); EnterMnemonic(opSMLALTT, "SMLALTT"); EnterMnemonic(opSMLAWB, "SMLAWB"); EnterMnemonic(opSMLAWT, "SMLAWT"); EnterMnemonic(opSMULBB, "SMULBB"); EnterMnemonic(opSMULBT, "SMULBT"); EnterMnemonic(opSMULTB, "SMULTB"); EnterMnemonic(opSMULTT, "SMULTT"); EnterMnemonic(opSMULWB, "SMULWB"); EnterMnemonic(opSMULWT, "SMULWT"); EnterMnemonic(opSMULL, "SMULL"); EnterMnemonic(opSTC, "STC"); EnterMnemonic(opSTC2, "STC2"); EnterMnemonic(opSTM, "STM"); EnterMnemonic(opSTR, "STR"); EnterMnemonic(opSUB, "SUB"); EnterMnemonic(opSWI, "SWI"); EnterMnemonic(opSWP, "SWP"); EnterMnemonic(opTEQ, "TEQ"); EnterMnemonic(opTST, "TST"); EnterMnemonic(opUMLAL, "UMLAL"); EnterMnemonic(opUMULL, "UMULL"); EnterMnemonic(opISB, "ISB"); EnterMnemonic(opLSL, "LSL"); EnterMnemonic(opLSR, "LSR"); EnterMnemonic(opSEV, "SEV"); EnterMnemonic(opDSB, "DSB"); EnterMnemonic(opLDREX, "LDREX"); EnterMnemonic(opSTREX, "STREX"); EnterMnemonic(opADR, "ADR"); EnterMnemonic(opLDREXB, "LDREXB"); EnterMnemonic(opSTREXB, "STREXB"); EnterMnemonic(opDMB, "DMB"); EnterMnemonic(opCLREX, "CLREX"); EnterMnemonic(opREV, "REV"); EnterMnemonic(opREV16, "REV16"); EnterMnemonic(opUXTH, "UXTH"); EnterMnemonic(opWFE, "WFE"); EnterMnemonic(opWFI, "WFI"); (* NEON mnemonics *) EnterMnemonic(opVADD, "VADD"); EnterMnemonic(opVADDL, "VADDL"); EnterMnemonic(opVADDW, "VADDW"); EnterMnemonic(opVMUL, "VMUL"); EnterMnemonic(opVMULL, "VMULL"); EnterMnemonic(opVMSR, "VMSR"); EnterMnemonic(opVMRS, "VMRS"); EnterMnemonic(opVLDR, "VLDR"); EnterMnemonic(opVSTR, "VSTR"); EnterMnemonic(opVDIV, "VDIV"); EnterMnemonic(opVMLA, "VMLA"); EnterMnemonic(opVMLS, "VMLS"); EnterMnemonic(opVMIN, "VMIN"); EnterMnemonic(opVMAX, "VMAX"); EnterMnemonic(opVSUB, "VSUB"); EnterMnemonic(opVABS, "VABS"); EnterMnemonic(opVABD, "VABD"); EnterMnemonic(opVLD1, "VLD1"); EnterMnemonic(opVST1, "VST1"); EnterMnemonic(opVPADD, "VPADD"); EnterMnemonic(opVMOV, "VMOV"); FOR i := 0 TO NumberMnemonics-1 DO ASSERT(mnemonics[i].name # "") END; instructionCount := 0; (*! adapt number of instructions if you enter a new instruction here *) FOR i := 0 TO NumberInstructions-1 DO instructionFormats[i].mnemonic := None END; EnterInstruction(opADC, {21, 23}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opADD, {23}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opAND, {}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opB, {25, 27}, {24..27}, {flagCondition}, encodingSignedImm24, None, None, None, None, None); EnterInstruction(opBIC, {22..24}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opBKPT, {4..6, 21, 24, 29..31}, {4..7, 20..31}, {}, encodingImm16, None, None, None, None, None); EnterInstruction(opBL, {24, 25, 27}, {24..27}, {flagCondition}, encodingSignedImm24, None, None, None, None, None); EnterInstruction(opBLX, {25, 27..31}, {25..31}, {}, encodingSignedImm24, None, None, None, None, None); EnterInstruction(opBLX, {4, 5, 8..19 (* SBO *), 21, 24}, {4..7, 20..27}, {flagCondition}, encodingR0, None, None, None, None, None); EnterInstruction(opBX, {4, 21, 8..19 (* SBO *), 24}, {4..7, 20..27}, {flagCondition}, encodingR0, None, None, None, None, None); EnterInstruction(opCDP, {25..27}, {4, 24..27}, {flagCondition}, encodingCoprocessor, encodingOpcode20, encodingCR12, encodingCR16, encodingCR0, encodingOpcode5); EnterInstruction(opCDP2, {25..27}, {4, 24..31}, {}, encodingCoprocessor, encodingOpcode20, encodingCR12, encodingCR16, encodingCR0, encodingOpcode5); EnterInstruction(opCLZ, {4, 8..11 (* SBO *), 16..19 (* SBO *), 21, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR0, None, None, None, None); EnterInstruction(opCMN, {20..22, 24}, {20..24, 26, 27}, {flagCondition}, encodingR16, encodingAddressingMode1, None, None, None, None); EnterInstruction(opCMP, {20, 22, 24}, {20..24, 26, 27}, {flagCondition}, encodingR16, encodingAddressingMode1, None, None, None, None); EnterInstruction(opEOR, {21}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opFABSD, {6,7,8,9,11,20,21,23,25,26,27}, {4..11,16..27}, {flagCondition}, encodingDR12, encodingDR0, None, None, None, None); EnterInstruction(opFABSS, {6,7, 9,11,20,21,23,25,26,27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFADDD, {8,9,11,20,21,25,26,27}, {4..11,20..27}, {flagCondition}, encodingDR12, encodingDR16, encodingDR0, None, None, None); EnterInstruction(opFADDS, { 9,11,20,21,25,26,27}, {4,6,8..11,20,21,23..27}, {flagCondition}, encodingFR12, encodingFR16, encodingFR0, None, None, None); EnterInstruction(opFCMPD, {6,8,9,11,18,20,21,23,25,26,27}, {4..11,16..27}, {flagCondition}, encodingDR12, encodingDR0, None, None, None, None); EnterInstruction(opFCMPED, {6,7,8,9,11,18,20,21,23,25,26,27}, {4..11,16..27}, {flagCondition}, encodingDR12, encodingDR0, None, None, None, None); EnterInstruction(opFCMPES, {6,7,9,11,18,20,21,23,25,26,27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFCMPEZD,{6,7,8,9,11,16,17,20,21,23,25,26,27},{4..11,16..27}, {flagCondition}, encodingDR12, None, None, None, None, None); EnterInstruction(opFCMPEZS,{6,7,9,11,16,18,20,21,23,25,26,27}, {4..11,16..21,23..27}, {flagCondition}, encodingFR12, None, None, None, None, None); EnterInstruction(opFCMPS, {6,9,11,18,20,21,23,25,26,27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFCMPZD, {6,8,9,11,16,18,20,21,23,25,26,27}, {4..11,16..27}, {flagCondition}, encodingDR12, None, None, None, None, None); EnterInstruction(opFCMPZS, {6,9,11,16,18,20,21,23,25,26,27}, {4..11,16..21,23..27}, {flagCondition}, encodingFR12, None, None, None, None, None); EnterInstruction(opFCPYD, {6,8,9,11,20,21,23,25,26,27}, {4..11,16..27}, {flagCondition}, encodingDR12, encodingDR0, None, None, None, None); EnterInstruction(opFCPYS, {6,9,11,20,21,23,25,26,27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFCVTDS, {6,7,9,11,16,17,18,20,21,23,25,26,27}, {4,6..11,16..27}, {flagCondition}, encodingDR12, encodingFR0, None, None, None, None); EnterInstruction(opFCVTSD, {6,7,8,9,11,16,17,18,20,21,23,25,26,27}, {4..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingDR0, None, None, None, None); EnterInstruction(opFDIVD, {8,9,11,23,25,26,27}, {4..11,20..27}, {flagCondition}, encodingDR12, encodingDR16, encodingDR0, None, None, None); EnterInstruction(opFDIVS, {9,11,23,25,26,27}, {4,6,8..11,20..21,23..27}, {flagCondition}, encodingFR12, encodingFR16, encodingFR0, None, None, None); EnterInstruction(opFLDD, {8,9,11,20,24,26,27}, {8..11,20..22,24..27}, {flagCondition}, encodingDR12, encodingAddressingMode5V, None, None, None, None); EnterInstruction(opFLDMIAD, {8,9,11,20,23,26,27}, {8..11,20,22..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingDRegisterList, None, None, None, None); EnterInstruction(opFLDMIAS, {9,11,20,23,26,27}, {8..11,20,23..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingFRegisterList, None, None, None, None); EnterInstruction(opFLDMIAX, {8,9,11,20,23,26,27}, {8..11,20,22..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingDRegisterList, None, None, None, None); EnterInstruction(opFLDMDBD, {8,9,11,20,24,26,27}, {8..11,20,22..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingDRegisterList, None, None, None, None); EnterInstruction(opFLDMDBS, {9,11,20,24,26,27}, {8..11,20,23..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingFRegisterList, None, None, None, None); EnterInstruction(opFLDMDBX, {8,9,11,20,24,26,27}, {8..11,20,22..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingDRegisterList, None, None, None, None); EnterInstruction(opFLDS, {9,11,20,24,26,27}, {8..11,20..21,24..27}, {flagCondition}, encodingFR12, encodingAddressingMode5V, None, None, None, None); EnterInstruction(opFMACD, {8,9,11,25,26,27}, {4..11,20..27}, {flagCondition}, encodingDR12, encodingDR16, encodingDR0, None, None, None); EnterInstruction(opFMACS, {9,11,25..27}, {4,6,8..11,20..21,23..27}, {flagCondition}, encodingFR12, encodingFR16, encodingFR0, None, None, None); EnterInstruction(opFMDHR, {4,8,9,11,21,25,26,27}, {4,7..11,20..27}, {flagCondition}, encodingDR16, encodingR12, None, None, None, None); EnterInstruction(opFMDLR, {4,8,9,11,25,26,27}, {4,7..11,20..27}, {flagCondition}, encodingDR16, encodingR12, None, None, None, None); EnterInstruction(opFMRDH, {4,8,9,11,20,21,25,26,27}, {4,7..11,20..27}, {flagCondition}, encodingR12, encodingDR16, None, None, None, None); EnterInstruction(opFMRDL, {4,8,9,11,20,25,26,27}, {4,7..11,20..27}, {flagCondition}, encodingR12, encodingDR16, None, None, None, None); EnterInstruction(opFMRS, {4,9,11,20,25,26,27}, {4,8..11,20..27}, {flagCondition}, encodingR12, encodingFR16, None, None, None, None); EnterInstruction(opFMRX, {4,9,11,20..23,25..27}, {4,7..11,20..27}, {flagCondition}, (*!todo*)None, None, None, None, None, None); EnterInstruction(opFMSCD, {8,9,11,20,25,26,27}, {4..11,20..27}, {flagCondition}, encodingDR12, encodingDR16, encodingDR0, None, None, None); EnterInstruction(opFMSCS, {9,11,20,25,26,27}, {4,6,8..11,20..21,23..27}, {flagCondition}, encodingFR12, encodingFR16, encodingFR0, None, None, None); EnterInstruction(opFMSR, {4,9,11,25,26,27}, {4,8..11,20..27}, {flagCondition}, encodingFR16, encodingR12, None, None, None, None); EnterInstruction(opFMSTAT, {4,9,11,12..16,20..23,25..27}, {4,8..27}, {flagCondition}, None, None, None, None, None, None); EnterInstruction(opFMULD, {8,9,11,21,25,26,27}, {4..11,20..27}, {flagCondition}, encodingDR12, encodingDR16, encodingDR0, None, None, None); EnterInstruction(opFMULS, {9,11,21,25,26,27}, {4,6,8..11,20..21,23..27}, {flagCondition}, encodingFR12, encodingFR16, encodingFR0, None, None, None); EnterInstruction(opFMXR, {4,9,11,21..23,25..27}, {4,7..11,20..27}, {flagCondition}, (*!todo*)None, None, None, None, None, None); EnterInstruction(opFNEGD, {6,8,9,11,16,20,21,23,25,26,27}, {4..11,16..27}, {flagCondition}, encodingDR12, encodingDR0, None, None, None, None); EnterInstruction(opFNEGS , {6,9,11,16,20,21,23,25,26,27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFNMACD, {6,8,9,11,25..27}, {4..11,20..27}, {flagCondition}, encodingDR12, encodingDR16, encodingDR0, None, None, None); EnterInstruction(opFNMACS, {6,9,11,25,26,27}, {4,6,8..11,20,21,23..27}, {flagCondition}, encodingFR12, encodingFR16, encodingFR0, None, None, None); EnterInstruction(opFNMSCD, {6,8,9,11,20,25,26,27}, {4..11,20..27}, {flagCondition}, encodingDR12, encodingDR16, encodingDR0, None, None, None); EnterInstruction(opFNMSCS, {6,9,11,20,25,26,27}, {4..11,20..21,23..27}, {flagCondition}, encodingFR12, encodingFR16, encodingFR0, None, None, None); EnterInstruction(opFNMULD, {6,8,9,11,21,25,26,27}, {4..11,20..27}, {flagCondition}, encodingDR12, encodingDR16, encodingDR0, None, None, None); EnterInstruction(opFNMULS, {6,9,11,21,25,26,27}, {4,6,8..11,20..21,23..27}, {flagCondition}, encodingFR12, encodingFR16, encodingFR0, None, None, None); EnterInstruction(opFSITOD, {6..9,11,19..21,23,25..27}, {4,6..11,16..27}, {flagCondition}, encodingDR12, encodingFR0, None, None, None, None); EnterInstruction(opFSITOS, {6,7,9,11,19..21,23,25..27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFSQRTD, {6..9,11,16,20,21,23,25..27}, {4..11,16..27}, {flagCondition}, encodingDR12, encodingDR0, None, None, None, None); EnterInstruction(opFSQRTS, {6,7,9,11,16,20,21,23,25..27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFSTD, {8,9,11,24,26,27}, {8..11,20..22,24..27}, {flagCondition}, encodingDR12, encodingAddressingMode5V, None, None, None, None); EnterInstruction(opFSTMIAD, {8,9,11,23,26,27}, {8..11,20,22..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingDRegisterList, None, None, None, None); EnterInstruction(opFSTMIAS, {9,11,23,26,27}, {8..11,20,23..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingFRegisterList, None, None, None, None); EnterInstruction(opFSTMIAX, {8,9,11,23,26,27}, {8..11,20,22..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingDRegisterList, None, None, None, None); EnterInstruction(opFSTMDBD, {8,9,11,24,26,27}, {8..11,20,22..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingDRegisterList, None, None, None, None); EnterInstruction(opFSTMDBS, {9,11,24,26,27}, {8..11,20,23..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16,encodingFRegisterList, None, None, None, None); EnterInstruction(opFSTMDBX, {8,9,11,24,26,27}, {8..11,20,22..27}, {flagCondition,flagBaseRegisterUpdate}, encodingR16, encodingDRegisterList, None, None, None, None); EnterInstruction(opFSTS, {9,11,24,26,27}, {8..11,20,21, 24..27}, {flagCondition}, encodingFR12, encodingAddressingMode5V, None, None, None, None); EnterInstruction(opFSUBD, {6,8,9,11,20,21,25..27}, {4..11,20..27}, {flagCondition}, encodingDR12, encodingDR16, encodingDR0, None, None, None); EnterInstruction(opFSUBS, {6,9,11,20,21,25,26,27}, {4,6,8..11,20..21,23..27}, {flagCondition}, encodingFR12, encodingFR16, encodingFR0, None, None, None); EnterInstruction(opFTOSID, {6,8,9,11,16,18..21,23,25..27}, {4..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingDR0, None, None, None, None); EnterInstruction(opFTOSIZD, {6,7,8,9,11,16,18..21,23,25..27}, {4..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingDR0, None, None, None, None); EnterInstruction(opFTOSIS, {6,9,11,16,18..21,23,25..27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFTOSIZS, {6,7,9,11,16,18..21,23,25..27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFTOUID, {6,8,9,11,18..21,23,25..27}, {4..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingDR0, None, None, None, None); EnterInstruction(opFTOUIZD, {6,7,8,9,11,18..21,23,25..27}, {4..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingDR0, None, None, None, None); EnterInstruction(opFTOUIS, {6,9,11,18..21,23,25..27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFTOUIZS, {6,7,9,11,18..21,23,25..27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opFUITOD, {6,8,9,11,19..21,23,25..27}, {4,6..11,16..27}, {flagCondition}, encodingDR12, encodingFR0, None, None, None, None); EnterInstruction(opFUITOS, {6,9,11,19..21,23,25..27}, {4,6..11,16..21,23..27}, {flagCondition}, encodingFR12, encodingFR0, None, None, None, None); EnterInstruction(opLDC, {20, 26, 27}, {20, 25..27}, {flagCondition, flagL}, encodingCoprocessor, encodingCR12, encodingAddressingMode5, None, None, None); EnterInstruction(opLDC2, {20, 26, 27, 28..31}, {20, 25..27, 28..31}, {flagL}, encodingCoprocessor, encodingCR12, encodingAddressingMode5, None, None, None); (*EnterInstruction(opLDM, {20, 27}, {20, 25..27}, {flagCondition, flagIA, flagIB, flagDA, flagDB, flagUserMode, flagBaseRegisterUpdate}, encodingR16, encodingRegisterList, None, None, None, None);*) EnterInstruction(opLDM, {20, 27}, {20, 25..27}, {flagCondition, flagIA, flagIB, flagDA, flagDB, flagBaseRegisterUpdate}, encodingR16, encodingRegisterList, None, None, None, None); EnterInstruction(opLDR, {20, 26}, {20, 26..27}, {flagCondition, flagB, flagT, flagBT}, encodingR12, encodingAddressingMode2, None, None, None, None); EnterInstruction(opLDR, {4, 7, 20}, {4, 7, 20, 25..27}, {flagCondition, flagH, flagSH, flagSB, flagD}, encodingR12, encodingAddressingMode3, None, None, None, None); EnterInstruction(opMCR, {4, 25, 26, 27}, {4, 20, 24..27}, {flagCondition}, encodingCoprocessor, encodingOpcode21, encodingR12, encodingCR16, encodingCR0, encodingOpcode5); EnterInstruction(opMCR2, {4, 25, 26, 27, 28..31}, {4, 20, 24..27, 28..31}, {}, encodingCoprocessor, encodingOpcode21, encodingCR12, encodingCR16, encodingCR0, encodingOpcode5); EnterInstruction(opMCRR, {22, 26, 27}, {20..27}, {flagCondition}, encodingCoprocessor, encodingOpcode4, encodingR12, encodingR16, encodingCR0, None); EnterInstruction(opMLA, {4, 7, 21}, {4..7, 21..27}, {flagCondition, flagS}, encodingR12, encodingR0, encodingR8, encodingR16, None, None); EnterInstruction(opMOV, {21, 23, 24}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingAddressingMode1, None, None, None, None); EnterInstruction(opMRC, {4, 20, 25, 26, 27}, {4, 20, 24..27}, {flagCondition}, encodingCoprocessor, encodingOpcode21, encodingR12, encodingCR16, encodingCR0, encodingOpcode5); EnterInstruction(opMRC2, {4, 20, 25, 26, 27, 28..31}, {4, 20, 24..27, 28..31}, {}, encodingCoprocessor, encodingOpcode21, encodingR12, encodingCR16, encodingCR0, encodingOpcode5); EnterInstruction(opMRRC, {20, 22, 26, 27}, {20..27}, {flagCondition}, encodingCoprocessor, encodingOpcode4, encodingR12, encodingR16, encodingCR0, None); EnterInstruction(opMRS, {24, 16..19 (* SBO *)}, {20, 21, 23..27}, {flagCondition}, encodingR12, encodingPSR, None, None, None, None); EnterInstruction(opMSR, {21, 24, 25, 12..15 (* SBO *)}, {20, 21, 23..27}, {flagCondition}, encodingFields, encodingRotImm8, None, None, None, None); EnterInstruction(opMSR, {21, 24, 12..15 (* SBO *)}, {4..7, 20, 21, 23..27}, {flagCondition}, encodingFields, encodingR0, None, None, None, None); EnterInstruction(opMUL, {4, 7}, {4..7, 21..27}, {flagCondition, flagS}, encodingR16, encodingR0, encodingR8, None, None, None); EnterInstruction(opMVN, {21..24}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingAddressingMode1, None, None, None, None); EnterInstruction(opORR, {23, 24}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opPLD, {28..31, 26, 24, 22, 20, 12..15}, {26..31, 24, 20..22, 12..15}, {flagCondition}, encodingAddressingMode2, None, None, None, None, None); EnterInstruction(opQADD, {4, 6, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR0, encodingR16, None, None, None); EnterInstruction(opQDADD, {4, 6, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR0, encodingR16, None, None, None); EnterInstruction(opQSUB, {4, 6, 21, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR0, encodingR16, None, None, None); EnterInstruction(opQDSUB, {4, 6, 21, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR0, encodingR16, None, None, None); EnterInstruction(opRSB, {21, 22}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opRSC, {21, 22, 23}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opSBC, {22, 23}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opSMLAL, {4, 7, 21, 22, 23}, {4..7, 21..27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingR0, encodingR8, None, None); EnterInstruction(opSMULL, {4, 7, 22, 23}, {4..7, 21..27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingR0, encodingR8, None, None); EnterInstruction(opSMLABB, {7, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, encodingR12, None, None); EnterInstruction(opSMLABT, {5, 7, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, encodingR12, None, None); EnterInstruction(opSMLATB, {6, 7, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, encodingR12, None, None); EnterInstruction(opSMLATT, {5, 6, 7, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, encodingR12, None, None); EnterInstruction(opSMLALBB, {7, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR16, encodingR0, encodingR8, None, None); EnterInstruction(opSMLALBT, {5, 7, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR16, encodingR0, encodingR8, None, None); EnterInstruction(opSMLALTB, {6, 7, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR16, encodingR0, encodingR8, None, None); EnterInstruction(opSMLALTT, {5, 6, 7, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR16, encodingR0, encodingR8, None, None); EnterInstruction(opSMLAWB, {7, 21, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, encodingR12, None, None); EnterInstruction(opSMLAWT, {6, 7, 21, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, encodingR12, None, None); EnterInstruction(opSMULBB, {7, 21, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, None, None, None); EnterInstruction(opSMULBT, {5, 21, 7, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, None, None, None); EnterInstruction(opSMULTB, {6, 7, 21, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, None, None, None); EnterInstruction(opSMULTT, {5, 6, 7, 21, 22, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, None, None, None); EnterInstruction(opSMULWB, {5, 7, 21, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, None, None, None); EnterInstruction(opSMULWT, {5, 6, 7, 21, 24}, {4..7, 20..27}, {flagCondition}, encodingR16, encodingR0, encodingR8, None, None, None); EnterInstruction(opSTC, {26, 27}, {20, 25..27}, {flagCondition, flagL}, encodingCoprocessor, encodingCR12, encodingAddressingMode5, None, None, None); EnterInstruction(opSTC2, {26, 27, 28..31}, {20, 25..27, 28..31}, {flagL}, encodingCoprocessor, encodingCR12, encodingAddressingMode5, None, None, None); (*EnterInstruction(opSTM, {27}, {20, 25..27}, {flagCondition, flagIA, flagIB, flagDA, flagDB, flagUserMode, flagBaseRegisterUpdate}, encodingR16, encodingRegisterList, None, None, None, None);*) EnterInstruction(opSTM, {27}, {20, 25..27}, {flagCondition, flagIA, flagIB, flagDA, flagDB, flagBaseRegisterUpdate}, encodingR16, encodingRegisterList, None, None, None, None); EnterInstruction(opSTR, {26}, {20, 26, 27}, {flagCondition, flagB, flagT, flagBT}, encodingR12, encodingAddressingMode2, None, None, None, None); EnterInstruction(opSTR, {4, 5, 7}, {4, 7, 20, 25..27}, {flagCondition, flagH, flagSH, flagSB, flagD}, encodingR12, encodingAddressingMode3, None, None, None, None); EnterInstruction(opSUB, {22}, {21..24, 26, 27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingAddressingMode1, None, None, None); EnterInstruction(opSWI, {24..27}, {24..27}, {flagCondition}, encodingImm24, None, None, None, None, None); EnterInstruction(opSWP, {4, 7, 24}, {4..7, 20..27}, {flagCondition}, encodingR12, encodingR0, encodingR16 (*! optional *), None, None, None); EnterInstruction(opSWP, {4, 7, 22, 24}, {4..7, 20..27}, {flagCondition, flagB}, encodingR12, encodingR0, encodingR16 (*! optional *), None, None, None); EnterInstruction(opTEQ, {20, 21, 24}, {20..24, 26, 27}, {flagCondition}, encodingR16, encodingAddressingMode1, None, None, None, None); EnterInstruction(opTST, {20, 24}, {20..24, 26, 27}, {flagCondition}, encodingR16, encodingAddressingMode1, None, None, None, None); EnterInstruction(opUMLAL, {4, 7, 21, 23}, {4..7, 21..27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingR0, encodingR8, None, None); EnterInstruction(opUMULL, {4, 7, 23}, {4..7, 21..27}, {flagCondition, flagS}, encodingR12, encodingR16, encodingR0, encodingR8, None, None); EnterNEONInstruction(opMOVW, "XXXX 0011 0000 XXXX XXXX XXXX XXXX XXXX",{flagCondition}, encodingR12, encodingImm12a0imm4a16, None, None, None, None); EnterNEONInstruction(opLDM, "XXXX 100X X101 XXXX 0XXX XXXX XXXX XXXX", {flagCondition, flagIA, flagDA, flagIB, flagDB, flagUserMode}, encodingR16, encodingRegisterList, None, None, None, None); EnterNEONInstruction(opSTM, "XXXX 100X X100 XXXX XXXX XXXX XXXX XXXX", {flagCondition, flagIA, flagDA, flagIB, flagDB, flagUserMode}, encodingR16, encodingRegisterList, None, None, None, None); EnterNEONInstruction(opISB, "1111 0101 0111 1111 1111 0000 0110 1111", {}, None, None, None, None, None, None); EnterNEONInstruction(opLSL, "XXXX 0001 1010 0000 XXXX XXXX X000 XXXX", {flagCondition, flagS}, encodingR12, encodingR0, encodingImm7to11, None, None, None); EnterNEONInstruction(opLSL, "XXXX 0001 1010 0000 XXXX XXXX 0001 XXXX", {flagCondition, flagS}, encodingR12, encodingR0, encodingR8, None, None, None); EnterNEONInstruction(opLSR, "XXXX 0001 1010 0000 XXXX XXXX X010 XXXX", {flagCondition, flagS}, encodingR12, encodingR0, encodingImm7to11, None, None, None); EnterNEONInstruction(opSEV, "XXXX 0011 0010 0000 1111 0000 0000 0100", {flagCondition}, None, None, None, None, None, None); EnterNEONInstruction(opDSB, "1111 0101 0111 1111 1111 0000 0100 1111", {}, None, None, None, None, None, None); (* Full System Reset only *) EnterNEONInstruction(opLDREX, "XXXX 0001 1001 XXXX XXXX 1111 1001 1111", {flagCondition}, encodingR12, encodingR16, None, None, None, None); EnterNEONInstruction(opSTREX, "XXXX 0001 1000 XXXX XXXX 1111 1001 XXXX", {flagCondition}, encodingR12, encodingR0, encodingR16, None, None, None); (* Only for labels after current instruction *) EnterNEONInstruction(opADR, "XXXX 0010 1000 1111 XXXX XXXX XXXX XXXX", {flagCondition}, encodingR12, encodingRotImm8, None, None, None, None); EnterNEONInstruction(opLDREXB, "XXXX 0001 1101 XXXX XXXX 1111 1001 1111", {flagCondition}, encodingR12, encodingR16, None, None, None, None); EnterNEONInstruction(opSTREXB, "XXXX 0001 1100 XXXX XXXX 1111 1001 XXXX", {flagCondition}, encodingR12, encodingR0, encodingR16, None, None, None); EnterNEONInstruction(opDMB, "1111 0101 0111 1111 1111 0000 0101 1111", {}, None, None, None, None, None, None); EnterNEONInstruction(opCLREX, "1111 0101 0111 1111 1111 0000 0001 1111", {}, None, None, None, None, None, None); EnterNEONInstruction(opREV, "XXXX 0110 1011 1111 XXXX 1111 0011 XXXX", {flagCondition}, encodingR12, encodingR0, None, None, None, None); EnterNEONInstruction(opREV16, "XXXX 0110 1011 1111 XXXX 1111 1011 XXXX", {flagCondition}, encodingR12, encodingR0, None, None, None, None); EnterNEONInstruction(opUXTH, "XXXX 0110 1111 1111 XXXX XX00 0111 XXXX", {flagCondition}, encodingR12, encodingR0, None, None, None, None); EnterNEONInstruction(opWFE, "XXXX 0011 0010 0000 1111 0000 0000 0010", {flagCondition}, None, None, None, None, None, None); EnterNEONInstruction(opWFI, "XXXX 0011 0010 0000 1111 0000 0000 0011", {flagCondition}, None, None, None, None, None, None); (* NEON instructions *) EnterNEONInstruction(opVADD, "1111 0010 0XSS XXXX XXXX 1000 XQX0 XXXX", {flagNEONInt, flagNEON8bits, flagNEON16bits, flagNEON32bits, flagNEON64bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVADD, "1111 0010 0X00 XXXX XXXX 1101 XQX0 XXXX", {flagNEONFloat, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVADD, "XXXX 1110 0X11 XXXX XXXX 101Q X0X0 XXXX", {flagCondition, flagNEONFloat, flagNEON64bits, flagNEON32bits}, encodingNEONDorSd, encodingNEONDorSn, encodingNEONDorSm, None, None, None); EnterNEONInstruction(opVADDL, "1111 001U 1XSS XXXX XXXX 0000 X0X0 XXXX", {flagNEONSigned, flagNEONUnsigned, flagNEON8bits, flagNEON16bits, flagNEON32bits}, encodingNEONQd, encodingNEONDm, encodingNEONDn, None, None, None); EnterNEONInstruction(opVADDW, "1111 001U 1XSS XXXX XXXX 0001 X0X0 XXXX", {flagNEONSigned, flagNEONUnsigned, flagNEON8bits, flagNEON16bits, flagNEON32bits}, encodingNEONQd, encodingNEONQm, encodingNEONDn, None, None, None); EnterNEONInstruction(opVMUL, "1111 0010 0XSS XXXX XXXX 1001 XQX1 XXXX", {flagNEONInt, flagNEONUnsigned, flagNEONSigned, flagNEON8bits, flagNEON16bits, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); (*! Does not support polynomail types yet *) EnterNEONInstruction(opVMUL, "1111 0011 0X00 XXXX XXXX 1101 XQX1 XXXX", {flagNEONFloat, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVMUL, "XXXX 1110 0X10 XXXX XXXX 101Q X0X0 XXXX", {flagNEONFloat, flagNEON32bits, flagNEON64bits, flagCondition}, encodingNEONDorSd, encodingNEONDorSm, encodingNEONDorSn, None, None, None); EnterNEONInstruction(opVMULL, "1111 001U 1XSS XXXX XXXX 1010 X1X0 XXXX", {flagNEONSigned, flagNEONUnsigned, flagNEON16bits, flagNEON32bits}, encodingNEONQd, encodingNEONQm, encodingNEONDn, None, None, None); EnterNEONInstruction(opVMSR, "XXXX 1110 1110 XXXX XXXX 1010 0001 0000", {flagCondition}, encodingNEONSysReg, encodingR12, None, None, None, None); EnterNEONInstruction(opVMRS, "XXXX 1110 1111 XXXX XXXX 1010 0001 0000", {flagCondition}, encodingR12, encodingNEONSysReg, None, None, None, None); EnterNEONInstruction(opVLDR, "XXXX 1101 UX01 XXXX XXXX 1011 XXXX XXXX", {flagCondition, flagNEON64bits}, encodingNEONDd, encodingR16, encodingNEONSigned8bitImm, None, None, None); EnterNEONInstruction(opVLDR, "XXXX 1101 UX01 XXXX XXXX 1010 XXXX XXXX", {flagCondition, flagNEON32bits}, encodingNEONSd, encodingR16, encodingNEONSigned8bitImm, None, None, None); EnterNEONInstruction(opVSTR, "XXXX 1101 UX00 XXXX XXXX 1011 XXXX XXXX", {flagCondition, flagNEON64bits}, encodingNEONDd, encodingR16, encodingNEONSigned8bitImm, None, None, None); EnterNEONInstruction(opVSTR, "XXXX 1101 UX00 XXXX XXXX 1010 XXXX XXXX", {flagCondition, flagNEON32bits}, encodingNEONSd, encodingR16, encodingNEONSigned8bitImm, None, None, None); EnterNEONInstruction(opVDIV, "XXXX 1110 1X00 XXXX XXXX 101Q X0X0 XXXX", {flagCondition, flagNEONFloat, flagNEON32bits, flagNEON64bits}, encodingNEONDorSd, encodingNEONDorSn, encodingNEONDorSm, None, None, None); EnterNEONInstruction(opVMLA, "1111 0010 0XSS XXXX XXXX 1001 XQX0 XXXX", {flagNEONInt, flagNEONSigned, flagNEONUnsigned, flagNEON8bits, flagNEON16bits, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVMLA, "1111 0010 0X00 XXXX XXXX 1101 XQX1 XXXX", {flagNEONFloat, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVMLA, "XXXX 1110 0X00 XXXX XXXX 101Q X0X0 XXXX", {flagCondition, flagNEONFloat, flagNEON64bits, flagNEON32bits}, encodingNEONDorSd, encodingNEONDorSn, encodingNEONDorSm, None, None, None); EnterNEONInstruction(opVMLS, "1111 0011 0XSS XXXX XXXX 1001 XQX0 XXXX", {flagNEONInt, flagNEONSigned, flagNEONUnsigned, flagNEON8bits, flagNEON16bits, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVMLS, "1111 0010 0X10 XXXX XXXX 1101 XQX1 XXXX", {flagNEONFloat, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVMLS, "XXXX 1110 0X00 XXXX XXXX 101Q X1X0 XXXX", {flagCondition, flagNEONFloat, flagNEON64bits, flagNEON32bits}, encodingNEONDorSd, encodingNEONDorSn, encodingNEONDorSm, None, None, None); EnterNEONInstruction(opVMIN, "1111 001U 0XSS XXXX XXXX 0110 XQX1 XXXX", {flagNEONSigned, flagNEONUnsigned, flagNEON8bits, flagNEON16bits, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVMAX, "1111 001U 0XSS XXXX XXXX 0110 XQX0 XXXX", {flagNEONSigned, flagNEONUnsigned, flagNEON8bits, flagNEON16bits, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVSUB, "1111 0011 0XSS XXXX XXXX 1000 XQX0 XXXX", {flagNEONInt, flagNEON8bits, flagNEON16bits, flagNEON32bits, flagNEON64bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); EnterNEONInstruction(opVABS, "1111 0011 1X11 SS01 XXXX 0o11 0QX0 XXXX", {flagNEONSigned, flagNEONFloat,flagNEON8bits, flagNEON16bits, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDm, None, None, None, None); EnterNEONInstruction(opVABD, "1111 001U 0XSS XXXX XXXX 0111 XQX0 XXXX", {flagNEONSigned, flagNEONUnsigned, flagNEON8bits, flagNEON16bits, flagNEON32bits}, encodingNEONQorDd, encodingNEONQorDn, encodingNEONQorDm, None, None, None); (* Fixed alignment and list size... not using [] or {} syntax *) EnterNEONInstruction(opVLD1, "1111 0100 0X10 XXXX XXXX 1010 SS00 1111", {flagNEON8bits, flagNEON16bits, flagNEON32bits, flagNEON64bits}, encodingNEONDd, encodingR16, None, None, None, None); EnterNEONInstruction(opVST1, "1111 0100 0X00 XXXX XXXX 1010 SS00 1111", {flagNEON8bits, flagNEON16bits, flagNEON32bits, flagNEON64bits}, encodingNEONDd, encodingR16, None, None, None, None); EnterNEONInstruction(opVPADD, "1111 0011 0X00 XXXX XXXX 1101 X0X0 XXXX", {flagNEON32bits, flagNEONFloat}, encodingNEONDd, encodingNEONDn, encodingNEONDm, None, None, None); EnterNEONInstruction(opVMOV, "XXXX 1110 0001 XXXX XXXX 1010 X001 0000", {flagCondition}, encodingR12, encodingNEONSn, None, None, None ,None); EnterNEONInstruction(opVMOV, "XXXX 1110 0000 XXXX XXXX 1010 X001 0000", {flagCondition}, encodingNEONSn, encodingR12, None, None, None, None); FOR i := 0 TO NumberInstructions-1 DO ASSERT(instructionFormats[i].mnemonic # None) END; END Init; (** dump the name of a condition (the last name entered is preferred) **) PROCEDURE DumpConditionName*(w: Streams.Writer; CONST conditionNumber: LONGINT); VAR i, foundIndex: LONGINT; BEGIN (* go through all condition names *) foundIndex := None; FOR i := 0 TO NumberConditionEntries - 1 DO IF conditionEntries[i].number = conditionNumber THEN foundIndex := i END END; ASSERT(foundIndex # None); w.String(conditionEntries[foundIndex].name); END DumpConditionName; (** dump the name of a register (the last name entered is preferred) **) PROCEDURE DumpRegisterName*(w: Streams.Writer; registerNumber: LONGINT); VAR i, foundIndex: LONGINT; BEGIN (* go through all register names *) foundIndex := None; FOR i := 0 TO NumberRegisterEntries - 1 DO IF registerEntries[i].number = registerNumber THEN foundIndex := i END END; ASSERT(foundIndex # None); w.String(registerEntries[foundIndex].name); END DumpRegisterName; PROCEDURE DumpOperand*(w: Streams.Writer; CONST operand: Operand); VAR i: LONGINT; first: BOOLEAN; mode: LONGINT; BEGIN mode := operand.mode; (* debugging *) CASE operand.mode OF | None: w.String("NONE!") | modeCoprocessor: w.String("P"); w.Int(operand.coprocessor, 1) | modeImmediate: w.String("#"); w.Int(operand.immediate, 1) | modeMemory: w.String("["); IF operand.register # None THEN DumpRegisterName(w, operand.register) END; IF PostIndexed IN operand.indexing THEN w.String("]") END; w.String(", "); IF operand.offsetRegister= None THEN w.String("#") END; IF Decrement IN operand.indexing THEN w.String("-"); ELSIF Increment IN operand.indexing THEN w.String("+"); ELSE HALT(100); END; IF operand.offsetRegister= None THEN (* w.Hex(operand.offsetImmediate, 1);w.String("H"); *) w.Int(operand.offsetImmediate, 0) ELSE DumpRegisterName(w, operand.offsetRegister) END; IF operand.shiftMode # None THEN w.String(", "); w.String(shiftNames[operand.shiftMode]); IF operand.shiftMode # shiftRRX THEN w.String(" "); IF operand.shiftRegister # None THEN DumpRegisterName(w, operand.shiftRegister) ELSE w.String("#"); w.Int(operand.shiftImmediate, 1); END; END; END; IF ~(PostIndexed IN operand.indexing) THEN w.String("]"); END; IF PreIndexed IN operand.indexing THEN w.String("!") END | modeOpcode: w.Int(operand.opcode, 0) | modeRegister: DumpRegisterName(w, operand.register); IF (operand.shiftMode # None) THEN w.String(", "); w.String(shiftNames[operand.shiftMode]); IF operand.shiftMode # shiftRRX THEN w.String(" "); IF operand.shiftRegister # None THEN DumpRegisterName(w, operand.shiftRegister) ELSE w.String("#"); w.Int(operand.shiftImmediate, 1); END; END; END | modeRegisterList: w.String("{");first := TRUE; FOR i := 0 TO 31 DO IF i IN operand.registerList THEN IF ~first THEN w.String(", ") ELSE first := FALSE END; DumpRegisterName(w, i + operand.register) END; END; w.String("}"); | modeOption: w.String("{"); w.Int(operand.option, 1); w.String("}") | modeRegisterWithFields: DumpRegisterName(w, operand.register); w.String("_"); IF fieldF IN operand.fields THEN w.String("f") END; IF fieldS IN operand.fields THEN w.String("s") END; IF fieldX IN operand.fields THEN w.String("x") END; IF fieldC IN operand.fields THEN w.String("c") END; END; END DumpOperand; PROCEDURE DumpInstruction*(w: Streams.Writer; CONST instruction: Instruction); VAR i: LONGINT; BEGIN IF instruction.format= None THEN w.String("undefined format"); w.Ln; ELSE w.String(mnemonics[instructionFormats[instruction.format].mnemonic].name); END; IF (instruction.condition # None) & (instruction.condition # conditionAL) THEN DumpConditionName(w, instruction.condition) END; FOR i := 0 TO NumberFlags-1 DO IF i IN instruction.flags THEN w.String(flagNames[i]); END; END; i := 0; WHILE (i 0 THEN w.String(", ") ELSE w.String(" ") END; DumpOperand(w, instruction.operands[i]); IF (i= 0) & (flagBaseRegisterUpdate IN instruction.flags) THEN w.String("!") ELSIF (i= 1) & (flagUserMode IN instruction.flags) THEN w.String("^"); END; INC(i); END; END DumpInstruction; PROCEDURE Test*(context: Commands.Context); VAR str: ARRAY 32 OF CHAR; mnemonic: LONGINT; condition: LONGINT; flags: SET; i: LONGINT; BEGIN IF context.arg.GetString(str) THEN IF FindMnemonic(str, mnemonic, condition, flags) THEN context.out.String("found: "); context.out.String(mnemonics[mnemonic].name); IF condition # None THEN context.out.String(":"); context.out.String(conditionEntries[condition].name); END; FOR i := 0 TO NumberFlags DO IF i IN flags THEN context.out.String(":"); context.out.String(flagNames[i]); END; END; END; END; END Test; PROCEDURE Test2*(context: Commands.Context); VAR operands: ARRAY 3 OF Operand; mnemonic: LONGINT; condition: LONGINT; flags: SET; instruction: Instruction; BEGIN InitRegister(operands[0], R0, None, None, 0); InitRegister(operands[1], R1, None, None, 0); InitRegister(operands[2], R1, shiftLSR, None, 8); IF FindMnemonic("ADDEQ", mnemonic, condition, flags) THEN IF MakeInstruction(instruction, mnemonic, condition, flags, operands) THEN DumpInstruction(context.out, instruction); ELSE context.error.String("instruction not found"); END ELSE context.error.String("mnemonic not found"); END; END Test2; PROCEDURE ReadCode(file: Files.File): BitSets.BitSet; VAR r: Files.Reader; val: LONGINT;bitSet: BitSets.BitSet; adr: LONGINT; BEGIN IF file = NIL THEN RETURN NIL END; adr := 0; NEW(r, file, 0); NEW(bitSet,0); WHILE r.Available()>0 DO r.RawLInt(val); INC(adr); bitSet.Resize(adr*32); bitSet.SetBits((adr-1)*32,32,val); END; RETURN bitSet END ReadCode; PROCEDURE Disassemble*(context: Commands.Context); TYPE Disasm = OBJECT (Disassembler.Disassembler) PROCEDURE DisassembleInstruction(bitSet: BitSets.BitSet; VAR adr: LONGINT; maxInstructionSize: LONGINT; w:Streams.Writer); VAR instruction: Instruction; value: LONGINT; mnemonic: LONGINT; BEGIN (* maxInstructionSize can be ignored here *) value := bitSet.GetBits(adr*8,32); IF Decode(value, instruction) THEN DumpInstruction(w, instruction); mnemonic := instructionFormats[instruction.format].mnemonic; IF (mnemonic = opBL) OR (mnemonic = opB) THEN WriteReference(instruction.operands[0].immediate+adr+8, TRUE (* points to code section *), w); ELSIF (mnemonic = opLDR) OR (mnemonic = opSTR) THEN (* LDR? ..., [PC, #...] or STR? ..., [PC, #...] *) ASSERT(instruction.operands[1].mode = modeMemory); IF (instruction.operands[1].register = PC) & (instruction.operands[1].offsetRegister = None) THEN IF Decrement IN instruction.operands[1].indexing THEN value := -instruction.operands[1].offsetImmediate + adr + 8; ELSE value := instruction.operands[1].offsetImmediate + adr + 8; END; WriteReference(value, TRUE, w); IF (value>=0) & (value * 8 + 32 < bitSet.GetSize()) THEN WriteReference(bitSet.GetBits(value * 8, 32) - codeDisplacement, TRUE, w); (* note that data references cannot be resolved like this *) END END END; ELSE w.String("*** COULD NOT DECODE ***"); END; INC(adr,4); END DisassembleInstruction; END Disasm; VAR disassembler: Disasm; codeFileName, dataFileName, logFileName: Files.FileName; codeFile, logFile: Files.File;code: BitSets.BitSet; options: Options.Options; address, offset: LONGINT; BEGIN IF context.arg.GetString(codeFileName) THEN codeFile := Files.Old(codeFileName); IF codeFile = NIL THEN context.out.String("file not found "); context.out.String(codeFileName); RETURN END; NEW(options); options.Add("l","logFile", Options.String); options.Add("a","address",Options.Integer); options.Add("o","offset",Options.Integer); IF options.Parse(context.arg, context.out) THEN IF ~options.GetInteger("a", address) THEN address := 0 END; NEW(disassembler, context.out); code := ReadCode(codeFile); IF options.GetString("logFile",logFileName) THEN logFile := Files.Old(logFileName); ELSE logFile := disassembler.GetLogFile(codeFileName) END; IF options.GetInteger("o",offset) THEN disassembler.SetDisplacements(offset,offset) END; disassembler.Disassemble(code, code, 8,8 , logFile, address); END; END; END Disassemble; BEGIN Init; END FoxARMInstructionSet. SystemTools.FreeDownTo FoxARMInstructionSet ~ FoxARMInstructionSet.Test BLEQSB ~ FoxARMInstructionSet.Test2 ~ FoxARMInstructionSet.Test3 "E:/Systembau11/WinAos/Work/Minos.boot" ~