From patchwork Thu Jun 17 17:49:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= X-Patchwork-Id: 12329049 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.6 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1B688C2B9F4 for ; Thu, 17 Jun 2021 17:52:03 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 11AE6613CB for ; Thu, 17 Jun 2021 17:52:02 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 11AE6613CB Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=amsat.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:54736 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1ltwBN-0005QD-4E for qemu-devel@archiver.kernel.org; Thu, 17 Jun 2021 13:52:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39718) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ltw8y-0001tA-EK for qemu-devel@nongnu.org; Thu, 17 Jun 2021 13:49:32 -0400 Received: from mail-wr1-x431.google.com ([2a00:1450:4864:20::431]:40803) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1ltw8s-0004Pw-RD for qemu-devel@nongnu.org; Thu, 17 Jun 2021 13:49:32 -0400 Received: by mail-wr1-x431.google.com with SMTP id y7so7687809wrh.7 for ; Thu, 17 Jun 2021 10:49:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ouJW6Tu1Wi2ugnpSAzhcCZMWHmSzJZ21PGf32aTzlN8=; b=ehdwTXi6pK+nUsSJiMCAVu7rD67R4Zbj/qpcKHL5FgVaAjY6NGDWwDFx5O+R9Jtife B8DUR8oLp40hUSZ8qbk8JrsrUod++3Jisx3NTZ+sv0HOiXPWFpb+hnLGnVm84C3GhpSP DDM6YpZ7ZJJ+Kr00iWqfww/SXZj5xaGhnlsSoyNHEVFoaYWILSf2MpDX1I2LI24PD4Wu vPIjcNXNzy94oWGFmyiUzKPdlw+nwJq6+R/0PGPw9c97mvSt9Jjez0WoByqcpHgOnXDG JBau69bgs2TnLtWxPF3Y6KhvFRChCNvY4FvtyKL7KMBgo/WzkbOPr28bOTJ1a26bfe17 5Xjg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=ouJW6Tu1Wi2ugnpSAzhcCZMWHmSzJZ21PGf32aTzlN8=; b=iTRr8Zguekt+y/QudIV5B2JyIU9QPv9RSsUFR2w8Tfbwb0fVl85+xD1h4BA8MsWrXI IWC5N1uWbLtYrEKxQVKrF/rLCFIkwow5RVOpPGNl8zape4IhpTRXWbMp9E1C5iRaymRB 3s9npNcW2bjwaG2lPysAZd/UgUb7Eige9YfONKbXXOGorjgfJZ/9JW5j3daqarm/Y7E4 PrHk4yFn7UWiG0ddMhI6MuevbEfPu6jQl9xL2lAruKuo4qbRZHSgrMBlg4jNff3Kph5r ElxaDGXCF1z479pXLEJJFQwZIaVdWbASCftxlBCjF+Y5ADJR7Y+7O+I2Vc0aPGDxcBvA NMlQ== X-Gm-Message-State: AOAM530Uo0o1XJL5fXgBrf1U1tjjDVJ+mb9lfxVnDqzPOx3xhuOcTpTe 9b1LYE3VfzDaGQnsIf2Ud+vwJ+eMzfRCVg== X-Google-Smtp-Source: ABdhPJwyEh9fgI03dRyo5tSGbZ4O/0sE6wRrv402Mze3Uo/cHZ7GEBBjDsn5mn4pAOolRB0NIgXnNg== X-Received: by 2002:adf:f98a:: with SMTP id f10mr7291089wrr.143.1623952163821; Thu, 17 Jun 2021 10:49:23 -0700 (PDT) Received: from x1w.. (93.red-83-35-24.dynamicip.rima-tde.net. [83.35.24.93]) by smtp.gmail.com with ESMTPSA id i16sm5899465wmm.9.2021.06.17.10.49.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Jun 2021 10:49:23 -0700 (PDT) From: =?utf-8?q?Philippe_Mathieu-Daud=C3=A9?= To: qemu-devel@nongnu.org Subject: [PATCH 3/4] target/mips: Extract the microMIPS ISA translation routines Date: Thu, 17 Jun 2021 19:49:06 +0200 Message-Id: <20210617174907.2904067-4-f4bug@amsat.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210617174907.2904067-1-f4bug@amsat.org> References: <20210617174907.2904067-1-f4bug@amsat.org> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::431; envelope-from=philippe.mathieu.daude@gmail.com; helo=mail-wr1-x431.google.com X-Spam_score_int: -14 X-Spam_score: -1.5 X-Spam_bar: - X-Spam_report: (-1.5 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FORGED_FROMDOMAIN=0.249, FREEMAIL_FROM=0.001, HEADER_FROM_DIFFERENT_DOMAINS=0.249, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Aleksandar Rikalo , Richard Henderson , =?utf-8?q?Philippe_Mathie?= =?utf-8?q?u-Daud=C3=A9?= , Aurelien Jarno Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Extract 3200+ lines from the huge translate.c to a new file, 'micromips_translate.c.inc'. As there are too many inter- dependencies we don't compile it as another object, but keep including it in the big translate.o. We gain in code maintainability. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20201120210844.2625602-12-f4bug@amsat.org> --- target/mips/tcg/translate.c | 3231 +-------------------- target/mips/tcg/micromips_translate.c.inc | 3231 +++++++++++++++++++++ 2 files changed, 3237 insertions(+), 3225 deletions(-) create mode 100644 target/mips/tcg/micromips_translate.c.inc diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index c939ba09f2b..7b173e2bd2f 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -12442,958 +12442,6 @@ static inline void gen_helper_do_semihosting(void *env) } #endif -/* microMIPS extension to MIPS32/MIPS64 */ - -/* - * microMIPS32/microMIPS64 major opcodes - * - * 1. MIPS Architecture for Programmers Volume II-B: - * The microMIPS32 Instruction Set (Revision 3.05) - * - * Table 6.2 microMIPS32 Encoding of Major Opcode Field - * - * 2. MIPS Architecture For Programmers Volume II-A: - * The MIPS64 Instruction Set (Revision 3.51) - */ - -enum { - POOL32A = 0x00, - POOL16A = 0x01, - LBU16 = 0x02, - MOVE16 = 0x03, - ADDI32 = 0x04, - R6_LUI = 0x04, - AUI = 0x04, - LBU32 = 0x05, - SB32 = 0x06, - LB32 = 0x07, - - POOL32B = 0x08, - POOL16B = 0x09, - LHU16 = 0x0a, - ANDI16 = 0x0b, - ADDIU32 = 0x0c, - LHU32 = 0x0d, - SH32 = 0x0e, - LH32 = 0x0f, - - POOL32I = 0x10, - POOL16C = 0x11, - LWSP16 = 0x12, - POOL16D = 0x13, - ORI32 = 0x14, - POOL32F = 0x15, - POOL32S = 0x16, /* MIPS64 */ - DADDIU32 = 0x17, /* MIPS64 */ - - POOL32C = 0x18, - LWGP16 = 0x19, - LW16 = 0x1a, - POOL16E = 0x1b, - XORI32 = 0x1c, - JALS32 = 0x1d, - BOVC = 0x1d, - BEQC = 0x1d, - BEQZALC = 0x1d, - ADDIUPC = 0x1e, - PCREL = 0x1e, - BNVC = 0x1f, - BNEC = 0x1f, - BNEZALC = 0x1f, - - R6_BEQZC = 0x20, - JIC = 0x20, - POOL16F = 0x21, - SB16 = 0x22, - BEQZ16 = 0x23, - BEQZC16 = 0x23, - SLTI32 = 0x24, - BEQ32 = 0x25, - BC = 0x25, - SWC132 = 0x26, - LWC132 = 0x27, - - /* 0x29 is reserved */ - RES_29 = 0x29, - R6_BNEZC = 0x28, - JIALC = 0x28, - SH16 = 0x2a, - BNEZ16 = 0x2b, - BNEZC16 = 0x2b, - SLTIU32 = 0x2c, - BNE32 = 0x2d, - BALC = 0x2d, - SDC132 = 0x2e, - LDC132 = 0x2f, - - /* 0x31 is reserved */ - RES_31 = 0x31, - BLEZALC = 0x30, - BGEZALC = 0x30, - BGEUC = 0x30, - SWSP16 = 0x32, - B16 = 0x33, - BC16 = 0x33, - ANDI32 = 0x34, - J32 = 0x35, - BGTZC = 0x35, - BLTZC = 0x35, - BLTC = 0x35, - SD32 = 0x36, /* MIPS64 */ - LD32 = 0x37, /* MIPS64 */ - - /* 0x39 is reserved */ - RES_39 = 0x39, - BGTZALC = 0x38, - BLTZALC = 0x38, - BLTUC = 0x38, - SW16 = 0x3a, - LI16 = 0x3b, - JALX32 = 0x3c, - JAL32 = 0x3d, - BLEZC = 0x3d, - BGEZC = 0x3d, - BGEC = 0x3d, - SW32 = 0x3e, - LW32 = 0x3f -}; - -/* PCREL Instructions perform PC-Relative address calculation. bits 20..16 */ -enum { - ADDIUPC_00 = 0x00, - ADDIUPC_01 = 0x01, - ADDIUPC_02 = 0x02, - ADDIUPC_03 = 0x03, - ADDIUPC_04 = 0x04, - ADDIUPC_05 = 0x05, - ADDIUPC_06 = 0x06, - ADDIUPC_07 = 0x07, - AUIPC = 0x1e, - ALUIPC = 0x1f, - LWPC_08 = 0x08, - LWPC_09 = 0x09, - LWPC_0A = 0x0A, - LWPC_0B = 0x0B, - LWPC_0C = 0x0C, - LWPC_0D = 0x0D, - LWPC_0E = 0x0E, - LWPC_0F = 0x0F, -}; - -/* POOL32A encoding of minor opcode field */ - -enum { - /* - * These opcodes are distinguished only by bits 9..6; those bits are - * what are recorded below. - */ - SLL32 = 0x0, - SRL32 = 0x1, - SRA = 0x2, - ROTR = 0x3, - SELEQZ = 0x5, - SELNEZ = 0x6, - R6_RDHWR = 0x7, - - SLLV = 0x0, - SRLV = 0x1, - SRAV = 0x2, - ROTRV = 0x3, - ADD = 0x4, - ADDU32 = 0x5, - SUB = 0x6, - SUBU32 = 0x7, - MUL = 0x8, - AND = 0x9, - OR32 = 0xa, - NOR = 0xb, - XOR32 = 0xc, - SLT = 0xd, - SLTU = 0xe, - - MOVN = 0x0, - R6_MUL = 0x0, - MOVZ = 0x1, - MUH = 0x1, - MULU = 0x2, - MUHU = 0x3, - LWXS = 0x4, - R6_DIV = 0x4, - MOD = 0x5, - R6_DIVU = 0x6, - MODU = 0x7, - - /* The following can be distinguished by their lower 6 bits. */ - BREAK32 = 0x07, - INS = 0x0c, - LSA = 0x0f, - ALIGN = 0x1f, - EXT = 0x2c, - POOL32AXF = 0x3c, - SIGRIE = 0x3f -}; - -/* POOL32AXF encoding of minor opcode field extension */ - -/* - * 1. MIPS Architecture for Programmers Volume II-B: - * The microMIPS32 Instruction Set (Revision 3.05) - * - * Table 6.5 POOL32Axf Encoding of Minor Opcode Extension Field - * - * 2. MIPS Architecture for Programmers VolumeIV-e: - * The MIPS DSP Application-Specific Extension - * to the microMIPS32 Architecture (Revision 2.34) - * - * Table 5.5 POOL32Axf Encoding of Minor Opcode Extension Field - */ - -enum { - /* bits 11..6 */ - TEQ = 0x00, - TGE = 0x08, - TGEU = 0x10, - TLT = 0x20, - TLTU = 0x28, - TNE = 0x30, - - MFC0 = 0x03, - MTC0 = 0x0b, - - /* begin of microMIPS32 DSP */ - - /* bits 13..12 for 0x01 */ - MFHI_ACC = 0x0, - MFLO_ACC = 0x1, - MTHI_ACC = 0x2, - MTLO_ACC = 0x3, - - /* bits 13..12 for 0x2a */ - MADD_ACC = 0x0, - MADDU_ACC = 0x1, - MSUB_ACC = 0x2, - MSUBU_ACC = 0x3, - - /* bits 13..12 for 0x32 */ - MULT_ACC = 0x0, - MULTU_ACC = 0x1, - - /* end of microMIPS32 DSP */ - - /* bits 15..12 for 0x2c */ - BITSWAP = 0x0, - SEB = 0x2, - SEH = 0x3, - CLO = 0x4, - CLZ = 0x5, - RDHWR = 0x6, - WSBH = 0x7, - MULT = 0x8, - MULTU = 0x9, - DIV = 0xa, - DIVU = 0xb, - MADD = 0xc, - MADDU = 0xd, - MSUB = 0xe, - MSUBU = 0xf, - - /* bits 15..12 for 0x34 */ - MFC2 = 0x4, - MTC2 = 0x5, - MFHC2 = 0x8, - MTHC2 = 0x9, - CFC2 = 0xc, - CTC2 = 0xd, - - /* bits 15..12 for 0x3c */ - JALR = 0x0, - JR = 0x0, /* alias */ - JALRC = 0x0, - JRC = 0x0, - JALR_HB = 0x1, - JALRC_HB = 0x1, - JALRS = 0x4, - JALRS_HB = 0x5, - - /* bits 15..12 for 0x05 */ - RDPGPR = 0xe, - WRPGPR = 0xf, - - /* bits 15..12 for 0x0d */ - TLBP = 0x0, - TLBR = 0x1, - TLBWI = 0x2, - TLBWR = 0x3, - TLBINV = 0x4, - TLBINVF = 0x5, - WAIT = 0x9, - IRET = 0xd, - DERET = 0xe, - ERET = 0xf, - - /* bits 15..12 for 0x15 */ - DMT = 0x0, - DVPE = 0x1, - EMT = 0x2, - EVPE = 0x3, - - /* bits 15..12 for 0x1d */ - DI = 0x4, - EI = 0x5, - - /* bits 15..12 for 0x2d */ - SYNC = 0x6, - SYSCALL = 0x8, - SDBBP = 0xd, - - /* bits 15..12 for 0x35 */ - MFHI32 = 0x0, - MFLO32 = 0x1, - MTHI32 = 0x2, - MTLO32 = 0x3, -}; - -/* POOL32B encoding of minor opcode field (bits 15..12) */ - -enum { - LWC2 = 0x0, - LWP = 0x1, - LDP = 0x4, - LWM32 = 0x5, - CACHE = 0x6, - LDM = 0x7, - SWC2 = 0x8, - SWP = 0x9, - SDP = 0xc, - SWM32 = 0xd, - SDM = 0xf -}; - -/* POOL32C encoding of minor opcode field (bits 15..12) */ - -enum { - LWL = 0x0, - SWL = 0x8, - LWR = 0x1, - SWR = 0x9, - PREF = 0x2, - ST_EVA = 0xa, - LL = 0x3, - SC = 0xb, - LDL = 0x4, - SDL = 0xc, - LDR = 0x5, - SDR = 0xd, - LD_EVA = 0x6, - LWU = 0xe, - LLD = 0x7, - SCD = 0xf -}; - -/* POOL32C LD-EVA encoding of minor opcode field (bits 11..9) */ - -enum { - LBUE = 0x0, - LHUE = 0x1, - LWLE = 0x2, - LWRE = 0x3, - LBE = 0x4, - LHE = 0x5, - LLE = 0x6, - LWE = 0x7, -}; - -/* POOL32C ST-EVA encoding of minor opcode field (bits 11..9) */ - -enum { - SWLE = 0x0, - SWRE = 0x1, - PREFE = 0x2, - CACHEE = 0x3, - SBE = 0x4, - SHE = 0x5, - SCE = 0x6, - SWE = 0x7, -}; - -/* POOL32F encoding of minor opcode field (bits 5..0) */ - -enum { - /* These are the bit 7..6 values */ - ADD_FMT = 0x0, - - SUB_FMT = 0x1, - - MUL_FMT = 0x2, - - DIV_FMT = 0x3, - - /* These are the bit 8..6 values */ - MOVN_FMT = 0x0, - RSQRT2_FMT = 0x0, - MOVF_FMT = 0x0, - RINT_FMT = 0x0, - SELNEZ_FMT = 0x0, - - MOVZ_FMT = 0x1, - LWXC1 = 0x1, - MOVT_FMT = 0x1, - CLASS_FMT = 0x1, - SELEQZ_FMT = 0x1, - - PLL_PS = 0x2, - SWXC1 = 0x2, - SEL_FMT = 0x2, - - PLU_PS = 0x3, - LDXC1 = 0x3, - - MOVN_FMT_04 = 0x4, - PUL_PS = 0x4, - SDXC1 = 0x4, - RECIP2_FMT = 0x4, - - MOVZ_FMT_05 = 0x05, - PUU_PS = 0x5, - LUXC1 = 0x5, - - CVT_PS_S = 0x6, - SUXC1 = 0x6, - ADDR_PS = 0x6, - PREFX = 0x6, - MADDF_FMT = 0x6, - - MULR_PS = 0x7, - MSUBF_FMT = 0x7, - - MADD_S = 0x01, - MADD_D = 0x09, - MADD_PS = 0x11, - ALNV_PS = 0x19, - MSUB_S = 0x21, - MSUB_D = 0x29, - MSUB_PS = 0x31, - - NMADD_S = 0x02, - NMADD_D = 0x0a, - NMADD_PS = 0x12, - NMSUB_S = 0x22, - NMSUB_D = 0x2a, - NMSUB_PS = 0x32, - - MIN_FMT = 0x3, - MAX_FMT = 0xb, - MINA_FMT = 0x23, - MAXA_FMT = 0x2b, - POOL32FXF = 0x3b, - - CABS_COND_FMT = 0x1c, /* MIPS3D */ - C_COND_FMT = 0x3c, - - CMP_CONDN_S = 0x5, - CMP_CONDN_D = 0x15 -}; - -/* POOL32Fxf encoding of minor opcode extension field */ - -enum { - CVT_L = 0x04, - RSQRT_FMT = 0x08, - FLOOR_L = 0x0c, - CVT_PW_PS = 0x1c, - CVT_W = 0x24, - SQRT_FMT = 0x28, - FLOOR_W = 0x2c, - CVT_PS_PW = 0x3c, - CFC1 = 0x40, - RECIP_FMT = 0x48, - CEIL_L = 0x4c, - CTC1 = 0x60, - CEIL_W = 0x6c, - MFC1 = 0x80, - CVT_S_PL = 0x84, - TRUNC_L = 0x8c, - MTC1 = 0xa0, - CVT_S_PU = 0xa4, - TRUNC_W = 0xac, - MFHC1 = 0xc0, - ROUND_L = 0xcc, - MTHC1 = 0xe0, - ROUND_W = 0xec, - - MOV_FMT = 0x01, - MOVF = 0x05, - ABS_FMT = 0x0d, - RSQRT1_FMT = 0x1d, - MOVT = 0x25, - NEG_FMT = 0x2d, - CVT_D = 0x4d, - RECIP1_FMT = 0x5d, - CVT_S = 0x6d -}; - -/* POOL32I encoding of minor opcode field (bits 25..21) */ - -enum { - BLTZ = 0x00, - BLTZAL = 0x01, - BGEZ = 0x02, - BGEZAL = 0x03, - BLEZ = 0x04, - BNEZC = 0x05, - BGTZ = 0x06, - BEQZC = 0x07, - TLTI = 0x08, - BC1EQZC = 0x08, - TGEI = 0x09, - BC1NEZC = 0x09, - TLTIU = 0x0a, - BC2EQZC = 0x0a, - TGEIU = 0x0b, - BC2NEZC = 0x0a, - TNEI = 0x0c, - R6_SYNCI = 0x0c, - LUI = 0x0d, - TEQI = 0x0e, - SYNCI = 0x10, - BLTZALS = 0x11, - BGEZALS = 0x13, - BC2F = 0x14, - BC2T = 0x15, - /* These overlap and are distinguished by bit16 of the instruction */ - BC1F = 0x1c, - BC1T = 0x1d, - BC1ANY2F = 0x1c, - BC1ANY2T = 0x1d, - BC1ANY4F = 0x1e, - BC1ANY4T = 0x1f -}; - -/* POOL16A encoding of minor opcode field */ - -enum { - ADDU16 = 0x0, - SUBU16 = 0x1 -}; - -/* POOL16B encoding of minor opcode field */ - -enum { - SLL16 = 0x0, - SRL16 = 0x1 -}; - -/* POOL16C encoding of minor opcode field */ - -enum { - NOT16 = 0x00, - XOR16 = 0x04, - AND16 = 0x08, - OR16 = 0x0c, - LWM16 = 0x10, - SWM16 = 0x14, - JR16 = 0x18, - JRC16 = 0x1a, - JALR16 = 0x1c, - JALR16S = 0x1e, - MFHI16 = 0x20, - MFLO16 = 0x24, - BREAK16 = 0x28, - SDBBP16 = 0x2c, - JRADDIUSP = 0x30 -}; - -/* R6 POOL16C encoding of minor opcode field (bits 0..5) */ - -enum { - R6_NOT16 = 0x00, - R6_AND16 = 0x01, - R6_LWM16 = 0x02, - R6_JRC16 = 0x03, - MOVEP = 0x04, - MOVEP_05 = 0x05, - MOVEP_06 = 0x06, - MOVEP_07 = 0x07, - R6_XOR16 = 0x08, - R6_OR16 = 0x09, - R6_SWM16 = 0x0a, - JALRC16 = 0x0b, - MOVEP_0C = 0x0c, - MOVEP_0D = 0x0d, - MOVEP_0E = 0x0e, - MOVEP_0F = 0x0f, - JRCADDIUSP = 0x13, - R6_BREAK16 = 0x1b, - R6_SDBBP16 = 0x3b -}; - -/* POOL16D encoding of minor opcode field */ - -enum { - ADDIUS5 = 0x0, - ADDIUSP = 0x1 -}; - -/* POOL16E encoding of minor opcode field */ - -enum { - ADDIUR2 = 0x0, - ADDIUR1SP = 0x1 -}; - -static int mmreg(int r) -{ - static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; - - return map[r]; -} - -/* Used for 16-bit store instructions. */ -static int mmreg2(int r) -{ - static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 }; - - return map[r]; -} - -#define uMIPS_RD(op) ((op >> 7) & 0x7) -#define uMIPS_RS(op) ((op >> 4) & 0x7) -#define uMIPS_RS2(op) uMIPS_RS(op) -#define uMIPS_RS1(op) ((op >> 1) & 0x7) -#define uMIPS_RD5(op) ((op >> 5) & 0x1f) -#define uMIPS_RS5(op) (op & 0x1f) - -/* Signed immediate */ -#define SIMM(op, start, width) \ - ((int32_t)(((op >> start) & ((~0U) >> (32 - width))) \ - << (32 - width)) \ - >> (32 - width)) -/* Zero-extended immediate */ -#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32 - width))) - -static void gen_addiur1sp(DisasContext *ctx) -{ - int rd = mmreg(uMIPS_RD(ctx->opcode)); - - gen_arith_imm(ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2); -} - -static void gen_addiur2(DisasContext *ctx) -{ - static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 }; - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rs = mmreg(uMIPS_RS(ctx->opcode)); - - gen_arith_imm(ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]); -} - -static void gen_addiusp(DisasContext *ctx) -{ - int encoded = ZIMM(ctx->opcode, 1, 9); - int decoded; - - if (encoded <= 1) { - decoded = 256 + encoded; - } else if (encoded <= 255) { - decoded = encoded; - } else if (encoded <= 509) { - decoded = encoded - 512; - } else { - decoded = encoded - 768; - } - - gen_arith_imm(ctx, OPC_ADDIU, 29, 29, decoded << 2); -} - -static void gen_addius5(DisasContext *ctx) -{ - int imm = SIMM(ctx->opcode, 1, 4); - int rd = (ctx->opcode >> 5) & 0x1f; - - gen_arith_imm(ctx, OPC_ADDIU, rd, rd, imm); -} - -static void gen_andi16(DisasContext *ctx) -{ - static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16, - 31, 32, 63, 64, 255, 32768, 65535 }; - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rs = mmreg(uMIPS_RS(ctx->opcode)); - int encoded = ZIMM(ctx->opcode, 0, 4); - - gen_logic_imm(ctx, OPC_ANDI, rd, rs, decoded_imm[encoded]); -} - -static void gen_ldst_multiple(DisasContext *ctx, uint32_t opc, int reglist, - int base, int16_t offset) -{ - TCGv t0, t1; - TCGv_i32 t2; - - if (ctx->hflags & MIPS_HFLAG_BMASK) { - gen_reserved_instruction(ctx); - return; - } - - t0 = tcg_temp_new(); - - gen_base_offset_addr(ctx, t0, base, offset); - - t1 = tcg_const_tl(reglist); - t2 = tcg_const_i32(ctx->mem_idx); - - save_cpu_state(ctx, 1); - switch (opc) { - case LWM32: - gen_helper_lwm(cpu_env, t0, t1, t2); - break; - case SWM32: - gen_helper_swm(cpu_env, t0, t1, t2); - break; -#ifdef TARGET_MIPS64 - case LDM: - gen_helper_ldm(cpu_env, t0, t1, t2); - break; - case SDM: - gen_helper_sdm(cpu_env, t0, t1, t2); - break; -#endif - } - tcg_temp_free(t0); - tcg_temp_free(t1); - tcg_temp_free_i32(t2); -} - - -static void gen_pool16c_insn(DisasContext *ctx) -{ - int rd = mmreg((ctx->opcode >> 3) & 0x7); - int rs = mmreg(ctx->opcode & 0x7); - - switch (((ctx->opcode) >> 4) & 0x3f) { - case NOT16 + 0: - case NOT16 + 1: - case NOT16 + 2: - case NOT16 + 3: - gen_logic(ctx, OPC_NOR, rd, rs, 0); - break; - case XOR16 + 0: - case XOR16 + 1: - case XOR16 + 2: - case XOR16 + 3: - gen_logic(ctx, OPC_XOR, rd, rd, rs); - break; - case AND16 + 0: - case AND16 + 1: - case AND16 + 2: - case AND16 + 3: - gen_logic(ctx, OPC_AND, rd, rd, rs); - break; - case OR16 + 0: - case OR16 + 1: - case OR16 + 2: - case OR16 + 3: - gen_logic(ctx, OPC_OR, rd, rd, rs); - break; - case LWM16 + 0: - case LWM16 + 1: - case LWM16 + 2: - case LWM16 + 3: - { - static const int lwm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; - int offset = ZIMM(ctx->opcode, 0, 4); - - gen_ldst_multiple(ctx, LWM32, lwm_convert[(ctx->opcode >> 4) & 0x3], - 29, offset << 2); - } - break; - case SWM16 + 0: - case SWM16 + 1: - case SWM16 + 2: - case SWM16 + 3: - { - static const int swm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; - int offset = ZIMM(ctx->opcode, 0, 4); - - gen_ldst_multiple(ctx, SWM32, swm_convert[(ctx->opcode >> 4) & 0x3], - 29, offset << 2); - } - break; - case JR16 + 0: - case JR16 + 1: - { - int reg = ctx->opcode & 0x1f; - - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 4); - } - break; - case JRC16 + 0: - case JRC16 + 1: - { - int reg = ctx->opcode & 0x1f; - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0); - /* - * Let normal delay slot handling in our caller take us - * to the branch target. - */ - } - break; - case JALR16 + 0: - case JALR16 + 1: - gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case JALR16S + 0: - case JALR16S + 1: - gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case MFHI16 + 0: - case MFHI16 + 1: - gen_HILO(ctx, OPC_MFHI, 0, uMIPS_RS5(ctx->opcode)); - break; - case MFLO16 + 0: - case MFLO16 + 1: - gen_HILO(ctx, OPC_MFLO, 0, uMIPS_RS5(ctx->opcode)); - break; - case BREAK16: - generate_exception_end(ctx, EXCP_BREAK); - break; - case SDBBP16: - if (is_uhi(extract32(ctx->opcode, 0, 4))) { - gen_helper_do_semihosting(cpu_env); - } else { - /* - * XXX: not clear which exception should be raised - * when in debug mode... - */ - check_insn(ctx, ISA_MIPS_R1); - generate_exception_end(ctx, EXCP_DBp); - } - break; - case JRADDIUSP + 0: - case JRADDIUSP + 1: - { - int imm = ZIMM(ctx->opcode, 0, 5); - gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); - gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); - /* - * Let normal delay slot handling in our caller take us - * to the branch target. - */ - } - break; - default: - gen_reserved_instruction(ctx); - break; - } -} - -static inline void gen_movep(DisasContext *ctx, int enc_dest, int enc_rt, - int enc_rs) -{ - int rd, re; - static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 }; - static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 }; - static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 }; - - rd = rd_enc[enc_dest]; - re = re_enc[enc_dest]; - gen_load_gpr(cpu_gpr[rd], rs_rt_enc[enc_rs]); - gen_load_gpr(cpu_gpr[re], rs_rt_enc[enc_rt]); -} - -static void gen_pool16c_r6_insn(DisasContext *ctx) -{ - int rt = mmreg((ctx->opcode >> 7) & 0x7); - int rs = mmreg((ctx->opcode >> 4) & 0x7); - - switch (ctx->opcode & 0xf) { - case R6_NOT16: - gen_logic(ctx, OPC_NOR, rt, rs, 0); - break; - case R6_AND16: - gen_logic(ctx, OPC_AND, rt, rt, rs); - break; - case R6_LWM16: - { - int lwm_converted = 0x11 + extract32(ctx->opcode, 8, 2); - int offset = extract32(ctx->opcode, 4, 4); - gen_ldst_multiple(ctx, LWM32, lwm_converted, 29, offset << 2); - } - break; - case R6_JRC16: /* JRCADDIUSP */ - if ((ctx->opcode >> 4) & 1) { - /* JRCADDIUSP */ - int imm = extract32(ctx->opcode, 5, 5); - gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); - gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); - } else { - /* JRC16 */ - rs = extract32(ctx->opcode, 5, 5); - gen_compute_branch(ctx, OPC_JR, 2, rs, 0, 0, 0); - } - break; - case MOVEP: - case MOVEP_05: - case MOVEP_06: - case MOVEP_07: - case MOVEP_0C: - case MOVEP_0D: - case MOVEP_0E: - case MOVEP_0F: - { - int enc_dest = uMIPS_RD(ctx->opcode); - int enc_rt = uMIPS_RS2(ctx->opcode); - int enc_rs = (ctx->opcode & 3) | ((ctx->opcode >> 1) & 4); - gen_movep(ctx, enc_dest, enc_rt, enc_rs); - } - break; - case R6_XOR16: - gen_logic(ctx, OPC_XOR, rt, rt, rs); - break; - case R6_OR16: - gen_logic(ctx, OPC_OR, rt, rt, rs); - break; - case R6_SWM16: - { - int swm_converted = 0x11 + extract32(ctx->opcode, 8, 2); - int offset = extract32(ctx->opcode, 4, 4); - gen_ldst_multiple(ctx, SWM32, swm_converted, 29, offset << 2); - } - break; - case JALRC16: /* BREAK16, SDBBP16 */ - switch (ctx->opcode & 0x3f) { - case JALRC16: - case JALRC16 + 0x20: - /* JALRC16 */ - gen_compute_branch(ctx, OPC_JALR, 2, (ctx->opcode >> 5) & 0x1f, - 31, 0, 0); - break; - case R6_BREAK16: - /* BREAK16 */ - generate_exception(ctx, EXCP_BREAK); - break; - case R6_SDBBP16: - /* SDBBP16 */ - if (is_uhi(extract32(ctx->opcode, 6, 4))) { - gen_helper_do_semihosting(cpu_env); - } else { - if (ctx->hflags & MIPS_HFLAG_SBRI) { - generate_exception(ctx, EXCP_RI); - } else { - generate_exception(ctx, EXCP_DBp); - } - } - break; - } - break; - default: - generate_exception(ctx, EXCP_RI); - break; - } -} - void gen_ldxs(DisasContext *ctx, int base, int index, int rd) { TCGv t0 = tcg_temp_new(); @@ -13414,69 +12462,6 @@ void gen_ldxs(DisasContext *ctx, int base, int index, int rd) tcg_temp_free(t1); } -static void gen_ldst_pair(DisasContext *ctx, uint32_t opc, int rd, - int base, int16_t offset) -{ - TCGv t0, t1; - - if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31) { - gen_reserved_instruction(ctx); - return; - } - - t0 = tcg_temp_new(); - t1 = tcg_temp_new(); - - gen_base_offset_addr(ctx, t0, base, offset); - - switch (opc) { - case LWP: - if (rd == base) { - gen_reserved_instruction(ctx); - return; - } - tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); - gen_store_gpr(t1, rd); - tcg_gen_movi_tl(t1, 4); - gen_op_addr_add(ctx, t0, t0, t1); - tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); - gen_store_gpr(t1, rd + 1); - break; - case SWP: - gen_load_gpr(t1, rd); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); - tcg_gen_movi_tl(t1, 4); - gen_op_addr_add(ctx, t0, t0, t1); - gen_load_gpr(t1, rd + 1); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); - break; -#ifdef TARGET_MIPS64 - case LDP: - if (rd == base) { - gen_reserved_instruction(ctx); - return; - } - tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ); - gen_store_gpr(t1, rd); - tcg_gen_movi_tl(t1, 8); - gen_op_addr_add(ctx, t0, t0, t1); - tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ); - gen_store_gpr(t1, rd + 1); - break; - case SDP: - gen_load_gpr(t1, rd); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); - tcg_gen_movi_tl(t1, 8); - gen_op_addr_add(ctx, t0, t0, t1); - gen_load_gpr(t1, rd + 1); - tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); - break; -#endif - } - tcg_temp_free(t0); - tcg_temp_free(t1); -} - static void gen_sync(int stype) { TCGBar tcg_mo = TCG_BAR_SC; @@ -13505,353 +12490,12 @@ static void gen_sync(int stype) tcg_gen_mb(tcg_mo); } -static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs) -{ - int extension = (ctx->opcode >> 6) & 0x3f; - int minor = (ctx->opcode >> 12) & 0xf; - uint32_t mips32_op; +/* ISA extensions (ASEs) */ - switch (extension) { - case TEQ: - mips32_op = OPC_TEQ; - goto do_trap; - case TGE: - mips32_op = OPC_TGE; - goto do_trap; - case TGEU: - mips32_op = OPC_TGEU; - goto do_trap; - case TLT: - mips32_op = OPC_TLT; - goto do_trap; - case TLTU: - mips32_op = OPC_TLTU; - goto do_trap; - case TNE: - mips32_op = OPC_TNE; - do_trap: - gen_trap(ctx, mips32_op, rs, rt, -1); - break; -#ifndef CONFIG_USER_ONLY - case MFC0: - case MFC0 + 32: - check_cp0_enabled(ctx); - if (rt == 0) { - /* Treat as NOP. */ - break; - } - gen_mfc0(ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7); - break; - case MTC0: - case MTC0 + 32: - check_cp0_enabled(ctx); - { - TCGv t0 = tcg_temp_new(); +/* MIPS16 extension to MIPS32 */ +#include "mips16e_translate.c.inc" - gen_load_gpr(t0, rt); - gen_mtc0(ctx, t0, rs, (ctx->opcode >> 11) & 0x7); - tcg_temp_free(t0); - } - break; -#endif - case 0x2a: - switch (minor & 3) { - case MADD_ACC: - gen_muldiv(ctx, OPC_MADD, (ctx->opcode >> 14) & 3, rs, rt); - break; - case MADDU_ACC: - gen_muldiv(ctx, OPC_MADDU, (ctx->opcode >> 14) & 3, rs, rt); - break; - case MSUB_ACC: - gen_muldiv(ctx, OPC_MSUB, (ctx->opcode >> 14) & 3, rs, rt); - break; - case MSUBU_ACC: - gen_muldiv(ctx, OPC_MSUBU, (ctx->opcode >> 14) & 3, rs, rt); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x32: - switch (minor & 3) { - case MULT_ACC: - gen_muldiv(ctx, OPC_MULT, (ctx->opcode >> 14) & 3, rs, rt); - break; - case MULTU_ACC: - gen_muldiv(ctx, OPC_MULTU, (ctx->opcode >> 14) & 3, rs, rt); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x2c: - switch (minor) { - case BITSWAP: - check_insn(ctx, ISA_MIPS_R6); - gen_bitswap(ctx, OPC_BITSWAP, rs, rt); - break; - case SEB: - gen_bshfl(ctx, OPC_SEB, rs, rt); - break; - case SEH: - gen_bshfl(ctx, OPC_SEH, rs, rt); - break; - case CLO: - mips32_op = OPC_CLO; - goto do_cl; - case CLZ: - mips32_op = OPC_CLZ; - do_cl: - check_insn(ctx, ISA_MIPS_R1); - gen_cl(ctx, mips32_op, rt, rs); - break; - case RDHWR: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_rdhwr(ctx, rt, rs, 0); - break; - case WSBH: - gen_bshfl(ctx, OPC_WSBH, rs, rt); - break; - case MULT: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MULT; - goto do_mul; - case MULTU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MULTU; - goto do_mul; - case DIV: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_DIV; - goto do_div; - case DIVU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_DIVU; - goto do_div; - do_div: - check_insn(ctx, ISA_MIPS_R1); - gen_muldiv(ctx, mips32_op, 0, rs, rt); - break; - case MADD: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADD; - goto do_mul; - case MADDU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADDU; - goto do_mul; - case MSUB: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUB; - goto do_mul; - case MSUBU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUBU; - do_mul: - check_insn(ctx, ISA_MIPS_R1); - gen_muldiv(ctx, mips32_op, 0, rs, rt); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x34: - switch (minor) { - case MFC2: - case MTC2: - case MFHC2: - case MTHC2: - case CFC2: - case CTC2: - generate_exception_err(ctx, EXCP_CpU, 2); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x3c: - switch (minor) { - case JALR: /* JALRC */ - case JALR_HB: /* JALRC_HB */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* JALRC, JALRC_HB */ - gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 0); - } else { - /* JALR, JALR_HB */ - gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - } - break; - case JALRS: - case JALRS_HB: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - default: - goto pool32axf_invalid; - } - break; - case 0x05: - switch (minor) { - case RDPGPR: - check_cp0_enabled(ctx); - check_insn(ctx, ISA_MIPS_R2); - gen_load_srsgpr(rs, rt); - break; - case WRPGPR: - check_cp0_enabled(ctx); - check_insn(ctx, ISA_MIPS_R2); - gen_store_srsgpr(rs, rt); - break; - default: - goto pool32axf_invalid; - } - break; -#ifndef CONFIG_USER_ONLY - case 0x0d: - switch (minor) { - case TLBP: - mips32_op = OPC_TLBP; - goto do_cp0; - case TLBR: - mips32_op = OPC_TLBR; - goto do_cp0; - case TLBWI: - mips32_op = OPC_TLBWI; - goto do_cp0; - case TLBWR: - mips32_op = OPC_TLBWR; - goto do_cp0; - case TLBINV: - mips32_op = OPC_TLBINV; - goto do_cp0; - case TLBINVF: - mips32_op = OPC_TLBINVF; - goto do_cp0; - case WAIT: - mips32_op = OPC_WAIT; - goto do_cp0; - case DERET: - mips32_op = OPC_DERET; - goto do_cp0; - case ERET: - mips32_op = OPC_ERET; - do_cp0: - gen_cp0(env, ctx, mips32_op, rt, rs); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x1d: - switch (minor) { - case DI: - check_cp0_enabled(ctx); - { - TCGv t0 = tcg_temp_new(); - - save_cpu_state(ctx, 1); - gen_helper_di(t0, cpu_env); - gen_store_gpr(t0, rs); - /* - * Stop translation as we may have switched the execution - * mode. - */ - ctx->base.is_jmp = DISAS_STOP; - tcg_temp_free(t0); - } - break; - case EI: - check_cp0_enabled(ctx); - { - TCGv t0 = tcg_temp_new(); - - save_cpu_state(ctx, 1); - gen_helper_ei(t0, cpu_env); - gen_store_gpr(t0, rs); - /* - * DISAS_STOP isn't sufficient, we need to ensure we break out - * of translated code to check for pending interrupts. - */ - gen_save_pc(ctx->base.pc_next + 4); - ctx->base.is_jmp = DISAS_EXIT; - tcg_temp_free(t0); - } - break; - default: - goto pool32axf_invalid; - } - break; -#endif - case 0x2d: - switch (minor) { - case SYNC: - gen_sync(extract32(ctx->opcode, 16, 5)); - break; - case SYSCALL: - generate_exception_end(ctx, EXCP_SYSCALL); - break; - case SDBBP: - if (is_uhi(extract32(ctx->opcode, 16, 10))) { - gen_helper_do_semihosting(cpu_env); - } else { - check_insn(ctx, ISA_MIPS_R1); - if (ctx->hflags & MIPS_HFLAG_SBRI) { - gen_reserved_instruction(ctx); - } else { - generate_exception_end(ctx, EXCP_DBp); - } - } - break; - default: - goto pool32axf_invalid; - } - break; - case 0x01: - switch (minor & 3) { - case MFHI_ACC: - gen_HILO(ctx, OPC_MFHI, minor >> 2, rs); - break; - case MFLO_ACC: - gen_HILO(ctx, OPC_MFLO, minor >> 2, rs); - break; - case MTHI_ACC: - gen_HILO(ctx, OPC_MTHI, minor >> 2, rs); - break; - case MTLO_ACC: - gen_HILO(ctx, OPC_MTLO, minor >> 2, rs); - break; - default: - goto pool32axf_invalid; - } - break; - case 0x35: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - switch (minor) { - case MFHI32: - gen_HILO(ctx, OPC_MFHI, 0, rs); - break; - case MFLO32: - gen_HILO(ctx, OPC_MFLO, 0, rs); - break; - case MTHI32: - gen_HILO(ctx, OPC_MTHI, 0, rs); - break; - case MTLO32: - gen_HILO(ctx, OPC_MTLO, 0, rs); - break; - default: - goto pool32axf_invalid; - } - break; - default: - pool32axf_invalid: - MIPS_INVAL("pool32axf"); - gen_reserved_instruction(ctx); - break; - } -} +/* microMIPS extension to MIPS32/MIPS64 */ /* * Values for microMIPS fmt field. Variable-width, depending on which @@ -13874,1870 +12518,7 @@ enum { FMT_DWL_L = 2 }; -static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) -{ - int extension = (ctx->opcode >> 6) & 0x3ff; - uint32_t mips32_op; - -#define FLOAT_1BIT_FMT(opc, fmt) ((fmt << 8) | opc) -#define FLOAT_2BIT_FMT(opc, fmt) ((fmt << 7) | opc) -#define COND_FLOAT_MOV(opc, cond) ((cond << 7) | opc) - - switch (extension) { - case FLOAT_1BIT_FMT(CFC1, 0): - mips32_op = OPC_CFC1; - goto do_cp1; - case FLOAT_1BIT_FMT(CTC1, 0): - mips32_op = OPC_CTC1; - goto do_cp1; - case FLOAT_1BIT_FMT(MFC1, 0): - mips32_op = OPC_MFC1; - goto do_cp1; - case FLOAT_1BIT_FMT(MTC1, 0): - mips32_op = OPC_MTC1; - goto do_cp1; - case FLOAT_1BIT_FMT(MFHC1, 0): - mips32_op = OPC_MFHC1; - goto do_cp1; - case FLOAT_1BIT_FMT(MTHC1, 0): - mips32_op = OPC_MTHC1; - do_cp1: - gen_cp1(ctx, mips32_op, rt, rs); - break; - - /* Reciprocal square root */ - case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_S): - mips32_op = OPC_RSQRT_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_D): - mips32_op = OPC_RSQRT_D; - goto do_unaryfp; - - /* Square root */ - case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_S): - mips32_op = OPC_SQRT_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_D): - mips32_op = OPC_SQRT_D; - goto do_unaryfp; - - /* Reciprocal */ - case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_S): - mips32_op = OPC_RECIP_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_D): - mips32_op = OPC_RECIP_D; - goto do_unaryfp; - - /* Floor */ - case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_S): - mips32_op = OPC_FLOOR_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_D): - mips32_op = OPC_FLOOR_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_S): - mips32_op = OPC_FLOOR_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_D): - mips32_op = OPC_FLOOR_W_D; - goto do_unaryfp; - - /* Ceiling */ - case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_S): - mips32_op = OPC_CEIL_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_D): - mips32_op = OPC_CEIL_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_S): - mips32_op = OPC_CEIL_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_D): - mips32_op = OPC_CEIL_W_D; - goto do_unaryfp; - - /* Truncation */ - case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_S): - mips32_op = OPC_TRUNC_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_D): - mips32_op = OPC_TRUNC_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_S): - mips32_op = OPC_TRUNC_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_D): - mips32_op = OPC_TRUNC_W_D; - goto do_unaryfp; - - /* Round */ - case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_S): - mips32_op = OPC_ROUND_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_D): - mips32_op = OPC_ROUND_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_S): - mips32_op = OPC_ROUND_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_D): - mips32_op = OPC_ROUND_W_D; - goto do_unaryfp; - - /* Integer to floating-point conversion */ - case FLOAT_1BIT_FMT(CVT_L, FMT_SD_S): - mips32_op = OPC_CVT_L_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_L, FMT_SD_D): - mips32_op = OPC_CVT_L_D; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_W, FMT_SD_S): - mips32_op = OPC_CVT_W_S; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_W, FMT_SD_D): - mips32_op = OPC_CVT_W_D; - goto do_unaryfp; - - /* Paired-foo conversions */ - case FLOAT_1BIT_FMT(CVT_S_PL, 0): - mips32_op = OPC_CVT_S_PL; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_S_PU, 0): - mips32_op = OPC_CVT_S_PU; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_PW_PS, 0): - mips32_op = OPC_CVT_PW_PS; - goto do_unaryfp; - case FLOAT_1BIT_FMT(CVT_PS_PW, 0): - mips32_op = OPC_CVT_PS_PW; - goto do_unaryfp; - - /* Floating-point moves */ - case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_S): - mips32_op = OPC_MOV_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_D): - mips32_op = OPC_MOV_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_PS): - mips32_op = OPC_MOV_PS; - goto do_unaryfp; - - /* Absolute value */ - case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_S): - mips32_op = OPC_ABS_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_D): - mips32_op = OPC_ABS_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_PS): - mips32_op = OPC_ABS_PS; - goto do_unaryfp; - - /* Negation */ - case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_S): - mips32_op = OPC_NEG_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_D): - mips32_op = OPC_NEG_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_PS): - mips32_op = OPC_NEG_PS; - goto do_unaryfp; - - /* Reciprocal square root step */ - case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_S): - mips32_op = OPC_RSQRT1_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_D): - mips32_op = OPC_RSQRT1_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_PS): - mips32_op = OPC_RSQRT1_PS; - goto do_unaryfp; - - /* Reciprocal step */ - case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_S): - mips32_op = OPC_RECIP1_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_D): - mips32_op = OPC_RECIP1_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_PS): - mips32_op = OPC_RECIP1_PS; - goto do_unaryfp; - - /* Conversions from double */ - case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_S): - mips32_op = OPC_CVT_D_S; - goto do_unaryfp; - case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_W): - mips32_op = OPC_CVT_D_W; - goto do_unaryfp; - case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_L): - mips32_op = OPC_CVT_D_L; - goto do_unaryfp; - - /* Conversions from single */ - case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_D): - mips32_op = OPC_CVT_S_D; - goto do_unaryfp; - case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_W): - mips32_op = OPC_CVT_S_W; - goto do_unaryfp; - case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_L): - mips32_op = OPC_CVT_S_L; - do_unaryfp: - gen_farith(ctx, mips32_op, -1, rs, rt, 0); - break; - - /* Conditional moves on floating-point codes */ - case COND_FLOAT_MOV(MOVT, 0): - case COND_FLOAT_MOV(MOVT, 1): - case COND_FLOAT_MOV(MOVT, 2): - case COND_FLOAT_MOV(MOVT, 3): - case COND_FLOAT_MOV(MOVT, 4): - case COND_FLOAT_MOV(MOVT, 5): - case COND_FLOAT_MOV(MOVT, 6): - case COND_FLOAT_MOV(MOVT, 7): - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1); - break; - case COND_FLOAT_MOV(MOVF, 0): - case COND_FLOAT_MOV(MOVF, 1): - case COND_FLOAT_MOV(MOVF, 2): - case COND_FLOAT_MOV(MOVF, 3): - case COND_FLOAT_MOV(MOVF, 4): - case COND_FLOAT_MOV(MOVF, 5): - case COND_FLOAT_MOV(MOVF, 6): - case COND_FLOAT_MOV(MOVF, 7): - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0); - break; - default: - MIPS_INVAL("pool32fxf"); - gen_reserved_instruction(ctx); - break; - } -} - -static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) -{ - int32_t offset; - uint16_t insn; - int rt, rs, rd, rr; - int16_t imm; - uint32_t op, minor, minor2, mips32_op; - uint32_t cond, fmt, cc; - - insn = translator_lduw(env, ctx->base.pc_next + 2); - ctx->opcode = (ctx->opcode << 16) | insn; - - rt = (ctx->opcode >> 21) & 0x1f; - rs = (ctx->opcode >> 16) & 0x1f; - rd = (ctx->opcode >> 11) & 0x1f; - rr = (ctx->opcode >> 6) & 0x1f; - imm = (int16_t) ctx->opcode; - - op = (ctx->opcode >> 26) & 0x3f; - switch (op) { - case POOL32A: - minor = ctx->opcode & 0x3f; - switch (minor) { - case 0x00: - minor = (ctx->opcode >> 6) & 0xf; - switch (minor) { - case SLL32: - mips32_op = OPC_SLL; - goto do_shifti; - case SRA: - mips32_op = OPC_SRA; - goto do_shifti; - case SRL32: - mips32_op = OPC_SRL; - goto do_shifti; - case ROTR: - mips32_op = OPC_ROTR; - do_shifti: - gen_shift_imm(ctx, mips32_op, rt, rs, rd); - break; - case SELEQZ: - check_insn(ctx, ISA_MIPS_R6); - gen_cond_move(ctx, OPC_SELEQZ, rd, rs, rt); - break; - case SELNEZ: - check_insn(ctx, ISA_MIPS_R6); - gen_cond_move(ctx, OPC_SELNEZ, rd, rs, rt); - break; - case R6_RDHWR: - check_insn(ctx, ISA_MIPS_R6); - gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3)); - break; - default: - goto pool32a_invalid; - } - break; - case 0x10: - minor = (ctx->opcode >> 6) & 0xf; - switch (minor) { - /* Arithmetic */ - case ADD: - mips32_op = OPC_ADD; - goto do_arith; - case ADDU32: - mips32_op = OPC_ADDU; - goto do_arith; - case SUB: - mips32_op = OPC_SUB; - goto do_arith; - case SUBU32: - mips32_op = OPC_SUBU; - goto do_arith; - case MUL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MUL; - do_arith: - gen_arith(ctx, mips32_op, rd, rs, rt); - break; - /* Shifts */ - case SLLV: - mips32_op = OPC_SLLV; - goto do_shift; - case SRLV: - mips32_op = OPC_SRLV; - goto do_shift; - case SRAV: - mips32_op = OPC_SRAV; - goto do_shift; - case ROTRV: - mips32_op = OPC_ROTRV; - do_shift: - gen_shift(ctx, mips32_op, rd, rs, rt); - break; - /* Logical operations */ - case AND: - mips32_op = OPC_AND; - goto do_logic; - case OR32: - mips32_op = OPC_OR; - goto do_logic; - case NOR: - mips32_op = OPC_NOR; - goto do_logic; - case XOR32: - mips32_op = OPC_XOR; - do_logic: - gen_logic(ctx, mips32_op, rd, rs, rt); - break; - /* Set less than */ - case SLT: - mips32_op = OPC_SLT; - goto do_slt; - case SLTU: - mips32_op = OPC_SLTU; - do_slt: - gen_slt(ctx, mips32_op, rd, rs, rt); - break; - default: - goto pool32a_invalid; - } - break; - case 0x18: - minor = (ctx->opcode >> 6) & 0xf; - switch (minor) { - /* Conditional moves */ - case MOVN: /* MUL */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* MUL */ - gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt); - } else { - /* MOVN */ - gen_cond_move(ctx, OPC_MOVN, rd, rs, rt); - } - break; - case MOVZ: /* MUH */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* MUH */ - gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt); - } else { - /* MOVZ */ - gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt); - } - break; - case MULU: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt); - break; - case MUHU: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt); - break; - case LWXS: /* DIV */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* DIV */ - gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt); - } else { - /* LWXS */ - gen_ldxs(ctx, rs, rt, rd); - } - break; - case MOD: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt); - break; - case R6_DIVU: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt); - break; - case MODU: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt); - break; - default: - goto pool32a_invalid; - } - break; - case INS: - gen_bitops(ctx, OPC_INS, rt, rs, rr, rd); - return; - case LSA: - check_insn(ctx, ISA_MIPS_R6); - gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2)); - break; - case ALIGN: - check_insn(ctx, ISA_MIPS_R6); - gen_align(ctx, 32, rd, rs, rt, extract32(ctx->opcode, 9, 2)); - break; - case EXT: - gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd); - return; - case POOL32AXF: - gen_pool32axf(env, ctx, rt, rs); - break; - case BREAK32: - generate_exception_end(ctx, EXCP_BREAK); - break; - case SIGRIE: - check_insn(ctx, ISA_MIPS_R6); - gen_reserved_instruction(ctx); - break; - default: - pool32a_invalid: - MIPS_INVAL("pool32a"); - gen_reserved_instruction(ctx); - break; - } - break; - case POOL32B: - minor = (ctx->opcode >> 12) & 0xf; - switch (minor) { - case CACHE: - check_cp0_enabled(ctx); - if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { - gen_cache_operation(ctx, rt, rs, imm); - } - break; - case LWC2: - case SWC2: - /* COP2: Not implemented. */ - generate_exception_err(ctx, EXCP_CpU, 2); - break; -#ifdef TARGET_MIPS64 - case LDP: - case SDP: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); -#endif - /* fall through */ - case LWP: - case SWP: - gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); - break; -#ifdef TARGET_MIPS64 - case LDM: - case SDM: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); -#endif - /* fall through */ - case LWM32: - case SWM32: - gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); - break; - default: - MIPS_INVAL("pool32b"); - gen_reserved_instruction(ctx); - break; - } - break; - case POOL32F: - if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { - minor = ctx->opcode & 0x3f; - check_cp1_enabled(ctx); - switch (minor) { - case ALNV_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_ALNV_PS; - goto do_madd; - case MADD_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADD_S; - goto do_madd; - case MADD_D: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADD_D; - goto do_madd; - case MADD_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MADD_PS; - goto do_madd; - case MSUB_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUB_S; - goto do_madd; - case MSUB_D: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUB_D; - goto do_madd; - case MSUB_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_MSUB_PS; - goto do_madd; - case NMADD_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMADD_S; - goto do_madd; - case NMADD_D: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMADD_D; - goto do_madd; - case NMADD_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMADD_PS; - goto do_madd; - case NMSUB_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMSUB_S; - goto do_madd; - case NMSUB_D: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMSUB_D; - goto do_madd; - case NMSUB_PS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_NMSUB_PS; - do_madd: - gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt); - break; - case CABS_COND_FMT: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - cond = (ctx->opcode >> 6) & 0xf; - cc = (ctx->opcode >> 13) & 0x7; - fmt = (ctx->opcode >> 10) & 0x3; - switch (fmt) { - case 0x0: - gen_cmpabs_s(ctx, cond, rt, rs, cc); - break; - case 0x1: - gen_cmpabs_d(ctx, cond, rt, rs, cc); - break; - case 0x2: - gen_cmpabs_ps(ctx, cond, rt, rs, cc); - break; - default: - goto pool32f_invalid; - } - break; - case C_COND_FMT: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - cond = (ctx->opcode >> 6) & 0xf; - cc = (ctx->opcode >> 13) & 0x7; - fmt = (ctx->opcode >> 10) & 0x3; - switch (fmt) { - case 0x0: - gen_cmp_s(ctx, cond, rt, rs, cc); - break; - case 0x1: - gen_cmp_d(ctx, cond, rt, rs, cc); - break; - case 0x2: - gen_cmp_ps(ctx, cond, rt, rs, cc); - break; - default: - goto pool32f_invalid; - } - break; - case CMP_CONDN_S: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_cmp_s(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); - break; - case CMP_CONDN_D: - check_insn(ctx, ISA_MIPS_R6); - gen_r6_cmp_d(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); - break; - case POOL32FXF: - gen_pool32fxf(ctx, rt, rs); - break; - case 0x00: - /* PLL foo */ - switch ((ctx->opcode >> 6) & 0x7) { - case PLL_PS: - mips32_op = OPC_PLL_PS; - goto do_ps; - case PLU_PS: - mips32_op = OPC_PLU_PS; - goto do_ps; - case PUL_PS: - mips32_op = OPC_PUL_PS; - goto do_ps; - case PUU_PS: - mips32_op = OPC_PUU_PS; - goto do_ps; - case CVT_PS_S: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_CVT_PS_S; - do_ps: - gen_farith(ctx, mips32_op, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case MIN_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MIN_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MIN_D, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case 0x08: - /* [LS][WDU]XC1 */ - switch ((ctx->opcode >> 6) & 0x7) { - case LWXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWXC1; - goto do_ldst_cp1; - case SWXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWXC1; - goto do_ldst_cp1; - case LDXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LDXC1; - goto do_ldst_cp1; - case SDXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SDXC1; - goto do_ldst_cp1; - case LUXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LUXC1; - goto do_ldst_cp1; - case SUXC1: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SUXC1; - do_ldst_cp1: - gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs); - break; - default: - goto pool32f_invalid; - } - break; - case MAX_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MAX_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MAX_D, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case 0x18: - /* 3D insns */ - check_insn_opc_removed(ctx, ISA_MIPS_R6); - fmt = (ctx->opcode >> 9) & 0x3; - switch ((ctx->opcode >> 6) & 0x7) { - case RSQRT2_FMT: - switch (fmt) { - case FMT_SDPS_S: - mips32_op = OPC_RSQRT2_S; - goto do_3d; - case FMT_SDPS_D: - mips32_op = OPC_RSQRT2_D; - goto do_3d; - case FMT_SDPS_PS: - mips32_op = OPC_RSQRT2_PS; - goto do_3d; - default: - goto pool32f_invalid; - } - break; - case RECIP2_FMT: - switch (fmt) { - case FMT_SDPS_S: - mips32_op = OPC_RECIP2_S; - goto do_3d; - case FMT_SDPS_D: - mips32_op = OPC_RECIP2_D; - goto do_3d; - case FMT_SDPS_PS: - mips32_op = OPC_RECIP2_PS; - goto do_3d; - default: - goto pool32f_invalid; - } - break; - case ADDR_PS: - mips32_op = OPC_ADDR_PS; - goto do_3d; - case MULR_PS: - mips32_op = OPC_MULR_PS; - do_3d: - gen_farith(ctx, mips32_op, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case 0x20: - /* MOV[FT].fmt, PREFX, RINT.fmt, CLASS.fmt*/ - cc = (ctx->opcode >> 13) & 0x7; - fmt = (ctx->opcode >> 9) & 0x3; - switch ((ctx->opcode >> 6) & 0x7) { - case MOVF_FMT: /* RINT_FMT */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* RINT_FMT */ - switch (fmt) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_RINT_S, 0, rt, rs, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_RINT_D, 0, rt, rs, 0); - break; - default: - goto pool32f_invalid; - } - } else { - /* MOVF_FMT */ - switch (fmt) { - case FMT_SDPS_S: - gen_movcf_s(ctx, rs, rt, cc, 0); - break; - case FMT_SDPS_D: - gen_movcf_d(ctx, rs, rt, cc, 0); - break; - case FMT_SDPS_PS: - check_ps(ctx); - gen_movcf_ps(ctx, rs, rt, cc, 0); - break; - default: - goto pool32f_invalid; - } - } - break; - case MOVT_FMT: /* CLASS_FMT */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* CLASS_FMT */ - switch (fmt) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_CLASS_S, 0, rt, rs, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_CLASS_D, 0, rt, rs, 0); - break; - default: - goto pool32f_invalid; - } - } else { - /* MOVT_FMT */ - switch (fmt) { - case FMT_SDPS_S: - gen_movcf_s(ctx, rs, rt, cc, 1); - break; - case FMT_SDPS_D: - gen_movcf_d(ctx, rs, rt, cc, 1); - break; - case FMT_SDPS_PS: - check_ps(ctx); - gen_movcf_ps(ctx, rs, rt, cc, 1); - break; - default: - goto pool32f_invalid; - } - } - break; - case PREFX: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - break; - default: - goto pool32f_invalid; - } - break; -#define FINSN_3ARG_SDPS(prfx) \ - switch ((ctx->opcode >> 8) & 0x3) { \ - case FMT_SDPS_S: \ - mips32_op = OPC_##prfx##_S; \ - goto do_fpop; \ - case FMT_SDPS_D: \ - mips32_op = OPC_##prfx##_D; \ - goto do_fpop; \ - case FMT_SDPS_PS: \ - check_ps(ctx); \ - mips32_op = OPC_##prfx##_PS; \ - goto do_fpop; \ - default: \ - goto pool32f_invalid; \ - } - case MINA_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MINA_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MINA_D, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case MAXA_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_farith(ctx, OPC_MAXA_S, rt, rs, rd, 0); - break; - case FMT_SDPS_D: - gen_farith(ctx, OPC_MAXA_D, rt, rs, rd, 0); - break; - default: - goto pool32f_invalid; - } - break; - case 0x30: - /* regular FP ops */ - switch ((ctx->opcode >> 6) & 0x3) { - case ADD_FMT: - FINSN_3ARG_SDPS(ADD); - break; - case SUB_FMT: - FINSN_3ARG_SDPS(SUB); - break; - case MUL_FMT: - FINSN_3ARG_SDPS(MUL); - break; - case DIV_FMT: - fmt = (ctx->opcode >> 8) & 0x3; - if (fmt == 1) { - mips32_op = OPC_DIV_D; - } else if (fmt == 0) { - mips32_op = OPC_DIV_S; - } else { - goto pool32f_invalid; - } - goto do_fpop; - default: - goto pool32f_invalid; - } - break; - case 0x38: - /* cmovs */ - switch ((ctx->opcode >> 6) & 0x7) { - case MOVN_FMT: /* SELEQZ_FMT */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* SELEQZ_FMT */ - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_sel_s(ctx, OPC_SELEQZ_S, rd, rt, rs); - break; - case FMT_SDPS_D: - gen_sel_d(ctx, OPC_SELEQZ_D, rd, rt, rs); - break; - default: - goto pool32f_invalid; - } - } else { - /* MOVN_FMT */ - FINSN_3ARG_SDPS(MOVN); - } - break; - case MOVN_FMT_04: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - FINSN_3ARG_SDPS(MOVN); - break; - case MOVZ_FMT: /* SELNEZ_FMT */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* SELNEZ_FMT */ - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_sel_s(ctx, OPC_SELNEZ_S, rd, rt, rs); - break; - case FMT_SDPS_D: - gen_sel_d(ctx, OPC_SELNEZ_D, rd, rt, rs); - break; - default: - goto pool32f_invalid; - } - } else { - /* MOVZ_FMT */ - FINSN_3ARG_SDPS(MOVZ); - } - break; - case MOVZ_FMT_05: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - FINSN_3ARG_SDPS(MOVZ); - break; - case SEL_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - gen_sel_s(ctx, OPC_SEL_S, rd, rt, rs); - break; - case FMT_SDPS_D: - gen_sel_d(ctx, OPC_SEL_D, rd, rt, rs); - break; - default: - goto pool32f_invalid; - } - break; - case MADDF_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - mips32_op = OPC_MADDF_S; - goto do_fpop; - case FMT_SDPS_D: - mips32_op = OPC_MADDF_D; - goto do_fpop; - default: - goto pool32f_invalid; - } - break; - case MSUBF_FMT: - check_insn(ctx, ISA_MIPS_R6); - switch ((ctx->opcode >> 9) & 0x3) { - case FMT_SDPS_S: - mips32_op = OPC_MSUBF_S; - goto do_fpop; - case FMT_SDPS_D: - mips32_op = OPC_MSUBF_D; - goto do_fpop; - default: - goto pool32f_invalid; - } - break; - default: - goto pool32f_invalid; - } - break; - do_fpop: - gen_farith(ctx, mips32_op, rt, rs, rd, 0); - break; - default: - pool32f_invalid: - MIPS_INVAL("pool32f"); - gen_reserved_instruction(ctx); - break; - } - } else { - generate_exception_err(ctx, EXCP_CpU, 1); - } - break; - case POOL32I: - minor = (ctx->opcode >> 21) & 0x1f; - switch (minor) { - case BLTZ: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4); - break; - case BLTZAL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case BLTZALS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case BGEZ: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4); - break; - case BGEZAL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case BGEZALS: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case BLEZ: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4); - break; - case BGTZ: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4); - break; - - /* Traps */ - case TLTI: /* BC1EQZC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* BC1EQZC */ - check_cp1_enabled(ctx); - gen_compute_branch1_r6(ctx, OPC_BC1EQZ, rs, imm << 1, 0); - } else { - /* TLTI */ - mips32_op = OPC_TLTI; - goto do_trapi; - } - break; - case TGEI: /* BC1NEZC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* BC1NEZC */ - check_cp1_enabled(ctx); - gen_compute_branch1_r6(ctx, OPC_BC1NEZ, rs, imm << 1, 0); - } else { - /* TGEI */ - mips32_op = OPC_TGEI; - goto do_trapi; - } - break; - case TLTIU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_TLTIU; - goto do_trapi; - case TGEIU: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_TGEIU; - goto do_trapi; - case TNEI: /* SYNCI */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* SYNCI */ - /* - * Break the TB to be able to sync copied instructions - * immediately. - */ - ctx->base.is_jmp = DISAS_STOP; - } else { - /* TNEI */ - mips32_op = OPC_TNEI; - goto do_trapi; - } - break; - case TEQI: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_TEQI; - do_trapi: - gen_trap(ctx, mips32_op, rs, -1, imm); - break; - - case BNEZC: - case BEQZC: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, - 4, rs, 0, imm << 1, 0); - /* - * Compact branches don't have a delay slot, so just let - * the normal delay slot handling take us to the branch - * target. - */ - break; - case LUI: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - gen_logic_imm(ctx, OPC_LUI, rs, 0, imm); - break; - case SYNCI: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - /* - * Break the TB to be able to sync copied instructions - * immediately. - */ - ctx->base.is_jmp = DISAS_STOP; - break; - case BC2F: - case BC2T: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - /* COP2: Not implemented. */ - generate_exception_err(ctx, EXCP_CpU, 2); - break; - case BC1F: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F; - goto do_cp1branch; - case BC1T: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T; - goto do_cp1branch; - case BC1ANY4F: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_BC1FANY4; - goto do_cp1mips3d; - case BC1ANY4T: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_BC1TANY4; - do_cp1mips3d: - check_cop1x(ctx); - check_insn(ctx, ASE_MIPS3D); - /* Fall through */ - do_cp1branch: - if (env->CP0_Config1 & (1 << CP0C1_FP)) { - check_cp1_enabled(ctx); - gen_compute_branch1(ctx, mips32_op, - (ctx->opcode >> 18) & 0x7, imm << 1); - } else { - generate_exception_err(ctx, EXCP_CpU, 1); - } - break; - default: - MIPS_INVAL("pool32i"); - gen_reserved_instruction(ctx); - break; - } - break; - case POOL32C: - minor = (ctx->opcode >> 12) & 0xf; - offset = sextract32(ctx->opcode, 0, - (ctx->insn_flags & ISA_MIPS_R6) ? 9 : 12); - switch (minor) { - case LWL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWL; - goto do_ld_lr; - case SWL: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWL; - goto do_st_lr; - case LWR: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWR; - goto do_ld_lr; - case SWR: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWR; - goto do_st_lr; -#if defined(TARGET_MIPS64) - case LDL: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LDL; - goto do_ld_lr; - case SDL: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SDL; - goto do_st_lr; - case LDR: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LDR; - goto do_ld_lr; - case SDR: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SDR; - goto do_st_lr; - case LWU: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - mips32_op = OPC_LWU; - goto do_ld_lr; - case LLD: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - mips32_op = OPC_LLD; - goto do_ld_lr; -#endif - case LL: - mips32_op = OPC_LL; - goto do_ld_lr; - do_ld_lr: - gen_ld(ctx, mips32_op, rt, rs, offset); - break; - do_st_lr: - gen_st(ctx, mips32_op, rt, rs, offset); - break; - case SC: - gen_st_cond(ctx, rt, rs, offset, MO_TESL, false); - break; -#if defined(TARGET_MIPS64) - case SCD: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - gen_st_cond(ctx, rt, rs, offset, MO_TEQ, false); - break; -#endif - case LD_EVA: - if (!ctx->eva) { - MIPS_INVAL("pool32c ld-eva"); - gen_reserved_instruction(ctx); - break; - } - check_cp0_enabled(ctx); - - minor2 = (ctx->opcode >> 9) & 0x7; - offset = sextract32(ctx->opcode, 0, 9); - switch (minor2) { - case LBUE: - mips32_op = OPC_LBUE; - goto do_ld_lr; - case LHUE: - mips32_op = OPC_LHUE; - goto do_ld_lr; - case LWLE: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWLE; - goto do_ld_lr; - case LWRE: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_LWRE; - goto do_ld_lr; - case LBE: - mips32_op = OPC_LBE; - goto do_ld_lr; - case LHE: - mips32_op = OPC_LHE; - goto do_ld_lr; - case LLE: - mips32_op = OPC_LLE; - goto do_ld_lr; - case LWE: - mips32_op = OPC_LWE; - goto do_ld_lr; - }; - break; - case ST_EVA: - if (!ctx->eva) { - MIPS_INVAL("pool32c st-eva"); - gen_reserved_instruction(ctx); - break; - } - check_cp0_enabled(ctx); - - minor2 = (ctx->opcode >> 9) & 0x7; - offset = sextract32(ctx->opcode, 0, 9); - switch (minor2) { - case SWLE: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWLE; - goto do_st_lr; - case SWRE: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - mips32_op = OPC_SWRE; - goto do_st_lr; - case PREFE: - /* Treat as no-op */ - if ((ctx->insn_flags & ISA_MIPS_R6) && (rt >= 24)) { - /* hint codes 24-31 are reserved and signal RI */ - generate_exception(ctx, EXCP_RI); - } - break; - case CACHEE: - /* Treat as no-op */ - if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { - gen_cache_operation(ctx, rt, rs, offset); - } - break; - case SBE: - mips32_op = OPC_SBE; - goto do_st_lr; - case SHE: - mips32_op = OPC_SHE; - goto do_st_lr; - case SCE: - gen_st_cond(ctx, rt, rs, offset, MO_TESL, true); - break; - case SWE: - mips32_op = OPC_SWE; - goto do_st_lr; - }; - break; - case PREF: - /* Treat as no-op */ - if ((ctx->insn_flags & ISA_MIPS_R6) && (rt >= 24)) { - /* hint codes 24-31 are reserved and signal RI */ - generate_exception(ctx, EXCP_RI); - } - break; - default: - MIPS_INVAL("pool32c"); - gen_reserved_instruction(ctx); - break; - } - break; - case ADDI32: /* AUI, LUI */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* AUI, LUI */ - gen_logic_imm(ctx, OPC_LUI, rt, rs, imm); - } else { - /* ADDI32 */ - mips32_op = OPC_ADDI; - goto do_addi; - } - break; - case ADDIU32: - mips32_op = OPC_ADDIU; - do_addi: - gen_arith_imm(ctx, mips32_op, rt, rs, imm); - break; - - /* Logical operations */ - case ORI32: - mips32_op = OPC_ORI; - goto do_logici; - case XORI32: - mips32_op = OPC_XORI; - goto do_logici; - case ANDI32: - mips32_op = OPC_ANDI; - do_logici: - gen_logic_imm(ctx, mips32_op, rt, rs, imm); - break; - - /* Set less than immediate */ - case SLTI32: - mips32_op = OPC_SLTI; - goto do_slti; - case SLTIU32: - mips32_op = OPC_SLTIU; - do_slti: - gen_slt_imm(ctx, mips32_op, rt, rs, imm); - break; - case JALX32: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; - gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - break; - case JALS32: /* BOVC, BEQC, BEQZALC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - if (rs >= rt) { - /* BOVC */ - mips32_op = OPC_BOVC; - } else if (rs < rt && rs == 0) { - /* BEQZALC */ - mips32_op = OPC_BEQZALC; - } else { - /* BEQC */ - mips32_op = OPC_BEQC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - } else { - /* JALS32 */ - offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; - gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - } - break; - case BEQ32: /* BC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* BC */ - gen_compute_compact_branch(ctx, OPC_BC, 0, 0, - sextract32(ctx->opcode << 1, 0, 27)); - } else { - /* BEQ32 */ - gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4); - } - break; - case BNE32: /* BALC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* BALC */ - gen_compute_compact_branch(ctx, OPC_BALC, 0, 0, - sextract32(ctx->opcode << 1, 0, 27)); - } else { - /* BNE32 */ - gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); - } - break; - case J32: /* BGTZC, BLTZC, BLTC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - if (rs == 0 && rt != 0) { - /* BGTZC */ - mips32_op = OPC_BGTZC; - } else if (rs != 0 && rt != 0 && rs == rt) { - /* BLTZC */ - mips32_op = OPC_BLTZC; - } else { - /* BLTC */ - mips32_op = OPC_BLTC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - } else { - /* J32 */ - gen_compute_branch(ctx, OPC_J, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); - } - break; - case JAL32: /* BLEZC, BGEZC, BGEC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - if (rs == 0 && rt != 0) { - /* BLEZC */ - mips32_op = OPC_BLEZC; - } else if (rs != 0 && rt != 0 && rs == rt) { - /* BGEZC */ - mips32_op = OPC_BGEZC; - } else { - /* BGEC */ - mips32_op = OPC_BGEC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - } else { - /* JAL32 */ - gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); - ctx->hflags |= MIPS_HFLAG_BDS_STRICT; - } - break; - /* Floating point (COP1) */ - case LWC132: - mips32_op = OPC_LWC1; - goto do_cop1; - case LDC132: - mips32_op = OPC_LDC1; - goto do_cop1; - case SWC132: - mips32_op = OPC_SWC1; - goto do_cop1; - case SDC132: - mips32_op = OPC_SDC1; - do_cop1: - gen_cop1_ldst(ctx, mips32_op, rt, rs, imm); - break; - case ADDIUPC: /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ - if (ctx->insn_flags & ISA_MIPS_R6) { - /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ - switch ((ctx->opcode >> 16) & 0x1f) { - case ADDIUPC_00: - case ADDIUPC_01: - case ADDIUPC_02: - case ADDIUPC_03: - case ADDIUPC_04: - case ADDIUPC_05: - case ADDIUPC_06: - case ADDIUPC_07: - gen_pcrel(ctx, OPC_ADDIUPC, ctx->base.pc_next & ~0x3, rt); - break; - case AUIPC: - gen_pcrel(ctx, OPC_AUIPC, ctx->base.pc_next, rt); - break; - case ALUIPC: - gen_pcrel(ctx, OPC_ALUIPC, ctx->base.pc_next, rt); - break; - case LWPC_08: - case LWPC_09: - case LWPC_0A: - case LWPC_0B: - case LWPC_0C: - case LWPC_0D: - case LWPC_0E: - case LWPC_0F: - gen_pcrel(ctx, R6_OPC_LWPC, ctx->base.pc_next & ~0x3, rt); - break; - default: - generate_exception(ctx, EXCP_RI); - break; - } - } else { - /* ADDIUPC */ - int reg = mmreg(ZIMM(ctx->opcode, 23, 3)); - offset = SIMM(ctx->opcode, 0, 23) << 2; - - gen_addiupc(ctx, reg, offset, 0, 0); - } - break; - case BNVC: /* BNEC, BNEZALC */ - check_insn(ctx, ISA_MIPS_R6); - if (rs >= rt) { - /* BNVC */ - mips32_op = OPC_BNVC; - } else if (rs < rt && rs == 0) { - /* BNEZALC */ - mips32_op = OPC_BNEZALC; - } else { - /* BNEC */ - mips32_op = OPC_BNEC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - break; - case R6_BNEZC: /* JIALC */ - check_insn(ctx, ISA_MIPS_R6); - if (rt != 0) { - /* BNEZC */ - gen_compute_compact_branch(ctx, OPC_BNEZC, rt, 0, - sextract32(ctx->opcode << 1, 0, 22)); - } else { - /* JIALC */ - gen_compute_compact_branch(ctx, OPC_JIALC, 0, rs, imm); - } - break; - case R6_BEQZC: /* JIC */ - check_insn(ctx, ISA_MIPS_R6); - if (rt != 0) { - /* BEQZC */ - gen_compute_compact_branch(ctx, OPC_BEQZC, rt, 0, - sextract32(ctx->opcode << 1, 0, 22)); - } else { - /* JIC */ - gen_compute_compact_branch(ctx, OPC_JIC, 0, rs, imm); - } - break; - case BLEZALC: /* BGEZALC, BGEUC */ - check_insn(ctx, ISA_MIPS_R6); - if (rs == 0 && rt != 0) { - /* BLEZALC */ - mips32_op = OPC_BLEZALC; - } else if (rs != 0 && rt != 0 && rs == rt) { - /* BGEZALC */ - mips32_op = OPC_BGEZALC; - } else { - /* BGEUC */ - mips32_op = OPC_BGEUC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - break; - case BGTZALC: /* BLTZALC, BLTUC */ - check_insn(ctx, ISA_MIPS_R6); - if (rs == 0 && rt != 0) { - /* BGTZALC */ - mips32_op = OPC_BGTZALC; - } else if (rs != 0 && rt != 0 && rs == rt) { - /* BLTZALC */ - mips32_op = OPC_BLTZALC; - } else { - /* BLTUC */ - mips32_op = OPC_BLTUC; - } - gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); - break; - /* Loads and stores */ - case LB32: - mips32_op = OPC_LB; - goto do_ld; - case LBU32: - mips32_op = OPC_LBU; - goto do_ld; - case LH32: - mips32_op = OPC_LH; - goto do_ld; - case LHU32: - mips32_op = OPC_LHU; - goto do_ld; - case LW32: - mips32_op = OPC_LW; - goto do_ld; -#ifdef TARGET_MIPS64 - case LD32: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - mips32_op = OPC_LD; - goto do_ld; - case SD32: - check_insn(ctx, ISA_MIPS3); - check_mips_64(ctx); - mips32_op = OPC_SD; - goto do_st; -#endif - case SB32: - mips32_op = OPC_SB; - goto do_st; - case SH32: - mips32_op = OPC_SH; - goto do_st; - case SW32: - mips32_op = OPC_SW; - goto do_st; - do_ld: - gen_ld(ctx, mips32_op, rt, rs, imm); - break; - do_st: - gen_st(ctx, mips32_op, rt, rs, imm); - break; - default: - gen_reserved_instruction(ctx); - break; - } -} - -static int decode_micromips_opc(CPUMIPSState *env, DisasContext *ctx) -{ - uint32_t op; - - /* make sure instructions are on a halfword boundary */ - if (ctx->base.pc_next & 0x1) { - env->CP0_BadVAddr = ctx->base.pc_next; - generate_exception_end(ctx, EXCP_AdEL); - return 2; - } - - op = (ctx->opcode >> 10) & 0x3f; - /* Enforce properly-sized instructions in a delay slot */ - if (ctx->hflags & MIPS_HFLAG_BDS_STRICT) { - switch (op & 0x7) { /* MSB-3..MSB-5 */ - case 0: - /* POOL32A, POOL32B, POOL32I, POOL32C */ - case 4: - /* ADDI32, ADDIU32, ORI32, XORI32, SLTI32, SLTIU32, ANDI32, JALX32 */ - case 5: - /* LBU32, LHU32, POOL32F, JALS32, BEQ32, BNE32, J32, JAL32 */ - case 6: - /* SB32, SH32, ADDIUPC, SWC132, SDC132, SW32 */ - case 7: - /* LB32, LH32, LWC132, LDC132, LW32 */ - if (ctx->hflags & MIPS_HFLAG_BDS16) { - gen_reserved_instruction(ctx); - return 2; - } - break; - case 1: - /* POOL16A, POOL16B, POOL16C, LWGP16, POOL16F */ - case 2: - /* LBU16, LHU16, LWSP16, LW16, SB16, SH16, SWSP16, SW16 */ - case 3: - /* MOVE16, ANDI16, POOL16D, POOL16E, BEQZ16, BNEZ16, B16, LI16 */ - if (ctx->hflags & MIPS_HFLAG_BDS32) { - gen_reserved_instruction(ctx); - return 2; - } - break; - } - } - - switch (op) { - case POOL16A: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rs1 = mmreg(uMIPS_RS1(ctx->opcode)); - int rs2 = mmreg(uMIPS_RS2(ctx->opcode)); - uint32_t opc = 0; - - switch (ctx->opcode & 0x1) { - case ADDU16: - opc = OPC_ADDU; - break; - case SUBU16: - opc = OPC_SUBU; - break; - } - if (ctx->insn_flags & ISA_MIPS_R6) { - /* - * In the Release 6, the register number location in - * the instruction encoding has changed. - */ - gen_arith(ctx, opc, rs1, rd, rs2); - } else { - gen_arith(ctx, opc, rd, rs1, rs2); - } - } - break; - case POOL16B: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rs = mmreg(uMIPS_RS(ctx->opcode)); - int amount = (ctx->opcode >> 1) & 0x7; - uint32_t opc = 0; - amount = amount == 0 ? 8 : amount; - - switch (ctx->opcode & 0x1) { - case SLL16: - opc = OPC_SLL; - break; - case SRL16: - opc = OPC_SRL; - break; - } - - gen_shift_imm(ctx, opc, rd, rs, amount); - } - break; - case POOL16C: - if (ctx->insn_flags & ISA_MIPS_R6) { - gen_pool16c_r6_insn(ctx); - } else { - gen_pool16c_insn(ctx); - } - break; - case LWGP16: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rb = 28; /* GP */ - int16_t offset = SIMM(ctx->opcode, 0, 7) << 2; - - gen_ld(ctx, OPC_LW, rd, rb, offset); - } - break; - case POOL16F: - check_insn_opc_removed(ctx, ISA_MIPS_R6); - if (ctx->opcode & 1) { - gen_reserved_instruction(ctx); - } else { - /* MOVEP */ - int enc_dest = uMIPS_RD(ctx->opcode); - int enc_rt = uMIPS_RS2(ctx->opcode); - int enc_rs = uMIPS_RS1(ctx->opcode); - gen_movep(ctx, enc_dest, enc_rt, enc_rs); - } - break; - case LBU16: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4); - offset = (offset == 0xf ? -1 : offset); - - gen_ld(ctx, OPC_LBU, rd, rb, offset); - } - break; - case LHU16: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; - - gen_ld(ctx, OPC_LHU, rd, rb, offset); - } - break; - case LWSP16: - { - int rd = (ctx->opcode >> 5) & 0x1f; - int rb = 29; /* SP */ - int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; - - gen_ld(ctx, OPC_LW, rd, rb, offset); - } - break; - case LW16: - { - int rd = mmreg(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; - - gen_ld(ctx, OPC_LW, rd, rb, offset); - } - break; - case SB16: - { - int rd = mmreg2(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4); - - gen_st(ctx, OPC_SB, rd, rb, offset); - } - break; - case SH16: - { - int rd = mmreg2(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; - - gen_st(ctx, OPC_SH, rd, rb, offset); - } - break; - case SWSP16: - { - int rd = (ctx->opcode >> 5) & 0x1f; - int rb = 29; /* SP */ - int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; - - gen_st(ctx, OPC_SW, rd, rb, offset); - } - break; - case SW16: - { - int rd = mmreg2(uMIPS_RD(ctx->opcode)); - int rb = mmreg(uMIPS_RS(ctx->opcode)); - int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; - - gen_st(ctx, OPC_SW, rd, rb, offset); - } - break; - case MOVE16: - { - int rd = uMIPS_RD5(ctx->opcode); - int rs = uMIPS_RS5(ctx->opcode); - - gen_arith(ctx, OPC_ADDU, rd, rs, 0); - } - break; - case ANDI16: - gen_andi16(ctx); - break; - case POOL16D: - switch (ctx->opcode & 0x1) { - case ADDIUS5: - gen_addius5(ctx); - break; - case ADDIUSP: - gen_addiusp(ctx); - break; - } - break; - case POOL16E: - switch (ctx->opcode & 0x1) { - case ADDIUR2: - gen_addiur2(ctx); - break; - case ADDIUR1SP: - gen_addiur1sp(ctx); - break; - } - break; - case B16: /* BC16 */ - gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, - sextract32(ctx->opcode, 0, 10) << 1, - (ctx->insn_flags & ISA_MIPS_R6) ? 0 : 4); - break; - case BNEZ16: /* BNEZC16 */ - case BEQZ16: /* BEQZC16 */ - gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, - mmreg(uMIPS_RD(ctx->opcode)), - 0, sextract32(ctx->opcode, 0, 7) << 1, - (ctx->insn_flags & ISA_MIPS_R6) ? 0 : 4); - - break; - case LI16: - { - int reg = mmreg(uMIPS_RD(ctx->opcode)); - int imm = ZIMM(ctx->opcode, 0, 7); - - imm = (imm == 0x7f ? -1 : imm); - tcg_gen_movi_tl(cpu_gpr[reg], imm); - } - break; - case RES_29: - case RES_31: - case RES_39: - gen_reserved_instruction(ctx); - break; - default: - decode_micromips32_opc(env, ctx); - return 4; - } - - return 2; -} - -/* ISA extensions (ASEs) */ - -/* MIPS16 extension to MIPS32 */ -#include "mips16e_translate.c.inc" +#include "micromips_translate.c.inc" /* * @@ -24378,7 +21159,7 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) decode_opc(env, ctx); } else if (ctx->insn_flags & ASE_MICROMIPS) { ctx->opcode = translator_lduw(env, ctx->base.pc_next); - insn_bytes = decode_micromips_opc(env, ctx); + insn_bytes = decode_isa_micromips(env, ctx); } else if (ctx->insn_flags & ASE_MIPS16) { ctx->opcode = translator_lduw(env, ctx->base.pc_next); insn_bytes = decode_ase_mips16e(env, ctx); diff --git a/target/mips/tcg/micromips_translate.c.inc b/target/mips/tcg/micromips_translate.c.inc new file mode 100644 index 00000000000..5e95f478546 --- /dev/null +++ b/target/mips/tcg/micromips_translate.c.inc @@ -0,0 +1,3231 @@ +/* + * microMIPS translation routines + * + * Copyright (c) 2004-2005 Jocelyn Mayer + * Copyright (c) 2006 Marius Groeger (FPU operations) + * Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support) + * Copyright (c) 2009 CodeSourcery (MIPS16 and microMIPS support) + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +/* + * microMIPS32/microMIPS64 major opcodes + * + * 1. MIPS Architecture for Programmers Volume II-B: + * The microMIPS32 Instruction Set (Revision 3.05) + * + * Table 6.2 microMIPS32 Encoding of Major Opcode Field + * + * 2. MIPS Architecture For Programmers Volume II-A: + * The MIPS64 Instruction Set (Revision 3.51) + */ + +enum { + POOL32A = 0x00, + POOL16A = 0x01, + LBU16 = 0x02, + MOVE16 = 0x03, + ADDI32 = 0x04, + R6_LUI = 0x04, + AUI = 0x04, + LBU32 = 0x05, + SB32 = 0x06, + LB32 = 0x07, + + POOL32B = 0x08, + POOL16B = 0x09, + LHU16 = 0x0a, + ANDI16 = 0x0b, + ADDIU32 = 0x0c, + LHU32 = 0x0d, + SH32 = 0x0e, + LH32 = 0x0f, + + POOL32I = 0x10, + POOL16C = 0x11, + LWSP16 = 0x12, + POOL16D = 0x13, + ORI32 = 0x14, + POOL32F = 0x15, + POOL32S = 0x16, /* MIPS64 */ + DADDIU32 = 0x17, /* MIPS64 */ + + POOL32C = 0x18, + LWGP16 = 0x19, + LW16 = 0x1a, + POOL16E = 0x1b, + XORI32 = 0x1c, + JALS32 = 0x1d, + BOVC = 0x1d, + BEQC = 0x1d, + BEQZALC = 0x1d, + ADDIUPC = 0x1e, + PCREL = 0x1e, + BNVC = 0x1f, + BNEC = 0x1f, + BNEZALC = 0x1f, + + R6_BEQZC = 0x20, + JIC = 0x20, + POOL16F = 0x21, + SB16 = 0x22, + BEQZ16 = 0x23, + BEQZC16 = 0x23, + SLTI32 = 0x24, + BEQ32 = 0x25, + BC = 0x25, + SWC132 = 0x26, + LWC132 = 0x27, + + /* 0x29 is reserved */ + RES_29 = 0x29, + R6_BNEZC = 0x28, + JIALC = 0x28, + SH16 = 0x2a, + BNEZ16 = 0x2b, + BNEZC16 = 0x2b, + SLTIU32 = 0x2c, + BNE32 = 0x2d, + BALC = 0x2d, + SDC132 = 0x2e, + LDC132 = 0x2f, + + /* 0x31 is reserved */ + RES_31 = 0x31, + BLEZALC = 0x30, + BGEZALC = 0x30, + BGEUC = 0x30, + SWSP16 = 0x32, + B16 = 0x33, + BC16 = 0x33, + ANDI32 = 0x34, + J32 = 0x35, + BGTZC = 0x35, + BLTZC = 0x35, + BLTC = 0x35, + SD32 = 0x36, /* MIPS64 */ + LD32 = 0x37, /* MIPS64 */ + + /* 0x39 is reserved */ + RES_39 = 0x39, + BGTZALC = 0x38, + BLTZALC = 0x38, + BLTUC = 0x38, + SW16 = 0x3a, + LI16 = 0x3b, + JALX32 = 0x3c, + JAL32 = 0x3d, + BLEZC = 0x3d, + BGEZC = 0x3d, + BGEC = 0x3d, + SW32 = 0x3e, + LW32 = 0x3f +}; + +/* PCREL Instructions perform PC-Relative address calculation. bits 20..16 */ +enum { + ADDIUPC_00 = 0x00, + ADDIUPC_01 = 0x01, + ADDIUPC_02 = 0x02, + ADDIUPC_03 = 0x03, + ADDIUPC_04 = 0x04, + ADDIUPC_05 = 0x05, + ADDIUPC_06 = 0x06, + ADDIUPC_07 = 0x07, + AUIPC = 0x1e, + ALUIPC = 0x1f, + LWPC_08 = 0x08, + LWPC_09 = 0x09, + LWPC_0A = 0x0A, + LWPC_0B = 0x0B, + LWPC_0C = 0x0C, + LWPC_0D = 0x0D, + LWPC_0E = 0x0E, + LWPC_0F = 0x0F, +}; + +/* POOL32A encoding of minor opcode field */ + +enum { + /* + * These opcodes are distinguished only by bits 9..6; those bits are + * what are recorded below. + */ + SLL32 = 0x0, + SRL32 = 0x1, + SRA = 0x2, + ROTR = 0x3, + SELEQZ = 0x5, + SELNEZ = 0x6, + R6_RDHWR = 0x7, + + SLLV = 0x0, + SRLV = 0x1, + SRAV = 0x2, + ROTRV = 0x3, + ADD = 0x4, + ADDU32 = 0x5, + SUB = 0x6, + SUBU32 = 0x7, + MUL = 0x8, + AND = 0x9, + OR32 = 0xa, + NOR = 0xb, + XOR32 = 0xc, + SLT = 0xd, + SLTU = 0xe, + + MOVN = 0x0, + R6_MUL = 0x0, + MOVZ = 0x1, + MUH = 0x1, + MULU = 0x2, + MUHU = 0x3, + LWXS = 0x4, + R6_DIV = 0x4, + MOD = 0x5, + R6_DIVU = 0x6, + MODU = 0x7, + + /* The following can be distinguished by their lower 6 bits. */ + BREAK32 = 0x07, + INS = 0x0c, + LSA = 0x0f, + ALIGN = 0x1f, + EXT = 0x2c, + POOL32AXF = 0x3c, + SIGRIE = 0x3f +}; + +/* POOL32AXF encoding of minor opcode field extension */ + +/* + * 1. MIPS Architecture for Programmers Volume II-B: + * The microMIPS32 Instruction Set (Revision 3.05) + * + * Table 6.5 POOL32Axf Encoding of Minor Opcode Extension Field + * + * 2. MIPS Architecture for Programmers VolumeIV-e: + * The MIPS DSP Application-Specific Extension + * to the microMIPS32 Architecture (Revision 2.34) + * + * Table 5.5 POOL32Axf Encoding of Minor Opcode Extension Field + */ + +enum { + /* bits 11..6 */ + TEQ = 0x00, + TGE = 0x08, + TGEU = 0x10, + TLT = 0x20, + TLTU = 0x28, + TNE = 0x30, + + MFC0 = 0x03, + MTC0 = 0x0b, + + /* begin of microMIPS32 DSP */ + + /* bits 13..12 for 0x01 */ + MFHI_ACC = 0x0, + MFLO_ACC = 0x1, + MTHI_ACC = 0x2, + MTLO_ACC = 0x3, + + /* bits 13..12 for 0x2a */ + MADD_ACC = 0x0, + MADDU_ACC = 0x1, + MSUB_ACC = 0x2, + MSUBU_ACC = 0x3, + + /* bits 13..12 for 0x32 */ + MULT_ACC = 0x0, + MULTU_ACC = 0x1, + + /* end of microMIPS32 DSP */ + + /* bits 15..12 for 0x2c */ + BITSWAP = 0x0, + SEB = 0x2, + SEH = 0x3, + CLO = 0x4, + CLZ = 0x5, + RDHWR = 0x6, + WSBH = 0x7, + MULT = 0x8, + MULTU = 0x9, + DIV = 0xa, + DIVU = 0xb, + MADD = 0xc, + MADDU = 0xd, + MSUB = 0xe, + MSUBU = 0xf, + + /* bits 15..12 for 0x34 */ + MFC2 = 0x4, + MTC2 = 0x5, + MFHC2 = 0x8, + MTHC2 = 0x9, + CFC2 = 0xc, + CTC2 = 0xd, + + /* bits 15..12 for 0x3c */ + JALR = 0x0, + JR = 0x0, /* alias */ + JALRC = 0x0, + JRC = 0x0, + JALR_HB = 0x1, + JALRC_HB = 0x1, + JALRS = 0x4, + JALRS_HB = 0x5, + + /* bits 15..12 for 0x05 */ + RDPGPR = 0xe, + WRPGPR = 0xf, + + /* bits 15..12 for 0x0d */ + TLBP = 0x0, + TLBR = 0x1, + TLBWI = 0x2, + TLBWR = 0x3, + TLBINV = 0x4, + TLBINVF = 0x5, + WAIT = 0x9, + IRET = 0xd, + DERET = 0xe, + ERET = 0xf, + + /* bits 15..12 for 0x15 */ + DMT = 0x0, + DVPE = 0x1, + EMT = 0x2, + EVPE = 0x3, + + /* bits 15..12 for 0x1d */ + DI = 0x4, + EI = 0x5, + + /* bits 15..12 for 0x2d */ + SYNC = 0x6, + SYSCALL = 0x8, + SDBBP = 0xd, + + /* bits 15..12 for 0x35 */ + MFHI32 = 0x0, + MFLO32 = 0x1, + MTHI32 = 0x2, + MTLO32 = 0x3, +}; + +/* POOL32B encoding of minor opcode field (bits 15..12) */ + +enum { + LWC2 = 0x0, + LWP = 0x1, + LDP = 0x4, + LWM32 = 0x5, + CACHE = 0x6, + LDM = 0x7, + SWC2 = 0x8, + SWP = 0x9, + SDP = 0xc, + SWM32 = 0xd, + SDM = 0xf +}; + +/* POOL32C encoding of minor opcode field (bits 15..12) */ + +enum { + LWL = 0x0, + SWL = 0x8, + LWR = 0x1, + SWR = 0x9, + PREF = 0x2, + ST_EVA = 0xa, + LL = 0x3, + SC = 0xb, + LDL = 0x4, + SDL = 0xc, + LDR = 0x5, + SDR = 0xd, + LD_EVA = 0x6, + LWU = 0xe, + LLD = 0x7, + SCD = 0xf +}; + +/* POOL32C LD-EVA encoding of minor opcode field (bits 11..9) */ + +enum { + LBUE = 0x0, + LHUE = 0x1, + LWLE = 0x2, + LWRE = 0x3, + LBE = 0x4, + LHE = 0x5, + LLE = 0x6, + LWE = 0x7, +}; + +/* POOL32C ST-EVA encoding of minor opcode field (bits 11..9) */ + +enum { + SWLE = 0x0, + SWRE = 0x1, + PREFE = 0x2, + CACHEE = 0x3, + SBE = 0x4, + SHE = 0x5, + SCE = 0x6, + SWE = 0x7, +}; + +/* POOL32F encoding of minor opcode field (bits 5..0) */ + +enum { + /* These are the bit 7..6 values */ + ADD_FMT = 0x0, + + SUB_FMT = 0x1, + + MUL_FMT = 0x2, + + DIV_FMT = 0x3, + + /* These are the bit 8..6 values */ + MOVN_FMT = 0x0, + RSQRT2_FMT = 0x0, + MOVF_FMT = 0x0, + RINT_FMT = 0x0, + SELNEZ_FMT = 0x0, + + MOVZ_FMT = 0x1, + LWXC1 = 0x1, + MOVT_FMT = 0x1, + CLASS_FMT = 0x1, + SELEQZ_FMT = 0x1, + + PLL_PS = 0x2, + SWXC1 = 0x2, + SEL_FMT = 0x2, + + PLU_PS = 0x3, + LDXC1 = 0x3, + + MOVN_FMT_04 = 0x4, + PUL_PS = 0x4, + SDXC1 = 0x4, + RECIP2_FMT = 0x4, + + MOVZ_FMT_05 = 0x05, + PUU_PS = 0x5, + LUXC1 = 0x5, + + CVT_PS_S = 0x6, + SUXC1 = 0x6, + ADDR_PS = 0x6, + PREFX = 0x6, + MADDF_FMT = 0x6, + + MULR_PS = 0x7, + MSUBF_FMT = 0x7, + + MADD_S = 0x01, + MADD_D = 0x09, + MADD_PS = 0x11, + ALNV_PS = 0x19, + MSUB_S = 0x21, + MSUB_D = 0x29, + MSUB_PS = 0x31, + + NMADD_S = 0x02, + NMADD_D = 0x0a, + NMADD_PS = 0x12, + NMSUB_S = 0x22, + NMSUB_D = 0x2a, + NMSUB_PS = 0x32, + + MIN_FMT = 0x3, + MAX_FMT = 0xb, + MINA_FMT = 0x23, + MAXA_FMT = 0x2b, + POOL32FXF = 0x3b, + + CABS_COND_FMT = 0x1c, /* MIPS3D */ + C_COND_FMT = 0x3c, + + CMP_CONDN_S = 0x5, + CMP_CONDN_D = 0x15 +}; + +/* POOL32Fxf encoding of minor opcode extension field */ + +enum { + CVT_L = 0x04, + RSQRT_FMT = 0x08, + FLOOR_L = 0x0c, + CVT_PW_PS = 0x1c, + CVT_W = 0x24, + SQRT_FMT = 0x28, + FLOOR_W = 0x2c, + CVT_PS_PW = 0x3c, + CFC1 = 0x40, + RECIP_FMT = 0x48, + CEIL_L = 0x4c, + CTC1 = 0x60, + CEIL_W = 0x6c, + MFC1 = 0x80, + CVT_S_PL = 0x84, + TRUNC_L = 0x8c, + MTC1 = 0xa0, + CVT_S_PU = 0xa4, + TRUNC_W = 0xac, + MFHC1 = 0xc0, + ROUND_L = 0xcc, + MTHC1 = 0xe0, + ROUND_W = 0xec, + + MOV_FMT = 0x01, + MOVF = 0x05, + ABS_FMT = 0x0d, + RSQRT1_FMT = 0x1d, + MOVT = 0x25, + NEG_FMT = 0x2d, + CVT_D = 0x4d, + RECIP1_FMT = 0x5d, + CVT_S = 0x6d +}; + +/* POOL32I encoding of minor opcode field (bits 25..21) */ + +enum { + BLTZ = 0x00, + BLTZAL = 0x01, + BGEZ = 0x02, + BGEZAL = 0x03, + BLEZ = 0x04, + BNEZC = 0x05, + BGTZ = 0x06, + BEQZC = 0x07, + TLTI = 0x08, + BC1EQZC = 0x08, + TGEI = 0x09, + BC1NEZC = 0x09, + TLTIU = 0x0a, + BC2EQZC = 0x0a, + TGEIU = 0x0b, + BC2NEZC = 0x0a, + TNEI = 0x0c, + R6_SYNCI = 0x0c, + LUI = 0x0d, + TEQI = 0x0e, + SYNCI = 0x10, + BLTZALS = 0x11, + BGEZALS = 0x13, + BC2F = 0x14, + BC2T = 0x15, + /* These overlap and are distinguished by bit16 of the instruction */ + BC1F = 0x1c, + BC1T = 0x1d, + BC1ANY2F = 0x1c, + BC1ANY2T = 0x1d, + BC1ANY4F = 0x1e, + BC1ANY4T = 0x1f +}; + +/* POOL16A encoding of minor opcode field */ + +enum { + ADDU16 = 0x0, + SUBU16 = 0x1 +}; + +/* POOL16B encoding of minor opcode field */ + +enum { + SLL16 = 0x0, + SRL16 = 0x1 +}; + +/* POOL16C encoding of minor opcode field */ + +enum { + NOT16 = 0x00, + XOR16 = 0x04, + AND16 = 0x08, + OR16 = 0x0c, + LWM16 = 0x10, + SWM16 = 0x14, + JR16 = 0x18, + JRC16 = 0x1a, + JALR16 = 0x1c, + JALR16S = 0x1e, + MFHI16 = 0x20, + MFLO16 = 0x24, + BREAK16 = 0x28, + SDBBP16 = 0x2c, + JRADDIUSP = 0x30 +}; + +/* R6 POOL16C encoding of minor opcode field (bits 0..5) */ + +enum { + R6_NOT16 = 0x00, + R6_AND16 = 0x01, + R6_LWM16 = 0x02, + R6_JRC16 = 0x03, + MOVEP = 0x04, + MOVEP_05 = 0x05, + MOVEP_06 = 0x06, + MOVEP_07 = 0x07, + R6_XOR16 = 0x08, + R6_OR16 = 0x09, + R6_SWM16 = 0x0a, + JALRC16 = 0x0b, + MOVEP_0C = 0x0c, + MOVEP_0D = 0x0d, + MOVEP_0E = 0x0e, + MOVEP_0F = 0x0f, + JRCADDIUSP = 0x13, + R6_BREAK16 = 0x1b, + R6_SDBBP16 = 0x3b +}; + +/* POOL16D encoding of minor opcode field */ + +enum { + ADDIUS5 = 0x0, + ADDIUSP = 0x1 +}; + +/* POOL16E encoding of minor opcode field */ + +enum { + ADDIUR2 = 0x0, + ADDIUR1SP = 0x1 +}; + +static int mmreg(int r) +{ + static const int map[] = { 16, 17, 2, 3, 4, 5, 6, 7 }; + + return map[r]; +} + +/* Used for 16-bit store instructions. */ +static int mmreg2(int r) +{ + static const int map[] = { 0, 17, 2, 3, 4, 5, 6, 7 }; + + return map[r]; +} + +#define uMIPS_RD(op) ((op >> 7) & 0x7) +#define uMIPS_RS(op) ((op >> 4) & 0x7) +#define uMIPS_RS2(op) uMIPS_RS(op) +#define uMIPS_RS1(op) ((op >> 1) & 0x7) +#define uMIPS_RD5(op) ((op >> 5) & 0x1f) +#define uMIPS_RS5(op) (op & 0x1f) + +/* Signed immediate */ +#define SIMM(op, start, width) \ + ((int32_t)(((op >> start) & ((~0U) >> (32 - width))) \ + << (32 - width)) \ + >> (32 - width)) +/* Zero-extended immediate */ +#define ZIMM(op, start, width) ((op >> start) & ((~0U) >> (32 - width))) + +static void gen_addiur1sp(DisasContext *ctx) +{ + int rd = mmreg(uMIPS_RD(ctx->opcode)); + + gen_arith_imm(ctx, OPC_ADDIU, rd, 29, ((ctx->opcode >> 1) & 0x3f) << 2); +} + +static void gen_addiur2(DisasContext *ctx) +{ + static const int decoded_imm[] = { 1, 4, 8, 12, 16, 20, 24, -1 }; + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs = mmreg(uMIPS_RS(ctx->opcode)); + + gen_arith_imm(ctx, OPC_ADDIU, rd, rs, decoded_imm[ZIMM(ctx->opcode, 1, 3)]); +} + +static void gen_addiusp(DisasContext *ctx) +{ + int encoded = ZIMM(ctx->opcode, 1, 9); + int decoded; + + if (encoded <= 1) { + decoded = 256 + encoded; + } else if (encoded <= 255) { + decoded = encoded; + } else if (encoded <= 509) { + decoded = encoded - 512; + } else { + decoded = encoded - 768; + } + + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, decoded << 2); +} + +static void gen_addius5(DisasContext *ctx) +{ + int imm = SIMM(ctx->opcode, 1, 4); + int rd = (ctx->opcode >> 5) & 0x1f; + + gen_arith_imm(ctx, OPC_ADDIU, rd, rd, imm); +} + +static void gen_andi16(DisasContext *ctx) +{ + static const int decoded_imm[] = { 128, 1, 2, 3, 4, 7, 8, 15, 16, + 31, 32, 63, 64, 255, 32768, 65535 }; + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs = mmreg(uMIPS_RS(ctx->opcode)); + int encoded = ZIMM(ctx->opcode, 0, 4); + + gen_logic_imm(ctx, OPC_ANDI, rd, rs, decoded_imm[encoded]); +} + +static void gen_ldst_multiple(DisasContext *ctx, uint32_t opc, int reglist, + int base, int16_t offset) +{ + TCGv t0, t1; + TCGv_i32 t2; + + if (ctx->hflags & MIPS_HFLAG_BMASK) { + gen_reserved_instruction(ctx); + return; + } + + t0 = tcg_temp_new(); + + gen_base_offset_addr(ctx, t0, base, offset); + + t1 = tcg_const_tl(reglist); + t2 = tcg_const_i32(ctx->mem_idx); + + save_cpu_state(ctx, 1); + switch (opc) { + case LWM32: + gen_helper_lwm(cpu_env, t0, t1, t2); + break; + case SWM32: + gen_helper_swm(cpu_env, t0, t1, t2); + break; +#ifdef TARGET_MIPS64 + case LDM: + gen_helper_ldm(cpu_env, t0, t1, t2); + break; + case SDM: + gen_helper_sdm(cpu_env, t0, t1, t2); + break; +#endif + } + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free_i32(t2); +} + + +static void gen_pool16c_insn(DisasContext *ctx) +{ + int rd = mmreg((ctx->opcode >> 3) & 0x7); + int rs = mmreg(ctx->opcode & 0x7); + + switch (((ctx->opcode) >> 4) & 0x3f) { + case NOT16 + 0: + case NOT16 + 1: + case NOT16 + 2: + case NOT16 + 3: + gen_logic(ctx, OPC_NOR, rd, rs, 0); + break; + case XOR16 + 0: + case XOR16 + 1: + case XOR16 + 2: + case XOR16 + 3: + gen_logic(ctx, OPC_XOR, rd, rd, rs); + break; + case AND16 + 0: + case AND16 + 1: + case AND16 + 2: + case AND16 + 3: + gen_logic(ctx, OPC_AND, rd, rd, rs); + break; + case OR16 + 0: + case OR16 + 1: + case OR16 + 2: + case OR16 + 3: + gen_logic(ctx, OPC_OR, rd, rd, rs); + break; + case LWM16 + 0: + case LWM16 + 1: + case LWM16 + 2: + case LWM16 + 3: + { + static const int lwm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; + int offset = ZIMM(ctx->opcode, 0, 4); + + gen_ldst_multiple(ctx, LWM32, lwm_convert[(ctx->opcode >> 4) & 0x3], + 29, offset << 2); + } + break; + case SWM16 + 0: + case SWM16 + 1: + case SWM16 + 2: + case SWM16 + 3: + { + static const int swm_convert[] = { 0x11, 0x12, 0x13, 0x14 }; + int offset = ZIMM(ctx->opcode, 0, 4); + + gen_ldst_multiple(ctx, SWM32, swm_convert[(ctx->opcode >> 4) & 0x3], + 29, offset << 2); + } + break; + case JR16 + 0: + case JR16 + 1: + { + int reg = ctx->opcode & 0x1f; + + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 4); + } + break; + case JRC16 + 0: + case JRC16 + 1: + { + int reg = ctx->opcode & 0x1f; + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0); + /* + * Let normal delay slot handling in our caller take us + * to the branch target. + */ + } + break; + case JALR16 + 0: + case JALR16 + 1: + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case JALR16S + 0: + case JALR16S + 1: + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case MFHI16 + 0: + case MFHI16 + 1: + gen_HILO(ctx, OPC_MFHI, 0, uMIPS_RS5(ctx->opcode)); + break; + case MFLO16 + 0: + case MFLO16 + 1: + gen_HILO(ctx, OPC_MFLO, 0, uMIPS_RS5(ctx->opcode)); + break; + case BREAK16: + generate_exception_end(ctx, EXCP_BREAK); + break; + case SDBBP16: + if (is_uhi(extract32(ctx->opcode, 0, 4))) { + gen_helper_do_semihosting(cpu_env); + } else { + /* + * XXX: not clear which exception should be raised + * when in debug mode... + */ + check_insn(ctx, ISA_MIPS_R1); + generate_exception_end(ctx, EXCP_DBp); + } + break; + case JRADDIUSP + 0: + case JRADDIUSP + 1: + { + int imm = ZIMM(ctx->opcode, 0, 5); + gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); + /* + * Let normal delay slot handling in our caller take us + * to the branch target. + */ + } + break; + default: + gen_reserved_instruction(ctx); + break; + } +} + +static inline void gen_movep(DisasContext *ctx, int enc_dest, int enc_rt, + int enc_rs) +{ + int rd, re; + static const int rd_enc[] = { 5, 5, 6, 4, 4, 4, 4, 4 }; + static const int re_enc[] = { 6, 7, 7, 21, 22, 5, 6, 7 }; + static const int rs_rt_enc[] = { 0, 17, 2, 3, 16, 18, 19, 20 }; + + rd = rd_enc[enc_dest]; + re = re_enc[enc_dest]; + gen_load_gpr(cpu_gpr[rd], rs_rt_enc[enc_rs]); + gen_load_gpr(cpu_gpr[re], rs_rt_enc[enc_rt]); +} + +static void gen_pool16c_r6_insn(DisasContext *ctx) +{ + int rt = mmreg((ctx->opcode >> 7) & 0x7); + int rs = mmreg((ctx->opcode >> 4) & 0x7); + + switch (ctx->opcode & 0xf) { + case R6_NOT16: + gen_logic(ctx, OPC_NOR, rt, rs, 0); + break; + case R6_AND16: + gen_logic(ctx, OPC_AND, rt, rt, rs); + break; + case R6_LWM16: + { + int lwm_converted = 0x11 + extract32(ctx->opcode, 8, 2); + int offset = extract32(ctx->opcode, 4, 4); + gen_ldst_multiple(ctx, LWM32, lwm_converted, 29, offset << 2); + } + break; + case R6_JRC16: /* JRCADDIUSP */ + if ((ctx->opcode >> 4) & 1) { + /* JRCADDIUSP */ + int imm = extract32(ctx->opcode, 5, 5); + gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); + gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); + } else { + /* JRC16 */ + rs = extract32(ctx->opcode, 5, 5); + gen_compute_branch(ctx, OPC_JR, 2, rs, 0, 0, 0); + } + break; + case MOVEP: + case MOVEP_05: + case MOVEP_06: + case MOVEP_07: + case MOVEP_0C: + case MOVEP_0D: + case MOVEP_0E: + case MOVEP_0F: + { + int enc_dest = uMIPS_RD(ctx->opcode); + int enc_rt = uMIPS_RS2(ctx->opcode); + int enc_rs = (ctx->opcode & 3) | ((ctx->opcode >> 1) & 4); + gen_movep(ctx, enc_dest, enc_rt, enc_rs); + } + break; + case R6_XOR16: + gen_logic(ctx, OPC_XOR, rt, rt, rs); + break; + case R6_OR16: + gen_logic(ctx, OPC_OR, rt, rt, rs); + break; + case R6_SWM16: + { + int swm_converted = 0x11 + extract32(ctx->opcode, 8, 2); + int offset = extract32(ctx->opcode, 4, 4); + gen_ldst_multiple(ctx, SWM32, swm_converted, 29, offset << 2); + } + break; + case JALRC16: /* BREAK16, SDBBP16 */ + switch (ctx->opcode & 0x3f) { + case JALRC16: + case JALRC16 + 0x20: + /* JALRC16 */ + gen_compute_branch(ctx, OPC_JALR, 2, (ctx->opcode >> 5) & 0x1f, + 31, 0, 0); + break; + case R6_BREAK16: + /* BREAK16 */ + generate_exception(ctx, EXCP_BREAK); + break; + case R6_SDBBP16: + /* SDBBP16 */ + if (is_uhi(extract32(ctx->opcode, 6, 4))) { + gen_helper_do_semihosting(cpu_env); + } else { + if (ctx->hflags & MIPS_HFLAG_SBRI) { + generate_exception(ctx, EXCP_RI); + } else { + generate_exception(ctx, EXCP_DBp); + } + } + break; + } + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } +} + +static void gen_ldst_pair(DisasContext *ctx, uint32_t opc, int rd, + int base, int16_t offset) +{ + TCGv t0, t1; + + if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31) { + gen_reserved_instruction(ctx); + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_base_offset_addr(ctx, t0, base, offset); + + switch (opc) { + case LWP: + if (rd == base) { + gen_reserved_instruction(ctx); + return; + } + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); + gen_store_gpr(t1, rd); + tcg_gen_movi_tl(t1, 4); + gen_op_addr_add(ctx, t0, t0, t1); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TESL); + gen_store_gpr(t1, rd + 1); + break; + case SWP: + gen_load_gpr(t1, rd); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + tcg_gen_movi_tl(t1, 4); + gen_op_addr_add(ctx, t0, t0, t1); + gen_load_gpr(t1, rd + 1); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL); + break; +#ifdef TARGET_MIPS64 + case LDP: + if (rd == base) { + gen_reserved_instruction(ctx); + return; + } + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ); + gen_store_gpr(t1, rd); + tcg_gen_movi_tl(t1, 8); + gen_op_addr_add(ctx, t0, t0, t1); + tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ); + gen_store_gpr(t1, rd + 1); + break; + case SDP: + gen_load_gpr(t1, rd); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); + tcg_gen_movi_tl(t1, 8); + gen_op_addr_add(ctx, t0, t0, t1); + gen_load_gpr(t1, rd + 1); + tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ); + break; +#endif + } + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +static void gen_pool32axf(CPUMIPSState *env, DisasContext *ctx, int rt, int rs) +{ + int extension = (ctx->opcode >> 6) & 0x3f; + int minor = (ctx->opcode >> 12) & 0xf; + uint32_t mips32_op; + + switch (extension) { + case TEQ: + mips32_op = OPC_TEQ; + goto do_trap; + case TGE: + mips32_op = OPC_TGE; + goto do_trap; + case TGEU: + mips32_op = OPC_TGEU; + goto do_trap; + case TLT: + mips32_op = OPC_TLT; + goto do_trap; + case TLTU: + mips32_op = OPC_TLTU; + goto do_trap; + case TNE: + mips32_op = OPC_TNE; + do_trap: + gen_trap(ctx, mips32_op, rs, rt, -1); + break; +#ifndef CONFIG_USER_ONLY + case MFC0: + case MFC0 + 32: + check_cp0_enabled(ctx); + if (rt == 0) { + /* Treat as NOP. */ + break; + } + gen_mfc0(ctx, cpu_gpr[rt], rs, (ctx->opcode >> 11) & 0x7); + break; + case MTC0: + case MTC0 + 32: + check_cp0_enabled(ctx); + { + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, rt); + gen_mtc0(ctx, t0, rs, (ctx->opcode >> 11) & 0x7); + tcg_temp_free(t0); + } + break; +#endif + case 0x2a: + switch (minor & 3) { + case MADD_ACC: + gen_muldiv(ctx, OPC_MADD, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MADDU_ACC: + gen_muldiv(ctx, OPC_MADDU, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MSUB_ACC: + gen_muldiv(ctx, OPC_MSUB, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MSUBU_ACC: + gen_muldiv(ctx, OPC_MSUBU, (ctx->opcode >> 14) & 3, rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x32: + switch (minor & 3) { + case MULT_ACC: + gen_muldiv(ctx, OPC_MULT, (ctx->opcode >> 14) & 3, rs, rt); + break; + case MULTU_ACC: + gen_muldiv(ctx, OPC_MULTU, (ctx->opcode >> 14) & 3, rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x2c: + switch (minor) { + case BITSWAP: + check_insn(ctx, ISA_MIPS_R6); + gen_bitswap(ctx, OPC_BITSWAP, rs, rt); + break; + case SEB: + gen_bshfl(ctx, OPC_SEB, rs, rt); + break; + case SEH: + gen_bshfl(ctx, OPC_SEH, rs, rt); + break; + case CLO: + mips32_op = OPC_CLO; + goto do_cl; + case CLZ: + mips32_op = OPC_CLZ; + do_cl: + check_insn(ctx, ISA_MIPS_R1); + gen_cl(ctx, mips32_op, rt, rs); + break; + case RDHWR: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_rdhwr(ctx, rt, rs, 0); + break; + case WSBH: + gen_bshfl(ctx, OPC_WSBH, rs, rt); + break; + case MULT: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MULT; + goto do_mul; + case MULTU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MULTU; + goto do_mul; + case DIV: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_DIV; + goto do_div; + case DIVU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_DIVU; + goto do_div; + do_div: + check_insn(ctx, ISA_MIPS_R1); + gen_muldiv(ctx, mips32_op, 0, rs, rt); + break; + case MADD: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADD; + goto do_mul; + case MADDU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADDU; + goto do_mul; + case MSUB: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUB; + goto do_mul; + case MSUBU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUBU; + do_mul: + check_insn(ctx, ISA_MIPS_R1); + gen_muldiv(ctx, mips32_op, 0, rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x34: + switch (minor) { + case MFC2: + case MTC2: + case MFHC2: + case MTHC2: + case CFC2: + case CTC2: + generate_exception_err(ctx, EXCP_CpU, 2); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x3c: + switch (minor) { + case JALR: /* JALRC */ + case JALR_HB: /* JALRC_HB */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* JALRC, JALRC_HB */ + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 0); + } else { + /* JALR, JALR_HB */ + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + } + break; + case JALRS: + case JALRS_HB: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + default: + goto pool32axf_invalid; + } + break; + case 0x05: + switch (minor) { + case RDPGPR: + check_cp0_enabled(ctx); + check_insn(ctx, ISA_MIPS_R2); + gen_load_srsgpr(rs, rt); + break; + case WRPGPR: + check_cp0_enabled(ctx); + check_insn(ctx, ISA_MIPS_R2); + gen_store_srsgpr(rs, rt); + break; + default: + goto pool32axf_invalid; + } + break; +#ifndef CONFIG_USER_ONLY + case 0x0d: + switch (minor) { + case TLBP: + mips32_op = OPC_TLBP; + goto do_cp0; + case TLBR: + mips32_op = OPC_TLBR; + goto do_cp0; + case TLBWI: + mips32_op = OPC_TLBWI; + goto do_cp0; + case TLBWR: + mips32_op = OPC_TLBWR; + goto do_cp0; + case TLBINV: + mips32_op = OPC_TLBINV; + goto do_cp0; + case TLBINVF: + mips32_op = OPC_TLBINVF; + goto do_cp0; + case WAIT: + mips32_op = OPC_WAIT; + goto do_cp0; + case DERET: + mips32_op = OPC_DERET; + goto do_cp0; + case ERET: + mips32_op = OPC_ERET; + do_cp0: + gen_cp0(env, ctx, mips32_op, rt, rs); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x1d: + switch (minor) { + case DI: + check_cp0_enabled(ctx); + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_helper_di(t0, cpu_env); + gen_store_gpr(t0, rs); + /* + * Stop translation as we may have switched the execution + * mode. + */ + ctx->base.is_jmp = DISAS_STOP; + tcg_temp_free(t0); + } + break; + case EI: + check_cp0_enabled(ctx); + { + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); + gen_helper_ei(t0, cpu_env); + gen_store_gpr(t0, rs); + /* + * DISAS_STOP isn't sufficient, we need to ensure we break out + * of translated code to check for pending interrupts. + */ + gen_save_pc(ctx->base.pc_next + 4); + ctx->base.is_jmp = DISAS_EXIT; + tcg_temp_free(t0); + } + break; + default: + goto pool32axf_invalid; + } + break; +#endif + case 0x2d: + switch (minor) { + case SYNC: + gen_sync(extract32(ctx->opcode, 16, 5)); + break; + case SYSCALL: + generate_exception_end(ctx, EXCP_SYSCALL); + break; + case SDBBP: + if (is_uhi(extract32(ctx->opcode, 16, 10))) { + gen_helper_do_semihosting(cpu_env); + } else { + check_insn(ctx, ISA_MIPS_R1); + if (ctx->hflags & MIPS_HFLAG_SBRI) { + gen_reserved_instruction(ctx); + } else { + generate_exception_end(ctx, EXCP_DBp); + } + } + break; + default: + goto pool32axf_invalid; + } + break; + case 0x01: + switch (minor & 3) { + case MFHI_ACC: + gen_HILO(ctx, OPC_MFHI, minor >> 2, rs); + break; + case MFLO_ACC: + gen_HILO(ctx, OPC_MFLO, minor >> 2, rs); + break; + case MTHI_ACC: + gen_HILO(ctx, OPC_MTHI, minor >> 2, rs); + break; + case MTLO_ACC: + gen_HILO(ctx, OPC_MTLO, minor >> 2, rs); + break; + default: + goto pool32axf_invalid; + } + break; + case 0x35: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + switch (minor) { + case MFHI32: + gen_HILO(ctx, OPC_MFHI, 0, rs); + break; + case MFLO32: + gen_HILO(ctx, OPC_MFLO, 0, rs); + break; + case MTHI32: + gen_HILO(ctx, OPC_MTHI, 0, rs); + break; + case MTLO32: + gen_HILO(ctx, OPC_MTLO, 0, rs); + break; + default: + goto pool32axf_invalid; + } + break; + default: + pool32axf_invalid: + MIPS_INVAL("pool32axf"); + gen_reserved_instruction(ctx); + break; + } +} + +static void gen_pool32fxf(DisasContext *ctx, int rt, int rs) +{ + int extension = (ctx->opcode >> 6) & 0x3ff; + uint32_t mips32_op; + +#define FLOAT_1BIT_FMT(opc, fmt) ((fmt << 8) | opc) +#define FLOAT_2BIT_FMT(opc, fmt) ((fmt << 7) | opc) +#define COND_FLOAT_MOV(opc, cond) ((cond << 7) | opc) + + switch (extension) { + case FLOAT_1BIT_FMT(CFC1, 0): + mips32_op = OPC_CFC1; + goto do_cp1; + case FLOAT_1BIT_FMT(CTC1, 0): + mips32_op = OPC_CTC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MFC1, 0): + mips32_op = OPC_MFC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MTC1, 0): + mips32_op = OPC_MTC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MFHC1, 0): + mips32_op = OPC_MFHC1; + goto do_cp1; + case FLOAT_1BIT_FMT(MTHC1, 0): + mips32_op = OPC_MTHC1; + do_cp1: + gen_cp1(ctx, mips32_op, rt, rs); + break; + + /* Reciprocal square root */ + case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_S): + mips32_op = OPC_RSQRT_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(RSQRT_FMT, FMT_SD_D): + mips32_op = OPC_RSQRT_D; + goto do_unaryfp; + + /* Square root */ + case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_S): + mips32_op = OPC_SQRT_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(SQRT_FMT, FMT_SD_D): + mips32_op = OPC_SQRT_D; + goto do_unaryfp; + + /* Reciprocal */ + case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_S): + mips32_op = OPC_RECIP_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(RECIP_FMT, FMT_SD_D): + mips32_op = OPC_RECIP_D; + goto do_unaryfp; + + /* Floor */ + case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_S): + mips32_op = OPC_FLOOR_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(FLOOR_L, FMT_SD_D): + mips32_op = OPC_FLOOR_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_S): + mips32_op = OPC_FLOOR_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(FLOOR_W, FMT_SD_D): + mips32_op = OPC_FLOOR_W_D; + goto do_unaryfp; + + /* Ceiling */ + case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_S): + mips32_op = OPC_CEIL_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CEIL_L, FMT_SD_D): + mips32_op = OPC_CEIL_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_S): + mips32_op = OPC_CEIL_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CEIL_W, FMT_SD_D): + mips32_op = OPC_CEIL_W_D; + goto do_unaryfp; + + /* Truncation */ + case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_S): + mips32_op = OPC_TRUNC_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(TRUNC_L, FMT_SD_D): + mips32_op = OPC_TRUNC_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_S): + mips32_op = OPC_TRUNC_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(TRUNC_W, FMT_SD_D): + mips32_op = OPC_TRUNC_W_D; + goto do_unaryfp; + + /* Round */ + case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_S): + mips32_op = OPC_ROUND_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(ROUND_L, FMT_SD_D): + mips32_op = OPC_ROUND_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_S): + mips32_op = OPC_ROUND_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(ROUND_W, FMT_SD_D): + mips32_op = OPC_ROUND_W_D; + goto do_unaryfp; + + /* Integer to floating-point conversion */ + case FLOAT_1BIT_FMT(CVT_L, FMT_SD_S): + mips32_op = OPC_CVT_L_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_L, FMT_SD_D): + mips32_op = OPC_CVT_L_D; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_W, FMT_SD_S): + mips32_op = OPC_CVT_W_S; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_W, FMT_SD_D): + mips32_op = OPC_CVT_W_D; + goto do_unaryfp; + + /* Paired-foo conversions */ + case FLOAT_1BIT_FMT(CVT_S_PL, 0): + mips32_op = OPC_CVT_S_PL; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_S_PU, 0): + mips32_op = OPC_CVT_S_PU; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_PW_PS, 0): + mips32_op = OPC_CVT_PW_PS; + goto do_unaryfp; + case FLOAT_1BIT_FMT(CVT_PS_PW, 0): + mips32_op = OPC_CVT_PS_PW; + goto do_unaryfp; + + /* Floating-point moves */ + case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_S): + mips32_op = OPC_MOV_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_D): + mips32_op = OPC_MOV_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(MOV_FMT, FMT_SDPS_PS): + mips32_op = OPC_MOV_PS; + goto do_unaryfp; + + /* Absolute value */ + case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_S): + mips32_op = OPC_ABS_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_D): + mips32_op = OPC_ABS_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(ABS_FMT, FMT_SDPS_PS): + mips32_op = OPC_ABS_PS; + goto do_unaryfp; + + /* Negation */ + case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_S): + mips32_op = OPC_NEG_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_D): + mips32_op = OPC_NEG_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(NEG_FMT, FMT_SDPS_PS): + mips32_op = OPC_NEG_PS; + goto do_unaryfp; + + /* Reciprocal square root step */ + case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_S): + mips32_op = OPC_RSQRT1_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_D): + mips32_op = OPC_RSQRT1_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RSQRT1_FMT, FMT_SDPS_PS): + mips32_op = OPC_RSQRT1_PS; + goto do_unaryfp; + + /* Reciprocal step */ + case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_S): + mips32_op = OPC_RECIP1_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_D): + mips32_op = OPC_RECIP1_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(RECIP1_FMT, FMT_SDPS_PS): + mips32_op = OPC_RECIP1_PS; + goto do_unaryfp; + + /* Conversions from double */ + case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_S): + mips32_op = OPC_CVT_D_S; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_W): + mips32_op = OPC_CVT_D_W; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_D, FMT_SWL_L): + mips32_op = OPC_CVT_D_L; + goto do_unaryfp; + + /* Conversions from single */ + case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_D): + mips32_op = OPC_CVT_S_D; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_W): + mips32_op = OPC_CVT_S_W; + goto do_unaryfp; + case FLOAT_2BIT_FMT(CVT_S, FMT_DWL_L): + mips32_op = OPC_CVT_S_L; + do_unaryfp: + gen_farith(ctx, mips32_op, -1, rs, rt, 0); + break; + + /* Conditional moves on floating-point codes */ + case COND_FLOAT_MOV(MOVT, 0): + case COND_FLOAT_MOV(MOVT, 1): + case COND_FLOAT_MOV(MOVT, 2): + case COND_FLOAT_MOV(MOVT, 3): + case COND_FLOAT_MOV(MOVT, 4): + case COND_FLOAT_MOV(MOVT, 5): + case COND_FLOAT_MOV(MOVT, 6): + case COND_FLOAT_MOV(MOVT, 7): + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 1); + break; + case COND_FLOAT_MOV(MOVF, 0): + case COND_FLOAT_MOV(MOVF, 1): + case COND_FLOAT_MOV(MOVF, 2): + case COND_FLOAT_MOV(MOVF, 3): + case COND_FLOAT_MOV(MOVF, 4): + case COND_FLOAT_MOV(MOVF, 5): + case COND_FLOAT_MOV(MOVF, 6): + case COND_FLOAT_MOV(MOVF, 7): + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_movci(ctx, rt, rs, (ctx->opcode >> 13) & 0x7, 0); + break; + default: + MIPS_INVAL("pool32fxf"); + gen_reserved_instruction(ctx); + break; + } +} + +static void decode_micromips32_opc(CPUMIPSState *env, DisasContext *ctx) +{ + int32_t offset; + uint16_t insn; + int rt, rs, rd, rr; + int16_t imm; + uint32_t op, minor, minor2, mips32_op; + uint32_t cond, fmt, cc; + + insn = translator_lduw(env, ctx->base.pc_next + 2); + ctx->opcode = (ctx->opcode << 16) | insn; + + rt = (ctx->opcode >> 21) & 0x1f; + rs = (ctx->opcode >> 16) & 0x1f; + rd = (ctx->opcode >> 11) & 0x1f; + rr = (ctx->opcode >> 6) & 0x1f; + imm = (int16_t) ctx->opcode; + + op = (ctx->opcode >> 26) & 0x3f; + switch (op) { + case POOL32A: + minor = ctx->opcode & 0x3f; + switch (minor) { + case 0x00: + minor = (ctx->opcode >> 6) & 0xf; + switch (minor) { + case SLL32: + mips32_op = OPC_SLL; + goto do_shifti; + case SRA: + mips32_op = OPC_SRA; + goto do_shifti; + case SRL32: + mips32_op = OPC_SRL; + goto do_shifti; + case ROTR: + mips32_op = OPC_ROTR; + do_shifti: + gen_shift_imm(ctx, mips32_op, rt, rs, rd); + break; + case SELEQZ: + check_insn(ctx, ISA_MIPS_R6); + gen_cond_move(ctx, OPC_SELEQZ, rd, rs, rt); + break; + case SELNEZ: + check_insn(ctx, ISA_MIPS_R6); + gen_cond_move(ctx, OPC_SELNEZ, rd, rs, rt); + break; + case R6_RDHWR: + check_insn(ctx, ISA_MIPS_R6); + gen_rdhwr(ctx, rt, rs, extract32(ctx->opcode, 11, 3)); + break; + default: + goto pool32a_invalid; + } + break; + case 0x10: + minor = (ctx->opcode >> 6) & 0xf; + switch (minor) { + /* Arithmetic */ + case ADD: + mips32_op = OPC_ADD; + goto do_arith; + case ADDU32: + mips32_op = OPC_ADDU; + goto do_arith; + case SUB: + mips32_op = OPC_SUB; + goto do_arith; + case SUBU32: + mips32_op = OPC_SUBU; + goto do_arith; + case MUL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MUL; + do_arith: + gen_arith(ctx, mips32_op, rd, rs, rt); + break; + /* Shifts */ + case SLLV: + mips32_op = OPC_SLLV; + goto do_shift; + case SRLV: + mips32_op = OPC_SRLV; + goto do_shift; + case SRAV: + mips32_op = OPC_SRAV; + goto do_shift; + case ROTRV: + mips32_op = OPC_ROTRV; + do_shift: + gen_shift(ctx, mips32_op, rd, rs, rt); + break; + /* Logical operations */ + case AND: + mips32_op = OPC_AND; + goto do_logic; + case OR32: + mips32_op = OPC_OR; + goto do_logic; + case NOR: + mips32_op = OPC_NOR; + goto do_logic; + case XOR32: + mips32_op = OPC_XOR; + do_logic: + gen_logic(ctx, mips32_op, rd, rs, rt); + break; + /* Set less than */ + case SLT: + mips32_op = OPC_SLT; + goto do_slt; + case SLTU: + mips32_op = OPC_SLTU; + do_slt: + gen_slt(ctx, mips32_op, rd, rs, rt); + break; + default: + goto pool32a_invalid; + } + break; + case 0x18: + minor = (ctx->opcode >> 6) & 0xf; + switch (minor) { + /* Conditional moves */ + case MOVN: /* MUL */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* MUL */ + gen_r6_muldiv(ctx, R6_OPC_MUL, rd, rs, rt); + } else { + /* MOVN */ + gen_cond_move(ctx, OPC_MOVN, rd, rs, rt); + } + break; + case MOVZ: /* MUH */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* MUH */ + gen_r6_muldiv(ctx, R6_OPC_MUH, rd, rs, rt); + } else { + /* MOVZ */ + gen_cond_move(ctx, OPC_MOVZ, rd, rs, rt); + } + break; + case MULU: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_MULU, rd, rs, rt); + break; + case MUHU: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_MUHU, rd, rs, rt); + break; + case LWXS: /* DIV */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* DIV */ + gen_r6_muldiv(ctx, R6_OPC_DIV, rd, rs, rt); + } else { + /* LWXS */ + gen_ldxs(ctx, rs, rt, rd); + } + break; + case MOD: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_MOD, rd, rs, rt); + break; + case R6_DIVU: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_DIVU, rd, rs, rt); + break; + case MODU: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_muldiv(ctx, R6_OPC_MODU, rd, rs, rt); + break; + default: + goto pool32a_invalid; + } + break; + case INS: + gen_bitops(ctx, OPC_INS, rt, rs, rr, rd); + return; + case LSA: + check_insn(ctx, ISA_MIPS_R6); + gen_lsa(ctx, rd, rt, rs, extract32(ctx->opcode, 9, 2)); + break; + case ALIGN: + check_insn(ctx, ISA_MIPS_R6); + gen_align(ctx, 32, rd, rs, rt, extract32(ctx->opcode, 9, 2)); + break; + case EXT: + gen_bitops(ctx, OPC_EXT, rt, rs, rr, rd); + return; + case POOL32AXF: + gen_pool32axf(env, ctx, rt, rs); + break; + case BREAK32: + generate_exception_end(ctx, EXCP_BREAK); + break; + case SIGRIE: + check_insn(ctx, ISA_MIPS_R6); + gen_reserved_instruction(ctx); + break; + default: + pool32a_invalid: + MIPS_INVAL("pool32a"); + gen_reserved_instruction(ctx); + break; + } + break; + case POOL32B: + minor = (ctx->opcode >> 12) & 0xf; + switch (minor) { + case CACHE: + check_cp0_enabled(ctx); + if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { + gen_cache_operation(ctx, rt, rs, imm); + } + break; + case LWC2: + case SWC2: + /* COP2: Not implemented. */ + generate_exception_err(ctx, EXCP_CpU, 2); + break; +#ifdef TARGET_MIPS64 + case LDP: + case SDP: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); +#endif + /* fall through */ + case LWP: + case SWP: + gen_ldst_pair(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; +#ifdef TARGET_MIPS64 + case LDM: + case SDM: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); +#endif + /* fall through */ + case LWM32: + case SWM32: + gen_ldst_multiple(ctx, minor, rt, rs, SIMM(ctx->opcode, 0, 12)); + break; + default: + MIPS_INVAL("pool32b"); + gen_reserved_instruction(ctx); + break; + } + break; + case POOL32F: + if (ctx->CP0_Config1 & (1 << CP0C1_FP)) { + minor = ctx->opcode & 0x3f; + check_cp1_enabled(ctx); + switch (minor) { + case ALNV_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_ALNV_PS; + goto do_madd; + case MADD_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADD_S; + goto do_madd; + case MADD_D: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADD_D; + goto do_madd; + case MADD_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MADD_PS; + goto do_madd; + case MSUB_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUB_S; + goto do_madd; + case MSUB_D: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUB_D; + goto do_madd; + case MSUB_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_MSUB_PS; + goto do_madd; + case NMADD_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMADD_S; + goto do_madd; + case NMADD_D: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMADD_D; + goto do_madd; + case NMADD_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMADD_PS; + goto do_madd; + case NMSUB_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMSUB_S; + goto do_madd; + case NMSUB_D: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMSUB_D; + goto do_madd; + case NMSUB_PS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_NMSUB_PS; + do_madd: + gen_flt3_arith(ctx, mips32_op, rd, rr, rs, rt); + break; + case CABS_COND_FMT: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + cond = (ctx->opcode >> 6) & 0xf; + cc = (ctx->opcode >> 13) & 0x7; + fmt = (ctx->opcode >> 10) & 0x3; + switch (fmt) { + case 0x0: + gen_cmpabs_s(ctx, cond, rt, rs, cc); + break; + case 0x1: + gen_cmpabs_d(ctx, cond, rt, rs, cc); + break; + case 0x2: + gen_cmpabs_ps(ctx, cond, rt, rs, cc); + break; + default: + goto pool32f_invalid; + } + break; + case C_COND_FMT: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + cond = (ctx->opcode >> 6) & 0xf; + cc = (ctx->opcode >> 13) & 0x7; + fmt = (ctx->opcode >> 10) & 0x3; + switch (fmt) { + case 0x0: + gen_cmp_s(ctx, cond, rt, rs, cc); + break; + case 0x1: + gen_cmp_d(ctx, cond, rt, rs, cc); + break; + case 0x2: + gen_cmp_ps(ctx, cond, rt, rs, cc); + break; + default: + goto pool32f_invalid; + } + break; + case CMP_CONDN_S: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_cmp_s(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); + break; + case CMP_CONDN_D: + check_insn(ctx, ISA_MIPS_R6); + gen_r6_cmp_d(ctx, (ctx->opcode >> 6) & 0x1f, rt, rs, rd); + break; + case POOL32FXF: + gen_pool32fxf(ctx, rt, rs); + break; + case 0x00: + /* PLL foo */ + switch ((ctx->opcode >> 6) & 0x7) { + case PLL_PS: + mips32_op = OPC_PLL_PS; + goto do_ps; + case PLU_PS: + mips32_op = OPC_PLU_PS; + goto do_ps; + case PUL_PS: + mips32_op = OPC_PUL_PS; + goto do_ps; + case PUU_PS: + mips32_op = OPC_PUU_PS; + goto do_ps; + case CVT_PS_S: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_CVT_PS_S; + do_ps: + gen_farith(ctx, mips32_op, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case MIN_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MIN_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MIN_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x08: + /* [LS][WDU]XC1 */ + switch ((ctx->opcode >> 6) & 0x7) { + case LWXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWXC1; + goto do_ldst_cp1; + case SWXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWXC1; + goto do_ldst_cp1; + case LDXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LDXC1; + goto do_ldst_cp1; + case SDXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SDXC1; + goto do_ldst_cp1; + case LUXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LUXC1; + goto do_ldst_cp1; + case SUXC1: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SUXC1; + do_ldst_cp1: + gen_flt3_ldst(ctx, mips32_op, rd, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + break; + case MAX_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MAX_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MAX_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x18: + /* 3D insns */ + check_insn_opc_removed(ctx, ISA_MIPS_R6); + fmt = (ctx->opcode >> 9) & 0x3; + switch ((ctx->opcode >> 6) & 0x7) { + case RSQRT2_FMT: + switch (fmt) { + case FMT_SDPS_S: + mips32_op = OPC_RSQRT2_S; + goto do_3d; + case FMT_SDPS_D: + mips32_op = OPC_RSQRT2_D; + goto do_3d; + case FMT_SDPS_PS: + mips32_op = OPC_RSQRT2_PS; + goto do_3d; + default: + goto pool32f_invalid; + } + break; + case RECIP2_FMT: + switch (fmt) { + case FMT_SDPS_S: + mips32_op = OPC_RECIP2_S; + goto do_3d; + case FMT_SDPS_D: + mips32_op = OPC_RECIP2_D; + goto do_3d; + case FMT_SDPS_PS: + mips32_op = OPC_RECIP2_PS; + goto do_3d; + default: + goto pool32f_invalid; + } + break; + case ADDR_PS: + mips32_op = OPC_ADDR_PS; + goto do_3d; + case MULR_PS: + mips32_op = OPC_MULR_PS; + do_3d: + gen_farith(ctx, mips32_op, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x20: + /* MOV[FT].fmt, PREFX, RINT.fmt, CLASS.fmt*/ + cc = (ctx->opcode >> 13) & 0x7; + fmt = (ctx->opcode >> 9) & 0x3; + switch ((ctx->opcode >> 6) & 0x7) { + case MOVF_FMT: /* RINT_FMT */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* RINT_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_RINT_S, 0, rt, rs, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_RINT_D, 0, rt, rs, 0); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVF_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_movcf_s(ctx, rs, rt, cc, 0); + break; + case FMT_SDPS_D: + gen_movcf_d(ctx, rs, rt, cc, 0); + break; + case FMT_SDPS_PS: + check_ps(ctx); + gen_movcf_ps(ctx, rs, rt, cc, 0); + break; + default: + goto pool32f_invalid; + } + } + break; + case MOVT_FMT: /* CLASS_FMT */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* CLASS_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_CLASS_S, 0, rt, rs, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_CLASS_D, 0, rt, rs, 0); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVT_FMT */ + switch (fmt) { + case FMT_SDPS_S: + gen_movcf_s(ctx, rs, rt, cc, 1); + break; + case FMT_SDPS_D: + gen_movcf_d(ctx, rs, rt, cc, 1); + break; + case FMT_SDPS_PS: + check_ps(ctx); + gen_movcf_ps(ctx, rs, rt, cc, 1); + break; + default: + goto pool32f_invalid; + } + } + break; + case PREFX: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + break; + default: + goto pool32f_invalid; + } + break; +#define FINSN_3ARG_SDPS(prfx) \ + switch ((ctx->opcode >> 8) & 0x3) { \ + case FMT_SDPS_S: \ + mips32_op = OPC_##prfx##_S; \ + goto do_fpop; \ + case FMT_SDPS_D: \ + mips32_op = OPC_##prfx##_D; \ + goto do_fpop; \ + case FMT_SDPS_PS: \ + check_ps(ctx); \ + mips32_op = OPC_##prfx##_PS; \ + goto do_fpop; \ + default: \ + goto pool32f_invalid; \ + } + case MINA_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MINA_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MINA_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case MAXA_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_farith(ctx, OPC_MAXA_S, rt, rs, rd, 0); + break; + case FMT_SDPS_D: + gen_farith(ctx, OPC_MAXA_D, rt, rs, rd, 0); + break; + default: + goto pool32f_invalid; + } + break; + case 0x30: + /* regular FP ops */ + switch ((ctx->opcode >> 6) & 0x3) { + case ADD_FMT: + FINSN_3ARG_SDPS(ADD); + break; + case SUB_FMT: + FINSN_3ARG_SDPS(SUB); + break; + case MUL_FMT: + FINSN_3ARG_SDPS(MUL); + break; + case DIV_FMT: + fmt = (ctx->opcode >> 8) & 0x3; + if (fmt == 1) { + mips32_op = OPC_DIV_D; + } else if (fmt == 0) { + mips32_op = OPC_DIV_S; + } else { + goto pool32f_invalid; + } + goto do_fpop; + default: + goto pool32f_invalid; + } + break; + case 0x38: + /* cmovs */ + switch ((ctx->opcode >> 6) & 0x7) { + case MOVN_FMT: /* SELEQZ_FMT */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* SELEQZ_FMT */ + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_sel_s(ctx, OPC_SELEQZ_S, rd, rt, rs); + break; + case FMT_SDPS_D: + gen_sel_d(ctx, OPC_SELEQZ_D, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVN_FMT */ + FINSN_3ARG_SDPS(MOVN); + } + break; + case MOVN_FMT_04: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + FINSN_3ARG_SDPS(MOVN); + break; + case MOVZ_FMT: /* SELNEZ_FMT */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* SELNEZ_FMT */ + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_sel_s(ctx, OPC_SELNEZ_S, rd, rt, rs); + break; + case FMT_SDPS_D: + gen_sel_d(ctx, OPC_SELNEZ_D, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + } else { + /* MOVZ_FMT */ + FINSN_3ARG_SDPS(MOVZ); + } + break; + case MOVZ_FMT_05: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + FINSN_3ARG_SDPS(MOVZ); + break; + case SEL_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + gen_sel_s(ctx, OPC_SEL_S, rd, rt, rs); + break; + case FMT_SDPS_D: + gen_sel_d(ctx, OPC_SEL_D, rd, rt, rs); + break; + default: + goto pool32f_invalid; + } + break; + case MADDF_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + mips32_op = OPC_MADDF_S; + goto do_fpop; + case FMT_SDPS_D: + mips32_op = OPC_MADDF_D; + goto do_fpop; + default: + goto pool32f_invalid; + } + break; + case MSUBF_FMT: + check_insn(ctx, ISA_MIPS_R6); + switch ((ctx->opcode >> 9) & 0x3) { + case FMT_SDPS_S: + mips32_op = OPC_MSUBF_S; + goto do_fpop; + case FMT_SDPS_D: + mips32_op = OPC_MSUBF_D; + goto do_fpop; + default: + goto pool32f_invalid; + } + break; + default: + goto pool32f_invalid; + } + break; + do_fpop: + gen_farith(ctx, mips32_op, rt, rs, rd, 0); + break; + default: + pool32f_invalid: + MIPS_INVAL("pool32f"); + gen_reserved_instruction(ctx); + break; + } + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } + break; + case POOL32I: + minor = (ctx->opcode >> 21) & 0x1f; + switch (minor) { + case BLTZ: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4); + break; + case BLTZAL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case BLTZALS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case BGEZ: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4); + break; + case BGEZAL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case BGEZALS: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case BLEZ: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4); + break; + case BGTZ: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4); + break; + + /* Traps */ + case TLTI: /* BC1EQZC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* BC1EQZC */ + check_cp1_enabled(ctx); + gen_compute_branch1_r6(ctx, OPC_BC1EQZ, rs, imm << 1, 0); + } else { + /* TLTI */ + mips32_op = OPC_TLTI; + goto do_trapi; + } + break; + case TGEI: /* BC1NEZC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* BC1NEZC */ + check_cp1_enabled(ctx); + gen_compute_branch1_r6(ctx, OPC_BC1NEZ, rs, imm << 1, 0); + } else { + /* TGEI */ + mips32_op = OPC_TGEI; + goto do_trapi; + } + break; + case TLTIU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_TLTIU; + goto do_trapi; + case TGEIU: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_TGEIU; + goto do_trapi; + case TNEI: /* SYNCI */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* SYNCI */ + /* + * Break the TB to be able to sync copied instructions + * immediately. + */ + ctx->base.is_jmp = DISAS_STOP; + } else { + /* TNEI */ + mips32_op = OPC_TNEI; + goto do_trapi; + } + break; + case TEQI: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_TEQI; + do_trapi: + gen_trap(ctx, mips32_op, rs, -1, imm); + break; + + case BNEZC: + case BEQZC: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, + 4, rs, 0, imm << 1, 0); + /* + * Compact branches don't have a delay slot, so just let + * the normal delay slot handling take us to the branch + * target. + */ + break; + case LUI: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + gen_logic_imm(ctx, OPC_LUI, rs, 0, imm); + break; + case SYNCI: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + /* + * Break the TB to be able to sync copied instructions + * immediately. + */ + ctx->base.is_jmp = DISAS_STOP; + break; + case BC2F: + case BC2T: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + /* COP2: Not implemented. */ + generate_exception_err(ctx, EXCP_CpU, 2); + break; + case BC1F: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1FANY2 : OPC_BC1F; + goto do_cp1branch; + case BC1T: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = (ctx->opcode & (1 << 16)) ? OPC_BC1TANY2 : OPC_BC1T; + goto do_cp1branch; + case BC1ANY4F: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_BC1FANY4; + goto do_cp1mips3d; + case BC1ANY4T: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_BC1TANY4; + do_cp1mips3d: + check_cop1x(ctx); + check_insn(ctx, ASE_MIPS3D); + /* Fall through */ + do_cp1branch: + if (env->CP0_Config1 & (1 << CP0C1_FP)) { + check_cp1_enabled(ctx); + gen_compute_branch1(ctx, mips32_op, + (ctx->opcode >> 18) & 0x7, imm << 1); + } else { + generate_exception_err(ctx, EXCP_CpU, 1); + } + break; + default: + MIPS_INVAL("pool32i"); + gen_reserved_instruction(ctx); + break; + } + break; + case POOL32C: + minor = (ctx->opcode >> 12) & 0xf; + offset = sextract32(ctx->opcode, 0, + (ctx->insn_flags & ISA_MIPS_R6) ? 9 : 12); + switch (minor) { + case LWL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWL; + goto do_ld_lr; + case SWL: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWL; + goto do_st_lr; + case LWR: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWR; + goto do_ld_lr; + case SWR: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWR; + goto do_st_lr; +#if defined(TARGET_MIPS64) + case LDL: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LDL; + goto do_ld_lr; + case SDL: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SDL; + goto do_st_lr; + case LDR: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LDR; + goto do_ld_lr; + case SDR: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SDR; + goto do_st_lr; + case LWU: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + mips32_op = OPC_LWU; + goto do_ld_lr; + case LLD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + mips32_op = OPC_LLD; + goto do_ld_lr; +#endif + case LL: + mips32_op = OPC_LL; + goto do_ld_lr; + do_ld_lr: + gen_ld(ctx, mips32_op, rt, rs, offset); + break; + do_st_lr: + gen_st(ctx, mips32_op, rt, rs, offset); + break; + case SC: + gen_st_cond(ctx, rt, rs, offset, MO_TESL, false); + break; +#if defined(TARGET_MIPS64) + case SCD: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + gen_st_cond(ctx, rt, rs, offset, MO_TEQ, false); + break; +#endif + case LD_EVA: + if (!ctx->eva) { + MIPS_INVAL("pool32c ld-eva"); + gen_reserved_instruction(ctx); + break; + } + check_cp0_enabled(ctx); + + minor2 = (ctx->opcode >> 9) & 0x7; + offset = sextract32(ctx->opcode, 0, 9); + switch (minor2) { + case LBUE: + mips32_op = OPC_LBUE; + goto do_ld_lr; + case LHUE: + mips32_op = OPC_LHUE; + goto do_ld_lr; + case LWLE: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWLE; + goto do_ld_lr; + case LWRE: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_LWRE; + goto do_ld_lr; + case LBE: + mips32_op = OPC_LBE; + goto do_ld_lr; + case LHE: + mips32_op = OPC_LHE; + goto do_ld_lr; + case LLE: + mips32_op = OPC_LLE; + goto do_ld_lr; + case LWE: + mips32_op = OPC_LWE; + goto do_ld_lr; + }; + break; + case ST_EVA: + if (!ctx->eva) { + MIPS_INVAL("pool32c st-eva"); + gen_reserved_instruction(ctx); + break; + } + check_cp0_enabled(ctx); + + minor2 = (ctx->opcode >> 9) & 0x7; + offset = sextract32(ctx->opcode, 0, 9); + switch (minor2) { + case SWLE: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWLE; + goto do_st_lr; + case SWRE: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + mips32_op = OPC_SWRE; + goto do_st_lr; + case PREFE: + /* Treat as no-op */ + if ((ctx->insn_flags & ISA_MIPS_R6) && (rt >= 24)) { + /* hint codes 24-31 are reserved and signal RI */ + generate_exception(ctx, EXCP_RI); + } + break; + case CACHEE: + /* Treat as no-op */ + if (ctx->hflags & MIPS_HFLAG_ITC_CACHE) { + gen_cache_operation(ctx, rt, rs, offset); + } + break; + case SBE: + mips32_op = OPC_SBE; + goto do_st_lr; + case SHE: + mips32_op = OPC_SHE; + goto do_st_lr; + case SCE: + gen_st_cond(ctx, rt, rs, offset, MO_TESL, true); + break; + case SWE: + mips32_op = OPC_SWE; + goto do_st_lr; + }; + break; + case PREF: + /* Treat as no-op */ + if ((ctx->insn_flags & ISA_MIPS_R6) && (rt >= 24)) { + /* hint codes 24-31 are reserved and signal RI */ + generate_exception(ctx, EXCP_RI); + } + break; + default: + MIPS_INVAL("pool32c"); + gen_reserved_instruction(ctx); + break; + } + break; + case ADDI32: /* AUI, LUI */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* AUI, LUI */ + gen_logic_imm(ctx, OPC_LUI, rt, rs, imm); + } else { + /* ADDI32 */ + mips32_op = OPC_ADDI; + goto do_addi; + } + break; + case ADDIU32: + mips32_op = OPC_ADDIU; + do_addi: + gen_arith_imm(ctx, mips32_op, rt, rs, imm); + break; + + /* Logical operations */ + case ORI32: + mips32_op = OPC_ORI; + goto do_logici; + case XORI32: + mips32_op = OPC_XORI; + goto do_logici; + case ANDI32: + mips32_op = OPC_ANDI; + do_logici: + gen_logic_imm(ctx, mips32_op, rt, rs, imm); + break; + + /* Set less than immediate */ + case SLTI32: + mips32_op = OPC_SLTI; + goto do_slti; + case SLTIU32: + mips32_op = OPC_SLTIU; + do_slti: + gen_slt_imm(ctx, mips32_op, rt, rs, imm); + break; + case JALX32: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; + gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; + case JALS32: /* BOVC, BEQC, BEQZALC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + if (rs >= rt) { + /* BOVC */ + mips32_op = OPC_BOVC; + } else if (rs < rt && rs == 0) { + /* BEQZALC */ + mips32_op = OPC_BEQZALC; + } else { + /* BEQC */ + mips32_op = OPC_BEQC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + } else { + /* JALS32 */ + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + } + break; + case BEQ32: /* BC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* BC */ + gen_compute_compact_branch(ctx, OPC_BC, 0, 0, + sextract32(ctx->opcode << 1, 0, 27)); + } else { + /* BEQ32 */ + gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4); + } + break; + case BNE32: /* BALC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* BALC */ + gen_compute_compact_branch(ctx, OPC_BALC, 0, 0, + sextract32(ctx->opcode << 1, 0, 27)); + } else { + /* BNE32 */ + gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); + } + break; + case J32: /* BGTZC, BLTZC, BLTC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + if (rs == 0 && rt != 0) { + /* BGTZC */ + mips32_op = OPC_BGTZC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BLTZC */ + mips32_op = OPC_BLTZC; + } else { + /* BLTC */ + mips32_op = OPC_BLTC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + } else { + /* J32 */ + gen_compute_branch(ctx, OPC_J, 4, rt, rs, + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); + } + break; + case JAL32: /* BLEZC, BGEZC, BGEC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + if (rs == 0 && rt != 0) { + /* BLEZC */ + mips32_op = OPC_BLEZC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BGEZC */ + mips32_op = OPC_BGEZC; + } else { + /* BGEC */ + mips32_op = OPC_BGEC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + } else { + /* JAL32 */ + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + } + break; + /* Floating point (COP1) */ + case LWC132: + mips32_op = OPC_LWC1; + goto do_cop1; + case LDC132: + mips32_op = OPC_LDC1; + goto do_cop1; + case SWC132: + mips32_op = OPC_SWC1; + goto do_cop1; + case SDC132: + mips32_op = OPC_SDC1; + do_cop1: + gen_cop1_ldst(ctx, mips32_op, rt, rs, imm); + break; + case ADDIUPC: /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ + if (ctx->insn_flags & ISA_MIPS_R6) { + /* PCREL: ADDIUPC, AUIPC, ALUIPC, LWPC */ + switch ((ctx->opcode >> 16) & 0x1f) { + case ADDIUPC_00: + case ADDIUPC_01: + case ADDIUPC_02: + case ADDIUPC_03: + case ADDIUPC_04: + case ADDIUPC_05: + case ADDIUPC_06: + case ADDIUPC_07: + gen_pcrel(ctx, OPC_ADDIUPC, ctx->base.pc_next & ~0x3, rt); + break; + case AUIPC: + gen_pcrel(ctx, OPC_AUIPC, ctx->base.pc_next, rt); + break; + case ALUIPC: + gen_pcrel(ctx, OPC_ALUIPC, ctx->base.pc_next, rt); + break; + case LWPC_08: + case LWPC_09: + case LWPC_0A: + case LWPC_0B: + case LWPC_0C: + case LWPC_0D: + case LWPC_0E: + case LWPC_0F: + gen_pcrel(ctx, R6_OPC_LWPC, ctx->base.pc_next & ~0x3, rt); + break; + default: + generate_exception(ctx, EXCP_RI); + break; + } + } else { + /* ADDIUPC */ + int reg = mmreg(ZIMM(ctx->opcode, 23, 3)); + offset = SIMM(ctx->opcode, 0, 23) << 2; + + gen_addiupc(ctx, reg, offset, 0, 0); + } + break; + case BNVC: /* BNEC, BNEZALC */ + check_insn(ctx, ISA_MIPS_R6); + if (rs >= rt) { + /* BNVC */ + mips32_op = OPC_BNVC; + } else if (rs < rt && rs == 0) { + /* BNEZALC */ + mips32_op = OPC_BNEZALC; + } else { + /* BNEC */ + mips32_op = OPC_BNEC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + break; + case R6_BNEZC: /* JIALC */ + check_insn(ctx, ISA_MIPS_R6); + if (rt != 0) { + /* BNEZC */ + gen_compute_compact_branch(ctx, OPC_BNEZC, rt, 0, + sextract32(ctx->opcode << 1, 0, 22)); + } else { + /* JIALC */ + gen_compute_compact_branch(ctx, OPC_JIALC, 0, rs, imm); + } + break; + case R6_BEQZC: /* JIC */ + check_insn(ctx, ISA_MIPS_R6); + if (rt != 0) { + /* BEQZC */ + gen_compute_compact_branch(ctx, OPC_BEQZC, rt, 0, + sextract32(ctx->opcode << 1, 0, 22)); + } else { + /* JIC */ + gen_compute_compact_branch(ctx, OPC_JIC, 0, rs, imm); + } + break; + case BLEZALC: /* BGEZALC, BGEUC */ + check_insn(ctx, ISA_MIPS_R6); + if (rs == 0 && rt != 0) { + /* BLEZALC */ + mips32_op = OPC_BLEZALC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BGEZALC */ + mips32_op = OPC_BGEZALC; + } else { + /* BGEUC */ + mips32_op = OPC_BGEUC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + break; + case BGTZALC: /* BLTZALC, BLTUC */ + check_insn(ctx, ISA_MIPS_R6); + if (rs == 0 && rt != 0) { + /* BGTZALC */ + mips32_op = OPC_BGTZALC; + } else if (rs != 0 && rt != 0 && rs == rt) { + /* BLTZALC */ + mips32_op = OPC_BLTZALC; + } else { + /* BLTUC */ + mips32_op = OPC_BLTUC; + } + gen_compute_compact_branch(ctx, mips32_op, rs, rt, imm << 1); + break; + /* Loads and stores */ + case LB32: + mips32_op = OPC_LB; + goto do_ld; + case LBU32: + mips32_op = OPC_LBU; + goto do_ld; + case LH32: + mips32_op = OPC_LH; + goto do_ld; + case LHU32: + mips32_op = OPC_LHU; + goto do_ld; + case LW32: + mips32_op = OPC_LW; + goto do_ld; +#ifdef TARGET_MIPS64 + case LD32: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + mips32_op = OPC_LD; + goto do_ld; + case SD32: + check_insn(ctx, ISA_MIPS3); + check_mips_64(ctx); + mips32_op = OPC_SD; + goto do_st; +#endif + case SB32: + mips32_op = OPC_SB; + goto do_st; + case SH32: + mips32_op = OPC_SH; + goto do_st; + case SW32: + mips32_op = OPC_SW; + goto do_st; + do_ld: + gen_ld(ctx, mips32_op, rt, rs, imm); + break; + do_st: + gen_st(ctx, mips32_op, rt, rs, imm); + break; + default: + gen_reserved_instruction(ctx); + break; + } +} + +static int decode_isa_micromips(CPUMIPSState *env, DisasContext *ctx) +{ + uint32_t op; + + /* make sure instructions are on a halfword boundary */ + if (ctx->base.pc_next & 0x1) { + env->CP0_BadVAddr = ctx->base.pc_next; + generate_exception_end(ctx, EXCP_AdEL); + return 2; + } + + op = (ctx->opcode >> 10) & 0x3f; + /* Enforce properly-sized instructions in a delay slot */ + if (ctx->hflags & MIPS_HFLAG_BDS_STRICT) { + switch (op & 0x7) { /* MSB-3..MSB-5 */ + case 0: + /* POOL32A, POOL32B, POOL32I, POOL32C */ + case 4: + /* ADDI32, ADDIU32, ORI32, XORI32, SLTI32, SLTIU32, ANDI32, JALX32 */ + case 5: + /* LBU32, LHU32, POOL32F, JALS32, BEQ32, BNE32, J32, JAL32 */ + case 6: + /* SB32, SH32, ADDIUPC, SWC132, SDC132, SW32 */ + case 7: + /* LB32, LH32, LWC132, LDC132, LW32 */ + if (ctx->hflags & MIPS_HFLAG_BDS16) { + gen_reserved_instruction(ctx); + return 2; + } + break; + case 1: + /* POOL16A, POOL16B, POOL16C, LWGP16, POOL16F */ + case 2: + /* LBU16, LHU16, LWSP16, LW16, SB16, SH16, SWSP16, SW16 */ + case 3: + /* MOVE16, ANDI16, POOL16D, POOL16E, BEQZ16, BNEZ16, B16, LI16 */ + if (ctx->hflags & MIPS_HFLAG_BDS32) { + gen_reserved_instruction(ctx); + return 2; + } + break; + } + } + + switch (op) { + case POOL16A: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs1 = mmreg(uMIPS_RS1(ctx->opcode)); + int rs2 = mmreg(uMIPS_RS2(ctx->opcode)); + uint32_t opc = 0; + + switch (ctx->opcode & 0x1) { + case ADDU16: + opc = OPC_ADDU; + break; + case SUBU16: + opc = OPC_SUBU; + break; + } + if (ctx->insn_flags & ISA_MIPS_R6) { + /* + * In the Release 6, the register number location in + * the instruction encoding has changed. + */ + gen_arith(ctx, opc, rs1, rd, rs2); + } else { + gen_arith(ctx, opc, rd, rs1, rs2); + } + } + break; + case POOL16B: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rs = mmreg(uMIPS_RS(ctx->opcode)); + int amount = (ctx->opcode >> 1) & 0x7; + uint32_t opc = 0; + amount = amount == 0 ? 8 : amount; + + switch (ctx->opcode & 0x1) { + case SLL16: + opc = OPC_SLL; + break; + case SRL16: + opc = OPC_SRL; + break; + } + + gen_shift_imm(ctx, opc, rd, rs, amount); + } + break; + case POOL16C: + if (ctx->insn_flags & ISA_MIPS_R6) { + gen_pool16c_r6_insn(ctx); + } else { + gen_pool16c_insn(ctx); + } + break; + case LWGP16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = 28; /* GP */ + int16_t offset = SIMM(ctx->opcode, 0, 7) << 2; + + gen_ld(ctx, OPC_LW, rd, rb, offset); + } + break; + case POOL16F: + check_insn_opc_removed(ctx, ISA_MIPS_R6); + if (ctx->opcode & 1) { + gen_reserved_instruction(ctx); + } else { + /* MOVEP */ + int enc_dest = uMIPS_RD(ctx->opcode); + int enc_rt = uMIPS_RS2(ctx->opcode); + int enc_rs = uMIPS_RS1(ctx->opcode); + gen_movep(ctx, enc_dest, enc_rt, enc_rs); + } + break; + case LBU16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4); + offset = (offset == 0xf ? -1 : offset); + + gen_ld(ctx, OPC_LBU, rd, rb, offset); + } + break; + case LHU16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; + + gen_ld(ctx, OPC_LHU, rd, rb, offset); + } + break; + case LWSP16: + { + int rd = (ctx->opcode >> 5) & 0x1f; + int rb = 29; /* SP */ + int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; + + gen_ld(ctx, OPC_LW, rd, rb, offset); + } + break; + case LW16: + { + int rd = mmreg(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; + + gen_ld(ctx, OPC_LW, rd, rb, offset); + } + break; + case SB16: + { + int rd = mmreg2(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4); + + gen_st(ctx, OPC_SB, rd, rb, offset); + } + break; + case SH16: + { + int rd = mmreg2(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 1; + + gen_st(ctx, OPC_SH, rd, rb, offset); + } + break; + case SWSP16: + { + int rd = (ctx->opcode >> 5) & 0x1f; + int rb = 29; /* SP */ + int16_t offset = ZIMM(ctx->opcode, 0, 5) << 2; + + gen_st(ctx, OPC_SW, rd, rb, offset); + } + break; + case SW16: + { + int rd = mmreg2(uMIPS_RD(ctx->opcode)); + int rb = mmreg(uMIPS_RS(ctx->opcode)); + int16_t offset = ZIMM(ctx->opcode, 0, 4) << 2; + + gen_st(ctx, OPC_SW, rd, rb, offset); + } + break; + case MOVE16: + { + int rd = uMIPS_RD5(ctx->opcode); + int rs = uMIPS_RS5(ctx->opcode); + + gen_arith(ctx, OPC_ADDU, rd, rs, 0); + } + break; + case ANDI16: + gen_andi16(ctx); + break; + case POOL16D: + switch (ctx->opcode & 0x1) { + case ADDIUS5: + gen_addius5(ctx); + break; + case ADDIUSP: + gen_addiusp(ctx); + break; + } + break; + case POOL16E: + switch (ctx->opcode & 0x1) { + case ADDIUR2: + gen_addiur2(ctx); + break; + case ADDIUR1SP: + gen_addiur1sp(ctx); + break; + } + break; + case B16: /* BC16 */ + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, + sextract32(ctx->opcode, 0, 10) << 1, + (ctx->insn_flags & ISA_MIPS_R6) ? 0 : 4); + break; + case BNEZ16: /* BNEZC16 */ + case BEQZ16: /* BEQZC16 */ + gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, + mmreg(uMIPS_RD(ctx->opcode)), + 0, sextract32(ctx->opcode, 0, 7) << 1, + (ctx->insn_flags & ISA_MIPS_R6) ? 0 : 4); + + break; + case LI16: + { + int reg = mmreg(uMIPS_RD(ctx->opcode)); + int imm = ZIMM(ctx->opcode, 0, 7); + + imm = (imm == 0x7f ? -1 : imm); + tcg_gen_movi_tl(cpu_gpr[reg], imm); + } + break; + case RES_29: + case RES_31: + case RES_39: + gen_reserved_instruction(ctx); + break; + default: + decode_micromips32_opc(env, ctx); + return 4; + } + + return 2; +}