| // -*- mode:c++ -*- |
| |
| // Copyright (c) 2010-2013,2016-2018 ARM Limited |
| // All rights reserved |
| // |
| // The license below extends only to copyright in the software and shall |
| // not be construed as granting a license to any other intellectual |
| // property including but not limited to intellectual property relating |
| // to a hardware implementation of the functionality of the software |
| // licensed hereunder. You may use the software subject to the license |
| // terms below provided that you ensure that this notice is replicated |
| // unmodified and in its entirety in all distributions of the software, |
| // modified or unmodified, in source code or in binary form. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer; |
| // redistributions in binary form must reproduce the above copyright |
| // notice, this list of conditions and the following disclaimer in the |
| // documentation and/or other materials provided with the distribution; |
| // neither the name of the copyright holders nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| // |
| // Authors: Gabe Black |
| // Giacomo Gabrielli |
| |
| def format Crc32() {{ |
| decode_block = ''' |
| { |
| const IntRegIndex rm = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 19, 16); |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| |
| uint8_t c_poly = bits(machInst, 9); |
| uint8_t sz = bits(machInst, 22, 21); |
| uint8_t crc_select = (c_poly << 2) | sz; |
| |
| switch(crc_select) { |
| case 0x0: |
| return new Crc32b(machInst, rd, rn, rm); |
| case 0x1: |
| return new Crc32h(machInst, rd, rn, rm); |
| case 0x2: |
| return new Crc32w(machInst, rd, rn, rm); |
| case 0x4: |
| return new Crc32cb(machInst, rd, rn, rm); |
| case 0x5: |
| return new Crc32ch(machInst, rd, rn, rm); |
| case 0x6: |
| return new Crc32cw(machInst, rd, rn, rm); |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| ''' |
| }}; |
| |
| def format ArmERet() {{ |
| decode_block = "return new Eret(machInst);" |
| }}; |
| |
| def format Svc() {{ |
| decode_block = "return new Svc(machInst, bits(machInst, 23, 0));" |
| }}; |
| |
| def format ArmSmcHyp() {{ |
| decode_block = ''' |
| { |
| if (bits(machInst, 21)) |
| { |
| return new Smc(machInst); |
| } else { |
| uint32_t imm16 = (bits(machInst, 19, 8) << 4) | |
| (bits(machInst, 3, 0) << 0); |
| return new Hvc(machInst, imm16); |
| } |
| } |
| ''' |
| }}; |
| |
| def format ArmMsrMrs() {{ |
| decode_block = ''' |
| { |
| const uint8_t byteMask = bits(machInst, 19, 16); |
| const uint8_t sysM = byteMask | (bits(machInst, 8) << 4); |
| const IntRegIndex rn = (IntRegIndex)(uint32_t)bits(machInst, 3, 0); |
| const IntRegIndex rd = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const uint32_t opcode = bits(machInst, 24, 21); |
| const bool useImm = bits(machInst, 25); |
| const bool r = bits(machInst, 22); |
| const bool isBanked = bits(machInst, 9); |
| |
| const uint32_t unrotated = bits(machInst, 7, 0); |
| const uint32_t rotation = (bits(machInst, 11, 8) << 1); |
| const uint32_t imm = rotate_imm(unrotated, rotation); |
| |
| switch (opcode) { |
| case 0x8: |
| if (isBanked) { |
| return new MrsBankedReg(machInst, rd, sysM, r!=0); |
| } else { |
| return new MrsCpsr(machInst, rd); |
| } |
| case 0x9: |
| if (useImm) { |
| return new MsrCpsrImm(machInst, imm, byteMask); |
| } else { |
| if (isBanked) { |
| return new MsrBankedReg(machInst, rn, sysM, r!=0); |
| } else { |
| return new MsrCpsrReg(machInst, rn, byteMask); |
| } |
| } |
| case 0xa: |
| if (isBanked) { |
| return new MrsBankedReg(machInst, rd, sysM, r!=0); |
| } else { |
| return new MrsSpsr(machInst, rd); |
| } |
| case 0xb: |
| if (useImm) { |
| return new MsrSpsrImm(machInst, imm, byteMask); |
| } else { |
| if (isBanked) { |
| return new MsrBankedReg(machInst, rn, sysM, r!=0); |
| } else { |
| return new MsrSpsrReg(machInst, rn, byteMask); |
| } |
| } |
| default: |
| return new Unknown(machInst); |
| } |
| } |
| ''' |
| }}; |
| |
| let {{ |
| header_output = ''' |
| StaticInstPtr |
| decodeMcrMrc14(ExtMachInst machInst); |
| ''' |
| decoder_output = ''' |
| StaticInstPtr |
| decodeMcrMrc14(ExtMachInst machInst) |
| { |
| const uint32_t opc1 = bits(machInst, 23, 21); |
| const uint32_t crn = bits(machInst, 19, 16); |
| const uint32_t opc2 = bits(machInst, 7, 5); |
| const uint32_t crm = bits(machInst, 3, 0); |
| const MiscRegIndex miscReg = decodeCP14Reg(crn, opc1, crm, opc2); |
| const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| |
| const bool isRead = bits(machInst, 20); |
| |
| switch (miscReg) { |
| case MISCREG_NOP: |
| return new NopInst(machInst); |
| case MISCREG_CP14_UNIMPL: |
| return new FailUnimplemented(isRead ? "mrc unknown" : "mcr unknown", |
| machInst, |
| csprintf("miscreg crn:%d opc1:%d crm:%d opc2:%d %s unknown", |
| crn, opc1, crm, opc2, isRead ? "read" : "write")); |
| default: |
| uint32_t iss = mcrMrcIssBuild(isRead, crm, rt, crn, opc1, opc2); |
| if (isRead) { |
| return new Mrc14(machInst, rt, miscReg, iss); |
| } else { |
| return new Mcr14(machInst, miscReg, rt, iss); |
| } |
| } |
| } |
| ''' |
| }}; |
| |
| def format McrMrc14() {{ |
| decode_block = ''' |
| return decodeMcrMrc14(machInst); |
| ''' |
| }}; |
| |
| let {{ |
| header_output = ''' |
| StaticInstPtr decodeMcrMrc14(ExtMachInst machInst); |
| StaticInstPtr decodeMcrMrc15(ExtMachInst machInst); |
| ''' |
| decoder_output = ''' |
| StaticInstPtr |
| decodeMcrMrc15(ExtMachInst machInst) |
| { |
| const uint32_t opc1 = bits(machInst, 23, 21); |
| const uint32_t crn = bits(machInst, 19, 16); |
| const uint32_t opc2 = bits(machInst, 7, 5); |
| const uint32_t crm = bits(machInst, 3, 0); |
| const MiscRegIndex miscReg = decodeCP15Reg(crn, opc1, crm, opc2); |
| const IntRegIndex rt = (IntRegIndex)(uint32_t)bits(machInst, 15, 12); |
| const bool isRead = bits(machInst, 20); |
| uint32_t iss = mcrMrcIssBuild(isRead, crm, rt, crn, opc1, opc2); |
| |
| switch (miscReg) { |
| case MISCREG_NOP: |
| return new McrMrcMiscInst(isRead ? "mrc nop" : "mcr nop", |
| machInst, iss, MISCREG_NOP); |
| case MISCREG_CP15_UNIMPL: |
| return new FailUnimplemented(isRead ? "mrc unkown" : "mcr unkown", |
| machInst, |
| csprintf("miscreg crn:%d opc1:%d crm:%d opc2:%d %s unknown", |
| crn, opc1, crm, opc2, isRead ? "read" : "write")); |
| case MISCREG_IMPDEF_UNIMPL: |
| |
| if (miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL]) { |
| auto mnemonic = |
| csprintf("miscreg crn:%d opc1:%d crm:%d opc2:%d %s", |
| crn, opc1, crm, opc2, isRead ? "read" : "write"); |
| |
| return new WarnUnimplemented( |
| isRead ? "mrc implementation defined" : |
| "mcr implementation defined", |
| machInst, mnemonic + " treated as NOP"); |
| } else { |
| return new McrMrcImplDefined( |
| isRead ? "mrc implementation defined" : |
| "mcr implementation defined", |
| machInst, iss, MISCREG_IMPDEF_UNIMPL); |
| } |
| case MISCREG_CP15ISB: |
| return new Isb(machInst, iss); |
| case MISCREG_CP15DSB: |
| return new Dsb(machInst, iss); |
| case MISCREG_CP15DMB: |
| return new Dmb(machInst, iss); |
| case MISCREG_DCIMVAC: |
| return new McrDcimvac(machInst, miscReg, rt, iss); |
| case MISCREG_DCCMVAC: |
| return new McrDccmvac(machInst, miscReg, rt, iss); |
| case MISCREG_DCCMVAU: |
| return new McrDccmvau(machInst, miscReg, rt, iss); |
| case MISCREG_DCCIMVAC: |
| return new McrDccimvac(machInst, miscReg, rt, iss); |
| default: |
| if (miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL]) { |
| std::string full_mnem = csprintf("%s %s", |
| isRead ? "mrc" : "mcr", miscRegName[miscReg]); |
| warn("\\tinstruction '%s' unimplemented\\n", full_mnem); |
| |
| // Remove the warn flag and set the implemented flag. This |
| // prevents the instruction warning a second time, it also |
| // means the instruction is actually generated. Actually |
| // creating the instruction to access an register that isn't |
| // implemented sounds a bit silly, but its required to get |
| // the correct behaviour for hyp traps and undef exceptions. |
| miscRegInfo[miscReg][MISCREG_IMPLEMENTED] = true; |
| miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL] = false; |
| } |
| |
| if (miscRegInfo[miscReg][MISCREG_IMPLEMENTED]) { |
| if (isRead) |
| return new Mrc15(machInst, rt, miscReg, iss); |
| return new Mcr15(machInst, miscReg, rt, iss); |
| } else { |
| return new FailUnimplemented(isRead ? "mrc" : "mcr", machInst, |
| csprintf("%s %s", isRead ? "mrc" : "mcr", |
| miscRegName[miscReg])); |
| } |
| } |
| } |
| ''' |
| }}; |
| |
| def format McrMrc15() {{ |
| decode_block = ''' |
| return decodeMcrMrc15(machInst); |
| ''' |
| }}; |
| |
| let {{ |
| header_output = ''' |
| StaticInstPtr |
| decodeMcrrMrrc15(ExtMachInst machInst); |
| ''' |
| decoder_output = ''' |
| StaticInstPtr |
| decodeMcrrMrrc15(ExtMachInst machInst) |
| { |
| const uint32_t crm = bits(machInst, 3, 0); |
| const uint32_t opc1 = bits(machInst, 7, 4); |
| const MiscRegIndex miscReg = decodeCP15Reg64(crm, opc1); |
| const IntRegIndex rt = (IntRegIndex) (uint32_t) bits(machInst, 15, 12); |
| const IntRegIndex rt2 = (IntRegIndex) (uint32_t) bits(machInst, 19, 16); |
| |
| const bool isRead = bits(machInst, 20); |
| |
| switch (miscReg) { |
| case MISCREG_CP15_UNIMPL: |
| return new FailUnimplemented(isRead ? "mrc" : "mcr", machInst, |
| csprintf("miscreg crm:%d opc1:%d 64-bit %s unknown", |
| crm, opc1, isRead ? "read" : "write")); |
| default: |
| if (miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL]) { |
| std::string full_mnem = csprintf("%s %s", |
| isRead ? "mrrc" : "mcrr", miscRegName[miscReg]); |
| warn("\\tinstruction '%s' unimplemented\\n", full_mnem); |
| |
| // Remove the warn flag and set the implemented flag. This |
| // prevents the instruction warning a second time, it also |
| // means the instruction is actually generated. Actually |
| // creating the instruction to access an register that isn't |
| // implemented sounds a bit silly, but its required to get |
| // the correct behaviour for hyp traps and undef exceptions. |
| miscRegInfo[miscReg][MISCREG_IMPLEMENTED] = true; |
| miscRegInfo[miscReg][MISCREG_WARN_NOT_FAIL] = false; |
| } |
| |
| if (miscRegInfo[miscReg][MISCREG_IMPLEMENTED]) { |
| uint32_t iss = mcrrMrrcIssBuild(isRead, crm, rt, rt2, opc1); |
| |
| if (isRead) { |
| StaticInstPtr si = new Mrrc15(machInst, miscReg, rt2, rt, iss); |
| if (miscRegInfo[miscReg][MISCREG_UNVERIFIABLE]) |
| si->setFlag(StaticInst::IsUnverifiable); |
| return si; |
| } |
| return new Mcrr15(machInst, rt2, rt, miscReg, iss); |
| } else { |
| return new FailUnimplemented(isRead ? "mrrc" : "mcrr", machInst, |
| csprintf("%s %s", |
| isRead ? "mrrc" : "mcrr", miscRegName[miscReg])); |
| } |
| } |
| } |
| ''' |
| }}; |
| |
| def format Mcrr15() {{ |
| decode_block = ''' |
| return decodeMcrrMrrc15(machInst); |
| ''' |
| }}; |
| |
| def format Mrrc15() {{ |
| decode_block = ''' |
| return decodeMcrrMrrc15(machInst); |
| ''' |
| }}; |