From patchwork Thu Jul 1 22:13:42 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aurelien Jarno X-Patchwork-Id: 57601 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id AC3111007D4 for ; Fri, 2 Jul 2010 08:16:35 +1000 (EST) Received: from localhost ([127.0.0.1]:37136 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OUS3b-0000Sw-Hz for incoming@patchwork.ozlabs.org; Thu, 01 Jul 2010 18:16:31 -0400 Received: from [140.186.70.92] (port=42704 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OUS1P-0007oW-43 for qemu-devel@nongnu.org; Thu, 01 Jul 2010 18:14:21 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OUS1H-0005f7-BU for qemu-devel@nongnu.org; Thu, 01 Jul 2010 18:14:13 -0400 Received: from hall.aurel32.net ([88.191.82.174]:43993) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OUS1H-0005ed-41 for qemu-devel@nongnu.org; Thu, 01 Jul 2010 18:14:07 -0400 Received: from ip-66-181-1-6.cust.i2bnetworks.com ([66.181.1.6] helo=ohm.aurel32.net) by hall.aurel32.net with esmtpsa (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.69) (envelope-from ) id 1OUS1D-0000WL-LF; Fri, 02 Jul 2010 00:14:05 +0200 Received: from aurel32 by ohm.aurel32.net with local (Exim 4.72) (envelope-from ) id 1OUS0z-0001mE-MK; Fri, 02 Jul 2010 00:13:49 +0200 From: Aurelien Jarno To: qemu-devel@nongnu.org Date: Fri, 2 Jul 2010 00:13:42 +0200 Message-Id: <1278022422-6786-1-git-send-email-aurelien@aurel32.net> X-Mailer: git-send-email 1.7.1 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) Cc: chen huacai , Aurelien Jarno Subject: [Qemu-devel] [PATCH] [RFC] target-mips: add loongson 2E & 2F integer instructions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds support for loongson 2E & 2F instructions. They are the same instructions, but differ by the opcode encoding. This patch has still a few problems (hence the RFC), but is enough to boot a fulong 2E kernel built with the -mloongson2e flag: - I am unable to understand the difference between DMULT.G and DMULTU.G instructions. As they are both a 64x64 => 64 multiplication, the signedness should not make any difference. They are implemented the same way in this patch. - Division by 0 is not supposed to trigger any arithmetic exception, however the manual doesn't explain which result is return in such condition. With this patch, QEMU will crash with a SIGFPE in sich a situation. Signed-off-by: Aurelien Jarno --- target-mips/translate.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 143 insertions(+), 0 deletions(-) diff --git a/target-mips/translate.c b/target-mips/translate.c index 0ab23d3..91882b7 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -267,6 +267,19 @@ enum { OPC_MUL = 0x02 | OPC_SPECIAL2, OPC_MSUB = 0x04 | OPC_SPECIAL2, OPC_MSUBU = 0x05 | OPC_SPECIAL2, + /* Loongson 2F */ + OPC_MULT_G_2F = 0x10 | OPC_SPECIAL2, + OPC_DMULT_G_2F = 0x11 | OPC_SPECIAL2, + OPC_MULTU_G_2F = 0x12 | OPC_SPECIAL2, + OPC_DMULTU_G_2F = 0x13 | OPC_SPECIAL2, + OPC_DIV_G_2F = 0x14 | OPC_SPECIAL2, + OPC_DDIV_G_2F = 0x15 | OPC_SPECIAL2, + OPC_DIVU_G_2F = 0x16 | OPC_SPECIAL2, + OPC_DDIVU_G_2F = 0x17 | OPC_SPECIAL2, + OPC_MOD_G_2F = 0x1c | OPC_SPECIAL2, + OPC_DMOD_G_2F = 0x1d | OPC_SPECIAL2, + OPC_MODU_G_2F = 0x1e | OPC_SPECIAL2, + OPC_DMODU_G_2F = 0x1f | OPC_SPECIAL2, /* Misc */ OPC_CLZ = 0x20 | OPC_SPECIAL2, OPC_CLO = 0x21 | OPC_SPECIAL2, @@ -293,6 +306,20 @@ enum { OPC_BSHFL = 0x20 | OPC_SPECIAL3, OPC_DBSHFL = 0x24 | OPC_SPECIAL3, OPC_RDHWR = 0x3B | OPC_SPECIAL3, + + /* Loongson 2E */ + OPC_MULT_G_2E = 0x18 | OPC_SPECIAL3, + OPC_MULTU_G_2E = 0x19 | OPC_SPECIAL3, + OPC_DIV_G_2E = 0x1A | OPC_SPECIAL3, + OPC_DIVU_G_2E = 0x1B | OPC_SPECIAL3, + OPC_DMULT_G_2E = 0x1C | OPC_SPECIAL3, + OPC_DMULTU_G_2E = 0x1D | OPC_SPECIAL3, + OPC_DDIV_G_2E = 0x1E | OPC_SPECIAL3, + OPC_DDIVU_G_2E = 0x1F | OPC_SPECIAL3, + OPC_MOD_G_2E = 0x22 | OPC_SPECIAL3, + OPC_MODU_G_2E = 0x23 | OPC_SPECIAL3, + OPC_DMOD_G_2E = 0x26 | OPC_SPECIAL3, + OPC_DMODU_G_2E = 0x27 | OPC_SPECIAL3, }; /* BSHFL opcodes */ @@ -2325,6 +2352,110 @@ static void gen_cl (DisasContext *ctx, uint32_t opc, tcg_temp_free(t0); } +#if defined(TARGET_MIPS64) +/* Godson integer instructions */ +static void gen_loongson_integer (DisasContext *ctx, uint32_t opc, + int rd, int rs, int rt) +{ + const char *opn = "loongson"; + TCGv t0, t1; + + if (rd == 0) { + /* Treat as NOP. */ + MIPS_DEBUG("NOP"); + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, rs); + gen_load_gpr(t1, rt); + switch (opc) { + case OPC_MULT_G_2E: + case OPC_MULT_G_2F: + tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + opn = "mult.g"; + break; + case OPC_MULTU_G_2E: + case OPC_MULTU_G_2F: + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + opn = "multu.g"; + break; + case OPC_DMULT_G_2E: + case OPC_DMULT_G_2F: + tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); + opn = "dmult.g"; + break; + case OPC_DMULTU_G_2E: + case OPC_DMULTU_G_2F: + tcg_gen_mul_tl(cpu_gpr[rd], t0, t1); + opn = "dmultu.g"; + break; + case OPC_DIV_G_2E: + case OPC_DIV_G_2F: + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_div_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + opn = "div.g"; + break; + case OPC_DIVU_G_2E: + case OPC_DIVU_G_2F: + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + opn = "divu.g"; + break; + case OPC_DDIV_G_2E: + case OPC_DDIV_G_2F: + tcg_gen_div_tl(cpu_gpr[rd], t0, t1); + opn = "ddiv.g"; + break; + case OPC_DDIVU_G_2E: + case OPC_DDIVU_G_2F: + tcg_gen_div_tl(cpu_gpr[rd], t0, t1); + opn = "ddivu.g"; + break; + case OPC_MOD_G_2E: + case OPC_MOD_G_2F: + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + opn = "mod.g"; + break; + case OPC_MODU_G_2E: + case OPC_MODU_G_2F: + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + opn = "modu.g"; + break; + case OPC_DMOD_G_2E: + case OPC_DMOD_G_2F: + tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); + opn = "dmod.g"; + break; + case OPC_DMODU_G_2E: + case OPC_DMODU_G_2F: + tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); + opn = "dmodu.g"; + break; + } + + MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]); + tcg_temp_free(t0); + tcg_temp_free(t1); +} +#endif + /* Traps */ static void gen_trap (DisasContext *ctx, uint32_t opc, int rs, int rt, int16_t imm) @@ -11603,6 +11734,12 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch) check_mips_64(ctx); gen_cl(ctx, op1, rd, rs); break; + case OPC_MULT_G_2F ... OPC_DDIVU_G_2F: + case OPC_MOD_G_2F ... OPC_DMOD_G_2F: + case OPC_MODU_G_2F ... OPC_DMODU_G_2F: + check_insn(env, ctx, INSN_LOONGSON2F); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; #endif default: /* Invalid */ MIPS_INVAL("special2"); @@ -11664,6 +11801,12 @@ static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch) op2 = MASK_DBSHFL(ctx->opcode); gen_bshfl(ctx, op2, rt, rd); break; + case OPC_MULT_G_2E ... OPC_DDIVU_G_2E: + case OPC_MOD_G_2E ... OPC_MODU_G_2E: + case OPC_DMOD_G_2E ... OPC_DMODU_G_2E: + check_insn(env, ctx, INSN_LOONGSON2E); + gen_loongson_integer(ctx, op1, rd, rs, rt); + break; #endif default: /* Invalid */ MIPS_INVAL("special3");