From patchwork Mon Jun 28 12:04:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347781 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=-21.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, 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 E03E3C2B9F4 for ; Mon, 28 Jun 2021 12:06:49 +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 0F3B261C69 for ; Mon, 28 Jun 2021 12:06:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0F3B261C69 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:60592 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq2I-0004zH-Vo for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:06:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51130) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0Y-00027u-5y for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:04:58 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45298 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0T-00014T-8X for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:04:57 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S3; Mon, 28 Jun 2021 20:04:45 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 01/20] target/loongarch: Add README Date: Mon, 28 Jun 2021 20:04:26 +0800 Message-Id: <1624881885-31692-2-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S3 X-Coremail-Antispam: 1UD129KBjvJXoW7WF15Cw17Cr4UWr18XFyDAwb_yoW8GF13pr 4fuFyfKr48GrZrJrn3Way3XFn8Xr4fGr47Wa129ry8CrsxJw1qvFn5twnFyFy7Zw1rKrW0 vryrCr1jgF4Uua7anT9S1TB71UUUUjDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UUUUUUUUU== X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch give an introduction to the LoongArch target. Signed-off-by: Song Gao --- MAINTAINERS | 5 +++++ target/loongarch/README | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 target/loongarch/README diff --git a/MAINTAINERS b/MAINTAINERS index 3ff56f5..f207805 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -209,6 +209,11 @@ F: disas/hppa.c F: hw/net/*i82596* F: include/hw/net/lasi_82596.h +LoongArch TCG CPUS +M: Song Gao +S: Maintained +F: target/loongarch/ + M68K TCG CPUs M: Laurent Vivier S: Maintained diff --git a/target/loongarch/README b/target/loongarch/README new file mode 100644 index 0000000..0addfc7 --- /dev/null +++ b/target/loongarch/README @@ -0,0 +1,16 @@ +LoongArch is the general processor architecture of Loongson. + +The following versions of the LoongArch core are supported + core: 3A5000 + https://github.com/loongson/LoongArch-Documentation/releases/download/LoongArch-Vol1-v3/LoongArch-Vol1-v1.00-EN.pdf + +There are several code directories + + 1 qemu/target/loongarch + This is the instruction emulation directory + 2 qemu/linux-user/loongarch64 + Linux-user simulation + 3 qemu/hw/loongarch + System simulation + 4 qemu/tests/tcg/loongarch + Linux-user test From patchwork Mon Jun 28 12:04:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347783 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.7 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UPPERCASE_50_75,URIBL_BLOCKED, 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 125DAC2B9F4 for ; Mon, 28 Jun 2021 12:06:59 +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 B014F61C69 for ; Mon, 28 Jun 2021 12:06:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B014F61C69 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:60962 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq2T-0005EA-Km for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:06:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51176) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0c-0002CZ-2p for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:02 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45302 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0T-00014U-AW for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:01 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S4; Mon, 28 Jun 2021 20:04:46 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 02/20] target/loongarch: Add CSR registers definition Date: Mon, 28 Jun 2021 20:04:27 +0800 Message-Id: <1624881885-31692-3-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S4 X-Coremail-Antispam: 1UD129KBjvAXoWftrWDKr1xXw1kurW8XryxZrb_yoW5Ary5Ao WrX3W3J345Gw1xCw4q9w4xWr4UAr18ZF1DX348tryFgwnrW3sFkr1DtrZ7W343XryIgr13 WF1qqr4vy390kr98n29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001, UPPERCASE_50_75=0.008 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch add basic CSR registers definition. The CSR registers definition copy from kernel arch/loongarch/include/asm/loongarchregs.h. Signed-off-by: Song Gao --- target/loongarch/cpu-csr.h | 724 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 724 insertions(+) create mode 100644 target/loongarch/cpu-csr.h diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h new file mode 100644 index 0000000..87273b1 --- /dev/null +++ b/target/loongarch/cpu-csr.h @@ -0,0 +1,724 @@ +/* + * QEMU LoongArch CSR + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef _CPU_CSR_H_ +#define _CPU_CSR_H_ + +/* + * basic CSR register copy + * copy from kernel arch/loongarch/include/asm/loongarchregs.h + */ + +#define LOONGARCH_CSR_CRMD 0x0 /* Current mode info */ +#define CSR_CRMD_DACM_SHIFT 7 +#define CSR_CRMD_DACM_WIDTH 2 +#define CSR_CRMD_DACM (0x3UL << CSR_CRMD_DACM_SHIFT) +#define CSR_CRMD_DACF_SHIFT 5 +#define CSR_CRMD_DACF_WIDTH 2 +#define CSR_CRMD_DACF (0x3UL << CSR_CRMD_DACF_SHIFT) +#define CSR_CRMD_PG_SHIFT 4 +#define CSR_CRMD_PG (0x1UL << CSR_CRMD_PG_SHIFT) +#define CSR_CRMD_DA_SHIFT 3 +#define CSR_CRMD_DA (0x1UL << CSR_CRMD_DA_SHIFT) +#define CSR_CRMD_IE_SHIFT 2 +#define CSR_CRMD_IE (0x1UL << CSR_CRMD_IE_SHIFT) +#define CSR_CRMD_PLV_SHIFT 0 +#define CSR_CRMD_PLV_WIDTH 2 +#define CSR_CRMD_PLV (0x3UL << CSR_CRMD_PLV_SHIFT) + +#define PLV_USER 3 +#define PLV_KERN 0 +#define PLV_MASK 0x3 + +#define LOONGARCH_CSR_PRMD 0x1 /* Prev-exception mode info */ +#define CSR_PRMD_PIE_SHIFT 2 +#define CSR_PRMD_PIE (0x1UL << CSR_PRMD_PIE_SHIFT) +#define CSR_PRMD_PPLV_SHIFT 0 +#define CSR_PRMD_PPLV_WIDTH 2 +#define CSR_PRMD_PPLV (0x3UL << CSR_PRMD_PPLV_SHIFT) + +#define LOONGARCH_CSR_EUEN 0x2 /* Extended unit enable */ +#define CSR_EUEN_LBTEN_SHIFT 3 +#define CSR_EUEN_LBTEN (0x1UL << CSR_EUEN_LBTEN_SHIFT) +#define CSR_EUEN_LASXEN_SHIFT 2 +#define CSR_EUEN_LASXEN (0x1UL << CSR_EUEN_LASXEN_SHIFT) +#define CSR_EUEN_LSXEN_SHIFT 1 +#define CSR_EUEN_LSXEN (0x1UL << CSR_EUEN_LSXEN_SHIFT) +#define CSR_EUEN_FPEN_SHIFT 0 +#define CSR_EUEN_FPEN (0x1UL << CSR_EUEN_FPEN_SHIFT) + +#define LOONGARCH_CSR_MISC 0x3 /* Misc config */ + +#define LOONGARCH_CSR_ECFG 0x4 /* Exception config */ +#define CSR_ECFG_VS_SHIFT 16 +#define CSR_ECFG_VS_WIDTH 3 +#define CSR_ECFG_VS (0x7UL << CSR_ECFG_VS_SHIFT) +#define CSR_ECFG_IM_SHIFT 0 +#define CSR_ECFG_IM_WIDTH 13 +#define CSR_ECFG_IM (0x1fffUL << CSR_ECFG_IM_SHIFT) + +#define CSR_ECFG_IPMASK 0x00001fff + +#define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ +#define CSR_ESTAT_ESUBCODE_SHIFT 22 +#define CSR_ESTAT_ESUBCODE_WIDTH 9 +#define CSR_ESTAT_ESUBCODE (0x1ffULL << CSR_ESTAT_ESUBCODE_SHIFT) +#define CSR_ESTAT_EXC_SH 16 +#define CSR_ESTAT_EXC_WIDTH 5 +#define CSR_ESTAT_EXC (0x1fULL << CSR_ESTAT_EXC_SH) +#define CSR_ESTAT_IS_SHIFT 0 +#define CSR_ESTAT_IS_WIDTH 15 +#define CSR_ESTAT_IS (0x7fffULL << CSR_ESTAT_IS_SHIFT) + +#define CSR_ESTAT_IPMASK 0x00001fff + +/* + * ExStatus.ExcCode + */ +#define EXCCODE_INT_START 64 +#define EXCCODE_RSV 0 /* Reserved */ +#define EXCCODE_TLBL 1 /* TLB miss on a load */ +#define EXCCODE_TLBS 2 /* TLB miss on a store */ +#define EXCCODE_TLBI 3 /* TLB miss on a ifetch */ +#define EXCCODE_TLBM 4 /* TLB modified fault */ +#define EXCCODE_TLBRI 5 /* TLB Read-Inhibit exception */ +#define EXCCODE_TLBXI 6 /* TLB Execution-Inhibit exception */ +#define EXCCODE_TLBPE 7 /* TLB Privilege Error */ +#define EXCCODE_ADE 8 /* Address Error */ +#define EXCCODE_ALE 9 /* Unalign Access */ +#define EXCCODE_OOB 10 /* Out of bounds */ +#define EXCCODE_SYS 11 /* System call */ +#define EXCCODE_BP 12 /* Breakpoint */ +#define EXCCODE_INE 13 /* Inst. Not Exist */ +#define EXCCODE_IPE 14 /* Inst. Privileged Error */ +#define EXCCODE_FPDIS 15 /* FPU Disabled */ +#define EXCCODE_LSXDIS 16 /* LSX Disabled */ +#define EXCCODE_LASXDIS 17 /* LASX Disabled */ +#define EXCCODE_FPE 18 /* Floating Point Exception */ +#define EXCCODE_WATCH 19 /* Watch address reference */ +#define EXCCODE_BTDIS 20 /* Binary Trans. Disabled */ +#define EXCCODE_BTE 21 /* Binary Trans. Exception */ +#define EXCCODE_PSI 22 /* Guest Privileged Error */ +#define EXCCODE_HYP 23 /* Hypercall */ +#define EXCCODE_GCM 24 /* Guest CSR modified */ +#define EXCCODE_SE 25 /* Security*/ + +#define LOONGARCH_CSR_ERA 0x6 /* Error PC */ + +#define LOONGARCH_CSR_BADV 0x7 /* Bad virtual address */ + +#define LOONGARCH_CSR_BADI 0x8 /* Bad instruction */ + +#define LOONGARCH_CSR_EEPN 0xc /* Exception enter base address */ + +/* TLB related CSR register */ +#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP*/ +#define CSR_TLBIDX_EHINV_SHIFT 31 +#define CSR_TLBIDX_EHINV (0x1ULL << CSR_TLBIDX_EHINV_SHIFT) +#define CSR_TLBIDX_PS_SHIFT 24 +#define CSR_TLBIDX_PS_WIDTH 6 +#define CSR_TLBIDX_PS (0x3fULL << CSR_TLBIDX_PS_SHIFT) +#define CSR_TLBIDX_IDX_SHIFT 0 +#define CSR_TLBIDX_IDX_WIDTH 12 +#define CSR_TLBIDX_IDX (0xfffULL << CSR_TLBIDX_IDX_SHIFT) +#define CSR_TLBIDX_SIZEM 0x3f000000 +#define CSR_TLBIDX_SIZE CSR_TLBIDX_PS_SHIFT +#define CSR_TLBIDX_IDXM 0xfff + +#define LOONGARCH_CSR_TLBEHI 0x11 /* TLB EntryHi without ASID */ + +#define LOONGARCH_CSR_TLBELO0 0x12 /* TLB EntryLo0 */ +#define CSR_TLBLO0_RPLV_SHIFT 63 +#define CSR_TLBLO0_RPLV (0x1ULL << CSR_TLBLO0_RPLV_SHIFT) +#define CSR_TLBLO0_XI_SHIFT 62 +#define CSR_TLBLO0_XI (0x1ULL << CSR_TLBLO0_XI_SHIFT) +#define CSR_TLBLO0_RI_SHIFT 61 +#define CSR_TLBLO0_RI (0x1ULL << CSR_TLBLO0_RI_SHIFT) +#define CSR_TLBLO0_PPN_SHIFT 12 +#define CSR_TLBLO0_PPN_WIDTH 36 /* ignore lower 12bits */ +#define CSR_TLBLO0_PPN (0xfffffffffULL << CSR_TLBLO0_PPN_SHIFT) +#define CSR_TLBLO0_GLOBAL_SHIFT 6 +#define CSR_TLBLO0_GLOBAL (0x1ULL << CSR_TLBLO0_GLOBAL_SHIFT) +#define CSR_TLBLO0_CCA_SHIFT 4 +#define CSR_TLBLO0_CCA_WIDTH 2 +#define CSR_TLBLO0_CCA (0x3ULL << CSR_TLBLO0_CCA_SHIFT) +#define CSR_TLBLO0_PLV_SHIFT 2 +#define CSR_TLBLO0_PLV_WIDTH 2 +#define CSR_TLBLO0_PLV (0x3ULL << CSR_TLBLO0_PLV_SHIFT) +#define CSR_TLBLO0_WE_SHIFT 1 +#define CSR_TLBLO0_WE (0x1ULL << CSR_TLBLO0_WE_SHIFT) +#define CSR_TLBLO0_V_SHIFT 0 +#define CSR_TLBLO0_V (0x1ULL << CSR_TLBLO0_V_SHIFT) + +#define LOONGARCH_CSR_TLBELO1 0x13 /* TLB EntryLo1 */ +#define CSR_TLBLO1_RPLV_SHIFT 63 +#define CSR_TLBLO1_RPLV (0x1ULL << CSR_TLBLO1_RPLV_SHIFT) +#define CSR_TLBLO1_XI_SHIFT 62 +#define CSR_TLBLO1_XI (0x1ULL << CSR_TLBLO1_XI_SHIFT) +#define CSR_TLBLO1_RI_SHIFT 61 +#define CSR_TLBLO1_RI (0x1ULL << CSR_TLBLO1_RI_SHIFT) +#define CSR_TLBLO1_PPN_SHIFT 12 +#define CSR_TLBLO1_PPN_WIDTH 36 +#define CSR_TLBLO1_PPN (0xfffffffffULL << CSR_TLBLO1_PPN_SHIFT) +#define CSR_TLBLO1_GLOBAL_SHIFT 6 +#define CSR_TLBLO1_GLOBAL (0x1ULL << CSR_TLBLO1_GLOBAL_SHIFT) +#define CSR_TLBLO1_CCA_SHIFT 4 +#define CSR_TLBLO1_CCA_WIDTH 2 +#define CSR_TLBLO1_CCA (0x3ULL << CSR_TLBLO1_CCA_SHIFT) +#define CSR_TLBLO1_PLV_SHIFT 2 +#define CSR_TLBLO1_PLV_WIDTH 2 +#define CSR_TLBLO1_PLV (0x3ULL << CSR_TLBLO1_PLV_SHIFT) +#define CSR_TLBLO1_WE_SHIFT 1 +#define CSR_TLBLO1_WE (0x1ULL << CSR_TLBLO1_WE_SHIFT) +#define CSR_TLBLO1_V_SHIFT 0 +#define CSR_TLBLO1_V (0x1ULL << CSR_TLBLO1_V_SHIFT) + +#define LOONGARCH_CSR_ASID 0x18 /* 64 ASID */ +#define CSR_ASID_BIT_SHIFT 16 /* ASIDBits */ +#define CSR_ASID_BIT_WIDTH 8 +#define CSR_ASID_BIT (0xffULL << CSR_ASID_BIT_SHIFT) +#define CSR_ASID_ASID_SHIFT 0 +#define CSR_ASID_ASID_WIDTH 10 +#define CSR_ASID_ASID (0x3ffULL << CSR_ASID_ASID_SHIFT) + +/* Page table base address when badv[47] = 0 */ +#define LOONGARCH_CSR_PGDL 0x19 +/* Page table base address when badv[47] = 1 */ +#define LOONGARCH_CSR_PGDH 0x1a + +#define LOONGARCH_CSR_PGD 0x1b /* Page table base */ + +#define LOONGARCH_CSR_PWCTL0 0x1c /* PWCtl0 */ +#define CSR_PWCTL0_PTEW_SHIFT 30 +#define CSR_PWCTL0_PTEW_WIDTH 2 +#define CSR_PWCTL0_PTEW (0x3ULL << CSR_PWCTL0_PTEW_SHIFT) +#define CSR_PWCTL0_DIR1WIDTH_SHIFT 25 +#define CSR_PWCTL0_DIR1WIDTH_WIDTH 5 +#define CSR_PWCTL0_DIR1WIDTH (0x1fULL << CSR_PWCTL0_DIR1WIDTH_SHIFT) +#define CSR_PWCTL0_DIR1BASE_SHIFT 20 +#define CSR_PWCTL0_DIR1BASE_WIDTH 5 +#define CSR_PWCTL0_DIR1BASE (0x1fULL << CSR_PWCTL0_DIR1BASE_SHIFT) +#define CSR_PWCTL0_DIR0WIDTH_SHIFT 15 +#define CSR_PWCTL0_DIR0WIDTH_WIDTH 5 +#define CSR_PWCTL0_DIR0WIDTH (0x1fULL << CSR_PWCTL0_DIR0WIDTH_SHIFT) +#define CSR_PWCTL0_DIR0BASE_SHIFT 10 +#define CSR_PWCTL0_DIR0BASE_WIDTH 5 +#define CSR_PWCTL0_DIR0BASE (0x1fULL << CSR_PWCTL0_DIR0BASE_SHIFT) +#define CSR_PWCTL0_PTWIDTH_SHIFT 5 +#define CSR_PWCTL0_PTWIDTH_WIDTH 5 +#define CSR_PWCTL0_PTWIDTH (0x1fULL << CSR_PWCTL0_PTWIDTH_SHIFT) +#define CSR_PWCTL0_PTBASE_SHIFT 0 +#define CSR_PWCTL0_PTBASE_WIDTH 5 +#define CSR_PWCTL0_PTBASE (0x1fULL << CSR_PWCTL0_PTBASE_SHIFT) + +#define LOONGARCH_CSR_PWCTL1 0x1d /* PWCtl1 */ +#define CSR_PWCTL1_DIR3WIDTH_SHIFT 18 +#define CSR_PWCTL1_DIR3WIDTH_WIDTH 5 +#define CSR_PWCTL1_DIR3WIDTH (0x1fULL << CSR_PWCTL1_DIR3WIDTH_SHIFT) +#define CSR_PWCTL1_DIR3BASE_SHIFT 12 +#define CSR_PWCTL1_DIR3BASE_WIDTH 5 +#define CSR_PWCTL1_DIR3BASE (0x1fULL << CSR_PWCTL0_DIR3BASE_SHIFT) +#define CSR_PWCTL1_DIR2WIDTH_SHIFT 6 +#define CSR_PWCTL1_DIR2WIDTH_WIDTH 5 +#define CSR_PWCTL1_DIR2WIDTH (0x1fULL << CSR_PWCTL1_DIR2WIDTH_SHIFT) +#define CSR_PWCTL1_DIR2BASE_SHIFT 0 +#define CSR_PWCTL1_DIR2BASE_WIDTH 5 +#define CSR_PWCTL1_DIR2BASE (0x1fULL << CSR_PWCTL0_DIR2BASE_SHIFT) + +#define LOONGARCH_CSR_STLBPGSIZE 0x1e +#define CSR_STLBPGSIZE_PS_WIDTH 6 +#define CSR_STLBPGSIZE_PS (0x3f) + +#define LOONGARCH_CSR_RVACFG 0x1f +#define CSR_RVACFG_RDVA_WIDTH 4 +#define CSR_RVACFG_RDVA (0xf) + +/* Config CSR registers */ +#define LOONGARCH_CSR_CPUID 0x20 /* CPU core number */ +#define CSR_CPUID_CID_WIDTH 9 +#define CSR_CPUID_CID (0x1ff) + +#define LOONGARCH_CSR_PRCFG1 0x21 /* Config1 */ +#define CSR_CONF1_VSMAX_SHIFT 12 +#define CSR_CONF1_VSMAX_WIDTH 3 +#define CSR_CONF1_VSMAX (7ULL << CSR_CONF1_VSMAX_SHIFT) +#define CSR_CONF1_TMRBITS_SHIFT 4 +#define CSR_CONF1_TMRBITS_WIDTH 8 +#define CSR_CONF1_TMRBITS (0xffULL << CSR_CONF1_TMRBITS_SHIFT) +#define CSR_CONF1_KSNUM_SHIFT 0 +#define CSR_CONF1_KSNUM_WIDTH 4 +#define CSR_CONF1_KSNUM (0x8) + +#define LOONGARCH_CSR_PRCFG2 0x22 /* Config2 */ +#define CSR_CONF2_PGMASK_SUPP 0x3ffff000 + +#define LOONGARCH_CSR_PRCFG3 0x23 /* Config3 */ +#define CSR_CONF3_STLBIDX_SHIFT 20 +#define CSR_CONF3_STLBIDX_WIDTH 6 +#define CSR_CONF3_STLBIDX (0x3fULL << CSR_CONF3_STLBIDX_SHIFT) +#define CSR_CONF3_STLBWAYS_SHIFT 12 +#define CSR_CONF3_STLBWAYS_WIDTH 8 +#define CSR_CONF3_STLBWAYS (0xffULL << CSR_CONF3_STLBWAYS_SHIFT) +#define CSR_CONF3_MTLBSIZE_SHIFT 4 +#define CSR_CONF3_MTLBSIZE_WIDTH 8 +#define CSR_CONF3_MTLBSIZE (0xffULL << CSR_CONF3_MTLBSIZE_SHIFT) +#define CSR_CONF3_TLBORG_SHIFT 0 +#define CSR_CONF3_TLBORG_WIDTH 4 +#define CSR_CONF3_TLBORG (0xfULL << CSR_CONF3_TLBORG_SHIFT) + +/* Kscratch registers */ +#define LOONGARCH_CSR_KS0 0x30 +#define LOONGARCH_CSR_KS1 0x31 +#define LOONGARCH_CSR_KS2 0x32 +#define LOONGARCH_CSR_KS3 0x33 +#define LOONGARCH_CSR_KS4 0x34 +#define LOONGARCH_CSR_KS5 0x35 +#define LOONGARCH_CSR_KS6 0x36 +#define LOONGARCH_CSR_KS7 0x37 +#define LOONGARCH_CSR_KS8 0x38 + +/* Timer registers */ +#define LOONGARCH_CSR_TMID 0x40 /* Timer ID */ + +#define LOONGARCH_CSR_TCFG 0x41 /* Timer config */ +#define CSR_TCFG_VAL_SHIFT 2 +#define CSR_TCFG_VAL_WIDTH 48 +#define CSR_TCFG_VAL (0x3fffffffffffULL << CSR_TCFG_VAL_SHIFT) +#define CSR_TCFG_PERIOD_SHIFT 1 +#define CSR_TCFG_PERIOD (0x1ULL << CSR_TCFG_PERIOD_SHIFT) +#define CSR_TCFG_EN (0x1) + +#define LOONGARCH_CSR_TVAL 0x42 /* Timer value */ + +#define LOONGARCH_CSR_CNTC 0x43 /* Timer offset */ + +#define LOONGARCH_CSR_TINTCLR 0x44 /* Timer interrupt clear */ +#define CSR_TINTCLR_TI_SHIFT 0 +#define CSR_TINTCLR_TI (1 << CSR_TINTCLR_TI_SHIFT) + +/* LLBCTL register */ +#define LOONGARCH_CSR_LLBIT 0x60 /* LLBit control */ +#define CSR_LLBIT_ROLLB_SHIFT 0 +#define CSR_LLBIT_ROLLB (1ULL << CSR_LLBIT_ROLLB_SHIFT) +#define CSR_LLBIT_WCLLB_SHIFT 1 +#define CSR_LLBIT_WCLLB (1ULL << CSR_LLBIT_WCLLB_SHIFT) +#define CSR_LLBIT_KLO_SHIFT 2 +#define CSR_LLBIT_KLO (1ULL << CSR_LLBIT_KLO_SHIFT) + +/* Implement dependent */ +#define LOONGARCH_CSR_IMPCTL1 0x80 /* Loongarch config1 */ +#define CSR_MISPEC_SHIFT 20 +#define CSR_MISPEC_WIDTH 8 +#define CSR_MISPEC (0xffULL << CSR_MISPEC_SHIFT) +#define CSR_SSEN_SHIFT 18 +#define CSR_SSEN (1ULL << CSR_SSEN_SHIFT) +#define CSR_SCRAND_SHIFT 17 +#define CSR_SCRAND (1ULL << CSR_SCRAND_SHIFT) +#define CSR_LLEXCL_SHIFT 16 +#define CSR_LLEXCL (1ULL << CSR_LLEXCL_SHIFT) +#define CSR_DISVC_SHIFT 15 +#define CSR_DISVC (1ULL << CSR_DISVC_SHIFT) +#define CSR_VCLRU_SHIFT 14 +#define CSR_VCLRU (1ULL << CSR_VCLRU_SHIFT) +#define CSR_DCLRU_SHIFT 13 +#define CSR_DCLRU (1ULL << CSR_DCLRU_SHIFT) +#define CSR_FASTLDQ_SHIFT 12 +#define CSR_FASTLDQ (1ULL << CSR_FASTLDQ_SHIFT) +#define CSR_USERCAC_SHIFT 11 +#define CSR_USERCAC (1ULL << CSR_USERCAC_SHIFT) +#define CSR_ANTI_MISPEC_SHIFT 10 +#define CSR_ANTI_MISPEC (1ULL << CSR_ANTI_MISPEC_SHIFT) +#define CSR_ANTI_FLUSHSFB_SHIFT 9 +#define CSR_ANTI_FLUSHSFB (1ULL << CSR_ANTI_FLUSHSFB_SHIFT) +#define CSR_STFILL_SHIFT 8 +#define CSR_STFILL (1ULL << CSR_STFILL_SHIFT) +#define CSR_LIFEP_SHIFT 7 +#define CSR_LIFEP (1ULL << CSR_LIFEP_SHIFT) +#define CSR_LLSYNC_SHIFT 6 +#define CSR_LLSYNC (1ULL << CSR_LLSYNC_SHIFT) +#define CSR_BRBTDIS_SHIFT 5 +#define CSR_BRBTDIS (1ULL << CSR_BRBTDIS_SHIFT) +#define CSR_RASDIS_SHIFT 4 +#define CSR_RASDIS (1ULL << CSR_RASDIS_SHIFT) +#define CSR_STPRE_SHIFT 2 +#define CSR_STPRE_WIDTH 2 +#define CSR_STPRE (3ULL << CSR_STPRE_SHIFT) +#define CSR_INSTPRE_SHIFT 1 +#define CSR_INSTPRE (1ULL << CSR_INSTPRE_SHIFT) +#define CSR_DATAPRE_SHIFT 0 +#define CSR_DATAPRE (1ULL << CSR_DATAPRE_SHIFT) + +#define LOONGARCH_CSR_IMPCTL2 0x81 /* loongarch config2 */ +#define CSR_IMPCTL2_MTLB_SHIFT 0 +#define CSR_IMPCTL2_MTLB (1ULL << CSR_IMPCTL2_MTLB_SHIFT) +#define CSR_IMPCTL2_STLB_SHIFT 1 +#define CSR_IMPCTL2_STLB (1ULL << CSR_IMPCTL2_STLB_SHIFT) +#define CSR_IMPCTL2_DTLB_SHIFT 2 +#define CSR_IMPCTL2_DTLB (1ULL << CSR_IMPCTL2_DTLB_SHIFT) +#define CSR_IMPCTL2_ITLB_SHIFT 3 +#define CSR_IMPCTL2_ITLB (1ULL << CSR_IMPCTL2_ITLB_SHIFT) +#define CSR_IMPCTL2_BTAC_SHIFT 4 +#define CSR_IMPCTL2_BTAC (1ULL << CSR_IMPCTL2_BTAC_SHIFT) + +#define LOONGARCH_CSR_GNMI 0x82 + +/* TLB refill registers */ +#define LOONGARCH_CSR_TLBRENT 0x88 /* TLB refill exception address */ +#define LOONGARCH_CSR_TLBRBADV 0x89 /* TLB refill badvaddr */ +#define LOONGARCH_CSR_TLBRERA 0x8a /* TLB refill ERA */ +#define LOONGARCH_CSR_TLBRSAVE 0x8b /* KScratch for TLB refill */ +#define LOONGARCH_CSR_TLBRELO0 0x8c /* TLB refill entrylo0 */ +#define LOONGARCH_CSR_TLBRELO1 0x8d /* TLB refill entrylo1 */ +#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */ +#define LOONGARCH_CSR_TLBRPRMD 0x8f /* TLB refill mode info */ + +/* Machine error registers */ +#define LOONGARCH_CSR_ERRCTL 0x90 /* ERRCTL */ +#define LOONGARCH_CSR_ERRINFO 0x91 /* Error info1 */ +#define LOONGARCH_CSR_ERRINFO1 0x92 /* Error info2 */ +#define LOONGARCH_CSR_ERRENT 0x93 /* Error exception base address */ +#define LOONGARCH_CSR_ERRERA 0x94 /* Error exception PC */ +#define LOONGARCH_CSR_ERRSAVE 0x95 /* KScratch machine error exception */ + +#define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */ + +/* Shadow MCSR : 0xc0 ~ 0xff */ +#define LOONGARCH_CSR_MCSR0 0xc0 /* CPUCFG0 and CPUCFG1 */ +#define MCSR0_INT_IMPL_SHIFT 58 +#define MCSR0_INT_IMPL 0 +#define MCSR0_IOCSR_BRD_SHIFT 57 +#define MCSR0_IOCSR_BRD (1ULL << MCSR0_IOCSR_BRD_SHIFT) +#define MCSR0_HUGEPG_SHIFT 56 +#define MCSR0_HUGEPG (1ULL << MCSR0_HUGEPG_SHIFT) +#define MCSR0_RPLVTLB_SHIFT 55 +#define MCSR0_RPLVTLB (1ULL << MCSR0_RPLVTLB_SHIFT) +#define MCSR0_EXEPROT_SHIFT 54 +#define MCSR0_EXEPROT (1ULL << MCSR0_EXEPROT_SHIFT) +#define MCSR0_RI_SHIFT 53 +#define MCSR0_RI (1ULL << MCSR0_RI_SHIFT) +#define MCSR0_UAL_SHIFT 52 +#define MCSR0_UAL (1ULL << MCSR0_UAL_SHIFT) +#define MCSR0_VABIT_SHIFT 44 +#define MCSR0_VABIT_WIDTH 8 +#define MCSR0_VABIT (0xffULL << MCSR0_VABIT_SHIFT) +#define VABIT_DEFAULT 0x2f +#define MCSR0_PABIT_SHIFT 36 +#define MCSR0_PABIT_WIDTH 8 +#define MCSR0_PABIT (0xffULL << MCSR0_PABIT_SHIFT) +#define PABIT_DEFAULT 0x2f +#define MCSR0_IOCSR_SHIFT 35 +#define MCSR0_IOCSR (1ULL << MCSR0_IOCSR_SHIFT) +#define MCSR0_PAGING_SHIFT 34 +#define MCSR0_PAGING (1ULL << MCSR0_PAGING_SHIFT) +#define MCSR0_GR64_SHIFT 33 +#define MCSR0_GR64 (1ULL << MCSR0_GR64_SHIFT) +#define GR64_DEFAULT 1 +#define MCSR0_GR32_SHIFT 32 +#define MCSR0_GR32 (1ULL << MCSR0_GR32_SHIFT) +#define GR32_DEFAULT 0 +#define MCSR0_PRID_WIDTH 32 +#define MCSR0_PRID 0x14C010 + +#define LOONGARCH_CSR_MCSR1 0xc1 /* CPUCFG2 and CPUCFG3 */ +#define MCSR1_HPFOLD_SHIFT 43 +#define MCSR1_HPFOLD (1ULL << MCSR1_HPFOLD_SHIFT) +#define MCSR1_SPW_LVL_SHIFT 40 +#define MCSR1_SPW_LVL_WIDTH 3 +#define MCSR1_SPW_LVL (7ULL << MCSR1_SPW_LVL_SHIFT) +#define MCSR1_ICACHET_SHIFT 39 +#define MCSR1_ICACHET (1ULL << MCSR1_ICACHET_SHIFT) +#define MCSR1_ITLBT_SHIFT 38 +#define MCSR1_ITLBT (1ULL << MCSR1_ITLBT_SHIFT) +#define MCSR1_LLDBAR_SHIFT 37 +#define MCSR1_LLDBAR (1ULL << MCSR1_LLDBAR_SHIFT) +#define MCSR1_SCDLY_SHIFT 36 +#define MCSR1_SCDLY (1ULL << MCSR1_SCDLY_SHIFT) +#define MCSR1_LLEXC_SHIFT 35 +#define MCSR1_LLEXC (1ULL << MCSR1_LLEXC_SHIFT) +#define MCSR1_UCACC_SHIFT 34 +#define MCSR1_UCACC (1ULL << MCSR1_UCACC_SHIFT) +#define MCSR1_SFB_SHIFT 33 +#define MCSR1_SFB (1ULL << MCSR1_SFB_SHIFT) +#define MCSR1_CCDMA_SHIFT 32 +#define MCSR1_CCDMA (1ULL << MCSR1_CCDMA_SHIFT) +#define MCSR1_LAMO_SHIFT 22 +#define MCSR1_LAMO (1ULL << MCSR1_LAMO_SHIFT) +#define MCSR1_LSPW_SHIFT 21 +#define MCSR1_LSPW (1ULL << MCSR1_LSPW_SHIFT) +#define MCSR1_LOONGARCHBT_SHIFT 20 +#define MCSR1_LOONGARCHBT (1ULL << MCSR1_LOONGARCHBT_SHIFT) +#define MCSR1_ARMBT_SHIFT 19 +#define MCSR1_ARMBT (1ULL << MCSR1_ARMBT_SHIFT) +#define MCSR1_X86BT_SHIFT 18 +#define MCSR1_X86BT (1ULL << MCSR1_X86BT_SHIFT) +#define MCSR1_LLFTPVERS_SHIFT 15 +#define MCSR1_LLFTPVERS_WIDTH 3 +#define MCSR1_LLFTPVERS (7ULL << MCSR1_LLFTPVERS_SHIFT) +#define MCSR1_LLFTP_SHIFT 14 +#define MCSR1_LLFTP (1ULL << MCSR1_LLFTP_SHIFT) +#define MCSR1_VZVERS_SHIFT 11 +#define MCSR1_VZVERS_WIDTH 3 +#define MCSR1_VZVERS (7ULL << MCSR1_VZVERS_SHIFT) +#define MCSR1_VZ_SHIFT 10 +#define MCSR1_VZ (1ULL << MCSR1_VZ_SHIFT) +#define MCSR1_CRYPTO_SHIFT 9 +#define MCSR1_CRYPTO (1ULL << MCSR1_CRYPTO_SHIFT) +#define MCSR1_COMPLEX_SHIFT 8 +#define MCSR1_COMPLEX (1ULL << MCSR1_COMPLEX_SHIFT) +#define MCSR1_LASX_SHIFT 7 +#define MCSR1_LASX (1ULL << MCSR1_LASX_SHIFT) +#define MCSR1_LSX_SHIFT 6 +#define MCSR1_LSX (1ULL << MCSR1_LSX_SHIFT) +#define MCSR1_FPVERS_SHIFT 3 +#define MCSR1_FPVERS_WIDTH 3 +#define MCSR1_FPVERS (7ULL << MCSR1_FPVERS_SHIFT) +#define MCSR1_FPDP_SHIFT 2 +#define MCSR1_FPDP (1ULL << MCSR1_FPDP_SHIFT) +#define MCSR1_FPSP_SHIFT 1 +#define MCSR1_FPSP (1ULL << MCSR1_FPSP_SHIFT) +#define MCSR1_FP_SHIFT 0 +#define MCSR1_FP (1ULL << MCSR1_FP_SHIFT) + +#define LOONGARCH_CSR_MCSR2 0xc2 /* CPUCFG4 and CPUCFG5 */ +#define MCSR2_CCDIV_SHIFT 48 +#define MCSR2_CCDIV_WIDTH 16 +#define MCSR2_CCDIV (0xffffULL << MCSR2_CCDIV_SHIFT) +#define MCSR2_CCMUL_SHIFT 32 +#define MCSR2_CCMUL_WIDTH 16 +#define MCSR2_CCMUL (0xffffULL << MCSR2_CCMUL_SHIFT) +#define MCSR2_CCFREQ_WIDTH 32 +#define MCSR2_CCFREQ (0xffffffff) +#define CCFREQ_DEFAULT 0x5f5e100 /* 100MHZ */ + +#define LOONGARCH_CSR_MCSR3 0xc3 /* CPUCFG6 */ +#define MCSR3_UPM_SHIFT 14 +#define MCSR3_UPM (1ULL << MCSR3_UPM_SHIFT) +#define MCSR3_PMBITS_SHIFT 8 +#define MCSR3_PMBITS_WIDTH 6 +#define MCSR3_PMBITS (0x3fULL << MCSR3_PMBITS_SHIFT) +#define PMBITS_DEFAULT 0x40 +#define MCSR3_PMNUM_SHIFT 4 +#define MCSR3_PMNUM_WIDTH 4 +#define MCSR3_PMNUM (0xfULL << MCSR3_PMNUM_SHIFT) +#define MCSR3_PAMVER_SHIFT 1 +#define MCSR3_PAMVER_WIDTH 3 +#define MCSR3_PAMVER (0x7ULL << MCSR3_PAMVER_SHIFT) +#define MCSR3_PMP_SHIFT 0 +#define MCSR3_PMP (1ULL << MCSR3_PMP_SHIFT) + +#define LOONGARCH_CSR_MCSR8 0xc8 /* CPUCFG16 and CPUCFG17 */ +#define MCSR8_L1I_SIZE_SHIFT 56 +#define MCSR8_L1I_SIZE_WIDTH 7 +#define MCSR8_L1I_SIZE (0x7fULL << MCSR8_L1I_SIZE_SHIFT) +#define MCSR8_L1I_IDX_SHIFT 48 +#define MCSR8_L1I_IDX_WIDTH 8 +#define MCSR8_L1I_IDX (0xffULL << MCSR8_L1I_IDX_SHIFT) +#define MCSR8_L1I_WAY_SHIFT 32 +#define MCSR8_L1I_WAY_WIDTH 16 +#define MCSR8_L1I_WAY (0xffffULL << MCSR8_L1I_WAY_SHIFT) +#define MCSR8_L3DINCL_SHIFT 16 +#define MCSR8_L3DINCL (1ULL << MCSR8_L3DINCL_SHIFT) +#define MCSR8_L3DPRIV_SHIFT 15 +#define MCSR8_L3DPRIV (1ULL << MCSR8_L3DPRIV_SHIFT) +#define MCSR8_L3DPRE_SHIFT 14 +#define MCSR8_L3DPRE (1ULL << MCSR8_L3DPRE_SHIFT) +#define MCSR8_L3IUINCL_SHIFT 13 +#define MCSR8_L3IUINCL (1ULL << MCSR8_L3IUINCL_SHIFT) +#define MCSR8_L3IUPRIV_SHIFT 12 +#define MCSR8_L3IUPRIV (1ULL << MCSR8_L3IUPRIV_SHIFT) +#define MCSR8_L3IUUNIFY_SHIFT 11 +#define MCSR8_L3IUUNIFY (1ULL << MCSR8_L3IUUNIFY_SHIFT) +#define MCSR8_L3IUPRE_SHIFT 10 +#define MCSR8_L3IUPRE (1ULL << MCSR8_L3IUPRE_SHIFT) +#define MCSR8_L2DINCL_SHIFT 9 +#define MCSR8_L2DINCL (1ULL << MCSR8_L2DINCL_SHIFT) +#define MCSR8_L2DPRIV_SHIFT 8 +#define MCSR8_L2DPRIV (1ULL << MCSR8_L2DPRIV_SHIFT) +#define MCSR8_L2DPRE_SHIFT 7 +#define MCSR8_L2DPRE (1ULL << MCSR8_L2DPRE_SHIFT) +#define MCSR8_L2IUINCL_SHIFT 6 +#define MCSR8_L2IUINCL (1ULL << MCSR8_L2IUINCL_SHIFT) +#define MCSR8_L2IUPRIV_SHIFT 5 +#define MCSR8_L2IUPRIV (1ULL << MCSR8_L2IUPRIV_SHIFT) +#define MCSR8_L2IUUNIFY_SHIFT 4 +#define MCSR8_L2IUUNIFY (1ULL << MCSR8_L2IUUNIFY_SHIFT) +#define MCSR8_L2IUPRE_SHIFT 3 +#define MCSR8_L2IUPRE (1ULL << MCSR8_L2IUPRE_SHIFT) +#define MCSR8_L1DPRE_SHIFT 2 +#define MCSR8_L1DPRE (1ULL << MCSR8_L1DPRE_SHIFT) +#define MCSR8_L1IUUNIFY_SHIFT 1 +#define MCSR8_L1IUUNIFY (1ULL << MCSR8_L1IUUNIFY_SHIFT) +#define MCSR8_L1IUPRE_SHIFT 0 +#define MCSR8_L1IUPRE (1ULL << MCSR8_L1IUPRE_SHIFT) + +#define LOONGARCH_CSR_MCSR9 0xc9 /* CPUCFG18 and CPUCFG19 */ +#define MCSR9_L2U_SIZE_SHIFT 56 +#define MCSR9_L2U_SIZE_WIDTH 7 +#define MCSR9_L2U_SIZE (0x7fULL << MCSR9_L2U_SIZE_SHIFT) +#define MCSR9_L2U_IDX_SHIFT 48 +#define MCSR9_L2U_IDX_WIDTH 8 +#define MCSR9_L2U_IDX (0xffULL << MCSR9_IDX_LOG_SHIFT) +#define MCSR9_L2U_WAY_SHIFT 32 +#define MCSR9_L2U_WAY_WIDTH 16 +#define MCSR9_L2U_WAY (0xffffULL << MCSR9_L2U_WAY_SHIFT) +#define MCSR9_L1D_SIZE_SHIFT 24 +#define MCSR9_L1D_SIZE_WIDTH 7 +#define MCSR9_L1D_SIZE (0x7fULL << MCSR9_L1D_SIZE_SHIFT) +#define MCSR9_L1D_IDX_SHIFT 16 +#define MCSR9_L1D_IDX_WIDTH 8 +#define MCSR9_L1D_IDX (0xffULL << MCSR9_L1D_IDX_SHIFT) +#define MCSR9_L1D_WAY_SHIFT 0 +#define MCSR9_L1D_WAY_WIDTH 16 +#define MCSR9_L1D_WAY (0xffffULL << MCSR9_L1D_WAY_SHIFT) + +#define LOONGARCH_CSR_MCSR10 0xca /* CPUCFG20 */ +#define MCSR10_L3U_SIZE_SHIFT 24 +#define MCSR10_L3U_SIZE_WIDTH 7 +#define MCSR10_L3U_SIZE (0x7fULL << MCSR10_L3U_SIZE_SHIFT) +#define MCSR10_L3U_IDX_SHIFT 16 +#define MCSR10_L3U_IDX_WIDTH 8 +#define MCSR10_L3U_IDX (0xffULL << MCSR10_L3U_IDX_SHIFT) +#define MCSR10_L3U_WAY_SHIFT 0 +#define MCSR10_L3U_WAY_WIDTH 16 +#define MCSR10_L3U_WAY (0xffffULL << MCSR10_L3U_WAY_SHIFT) + +#define LOONGARCH_CSR_MCSR24 0xf0 /* CPUCFG48 */ +#define MCSR24_RAMCG_SHIFT 3 +#define MCSR24_RAMCG (1ULL << MCSR24_RAMCG_SHIFT) +#define MCSR24_VFPUCG_SHIFT 2 +#define MCSR24_VFPUCG (1ULL << MCSR24_VFPUCG_SHIFT) +#define MCSR24_NAPEN_SHIFT 1 +#define MCSR24_NAPEN (1ULL << MCSR24_NAPEN_SHIFT) +#define MCSR24_MCSRLOCK_SHIFT 0 +#define MCSR24_MCSRLOCK (1ULL << MCSR24_MCSRLOCK_SHIFT) + +/* Uncached accelerate windows registers */ +#define LOONGARCH_CSR_UCAWIN 0x100 /* read only info */ +#define LOONGARCH_CSR_UCAWIN0_LO 0x102 /* win0 low */ +#define LOONGARCH_CSR_UCAWIN0_HI 0x103 /* win0 high */ +#define LOONGARCH_CSR_UCAWIN1_LO 0x104 /* win1 low */ +#define LOONGARCH_CSR_UCAWIN1_HI 0x105 /* win1 high */ +#define LOONGARCH_CSR_UCAWIN2_LO 0x106 /* win2 low */ +#define LOONGARCH_CSR_UCAWIN2_HI 0x107 /* win2 high */ +#define LOONGARCH_CSR_UCAWIN3_LO 0x108 /* win3 low */ +#define LOONGARCH_CSR_UCAWIN3_HI 0x109 /* win3 high */ + +/* Direct map windows registers */ +#define LOONGARCH_CSR_DMWIN0 0x180 /* direct map win0: MEM & IF */ +#define LOONGARCH_CSR_DMWIN1 0x181 /* direct map win1: MEM & IF */ +#define LOONGARCH_CSR_DMWIN2 0x182 /* direct map win2: MEM */ +#define LOONGARCH_CSR_DMWIN3 0x183 /* direct map win3: MEM */ + +/* Performance counter registers */ +#define LOONGARCH_CSR_PERFCTRL0 0x200 /* perf event 0 config */ +#define LOONGARCH_CSR_PERFCNTR0 0x201 /* perf event 0 count value */ +#define LOONGARCH_CSR_PERFCTRL1 0x202 /* perf event 1 config */ +#define LOONGARCH_CSR_PERFCNTR1 0x203 /* perf event 1 count value */ +#define LOONGARCH_CSR_PERFCTRL2 0x204 /* perf event 2 config */ +#define LOONGARCH_CSR_PERFCNTR2 0x205 /* perf event 2 count value */ +#define LOONGARCH_CSR_PERFCTRL3 0x206 /* perf event 3 config */ +#define LOONGARCH_CSR_PERFCNTR3 0x207 /* perf event 3 count value */ +#define CSR_PERFCTRL_PLV0 (1ULL << 16) +#define CSR_PERFCTRL_PLV1 (1ULL << 17) +#define CSR_PERFCTRL_PLV2 (1ULL << 18) +#define CSR_PERFCTRL_PLV3 (1ULL << 19) +#define CSR_PERFCTRL_IE (1ULL << 20) +#define CSR_PERFCTRL_EVENT 0x3ff + +/* CSR register */ +#define CPU_LOONGARCH_CSR \ + uint64_t CSR_CRMD; \ + uint64_t CSR_PRMD; \ + uint64_t CSR_EUEN; \ + uint64_t CSR_MISC; \ + uint64_t CSR_ECFG; \ + uint64_t CSR_ESTAT; \ + uint64_t CSR_ERA; \ + uint64_t CSR_BADV; \ + uint64_t CSR_BADI; \ + uint64_t CSR_EEPN; \ + uint64_t CSR_TLBIDX; \ + uint64_t CSR_TLBEHI; \ + uint64_t CSR_TLBELO0; \ + uint64_t CSR_TLBELO1; \ + uint64_t CSR_ASID; \ + uint64_t CSR_PGDL; \ + uint64_t CSR_PGDH; \ + uint64_t CSR_PGD; \ + uint64_t CSR_PWCTL0; \ + uint64_t CSR_PWCTL1; \ + uint64_t CSR_STLBPGSIZE; \ + uint64_t CSR_RVACFG; \ + uint64_t CSR_CPUID; \ + uint64_t CSR_PRCFG1; \ + uint64_t CSR_PRCFG2; \ + uint64_t CSR_PRCFG3; \ + uint64_t CSR_KS0; \ + uint64_t CSR_KS1; \ + uint64_t CSR_KS2; \ + uint64_t CSR_KS3; \ + uint64_t CSR_KS4; \ + uint64_t CSR_KS5; \ + uint64_t CSR_KS6; \ + uint64_t CSR_KS7; \ + uint64_t CSR_KS8; \ + uint64_t CSR_TMID; \ + uint64_t CSR_TCFG; \ + uint64_t CSR_TVAL; \ + uint64_t CSR_CNTC; \ + uint64_t CSR_TINTCLR; \ + uint64_t CSR_LLBIT; \ + uint64_t CSR_IMPCTL1; \ + uint64_t CSR_IMPCTL2; \ + uint64_t CSR_GNMI; \ + uint64_t CSR_TLBRENT; \ + uint64_t CSR_TLBRBADV; \ + uint64_t CSR_TLBRERA; \ + uint64_t CSR_TLBRSAVE; \ + uint64_t CSR_TLBRELO0; \ + uint64_t CSR_TLBRELO1; \ + uint64_t CSR_TLBREHI; \ + uint64_t CSR_TLBRPRMD; \ + uint64_t CSR_ERRCTL; \ + uint64_t CSR_ERRINFO; \ + uint64_t CSR_ERRINFO1; \ + uint64_t CSR_ERRENT; \ + uint64_t CSR_ERRERA; \ + uint64_t CSR_ERRSAVE; \ + uint64_t CSR_CTAG; \ + uint64_t CSR_MCSR0; \ + uint64_t CSR_MCSR1; \ + uint64_t CSR_MCSR2; \ + uint64_t CSR_MCSR3; \ + uint64_t CSR_MCSR8; \ + uint64_t CSR_MCSR9; \ + uint64_t CSR_MCSR10; \ + uint64_t CSR_MCSR24; \ + uint64_t CSR_UCAWIN; \ + uint64_t CSR_UCAWIN0_LO; \ + uint64_t CSR_UCAWIN0_HI; \ + uint64_t CSR_UCAWIN1_LO; \ + uint64_t CSR_UCAWIN1_HI; \ + uint64_t CSR_UCAWIN2_LO; \ + uint64_t CSR_UCAWIN2_HI; \ + uint64_t CSR_UCAWIN3_LO; \ + uint64_t CSR_UCAWIN3_HI; \ + uint64_t CSR_DMWIN0; \ + uint64_t CSR_DMWIN1; \ + uint64_t CSR_DMWIN2; \ + uint64_t CSR_DMWIN3; \ + uint64_t CSR_PERFCTRL0; \ + uint64_t CSR_PERFCNTR0; \ + uint64_t CSR_PERFCTRL1; \ + uint64_t CSR_PERFCNTR1; \ + uint64_t CSR_PERFCTRL2; \ + uint64_t CSR_PERFCNTR2; \ + uint64_t CSR_PERFCTRL3; \ + uint64_t CSR_PERFCNTR3; \ + +#endif From patchwork Mon Jun 28 12:04:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347797 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 46BA0C2B9F4 for ; Mon, 28 Jun 2021 12:10:17 +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 DB58561C49 for ; Mon, 28 Jun 2021 12:10:16 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DB58561C49 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:40828 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq5d-0002Jb-He for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:10:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51148) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0Z-0002AG-Sp for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:04:59 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45326 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0T-00015F-Lm for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:04:59 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S5; Mon, 28 Jun 2021 20:04:46 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 03/20] target/loongarch: Add core definition Date: Mon, 28 Jun 2021 20:04:28 +0800 Message-Id: <1624881885-31692-4-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S5 X-Coremail-Antispam: 1UD129KBjvAXoWfWF1DWF1DJw18uFWrAw4Dtwb_yoW5GF4fZo W8AFWfXa18Jr1Ska9a93sIg3y2qry8CF4DAa40vrWxWa18tay5GrykK34avFy7Xr95XrW7 CasFg3ZrJay7Crn3n29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch add target state header,target definitions and initialization routines. Signed-off-by: Song Gao --- target/loongarch/cpu-param.h | 21 ++ target/loongarch/cpu-qom.h | 41 ++++ target/loongarch/cpu.c | 451 +++++++++++++++++++++++++++++++++++++++++++ target/loongarch/cpu.h | 245 +++++++++++++++++++++++ target/loongarch/internal.h | 74 +++++++ 5 files changed, 832 insertions(+) create mode 100644 target/loongarch/cpu-param.h create mode 100644 target/loongarch/cpu-qom.h create mode 100644 target/loongarch/cpu.c create mode 100644 target/loongarch/cpu.h create mode 100644 target/loongarch/internal.h diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h new file mode 100644 index 0000000..582ee29 --- /dev/null +++ b/target/loongarch/cpu-param.h @@ -0,0 +1,21 @@ +/* + * LoongArch cpu parameters for qemu. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef LOONGARCH_CPU_PARAM_H +#define LOONGARCH_CPU_PARAM_H 1 + +#ifdef TARGET_LOONGARCH64 +#define TARGET_LONG_BITS 64 +#define TARGET_PHYS_ADDR_SPACE_BITS 48 +#define TARGET_VIRT_ADDR_SPACE_BITS 48 +#endif + +#define TARGET_PAGE_BITS 12 +#define NB_MMU_MODES 4 + +#endif diff --git a/target/loongarch/cpu-qom.h b/target/loongarch/cpu-qom.h new file mode 100644 index 0000000..ce14d13 --- /dev/null +++ b/target/loongarch/cpu-qom.h @@ -0,0 +1,41 @@ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef QEMU_LOONGARCH_CPU_QOM_H +#define QEMU_LOONGARCH_CPU_QOM_H + +#include "hw/core/cpu.h" +#include "qom/object.h" + +#ifdef TARGET_LOONGARCH64 +#define TYPE_LOONGARCH_CPU "loongarch64-cpu" +#else +#error LoongArch 32bit emulation is not implemented yet +#endif + +OBJECT_DECLARE_TYPE(LoongArchCPU, LoongArchCPUClass, + LOONGARCH_CPU) + +/** + * LoongArchCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * + * A LoongArch CPU model. + */ +struct LoongArchCPUClass { + /*< private >*/ + CPUClass parent_class; + /*< public >*/ + + DeviceRealize parent_realize; + DeviceReset parent_reset; + const struct loongarch_def_t *cpu_def; +}; + +#endif diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c new file mode 100644 index 0000000..b368e79 --- /dev/null +++ b/target/loongarch/cpu.c @@ -0,0 +1,451 @@ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "qemu/qemu-print.h" +#include "qapi/error.h" +#include "qemu/module.h" +#include "sysemu/qtest.h" +#include "exec/exec-all.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-clock.h" +#include "qapi/qapi-commands-machine-target.h" +#include "cpu.h" +#include "cpu-csr.h" +#include "cpu-qom.h" +#include "internal.h" + +static const char * const excp_names[EXCP_LAST + 1] = { + [EXCP_INTE] = "Interrupt error", + [EXCP_ADE] = "Address error", + [EXCP_SYSCALL] = "Syscall", + [EXCP_BREAK] = "Break", + [EXCP_FPDIS] = "FPU Disabled", + [EXCP_INE] = "Inst. Not Exist", + [EXCP_TRAP] = "Trap", + [EXCP_FPE] = "Floating Point Exception", + [EXCP_TLBM] = "TLB modified fault", + [EXCP_TLBL] = "TLB miss on a load", + [EXCP_TLBS] = "TLB miss on a store", + [EXCP_TLBPE] = "TLB Privilege Error", + [EXCP_TLBXI] = "TLB Execution-Inhibit exception", + [EXCP_TLBRI] = "TLB Read-Inhibit exception", +}; + +const char *loongarch_exception_name(int32_t exception) +{ + if (exception < 0 || exception > EXCP_LAST) { + return "unknown"; + } + return excp_names[exception]; +} + +target_ulong exception_resume_pc(CPULoongArchState *env) +{ + target_ulong bad_pc; + + bad_pc = env->active_tc.PC; + + return bad_pc; +} + +void QEMU_NORETURN do_raise_exception_err(CPULoongArchState *env, + uint32_t exception, + int error_code, + uintptr_t pc) +{ + CPUState *cs = env_cpu(env); + + qemu_log_mask(CPU_LOG_INT, "%s: %d (%s) %d\n", + __func__, + exception, + loongarch_exception_name(exception), + error_code); + cs->exception_index = exception; + env->error_code = error_code; + + cpu_loop_exit_restore(cs, pc); +} + +static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + env->active_tc.PC = value & ~(target_ulong)1; +} + +#ifdef CONFIG_TCG +static void loongarch_cpu_synchronize_from_tb(CPUState *cs, + const TranslationBlock *tb) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + env->active_tc.PC = tb->pc; + env->hflags &= ~LOONGARCH_HFLAG_BMASK; + env->hflags |= tb->flags & LOONGARCH_HFLAG_BMASK; +} +#endif /* CONFIG_TCG */ + +static bool loongarch_cpu_has_work(CPUState *cs) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + bool has_work = false; + + if ((cs->interrupt_request & CPU_INTERRUPT_HARD) && + cpu_loongarch_hw_interrupts_pending(env)) { + has_work = true; + } + + return has_work; +} + +#define LOONGARCH_CONFIG1 \ +((0x8 << CSR_CONF1_KSNUM_SHIFT) | (0x2f << CSR_CONF1_TMRBITS_SHIFT) | \ + (0x7 << CSR_CONF1_VSMAX_SHIFT)) + +#define LOONGARCH_CONFIG3 \ +((0x2 << CSR_CONF3_TLBORG_SHIFT) | (0x3f << CSR_CONF3_MTLBSIZE_SHIFT) | \ + (0x7 << CSR_CONF3_STLBWAYS_SHIFT) | (0x8 << CSR_CONF3_STLBIDX_SHIFT)) + +#define LOONGARCH_MCSR0 \ +((0x0UL << MCSR0_GR32_SHIFT) | (0x1UL << MCSR0_GR64_SHIFT) | \ + (0x1UL << MCSR0_PAGING_SHIFT) | (0x1UL << MCSR0_IOCSR_SHIFT) | \ + (0x2fUL << MCSR0_PABIT_SHIFT) | (0x2fUL << MCSR0_VABIT_SHIFT) | \ + (0x1UL << MCSR0_UAL_SHIFT) | (0x1UL << MCSR0_RI_SHIFT) | \ + (0x1UL << MCSR0_EXEPROT_SHIFT) | (0x1UL << MCSR0_RPLVTLB_SHIFT) | \ + (0x1UL << MCSR0_HUGEPG_SHIFT) | (0x1UL << MCSR0_IOCSR_BRD_SHIFT) | \ + (0x0UL << MCSR0_INT_IMPL_SHIFT) | MCSR0_PRID) + +#define LOONGARCH_MCSR1 \ +((0x1UL << MCSR1_FP_SHIFT) | (0x1UL << MCSR1_FPSP_SHIFT) | \ + (0x1UL << MCSR1_FPDP_SHIFT) | (0x1UL << MCSR1_FPVERS_SHIFT) | \ + (0x1UL << MCSR1_LSX_SHIFT) | (0x1UL << MCSR1_LASX_SHIFT) | \ + (0x1UL << MCSR1_COMPLEX_SHIFT) | (0x1UL << MCSR1_CRYPTO_SHIFT) | \ + (0x0UL << MCSR1_VZ_SHIFT) | (0x0UL << MCSR1_VZVERS_SHIFT) | \ + (0x1UL << MCSR1_LLFTP_SHIFT) | (0x1UL << MCSR1_LLFTPVERS_SHIFT) | \ + (0x0UL << MCSR1_X86BT_SHIFT) | (0x0UL << MCSR1_ARMBT_SHIFT) | \ + (0x0UL << MCSR1_LOONGARCHBT_SHIFT) | (0x1UL << MCSR1_LSPW_SHIFT) | \ + (0x1UL << MCSR1_LAMO_SHIFT) | (0x1UL << MCSR1_CCDMA_SHIFT) | \ + (0x1UL << MCSR1_SFB_SHIFT) | (0x1UL << MCSR1_UCACC_SHIFT) | \ + (0x1UL << MCSR1_LLEXC_SHIFT) | (0x1UL << MCSR1_SCDLY_SHIFT) | \ + (0x1UL << MCSR1_LLDBAR_SHIFT) | (0x1UL << MCSR1_ITLBT_SHIFT) | \ + (0x1UL << MCSR1_ICACHET_SHIFT) | (0x4UL << MCSR1_SPW_LVL_SHIFT) | \ + (0x1UL << MCSR1_HPFOLD_SHIFT)) + +#define LOONGARCH_MCSR2 \ +((0x1UL << MCSR2_CCMUL_SHIFT) | (0x1UL << MCSR2_CCDIV_SHIFT) | CCFREQ_DEFAULT) + +#define LOONGARCH_MCSR3 \ +((0x1UL << MCSR3_PMP_SHIFT) | (0x1UL << MCSR3_PAMVER_SHIFT) | \ + (0x3UL << MCSR3_PMNUM_SHIFT) | (0x3fUL < MCSR3_PMBITS_SHIFT) | \ + (0x1UL << MCSR3_UPM_SHIFT)) + + +#define LOONGARCH_MCSR8 \ +((0x1UL << MCSR8_L1IUPRE_SHIFT) | (0x0 << MCSR8_L1IUUNIFY_SHIFT) | \ + (0x1UL << MCSR8_L1DPRE_SHIFT) | (0x1UL << MCSR8_L2IUPRE_SHIFT) | \ + (0x1UL << MCSR8_L2IUUNIFY_SHIFT) | (0x1UL << MCSR8_L2IUPRIV_SHIFT) | \ + (0x0 << MCSR8_L2IUINCL_SHIFT) | (0x0 << MCSR8_L2DPRE_SHIFT) | \ + (0x0 << MCSR8_L2DPRIV_SHIFT) | (0x0 << MCSR8_L2DINCL_SHIFT) | \ + (0x1UL << MCSR8_L3IUPRE_SHIFT) | (0x1UL << MCSR8_L3IUUNIFY_SHIFT) | \ + (0x0 << MCSR8_L3IUPRIV_SHIFT) | (0x1UL << MCSR8_L3IUINCL_SHIFT) | \ + (0x0 << MCSR8_L3DPRE_SHIFT) | (0x0 < MCSR8_L3DPRIV_SHIFT) | \ + (0x0 << MCSR8_L3DINCL_SHIFT) | (0x3UL << MCSR8_L1I_WAY_SHIFT) | \ + (0x8UL << MCSR8_L1I_IDX_SHIFT) | (0x6UL << MCSR8_L1I_SIZE_SHIFT)) + +#define LOONGARCH_MCSR9 \ +((0x3UL << MCSR9_L1D_WAY_SHIFT) | (0x8UL << MCSR9_L1D_IDX_SHIFT) | \ + (0x6UL << MCSR9_L1D_SIZE_SHIFT) | (0xfUL << MCSR9_L2U_WAY_SHIFT) | \ + (0x8UL << MCSR9_L2U_IDX_SHIFT) | (0x6UL << MCSR9_L2U_SIZE_SHIFT)) + +#define LOONGARCH_MCSR10 \ +((0xfUL << MCSR10_L3U_WAY_SHIFT) | (0xfUL << MCSR10_L3U_IDX_SHIFT) | \ + (0x6UL << MCSR10_L3U_SIZE_SHIFT)) + +#define LOONGARCH_MCSR24 \ +((0x0 << MCSR24_MCSRLOCK_SHIFT) | (0x0 << MCSR24_NAPEN_SHIFT) | \ + (0x0 << MCSR24_VFPUCG_SHIFT) | (0x0 << MCSR24_RAMCG_SHIFT)) + +/* LoongArch CPU definitions */ +const loongarch_def_t loongarch_defs[] = { + { + .name = "Loongson-3A5000", + + /* for LoongArch CSR */ + .CSR_PRCFG1 = LOONGARCH_CONFIG1, + .CSR_PRCFG2 = 0x3ffff000, + .CSR_PRCFG3 = LOONGARCH_CONFIG3, + .CSR_CRMD = (0 << CSR_CRMD_PLV_SHIFT) | (0 << CSR_CRMD_IE_SHIFT) | + (1 << CSR_CRMD_DA_SHIFT) | (0 << CSR_CRMD_PG_SHIFT) | + (1 << CSR_CRMD_DACF_SHIFT) | (1 << CSR_CRMD_DACM_SHIFT), + .CSR_ECFG = 0x7 << 16, + .CSR_STLBPGSIZE = 0xe, + .CSR_RVACFG = 0x0, + .CSR_MCSR0 = LOONGARCH_MCSR0, + .CSR_MCSR1 = LOONGARCH_MCSR1, + .CSR_MCSR2 = LOONGARCH_MCSR2, + .CSR_MCSR3 = 0, + .CSR_MCSR8 = LOONGARCH_MCSR8, + .CSR_MCSR9 = LOONGARCH_MCSR9, + .CSR_MCSR10 = LOONGARCH_MCSR10, + .CSR_MCSR24 = LOONGARCH_MCSR24, + .FCSR0 = 0x0, + .FCSR0_MASK = 0x1f1f03df, + .PABITS = 48, + .INSN_FLAGS = CPU_LA64 | INSN_LOONGARCH, + .MMU_TYPE = MMU_TYPE_LS3A5K, + }, + { + .name = "host", + + /* for LoongArch CSR */ + .CSR_PRCFG1 = LOONGARCH_CONFIG1, + .CSR_PRCFG2 = 0x3ffff000, + .CSR_PRCFG3 = LOONGARCH_CONFIG3, + .CSR_CRMD = (0 << CSR_CRMD_PLV_SHIFT) | (0 << CSR_CRMD_IE_SHIFT) | + (1 << CSR_CRMD_DA_SHIFT) | (0 << CSR_CRMD_PG_SHIFT) | + (1 << CSR_CRMD_DACF_SHIFT) | (1 << CSR_CRMD_DACM_SHIFT), + .CSR_ECFG = 0x7 << 16, + .CSR_STLBPGSIZE = 0xe, + .CSR_RVACFG = 0x0, + .CSR_MCSR0 = LOONGARCH_MCSR0, + .CSR_MCSR1 = LOONGARCH_MCSR1, + .CSR_MCSR2 = LOONGARCH_MCSR2, + .CSR_MCSR3 = 0, + .CSR_MCSR8 = LOONGARCH_MCSR8, + .CSR_MCSR9 = LOONGARCH_MCSR9, + .CSR_MCSR10 = LOONGARCH_MCSR10, + .CSR_MCSR24 = LOONGARCH_MCSR24, + .FCSR0 = 0x0, + .FCSR0_MASK = 0x1f1f03df, + .PABITS = 48, + .INSN_FLAGS = CPU_LA64 | INSN_LOONGARCH, + .MMU_TYPE = MMU_TYPE_LS3A5K, + }, +}; + +const int loongarch_defs_number = ARRAY_SIZE(loongarch_defs); + +void loongarch_cpu_list(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(loongarch_defs); i++) { + qemu_printf("LoongArch '%s'\n", loongarch_defs[i].name); + } +} + +static void fpu_init(CPULoongArchState *env, const loongarch_def_t *def) +{ + memcpy(&env->active_fpu, &env->fpus[0], sizeof(env->active_fpu)); +} + +static void loongarch_cpu_reset(DeviceState *dev) +{ + CPUState *cs = CPU(dev); + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + LoongArchCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(cpu); + CPULoongArchState *env = &cpu->env; + + mcc->parent_reset(dev); + + memset(env, 0, offsetof(CPULoongArchState, end_reset_fields)); + + /* Reset registers to their default values */ + env->CSR_PRCFG1 = env->cpu_model->CSR_PRCFG1; + env->CSR_PRCFG2 = env->cpu_model->CSR_PRCFG2; + env->CSR_PRCFG3 = env->cpu_model->CSR_PRCFG3; + env->CSR_CRMD = env->cpu_model->CSR_CRMD; + env->CSR_ECFG = env->cpu_model->CSR_ECFG; + env->CSR_STLBPGSIZE = env->cpu_model->CSR_STLBPGSIZE; + env->CSR_RVACFG = env->cpu_model->CSR_RVACFG; + env->CSR_MCSR0 = env->cpu_model->CSR_MCSR0; + env->CSR_MCSR1 = env->cpu_model->CSR_MCSR1; + env->CSR_MCSR2 = env->cpu_model->CSR_MCSR2; + env->CSR_MCSR3 = env->cpu_model->CSR_MCSR3; + env->CSR_MCSR8 = env->cpu_model->CSR_MCSR8; + env->CSR_MCSR9 = env->cpu_model->CSR_MCSR9; + env->CSR_MCSR10 = env->cpu_model->CSR_MCSR10; + env->CSR_MCSR24 = env->cpu_model->CSR_MCSR24; + + env->current_tc = 0; + env->PABITS = env->cpu_model->PABITS; + env->active_fpu.fcsr0_mask = env->cpu_model->FCSR0_MASK; + env->active_fpu.fcsr0 = env->cpu_model->FCSR0; + env->insn_flags = env->cpu_model->INSN_FLAGS; + + compute_hflags(env); + restore_pamask(env); + cs->exception_index = EXCP_NONE; +} + +static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info) +{ + info->print_insn = print_insn_loongarch; +} + +static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cs = CPU(dev); + LoongArchCPU *cpu = LOONGARCH_CPU(dev); + CPULoongArchState *env = &cpu->env; + LoongArchCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(dev); + Error *local_err = NULL; + + cpu_exec_realizefn(cs, &local_err); + if (local_err != NULL) { + error_propagate(errp, local_err); + return; + } + + env->exception_base = 0x1C000000; + + fpu_init(env, env->cpu_model); + + cpu_reset(cs); + qemu_init_vcpu(cs); + + mcc->parent_realize(dev, errp); +} + +static void loongarch_cpu_initfn(Object *obj) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(obj); + CPULoongArchState *env = &cpu->env; + LoongArchCPUClass *mcc = LOONGARCH_CPU_GET_CLASS(obj); + + cpu_set_cpustate_pointers(cpu); + cpu->clock = qdev_init_clock_in(DEVICE(obj), "clk-in", NULL, cpu, 0); + env->cpu_model = mcc->cpu_def; +} + +static char *loongarch_cpu_type_name(const char *cpu_model) +{ + return g_strdup_printf(LOONGARCH_CPU_TYPE_NAME("%s"), cpu_model); +} + +static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model) +{ + ObjectClass *oc; + char *typename; + + typename = loongarch_cpu_type_name(cpu_model); + oc = object_class_by_name(typename); + g_free(typename); + return oc; +} + +static Property loongarch_cpu_properties[] = { + DEFINE_PROP_INT32("core-id", LoongArchCPU, core_id, -1), + DEFINE_PROP_UINT32("id", LoongArchCPU, id, UNASSIGNED_CPU_ID), + DEFINE_PROP_INT32("node-id", LoongArchCPU, node_id, CPU_UNSET_NUMA_NODE_ID), + DEFINE_PROP_END_OF_LIST() +}; + +#ifdef CONFIG_TCG +#include "hw/core/tcg-cpu-ops.h" + +static struct TCGCPUOps loongarch_tcg_ops = { + .initialize = loongarch_tcg_init, + .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, +}; +#endif /* CONFIG_TCG */ + +static void loongarch_cpu_class_init(ObjectClass *c, void *data) +{ + LoongArchCPUClass *mcc = LOONGARCH_CPU_CLASS(c); + CPUClass *cc = CPU_CLASS(c); + DeviceClass *dc = DEVICE_CLASS(c); + + device_class_set_parent_realize(dc, loongarch_cpu_realizefn, + &mcc->parent_realize); + device_class_set_parent_reset(dc, loongarch_cpu_reset, &mcc->parent_reset); + device_class_set_props(dc, loongarch_cpu_properties); + + cc->class_by_name = loongarch_cpu_class_by_name; + cc->has_work = loongarch_cpu_has_work; + cc->dump_state = loongarch_cpu_dump_state; + cc->set_pc = loongarch_cpu_set_pc; + cc->disas_set_info = loongarch_cpu_disas_set_info; +#ifdef CONFIG_TCG + cc->tcg_ops = &loongarch_tcg_ops; +#endif +} + +static const TypeInfo loongarch_cpu_type_info = { + .name = TYPE_LOONGARCH_CPU, + .parent = TYPE_CPU, + .instance_size = sizeof(LoongArchCPU), + .instance_init = loongarch_cpu_initfn, + .abstract = true, + .class_size = sizeof(LoongArchCPUClass), + .class_init = loongarch_cpu_class_init, +}; + +static void loongarch_cpu_cpudef_class_init(ObjectClass *oc, void *data) +{ + LoongArchCPUClass *mcc = LOONGARCH_CPU_CLASS(oc); + mcc->cpu_def = data; +} + +static void loongarch_register_cpudef_type(const struct loongarch_def_t *def) +{ + char *typename = loongarch_cpu_type_name(def->name); + TypeInfo ti = { + .name = typename, + .parent = TYPE_LOONGARCH_CPU, + .class_init = loongarch_cpu_cpudef_class_init, + .class_data = (void *)def, + }; + + type_register(&ti); + g_free(typename); +} + +static void loongarch_cpu_register_types(void) +{ + int i; + + type_register_static(&loongarch_cpu_type_info); + for (i = 0; i < loongarch_defs_number; i++) { + loongarch_register_cpudef_type(&loongarch_defs[i]); + } +} + +type_init(loongarch_cpu_register_types) + +static void loongarch_cpu_add_definition(gpointer data, gpointer user_data) +{ + ObjectClass *oc = data; + CpuDefinitionInfoList **cpu_list = user_data; + CpuDefinitionInfo *info; + const char *typename; + + typename = object_class_get_name(oc); + info = g_malloc0(sizeof(*info)); + info->name = g_strndup(typename, + strlen(typename) - strlen("-" TYPE_LOONGARCH_CPU)); + info->q_typename = g_strdup(typename); + + QAPI_LIST_PREPEND(*cpu_list, info); +} + +CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp) +{ + CpuDefinitionInfoList *cpu_list = NULL; + GSList *list; + + list = object_class_get_list(TYPE_LOONGARCH_CPU, false); + g_slist_foreach(list, loongarch_cpu_add_definition, &cpu_list); + g_slist_free(list); + + return cpu_list; +} diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h new file mode 100644 index 0000000..1352188 --- /dev/null +++ b/target/loongarch/cpu.h @@ -0,0 +1,245 @@ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef LOONGARCH_CPU_H +#define LOONGARCH_CPU_H + +#include "exec/cpu-defs.h" +#include "fpu/softfloat-types.h" +#include "hw/clock.h" +#include "cpu-qom.h" +#include "cpu-csr.h" + +#define ISA_LA32 0x00000001ULL +#define ISA_LA64 0x00000002ULL +#define INSN_LOONGARCH 0x00010000ULL + +#define CPU_LA32 (ISA_LA32) +#define CPU_LA64 (ISA_LA32 | ISA_LA64) + +#define TCG_GUEST_DEFAULT_MO (0) +#define UNASSIGNED_CPU_ID 0xFFFFFFFF + +typedef union fpr_t fpr_t; +union fpr_t { + float64 fd; /* ieee double precision */ + float32 fs[2];/* ieee single precision */ + uint64_t d; /* binary double fixed-point */ + uint32_t w[2]; /* binary single fixed-point */ +}; + +/* + * define FP_ENDIAN_IDX to access the same location + * in the fpr_t union regardless of the host endianness + */ +#if defined(HOST_WORDS_BIGENDIAN) +# define FP_ENDIAN_IDX 1 +#else +# define FP_ENDIAN_IDX 0 +#endif + +typedef struct CPULoongArchFPUContext CPULoongArchFPUContext; +struct CPULoongArchFPUContext { + /* Floating point registers */ + fpr_t fpr[32]; + float_status fp_status; + + bool cf[8]; + /* + * fcsr0 + * 31:29 |28:24 |23:21 |20:16 |15:10 |9:8 |7 |6 |5 |4:0 + * Cause Flags RM DAE TM Enables + */ + uint32_t fcsr0; + uint32_t fcsr0_mask; + uint32_t vcsr16; + +#define FCSR0_M1 0xdf /* FCSR1 mask, DAE, TM and Enables */ +#define FCSR0_M2 0x1f1f0000 /* FCSR2 mask, Cause and Flags */ +#define FCSR0_M3 0x300 /* FCSR3 mask, Round Mode */ +#define FCSR0_RM 8 /* Round Mode bit num on fcsr0 */ +#define GET_FP_CAUSE(reg) (((reg) >> 24) & 0x1f) +#define GET_FP_ENABLE(reg) (((reg) >> 0) & 0x1f) +#define GET_FP_FLAGS(reg) (((reg) >> 16) & 0x1f) +#define SET_FP_CAUSE(reg, v) do { (reg) = ((reg) & ~(0x1f << 24)) | \ + ((v & 0x1f) << 24); \ + } while (0) +#define SET_FP_ENABLE(reg, v) do { (reg) = ((reg) & ~(0x1f << 0)) | \ + ((v & 0x1f) << 0); \ + } while (0) +#define SET_FP_FLAGS(reg, v) do { (reg) = ((reg) & ~(0x1f << 16)) | \ + ((v & 0x1f) << 16); \ + } while (0) +#define UPDATE_FP_FLAGS(reg, v) do { (reg) |= ((v & 0x1f) << 16); } while (0) +#define FP_INEXACT 1 +#define FP_UNDERFLOW 2 +#define FP_OVERFLOW 4 +#define FP_DIV0 8 +#define FP_INVALID 16 +}; + +#define TARGET_INSN_START_EXTRA_WORDS 2 + +typedef struct loongarch_def_t loongarch_def_t; + +#define LOONGARCH_FPU_MAX 1 + +typedef struct TCState TCState; +struct TCState { + target_ulong gpr[32]; + target_ulong PC; +}; + +#define N_IRQS 14 + +typedef struct CPULoongArchState CPULoongArchState; +struct CPULoongArchState { + TCState active_tc; + CPULoongArchFPUContext active_fpu; + + uint32_t current_tc; + uint64_t scr[4]; + uint32_t current_fpu; + + uint32_t PABITS; +#define PABITS_BASE 36 + uint64_t PAMask; +#define PAMASK_BASE ((1ULL << PABITS_BASE) - 1) + + /* LoongArch CSR register */ + CPU_LOONGARCH_CSR + target_ulong lladdr; /* LL virtual address compared against SC */ + target_ulong llval; + + CPULoongArchFPUContext fpus[LOONGARCH_FPU_MAX]; + + /* QEMU */ + int error_code; + uint32_t hflags; /* CPU State */ +#define TLB_NOMATCH 0x1 +#define INST_INAVAIL 0x2 /* Invalid instruction word for BadInstr */ + /* TMASK defines different execution modes */ +#define LOONGARCH_HFLAG_TMASK 0x1F5807FF +#define LOONGARCH_HFLAG_KU 0x00003 /* kernel/supervisor/user mode mask */ +#define LOONGARCH_HFLAG_UM 0x00003 /* user mode flag */ +#define LOONGARCH_HFLAG_KM 0x00000 /* kernel mode flag */ +#define LOONGARCH_HFLAG_64 0x00008 /* 64-bit instructions enabled */ +#define LOONGARCH_HFLAG_FPU 0x00020 /* FPU enabled */ +#define LOONGARCH_HFLAG_F64 0x00040 /* 64-bit FPU enabled */ +#define LOONGARCH_HFLAG_BMASK 0x3800 +#define LOONGARCH_HFLAG_B 0x00800 /* Unconditional branch */ +#define LOONGARCH_HFLAG_BC 0x01000 /* Conditional branch */ +#define LOONGARCH_HFLAG_BR 0x02000 /* branch to register (can't link TB) */ +#define LOONGARCH_HFLAG_FRE 0x2000000 /* FRE enabled */ +#define LOONGARCH_HFLAG_ELPA 0x4000000 + target_ulong btarget; /* Jump / branch target */ + target_ulong bcond; /* Branch condition (if needed) */ + + uint64_t insn_flags; /* Supported instruction set */ + + /* Fields up to this point are cleared by a CPU reset */ + struct {} end_reset_fields; + + const loongarch_def_t *cpu_model; + void *irq[N_IRQS]; + QEMUTimer *timer; /* Internal timer */ + target_ulong exception_base; /* ExceptionBase input to the core */ +}; + +/** + * LoongArchCPU: + * @env: #CPULoongArchState + * @clock: this CPU input clock (may be connected + * to an output clock from another device). + * + * A LoongArch CPU. + */ +struct LoongArchCPU { + /*< private >*/ + CPUState parent_obj; + /*< public >*/ + + Clock *clock; + CPUNegativeOffsetState neg; + CPULoongArchState env; + uint32_t id; + int32_t node_id; /* NUMA node this CPU belongs to */ + int32_t core_id; +}; + +target_ulong exception_resume_pc(CPULoongArchState *env); + +static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, + target_ulong *pc, + target_ulong *cs_base, + uint32_t *flags) +{ + *pc = env->active_tc.PC; + *cs_base = 0; + *flags = env->hflags & (LOONGARCH_HFLAG_TMASK | LOONGARCH_HFLAG_BMASK); +} + +static inline LoongArchCPU *loongarch_env_get_cpu(CPULoongArchState *env) +{ + return container_of(env, LoongArchCPU, env); +} + +#define ENV_GET_CPU(e) CPU(loongarch_env_get_cpu(e)) + +void loongarch_cpu_list(void); + +#define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0 + +#define cpu_signal_handler cpu_loongarch_signal_handler +#define cpu_list loongarch_cpu_list + +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE1_SUFFIX _super +#define MMU_MODE2_SUFFIX _user +#define MMU_MODE3_SUFFIX _error +#define MMU_USER_IDX 2 + +static inline int cpu_mmu_index(CPULoongArchState *env, bool ifetch) +{ + return MMU_USER_IDX; +} + +typedef CPULoongArchState CPUArchState; +typedef LoongArchCPU ArchCPU; + +#include "exec/cpu-all.h" + +/* Exceptions */ +enum { + EXCP_NONE = -1, + EXCP_INTE = 0, + EXCP_ADE, + EXCP_SYSCALL, + EXCP_BREAK, + EXCP_FPDIS, + EXCP_INE, + EXCP_TRAP, + EXCP_FPE, + EXCP_TLBM, + EXCP_TLBL, + EXCP_TLBS, + EXCP_TLBPE, + EXCP_TLBXI, + EXCP_TLBRI, + + EXCP_LAST = EXCP_TLBRI, +}; + +int cpu_loongarch_signal_handler(int host_signum, void *pinfo, void *puc); + +#define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU +#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX +#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU + +#endif /* LOONGARCH_CPU_H */ diff --git a/target/loongarch/internal.h b/target/loongarch/internal.h new file mode 100644 index 0000000..e2394af --- /dev/null +++ b/target/loongarch/internal.h @@ -0,0 +1,74 @@ +/* + * LoongArch internal definitions and helpers. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef LOONGARCH_INTERNAL_H +#define LOONGARCH_INTERNAL_H + +#include "exec/memattrs.h" + +enum loongarch_mmu_types { + MMU_TYPE_NONE, + MMU_TYPE_LS3A5K, +}; + +struct loongarch_def_t { + const char *name; + int32_t FCSR0; + int32_t FCSR0_MASK; + int32_t PABITS; + CPU_LOONGARCH_CSR + uint64_t INSN_FLAGS; + enum loongarch_mmu_types MMU_TYPE; +}; + +extern const struct loongarch_def_t loongarch_defs[]; +extern const int loongarch_defs_number; + +void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); + +#define cpu_signal_handler cpu_loongarch_signal_handler + +void loongarch_tcg_init(void); + +void QEMU_NORETURN do_raise_exception_err(CPULoongArchState *env, + uint32_t exception, + int error_code, + uintptr_t pc); + +static inline void QEMU_NORETURN do_raise_exception(CPULoongArchState *env, + uint32_t exception, + uintptr_t pc) +{ + do_raise_exception_err(env, exception, 0, pc); +} + +static inline void restore_pamask(CPULoongArchState *env) +{ + if (env->hflags & LOONGARCH_HFLAG_ELPA) { + env->PAMask = (1ULL << env->PABITS) - 1; + } else { + env->PAMask = PAMASK_BASE; + } +} + +static inline void compute_hflags(CPULoongArchState *env) +{ + env->hflags &= ~(LOONGARCH_HFLAG_64 | LOONGARCH_HFLAG_FPU | + LOONGARCH_HFLAG_KU | LOONGARCH_HFLAG_ELPA); + + env->hflags |= (env->CSR_CRMD & CSR_CRMD_PLV); + env->hflags |= LOONGARCH_HFLAG_64; + + if (env->CSR_EUEN & CSR_EUEN_FPEN) { + env->hflags |= LOONGARCH_HFLAG_FPU; + } +} + +const char *loongarch_exception_name(int32_t exception); + +#endif From patchwork Mon Jun 28 12:04:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347835 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 5299BC2B9F4 for ; Mon, 28 Jun 2021 12:13:25 +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 F227261477 for ; Mon, 28 Jun 2021 12:13:24 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org F227261477 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:49270 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq8h-0008Tr-U6 for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:13:23 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51162) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0a-0002Av-S5 for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:01 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45346 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0T-00015H-8M for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:00 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S6; Mon, 28 Jun 2021 20:04:47 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 04/20] target/loongarch: Add interrupt handling support Date: Mon, 28 Jun 2021 20:04:29 +0800 Message-Id: <1624881885-31692-5-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S6 X-Coremail-Antispam: 1UD129KBjvJXoWxXrWxCFy8KF45AF43Ar1kZrb_yoW5Wr13pr W7ZFy5Ar48JrZrJ393Ja98Zrn8Zr1xWry29a1ay34FkF4jqr1UXr1kt34DXF15u34rWry2 vF1rAa4Uu3WUJaDanT9S1TB71UUUUjDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UUUUUUUUU== X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch introduces functions loongarch_cpu_do_interrupt() and loongarch_cpu_exec_interrupt() Signed-off-by: Song Gao --- target/loongarch/cpu.c | 23 +++++++++++++++++++++++ target/loongarch/internal.h | 24 ++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index b368e79..c3ecc4b 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -80,6 +80,28 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr value) env->active_tc.PC = value & ~(target_ulong)1; } +bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ + if (interrupt_request & CPU_INTERRUPT_HARD) { + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + + if (cpu_loongarch_hw_interrupts_enabled(env) && + cpu_loongarch_hw_interrupts_pending(env)) { + cs->exception_index = EXCP_INTE; + env->error_code = 0; + loongarch_cpu_do_interrupt(cs); + return true; + } + } + return false; +} + +void loongarch_cpu_do_interrupt(CPUState *cs) +{ + cs->exception_index = EXCP_NONE; +} + #ifdef CONFIG_TCG static void loongarch_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) @@ -356,6 +378,7 @@ static Property loongarch_cpu_properties[] = { static struct TCGCPUOps loongarch_tcg_ops = { .initialize = loongarch_tcg_init, .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, + .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, }; #endif /* CONFIG_TCG */ diff --git a/target/loongarch/internal.h b/target/loongarch/internal.h index e2394af..09e667c 100644 --- a/target/loongarch/internal.h +++ b/target/loongarch/internal.h @@ -29,10 +29,34 @@ struct loongarch_def_t { extern const struct loongarch_def_t loongarch_defs[]; extern const int loongarch_defs_number; +void loongarch_cpu_do_interrupt(CPUState *cpu); +bool loongarch_cpu_exec_interrupt(CPUState *cpu, int int_req); void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags); #define cpu_signal_handler cpu_loongarch_signal_handler +static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env) +{ + bool ret = 0; + + ret = env->CSR_CRMD & (1 << CSR_CRMD_IE_SHIFT); + + return ret; +} + +static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env) +{ + int32_t pending; + int32_t status; + bool r; + + pending = env->CSR_ESTAT & CSR_ESTAT_IPMASK; + status = env->CSR_ECFG & CSR_ECFG_IPMASK; + + r = (pending & status) != 0; + return r; +} + void loongarch_tcg_init(void); void QEMU_NORETURN do_raise_exception_err(CPULoongArchState *env, From patchwork Mon Jun 28 12:04:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347867 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 66B4AC2B9F4 for ; Mon, 28 Jun 2021 12:31:48 +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 1812C6197F for ; Mon, 28 Jun 2021 12:31:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1812C6197F Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:37730 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqQU-0005qo-Th for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:31:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52490) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq6f-0004cQ-LV for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:11:17 -0400 Received: from mail.loongson.cn ([114.242.206.163]:47008 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq6d-00045Y-2x for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:11:17 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S7; Mon, 28 Jun 2021 20:04:47 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 05/20] target/loongarch: Add memory management support Date: Mon, 28 Jun 2021 20:04:30 +0800 Message-Id: <1624881885-31692-6-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S7 X-Coremail-Antispam: 1UD129KBjvJXoWxWFWkKryrWw4rtrW7Gr17Wrg_yoWrArW5pr 9rCryUGF48X39xZ3yfXa4FqF15ua1xGryIva1ft34Sk34aqr1jvr4vg3srXF15Cw4UJw4I v3WrZw1jgF1UZaDanT9S1TB71UUUUjDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UUUUUUUUU== X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch introduces one memory-management-related functions - loongarch_cpu_tlb_fill() Signed-off-by: Song Gao --- target/loongarch/cpu.c | 1 + target/loongarch/internal.h | 9 ++++ target/loongarch/tlb_helper.c | 109 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 target/loongarch/tlb_helper.c diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index c3ecc4b..a39a3bd 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -379,6 +379,7 @@ static struct TCGCPUOps loongarch_tcg_ops = { .initialize = loongarch_tcg_init, .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, + .tlb_fill = loongarch_cpu_tlb_fill, }; #endif /* CONFIG_TCG */ diff --git a/target/loongarch/internal.h b/target/loongarch/internal.h index 09e667c..40454ee 100644 --- a/target/loongarch/internal.h +++ b/target/loongarch/internal.h @@ -95,4 +95,13 @@ static inline void compute_hflags(CPULoongArchState *env) const char *loongarch_exception_name(int32_t exception); +/* tlb_helper.c */ +bool loongarch_cpu_tlb_fill(CPUState *cs, + vaddr address, + int size, + MMUAccessType access_type, + int mmu_idx, + bool probe, + uintptr_t retaddr); + #endif diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c new file mode 100644 index 0000000..3889109 --- /dev/null +++ b/target/loongarch/tlb_helper.c @@ -0,0 +1,109 @@ +/* + * LoongArch tlb emulation helpers for qemu. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internal.h" +#include "cpu-csr.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "exec/log.h" + +enum { + TLBRET_PE = -7, + TLBRET_XI = -6, + TLBRET_RI = -5, + TLBRET_DIRTY = -4, + TLBRET_INVALID = -3, + TLBRET_NOMATCH = -2, + TLBRET_BADADDR = -1, + TLBRET_MATCH = 0 +}; + +static void raise_mmu_exception(CPULoongArchState *env, target_ulong address, + MMUAccessType access_type, int tlb_error) +{ + CPUState *cs = env_cpu(env); + int exception = 0, error_code = 0; + + if (access_type == MMU_INST_FETCH) { + error_code |= INST_INAVAIL; + } + + switch (tlb_error) { + default: + case TLBRET_BADADDR: + exception = EXCP_ADE; + break; + case TLBRET_NOMATCH: + /* No TLB match for a mapped address */ + if (access_type == MMU_DATA_STORE) { + exception = EXCP_TLBS; + } else { + exception = EXCP_TLBL; + } + error_code |= TLB_NOMATCH; + break; + case TLBRET_INVALID: + /* TLB match with no valid bit */ + if (access_type == MMU_DATA_STORE) { + exception = EXCP_TLBS; + } else { + exception = EXCP_TLBL; + } + break; + case TLBRET_DIRTY: + exception = EXCP_TLBM; + break; + case TLBRET_XI: + /* Execute-Inhibit Exception */ + exception = EXCP_TLBXI; + break; + case TLBRET_RI: + /* Read-Inhibit Exception */ + exception = EXCP_TLBRI; + break; + case TLBRET_PE: + /* Privileged Exception */ + exception = EXCP_TLBPE; + break; + } + + if (env->insn_flags & INSN_LOONGARCH) { + if (tlb_error == TLBRET_NOMATCH) { + env->CSR_TLBRBADV = address; + env->CSR_TLBREHI = address & (TARGET_PAGE_MASK << 1); + cs->exception_index = exception; + env->error_code = error_code; + return; + } + } + + /* Raise exception */ + env->CSR_BADV = address; + cs->exception_index = exception; + env->error_code = error_code; + + if (env->insn_flags & INSN_LOONGARCH) { + env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1); + } +} + +bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + int ret = TLBRET_BADADDR; + + /* data access */ + raise_mmu_exception(env, address, access_type, ret); + do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr); +} From patchwork Mon Jun 28 12:04:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347857 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 3DAC7C2B9F4 for ; Mon, 28 Jun 2021 12:24:20 +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 CE0D96144B for ; Mon, 28 Jun 2021 12:24:19 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CE0D96144B Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:48332 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqJG-0002I4-QT for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:24:18 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52492) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq6h-0004hM-9L for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:11:19 -0400 Received: from mail.loongson.cn ([114.242.206.163]:46926 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq6a-00042W-26 for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:11:19 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S8; Mon, 28 Jun 2021 20:04:48 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 06/20] target/loongarch: Add main translation routines Date: Mon, 28 Jun 2021 20:04:31 +0800 Message-Id: <1624881885-31692-7-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S8 X-Coremail-Antispam: 1UD129KBjvAXoW3tFW8XrWkGF1UGw45AFyrWFg_yoW8CF45uo W7CF45Ary8GrnxZr9akr4kJa42qF4Ika1UJa90va1kWa18CrW5tF9xKw15ZrW7JF4kGay7 WF9avF17Xan7Jrnxn29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch add main translation routines and basic functions for translation. Signed-off-by: Song Gao --- target/loongarch/helper.h | 10 + target/loongarch/op_helper.c | 28 +++ target/loongarch/translate.c | 537 +++++++++++++++++++++++++++++++++++++++++++ target/loongarch/translate.h | 58 +++++ 4 files changed, 633 insertions(+) create mode 100644 target/loongarch/helper.h create mode 100644 target/loongarch/op_helper.c create mode 100644 target/loongarch/translate.c create mode 100644 target/loongarch/translate.h diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h new file mode 100644 index 0000000..6c7e19b --- /dev/null +++ b/target/loongarch/helper.h @@ -0,0 +1,10 @@ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) +DEF_HELPER_2(raise_exception, noreturn, env, i32) diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c new file mode 100644 index 0000000..97113e4 --- /dev/null +++ b/target/loongarch/op_helper.c @@ -0,0 +1,28 @@ +/* + * LoongArch emulation helpers for qemu. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "qemu/main-loop.h" +#include "cpu.h" +#include "internal.h" +#include "qemu/host-utils.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" + +/* Exceptions helpers */ +void helper_raise_exception_err(CPULoongArchState *env, uint32_t exception, + int error_code) +{ + do_raise_exception_err(env, exception, error_code, 0); +} + +void helper_raise_exception(CPULoongArchState *env, uint32_t exception) +{ + do_raise_exception(env, exception, GETPC()); +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c new file mode 100644 index 0000000..83efd39 --- /dev/null +++ b/target/loongarch/translate.c @@ -0,0 +1,537 @@ +/* + * LoongArch emulation for QEMU - main translation routines. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internal.h" +#include "tcg/tcg-op.h" +#include "exec/translator.h" +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" +#include "semihosting/semihost.h" + +#include "exec/translator.h" +#include "exec/log.h" +#include "qemu/qemu-print.h" +#include "fpu_helper.h" +#include "translate.h" +#include "instmap.h" + +/* global register indices */ +TCGv cpu_gpr[32], cpu_PC; +TCGv btarget, bcond; +static TCGv cpu_lladdr, cpu_llval; +static TCGv_i32 hflags; +TCGv_i32 fpu_fcsr0; +TCGv_i64 fpu_f64[32]; + +#include "exec/gen-icount.h" + +#define DISAS_STOP DISAS_TARGET_0 +#define DISAS_EXIT DISAS_TARGET_1 + +static const char * const regnames[] = { + "r0", "ra", "tp", "sp", "a0", "a1", "a2", "a3", + "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3", + "t4", "t5", "t6", "t7", "t8", "x0", "fp", "s0", + "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", +}; + +static const char * const fregnames[] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", +}; + +/* General purpose registers moves. */ +void gen_load_gpr(TCGv t, int reg) +{ + if (reg == 0) { + tcg_gen_movi_tl(t, 0); + } else { + tcg_gen_mov_tl(t, cpu_gpr[reg]); + } +} + +void gen_store_gpr(TCGv t, int reg) +{ + if (reg != 0) { + tcg_gen_mov_tl(cpu_gpr[reg], t); + } +} + +static inline void gen_save_pc(target_ulong pc) +{ + tcg_gen_movi_tl(cpu_PC, pc); +} + +static inline void save_cpu_state(DisasContext *ctx, int do_save_pc) +{ + if (do_save_pc && ctx->base.pc_next != ctx->saved_pc) { + gen_save_pc(ctx->base.pc_next); + ctx->saved_pc = ctx->base.pc_next; + } + if (ctx->hflags != ctx->saved_hflags) { + tcg_gen_movi_i32(hflags, ctx->hflags); + ctx->saved_hflags = ctx->hflags; + switch (ctx->hflags & LOONGARCH_HFLAG_BMASK) { + case LOONGARCH_HFLAG_BR: + break; + case LOONGARCH_HFLAG_BC: + case LOONGARCH_HFLAG_B: + tcg_gen_movi_tl(btarget, ctx->btarget); + break; + } + } +} + +static inline void restore_cpu_state(CPULoongArchState *env, DisasContext *ctx) +{ + ctx->saved_hflags = ctx->hflags; + switch (ctx->hflags & LOONGARCH_HFLAG_BMASK) { + case LOONGARCH_HFLAG_BR: + break; + case LOONGARCH_HFLAG_BC: + case LOONGARCH_HFLAG_B: + ctx->btarget = env->btarget; + break; + } +} + +void generate_exception_err(DisasContext *ctx, int excp, int err) +{ + TCGv_i32 texcp = tcg_const_i32(excp); + TCGv_i32 terr = tcg_const_i32(err); + save_cpu_state(ctx, 1); + gen_helper_raise_exception_err(cpu_env, texcp, terr); + tcg_temp_free_i32(terr); + tcg_temp_free_i32(texcp); + ctx->base.is_jmp = DISAS_NORETURN; +} + +void generate_exception_end(DisasContext *ctx, int excp) +{ + generate_exception_err(ctx, excp, 0); +} + +void gen_reserved_instruction(DisasContext *ctx) +{ + generate_exception_end(ctx, EXCP_INE); +} + +void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) +{ + tcg_gen_extrl_i64_i32(t, fpu_f64[reg]); +} + +void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg) +{ + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t64, t); + tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 0, 32); + tcg_temp_free_i64(t64); +} + +static void gen_load_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) +{ + tcg_gen_extrh_i64_i32(t, fpu_f64[reg]); +} + +static void gen_store_fpr32h(DisasContext *ctx, TCGv_i32 t, int reg) +{ + TCGv_i64 t64 = tcg_temp_new_i64(); + tcg_gen_extu_i32_i64(t64, t); + tcg_gen_deposit_i64(fpu_f64[reg], fpu_f64[reg], t64, 32, 32); + tcg_temp_free_i64(t64); +} + +void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) +{ + tcg_gen_mov_i64(t, fpu_f64[reg]); +} + +void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg) +{ + tcg_gen_mov_i64(fpu_f64[reg], t); +} + +/* Addresses computation */ +void gen_op_addr_add(DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1) +{ + tcg_gen_add_tl(ret, arg0, arg1); +} + +/* Sign-extract the low 32-bits to a target_long. */ +void gen_move_low32(TCGv ret, TCGv_i64 arg) +{ + tcg_gen_ext32s_i64(ret, arg); +} + +/* Sign-extract the high 32-bits to a target_long. */ +void gen_move_high32(TCGv ret, TCGv_i64 arg) +{ + tcg_gen_sari_i64(ret, arg, 32); +} + +void check_fpu_enabled(DisasContext *ctx) +{ + /* Nop */ +} + +/* + * This code generates a "reserved instruction" exception if 64-bit + * instructions are not enabled. + */ +void check_loongarch_64(DisasContext *ctx) +{ + if (unlikely(!(ctx->hflags & LOONGARCH_HFLAG_64))) { + gen_reserved_instruction(ctx); + } +} + +void gen_base_offset_addr(DisasContext *ctx, TCGv addr, int base, int offset) +{ + if (base == 0) { + tcg_gen_movi_tl(addr, offset); + } else if (offset == 0) { + gen_load_gpr(addr, base); + } else { + tcg_gen_movi_tl(addr, offset); + gen_op_addr_add(ctx, addr, cpu_gpr[base], addr); + } +} + + +static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest) +{ + return true; +} + +static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) +{ + if (use_goto_tb(ctx, dest)) { + tcg_gen_goto_tb(n); + gen_save_pc(dest); + tcg_gen_exit_tb(ctx->base.tb, n); + } else { + gen_save_pc(dest); + tcg_gen_lookup_and_goto_ptr(); + } +} + +static inline void clear_branch_hflags(DisasContext *ctx) +{ + ctx->hflags &= ~LOONGARCH_HFLAG_BMASK; + if (ctx->base.is_jmp == DISAS_NEXT) { + save_cpu_state(ctx, 0); + } else { + /* + * It is not safe to save ctx->hflags as hflags may be changed + * in execution time. + */ + tcg_gen_andi_i32(hflags, hflags, ~LOONGARCH_HFLAG_BMASK); + } +} + +static void gen_branch(DisasContext *ctx, int insn_bytes) +{ + if (ctx->hflags & LOONGARCH_HFLAG_BMASK) { + int proc_hflags = ctx->hflags & LOONGARCH_HFLAG_BMASK; + /* Branches completion */ + clear_branch_hflags(ctx); + ctx->base.is_jmp = DISAS_NORETURN; + switch (proc_hflags & LOONGARCH_HFLAG_BMASK) { + case LOONGARCH_HFLAG_B: + /* unconditional branch */ + gen_goto_tb(ctx, 0, ctx->btarget); + break; + case LOONGARCH_HFLAG_BC: + /* Conditional branch */ + { + TCGLabel *l1 = gen_new_label(); + + tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1); + gen_goto_tb(ctx, 1, ctx->base.pc_next + insn_bytes); + gen_set_label(l1); + gen_goto_tb(ctx, 0, ctx->btarget); + } + break; + case LOONGARCH_HFLAG_BR: + /* unconditional branch to register */ + tcg_gen_mov_tl(cpu_PC, btarget); + tcg_gen_lookup_and_goto_ptr(); + break; + default: + fprintf(stderr, "unknown branch 0x%x\n", proc_hflags); + abort(); + } + } +} + +static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, + CPUState *cs) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + CPULoongArchState *env = cs->env_ptr; + + ctx->page_start = ctx->base.pc_first & TARGET_PAGE_MASK; + ctx->saved_pc = -1; + ctx->insn_flags = env->insn_flags; + ctx->btarget = 0; + ctx->PAMask = env->PAMask; + /* Restore state from the tb context. */ + ctx->hflags = (uint32_t)ctx->base.tb->flags; + restore_cpu_state(env, ctx); + ctx->mem_idx = LOONGARCH_HFLAG_UM; + ctx->default_tcg_memop_mask = MO_UNALN; +} + +static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) +{ +} + +static void loongarch_tr_insn_start(DisasContextBase *dcbase, CPUState *cs) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + tcg_gen_insn_start(ctx->base.pc_next, ctx->hflags & LOONGARCH_HFLAG_BMASK, + ctx->btarget); +} + +static bool loongarch_tr_breakpoint_check(DisasContextBase *dcbase, + CPUState *cs, + const CPUBreakpoint *bp) +{ + return true; +} + +/* 128 and 256 msa vector instructions are not supported yet */ +static bool decode_lsx(uint32_t opcode) +{ + uint32_t value = (opcode & 0xff000000); + + if ((opcode & 0xf0000000) == 0x70000000) { + return true; + } else if ((opcode & 0xfff00000) == 0x38400000) { + return true; + } else { + switch (value) { + case 0x09000000: + case 0x0a000000: + case 0x0e000000: + case 0x0f000000: + case 0x2c000000: + case 0x30000000: + case 0x31000000: + case 0x32000000: + case 0x33000000: + return true; + } + } + return false; +} + +static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) +{ + CPULoongArchState *env = cs->env_ptr; + DisasContext *ctx = container_of(dcbase, DisasContext, base); + int insn_bytes = 4; + + ctx->opcode = cpu_ldl_code(env, ctx->base.pc_next); + + if (!decode(ctx, ctx->opcode)) { + if (!decode_lsx(ctx->opcode)) { + fprintf(stderr, "Error: unkown opcode. 0x%lx: 0x%x\n", + ctx->base.pc_next, ctx->opcode); + } + generate_exception_end(ctx, EXCP_INE); + } + + if (ctx->hflags & LOONGARCH_HFLAG_BMASK) { + gen_branch(ctx, insn_bytes); + } + ctx->base.pc_next += insn_bytes; +} + +static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + + switch (ctx->base.is_jmp) { + case DISAS_STOP: + gen_save_pc(ctx->base.pc_next); + tcg_gen_lookup_and_goto_ptr(); + break; + case DISAS_NEXT: + case DISAS_TOO_MANY: + save_cpu_state(ctx, 0); + gen_goto_tb(ctx, 0, ctx->base.pc_next); + break; + case DISAS_EXIT: + tcg_gen_exit_tb(NULL, 0); + break; + case DISAS_NORETURN: + break; + default: + g_assert_not_reached(); + } +} + +static void loongarch_tr_disas_log(const DisasContextBase *dcbase, CPUState *cs) +{ + qemu_log("IN: %s\n", lookup_symbol(dcbase->pc_first)); + log_target_disas(cs, dcbase->pc_first, dcbase->tb->size); +} + +static const TranslatorOps loongarch_tr_ops = { + .init_disas_context = loongarch_tr_init_disas_context, + .tb_start = loongarch_tr_tb_start, + .insn_start = loongarch_tr_insn_start, + .breakpoint_check = loongarch_tr_breakpoint_check, + .translate_insn = loongarch_tr_translate_insn, + .tb_stop = loongarch_tr_tb_stop, + .disas_log = loongarch_tr_disas_log, +}; + +void gen_intermediate_code(CPUState *cs, TranslationBlock *tb, int max_insns) +{ + DisasContext ctx; + + translator_loop(&loongarch_tr_ops, &ctx.base, cs, tb, max_insns); +} + +static void fpu_dump_state(CPULoongArchState *env, FILE * f, int flags) +{ + int i; + int is_fpu64 = 1; + +#define printfpr(fp) \ + do { \ + if (is_fpu64) \ + qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu: %13g\n", \ + (fp)->w[FP_ENDIAN_IDX], (fp)->d, \ + (double)(fp)->fd, \ + (double)(fp)->fs[FP_ENDIAN_IDX], \ + (double)(fp)->fs[!FP_ENDIAN_IDX]); \ + else { \ + fpr_t tmp; \ + tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \ + tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \ + qemu_fprintf(f, "w:%08x d:%016" PRIx64 \ + " fd:%13g fs:%13g psu:%13g\n", \ + tmp.w[FP_ENDIAN_IDX], tmp.d, \ + (double)tmp.fd, \ + (double)tmp.fs[FP_ENDIAN_IDX], \ + (double)tmp.fs[!FP_ENDIAN_IDX]); \ + } \ + } while (0) + + + qemu_fprintf(f, + "FCSR0 0x%08x SR.FR %d fp_status 0x%02x\n", + env->active_fpu.fcsr0, is_fpu64, + get_float_exception_flags(&env->active_fpu.fp_status)); + for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) { + qemu_fprintf(f, "%3s: ", fregnames[i]); + printfpr(&env->active_fpu.fpr[i]); + } + +#undef printfpr +} + +void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) +{ + LoongArchCPU *cpu = LOONGARCH_CPU(cs); + CPULoongArchState *env = &cpu->env; + int i; + + qemu_fprintf(f, "pc=0x" TARGET_FMT_lx " ds %04x " + TARGET_FMT_lx " " TARGET_FMT_ld "\n", + env->active_tc.PC, env->hflags, env->btarget, env->bcond); + for (i = 0; i < 32; i++) { + if ((i & 3) == 0) { + qemu_fprintf(f, "GPR%02d:", i); + } + qemu_fprintf(f, " %s " TARGET_FMT_lx, + regnames[i], env->active_tc.gpr[i]); + if ((i & 3) == 3) { + qemu_fprintf(f, "\n"); + } + } + + qemu_fprintf(f, "EUEN 0x%lx\n", env->CSR_EUEN); + qemu_fprintf(f, "ESTAT 0x%lx\n", env->CSR_ESTAT); + qemu_fprintf(f, "ERA 0x%lx\n", env->CSR_ERA); + qemu_fprintf(f, "CRMD 0x%lx\n", env->CSR_CRMD); + qemu_fprintf(f, "PRMD 0x%lx\n", env->CSR_PRMD); + qemu_fprintf(f, "BadVAddr 0x%lx\n", env->CSR_BADV); + qemu_fprintf(f, "TLB refill ERA 0x%lx\n", env->CSR_TLBRERA); + qemu_fprintf(f, "TLB refill BadV 0x%lx\n", env->CSR_TLBRBADV); + qemu_fprintf(f, "EEPN 0x%lx\n", env->CSR_EEPN); + qemu_fprintf(f, "BadInstr 0x%lx\n", env->CSR_BADI); + qemu_fprintf(f, "PRCFG1 0x%lx\nPRCFG2 0x%lx\nPRCFG3 0x%lx\n", + env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3); + if ((flags & CPU_DUMP_FPU) && (env->hflags & LOONGARCH_HFLAG_FPU)) { + fpu_dump_state(env, f, flags); + } +} + +void loongarch_tcg_init(void) +{ + int i; + + for (i = 0; i < 32; i++) + cpu_gpr[i] = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, + active_tc.gpr[i]), + regnames[i]); + + for (i = 0; i < 32; i++) { + int off = offsetof(CPULoongArchState, active_fpu.fpr[i].d); + fpu_f64[i] = tcg_global_mem_new_i64(cpu_env, off, fregnames[i]); + } + + cpu_PC = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, + active_tc.PC), "PC"); + bcond = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, bcond), "bcond"); + btarget = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, btarget), + "btarget"); + hflags = tcg_global_mem_new_i32(cpu_env, + offsetof(CPULoongArchState, hflags), + "hflags"); + fpu_fcsr0 = tcg_global_mem_new_i32(cpu_env, + offsetof(CPULoongArchState, + active_fpu.fcsr0), "fcsr0"); + cpu_lladdr = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, lladdr), + "lladdr"); + cpu_llval = tcg_global_mem_new(cpu_env, + offsetof(CPULoongArchState, llval), + "llval"); +} + +void restore_state_to_opc(CPULoongArchState *env, TranslationBlock *tb, + target_ulong *data) +{ + env->active_tc.PC = data[0]; + env->hflags &= ~LOONGARCH_HFLAG_BMASK; + env->hflags |= data[1]; + switch (env->hflags & LOONGARCH_HFLAG_BMASK) { + case LOONGARCH_HFLAG_BR: + break; + case LOONGARCH_HFLAG_BC: + case LOONGARCH_HFLAG_B: + env->btarget = data[2]; + break; + } +} diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h new file mode 100644 index 0000000..c7f2b4b --- /dev/null +++ b/target/loongarch/translate.h @@ -0,0 +1,58 @@ +/* + * LoongArch translation routines. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef TARGET_LOONGARCH_TRANSLATE_H +#define TARGET_LOONGARCH_TRANSLATE_H + +#include "exec/translator.h" + +#define LOONGARCH_DEBUG_DISAS 0 + +typedef struct DisasContext { + DisasContextBase base; + target_ulong saved_pc; + target_ulong page_start; + uint32_t opcode; + uint64_t insn_flags; + /* Routine used to access memory */ + int mem_idx; + MemOp default_tcg_memop_mask; + uint32_t hflags, saved_hflags; + target_ulong btarget; + uint64_t PAMask; +} DisasContext; + +void generate_exception_err(DisasContext *ctx, int excp, int err); +void generate_exception_end(DisasContext *ctx, int excp); +void gen_reserved_instruction(DisasContext *ctx); + +void check_insn(DisasContext *ctx, uint64_t flags); +void check_loongarch_64(DisasContext *ctx); +void check_fpu_enabled(DisasContext *ctx); + +void gen_base_offset_addr(DisasContext *ctx, TCGv addr, int base, int offset); +void gen_move_low32(TCGv ret, TCGv_i64 arg); +void gen_move_high32(TCGv ret, TCGv_i64 arg); +void gen_load_gpr(TCGv t, int reg); +void gen_store_gpr(TCGv t, int reg); +void gen_load_fpr32(DisasContext *ctx, TCGv_i32 t, int reg); +void gen_load_fpr64(DisasContext *ctx, TCGv_i64 t, int reg); +void gen_store_fpr32(DisasContext *ctx, TCGv_i32 t, int reg); +void gen_store_fpr64(DisasContext *ctx, TCGv_i64 t, int reg); + +/* + * Address Computation and Large Constant Instructions + */ +void gen_op_addr_add(DisasContext *ctx, TCGv ret, TCGv arg0, TCGv arg1); + +extern TCGv cpu_gpr[32], cpu_PC; +extern TCGv_i32 fpu_fscr0; +extern TCGv_i64 fpu_f64[32]; +extern TCGv bcond; + +#endif From patchwork Mon Jun 28 12:04:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347849 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 BF1ADC2B9F4 for ; Mon, 28 Jun 2021 12:20:14 +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 4A35F61584 for ; Mon, 28 Jun 2021 12:20:14 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4A35F61584 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:38004 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqFH-0003Zl-Mk for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:20:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51178) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0c-0002Cj-4f for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:02 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45404 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0U-00018U-2F for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:01 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S9; Mon, 28 Jun 2021 20:04:49 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 07/20] target/loongarch: Add fixed point arithmetic instruction translation Date: Mon, 28 Jun 2021 20:04:32 +0800 Message-Id: <1624881885-31692-8-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S9 X-Coremail-Antispam: 1UD129KBjvAXoWfXw4kWF1rJr4kXF48Aw1kXwb_yoW5Wr43Go W7JayDGrZ5Kw17Xrn09a18XF4Iqw48Cay3J390v3Z5WF43Cr17tw17Kw1rZayxJa4vgrW3 Xa4aqF43J3y3Jr98n29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement fixed point arithemtic instruction translation. This includes: - ADD.{W/D}, SUB.{W/D} - ADDI.{W/D}, ADDU16ID - ALSL.{W[U]/D} - LU12I.W, LU32I.D LU52I.D - SLT[U], SLT[U]I - PCADDI, PCADDU12I, PCADDU18I, PCALAU12I - AND, OR, NOR, XOR, ANDN, ORN - MUL.{W/D}, MULH.{W[U]/D[U]} - MULW.D.W[U] - DIV.{W[U]/D[U]}, MOD.{W[U]/D[U]} - ANDI, ORI, XORI Signed-off-by: Song Gao --- target/loongarch/insns.decode | 89 ++++++++ target/loongarch/instmap.h | 53 +++++ target/loongarch/trans.inc.c | 367 +++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 458 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 967 insertions(+) create mode 100644 target/loongarch/insns.decode create mode 100644 target/loongarch/instmap.h create mode 100644 target/loongarch/trans.inc.c diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode new file mode 100644 index 0000000..1e0b755 --- /dev/null +++ b/target/loongarch/insns.decode @@ -0,0 +1,89 @@ +# +# LoongArch instruction decode definitions. +# +# Copyright (c) 2021 Loongson Technology Corporation Limited +# +# SPDX-License-Identifier: LGPL-2.1+ +# + +# +# Fields +# +%rd 0:5 +%rj 5:5 +%rk 10:5 +%sa2 15:2 +%si12 10:s12 +%ui12 10:12 +%si16 10:s16 +%si20 5:s20 + +# +# Argument sets +# +&fmt_rdrjrk rd rj rk +&fmt_rdrjsi12 rd rj si12 +&fmt_rdrjrksa2 rd rj rk sa2 +&fmt_rdrjsi16 rd rj si16 +&fmt_rdrjui12 rd rj ui12 +&fmt_rdsi20 rd si20 + +# +# Formats +# +@fmt_rdrjrk .... ........ ..... ..... ..... ..... &fmt_rdrjrk %rd %rj %rk +@fmt_rdrjsi12 .... ...... ............ ..... ..... &fmt_rdrjsi12 %rd %rj %si12 +@fmt_rdrjui12 .... ...... ............ ..... ..... &fmt_rdrjui12 %rd %rj %ui12 +@fmt_rdrjrksa2 .... ........ ... .. ..... ..... ..... &fmt_rdrjrksa2 %rd %rj %rk %sa2 +@fmt_rdrjsi16 .... .. ................ ..... ..... &fmt_rdrjsi16 %rd %rj %si16 +@fmt_rdsi20 .... ... .................... ..... &fmt_rdsi20 %rd %si20 + +# +# Fixed point arithmetic operation instruction +# +add_w 0000 00000001 00000 ..... ..... ..... @fmt_rdrjrk +add_d 0000 00000001 00001 ..... ..... ..... @fmt_rdrjrk +sub_w 0000 00000001 00010 ..... ..... ..... @fmt_rdrjrk +sub_d 0000 00000001 00011 ..... ..... ..... @fmt_rdrjrk +slt 0000 00000001 00100 ..... ..... ..... @fmt_rdrjrk +sltu 0000 00000001 00101 ..... ..... ..... @fmt_rdrjrk +slti 0000 001000 ............ ..... ..... @fmt_rdrjsi12 +sltui 0000 001001 ............ ..... ..... @fmt_rdrjsi12 +nor 0000 00000001 01000 ..... ..... ..... @fmt_rdrjrk +and 0000 00000001 01001 ..... ..... ..... @fmt_rdrjrk +or 0000 00000001 01010 ..... ..... ..... @fmt_rdrjrk +xor 0000 00000001 01011 ..... ..... ..... @fmt_rdrjrk +orn 0000 00000001 01100 ..... ..... ..... @fmt_rdrjrk +andn 0000 00000001 01101 ..... ..... ..... @fmt_rdrjrk +mul_w 0000 00000001 11000 ..... ..... ..... @fmt_rdrjrk +mulh_w 0000 00000001 11001 ..... ..... ..... @fmt_rdrjrk +mulh_wu 0000 00000001 11010 ..... ..... ..... @fmt_rdrjrk +mul_d 0000 00000001 11011 ..... ..... ..... @fmt_rdrjrk +mulh_d 0000 00000001 11100 ..... ..... ..... @fmt_rdrjrk +mulh_du 0000 00000001 11101 ..... ..... ..... @fmt_rdrjrk +mulw_d_w 0000 00000001 11110 ..... ..... ..... @fmt_rdrjrk +mulw_d_wu 0000 00000001 11111 ..... ..... ..... @fmt_rdrjrk +div_w 0000 00000010 00000 ..... ..... ..... @fmt_rdrjrk +mod_w 0000 00000010 00001 ..... ..... ..... @fmt_rdrjrk +div_wu 0000 00000010 00010 ..... ..... ..... @fmt_rdrjrk +mod_wu 0000 00000010 00011 ..... ..... ..... @fmt_rdrjrk +div_d 0000 00000010 00100 ..... ..... ..... @fmt_rdrjrk +mod_d 0000 00000010 00101 ..... ..... ..... @fmt_rdrjrk +div_du 0000 00000010 00110 ..... ..... ..... @fmt_rdrjrk +mod_du 0000 00000010 00111 ..... ..... ..... @fmt_rdrjrk +alsl_w 0000 00000000 010 .. ..... ..... ..... @fmt_rdrjrksa2 +alsl_wu 0000 00000000 011 .. ..... ..... ..... @fmt_rdrjrksa2 +alsl_d 0000 00000010 110 .. ..... ..... ..... @fmt_rdrjrksa2 +lu12i_w 0001 010 .................... ..... @fmt_rdsi20 +lu32i_d 0001 011 .................... ..... @fmt_rdsi20 +lu52i_d 0000 001100 ............ ..... ..... @fmt_rdrjsi12 +pcaddi 0001 100 .................... ..... @fmt_rdsi20 +pcalau12i 0001 101 .................... ..... @fmt_rdsi20 +pcaddu12i 0001 110 .................... ..... @fmt_rdsi20 +pcaddu18i 0001 111 .................... ..... @fmt_rdsi20 +addi_w 0000 001010 ............ ..... ..... @fmt_rdrjsi12 +addi_d 0000 001011 ............ ..... ..... @fmt_rdrjsi12 +addu16i_d 0001 00 ................ ..... ..... @fmt_rdrjsi16 +andi 0000 001101 ............ ..... ..... @fmt_rdrjui12 +ori 0000 001110 ............ ..... ..... @fmt_rdrjui12 +xori 0000 001111 ............ ..... ..... @fmt_rdrjui12 diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h new file mode 100644 index 0000000..8844333 --- /dev/null +++ b/target/loongarch/instmap.h @@ -0,0 +1,53 @@ +/* + * LoongArch emulation for qemu: instruction opcode + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef TARGET_LOONGARCH_INSTMAP_H +#define TARGET_LOONGARCH_INSTMAP_H + +/* fixed point opcodes */ +enum { + LA_OPC_ADD_W = (0x00020 << 15), + LA_OPC_ADD_D = (0x00021 << 15), + LA_OPC_SUB_W = (0x00022 << 15), + LA_OPC_SUB_D = (0x00023 << 15), + LA_OPC_SLT = (0x00024 << 15), + LA_OPC_SLTU = (0x00025 << 15), + LA_OPC_NOR = (0x00028 << 15), + LA_OPC_AND = (0x00029 << 15), + LA_OPC_OR = (0x0002A << 15), + LA_OPC_XOR = (0x0002B << 15), + LA_OPC_MUL_W = (0x00038 << 15), + LA_OPC_MULH_W = (0x00039 << 15), + LA_OPC_MULH_WU = (0x0003A << 15), + LA_OPC_MUL_D = (0x0003B << 15), + LA_OPC_MULH_D = (0x0003C << 15), + LA_OPC_MULH_DU = (0x0003D << 15), + LA_OPC_DIV_W = (0x00040 << 15), + LA_OPC_MOD_W = (0x00041 << 15), + LA_OPC_DIV_WU = (0x00042 << 15), + LA_OPC_MOD_WU = (0x00043 << 15), + LA_OPC_DIV_D = (0x00044 << 15), + LA_OPC_MOD_D = (0x00045 << 15), + LA_OPC_DIV_DU = (0x00046 << 15), + LA_OPC_MOD_DU = (0x00047 << 15), + + LA_OPC_ALSL_W = (0x0002 << 17), + LA_OPC_ALSL_D = (0x0016 << 17) + +}; + +/* 12 bit immediate opcodes */ +enum { + LA_OPC_SLTI = (0x008 << 22), + LA_OPC_SLTIU = (0x009 << 22), + LA_OPC_ADDI_W = (0x00A << 22), + LA_OPC_ADDI_D = (0x00B << 22), + LA_OPC_ANDI = (0x00D << 22), + LA_OPC_ORI = (0x00E << 22), + LA_OPC_XORI = (0x00F << 22) +}; diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c new file mode 100644 index 0000000..a5bc1ea --- /dev/null +++ b/target/loongarch/trans.inc.c @@ -0,0 +1,367 @@ +/* + * LoongArch translate functions + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +/* Fixed point arithmetic operation instruction translation */ +static bool trans_add_w(DisasContext *ctx, arg_add_w *a) +{ + gen_loongarch_arith(ctx, LA_OPC_ADD_W, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_add_d(DisasContext *ctx, arg_add_d *a) +{ + gen_loongarch_arith(ctx, LA_OPC_ADD_D, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_sub_w(DisasContext *ctx, arg_sub_w *a) +{ + gen_loongarch_arith(ctx, LA_OPC_SUB_W, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_sub_d(DisasContext *ctx, arg_sub_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_arith(ctx, LA_OPC_SUB_D, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_slt(DisasContext *ctx, arg_slt *a) +{ + gen_loongarch_slt(ctx, LA_OPC_SLT, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_sltu(DisasContext *ctx, arg_sltu *a) +{ + gen_loongarch_slt(ctx, LA_OPC_SLTU, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_slti(DisasContext *ctx, arg_slti *a) +{ + gen_loongarch_slt_imm(ctx, LA_OPC_SLTI, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_sltui(DisasContext *ctx, arg_sltui *a) +{ + gen_loongarch_slt_imm(ctx, LA_OPC_SLTIU, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_nor(DisasContext *ctx, arg_nor *a) +{ + gen_loongarch_logic(ctx, LA_OPC_NOR, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_and(DisasContext *ctx, arg_and *a) +{ + gen_loongarch_logic(ctx, LA_OPC_AND, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_or(DisasContext *ctx, arg_or *a) +{ + gen_loongarch_logic(ctx, LA_OPC_OR, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_xor(DisasContext *ctx, arg_xor *a) +{ + gen_loongarch_logic(ctx, LA_OPC_XOR, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_orn(DisasContext *ctx, arg_orn *a) +{ + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rk); + tcg_gen_not_tl(t0, t0); + tcg_gen_or_tl(cpu_gpr[a->rd], cpu_gpr[a->rj], t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_andn(DisasContext *ctx, arg_andn *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t0, a->rk); + gen_load_gpr(t1, a->rj); + tcg_gen_not_tl(t0, t0); + tcg_gen_and_tl(cpu_gpr[a->rd], t1, t0); + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_mul_w(DisasContext *ctx, arg_mul_w *a) +{ + gen_loongarch_muldiv(ctx, LA_OPC_MUL_W, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mulh_w(DisasContext *ctx, arg_mulh_w *a) +{ + gen_loongarch_muldiv(ctx, LA_OPC_MULH_W, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mulh_wu(DisasContext *ctx, arg_mulh_wu *a) +{ + gen_loongarch_muldiv(ctx, LA_OPC_MULH_WU, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mul_d(DisasContext *ctx, arg_mul_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_muldiv(ctx, LA_OPC_MUL_D, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mulh_d(DisasContext *ctx, arg_mulh_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_muldiv(ctx, LA_OPC_MULH_D, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mulh_du(DisasContext *ctx, arg_mulh_du *a) +{ + check_loongarch_64(ctx); + gen_loongarch_muldiv(ctx, LA_OPC_MULH_DU, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mulw_d_w(DisasContext *ctx, arg_mulw_d_w *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + gen_load_gpr(t0, a->rj); + gen_load_gpr(t1, a->rk); + tcg_gen_ext32s_i64(t0, t0); + tcg_gen_ext32s_i64(t1, t1); + tcg_gen_mul_i64(t2, t0, t1); + gen_store_gpr(t2, a->rd); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return true; +} + +static bool trans_mulw_d_wu(DisasContext *ctx, arg_mulw_d_wu *a) +{ + TCGv_i64 t0 = tcg_temp_new_i64(); + TCGv_i64 t1 = tcg_temp_new_i64(); + TCGv_i64 t2 = tcg_temp_new_i64(); + gen_load_gpr(t0, a->rj); + gen_load_gpr(t1, a->rk); + tcg_gen_ext32u_i64(t0, t0); + tcg_gen_ext32u_i64(t1, t1); + tcg_gen_mul_i64(t2, t0, t1); + gen_store_gpr(t2, a->rd); + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + tcg_temp_free_i64(t2); + return true; +} + +static bool trans_div_w(DisasContext *ctx, arg_div_w *a) +{ + gen_loongarch_muldiv(ctx, LA_OPC_DIV_W, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mod_w(DisasContext *ctx, arg_mod_w *a) +{ + gen_loongarch_muldiv(ctx, LA_OPC_MOD_W, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_div_wu(DisasContext *ctx, arg_div_wu *a) +{ + gen_loongarch_muldiv(ctx, LA_OPC_DIV_WU, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mod_wu(DisasContext *ctx, arg_mod_wu *a) +{ + gen_loongarch_muldiv(ctx, LA_OPC_MOD_WU, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_div_d(DisasContext *ctx, arg_div_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_muldiv(ctx, LA_OPC_DIV_D, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mod_d(DisasContext *ctx, arg_mod_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_muldiv(ctx, LA_OPC_MOD_D, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_div_du(DisasContext *ctx, arg_div_du *a) +{ + check_loongarch_64(ctx); + gen_loongarch_muldiv(ctx, LA_OPC_DIV_DU, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_mod_du(DisasContext *ctx, arg_mod_du *a) +{ + check_loongarch_64(ctx); + gen_loongarch_muldiv(ctx, LA_OPC_MOD_DU, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_alsl_w(DisasContext *ctx, arg_alsl_w *a) +{ + gen_loongarch_alsl(ctx, LA_OPC_ALSL_W, a->rd, a->rj, a->rk, a->sa2); + return true; +} + +static bool trans_alsl_wu(DisasContext *ctx, arg_alsl_wu *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t0, a->rj); + gen_load_gpr(t1, a->rk); + tcg_gen_shli_tl(t0, t0, a->sa2 + 1); + tcg_gen_add_tl(t0, t0, t1); + tcg_gen_ext32u_tl(cpu_gpr[a->rd], t0); + tcg_temp_free(t0); + tcg_temp_free(t1); + + return true; +} + +static bool trans_alsl_d(DisasContext *ctx, arg_alsl_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_alsl(ctx, LA_OPC_ALSL_D, a->rd, a->rj, a->rk, a->sa2); + return true; +} + +static bool trans_lu12i_w(DisasContext *ctx, arg_lu12i_w *a) +{ + tcg_gen_movi_tl(cpu_gpr[a->rd], a->si20 << 12); + return true; +} + +static bool trans_lu32i_d(DisasContext *ctx, arg_lu32i_d *a) +{ + TCGv_i64 t0, t1; + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + tcg_gen_movi_tl(t0, a->si20); + tcg_gen_concat_tl_i64(t1, cpu_gpr[a->rd], t0); + gen_store_gpr(t1, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_lu52i_d(DisasContext *ctx, arg_lu52i_d *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_load_gpr(t1, a->rj); + + tcg_gen_movi_tl(t0, a->si12); + tcg_gen_shli_tl(t0, t0, 52); + tcg_gen_andi_tl(t1, t1, 0xfffffffffffffU); + tcg_gen_or_tl(cpu_gpr[a->rd], t0, t1); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_pcaddi(DisasContext *ctx, arg_pcaddi *a) +{ + target_ulong pc = ctx->base.pc_next; + target_ulong addr = pc + (a->si20 << 2); + tcg_gen_movi_tl(cpu_gpr[a->rd], addr); + return true; +} + +static bool trans_pcalau12i(DisasContext *ctx, arg_pcalau12i *a) +{ + target_ulong pc = ctx->base.pc_next; + target_ulong addr = (pc + (a->si20 << 12)) & ~0xfff; + tcg_gen_movi_tl(cpu_gpr[a->rd], addr); + return true; +} + +static bool trans_pcaddu12i(DisasContext *ctx, arg_pcaddu12i *a) +{ + target_ulong pc = ctx->base.pc_next; + target_ulong addr = pc + (a->si20 << 12); + tcg_gen_movi_tl(cpu_gpr[a->rd], addr); + return true; +} + +static bool trans_pcaddu18i(DisasContext *ctx, arg_pcaddu18i *a) +{ + target_ulong pc = ctx->base.pc_next; + target_ulong addr = pc + ((target_ulong)(a->si20) << 18); + tcg_gen_movi_tl(cpu_gpr[a->rd], addr); + return true; +} + +static bool trans_addi_w(DisasContext *ctx, arg_addi_w *a) +{ + gen_loongarch_arith_imm(ctx, LA_OPC_ADDI_W, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_addi_d(DisasContext *ctx, arg_addi_d *a) +{ + gen_loongarch_arith_imm(ctx, LA_OPC_ADDI_D, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_addu16i_d(DisasContext *ctx, arg_addu16i_d *a) +{ + if (a->rj != 0) { + tcg_gen_addi_tl(cpu_gpr[a->rd], cpu_gpr[a->rj], a->si16 << 16); + } else { + tcg_gen_movi_tl(cpu_gpr[a->rd], a->si16 << 16); + } + return true; +} + +static bool trans_andi(DisasContext *ctx, arg_andi *a) +{ + gen_loongarch_logic_imm(ctx, LA_OPC_ANDI, a->rd, a->rj, a->ui12); + return true; +} + +static bool trans_ori(DisasContext *ctx, arg_ori *a) +{ + gen_loongarch_logic_imm(ctx, LA_OPC_ORI, a->rd, a->rj, a->ui12); + return true; +} + +static bool trans_xori(DisasContext *ctx, arg_xori *a) +{ + gen_loongarch_logic_imm(ctx, LA_OPC_XORI, a->rd, a->rj, a->ui12); + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 83efd39..3b40a59 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -292,6 +292,461 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, ctx->default_tcg_memop_mask = MO_UNALN; } +/* loongarch arithmetic */ +static void gen_loongarch_arith(DisasContext *ctx, uint32_t opc, + int rd, int rj, int rk) +{ + if (rd == 0) { + /* Treat as NOP. */ + return; + } + + switch (opc) { + case LA_OPC_ADD_W: + if (rj != 0 && rk != 0) { + tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rj], cpu_gpr[rk]); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } else if (rj == 0 && rk != 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rk]); + } else if (rj != 0 && rk == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rj]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + break; + case LA_OPC_SUB_W: + if (rj != 0 && rk != 0) { + tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rj], cpu_gpr[rk]); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } else if (rj == 0 && rk != 0) { + tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rk]); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } else if (rj != 0 && rk == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rj]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + break; + case LA_OPC_ADD_D: + if (rj != 0 && rk != 0) { + tcg_gen_add_tl(cpu_gpr[rd], cpu_gpr[rj], cpu_gpr[rk]); + } else if (rj == 0 && rk != 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rk]); + } else if (rj != 0 && rk == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rj]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + break; + case LA_OPC_SUB_D: + if (rj != 0 && rk != 0) { + tcg_gen_sub_tl(cpu_gpr[rd], cpu_gpr[rj], cpu_gpr[rk]); + } else if (rj == 0 && rk != 0) { + tcg_gen_neg_tl(cpu_gpr[rd], cpu_gpr[rk]); + } else if (rj != 0 && rk == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rj]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + break; + } +} + +/* loongarch arithmetic with immediate operand */ +static void gen_loongarch_arith_imm(DisasContext *ctx, uint32_t opc, + int rd, int rj, int imm) +{ + target_ulong uimm = (target_long)imm; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + switch (opc) { + case LA_OPC_ADDI_W: + if (rj != 0) { + tcg_gen_addi_tl(cpu_gpr[rd], cpu_gpr[rj], uimm); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], uimm); + } + break; + case LA_OPC_ADDI_D: + if (rj != 0) { + tcg_gen_addi_tl(cpu_gpr[rd], cpu_gpr[rj], uimm); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], uimm); + } + break; + } +} + +/* loongarch set on lower than */ +static void gen_loongarch_slt(DisasContext *ctx, uint32_t opc, + int rd, int rj, int rk) +{ + TCGv t0, t1; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, rj); + gen_load_gpr(t1, rk); + switch (opc) { + case LA_OPC_SLT: + tcg_gen_setcond_tl(TCG_COND_LT, cpu_gpr[rd], t0, t1); + break; + case LA_OPC_SLTU: + tcg_gen_setcond_tl(TCG_COND_LTU, cpu_gpr[rd], t0, t1); + break; + } + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +/* loongarch set on less than with immediate operand */ +static void gen_loongarch_slt_imm(DisasContext *ctx, uint32_t opc, + int rd, int rj, int16_t imm) +{ + target_ulong uimm = (target_long)imm; + TCGv t0; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = tcg_temp_new(); + gen_load_gpr(t0, rj); + switch (opc) { + case LA_OPC_SLTI: + tcg_gen_setcondi_tl(TCG_COND_LT, cpu_gpr[rd], t0, uimm); + break; + case LA_OPC_SLTIU: + tcg_gen_setcondi_tl(TCG_COND_LTU, cpu_gpr[rd], t0, uimm); + break; + } + tcg_temp_free(t0); +} + +/* loongarch logic */ +static void gen_loongarch_logic(DisasContext *ctx, uint32_t opc, + int rd, int rj, int rk) +{ + if (rd == 0) { + /* Treat as NOP. */ + return; + } + + switch (opc) { + case LA_OPC_AND: + if (likely(rj != 0 && rk != 0)) { + tcg_gen_and_tl(cpu_gpr[rd], cpu_gpr[rj], cpu_gpr[rk]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + break; + case LA_OPC_NOR: + if (rj != 0 && rk != 0) { + tcg_gen_nor_tl(cpu_gpr[rd], cpu_gpr[rj], cpu_gpr[rk]); + } else if (rj == 0 && rk != 0) { + tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rk]); + } else if (rj != 0 && rk == 0) { + tcg_gen_not_tl(cpu_gpr[rd], cpu_gpr[rj]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], ~((target_ulong)0)); + } + break; + case LA_OPC_OR: + if (likely(rj != 0 && rk != 0)) { + tcg_gen_or_tl(cpu_gpr[rd], cpu_gpr[rj], cpu_gpr[rk]); + } else if (rj == 0 && rk != 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rk]); + } else if (rj != 0 && rk == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rj]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + break; + case LA_OPC_XOR: + if (likely(rj != 0 && rk != 0)) { + tcg_gen_xor_tl(cpu_gpr[rd], cpu_gpr[rj], cpu_gpr[rk]); + } else if (rj == 0 && rk != 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rk]); + } else if (rj != 0 && rk == 0) { + tcg_gen_mov_tl(cpu_gpr[rd], cpu_gpr[rj]); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + break; + } +} + +/* loongarch logic with immediate operand */ +static void gen_loongarch_logic_imm(DisasContext *ctx, uint32_t opc, + int rd, int rj, int16_t imm) +{ + target_ulong uimm; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + uimm = (uint16_t)imm; + switch (opc) { + case LA_OPC_ANDI: + if (likely(rj != 0)) { + tcg_gen_andi_tl(cpu_gpr[rd], cpu_gpr[rj], uimm); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], 0); + } + break; + case LA_OPC_ORI: + if (rj != 0) { + tcg_gen_ori_tl(cpu_gpr[rd], cpu_gpr[rj], uimm); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], uimm); + } + break; + case LA_OPC_XORI: + if (likely(rj != 0)) { + tcg_gen_xori_tl(cpu_gpr[rd], cpu_gpr[rj], uimm); + } else { + tcg_gen_movi_tl(cpu_gpr[rd], uimm); + } + break; + default: + break; + } +} + +/* loongarch mul and div */ +static void gen_loongarch_muldiv(DisasContext *ctx, int opc, int rd, + int rj, int rk) +{ + TCGv t0, t1; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, rj); + gen_load_gpr(t1, rk); + + switch (opc) { + case LA_OPC_DIV_W: + { + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); + tcg_gen_and_tl(t2, t2, t3); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_tl(t2, t2, t3); + tcg_gen_movi_tl(t3, 0); + tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_div_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + break; + case LA_OPC_MOD_W: + { + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + tcg_gen_ext32s_tl(t0, t0); + tcg_gen_ext32s_tl(t1, t1); + tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, INT_MIN); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1); + tcg_gen_and_tl(t2, t2, t3); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_tl(t2, t2, t3); + tcg_gen_movi_tl(t3, 0); + tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + break; + case LA_OPC_DIV_WU: + { + TCGv t2 = tcg_const_tl(0); + TCGv t3 = tcg_const_tl(1); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); + tcg_gen_divu_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + break; + case LA_OPC_MOD_WU: + { + TCGv t2 = tcg_const_tl(0); + TCGv t3 = tcg_const_tl(1); + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); + tcg_gen_remu_tl(cpu_gpr[rd], t0, t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + break; + case LA_OPC_MUL_W: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_mul_i32(t2, t2, t3); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + break; + case LA_OPC_MULH_W: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_muls2_i32(t2, t3, t2, t3); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + break; + case LA_OPC_MULH_WU: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_mulu2_i32(t2, t3, t2, t3); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t3); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + break; + case LA_OPC_DIV_D: + { + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); + tcg_gen_and_tl(t2, t2, t3); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_tl(t2, t2, t3); + tcg_gen_movi_tl(t3, 0); + tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_div_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + break; + case LA_OPC_MOD_D: + { + TCGv t2 = tcg_temp_new(); + TCGv t3 = tcg_temp_new(); + tcg_gen_setcondi_tl(TCG_COND_EQ, t2, t0, -1LL << 63); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, -1LL); + tcg_gen_and_tl(t2, t2, t3); + tcg_gen_setcondi_tl(TCG_COND_EQ, t3, t1, 0); + tcg_gen_or_tl(t2, t2, t3); + tcg_gen_movi_tl(t3, 0); + tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1); + tcg_gen_rem_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + break; + case LA_OPC_DIV_DU: + { + TCGv t2 = tcg_const_tl(0); + TCGv t3 = tcg_const_tl(1); + tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); + tcg_gen_divu_i64(cpu_gpr[rd], t0, t1); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + break; + case LA_OPC_MOD_DU: + { + TCGv t2 = tcg_const_tl(0); + TCGv t3 = tcg_const_tl(1); + tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1); + tcg_gen_remu_i64(cpu_gpr[rd], t0, t1); + tcg_temp_free(t3); + tcg_temp_free(t2); + } + break; + case LA_OPC_MUL_D: + tcg_gen_mul_i64(cpu_gpr[rd], t0, t1); + break; + case LA_OPC_MULH_D: + { + TCGv t2 = tcg_temp_new(); + tcg_gen_muls2_i64(t2, cpu_gpr[rd], t0, t1); + tcg_temp_free(t2); + } + break; + case LA_OPC_MULH_DU: + { + TCGv t2 = tcg_temp_new(); + tcg_gen_mulu2_i64(t2, cpu_gpr[rd], t0, t1); + tcg_temp_free(t2); + } + break; + default: + generate_exception_end(ctx, EXCP_INE); + goto out; + } + out: + tcg_temp_free(t0); + tcg_temp_free(t1); + + return; +} + +/* loongarch alsl_X */ +static void gen_loongarch_alsl(DisasContext *ctx, int opc, int rd, + int rj, int rk, int imm2) +{ + TCGv t0; + TCGv t1; + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, rj); + gen_load_gpr(t1, rk); + tcg_gen_shli_tl(t0, t0, imm2 + 1); + tcg_gen_add_tl(cpu_gpr[rd], t0, t1); + if (opc == LA_OPC_ALSL_W) { + tcg_gen_ext32s_tl(cpu_gpr[rd], cpu_gpr[rd]); + } + + tcg_temp_free(t1); + tcg_temp_free(t0); + + return; +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } @@ -337,6 +792,9 @@ static bool decode_lsx(uint32_t opcode) return false; } +#include "decode-insns.c.inc" +#include "trans.inc.c" + static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs) { CPULoongArchState *env = cs->env_ptr; From patchwork Mon Jun 28 12:04:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347841 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 BFADCC2B9F4 for ; Mon, 28 Jun 2021 12:16:48 +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 33EB361C3D for ; Mon, 28 Jun 2021 12:16:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 33EB361C3D Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:57670 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqBw-0006CK-Db for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:16:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51188) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0c-0002DH-Gn for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:02 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45420 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0V-00019E-7Z for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:02 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S10; Mon, 28 Jun 2021 20:04:51 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 08/20] target/loongarch: Add fixed point shift instruction translation Date: Mon, 28 Jun 2021 20:04:33 +0800 Message-Id: <1624881885-31692-9-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S10 X-Coremail-Antispam: 1UD129KBjvJXoW3CF15uF1fGFyrZry5GryUKFg_yoWDArWxpr 1Uury8Wr48tr17Gr9Ikr15Gr98JF1IkF1jg3sav348CF48J3WDJrnYy3yayFWjvws7WFWj vF98uFy7KFy8XwUanT9S1TB71UUUUjDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UUUUUUUUU== X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement fixed point shift instruction translation. This includes: - SLL.W, SRL.W, SRA.W, ROTR.W - SLLI.W, SRLI.W, SRAI.W, ROTRI.W - SLL.D, SRL.D, SRA.D, ROTR.D - SLLI.D, SRLI.D, SRAI.D, ROTRI.D Signed-off-by: Song Gao --- target/loongarch/insns.decode | 26 ++++++++ target/loongarch/instmap.h | 13 ++++ target/loongarch/trans.inc.c | 134 ++++++++++++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 107 +++++++++++++++++++++++++++++++++ 4 files changed, 280 insertions(+) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 1e0b755..9302576 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -17,6 +17,8 @@ %ui12 10:12 %si16 10:s16 %si20 5:s20 +%ui5 10:5 +%ui6 10:6 # # Argument sets @@ -27,6 +29,8 @@ &fmt_rdrjsi16 rd rj si16 &fmt_rdrjui12 rd rj ui12 &fmt_rdsi20 rd si20 +&fmt_rdrjui5 rd rj ui5 +&fmt_rdrjui6 rd rj ui6 # # Formats @@ -37,6 +41,8 @@ @fmt_rdrjrksa2 .... ........ ... .. ..... ..... ..... &fmt_rdrjrksa2 %rd %rj %rk %sa2 @fmt_rdrjsi16 .... .. ................ ..... ..... &fmt_rdrjsi16 %rd %rj %si16 @fmt_rdsi20 .... ... .................... ..... &fmt_rdsi20 %rd %si20 +@fmt_rdrjui5 .... ........ ..... ..... ..... ..... &fmt_rdrjui5 %rd %rj %ui5 +@fmt_rdrjui6 .... ........ .... ...... ..... ..... &fmt_rdrjui6 %rd %rj %ui6 # # Fixed point arithmetic operation instruction @@ -87,3 +93,23 @@ addu16i_d 0001 00 ................ ..... ..... @fmt_rdrjsi16 andi 0000 001101 ............ ..... ..... @fmt_rdrjui12 ori 0000 001110 ............ ..... ..... @fmt_rdrjui12 xori 0000 001111 ............ ..... ..... @fmt_rdrjui12 + +# +# Fixed point shift operation instruction +# +sll_w 0000 00000001 01110 ..... ..... ..... @fmt_rdrjrk +srl_w 0000 00000001 01111 ..... ..... ..... @fmt_rdrjrk +sra_w 0000 00000001 10000 ..... ..... ..... @fmt_rdrjrk +sll_d 0000 00000001 10001 ..... ..... ..... @fmt_rdrjrk +srl_d 0000 00000001 10010 ..... ..... ..... @fmt_rdrjrk +sra_d 0000 00000001 10011 ..... ..... ..... @fmt_rdrjrk +rotr_w 0000 00000001 10110 ..... ..... ..... @fmt_rdrjrk +rotr_d 0000 00000001 10111 ..... ..... ..... @fmt_rdrjrk +slli_w 0000 00000100 00001 ..... ..... ..... @fmt_rdrjui5 +slli_d 0000 00000100 0001 ...... ..... ..... @fmt_rdrjui6 +srli_w 0000 00000100 01001 ..... ..... ..... @fmt_rdrjui5 +srli_d 0000 00000100 0101 ...... ..... ..... @fmt_rdrjui6 +srai_w 0000 00000100 10001 ..... ..... ..... @fmt_rdrjui5 +srai_d 0000 00000100 1001 ...... ..... ..... @fmt_rdrjui6 +rotri_w 0000 00000100 11001 ..... ..... ..... @fmt_rdrjui5 +rotri_d 0000 00000100 1101 ...... ..... ..... @fmt_rdrjui6 diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h index 8844333..5aaffb4 100644 --- a/target/loongarch/instmap.h +++ b/target/loongarch/instmap.h @@ -21,6 +21,14 @@ enum { LA_OPC_AND = (0x00029 << 15), LA_OPC_OR = (0x0002A << 15), LA_OPC_XOR = (0x0002B << 15), + LA_OPC_SLL_W = (0x0002E << 15), + LA_OPC_SRL_W = (0x0002F << 15), + LA_OPC_SRA_W = (0x00030 << 15), + LA_OPC_SLL_D = (0x00031 << 15), + LA_OPC_SRL_D = (0x00032 << 15), + LA_OPC_SRA_D = (0x00033 << 15), + LA_OPC_ROTR_W = (0x00036 << 15), + LA_OPC_ROTR_D = (0x00037 << 15), LA_OPC_MUL_W = (0x00038 << 15), LA_OPC_MULH_W = (0x00039 << 15), LA_OPC_MULH_WU = (0x0003A << 15), @@ -35,6 +43,9 @@ enum { LA_OPC_MOD_D = (0x00045 << 15), LA_OPC_DIV_DU = (0x00046 << 15), LA_OPC_MOD_DU = (0x00047 << 15), + LA_OPC_SRLI_W = (0x00089 << 15), + LA_OPC_SRAI_W = (0x00091 << 15), + LA_OPC_ROTRI_W = (0x00099 << 15), LA_OPC_ALSL_W = (0x0002 << 17), LA_OPC_ALSL_D = (0x0016 << 17) @@ -51,3 +62,5 @@ enum { LA_OPC_ORI = (0x00E << 22), LA_OPC_XORI = (0x00F << 22) }; + +#endif diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index a5bc1ea..7d3b45f 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -365,3 +365,137 @@ static bool trans_xori(DisasContext *ctx, arg_xori *a) gen_loongarch_logic_imm(ctx, LA_OPC_XORI, a->rd, a->rj, a->ui12); return true; } + +/* Fixed point shift operation instruction translation */ +static bool trans_sll_w(DisasContext *ctx, arg_sll_w *a) +{ + gen_loongarch_shift(ctx, LA_OPC_SLL_W, a->rd, a->rk, a->rj); + return true; +} + +static bool trans_srl_w(DisasContext *ctx, arg_srl_w *a) +{ + gen_loongarch_shift(ctx, LA_OPC_SRL_W, a->rd, a->rk, a->rj); + return true; +} + +static bool trans_sra_w(DisasContext *ctx, arg_sra_w *a) +{ + gen_loongarch_shift(ctx, LA_OPC_SRA_W, a->rd, a->rk, a->rj); + return true; +} + +static bool trans_sll_d(DisasContext *ctx, arg_sll_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_shift(ctx, LA_OPC_SLL_D, a->rd, a->rk, a->rj); + return true; +} +static bool trans_srl_d(DisasContext *ctx, arg_srl_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_shift(ctx, LA_OPC_SRL_D, a->rd, a->rk, a->rj); + return true; +} + +static bool trans_sra_d(DisasContext *ctx, arg_sra_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_shift(ctx, LA_OPC_SRA_D, a->rd, a->rk, a->rj); + return true; +} + +static bool trans_rotr_w(DisasContext *ctx, arg_rotr_w *a) +{ + gen_loongarch_shift(ctx, LA_OPC_ROTR_W, a->rd, a->rk, a->rj); + return true; +} + +static bool trans_rotr_d(DisasContext *ctx, arg_rotr_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_shift(ctx, LA_OPC_ROTR_D, a->rd, a->rk, a->rj); + return true; +} + +static bool trans_slli_w(DisasContext *ctx, arg_slli_w *a) +{ + if (a->rd == 0) { + /* Nop */ + return true; + } + + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, a->rj); + tcg_gen_shli_tl(t0, t0, a->ui5); + tcg_gen_ext32s_tl(cpu_gpr[a->rd], t0); + + tcg_temp_free(t0); + return true; +} + +static bool trans_slli_d(DisasContext *ctx, arg_slli_d *a) +{ + if (a->rd == 0) { + /* Nop */ + return true; + } + + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, a->rj); + tcg_gen_shli_tl(cpu_gpr[a->rd], t0, a->ui6); + + tcg_temp_free(t0); + return true; +} + +static bool trans_srli_w(DisasContext *ctx, arg_srli_w *a) +{ + gen_loongarch_shift_imm(ctx, LA_OPC_SRLI_W, a->rd, a->rj, a->ui5); + return true; +} + +static bool trans_srli_d(DisasContext *ctx, arg_srli_d *a) +{ + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, a->rj); + tcg_gen_shri_tl(cpu_gpr[a->rd], t0, a->ui6); + + tcg_temp_free(t0); + return true; +} + +static bool trans_srai_w(DisasContext *ctx, arg_srai_w *a) +{ + gen_loongarch_shift_imm(ctx, LA_OPC_SRAI_W, a->rd, a->rj, a->ui5); + return true; +} + +static bool trans_srai_d(DisasContext *ctx, arg_srai_d *a) +{ + TCGv t0 = tcg_temp_new(); + check_loongarch_64(ctx); + gen_load_gpr(t0, a->rj); + tcg_gen_sari_tl(cpu_gpr[a->rd], t0, a->ui6); + tcg_temp_free(t0); + return true; +} + +static bool trans_rotri_w(DisasContext *ctx, arg_rotri_w *a) +{ + gen_loongarch_shift_imm(ctx, LA_OPC_ROTRI_W, a->rd, a->rj, a->ui5); + return true; +} + +static bool trans_rotri_d(DisasContext *ctx, arg_rotri_d *a) +{ + TCGv t0 = tcg_temp_new(); + check_loongarch_64(ctx); + gen_load_gpr(t0, a->rj); + tcg_gen_rotri_tl(cpu_gpr[a->rd], t0, a->ui6); + tcg_temp_free(t0); + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 3b40a59..60f884f 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -747,6 +747,113 @@ static void gen_loongarch_alsl(DisasContext *ctx, int opc, int rd, return; } +/*loongarch shifts */ +static void gen_loongarch_shift(DisasContext *ctx, uint32_t opc, + int rd, int rj, int rk) +{ + TCGv t0, t1; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + gen_load_gpr(t0, rj); + gen_load_gpr(t1, rk); + switch (opc) { + case LA_OPC_SLL_W: + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_shl_tl(t0, t1, t0); + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + break; + case LA_OPC_SRA_W: + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); + break; + case LA_OPC_SRL_W: + tcg_gen_ext32u_tl(t1, t1); + tcg_gen_andi_tl(t0, t0, 0x1f); + tcg_gen_shr_tl(t0, t1, t0); + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + break; + case LA_OPC_ROTR_W: + { + TCGv_i32 t2 = tcg_temp_new_i32(); + TCGv_i32 t3 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(t2, t0); + tcg_gen_trunc_tl_i32(t3, t1); + tcg_gen_andi_i32(t2, t2, 0x1f); + tcg_gen_rotr_i32(t2, t3, t2); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t2); + tcg_temp_free_i32(t2); + tcg_temp_free_i32(t3); + } + break; + case LA_OPC_SLL_D: + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_shl_tl(cpu_gpr[rd], t1, t0); + break; + case LA_OPC_SRA_D: + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_sar_tl(cpu_gpr[rd], t1, t0); + break; + case LA_OPC_SRL_D: + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_shr_tl(cpu_gpr[rd], t1, t0); + break; + case LA_OPC_ROTR_D: + tcg_gen_andi_tl(t0, t0, 0x3f); + tcg_gen_rotr_tl(cpu_gpr[rd], t1, t0); + break; + } + tcg_temp_free(t0); + tcg_temp_free(t1); +} + +/* loongarch shifts with immediate operand */ +static void gen_loongarch_shift_imm(DisasContext *ctx, uint32_t opc, + int rd, int rj, int16_t imm) +{ + target_ulong uimm = ((uint16_t)imm) & 0x1f; + TCGv t0; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, rj); + switch (opc) { + case LA_OPC_SRAI_W: + tcg_gen_sari_tl(cpu_gpr[rd], t0, uimm); + break; + case LA_OPC_SRLI_W: + if (uimm != 0) { + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_shri_tl(cpu_gpr[rd], t0, uimm); + } else { + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + } + break; + case LA_OPC_ROTRI_W: + if (uimm != 0) { + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(t1, t0); + tcg_gen_rotri_i32(t1, t1, uimm); + tcg_gen_ext_i32_tl(cpu_gpr[rd], t1); + tcg_temp_free_i32(t1); + } else { + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + } + break; + } + tcg_temp_free(t0); +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347799 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 3F826C2B9F4 for ; Mon, 28 Jun 2021 12:10:43 +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 7E6FE61477 for ; Mon, 28 Jun 2021 12:10:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7E6FE61477 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:41366 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq65-0002hR-Jm for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:10:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51212) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0f-0002Hj-RK for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:05 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45482 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0Y-0001A9-6D for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:05 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S11; Mon, 28 Jun 2021 20:04:52 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 09/20] target/loongarch: Add fixed point bit instruction translation Date: Mon, 28 Jun 2021 20:04:34 +0800 Message-Id: <1624881885-31692-10-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S11 X-Coremail-Antispam: 1UD129KBjvAXoWftr4rtF4fGw48ur45Ar1fJFb_yoW8uFyxZo W7GF15ArW8Gw1avrnIva1DXr4jqry8Cay7J39I9w1kW3W8Cry7tFyjgFn5ZayxJws2grW5 Xa4aqFnxJ3y3Ar97n29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement fixed point bit instruction translation. This includes: - EXT.W.{B/H} - CL{O/Z}.{W/D}, CT{O/Z}.{W/D} - BYTEPICK.{W/D} - REVB.{2H/4H/2W/D} - REVH.{2W/D} - BITREV.{4B/8B}, BITREV.{W/D} - BSTRINS.{W/D}, BSTRPICK.{W/D} - MASKEQZ, MASKNEZ Signed-off-by: Song Gao --- target/loongarch/helper.h | 10 ++ target/loongarch/insns.decode | 45 +++++++ target/loongarch/instmap.h | 19 ++- target/loongarch/op_helper.c | 119 +++++++++++++++++ target/loongarch/trans.inc.c | 233 +++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 298 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 722 insertions(+), 2 deletions(-) diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 6c7e19b..bbbcc26 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -8,3 +8,13 @@ DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) DEF_HELPER_2(raise_exception, noreturn, env, i32) + +DEF_HELPER_2(cto_w, tl, env, tl) +DEF_HELPER_2(ctz_w, tl, env, tl) +DEF_HELPER_2(cto_d, tl, env, tl) +DEF_HELPER_2(ctz_d, tl, env, tl) +DEF_HELPER_2(bitrev_w, tl, env, tl) +DEF_HELPER_2(bitrev_d, tl, env, tl) + +DEF_HELPER_FLAGS_1(loongarch_bitswap, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(loongarch_dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 9302576..ec599a9 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -13,12 +13,17 @@ %rj 5:5 %rk 10:5 %sa2 15:2 +%sa3 15:3 %si12 10:s12 %ui12 10:12 %si16 10:s16 %si20 5:s20 %ui5 10:5 %ui6 10:6 +%msbw 16:5 +%lsbw 10:5 +%msbd 16:6 +%lsbd 10:6 # # Argument sets @@ -31,6 +36,10 @@ &fmt_rdsi20 rd si20 &fmt_rdrjui5 rd rj ui5 &fmt_rdrjui6 rd rj ui6 +&fmt_rdrj rd rj +&fmt_rdrjrksa3 rd rj rk sa3 +&fmt_rdrjmsbwlsbw rd rj msbw lsbw +&fmt_rdrjmsbdlsbd rd rj msbd lsbd # # Formats @@ -43,6 +52,10 @@ @fmt_rdsi20 .... ... .................... ..... &fmt_rdsi20 %rd %si20 @fmt_rdrjui5 .... ........ ..... ..... ..... ..... &fmt_rdrjui5 %rd %rj %ui5 @fmt_rdrjui6 .... ........ .... ...... ..... ..... &fmt_rdrjui6 %rd %rj %ui6 +@fmt_rdrj .... ........ ..... ..... ..... ..... &fmt_rdrj %rd %rj +@fmt_rdrjmsbwlsbw .... ....... ..... . ..... ..... ..... &fmt_rdrjmsbwlsbw %rd %rj %msbw %lsbw +@fmt_rdrjmsbdlsbd .... ...... ...... ...... ..... ..... &fmt_rdrjmsbdlsbd %rd %rj %msbd %lsbd +@fmt_rdrjrksa3 .... ........ .. ... ..... ..... ..... &fmt_rdrjrksa3 %rd %rj %rk %sa3 # # Fixed point arithmetic operation instruction @@ -113,3 +126,35 @@ srai_w 0000 00000100 10001 ..... ..... ..... @fmt_rdrjui5 srai_d 0000 00000100 1001 ...... ..... ..... @fmt_rdrjui6 rotri_w 0000 00000100 11001 ..... ..... ..... @fmt_rdrjui5 rotri_d 0000 00000100 1101 ...... ..... ..... @fmt_rdrjui6 + +# +# Fixed point bit operation instruction +# +ext_w_h 0000 00000000 00000 10110 ..... ..... @fmt_rdrj +ext_w_b 0000 00000000 00000 10111 ..... ..... @fmt_rdrj +clo_w 0000 00000000 00000 00100 ..... ..... @fmt_rdrj +clz_w 0000 00000000 00000 00101 ..... ..... @fmt_rdrj +cto_w 0000 00000000 00000 00110 ..... ..... @fmt_rdrj +ctz_w 0000 00000000 00000 00111 ..... ..... @fmt_rdrj +clo_d 0000 00000000 00000 01000 ..... ..... @fmt_rdrj +clz_d 0000 00000000 00000 01001 ..... ..... @fmt_rdrj +cto_d 0000 00000000 00000 01010 ..... ..... @fmt_rdrj +ctz_d 0000 00000000 00000 01011 ..... ..... @fmt_rdrj +revb_2h 0000 00000000 00000 01100 ..... ..... @fmt_rdrj +revb_4h 0000 00000000 00000 01101 ..... ..... @fmt_rdrj +revb_2w 0000 00000000 00000 01110 ..... ..... @fmt_rdrj +revb_d 0000 00000000 00000 01111 ..... ..... @fmt_rdrj +revh_2w 0000 00000000 00000 10000 ..... ..... @fmt_rdrj +revh_d 0000 00000000 00000 10001 ..... ..... @fmt_rdrj +bitrev_4b 0000 00000000 00000 10010 ..... ..... @fmt_rdrj +bitrev_8b 0000 00000000 00000 10011 ..... ..... @fmt_rdrj +bitrev_w 0000 00000000 00000 10100 ..... ..... @fmt_rdrj +bitrev_d 0000 00000000 00000 10101 ..... ..... @fmt_rdrj +bytepick_w 0000 00000000 100 .. ..... ..... ..... @fmt_rdrjrksa2 +bytepick_d 0000 00000000 11 ... ..... ..... ..... @fmt_rdrjrksa3 +maskeqz 0000 00000001 00110 ..... ..... ..... @fmt_rdrjrk +masknez 0000 00000001 00111 ..... ..... ..... @fmt_rdrjrk +bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @fmt_rdrjmsbwlsbw +bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @fmt_rdrjmsbwlsbw +bstrins_d 0000 000010 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd +bstrpick_d 0000 000011 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h index 5aaffb4..57b5a1c 100644 --- a/target/loongarch/instmap.h +++ b/target/loongarch/instmap.h @@ -11,12 +11,26 @@ /* fixed point opcodes */ enum { + LA_OPC_CLO_W = (0x000004 << 10), + LA_OPC_CLZ_W = (0x000005 << 10), + LA_OPC_CLO_D = (0x000008 << 10), + LA_OPC_CLZ_D = (0x000009 << 10), + LA_OPC_REVB_2H = (0x00000C << 10), + LA_OPC_REVB_4H = (0x00000D << 10), + LA_OPC_REVH_D = (0x000011 << 10), + LA_OPC_BREV_4B = (0x000012 << 10), + LA_OPC_BREV_8B = (0x000013 << 10), + LA_OPC_EXT_WH = (0x000016 << 10), + LA_OPC_EXT_WB = (0x000017 << 10), + LA_OPC_ADD_W = (0x00020 << 15), LA_OPC_ADD_D = (0x00021 << 15), LA_OPC_SUB_W = (0x00022 << 15), LA_OPC_SUB_D = (0x00023 << 15), LA_OPC_SLT = (0x00024 << 15), LA_OPC_SLTU = (0x00025 << 15), + LA_OPC_MASKEQZ = (0x00026 << 15), + LA_OPC_MASKNEZ = (0x00027 << 15), LA_OPC_NOR = (0x00028 << 15), LA_OPC_AND = (0x00029 << 15), LA_OPC_OR = (0x0002A << 15), @@ -48,8 +62,9 @@ enum { LA_OPC_ROTRI_W = (0x00099 << 15), LA_OPC_ALSL_W = (0x0002 << 17), - LA_OPC_ALSL_D = (0x0016 << 17) - + LA_OPC_ALSL_D = (0x0016 << 17), + LA_OPC_TRINS_W = (0x003 << 21) | (0x0 << 15), + LA_OPC_TRPICK_W = (0x003 << 21) | (0x1 << 15) }; /* 12 bit immediate opcodes */ diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index 97113e4..1725f9b 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -26,3 +26,122 @@ void helper_raise_exception(CPULoongArchState *env, uint32_t exception) { do_raise_exception(env, exception, GETPC()); } + +target_ulong helper_cto_w(CPULoongArchState *env, target_ulong rj) +{ + uint32_t v = (uint32_t)rj; + int temp = 0; + + while ((v & 0x1) == 1) { + temp++; + v = v >> 1; + } + + return (target_ulong)temp; +} + +target_ulong helper_ctz_w(CPULoongArchState *env, target_ulong rj) +{ + uint32_t v = (uint32_t)rj; + + if (v == 0) { + return 32; + } + + int temp = 0; + while ((v & 0x1) == 0) { + temp++; + v = v >> 1; + } + + return (target_ulong)temp; +} + +target_ulong helper_cto_d(CPULoongArchState *env, target_ulong rj) +{ + uint64_t v = rj; + int temp = 0; + + while ((v & 0x1) == 1) { + temp++; + v = v >> 1; + } + + return (target_ulong)temp; +} + +target_ulong helper_ctz_d(CPULoongArchState *env, target_ulong rj) +{ + uint64_t v = rj; + + if (v == 0) { + return 64; + } + + int temp = 0; + while ((v & 0x1) == 0) { + temp++; + v = v >> 1; + } + + return (target_ulong)temp; +} + +target_ulong helper_bitrev_w(CPULoongArchState *env, target_ulong rj) +{ + int32_t v = (int32_t)rj; + const int SIZE = 32; + uint8_t bytes[SIZE]; + + int i; + for (i = 0; i < SIZE; i++) { + bytes[i] = v & 0x1; + v = v >> 1; + } + /* v == 0 */ + for (i = 0; i < SIZE; i++) { + v = v | ((uint32_t)bytes[i] << (SIZE - 1 - i)); + } + + return (target_ulong)(int32_t)v; +} + +target_ulong helper_bitrev_d(CPULoongArchState *env, target_ulong rj) +{ + uint64_t v = rj; + const int SIZE = 64; + uint8_t bytes[SIZE]; + + int i; + for (i = 0; i < SIZE; i++) { + bytes[i] = v & 0x1; + v = v >> 1; + } + /* v == 0 */ + for (i = 0; i < SIZE; i++) { + v = v | ((uint64_t)bytes[i] << (SIZE - 1 - i)); + } + + return (target_ulong)v; +} + +static inline target_ulong bitswap(target_ulong v) +{ + v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | + ((v & (target_ulong)0x5555555555555555ULL) << 1); + v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | + ((v & (target_ulong)0x3333333333333333ULL) << 2); + v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | + ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); + return v; +} + +target_ulong helper_loongarch_dbitswap(target_ulong rj) +{ + return bitswap(rj); +} + +target_ulong helper_loongarch_bitswap(target_ulong rt) +{ + return (int32_t)bitswap(rt); +} diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index 7d3b45f..5473361 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -499,3 +499,236 @@ static bool trans_rotri_d(DisasContext *ctx, arg_rotri_d *a) tcg_temp_free(t0); return true; } + +/* Fixed point bit operation instruction translation */ +static bool trans_ext_w_h(DisasContext *ctx, arg_ext_w_h *a) +{ + gen_loongarch_bshfl(ctx, LA_OPC_EXT_WH, a->rj, a->rd); + return true; +} + +static bool trans_ext_w_b(DisasContext *ctx, arg_ext_w_b *a) +{ + gen_loongarch_bshfl(ctx, LA_OPC_EXT_WB, a->rj, a->rd); + return true; +} + +static bool trans_clo_w(DisasContext *ctx, arg_clo_w *a) +{ + gen_loongarch_cl(ctx, LA_OPC_CLO_W, a->rd, a->rj); + return true; +} + +static bool trans_clz_w(DisasContext *ctx, arg_clz_w *a) +{ + gen_loongarch_cl(ctx, LA_OPC_CLZ_W, a->rd, a->rj); + return true; +} + +static bool trans_cto_w(DisasContext *ctx, arg_cto_w *a) +{ + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, a->rj); + gen_helper_cto_w(cpu_gpr[a->rd], cpu_env, t0); + + tcg_temp_free(t0); + return true; +} + +static bool trans_ctz_w(DisasContext *ctx, arg_ctz_w *a) +{ + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, a->rj); + gen_helper_ctz_w(cpu_gpr[a->rd], cpu_env, t0); + + tcg_temp_free(t0); + return true; +} +static bool trans_clo_d(DisasContext *ctx, arg_clo_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_cl(ctx, LA_OPC_CLO_D, a->rd, a->rj); + return true; +} + +static bool trans_clz_d(DisasContext *ctx, arg_clz_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_cl(ctx, LA_OPC_CLZ_D, a->rd, a->rj); + return true; +} + +static bool trans_cto_d(DisasContext *ctx, arg_cto_d *a) +{ + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, a->rj); + gen_helper_cto_d(cpu_gpr[a->rd], cpu_env, t0); + + tcg_temp_free(t0); + return true; +} + +static bool trans_ctz_d(DisasContext *ctx, arg_ctz_d *a) +{ + TCGv t0 = tcg_temp_new(); + + gen_load_gpr(t0, a->rj); + gen_helper_ctz_d(cpu_gpr[a->rd], cpu_env, t0); + + tcg_temp_free(t0); + return true; +} + +static bool trans_revb_2h(DisasContext *ctx, arg_revb_2h *a) +{ + gen_loongarch_bshfl(ctx, LA_OPC_REVB_2H, a->rj, a->rd); + return true; +} + +static bool trans_revb_4h(DisasContext *ctx, arg_revb_4h *a) +{ + check_loongarch_64(ctx); + gen_loongarch_bshfl(ctx, LA_OPC_REVB_4H, a->rj, a->rd); + return true; +} + +static bool trans_revb_2w(DisasContext *ctx, arg_revb_2w *a) +{ + handle_rev32(ctx, a->rj, a->rd); + return true; +} + +static bool trans_revb_d(DisasContext *ctx, arg_revb_d *a) +{ + handle_rev64(ctx, a->rj, a->rd); + return true; +} +static bool trans_revh_2w(DisasContext *ctx, arg_revh_2w *a) +{ + handle_rev16(ctx, a->rj, a->rd); + return true; +} + +static bool trans_revh_d(DisasContext *ctx, arg_revh_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_bshfl(ctx, LA_OPC_REVH_D, a->rj, a->rd); + return true; +} + +static bool trans_bitrev_4b(DisasContext *ctx, arg_bitrev_4b *a) +{ + gen_loongarch_bitswap(ctx, LA_OPC_BREV_4B, a->rd, a->rj); + return true; +} + +static bool trans_bitrev_8b(DisasContext *ctx, arg_bitrev_8b *a) +{ + check_loongarch_64(ctx); + gen_loongarch_bitswap(ctx, LA_OPC_BREV_8B, a->rd, a->rj); + return true; +} + +static bool trans_bitrev_w(DisasContext *ctx, arg_bitrev_w *a) +{ + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rj); + gen_helper_bitrev_w(cpu_gpr[a->rd], cpu_env, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_bitrev_d(DisasContext *ctx, arg_bitrev_d *a) +{ + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rj); + gen_helper_bitrev_d(cpu_gpr[a->rd], cpu_env, t0); + tcg_temp_free(t0); + return true; +} + +static bool trans_bytepick_w(DisasContext *ctx, arg_bytepick_w *a) +{ + gen_loongarch_align(ctx, 32, a->rd, a->rj, a->rk, a->sa2); + return true; +} + +static bool trans_bytepick_d(DisasContext *ctx, arg_bytepick_d *a) +{ + check_loongarch_64(ctx); + gen_loongarch_align(ctx, 64, a->rd, a->rj, a->rk, a->sa3); + return true; +} + +static bool trans_maskeqz(DisasContext *ctx, arg_maskeqz *a) +{ + gen_loongarch_cond_zero(ctx, LA_OPC_MASKEQZ, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_masknez(DisasContext *ctx, arg_masknez *a) +{ + gen_loongarch_cond_zero(ctx, LA_OPC_MASKNEZ, a->rd, a->rj, a->rk); + return true; +} + +static bool trans_bstrins_d(DisasContext *ctx, arg_bstrins_d *a) +{ + int lsb = a->lsbd; + int msb = a->msbd; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + if (lsb > msb) { + return false; + } + + gen_load_gpr(t1, a->rj); + gen_load_gpr(t0, a->rd); + tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); + gen_store_gpr(t0, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_bstrpick_d(DisasContext *ctx, arg_bstrpick_d *a) +{ + int lsb = a->lsbd; + int msb = a->msbd; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + if (lsb > msb) { + return false; + } + + gen_load_gpr(t1, a->rj); + gen_load_gpr(t0, a->rd); + tcg_gen_extract_tl(t0, t1, lsb, msb - lsb + 1); + gen_store_gpr(t0, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_bstrins_w(DisasContext *ctx, arg_bstrins_w *a) +{ + gen_loongarch_bitops(ctx, LA_OPC_TRINS_W, a->rd, a->rj, a->lsbw, a->msbw); + return true; +} + +static bool trans_bstrpick_w(DisasContext *ctx, arg_bstrpick_w *a) +{ + if (a->lsbw > a->msbw) { + return false; + } + gen_loongarch_bitops(ctx, LA_OPC_TRPICK_W, + a->rd, a->rj, a->lsbw, a->msbw - a->lsbw); + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 60f884f..8c735df 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -854,6 +854,304 @@ static void gen_loongarch_shift_imm(DisasContext *ctx, uint32_t opc, tcg_temp_free(t0); } +/* loongarch bit shift */ +static void gen_loongarch_bshfl(DisasContext *ctx, uint32_t opc, + int rj, int rd) +{ + TCGv t0; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, rj); + switch (opc) { + case LA_OPC_REVB_2H: + { + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_const_tl(0x00FF00FF); + tcg_gen_shri_tl(t1, t0, 8); + tcg_gen_and_tl(t1, t1, t2); + tcg_gen_and_tl(t0, t0, t2); + tcg_gen_shli_tl(t0, t0, 8); + tcg_gen_or_tl(t0, t0, t1); + tcg_temp_free(t2); + tcg_temp_free(t1); + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + } + break; + case LA_OPC_EXT_WB: + tcg_gen_ext8s_tl(cpu_gpr[rd], t0); + break; + case LA_OPC_EXT_WH: + tcg_gen_ext16s_tl(cpu_gpr[rd], t0); + break; + case LA_OPC_REVB_4H: + { + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_const_tl(0x00FF00FF00FF00FFULL); + tcg_gen_shri_tl(t1, t0, 8); + tcg_gen_and_tl(t1, t1, t2); + tcg_gen_and_tl(t0, t0, t2); + tcg_gen_shli_tl(t0, t0, 8); + tcg_gen_or_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t2); + tcg_temp_free(t1); + } + break; + case LA_OPC_REVH_D: + { + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_const_tl(0x0000FFFF0000FFFFULL); + tcg_gen_shri_tl(t1, t0, 16); + tcg_gen_and_tl(t1, t1, t2); + tcg_gen_and_tl(t0, t0, t2); + tcg_gen_shli_tl(t0, t0, 16); + tcg_gen_or_tl(t0, t0, t1); + tcg_gen_shri_tl(t1, t0, 32); + tcg_gen_shli_tl(t0, t0, 32); + tcg_gen_or_tl(cpu_gpr[rd], t0, t1); + tcg_temp_free(t2); + tcg_temp_free(t1); + } + break; + default: + gen_reserved_instruction(ctx); + tcg_temp_free(t0); + return; + } + tcg_temp_free(t0); +} + +/* loongarch clo/clz */ +static void gen_loongarch_cl(DisasContext *ctx, uint32_t opc, + int rd, int rj) +{ + TCGv t0; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = cpu_gpr[rd]; + gen_load_gpr(t0, rj); + + switch (opc) { + case LA_OPC_CLO_W: + case LA_OPC_CLO_D: + tcg_gen_not_tl(t0, t0); + break; + } + + switch (opc) { + case LA_OPC_CLO_W: + case LA_OPC_CLZ_W: + tcg_gen_ext32u_tl(t0, t0); + tcg_gen_clzi_tl(t0, t0, TARGET_LONG_BITS); + tcg_gen_subi_tl(t0, t0, TARGET_LONG_BITS - 32); + break; + case LA_OPC_CLO_D: + case LA_OPC_CLZ_D: + tcg_gen_clzi_i64(t0, t0, 64); + break; + } +} + +static void handle_rev64(DisasContext *ctx, + unsigned int rj, unsigned int rd) +{ + tcg_gen_bswap64_i64(cpu_gpr[rd], cpu_gpr[rj]); +} + +static void handle_rev32(DisasContext *ctx, + unsigned int rj, unsigned int rd) +{ + TCGv_i64 tcg_rd = tcg_temp_new_i64(); + gen_load_gpr(tcg_rd, rd); + + TCGv_i64 tcg_tmp = tcg_temp_new_i64(); + TCGv_i64 tcg_rj = tcg_temp_new_i64(); + gen_load_gpr(tcg_rj, rj); + + tcg_gen_ext32u_i64(tcg_tmp, tcg_rj); + tcg_gen_bswap32_i64(tcg_rd, tcg_tmp); + tcg_gen_shri_i64(tcg_tmp, tcg_rj, 32); + tcg_gen_bswap32_i64(tcg_tmp, tcg_tmp); + tcg_gen_concat32_i64(cpu_gpr[rd], tcg_rd, tcg_tmp); + + tcg_temp_free_i64(tcg_tmp); + tcg_temp_free_i64(tcg_rd); + tcg_temp_free_i64(tcg_rj); +} + +static void handle_rev16(DisasContext *ctx, unsigned int rj, unsigned int rd) +{ + TCGv_i64 tcg_rd = tcg_temp_new_i64(); + TCGv_i64 tcg_rj = tcg_temp_new_i64(); + gen_load_gpr(tcg_rd, rd); + gen_load_gpr(tcg_rj, rj); + TCGv_i64 tcg_tmp = tcg_temp_new_i64(); + TCGv_i64 mask = tcg_const_i64(0x0000ffff0000ffffull); + + tcg_gen_shri_i64(tcg_tmp, tcg_rj, 16); + tcg_gen_and_i64(tcg_rd, tcg_rj, mask); + tcg_gen_and_i64(tcg_tmp, tcg_tmp, mask); + tcg_gen_shli_i64(tcg_rd, tcg_rd, 16); + tcg_gen_or_i64(cpu_gpr[rd], tcg_rd, tcg_tmp); + + tcg_temp_free_i64(mask); + tcg_temp_free_i64(tcg_tmp); + tcg_temp_free_i64(tcg_rd); + tcg_temp_free_i64(tcg_rj); +} + +/* loongarch bit swap */ +static void gen_loongarch_bitswap(DisasContext *ctx, int opc, int rd, int rj) +{ + TCGv t0; + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = tcg_temp_new(); + gen_load_gpr(t0, rj); + switch (opc) { + case LA_OPC_BREV_4B: + gen_helper_loongarch_bitswap(cpu_gpr[rd], t0); + break; + case LA_OPC_BREV_8B: + gen_helper_loongarch_dbitswap(cpu_gpr[rd], t0); + break; + } + tcg_temp_free(t0); +} + +/* loongarch align bits */ +static void gen_loongarch_align_bits(DisasContext *ctx, int wordsz, int rd, + int rj, int rk, int bits) +{ + TCGv t0; + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = tcg_temp_new(); + if (bits == 0 || bits == wordsz) { + if (bits == 0) { + gen_load_gpr(t0, rk); + } else { + gen_load_gpr(t0, rj); + } + switch (wordsz) { + case 32: + tcg_gen_ext32s_tl(cpu_gpr[rd], t0); + break; + case 64: + tcg_gen_mov_tl(cpu_gpr[rd], t0); + break; + } + } else { + TCGv t1 = tcg_temp_new(); + gen_load_gpr(t0, rk); + gen_load_gpr(t1, rj); + switch (wordsz) { + case 32: + { + TCGv_i64 t2 = tcg_temp_new_i64(); + tcg_gen_concat_tl_i64(t2, t1, t0); + tcg_gen_shri_i64(t2, t2, 32 - bits); + gen_move_low32(cpu_gpr[rd], t2); + tcg_temp_free_i64(t2); + } + break; + case 64: + tcg_gen_shli_tl(t0, t0, bits); + tcg_gen_shri_tl(t1, t1, 64 - bits); + tcg_gen_or_tl(cpu_gpr[rd], t1, t0); + break; + } + tcg_temp_free(t1); + } + tcg_temp_free(t0); +} + +/* loongarch align */ +static void gen_loongarch_align(DisasContext *ctx, int wordsz, int rd, + int rj, int rk, int bp) +{ + gen_loongarch_align_bits(ctx, wordsz, rd, rj, rk, bp * 8); +} + +/* loongarch cond set zero */ +static void gen_loongarch_cond_zero(DisasContext *ctx, uint32_t opc, + int rd, int rj, int rk) +{ + TCGv t0, t1, t2; + + if (rd == 0) { + /* Treat as NOP. */ + return; + } + + t0 = tcg_temp_new(); + gen_load_gpr(t0, rk); + t1 = tcg_const_tl(0); + t2 = tcg_temp_new(); + gen_load_gpr(t2, rj); + switch (opc) { + case LA_OPC_MASKEQZ: + tcg_gen_movcond_tl(TCG_COND_NE, cpu_gpr[rd], t0, t1, t2, t1); + break; + case LA_OPC_MASKNEZ: + tcg_gen_movcond_tl(TCG_COND_EQ, cpu_gpr[rd], t0, t1, t2, t1); + break; + } + tcg_temp_free(t2); + tcg_temp_free(t1); + tcg_temp_free(t0); +} + +/* loongarch bit ops */ +static void gen_loongarch_bitops(DisasContext *ctx, uint32_t opc, int rd, + int rj, int lsb, int msb) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + gen_load_gpr(t1, rj); + switch (opc) { + case LA_OPC_TRPICK_W: + if (lsb + msb > 31) { + goto fail; + } + if (msb != 31) { + tcg_gen_extract_tl(t0, t1, lsb, msb + 1); + } else { + tcg_gen_ext32s_tl(t0, t1); + } + break; + case LA_OPC_TRINS_W: + if (lsb > msb) { + goto fail; + } + gen_load_gpr(t0, rd); + tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1); + tcg_gen_ext32s_tl(t0, t0); + break; + default: +fail: + gen_reserved_instruction(ctx); + tcg_temp_free(t0); + tcg_temp_free(t1); + return; + } + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + tcg_temp_free(t1); +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347855 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 B3F6AC2B9F4 for ; Mon, 28 Jun 2021 12:23:38 +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 2BBEE61584 for ; Mon, 28 Jun 2021 12:23:38 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2BBEE61584 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:46882 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqIb-0001E4-4H for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:23:37 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51222) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0h-0002Iv-Oj for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:07 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45516 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0a-0001BD-UV for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:07 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S12; Mon, 28 Jun 2021 20:04:54 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 10/20] target/loongarch: Add fixed point load/store instruction translation Date: Mon, 28 Jun 2021 20:04:35 +0800 Message-Id: <1624881885-31692-11-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S12 X-Coremail-Antispam: 1UD129KBjvAXoWfZFy7Zw1UXw4xCryDWry5CFg_yoW8ur18Xo WUJF45Jr48Gw13WrnIkw4DXF1Sqw1xCF13Aws0vwnrK3WxGrnrtryqgrn5XayfJ3y2gryr Xa4aqF1ay3y3AryDn29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement fixed point load/store instruction translation. This includes: - LD.{B[U]/H[U]/W[U]/D}, ST.{B/H/W/D} - LDX.{B[U]/H[U]/W[U]/D}, STX.{B/H/W/D} - LDPTR.{W/D}, STPTR.{W/D} - PRELD, PRELDX - LD{GT/LE}.{B/H/W/D}, ST{GT/LE}.{B/H/W/D} - DBAR, IBAR Signed-off-by: Song Gao --- target/loongarch/helper.h | 3 + target/loongarch/insns.decode | 61 ++++++ target/loongarch/instmap.h | 20 ++ target/loongarch/op_helper.c | 15 ++ target/loongarch/trans.inc.c | 446 ++++++++++++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 112 +++++++++++ 6 files changed, 657 insertions(+) diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index bbbcc26..5cd38c8 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -18,3 +18,6 @@ DEF_HELPER_2(bitrev_d, tl, env, tl) DEF_HELPER_FLAGS_1(loongarch_bitswap, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(loongarch_dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) + +DEF_HELPER_3(asrtle_d, void, env, tl, tl) +DEF_HELPER_3(asrtgt_d, void, env, tl, tl) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index ec599a9..c5c08c8 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -24,6 +24,9 @@ %lsbw 10:5 %msbd 16:6 %lsbd 10:6 +%si14 10:s14 +%hint 0:5 +%whint 0:15 # # Argument sets @@ -40,6 +43,10 @@ &fmt_rdrjrksa3 rd rj rk sa3 &fmt_rdrjmsbwlsbw rd rj msbw lsbw &fmt_rdrjmsbdlsbd rd rj msbd lsbd +&fmt_rdrjsi14 rd rj si14 +&fmt_hintrjsi12 hint rj si12 +&fmt_hintrjrk hint rj rk +&fmt_whint whint # # Formats @@ -56,6 +63,10 @@ @fmt_rdrjmsbwlsbw .... ....... ..... . ..... ..... ..... &fmt_rdrjmsbwlsbw %rd %rj %msbw %lsbw @fmt_rdrjmsbdlsbd .... ...... ...... ...... ..... ..... &fmt_rdrjmsbdlsbd %rd %rj %msbd %lsbd @fmt_rdrjrksa3 .... ........ .. ... ..... ..... ..... &fmt_rdrjrksa3 %rd %rj %rk %sa3 +@fmt_hintrjsi12 .... ...... ............ ..... ..... &fmt_hintrjsi12 %hint %rj %si12 +@fmt_hintrjrk .... ........ ..... ..... ..... ..... &fmt_hintrjrk %hint %rj %rk +@fmt_whint .... ........ ..... ............... &fmt_whint %whint +@fmt_rdrjsi14 .... .... .............. ..... ..... &fmt_rdrjsi14 %rd %rj %si14 # # Fixed point arithmetic operation instruction @@ -158,3 +169,53 @@ bstrins_w 0000 0000011 ..... 0 ..... ..... ..... @fmt_rdrjmsbwlsbw bstrpick_w 0000 0000011 ..... 1 ..... ..... ..... @fmt_rdrjmsbwlsbw bstrins_d 0000 000010 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd bstrpick_d 0000 000011 ...... ...... ..... ..... @fmt_rdrjmsbdlsbd + +# +# Fixed point load/store instruction +# +ld_b 0010 100000 ............ ..... ..... @fmt_rdrjsi12 +ld_h 0010 100001 ............ ..... ..... @fmt_rdrjsi12 +ld_w 0010 100010 ............ ..... ..... @fmt_rdrjsi12 +ld_d 0010 100011 ............ ..... ..... @fmt_rdrjsi12 +st_b 0010 100100 ............ ..... ..... @fmt_rdrjsi12 +st_h 0010 100101 ............ ..... ..... @fmt_rdrjsi12 +st_w 0010 100110 ............ ..... ..... @fmt_rdrjsi12 +st_d 0010 100111 ............ ..... ..... @fmt_rdrjsi12 +ld_bu 0010 101000 ............ ..... ..... @fmt_rdrjsi12 +ld_hu 0010 101001 ............ ..... ..... @fmt_rdrjsi12 +ld_wu 0010 101010 ............ ..... ..... @fmt_rdrjsi12 +ldx_b 0011 10000000 00000 ..... ..... ..... @fmt_rdrjrk +ldx_h 0011 10000000 01000 ..... ..... ..... @fmt_rdrjrk +ldx_w 0011 10000000 10000 ..... ..... ..... @fmt_rdrjrk +ldx_d 0011 10000000 11000 ..... ..... ..... @fmt_rdrjrk +stx_b 0011 10000001 00000 ..... ..... ..... @fmt_rdrjrk +stx_h 0011 10000001 01000 ..... ..... ..... @fmt_rdrjrk +stx_w 0011 10000001 10000 ..... ..... ..... @fmt_rdrjrk +stx_d 0011 10000001 11000 ..... ..... ..... @fmt_rdrjrk +ldx_bu 0011 10000010 00000 ..... ..... ..... @fmt_rdrjrk +ldx_hu 0011 10000010 01000 ..... ..... ..... @fmt_rdrjrk +ldx_wu 0011 10000010 10000 ..... ..... ..... @fmt_rdrjrk +preld 0010 101011 ............ ..... ..... @fmt_hintrjsi12 +preldx 0011 10000010 11000 ..... ..... ..... @fmt_hintrjrk +dbar 0011 10000111 00100 ............... @fmt_whint +ibar 0011 10000111 00101 ............... @fmt_whint +ldptr_w 0010 0100 .............. ..... ..... @fmt_rdrjsi14 +stptr_w 0010 0101 .............. ..... ..... @fmt_rdrjsi14 +ldptr_d 0010 0110 .............. ..... ..... @fmt_rdrjsi14 +stptr_d 0010 0111 .............. ..... ..... @fmt_rdrjsi14 +ldgt_b 0011 10000111 10000 ..... ..... ..... @fmt_rdrjrk +ldgt_h 0011 10000111 10001 ..... ..... ..... @fmt_rdrjrk +ldgt_w 0011 10000111 10010 ..... ..... ..... @fmt_rdrjrk +ldgt_d 0011 10000111 10011 ..... ..... ..... @fmt_rdrjrk +ldle_b 0011 10000111 10100 ..... ..... ..... @fmt_rdrjrk +ldle_h 0011 10000111 10101 ..... ..... ..... @fmt_rdrjrk +ldle_w 0011 10000111 10110 ..... ..... ..... @fmt_rdrjrk +ldle_d 0011 10000111 10111 ..... ..... ..... @fmt_rdrjrk +stgt_b 0011 10000111 11000 ..... ..... ..... @fmt_rdrjrk +stgt_h 0011 10000111 11001 ..... ..... ..... @fmt_rdrjrk +stgt_w 0011 10000111 11010 ..... ..... ..... @fmt_rdrjrk +stgt_d 0011 10000111 11011 ..... ..... ..... @fmt_rdrjrk +stle_b 0011 10000111 11100 ..... ..... ..... @fmt_rdrjrk +stle_h 0011 10000111 11101 ..... ..... ..... @fmt_rdrjrk +stle_w 0011 10000111 11110 ..... ..... ..... @fmt_rdrjrk +stle_d 0011 10000111 11111 ..... ..... ..... @fmt_rdrjrk diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h index 57b5a1c..b6ddb7d 100644 --- a/target/loongarch/instmap.h +++ b/target/loongarch/instmap.h @@ -78,4 +78,24 @@ enum { LA_OPC_XORI = (0x00F << 22) }; +/* load/store opcodes */ +enum { + LA_OPC_LD_B = (0x0A0 << 22), + LA_OPC_LD_H = (0x0A1 << 22), + LA_OPC_LD_W = (0x0A2 << 22), + LA_OPC_LD_D = (0x0A3 << 22), + LA_OPC_ST_B = (0x0A4 << 22), + LA_OPC_ST_H = (0x0A5 << 22), + LA_OPC_ST_W = (0x0A6 << 22), + LA_OPC_ST_D = (0x0A7 << 22), + LA_OPC_LD_BU = (0x0A8 << 22), + LA_OPC_LD_HU = (0x0A9 << 22), + LA_OPC_LD_WU = (0x0AA << 22), + + LA_OPC_LDPTR_W = (0x24 << 24), + LA_OPC_STPTR_W = (0x25 << 24), + LA_OPC_LDPTR_D = (0x26 << 24), + LA_OPC_STPTR_D = (0x27 << 24) +}; + #endif diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index 1725f9b..66499d4 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -145,3 +145,18 @@ target_ulong helper_loongarch_bitswap(target_ulong rt) { return (int32_t)bitswap(rt); } + +/* loongarch assert op */ +void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) +{ + if (rj > rk) { + do_raise_exception(env, EXCP_ADE, GETPC()); + } +} + +void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) +{ + if (rj <= rk) { + do_raise_exception(env, EXCP_ADE, GETPC()); + } +} diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index 5473361..9880a7f 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -732,3 +732,449 @@ static bool trans_bstrpick_w(DisasContext *ctx, arg_bstrpick_w *a) a->rd, a->rj, a->lsbw, a->msbw - a->lsbw); return true; } + +/* Fixed point load/store instruction translation */ +static bool trans_ld_b(DisasContext *ctx, arg_ld_b *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LD_B, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_ld_h(DisasContext *ctx, arg_ld_h *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LD_H, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_ld_w(DisasContext *ctx, arg_ld_w *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LD_W, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_ld_d(DisasContext *ctx, arg_ld_d *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LD_D, a->rd, a->rj, a->si12); + return true; +} +static bool trans_st_b(DisasContext *ctx, arg_st_b *a) +{ + gen_loongarch_st(ctx, LA_OPC_ST_B, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_st_h(DisasContext *ctx, arg_st_h *a) +{ + gen_loongarch_st(ctx, LA_OPC_ST_H, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_st_w(DisasContext *ctx, arg_st_w *a) +{ + gen_loongarch_st(ctx, LA_OPC_ST_W, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_st_d(DisasContext *ctx, arg_st_d *a) +{ + gen_loongarch_st(ctx, LA_OPC_ST_D, a->rd, a->rj, a->si12); + return true; +} +static bool trans_ld_bu(DisasContext *ctx, arg_ld_bu *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LD_BU, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_ld_hu(DisasContext *ctx, arg_ld_hu *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LD_HU, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_ld_wu(DisasContext *ctx, arg_ld_wu *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LD_WU, a->rd, a->rj, a->si12); + return true; +} + +static bool trans_ldx_b(DisasContext *ctx, arg_ldx_b *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_SB); + gen_store_gpr(t1, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_ldx_h(DisasContext *ctx, arg_ldx_h *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TESW | ctx->default_tcg_memop_mask); + gen_store_gpr(t1, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_ldx_w(DisasContext *ctx, arg_ldx_w *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TESL | ctx->default_tcg_memop_mask); + gen_store_gpr(t1, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_ldx_d(DisasContext *ctx, arg_ldx_d *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEQ | ctx->default_tcg_memop_mask); + gen_store_gpr(t1, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_stx_b(DisasContext *ctx, arg_stx_b *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + gen_load_gpr(t1, a->rd); + tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_8); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_stx_h(DisasContext *ctx, arg_stx_h *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + gen_load_gpr(t1, a->rd); + tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUW | + ctx->default_tcg_memop_mask); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_stx_w(DisasContext *ctx, arg_stx_w *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + gen_load_gpr(t1, a->rd); + tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_stx_d(DisasContext *ctx, arg_stx_d *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + gen_load_gpr(t1, a->rd); + tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_ldx_bu(DisasContext *ctx, arg_ldx_bu *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_UB); + gen_store_gpr(t1, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_ldx_hu(DisasContext *ctx, arg_ldx_hu *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEUW | + ctx->default_tcg_memop_mask); + gen_store_gpr(t1, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_ldx_wu(DisasContext *ctx, arg_ldx_wu *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_op_addr_add(ctx, t0, cpu_gpr[a->rj], cpu_gpr[a->rk]); + tcg_gen_qemu_ld_tl(t1, t0, mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t1, a->rd); + + tcg_temp_free(t0); + tcg_temp_free(t1); + return true; +} + +static bool trans_preld(DisasContext *ctx, arg_preld *a) +{ + /* Treat as NOP. */ + return true; +} + +static bool trans_preldx(DisasContext *ctx, arg_preldx *a) +{ + /* Treat as NOP. */ + return true; +} + +static bool trans_dbar(DisasContext *ctx, arg_dbar * a) +{ + gen_loongarch_sync(a->whint); + return true; +} + +static bool trans_ibar(DisasContext *ctx, arg_ibar *a) +{ + /* + * IBAR is a no-op in QEMU, + * however we need to end the translation block + */ + ctx->base.is_jmp = DISAS_STOP; + return true; +} + +static bool trans_ldptr_w(DisasContext *ctx, arg_ldptr_w *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LDPTR_W, a->rd, a->rj, a->si14 << 2); + return true; +} + +static bool trans_stptr_w(DisasContext *ctx, arg_stptr_w *a) +{ + gen_loongarch_st(ctx, LA_OPC_STPTR_W, a->rd, a->rj, a->si14 << 2); + return true; +} + +static bool trans_ldptr_d(DisasContext *ctx, arg_ldptr_d *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LDPTR_D, a->rd, a->rj, a->si14 << 2); + return true; +} + +static bool trans_stptr_d(DisasContext *ctx, arg_stptr_d *a) +{ + gen_loongarch_st(ctx, LA_OPC_STPTR_D, a->rd, a->rj, a->si14 << 2); + return true; +} + +#define ASRTGT \ + do { \ + TCGv t1 = tcg_temp_new(); \ + TCGv t2 = tcg_temp_new(); \ + gen_load_gpr(t1, a->rj); \ + gen_load_gpr(t2, a->rk); \ + gen_helper_asrtgt_d(cpu_env, t1, t2); \ + tcg_temp_free(t1); \ + tcg_temp_free(t2); \ + } while (0) + +#define ASRTLE \ + do { \ + TCGv t1 = tcg_temp_new(); \ + TCGv t2 = tcg_temp_new(); \ + gen_load_gpr(t1, a->rj); \ + gen_load_gpr(t2, a->rk); \ + gen_helper_asrtle_d(cpu_env, t1, t2); \ + tcg_temp_free(t1); \ + tcg_temp_free(t2); \ + } while (0) + +#define DECL_ARG(name) \ + arg_ ## name arg = { \ + .rd = a->rd, \ + .rj = a->rj, \ + .rk = a->rk, \ + }; + +static bool trans_ldgt_b(DisasContext *ctx, arg_ldgt_b *a) +{ + ASRTGT; + DECL_ARG(ldx_b) + trans_ldx_b(ctx, &arg); + return true; +} + +static bool trans_ldgt_h(DisasContext *ctx, arg_ldgt_h *a) +{ + ASRTGT; + DECL_ARG(ldx_h) + trans_ldx_h(ctx, &arg); + return true; +} + +static bool trans_ldgt_w(DisasContext *ctx, arg_ldgt_w *a) +{ + ASRTGT; + DECL_ARG(ldx_w) + trans_ldx_w(ctx, &arg); + return true; +} + +static bool trans_ldgt_d(DisasContext *ctx, arg_ldgt_d *a) +{ + ASRTGT; + DECL_ARG(ldx_d) + trans_ldx_d(ctx, &arg); + return true; +} + +static bool trans_ldle_b(DisasContext *ctx, arg_ldle_b *a) +{ + ASRTLE; + DECL_ARG(ldx_b) + trans_ldx_b(ctx, &arg); + return true; +} + +static bool trans_ldle_h(DisasContext *ctx, arg_ldle_h *a) +{ + ASRTLE; + DECL_ARG(ldx_h) + trans_ldx_h(ctx, &arg); + return true; +} + +static bool trans_ldle_w(DisasContext *ctx, arg_ldle_w *a) +{ + ASRTLE; + DECL_ARG(ldx_w) + trans_ldx_w(ctx, &arg); + return true; +} + +static bool trans_ldle_d(DisasContext *ctx, arg_ldle_d *a) +{ + ASRTLE; + DECL_ARG(ldx_d) + trans_ldx_d(ctx, &arg); + return true; +} + +static bool trans_stgt_b(DisasContext *ctx, arg_stgt_b *a) +{ + ASRTGT; + DECL_ARG(stx_b) + trans_stx_b(ctx, &arg); + return true; +} + +static bool trans_stgt_h(DisasContext *ctx, arg_stgt_h *a) +{ + ASRTGT; + DECL_ARG(stx_h) + trans_stx_h(ctx, &arg); + return true; +} + +static bool trans_stgt_w(DisasContext *ctx, arg_stgt_w *a) +{ + ASRTGT; + DECL_ARG(stx_w) + trans_stx_w(ctx, &arg); + return true; +} + +static bool trans_stgt_d(DisasContext *ctx, arg_stgt_d *a) +{ + ASRTGT; + DECL_ARG(stx_d) + trans_stx_d(ctx, &arg); + return true; +} + +static bool trans_stle_b(DisasContext *ctx, arg_stle_b *a) +{ + ASRTLE; + DECL_ARG(stx_b) + trans_stx_b(ctx, &arg); + return true; +} + +static bool trans_stle_h(DisasContext *ctx, arg_stle_h *a) +{ + ASRTLE; + DECL_ARG(stx_h) + trans_stx_h(ctx, &arg); + return true; +} + +static bool trans_stle_w(DisasContext *ctx, arg_stle_w *a) +{ + ASRTLE; + DECL_ARG(stx_w) + trans_stx_w(ctx, &arg); + return true; +} + +static bool trans_stle_d(DisasContext *ctx, arg_stle_d *a) +{ + ASRTLE; + DECL_ARG(stx_d) + trans_stx_d(ctx, &arg); + return true; +} + +#undef DECL_ARG diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 8c735df..d9d2f1a 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -292,6 +292,35 @@ static void loongarch_tr_init_disas_context(DisasContextBase *dcbase, ctx->default_tcg_memop_mask = MO_UNALN; } +/* loongarch sync */ +static void gen_loongarch_sync(int stype) +{ + TCGBar tcg_mo = TCG_BAR_SC; + + switch (stype) { + case 0x4: /* SYNC_WMB */ + tcg_mo |= TCG_MO_ST_ST; + break; + case 0x10: /* SYNC_MB */ + tcg_mo |= TCG_MO_ALL; + break; + case 0x11: /* SYNC_ACQUIRE */ + tcg_mo |= TCG_MO_LD_LD | TCG_MO_LD_ST; + break; + case 0x12: /* SYNC_RELEASE */ + tcg_mo |= TCG_MO_ST_ST | TCG_MO_LD_ST; + break; + case 0x13: /* SYNC_RMB */ + tcg_mo |= TCG_MO_LD_LD; + break; + default: + tcg_mo |= TCG_MO_ALL; + break; + } + + tcg_gen_mb(tcg_mo); +} + /* loongarch arithmetic */ static void gen_loongarch_arith(DisasContext *ctx, uint32_t opc, int rd, int rj, int rk) @@ -1152,6 +1181,89 @@ fail: tcg_temp_free(t1); } +/* loongarch load */ +static void gen_loongarch_ld(DisasContext *ctx, uint32_t opc, + int rd, int base, int offset) +{ + int mem_idx = ctx->mem_idx; + + TCGv t0 = tcg_temp_new(); + gen_base_offset_addr(ctx, t0, base, offset); + + switch (opc) { + case LA_OPC_LD_WU: + tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, rd); + break; + case LA_OPC_LDPTR_D: + case LA_OPC_LD_D: + tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, rd); + break; + case LA_OPC_LDPTR_W: + case LA_OPC_LD_W: + tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESL | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, rd); + break; + case LA_OPC_LD_H: + tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TESW | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, rd); + break; + case LA_OPC_LD_HU: + tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_TEUW | + ctx->default_tcg_memop_mask); + gen_store_gpr(t0, rd); + break; + case LA_OPC_LD_B: + tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_SB); + gen_store_gpr(t0, rd); + break; + case LA_OPC_LD_BU: + tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_UB); + gen_store_gpr(t0, rd); + break; + } + tcg_temp_free(t0); +} + +/* loongarch store */ +static void gen_loongarch_st(DisasContext *ctx, uint32_t opc, int rd, + int base, int offset) +{ + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + int mem_idx = ctx->mem_idx; + + gen_base_offset_addr(ctx, t0, base, offset); + gen_load_gpr(t1, rd); + + switch (opc) { + case LA_OPC_STPTR_D: + case LA_OPC_ST_D: + tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + break; + case LA_OPC_STPTR_W: + case LA_OPC_ST_W: + tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + break; + case LA_OPC_ST_H: + tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_TEUW | + ctx->default_tcg_memop_mask); + break; + case LA_OPC_ST_B: + tcg_gen_qemu_st_tl(t1, t0, mem_idx, MO_8); + break; + } + tcg_temp_free(t0); + tcg_temp_free(t1); +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347839 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 4D931C2B9F4 for ; Mon, 28 Jun 2021 12:14:50 +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 B9C4F61A2B for ; Mon, 28 Jun 2021 12:14:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B9C4F61A2B Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:53272 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqA4-0002tv-R9 for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:14:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51254) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0s-0002gp-Ke for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:19 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45530 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0o-0001Ci-1Y for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:18 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S13; Mon, 28 Jun 2021 20:04:58 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 11/20] target/loongarch: Add fixed point atomic instruction translation Date: Mon, 28 Jun 2021 20:04:36 +0800 Message-Id: <1624881885-31692-12-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S13 X-Coremail-Antispam: 1UD129KBjvJXoW3ur4kJrW8Arykuw47CFWfKrg_yoWkKry5pr 1jyry7Jr40vr17Jr93tw45Gw1DGrs7Cw42gr9xtw1vvF4UXF1UX3W8Aay2gFWjqrn5uFW0 yFW3A34j9FyUX3JanT9S1TB71UUUUjDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UUUUUUUUU== X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement fixed point atomic instruction translation. This includes: - LL.{W/D}, SC.{W/D} - AM{SWAP/ADD/AND/OR/XOR/MAX/MIN}[_DB].{W/D} - AM{MAX/MIN}[_DB].{WU/DU} Signed-off-by: Song Gao --- target/loongarch/insns.decode | 44 ++++++++++++ target/loongarch/instmap.h | 2 + target/loongarch/trans.inc.c | 155 ++++++++++++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 54 +++++++++++++++ 4 files changed, 255 insertions(+) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index c5c08c8..beb2e4a 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -219,3 +219,47 @@ stle_b 0011 10000111 11100 ..... ..... ..... @fmt_rdrjrk stle_h 0011 10000111 11101 ..... ..... ..... @fmt_rdrjrk stle_w 0011 10000111 11110 ..... ..... ..... @fmt_rdrjrk stle_d 0011 10000111 11111 ..... ..... ..... @fmt_rdrjrk + +# +# Fixed point atomic instruction +# +ll_w 0010 0000 .............. ..... ..... @fmt_rdrjsi14 +sc_w 0010 0001 .............. ..... ..... @fmt_rdrjsi14 +ll_d 0010 0010 .............. ..... ..... @fmt_rdrjsi14 +sc_d 0010 0011 .............. ..... ..... @fmt_rdrjsi14 +amswap_w 0011 10000110 00000 ..... ..... ..... @fmt_rdrjrk +amswap_d 0011 10000110 00001 ..... ..... ..... @fmt_rdrjrk +amadd_w 0011 10000110 00010 ..... ..... ..... @fmt_rdrjrk +amadd_d 0011 10000110 00011 ..... ..... ..... @fmt_rdrjrk +amand_w 0011 10000110 00100 ..... ..... ..... @fmt_rdrjrk +amand_d 0011 10000110 00101 ..... ..... ..... @fmt_rdrjrk +amor_w 0011 10000110 00110 ..... ..... ..... @fmt_rdrjrk +amor_d 0011 10000110 00111 ..... ..... ..... @fmt_rdrjrk +amxor_w 0011 10000110 01000 ..... ..... ..... @fmt_rdrjrk +amxor_d 0011 10000110 01001 ..... ..... ..... @fmt_rdrjrk +ammax_w 0011 10000110 01010 ..... ..... ..... @fmt_rdrjrk +ammax_d 0011 10000110 01011 ..... ..... ..... @fmt_rdrjrk +ammin_w 0011 10000110 01100 ..... ..... ..... @fmt_rdrjrk +ammin_d 0011 10000110 01101 ..... ..... ..... @fmt_rdrjrk +ammax_wu 0011 10000110 01110 ..... ..... ..... @fmt_rdrjrk +ammax_du 0011 10000110 01111 ..... ..... ..... @fmt_rdrjrk +ammin_wu 0011 10000110 10000 ..... ..... ..... @fmt_rdrjrk +ammin_du 0011 10000110 10001 ..... ..... ..... @fmt_rdrjrk +amswap_db_w 0011 10000110 10010 ..... ..... ..... @fmt_rdrjrk +amswap_db_d 0011 10000110 10011 ..... ..... ..... @fmt_rdrjrk +amadd_db_w 0011 10000110 10100 ..... ..... ..... @fmt_rdrjrk +amadd_db_d 0011 10000110 10101 ..... ..... ..... @fmt_rdrjrk +amand_db_w 0011 10000110 10110 ..... ..... ..... @fmt_rdrjrk +amand_db_d 0011 10000110 10111 ..... ..... ..... @fmt_rdrjrk +amor_db_w 0011 10000110 11000 ..... ..... ..... @fmt_rdrjrk +amor_db_d 0011 10000110 11001 ..... ..... ..... @fmt_rdrjrk +amxor_db_w 0011 10000110 11010 ..... ..... ..... @fmt_rdrjrk +amxor_db_d 0011 10000110 11011 ..... ..... ..... @fmt_rdrjrk +ammax_db_w 0011 10000110 11100 ..... ..... ..... @fmt_rdrjrk +ammax_db_d 0011 10000110 11101 ..... ..... ..... @fmt_rdrjrk +ammin_db_w 0011 10000110 11110 ..... ..... ..... @fmt_rdrjrk +ammin_db_d 0011 10000110 11111 ..... ..... ..... @fmt_rdrjrk +ammax_db_wu 0011 10000111 00000 ..... ..... ..... @fmt_rdrjrk +ammax_db_du 0011 10000111 00001 ..... ..... ..... @fmt_rdrjrk +ammin_db_wu 0011 10000111 00010 ..... ..... ..... @fmt_rdrjrk +ammin_db_du 0011 10000111 00011 ..... ..... ..... @fmt_rdrjrk diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h index b6ddb7d..ea5396e 100644 --- a/target/loongarch/instmap.h +++ b/target/loongarch/instmap.h @@ -92,6 +92,8 @@ enum { LA_OPC_LD_HU = (0x0A9 << 22), LA_OPC_LD_WU = (0x0AA << 22), + LA_OPC_LL_W = (0x20 << 24), + LA_OPC_LL_D = (0x22 << 24), LA_OPC_LDPTR_W = (0x24 << 24), LA_OPC_STPTR_W = (0x25 << 24), LA_OPC_LDPTR_D = (0x26 << 24), diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index 9880a7f..3f1e64f 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -1178,3 +1178,158 @@ static bool trans_stle_d(DisasContext *ctx, arg_stle_d *a) } #undef DECL_ARG + +/* Fixed point atomic instruction translation */ +static bool trans_ll_w(DisasContext *ctx, arg_ll_w *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LL_W, a->rd, a->rj, a->si14 << 2); + return true; +} + +static bool trans_sc_w(DisasContext *ctx, arg_sc_w *a) +{ + gen_loongarch_st_cond(ctx, a->rd, a->rj, a->si14 << 2, MO_TESL, false); + return true; +} + +static bool trans_ll_d(DisasContext *ctx, arg_ll_d *a) +{ + gen_loongarch_ld(ctx, LA_OPC_LL_D, a->rd, a->rj, a->si14 << 2); + return true; +} + +static bool trans_sc_d(DisasContext *ctx, arg_sc_d *a) +{ + gen_loongarch_st_cond(ctx, a->rd, a->rj, a->si14 << 2, MO_TEQ, false); + return true; +} + +#define TRANS_AM_W(name, op) \ +static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ +{ \ + if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ + printf("%s: warning, register equal\n", __func__); \ + return false; \ + } \ + int mem_idx = ctx->mem_idx; \ + TCGv addr = tcg_temp_new(); \ + TCGv val = tcg_temp_new(); \ + TCGv ret = tcg_temp_new(); \ + \ + gen_load_gpr(addr, a->rj); \ + gen_load_gpr(val, a->rk); \ + tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TESL | \ + ctx->default_tcg_memop_mask); \ + gen_store_gpr(ret, a->rd); \ + \ + tcg_temp_free(addr); \ + tcg_temp_free(val); \ + tcg_temp_free(ret); \ + return true; \ +} +#define TRANS_AM_D(name, op) \ +static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ +{ \ + if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ + printf("%s: warning, register equal\n", __func__); \ + return false; \ + } \ + int mem_idx = ctx->mem_idx; \ + TCGv addr = tcg_temp_new(); \ + TCGv val = tcg_temp_new(); \ + TCGv ret = tcg_temp_new(); \ + \ + gen_load_gpr(addr, a->rj); \ + gen_load_gpr(val, a->rk); \ + tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TEQ | \ + ctx->default_tcg_memop_mask); \ + gen_store_gpr(ret, a->rd); \ + \ + tcg_temp_free(addr); \ + tcg_temp_free(val); \ + tcg_temp_free(ret); \ + return true; \ +} +#define TRANS_AM(name, op) \ + TRANS_AM_W(name##_w, op) \ + TRANS_AM_D(name##_d, op) +TRANS_AM(amswap, xchg) /* trans_amswap_w, trans_amswap_d */ +TRANS_AM(amadd, fetch_add) /* trans_amadd_w, trans_amadd_d */ +TRANS_AM(amand, fetch_and) /* trans_amand_w, trans_amand_d */ +TRANS_AM(amor, fetch_or) /* trans_amor_w, trans_amor_d */ +TRANS_AM(amxor, fetch_xor) /* trans_amxor_w, trans_amxor_d */ +TRANS_AM(ammax, fetch_smax) /* trans_ammax_w, trans_ammax_d */ +TRANS_AM(ammin, fetch_smin) /* trans_ammin_w, trans_ammin_d */ +TRANS_AM_W(ammax_wu, fetch_umax) /* trans_ammax_wu */ +TRANS_AM_D(ammax_du, fetch_umax) /* trans_ammax_du */ +TRANS_AM_W(ammin_wu, fetch_umin) /* trans_ammin_wu */ +TRANS_AM_D(ammin_du, fetch_umin) /* trans_ammin_du */ +#undef TRANS_AM +#undef TRANS_AM_W +#undef TRANS_AM_D + +#define TRANS_AM_DB_W(name, op) \ +static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ +{ \ + if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ + printf("%s: warning, register equal\n", __func__); \ + return false; \ + } \ + int mem_idx = ctx->mem_idx; \ + TCGv addr = tcg_temp_new(); \ + TCGv val = tcg_temp_new(); \ + TCGv ret = tcg_temp_new(); \ + \ + gen_loongarch_sync(0x10); \ + gen_load_gpr(addr, a->rj); \ + gen_load_gpr(val, a->rk); \ + tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TESL | \ + ctx->default_tcg_memop_mask); \ + gen_store_gpr(ret, a->rd); \ + \ + tcg_temp_free(addr); \ + tcg_temp_free(val); \ + tcg_temp_free(ret); \ + return true; \ +} +#define TRANS_AM_DB_D(name, op) \ +static bool trans_ ## name(DisasContext *ctx, arg_ ## name * a) \ +{ \ + if ((a->rd != 0) && ((a->rj == a->rd) || (a->rk == a->rd))) { \ + printf("%s: warning, register equal\n", __func__); \ + return false; \ + } \ + int mem_idx = ctx->mem_idx; \ + TCGv addr = tcg_temp_new(); \ + TCGv val = tcg_temp_new(); \ + TCGv ret = tcg_temp_new(); \ + \ + gen_loongarch_sync(0x10); \ + gen_load_gpr(addr, a->rj); \ + gen_load_gpr(val, a->rk); \ + tcg_gen_atomic_##op##_tl(ret, addr, val, mem_idx, MO_TEQ | \ + ctx->default_tcg_memop_mask); \ + gen_store_gpr(ret, a->rd); \ + \ + tcg_temp_free(addr); \ + tcg_temp_free(val); \ + tcg_temp_free(ret); \ + return true; \ +} +#define TRANS_AM_DB(name, op) \ + TRANS_AM_DB_W(name##_db_w, op) \ + TRANS_AM_DB_D(name##_db_d, op) +TRANS_AM_DB(amswap, xchg) /* trans_amswap_db_w, trans_amswap_db_d */ +TRANS_AM_DB(amadd, fetch_add) /* trans_amadd_db_w, trans_amadd_db_d */ +TRANS_AM_DB(amand, fetch_and) /* trans_amand_db_w, trans_amand_db_d */ +TRANS_AM_DB(amor, fetch_or) /* trans_amor_db_w, trans_amor_db_d */ +TRANS_AM_DB(amxor, fetch_xor) /* trans_amxor_db_w, trans_amxor_db_d */ +TRANS_AM_DB(ammax, fetch_smax) /* trans_ammax_db_w, trans_ammax_db_d */ +TRANS_AM_DB(ammin, fetch_smin) /* trans_ammin_db_w, trans_ammin_db_d */ +TRANS_AM_DB_W(ammax_db_wu, fetch_umax) /* trans_ammax_db_wu */ +TRANS_AM_DB_D(ammax_db_du, fetch_umax) /* trans_ammax_db_du */ +TRANS_AM_DB_W(ammin_db_wu, fetch_umin) /* trans_ammin_db_wu */ +TRANS_AM_DB_D(ammin_db_du, fetch_umin) /* trans_ammin_db_du */ +#undef TRANS_AM_DB +#undef TRANS_AM_DB_W +#undef TRANS_AM_DB_D diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index d9d2f1a..bf14507 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -1181,6 +1181,21 @@ fail: tcg_temp_free(t1); } +#define OP_LD_ATOMIC(insn, fname) \ +static inline void op_ld_##insn(TCGv ret, TCGv arg1, int mem_idx, \ + DisasContext *ctx) \ +{ \ + TCGv t0 = tcg_temp_new(); \ + tcg_gen_mov_tl(t0, arg1); \ + tcg_gen_qemu_##fname(ret, arg1, ctx->mem_idx); \ + tcg_gen_st_tl(t0, cpu_env, offsetof(CPULoongArchState, lladdr)); \ + tcg_gen_st_tl(ret, cpu_env, offsetof(CPULoongArchState, llval)); \ + tcg_temp_free(t0); \ +} +OP_LD_ATOMIC(ll, ld32s); +OP_LD_ATOMIC(lld, ld64); +#undef OP_LD_ATOMIC + /* loongarch load */ static void gen_loongarch_ld(DisasContext *ctx, uint32_t opc, int rd, int base, int offset) @@ -1226,6 +1241,14 @@ static void gen_loongarch_ld(DisasContext *ctx, uint32_t opc, tcg_gen_qemu_ld_tl(t0, t0, mem_idx, MO_UB); gen_store_gpr(t0, rd); break; + case LA_OPC_LL_W: + op_ld_ll(t0, t0, mem_idx, ctx); + gen_store_gpr(t0, rd); + break; + case LA_OPC_LL_D: + op_ld_lld(t0, t0, mem_idx, ctx); + gen_store_gpr(t0, rd); + break; } tcg_temp_free(t0); } @@ -1264,6 +1287,37 @@ static void gen_loongarch_st(DisasContext *ctx, uint32_t opc, int rd, tcg_temp_free(t1); } +/* loongarch st cond */ +static void gen_loongarch_st_cond(DisasContext *ctx, int rd, int base, + int offset, MemOp tcg_mo, bool eva) +{ + TCGv t0 = tcg_temp_new(); + TCGv addr = tcg_temp_new(); + TCGv val = tcg_temp_new(); + TCGLabel *l1 = gen_new_label(); + TCGLabel *done = gen_new_label(); + + /* compare the address against that of the preceding LL */ + gen_base_offset_addr(ctx, addr, base, offset); + tcg_gen_brcond_tl(TCG_COND_EQ, addr, cpu_lladdr, l1); + tcg_gen_movi_tl(t0, 0); + gen_store_gpr(t0, rd); + tcg_gen_br(done); + + gen_set_label(l1); + /* generate cmpxchg */ + gen_load_gpr(val, rd); + tcg_gen_atomic_cmpxchg_tl(t0, cpu_lladdr, cpu_llval, val, + eva ? LOONGARCH_HFLAG_UM : ctx->mem_idx, tcg_mo); + tcg_gen_setcond_tl(TCG_COND_EQ, t0, t0, cpu_llval); + gen_store_gpr(t0, rd); + + gen_set_label(done); + tcg_temp_free(t0); + tcg_temp_free(addr); + tcg_temp_free(val); +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347847 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 43947C2B9F4 for ; Mon, 28 Jun 2021 12:18:09 +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 969FF61C69 for ; Mon, 28 Jun 2021 12:18:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 969FF61C69 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:33486 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqDH-0000Z1-FU for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:18:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51252) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0r-0002ga-9s for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:19 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45548 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0o-0001D3-0z for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:17 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S14; Mon, 28 Jun 2021 20:05:00 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 12/20] target/loongarch: Add fixed point extra instruction translation Date: Mon, 28 Jun 2021 20:04:37 +0800 Message-Id: <1624881885-31692-13-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S14 X-Coremail-Antispam: 1UD129KBjvJXoW3GF4fGF1xtw45uFyUKry3urg_yoWfCF13pr 18CryUGr48tFy3Z3sxKw15Jr45Ar1xu3W2q3yftw18AF1xWF1DXr10y3yakF4UGr1kZr43 Zas8AFWDKFyUXaUanT9S1TB71UUUUjDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UUUUUUUUU== X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement fixed point extra instruction translation. This includes: - CRC[C].W.{B/H/W/D}.W - SYSCALL - BREAK - ASRT{LE/GT}.D - RDTIME{L/H}.W, RDTIME.D - CPUCFG Signed-off-by: Song Gao --- target/loongarch/helper.h | 4 ++ target/loongarch/insns.decode | 25 ++++++++++ target/loongarch/op_helper.c | 69 ++++++++++++++++++++++++++ target/loongarch/trans.inc.c | 111 ++++++++++++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 27 ++++++++++ 5 files changed, 236 insertions(+) diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 5cd38c8..a60f293 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -21,3 +21,7 @@ DEF_HELPER_FLAGS_1(loongarch_dbitswap, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_3(asrtle_d, void, env, tl, tl) DEF_HELPER_3(asrtgt_d, void, env, tl, tl) + +DEF_HELPER_3(crc32, tl, tl, tl, i32) +DEF_HELPER_3(crc32c, tl, tl, tl, i32) +DEF_HELPER_2(cpucfg, tl, env, tl) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index beb2e4a..209e147 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -27,6 +27,7 @@ %si14 10:s14 %hint 0:5 %whint 0:15 +%code 0:15 # # Argument sets @@ -47,6 +48,8 @@ &fmt_hintrjsi12 hint rj si12 &fmt_hintrjrk hint rj rk &fmt_whint whint +&fmt_rjrk rj rk +&fmt_code code # # Formats @@ -67,6 +70,8 @@ @fmt_hintrjrk .... ........ ..... ..... ..... ..... &fmt_hintrjrk %hint %rj %rk @fmt_whint .... ........ ..... ............... &fmt_whint %whint @fmt_rdrjsi14 .... .... .............. ..... ..... &fmt_rdrjsi14 %rd %rj %si14 +@fmt_rjrk .... ........ ..... ..... ..... ..... &fmt_rjrk %rj %rk +@fmt_code .... ........ ..... ............... &fmt_code %code # # Fixed point arithmetic operation instruction @@ -263,3 +268,23 @@ ammax_db_wu 0011 10000111 00000 ..... ..... ..... @fmt_rdrjrk ammax_db_du 0011 10000111 00001 ..... ..... ..... @fmt_rdrjrk ammin_db_wu 0011 10000111 00010 ..... ..... ..... @fmt_rdrjrk ammin_db_du 0011 10000111 00011 ..... ..... ..... @fmt_rdrjrk + +# +# Fixed point extra instruction +# +crc_w_b_w 0000 00000010 01000 ..... ..... ..... @fmt_rdrjrk +crc_w_h_w 0000 00000010 01001 ..... ..... ..... @fmt_rdrjrk +crc_w_w_w 0000 00000010 01010 ..... ..... ..... @fmt_rdrjrk +crc_w_d_w 0000 00000010 01011 ..... ..... ..... @fmt_rdrjrk +crcc_w_b_w 0000 00000010 01100 ..... ..... ..... @fmt_rdrjrk +crcc_w_h_w 0000 00000010 01101 ..... ..... ..... @fmt_rdrjrk +crcc_w_w_w 0000 00000010 01110 ..... ..... ..... @fmt_rdrjrk +crcc_w_d_w 0000 00000010 01111 ..... ..... ..... @fmt_rdrjrk +break 0000 00000010 10100 ............... @fmt_code +syscall 0000 00000010 10110 ............... @fmt_code +asrtle_d 0000 00000000 00010 ..... ..... 00000 @fmt_rjrk +asrtgt_d 0000 00000000 00011 ..... ..... 00000 @fmt_rjrk +rdtimel_w 0000 00000000 00000 11000 ..... ..... @fmt_rdrj +rdtimeh_w 0000 00000000 00000 11001 ..... ..... @fmt_rdrj +rdtime_d 0000 00000000 00000 11010 ..... ..... @fmt_rdrj +cpucfg 0000 00000000 00000 11011 ..... ..... @fmt_rdrj diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c index 66499d4..55ebff1 100644 --- a/target/loongarch/op_helper.c +++ b/target/loongarch/op_helper.c @@ -14,6 +14,8 @@ #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" +#include "qemu/crc32c.h" +#include /* Exceptions helpers */ void helper_raise_exception_err(CPULoongArchState *env, uint32_t exception, @@ -160,3 +162,70 @@ void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) do_raise_exception(env, EXCP_ADE, GETPC()); } } + +target_ulong helper_crc32(target_ulong val, target_ulong m, uint32_t sz) +{ + uint8_t buf[8]; + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); + + m &= mask; + stq_le_p(buf, m); + return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); +} + +target_ulong helper_crc32c(target_ulong val, target_ulong m, uint32_t sz) +{ + uint8_t buf[8]; + target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); + m &= mask; + stq_le_p(buf, m); + return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); +} + +target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) +{ + target_ulong r = 0; + + switch (rj) { + case 0: + r = env->CSR_MCSR0 & 0xffffffff; + break; + case 1: + r = (env->CSR_MCSR0 & 0xffffffff00000000) >> 32; + break; + case 2: + r = env->CSR_MCSR1 & 0xffffffff; + break; + case 3: + r = (env->CSR_MCSR1 & 0xffffffff00000000) >> 32; + break; + case 4: + r = env->CSR_MCSR2 & 0xffffffff; + break; + case 5: + r = (env->CSR_MCSR2 & 0xffffffff00000000) >> 32; + break; + case 6: + r = env->CSR_MCSR3 & 0xffffffff; + break; + case 10: + r = env->CSR_MCSR8 & 0xffffffff; + break; + case 11: + r = (env->CSR_MCSR8 & 0xffffffff00000000) >> 32; + break; + case 12: + r = env->CSR_MCSR9 & 0xffffffff; + break; + case 13: + r = (env->CSR_MCSR9 & 0xffffffff00000000) >> 32; + break; + case 14: + r = env->CSR_MCSR10 & 0xffffffff; + break; + case 30: + r = env->CSR_MCSR24 & 0xffffffff; + break; + } + return r; +} diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index 3f1e64f..a63782d 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -1333,3 +1333,114 @@ TRANS_AM_DB_D(ammin_db_du, fetch_umin) /* trans_ammin_db_du */ #undef TRANS_AM_DB #undef TRANS_AM_DB_W #undef TRANS_AM_DB_D + +/* Fixed point extra instruction translation */ +static bool trans_crc_w_b_w(DisasContext *ctx, arg_crc_w_b_w *a) +{ + gen_crc32(ctx, a->rd, a->rj, a->rk, 1, 0); + return true; +} + +static bool trans_crc_w_h_w(DisasContext *ctx, arg_crc_w_h_w *a) +{ + gen_crc32(ctx, a->rd, a->rj, a->rk, 2, 0); + return true; +} + +static bool trans_crc_w_w_w(DisasContext *ctx, arg_crc_w_w_w *a) +{ + gen_crc32(ctx, a->rd, a->rj, a->rk, 4, 0); + return true; +} + +static bool trans_crc_w_d_w(DisasContext *ctx, arg_crc_w_d_w *a) +{ + gen_crc32(ctx, a->rd, a->rj, a->rk, 8, 0); + return true; +} +static bool trans_crcc_w_b_w(DisasContext *ctx, arg_crcc_w_b_w *a) +{ + gen_crc32(ctx, a->rd, a->rj, a->rk, 1, 1); + return true; +} + +static bool trans_crcc_w_h_w(DisasContext *ctx, arg_crcc_w_h_w *a) +{ + gen_crc32(ctx, a->rd, a->rj, a->rk, 2, 1); + return true; +} + +static bool trans_crcc_w_w_w(DisasContext *ctx, arg_crcc_w_w_w *a) +{ + gen_crc32(ctx, a->rd, a->rj, a->rk, 4, 1); + return true; +} + +static bool trans_crcc_w_d_w(DisasContext *ctx, arg_crcc_w_d_w *a) +{ + gen_crc32(ctx, a->rd, a->rj, a->rk, 8, 1); + return true; +} + +static bool trans_break(DisasContext *ctx, arg_break *a) +{ + generate_exception_end(ctx, EXCP_BREAK); + return true; +} + +static bool trans_syscall(DisasContext *ctx, arg_syscall *a) +{ + generate_exception_end(ctx, EXCP_SYSCALL); + return true; +} + +static bool trans_asrtle_d(DisasContext *ctx, arg_asrtle_d * a) +{ + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + gen_load_gpr(t1, a->rj); + gen_load_gpr(t2, a->rk); + gen_helper_asrtle_d(cpu_env, t1, t2); + tcg_temp_free(t1); + tcg_temp_free(t2); + return true; +} + +static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a) +{ + TCGv t1 = tcg_temp_new(); + TCGv t2 = tcg_temp_new(); + gen_load_gpr(t1, a->rj); + gen_load_gpr(t2, a->rk); + gen_helper_asrtgt_d(cpu_env, t1, t2); + tcg_temp_free(t1); + tcg_temp_free(t2); + return true; +} + +static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a) +{ + /* Nop */ + return true; +} + +static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a) +{ + /* Nop */ + return true; +} + +static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a) +{ + /* Nop */ + return true; +} + +static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) +{ + TCGv t0 = tcg_temp_new(); + gen_load_gpr(t0, a->rj); + gen_helper_cpucfg(cpu_gpr[a->rd], cpu_env, t0); + tcg_temp_free(t0); + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index bf14507..571ef58 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -1318,6 +1318,33 @@ static void gen_loongarch_st_cond(DisasContext *ctx, int rd, int base, tcg_temp_free(val); } +static void gen_crc32(DisasContext *ctx, int rd, int rj, int rk, int sz, + int crc32c) +{ + TCGv t0; + TCGv t1; + TCGv_i32 tsz = tcg_const_i32(1 << sz); + if (rd == 0) { + /* Treat as NOP. */ + return; + } + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + gen_load_gpr(t0, rk); + gen_load_gpr(t1, rj); + + if (crc32c) { + gen_helper_crc32c(cpu_gpr[rd], t0, t1, tsz); + } else { + gen_helper_crc32(cpu_gpr[rd], t0, t1, tsz); + } + + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_temp_free_i32(tsz); +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347843 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 D6BA8C2B9F4 for ; Mon, 28 Jun 2021 12:17:12 +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 7420661C49 for ; Mon, 28 Jun 2021 12:17:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7420661C49 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:59268 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqCN-0007LI-Gm for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:17:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51366) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq13-0002sw-UT for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:30 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45562 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0p-0001DF-CG for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:29 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S15; Mon, 28 Jun 2021 20:05:01 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 13/20] target/loongarch: Add floating point arithmetic instruction translation Date: Mon, 28 Jun 2021 20:04:38 +0800 Message-Id: <1624881885-31692-14-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S15 X-Coremail-Antispam: 1UD129KBjvAXoWDZryrGr4xWr4ktw1kXFW7twb_yoWrAr1UWo WUC3W5ArW8Gw47ur9Ikws8Xa12qFWjvFsrJrWF934rWF4xCr47KFy7Wan5Aa4xKr4Fgry5 Xrnay3Wft343Kr97n29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement floating point arithmetic instruction translation. This includes: - F{ADD/SUB/MUL/DIV}.{S/D} - F{MADD/MSUB/NMADD/NMSUB}.{S/D} - F{MAX/MIN}.{S/D} - F{MAXA/MINA}.{S/D} - F{ABS/NEG}.{S/D} - F{SQRT/RECIP/RSQRT}.{S/D} - F{SCALEB/LOGB/COPYSIGN}.{S/D} - FCLASS.{S/D} Signed-off-by: Song Gao --- target/loongarch/cpu.c | 2 + target/loongarch/fpu_helper.c | 381 +++++++++++++++++++++++++++++++++++++ target/loongarch/fpu_helper.h | 34 ++++ target/loongarch/helper.h | 47 +++++ target/loongarch/insns.decode | 56 ++++++ target/loongarch/instmap.h | 32 ++++ target/loongarch/trans.inc.c | 427 ++++++++++++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 334 +++++++++++++++++++++++++++++++++ 8 files changed, 1313 insertions(+) create mode 100644 target/loongarch/fpu_helper.c create mode 100644 target/loongarch/fpu_helper.h diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index a39a3bd..f4df484 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -19,6 +19,7 @@ #include "cpu-csr.h" #include "cpu-qom.h" #include "internal.h" +#include "fpu_helper.h" static const char * const excp_names[EXCP_LAST + 1] = { [EXCP_INTE] = "Interrupt error", @@ -305,6 +306,7 @@ static void loongarch_cpu_reset(DeviceState *dev) env->insn_flags = env->cpu_model->INSN_FLAGS; compute_hflags(env); + restore_fp_status(env); restore_pamask(env); cs->exception_index = EXCP_NONE; } diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c new file mode 100644 index 0000000..d085bb0 --- /dev/null +++ b/target/loongarch/fpu_helper.c @@ -0,0 +1,381 @@ +/* + * LoongArch float point emulation helpers for qemu + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internal.h" +#include "fpu_helper.h" +#include "exec/helper-proto.h" +#include "exec/exec-all.h" +#include "exec/cpu_ldst.h" +#include "fpu/softfloat.h" + +#define FP_TO_INT32_OVERFLOW 0x7fffffff +#define FP_TO_INT64_OVERFLOW 0x7fffffffffffffffULL + +#define FP_CLASS_SIGNALING_NAN 0x001 +#define FP_CLASS_QUIET_NAN 0x002 +#define FP_CLASS_NEGATIVE_INFINITY 0x004 +#define FP_CLASS_NEGATIVE_NORMAL 0x008 +#define FP_CLASS_NEGATIVE_SUBNORMAL 0x010 +#define FP_CLASS_NEGATIVE_ZERO 0x020 +#define FP_CLASS_POSITIVE_INFINITY 0x040 +#define FP_CLASS_POSITIVE_NORMAL 0x080 +#define FP_CLASS_POSITIVE_SUBNORMAL 0x100 +#define FP_CLASS_POSITIVE_ZERO 0x200 + +/* convert loongarch rounding mode in fcsr0 to IEEE library */ +const FloatRoundMode ieee_rm[4] = { + float_round_nearest_even, + float_round_to_zero, + float_round_up, + float_round_down +}; + +int ieee_ex_to_loongarch(int xcpt) +{ + int ret = 0; + if (xcpt) { + if (xcpt & float_flag_invalid) { + ret |= FP_INVALID; + } + if (xcpt & float_flag_overflow) { + ret |= FP_OVERFLOW; + } + if (xcpt & float_flag_underflow) { + ret |= FP_UNDERFLOW; + } + if (xcpt & float_flag_divbyzero) { + ret |= FP_DIV0; + } + if (xcpt & float_flag_inexact) { + ret |= FP_INEXACT; + } + } + return ret; +} + +static inline void update_fcsr0(CPULoongArchState *env, uintptr_t pc) +{ + int tmp = ieee_ex_to_loongarch(get_float_exception_flags( + &env->active_fpu.fp_status)); + + SET_FP_CAUSE(env->active_fpu.fcsr0, tmp); + if (tmp) { + set_float_exception_flags(0, &env->active_fpu.fp_status); + + if (GET_FP_ENABLE(env->active_fpu.fcsr0) & tmp) { + do_raise_exception(env, EXCP_FPE, pc); + } else { + UPDATE_FP_FLAGS(env->active_fpu.fcsr0, tmp); + } + } +} + +uint64_t helper_fp_sqrt_d(CPULoongArchState *env, uint64_t fp) +{ + fp = float64_sqrt(fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp; +} + +uint32_t helper_fp_sqrt_s(CPULoongArchState *env, uint32_t fp) +{ + fp = float32_sqrt(fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp; +} + +uint64_t helper_fp_abs_d(uint64_t fp) +{ + return float64_abs(fp); +} +uint32_t helper_fp_abs_s(uint32_t fp) +{ + return float32_abs(fp); +} + +uint64_t helper_fp_neg_d(uint64_t fp) +{ + return float64_chs(fp); +} +uint32_t helper_fp_neg_s(uint32_t fp) +{ + return float32_chs(fp); +} + +uint64_t helper_fp_recip_d(CPULoongArchState *env, uint64_t fp) +{ + uint64_t fp1; + + fp1 = float64_div(float64_one, fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp1; +} + +uint32_t helper_fp_recip_s(CPULoongArchState *env, uint32_t fp) +{ + uint32_t fp1; + + fp1 = float32_div(float32_one, fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp1; +} + +uint64_t helper_fp_rsqrt_d(CPULoongArchState *env, uint64_t fp) +{ + uint64_t fp1; + + fp1 = float64_sqrt(fp, &env->active_fpu.fp_status); + fp1 = float64_div(float64_one, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp1; +} + +uint32_t helper_fp_rsqrt_s(CPULoongArchState *env, uint32_t fp) +{ + uint32_t fp1; + + fp1 = float32_sqrt(fp, &env->active_fpu.fp_status); + fp1 = float32_div(float32_one, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp1; +} + +uint32_t fp_class_s(uint32_t arg, float_status *status) +{ + if (float32_is_signaling_nan(arg, status)) { + return FP_CLASS_SIGNALING_NAN; + } else if (float32_is_quiet_nan(arg, status)) { + return FP_CLASS_QUIET_NAN; + } else if (float32_is_neg(arg)) { + if (float32_is_infinity(arg)) { + return FP_CLASS_NEGATIVE_INFINITY; + } else if (float32_is_zero(arg)) { + return FP_CLASS_NEGATIVE_ZERO; + } else if (float32_is_zero_or_denormal(arg)) { + return FP_CLASS_NEGATIVE_SUBNORMAL; + } else { + return FP_CLASS_NEGATIVE_NORMAL; + } + } else { + if (float32_is_infinity(arg)) { + return FP_CLASS_POSITIVE_INFINITY; + } else if (float32_is_zero(arg)) { + return FP_CLASS_POSITIVE_ZERO; + } else if (float32_is_zero_or_denormal(arg)) { + return FP_CLASS_POSITIVE_SUBNORMAL; + } else { + return FP_CLASS_POSITIVE_NORMAL; + } + } +} + +uint32_t helper_fp_class_s(CPULoongArchState *env, uint32_t arg) +{ + return fp_class_s(arg, &env->active_fpu.fp_status); +} + +uint64_t fp_class_d(uint64_t arg, float_status *status) +{ + if (float64_is_signaling_nan(arg, status)) { + return FP_CLASS_SIGNALING_NAN; + } else if (float64_is_quiet_nan(arg, status)) { + return FP_CLASS_QUIET_NAN; + } else if (float64_is_neg(arg)) { + if (float64_is_infinity(arg)) { + return FP_CLASS_NEGATIVE_INFINITY; + } else if (float64_is_zero(arg)) { + return FP_CLASS_NEGATIVE_ZERO; + } else if (float64_is_zero_or_denormal(arg)) { + return FP_CLASS_NEGATIVE_SUBNORMAL; + } else { + return FP_CLASS_NEGATIVE_NORMAL; + } + } else { + if (float64_is_infinity(arg)) { + return FP_CLASS_POSITIVE_INFINITY; + } else if (float64_is_zero(arg)) { + return FP_CLASS_POSITIVE_ZERO; + } else if (float64_is_zero_or_denormal(arg)) { + return FP_CLASS_POSITIVE_SUBNORMAL; + } else { + return FP_CLASS_POSITIVE_NORMAL; + } + } +} + +uint64_t helper_fp_class_d(CPULoongArchState *env, uint64_t arg) +{ + return fp_class_d(arg, &env->active_fpu.fp_status); +} + +uint64_t helper_fp_add_d(CPULoongArchState *env, uint64_t fp, uint64_t fp1) +{ + uint64_t fp2; + + fp2 = float64_add(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +uint32_t helper_fp_add_s(CPULoongArchState *env, uint32_t fp, uint32_t fp1) +{ + uint32_t fp2; + + fp2 = float32_add(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +uint64_t helper_fp_sub_d(CPULoongArchState *env, uint64_t fp, uint64_t fp1) +{ + uint64_t fp2; + + fp2 = float64_sub(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +uint32_t helper_fp_sub_s(CPULoongArchState *env, uint32_t fp, uint32_t fp1) +{ + uint32_t fp2; + + fp2 = float32_sub(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +uint64_t helper_fp_mul_d(CPULoongArchState *env, uint64_t fp, uint64_t fp1) +{ + uint64_t fp2; + + fp2 = float64_mul(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +uint32_t helper_fp_mul_s(CPULoongArchState *env, uint32_t fp, uint32_t fp1) +{ + uint32_t fp2; + + fp2 = float32_mul(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +uint64_t helper_fp_div_d(CPULoongArchState *env, uint64_t fp, uint64_t fp1) +{ + uint64_t fp2; + + fp2 = float64_div(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +uint32_t helper_fp_div_s(CPULoongArchState *env, uint32_t fp, uint32_t fp1) +{ + uint32_t fp2; + + fp2 = float32_div(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +uint64_t helper_fp_exp2_d(CPULoongArchState *env, + uint64_t fp, uint64_t fp1) +{ + uint64_t fp2; + int64_t n = (int64_t)fp1; + + fp2 = float64_scalbn(fp, + n > 0x1000 ? 0x1000 : + n < -0x1000 ? -0x1000 : n, + &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +uint32_t helper_fp_exp2_s(CPULoongArchState *env, + uint32_t fp, uint32_t fp1) +{ + uint32_t fp2; + int32_t n = (int32_t)fp1; + + fp2 = float32_scalbn(fp, + n > 0x200 ? 0x200 : + n < -0x200 ? -0x200 : n, + &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp2; +} + +#define FP_MINMAX(name, bits, minmaxfunc) \ +uint ## bits ## _t helper_fp_ ## name(CPULoongArchState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _ ## minmaxfunc(fs, ft, \ + &env->active_fpu.fp_status); \ + update_fcsr0(env, GETPC()); \ + return fdret; \ +} + +FP_MINMAX(max_s, 32, maxnum) +FP_MINMAX(max_d, 64, maxnum) +FP_MINMAX(maxa_s, 32, maxnummag) +FP_MINMAX(maxa_d, 64, maxnummag) +FP_MINMAX(min_s, 32, minnum) +FP_MINMAX(min_d, 64, minnum) +FP_MINMAX(mina_s, 32, minnummag) +FP_MINMAX(mina_d, 64, minnummag) +#undef FP_MINMAX + +#define FP_FMADDSUB(name, bits, muladd_arg) \ +uint ## bits ## _t helper_fp_ ## name(CPULoongArchState *env, \ + uint ## bits ## _t fs, \ + uint ## bits ## _t ft, \ + uint ## bits ## _t fd) \ +{ \ + uint ## bits ## _t fdret; \ + \ + fdret = float ## bits ## _muladd(fs, ft, fd, muladd_arg, \ + &env->active_fpu.fp_status); \ + update_fcsr0(env, GETPC()); \ + return fdret; \ +} + +FP_FMADDSUB(madd_s, 32, 0) +FP_FMADDSUB(madd_d, 64, 0) +FP_FMADDSUB(msub_s, 32, float_muladd_negate_c) +FP_FMADDSUB(msub_d, 64, float_muladd_negate_c) +FP_FMADDSUB(nmadd_s, 32, float_muladd_negate_result) +FP_FMADDSUB(nmadd_d, 64, float_muladd_negate_result) +FP_FMADDSUB(nmsub_s, 32, float_muladd_negate_result | float_muladd_negate_c) +FP_FMADDSUB(nmsub_d, 64, float_muladd_negate_result | float_muladd_negate_c) +#undef FP_FMADDSUB + +uint32_t helper_fp_logb_s(CPULoongArchState *env, uint32_t fp) +{ + uint32_t fp1; + + fp1 = float32_log2(fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp1; +} + +uint64_t helper_fp_logb_d(CPULoongArchState *env, uint64_t fp) +{ + uint64_t fp1; + + fp1 = float64_log2(fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return fp1; +} diff --git a/target/loongarch/fpu_helper.h b/target/loongarch/fpu_helper.h new file mode 100644 index 0000000..2537a3d --- /dev/null +++ b/target/loongarch/fpu_helper.h @@ -0,0 +1,34 @@ +/* + * QEMU LoongArch CPU + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "fpu/softfloat-helpers.h" +#include "cpu.h" + +extern const FloatRoundMode ieee_rm[4]; + +uint32_t fp_class_s(uint32_t arg, float_status *fst); +uint64_t fp_class_d(uint64_t arg, float_status *fst); + +int ieee_ex_to_loongarch(int xcpt); + +static inline void restore_rounding_mode(CPULoongArchState *env) +{ + set_float_rounding_mode(ieee_rm[(env->active_fpu.fcsr0 >> FCSR0_RM) & 0x3], + &env->active_fpu.fp_status); +} + +static inline void restore_flush_mode(CPULoongArchState *env) +{ + set_flush_to_zero(0, &env->active_fpu.fp_status); +} + +static inline void restore_fp_status(CPULoongArchState *env) +{ + restore_rounding_mode(env); + restore_flush_mode(env); +} diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index a60f293..e945177 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -25,3 +25,50 @@ DEF_HELPER_3(asrtgt_d, void, env, tl, tl) DEF_HELPER_3(crc32, tl, tl, tl, i32) DEF_HELPER_3(crc32c, tl, tl, tl, i32) DEF_HELPER_2(cpucfg, tl, env, tl) + +/* Floating-point helper */ +DEF_HELPER_3(fp_add_s, i32, env, i32, i32) +DEF_HELPER_3(fp_add_d, i64, env, i64, i64) +DEF_HELPER_3(fp_sub_s, i32, env, i32, i32) +DEF_HELPER_3(fp_sub_d, i64, env, i64, i64) +DEF_HELPER_3(fp_mul_s, i32, env, i32, i32) +DEF_HELPER_3(fp_mul_d, i64, env, i64, i64) +DEF_HELPER_3(fp_div_s, i32, env, i32, i32) +DEF_HELPER_3(fp_div_d, i64, env, i64, i64) +DEF_HELPER_3(fp_max_s, i32, env, i32, i32) +DEF_HELPER_3(fp_max_d, i64, env, i64, i64) +DEF_HELPER_3(fp_maxa_s, i32, env, i32, i32) +DEF_HELPER_3(fp_maxa_d, i64, env, i64, i64) +DEF_HELPER_3(fp_min_s, i32, env, i32, i32) +DEF_HELPER_3(fp_min_d, i64, env, i64, i64) +DEF_HELPER_3(fp_mina_s, i32, env, i32, i32) +DEF_HELPER_3(fp_mina_d, i64, env, i64, i64) + +DEF_HELPER_4(fp_madd_s, i32, env, i32, i32, i32) +DEF_HELPER_4(fp_madd_d, i64, env, i64, i64, i64) +DEF_HELPER_4(fp_msub_s, i32, env, i32, i32, i32) +DEF_HELPER_4(fp_msub_d, i64, env, i64, i64, i64) +DEF_HELPER_4(fp_nmadd_s, i32, env, i32, i32, i32) +DEF_HELPER_4(fp_nmadd_d, i64, env, i64, i64, i64) +DEF_HELPER_4(fp_nmsub_s, i32, env, i32, i32, i32) +DEF_HELPER_4(fp_nmsub_d, i64, env, i64, i64, i64) + +DEF_HELPER_3(fp_exp2_s, i32, env, i32, i32) +DEF_HELPER_3(fp_exp2_d, i64, env, i64, i64) +DEF_HELPER_2(fp_logb_s, i32, env, i32) +DEF_HELPER_2(fp_logb_d, i64, env, i64) + +DEF_HELPER_1(fp_abs_s, i32, i32) +DEF_HELPER_1(fp_abs_d, i64, i64) +DEF_HELPER_1(fp_neg_s, i32, i32) +DEF_HELPER_1(fp_neg_d, i64, i64) + +DEF_HELPER_2(fp_sqrt_s, i32, env, i32) +DEF_HELPER_2(fp_sqrt_d, i64, env, i64) +DEF_HELPER_2(fp_rsqrt_s, i32, env, i32) +DEF_HELPER_2(fp_rsqrt_d, i64, env, i64) +DEF_HELPER_2(fp_recip_s, i32, env, i32) +DEF_HELPER_2(fp_recip_d, i64, env, i64) + +DEF_HELPER_FLAGS_2(fp_class_s, TCG_CALL_NO_RWG_SE, i32, env, i32) +DEF_HELPER_FLAGS_2(fp_class_d, TCG_CALL_NO_RWG_SE, i64, env, i64) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 209e147..8730725 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -28,6 +28,10 @@ %hint 0:5 %whint 0:15 %code 0:15 +%fd 0:5 +%fj 5:5 +%fk 10:5 +%fa 15:5 # # Argument sets @@ -50,6 +54,9 @@ &fmt_whint whint &fmt_rjrk rj rk &fmt_code code +&fmt_fdfjfk fd fj fk +&fmt_fdfjfkfa fd fj fk fa +&fmt_fdfj fd fj # # Formats @@ -72,6 +79,9 @@ @fmt_rdrjsi14 .... .... .............. ..... ..... &fmt_rdrjsi14 %rd %rj %si14 @fmt_rjrk .... ........ ..... ..... ..... ..... &fmt_rjrk %rj %rk @fmt_code .... ........ ..... ............... &fmt_code %code +@fmt_fdfjfk .... ........ ..... ..... ..... ..... &fmt_fdfjfk %fd %fj %fk +@fmt_fdfjfkfa .... ........ ..... ..... ..... ..... &fmt_fdfjfkfa %fd %fj %fk %fa +@fmt_fdfj .... ........ ..... ..... ..... ..... &fmt_fdfj %fd %fj # # Fixed point arithmetic operation instruction @@ -288,3 +298,49 @@ rdtimel_w 0000 00000000 00000 11000 ..... ..... @fmt_rdrj rdtimeh_w 0000 00000000 00000 11001 ..... ..... @fmt_rdrj rdtime_d 0000 00000000 00000 11010 ..... ..... @fmt_rdrj cpucfg 0000 00000000 00000 11011 ..... ..... @fmt_rdrj + +# +# Floating point arithmetic operation instruction +# +fadd_s 0000 00010000 00001 ..... ..... ..... @fmt_fdfjfk +fadd_d 0000 00010000 00010 ..... ..... ..... @fmt_fdfjfk +fsub_s 0000 00010000 00101 ..... ..... ..... @fmt_fdfjfk +fsub_d 0000 00010000 00110 ..... ..... ..... @fmt_fdfjfk +fmul_s 0000 00010000 01001 ..... ..... ..... @fmt_fdfjfk +fmul_d 0000 00010000 01010 ..... ..... ..... @fmt_fdfjfk +fdiv_s 0000 00010000 01101 ..... ..... ..... @fmt_fdfjfk +fdiv_d 0000 00010000 01110 ..... ..... ..... @fmt_fdfjfk +fmadd_s 0000 10000001 ..... ..... ..... ..... @fmt_fdfjfkfa +fmadd_d 0000 10000010 ..... ..... ..... ..... @fmt_fdfjfkfa +fmsub_s 0000 10000101 ..... ..... ..... ..... @fmt_fdfjfkfa +fmsub_d 0000 10000110 ..... ..... ..... ..... @fmt_fdfjfkfa +fnmadd_s 0000 10001001 ..... ..... ..... ..... @fmt_fdfjfkfa +fnmadd_d 0000 10001010 ..... ..... ..... ..... @fmt_fdfjfkfa +fnmsub_s 0000 10001101 ..... ..... ..... ..... @fmt_fdfjfkfa +fnmsub_d 0000 10001110 ..... ..... ..... ..... @fmt_fdfjfkfa +fmax_s 0000 00010000 10001 ..... ..... ..... @fmt_fdfjfk +fmax_d 0000 00010000 10010 ..... ..... ..... @fmt_fdfjfk +fmin_s 0000 00010000 10101 ..... ..... ..... @fmt_fdfjfk +fmin_d 0000 00010000 10110 ..... ..... ..... @fmt_fdfjfk +fmaxa_s 0000 00010000 11001 ..... ..... ..... @fmt_fdfjfk +fmaxa_d 0000 00010000 11010 ..... ..... ..... @fmt_fdfjfk +fmina_s 0000 00010000 11101 ..... ..... ..... @fmt_fdfjfk +fmina_d 0000 00010000 11110 ..... ..... ..... @fmt_fdfjfk +fabs_s 0000 00010001 01000 00001 ..... ..... @fmt_fdfj +fabs_d 0000 00010001 01000 00010 ..... ..... @fmt_fdfj +fneg_s 0000 00010001 01000 00101 ..... ..... @fmt_fdfj +fneg_d 0000 00010001 01000 00110 ..... ..... @fmt_fdfj +fsqrt_s 0000 00010001 01000 10001 ..... ..... @fmt_fdfj +fsqrt_d 0000 00010001 01000 10010 ..... ..... @fmt_fdfj +frecip_s 0000 00010001 01000 10101 ..... ..... @fmt_fdfj +frecip_d 0000 00010001 01000 10110 ..... ..... @fmt_fdfj +frsqrt_s 0000 00010001 01000 11001 ..... ..... @fmt_fdfj +frsqrt_d 0000 00010001 01000 11010 ..... ..... @fmt_fdfj +fscaleb_s 0000 00010001 00001 ..... ..... ..... @fmt_fdfjfk +fscaleb_d 0000 00010001 00010 ..... ..... ..... @fmt_fdfjfk +flogb_s 0000 00010001 01000 01001 ..... ..... @fmt_fdfj +flogb_d 0000 00010001 01000 01010 ..... ..... @fmt_fdfj +fcopysign_s 0000 00010001 00101 ..... ..... ..... @fmt_fdfjfk +fcopysign_d 0000 00010001 00110 ..... ..... ..... @fmt_fdfjfk +fclass_s 0000 00010001 01000 01101 ..... ..... @fmt_fdfj +fclass_d 0000 00010001 01000 01110 ..... ..... @fmt_fdfj diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h index ea5396e..f562e32 100644 --- a/target/loongarch/instmap.h +++ b/target/loongarch/instmap.h @@ -67,6 +67,38 @@ enum { LA_OPC_TRPICK_W = (0x003 << 21) | (0x1 << 15) }; +/* floating point opcodes*/ +enum { + LA_OPC_FABS_S = (0x004501 << 10), + LA_OPC_FABS_D = (0x004502 << 10), + LA_OPC_FNEG_S = (0x004505 << 10), + LA_OPC_FNEG_D = (0x004506 << 10), + LA_OPC_FCLASS_S = (0x00450D << 10), + LA_OPC_FCLASS_D = (0x00450E << 10), + LA_OPC_FSQRT_S = (0x004511 << 10), + LA_OPC_FSQRT_D = (0x004512 << 10), + LA_OPC_FRECIP_S = (0x004515 << 10), + LA_OPC_FRECIP_D = (0x004516 << 10), + LA_OPC_FRSQRT_S = (0x004519 << 10), + LA_OPC_FRSQRT_D = (0x00451A << 10), + LA_OPC_FADD_S = (0x00201 << 15), + LA_OPC_FADD_D = (0x00202 << 15), + LA_OPC_FSUB_S = (0x00205 << 15), + LA_OPC_FSUB_D = (0x00206 << 15), + LA_OPC_FMUL_S = (0x00209 << 15), + LA_OPC_FMUL_D = (0x0020A << 15), + LA_OPC_FDIV_S = (0x0020D << 15), + LA_OPC_FDIV_D = (0x0020E << 15), + LA_OPC_FMAX_S = (0x00211 << 15), + LA_OPC_FMAX_D = (0x00212 << 15), + LA_OPC_FMIN_S = (0x00215 << 15), + LA_OPC_FMIN_D = (0x00216 << 15), + LA_OPC_FMAXA_S = (0x00219 << 15), + LA_OPC_FMAXA_D = (0x0021A << 15), + LA_OPC_FMINA_S = (0x0021D << 15), + LA_OPC_FMINA_D = (0x0021E << 15) +}; + /* 12 bit immediate opcodes */ enum { LA_OPC_SLTI = (0x008 << 22), diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index a63782d..cd82155 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -1444,3 +1444,430 @@ static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a) tcg_temp_free(t0); return true; } + +/* Floating point arithmetic operation instruction translation */ +static bool trans_fadd_s(DisasContext *ctx, arg_fadd_s * a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FADD_S, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fadd_d(DisasContext *ctx, arg_fadd_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FADD_D, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fsub_s(DisasContext *ctx, arg_fsub_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FSUB_S, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fsub_d(DisasContext *ctx, arg_fsub_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FSUB_D, a->fk, a->fj, a->fd); + return true; +} +static bool trans_fmul_s(DisasContext *ctx, arg_fmul_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMUL_S, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fmul_d(DisasContext *ctx, arg_fmul_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMUL_D, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fdiv_s(DisasContext *ctx, arg_fdiv_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FDIV_S, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fdiv_d(DisasContext *ctx, arg_fdiv_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FDIV_D, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fmadd_s(DisasContext *ctx, arg_fmadd_s *a) +{ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + TCGv_i32 fp3 = tcg_temp_new_i32(); + + check_fpu_enabled(ctx); + gen_load_fpr32(ctx, fp0, a->fj); + gen_load_fpr32(ctx, fp1, a->fk); + gen_load_fpr32(ctx, fp2, a->fa); + gen_helper_fp_madd_s(fp3, cpu_env, fp0, fp1, fp2); + gen_store_fpr32(ctx, fp3, a->fd); + + tcg_temp_free_i32(fp3); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + return true; +} + +static bool trans_fmadd_d(DisasContext *ctx, arg_fmadd_d *a) +{ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + TCGv_i64 fp3 = tcg_temp_new_i64(); + + check_fpu_enabled(ctx); + gen_load_fpr64(ctx, fp0, a->fj); + gen_load_fpr64(ctx, fp1, a->fk); + gen_load_fpr64(ctx, fp2, a->fa); + gen_helper_fp_madd_d(fp3, cpu_env, fp0, fp1, fp2); + gen_store_fpr64(ctx, fp3, a->fd); + + tcg_temp_free_i64(fp3); + tcg_temp_free_i64(fp2); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + return true; +} + +static bool trans_fmsub_s(DisasContext *ctx, arg_fmsub_s *a) +{ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + TCGv_i32 fp3 = tcg_temp_new_i32(); + + check_fpu_enabled(ctx); + gen_load_fpr32(ctx, fp0, a->fj); + gen_load_fpr32(ctx, fp1, a->fk); + gen_load_fpr32(ctx, fp2, a->fa); + gen_helper_fp_msub_s(fp3, cpu_env, fp0, fp1, fp2); + gen_store_fpr32(ctx, fp3, a->fd); + + tcg_temp_free_i32(fp3); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + return true; +} + +static bool trans_fmsub_d(DisasContext *ctx, arg_fmsub_d *a) +{ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + TCGv_i64 fp3 = tcg_temp_new_i64(); + + check_fpu_enabled(ctx); + gen_load_fpr64(ctx, fp0, a->fj); + gen_load_fpr64(ctx, fp1, a->fk); + gen_load_fpr64(ctx, fp2, a->fa); + gen_helper_fp_msub_d(fp3, cpu_env, fp0, fp1, fp2); + + tcg_temp_free_i64(fp3); + tcg_temp_free_i64(fp2); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + return true; +} + +static bool trans_fnmadd_s(DisasContext *ctx, arg_fnmadd_s *a) +{ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + TCGv_i32 fp3 = tcg_temp_new_i32(); + + check_fpu_enabled(ctx); + gen_load_fpr32(ctx, fp0, a->fj); + gen_load_fpr32(ctx, fp1, a->fk); + gen_load_fpr32(ctx, fp2, a->fa); + gen_helper_fp_nmadd_s(fp3, cpu_env, fp0, fp1, fp2); + + tcg_temp_free_i32(fp3); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + return true; +} + +static bool trans_fnmadd_d(DisasContext *ctx, arg_fnmadd_d *a) +{ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + TCGv_i64 fp3 = tcg_temp_new_i64(); + + check_fpu_enabled(ctx); + gen_load_fpr64(ctx, fp0, a->fj); + gen_load_fpr64(ctx, fp1, a->fk); + gen_load_fpr64(ctx, fp2, a->fa); + gen_helper_fp_nmadd_d(fp3, cpu_env, fp0, fp1, fp2); + + tcg_temp_free_i64(fp3); + tcg_temp_free_i64(fp2); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + return true; +} + +static bool trans_fnmsub_s(DisasContext *ctx, arg_fnmsub_s *a) +{ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + TCGv_i32 fp3 = tcg_temp_new_i32(); + + check_fpu_enabled(ctx); + gen_load_fpr32(ctx, fp0, a->fj); + gen_load_fpr32(ctx, fp1, a->fk); + gen_load_fpr32(ctx, fp2, a->fa); + gen_helper_fp_nmsub_s(fp3, cpu_env, fp0, fp1, fp2); + + tcg_temp_free_i32(fp3); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + return true; +} + +static bool trans_fnmsub_d(DisasContext *ctx, arg_fnmsub_d *a) +{ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + TCGv_i64 fp3 = tcg_temp_new_i64(); + + check_fpu_enabled(ctx); + gen_load_fpr64(ctx, fp0, a->fj); + gen_load_fpr64(ctx, fp1, a->fk); + gen_load_fpr64(ctx, fp2, a->fa); + gen_helper_fp_nmsub_d(fp3, cpu_env, fp0, fp1, fp2); + + tcg_temp_free_i64(fp3); + tcg_temp_free_i64(fp2); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + return true; +} + +static bool trans_fmax_s(DisasContext *ctx, arg_fmax_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMAX_S, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fmax_d(DisasContext *ctx, arg_fmax_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMAX_D, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fmin_s(DisasContext *ctx, arg_fmin_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMIN_S, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fmin_d(DisasContext *ctx, arg_fmin_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMIN_D, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fmaxa_s(DisasContext *ctx, arg_fmaxa_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMAXA_S, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fmaxa_d(DisasContext *ctx, arg_fmaxa_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMAXA_D, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fmina_s(DisasContext *ctx, arg_fmina_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMINA_S, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fmina_d(DisasContext *ctx, arg_fmina_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FMINA_D, a->fk, a->fj, a->fd); + return true; +} + +static bool trans_fabs_s(DisasContext *ctx, arg_fabs_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FABS_S, 0, a->fj, a->fd); + return true; +} + +static bool trans_fabs_d(DisasContext *ctx, arg_fabs_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FABS_D, 0, a->fj, a->fd); + return true; +} + +static bool trans_fneg_s(DisasContext *ctx, arg_fneg_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FNEG_S, 0, a->fj, a->fd); + return true; +} + +static bool trans_fneg_d(DisasContext *ctx, arg_fneg_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FNEG_D, 0, a->fj, a->fd); + return true; +} + +static bool trans_fsqrt_s(DisasContext *ctx, arg_fsqrt_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FSQRT_S, 0, a->fj, a->fd); + return true; +} + +static bool trans_fsqrt_d(DisasContext *ctx, arg_fsqrt_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FSQRT_D, 0, a->fj, a->fd); + return true; +} + +static bool trans_frecip_s(DisasContext *ctx, arg_frecip_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FRECIP_S, 0, a->fj, a->fd); + return true; +} + +static bool trans_frecip_d(DisasContext *ctx, arg_frecip_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FRECIP_D, 0, a->fj, a->fd); + return true; +} + +static bool trans_frsqrt_s(DisasContext *ctx, arg_frsqrt_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FRSQRT_S, 0, a->fj, a->fd); + return true; +} + +static bool trans_frsqrt_d(DisasContext *ctx, arg_frsqrt_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FRSQRT_D, 0, a->fj, a->fd); + return true; +} + +static bool trans_fscaleb_s(DisasContext *ctx, arg_fscaleb_s *a) +{ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + check_fpu_enabled(ctx); + gen_load_fpr32(ctx, fp0, a->fj); + gen_load_fpr32(ctx, fp1, a->fk); + gen_helper_fp_exp2_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(ctx, fp0, a->fd); + tcg_temp_free_i32(fp0); + return true; +} + +static bool trans_fscaleb_d(DisasContext *ctx, arg_fscaleb_d *a) +{ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + check_fpu_enabled(ctx); + gen_load_fpr64(ctx, fp0, a->fj); + gen_load_fpr64(ctx, fp1, a->fk); + gen_helper_fp_exp2_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, a->fd); + tcg_temp_free_i64(fp0); + return true; +} + +static bool trans_flogb_s(DisasContext *ctx, arg_flogb_s *a) +{ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + check_fpu_enabled(ctx); + gen_load_fpr32(ctx, fp0, a->fj); + gen_helper_fp_logb_s(fp1, cpu_env, fp0); + gen_store_fpr32(ctx, fp1, a->fd); + + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + return true; +} + +static bool trans_flogb_d(DisasContext *ctx, arg_flogb_d *a) +{ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + check_fpu_enabled(ctx); + gen_load_fpr64(ctx, fp0, a->fj); + gen_helper_fp_logb_d(fp1, cpu_env, fp0); + gen_store_fpr64(ctx, fp1, a->fd); + + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + return true; +} + +static bool trans_fcopysign_s(DisasContext *ctx, arg_fcopysign_s *a) +{ + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + + check_fpu_enabled(ctx); + gen_load_fpr32(ctx, fp0, a->fj); + gen_load_fpr32(ctx, fp1, a->fk); + tcg_gen_deposit_i32(fp2, fp1, fp0, 0, 31); + gen_store_fpr32(ctx, fp2, a->fd); + + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + return true; +} + +static bool trans_fcopysign_d(DisasContext *ctx, arg_fcopysign_d *a) +{ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + TCGv_i64 fp2 = tcg_temp_new_i64(); + + check_fpu_enabled(ctx); + gen_load_fpr64(ctx, fp0, a->fj); + gen_load_fpr64(ctx, fp1, a->fk); + tcg_gen_deposit_i64(fp2, fp1, fp0, 0, 63); + gen_store_fpr64(ctx, fp2, a->fd); + + tcg_temp_free_i64(fp2); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + return true; +} + +static bool trans_fclass_s(DisasContext *ctx, arg_fclass_s *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FCLASS_S, 0, a->fj, a->fd); + return true; +} + +static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a) +{ + gen_loongarch_fp_arith(ctx, LA_OPC_FCLASS_D, 0, a->fj, a->fd); + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 571ef58..82b255e 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -1345,6 +1345,340 @@ static void gen_crc32(DisasContext *ctx, int rd, int rj, int rk, int sz, tcg_temp_free_i32(tsz); } +/* loongarch floating-point arithmetic */ +static void gen_loongarch_fp_arith(DisasContext *ctx, uint32_t opc, + int fk, int fj, int fd) +{ + check_fpu_enabled(ctx); + switch (opc) { + case LA_OPC_FADD_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_load_fpr32(ctx, fp1, fk); + gen_helper_fp_add_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FADD_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_load_fpr64(ctx, fp1, fk); + gen_helper_fp_add_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FSUB_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_load_fpr32(ctx, fp1, fk); + gen_helper_fp_sub_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FSUB_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_load_fpr64(ctx, fp1, fk); + gen_helper_fp_sub_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FMUL_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_load_fpr32(ctx, fp1, fk); + gen_helper_fp_mul_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FMUL_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_load_fpr64(ctx, fp1, fk); + gen_helper_fp_mul_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FDIV_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_load_fpr32(ctx, fp1, fk); + gen_helper_fp_div_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FDIV_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_load_fpr64(ctx, fp1, fk); + gen_helper_fp_div_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FMAX_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, fj); + gen_load_fpr32(ctx, fp1, fk); + gen_helper_fp_max_s(fp1, cpu_env, fp0, fp1); + gen_store_fpr32(ctx, fp1, fd); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FMAX_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fj); + gen_load_fpr64(ctx, fp1, fk); + gen_helper_fp_max_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FMIN_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, fj); + gen_load_fpr32(ctx, fp1, fk); + gen_helper_fp_min_s(fp2, cpu_env, fp0, fp1); + gen_store_fpr32(ctx, fp2, fd); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FMIN_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fj); + gen_load_fpr64(ctx, fp1, fk); + gen_helper_fp_min_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FMAXA_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, fj); + gen_load_fpr32(ctx, fp1, fk); + gen_helper_fp_maxa_s(fp1, cpu_env, fp0, fp1); + gen_store_fpr32(ctx, fp1, fd); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FMAXA_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fj); + gen_load_fpr64(ctx, fp1, fk); + gen_helper_fp_maxa_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FMINA_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + TCGv_i32 fp1 = tcg_temp_new_i32(); + TCGv_i32 fp2 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, fj); + gen_load_fpr32(ctx, fp1, fk); + gen_helper_fp_mina_s(fp2, cpu_env, fp0, fp1); + gen_store_fpr32(ctx, fp2, fd); + tcg_temp_free_i32(fp2); + tcg_temp_free_i32(fp1); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FMINA_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i64 fp1 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fj); + gen_load_fpr64(ctx, fp1, fk); + gen_helper_fp_mina_d(fp1, cpu_env, fp0, fp1); + gen_store_fpr64(ctx, fp1, fd); + tcg_temp_free_i64(fp1); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FABS_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_abs_s(fp0, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FABS_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_abs_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FNEG_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_neg_s(fp0, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FNEG_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_neg_d(fp0, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FSQRT_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_sqrt_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FSQRT_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_sqrt_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FRECIP_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_recip_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FRECIP_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_recip_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FRSQRT_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_rsqrt_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FRSQRT_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_rsqrt_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FCLASS_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_class_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FCLASS_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_class_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + default: + generate_exception_end(ctx, EXCP_INE); + return; + } +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347801 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 C3FECC49361 for ; Mon, 28 Jun 2021 12:10:56 +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 7660C61C70 for ; Mon, 28 Jun 2021 12:10:56 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7660C61C70 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:42056 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq6J-0003Af-Gm for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:10:55 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51338) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq10-0002pS-CB for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:27 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45580 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0p-0001DN-Nv for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:26 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S16; Mon, 28 Jun 2021 20:05:01 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 14/20] target/loongarch: Add floating point comparison instruction translation Date: Mon, 28 Jun 2021 20:04:39 +0800 Message-Id: <1624881885-31692-15-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S16 X-Coremail-Antispam: 1UD129KBjvdXoW5tr4fXF1xWryfZF15Zry7p5X_Gw15twc_ZF 43XFyUGrs5CFWYga9Fqa4vy343KryDuF4YgFyFq39rCr4UG3yIqr1ktas3uw4UX34rJrWj kF1a9w1vv3WYvjkaLaAFLSUrUUUUnb8apTn2vfkv8UJUUUU8Yxn0WfASr-VFAUDa7-sFnT 9fnUUIcSsGvfJ3UbIYCTnIWIevJa73UjIFyTuYvj4RJUUUUUUUU X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement floating point comparison instruction translation. This includes: - FCMP.cond.{S/D} Signed-off-by: Song Gao --- target/loongarch/fpu_helper.c | 613 ++++++++++++++++++++++++++++++++++++++++++ target/loongarch/helper.h | 49 ++++ target/loongarch/insns.decode | 10 + target/loongarch/trans.inc.c | 15 ++ target/loongarch/translate.c | 90 +++++++ 5 files changed, 777 insertions(+) diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c index d085bb0..2c85113 100644 --- a/target/loongarch/fpu_helper.c +++ b/target/loongarch/fpu_helper.c @@ -379,3 +379,616 @@ uint64_t helper_fp_logb_d(CPULoongArchState *env, uint64_t fp) update_fcsr0(env, GETPC()); return fp1; } + +void helper_movreg2cf_i32(CPULoongArchState *env, uint32_t cd, uint32_t src) +{ + env->active_fpu.cf[cd & 0x7] = src & 0x1; +} + +void helper_movreg2cf_i64(CPULoongArchState *env, uint32_t cd, uint64_t src) +{ + env->active_fpu.cf[cd & 0x7] = src & 0x1; +} + +/* fcmp.cond.s */ +uint32_t helper_fp_cmp_caf_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = (float32_unordered_quiet(fp1, fp, &env->active_fpu.fp_status), 0); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_cun_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered_quiet(fp1, fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_ceq_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_eq_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_cueq_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered_quiet(fp1, fp, &env->active_fpu.fp_status) || + float32_eq_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_clt_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_lt_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_cult_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered_quiet(fp1, fp, &env->active_fpu.fp_status) || + float32_lt_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_cle_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_le_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_cule_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered_quiet(fp1, fp, &env->active_fpu.fp_status) || + float32_le_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_cne_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_lt_quiet(fp1, fp, &env->active_fpu.fp_status) || + float32_lt_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_cor_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_le_quiet(fp1, fp, &env->active_fpu.fp_status) || + float32_le_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_cune_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered_quiet(fp1, fp, &env->active_fpu.fp_status) || + float32_lt_quiet(fp1, fp, &env->active_fpu.fp_status) || + float32_lt_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + + +uint32_t helper_fp_cmp_saf_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = (float32_unordered(fp1, fp, &env->active_fpu.fp_status), 0); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_sun_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered(fp1, fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_seq_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_eq(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_sueq_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered(fp1, fp, &env->active_fpu.fp_status) || + float32_eq(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_slt_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_lt(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_sult_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered(fp1, fp, &env->active_fpu.fp_status) || + float32_lt(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_sle_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_le(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_sule_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered(fp1, fp, &env->active_fpu.fp_status) || + float32_le(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_sne_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_lt(fp1, fp, &env->active_fpu.fp_status) || + float32_lt(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_sor_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_le(fp1, fp, &env->active_fpu.fp_status) || + float32_le(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint32_t helper_fp_cmp_sune_s(CPULoongArchState *env, uint32_t fp, + uint32_t fp1) +{ + uint64_t ret; + ret = float32_unordered(fp1, fp, &env->active_fpu.fp_status) || + float32_lt(fp1, fp, &env->active_fpu.fp_status) || + float32_lt(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +/* fcmp.cond.d */ +uint64_t helper_fp_cmp_caf_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = (float64_unordered_quiet(fp1, fp, &env->active_fpu.fp_status), 0); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_cun_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered_quiet(fp1, fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_ceq_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_eq_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_cueq_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered_quiet(fp1, fp, &env->active_fpu.fp_status) || + float64_eq_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_clt_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_lt_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_cult_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered_quiet(fp1, fp, &env->active_fpu.fp_status) || + float64_lt_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_cle_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_le_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_cule_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered_quiet(fp1, fp, &env->active_fpu.fp_status) || + float64_le_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_cne_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_lt_quiet(fp1, fp, &env->active_fpu.fp_status) || + float64_lt_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_cor_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_le_quiet(fp1, fp, &env->active_fpu.fp_status) || + float64_le_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_cune_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered_quiet(fp1, fp, &env->active_fpu.fp_status) || + float64_lt_quiet(fp1, fp, &env->active_fpu.fp_status) || + float64_lt_quiet(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_saf_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = (float64_unordered(fp1, fp, &env->active_fpu.fp_status), 0); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_sun_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered(fp1, fp, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_seq_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_eq(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_sueq_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered(fp1, fp, &env->active_fpu.fp_status) || + float64_eq(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_slt_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_lt(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_sult_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered(fp1, fp, &env->active_fpu.fp_status) || + float64_lt(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_sle_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_le(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_sule_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered(fp1, fp, &env->active_fpu.fp_status) || + float64_le(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_sne_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_lt(fp1, fp, &env->active_fpu.fp_status) || + float64_lt(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_sor_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_le(fp1, fp, &env->active_fpu.fp_status) || + float64_le(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} + +uint64_t helper_fp_cmp_sune_d(CPULoongArchState *env, uint64_t fp, + uint64_t fp1) +{ + uint64_t ret; + ret = float64_unordered(fp1, fp, &env->active_fpu.fp_status) || + float64_lt(fp1, fp, &env->active_fpu.fp_status) || + float64_lt(fp, fp1, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + if (ret) { + return -1; + } else { + return 0; + } +} diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index e945177..b1a81c5 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -72,3 +72,52 @@ DEF_HELPER_2(fp_recip_d, i64, env, i64) DEF_HELPER_FLAGS_2(fp_class_s, TCG_CALL_NO_RWG_SE, i32, env, i32) DEF_HELPER_FLAGS_2(fp_class_d, TCG_CALL_NO_RWG_SE, i64, env, i64) + +/* fcmp.cond.s/d */ +DEF_HELPER_3(fp_cmp_caf_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_caf_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_cun_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_cun_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_ceq_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_ceq_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_cueq_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_cueq_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_clt_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_clt_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_cult_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_cult_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_cle_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_cle_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_cule_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_cule_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_cne_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_cne_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_cor_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_cor_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_cune_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_cune_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_saf_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_saf_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_sun_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_sun_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_seq_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_seq_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_sueq_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_sueq_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_slt_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_slt_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_sult_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_sult_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_sle_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_sle_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_sule_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_sule_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_sne_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_sne_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_sor_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_sor_s, i32, env, i32, i32) +DEF_HELPER_3(fp_cmp_sune_d, i64, env, i64, i64) +DEF_HELPER_3(fp_cmp_sune_s, i32, env, i32, i32) + +DEF_HELPER_3(movreg2cf_i32, void, env, i32, i32) +DEF_HELPER_3(movreg2cf_i64, void, env, i32, i64) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 8730725..7bf4f0f 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -32,6 +32,8 @@ %fj 5:5 %fk 10:5 %fa 15:5 +%cd 0:3 +%fcond 15:5 # # Argument sets @@ -57,6 +59,7 @@ &fmt_fdfjfk fd fj fk &fmt_fdfjfkfa fd fj fk fa &fmt_fdfj fd fj +&fmt_cdfjfkfcond cd fj fk fcond # # Formats @@ -82,6 +85,7 @@ @fmt_fdfjfk .... ........ ..... ..... ..... ..... &fmt_fdfjfk %fd %fj %fk @fmt_fdfjfkfa .... ........ ..... ..... ..... ..... &fmt_fdfjfkfa %fd %fj %fk %fa @fmt_fdfj .... ........ ..... ..... ..... ..... &fmt_fdfj %fd %fj +@fmt_cdfjfkfcond .... ........ ..... ..... ..... .. ... &fmt_cdfjfkfcond %cd %fj %fk %fcond # # Fixed point arithmetic operation instruction @@ -344,3 +348,9 @@ fcopysign_s 0000 00010001 00101 ..... ..... ..... @fmt_fdfjfk fcopysign_d 0000 00010001 00110 ..... ..... ..... @fmt_fdfjfk fclass_s 0000 00010001 01000 01101 ..... ..... @fmt_fdfj fclass_d 0000 00010001 01000 01110 ..... ..... @fmt_fdfj + +# +# Floating point compare instruction +# +fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @fmt_cdfjfkfcond +fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @fmt_cdfjfkfcond diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index cd82155..fab2805 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -1871,3 +1871,18 @@ static bool trans_fclass_d(DisasContext *ctx, arg_fclass_d *a) gen_loongarch_fp_arith(ctx, LA_OPC_FCLASS_D, 0, a->fj, a->fd); return true; } + +/* Floating point compare instruction translation */ +static bool trans_fcmp_cond_s(DisasContext *ctx, arg_fcmp_cond_s *a) +{ + check_fpu_enabled(ctx); + gen_loongarch_fp_cmp_s(ctx, a->fcond, a->fk, a->fj, a->cd); + return true; +} + +static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) +{ + check_fpu_enabled(ctx); + gen_loongarch_fp_cmp_d(ctx, a->fcond, a->fk, a->fj, a->cd); + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 82b255e..4e7b687 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -1679,6 +1679,96 @@ static void gen_loongarch_fp_arith(DisasContext *ctx, uint32_t opc, } } +#define FP_CMP(fmt, bits, STORE) \ +static inline void gen_loongarch_fp_cmp_ ## fmt(DisasContext *ctx, int fcond, \ + int fk, int fj, int cd) \ +{ \ + TCGv_i ## bits fp0 = tcg_temp_new_i ## bits(); \ + TCGv_i ## bits fp1 = tcg_temp_new_i ## bits(); \ + TCGv_i32 fcc = tcg_const_i32(cd); \ + check_fpu_enabled(ctx); \ + gen_load_fpr ## bits(ctx, fp0, fj); \ + gen_load_fpr ## bits(ctx, fp1, fk); \ + switch (fcond) { \ + case 0: \ + gen_helper_fp_cmp_caf_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 1: \ + gen_helper_fp_cmp_saf_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 2: \ + gen_helper_fp_cmp_clt_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 3: \ + gen_helper_fp_cmp_slt_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 4: \ + gen_helper_fp_cmp_ceq_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 5: \ + gen_helper_fp_cmp_seq_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 6: \ + gen_helper_fp_cmp_cle_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 7: \ + gen_helper_fp_cmp_sle_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 8: \ + gen_helper_fp_cmp_cun_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 9: \ + gen_helper_fp_cmp_sun_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 10: \ + gen_helper_fp_cmp_cult_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 11: \ + gen_helper_fp_cmp_sult_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 12: \ + gen_helper_fp_cmp_cueq_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 13: \ + gen_helper_fp_cmp_sueq_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 14: \ + gen_helper_fp_cmp_cule_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 15: \ + gen_helper_fp_cmp_sule_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 16: \ + gen_helper_fp_cmp_cne_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 17: \ + gen_helper_fp_cmp_sne_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 20: \ + gen_helper_fp_cmp_cor_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 21: \ + gen_helper_fp_cmp_sor_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 24: \ + gen_helper_fp_cmp_cune_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + case 25: \ + gen_helper_fp_cmp_sune_ ## fmt(fp0, cpu_env, fp0, fp1); \ + break; \ + default: \ + abort(); \ + } \ + STORE; \ + tcg_temp_free_i ## bits(fp0); \ + tcg_temp_free_i ## bits(fp1); \ + tcg_temp_free_i32(fcc); \ +} + +FP_CMP(d, 64, gen_helper_movreg2cf_i64(cpu_env, fcc, fp0)) +FP_CMP(s, 32, gen_helper_movreg2cf_i32(cpu_env, fcc, fp0)) +#undef FP_CMP + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347785 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 2CCB4C2B9F4 for ; Mon, 28 Jun 2021 12:07:19 +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 B7BAA61C71 for ; Mon, 28 Jun 2021 12:07:18 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B7BAA61C71 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:33478 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq2n-0005jY-P1 for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:07:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51306) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0w-0002ku-JQ for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:22 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45596 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0p-0001DT-O4 for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:22 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S17; Mon, 28 Jun 2021 20:05:02 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 15/20] target/loongarch: Add floating point conversion instruction translation Date: Mon, 28 Jun 2021 20:04:40 +0800 Message-Id: <1624881885-31692-16-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S17 X-Coremail-Antispam: 1UD129KBjvAXoWfKr4rZFW7Aw1kWrWfJFy5Arb_yoW5CF1kCo WUuF15Aw4rGw47urZYkws8Xw4IqryDCF4fGr9Iv34kWFn7Cr4UKFyfWrn5AayftrWFvrW5 XF9ayFn3Aw13Ar93n29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement floating point conversion instruction translation. This includes: - FCVT.S.D, FCVT.D.S - FFINT.{S/D}.{W/L}, FTINT.{W/L}.{S/D} - FTINT{RM/RP/RZ/RNE}.{W/L}.{S/D} - FRINT.{S/D} Signed-off-by: Song Gao --- target/loongarch/fpu_helper.c | 362 ++++++++++++++++++++++++++++++++++++++++++ target/loongarch/helper.h | 29 ++++ target/loongarch/insns.decode | 32 ++++ target/loongarch/instmap.h | 29 ++++ target/loongarch/trans.inc.c | 169 ++++++++++++++++++++ target/loongarch/translate.c | 318 +++++++++++++++++++++++++++++++++++++ 6 files changed, 939 insertions(+) diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c index 2c85113..e72fbc4 100644 --- a/target/loongarch/fpu_helper.c +++ b/target/loongarch/fpu_helper.c @@ -992,3 +992,365 @@ uint64_t helper_fp_cmp_sune_d(CPULoongArchState *env, uint64_t fp, return 0; } } + +/* floating point conversion */ +uint64_t helper_fp_cvt_d_s(CPULoongArchState *env, uint32_t src) +{ + uint64_t dest; + + dest = float32_to_float64(src, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_fint_d_w(CPULoongArchState *env, uint32_t src) +{ + uint64_t dest; + + dest = int32_to_float64(src, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_fint_d_l(CPULoongArchState *env, uint64_t src) +{ + uint64_t dest; + + dest = int64_to_float64(src, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_cvt_s_d(CPULoongArchState *env, uint64_t src) +{ + uint32_t dest; + + dest = float64_to_float32(src, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_fint_s_w(CPULoongArchState *env, uint32_t src) +{ + uint32_t dest; + + dest = int32_to_float32(src, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_fint_s_l(CPULoongArchState *env, uint64_t src) +{ + uint32_t dest; + + dest = int64_to_float32(src, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tintrm_l_d(CPULoongArchState *env, uint64_t src) +{ + uint64_t dest; + + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + dest = float64_to_int64(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tintrm_l_s(CPULoongArchState *env, uint32_t src) +{ + uint64_t dest; + + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + dest = float32_to_int64(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tintrm_w_d(CPULoongArchState *env, uint64_t src) +{ + uint32_t dest; + + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + dest = float64_to_int32(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tintrm_w_s(CPULoongArchState *env, uint32_t src) +{ + uint32_t dest; + + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + dest = float32_to_int32(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tintrp_l_d(CPULoongArchState *env, uint64_t src) +{ + uint64_t dest; + + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + dest = float64_to_int64(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tintrp_l_s(CPULoongArchState *env, uint32_t src) +{ + uint64_t dest; + + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + dest = float32_to_int64(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tintrp_w_d(CPULoongArchState *env, uint64_t src) +{ + uint32_t dest; + + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + dest = float64_to_int32(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tintrp_w_s(CPULoongArchState *env, uint32_t src) +{ + uint32_t dest; + + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + dest = float32_to_int32(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tintrz_l_d(CPULoongArchState *env, uint64_t src) +{ + uint64_t dest; + + dest = float64_to_int64_round_to_zero(src, + &env->active_fpu.fp_status); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tintrz_l_s(CPULoongArchState *env, uint32_t src) +{ + uint64_t dest; + + dest = float32_to_int64_round_to_zero(src, &env->active_fpu.fp_status); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tintrz_w_d(CPULoongArchState *env, uint64_t src) +{ + uint32_t dest; + + dest = float64_to_int32_round_to_zero(src, &env->active_fpu.fp_status); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tintrz_w_s(CPULoongArchState *env, uint32_t src) +{ + uint32_t dest; + + dest = float32_to_int32_round_to_zero(src, &env->active_fpu.fp_status); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tintrne_l_d(CPULoongArchState *env, uint64_t src) +{ + uint64_t dest; + + set_float_rounding_mode(float_round_nearest_even, + &env->active_fpu.fp_status); + dest = float64_to_int64(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tintrne_l_s(CPULoongArchState *env, uint32_t src) +{ + uint64_t dest; + + set_float_rounding_mode(float_round_nearest_even, + &env->active_fpu.fp_status); + dest = float32_to_int64(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tintrne_w_d(CPULoongArchState *env, uint64_t src) +{ + uint32_t dest; + + set_float_rounding_mode(float_round_nearest_even, + &env->active_fpu.fp_status); + dest = float64_to_int32(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tintrne_w_s(CPULoongArchState *env, uint32_t src) +{ + uint32_t dest; + + set_float_rounding_mode(float_round_nearest_even, + &env->active_fpu.fp_status); + dest = float32_to_int32(src, &env->active_fpu.fp_status); + restore_rounding_mode(env); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tint_l_d(CPULoongArchState *env, uint64_t src) +{ + uint64_t dest; + + dest = float64_to_int64(src, &env->active_fpu.fp_status); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_tint_l_s(CPULoongArchState *env, uint32_t src) +{ + uint64_t dest; + + dest = float32_to_int64(src, &env->active_fpu.fp_status); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT64_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tint_w_s(CPULoongArchState *env, uint32_t src) +{ + uint32_t dest; + + dest = float32_to_int32(src, &env->active_fpu.fp_status); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_tint_w_d(CPULoongArchState *env, uint64_t src) +{ + uint32_t dest; + + dest = float64_to_int32(src, &env->active_fpu.fp_status); + if (get_float_exception_flags(&env->active_fpu.fp_status) + & (float_flag_invalid | float_flag_overflow)) { + dest = FP_TO_INT32_OVERFLOW; + } + update_fcsr0(env, GETPC()); + return dest; +} + +uint32_t helper_fp_rint_s(CPULoongArchState *env, uint32_t src) +{ + uint32_t dest; + + dest = float32_round_to_int(src, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return dest; +} + +uint64_t helper_fp_rint_d(CPULoongArchState *env, uint64_t src) +{ + uint64_t dest; + + dest = float64_round_to_int(src, &env->active_fpu.fp_status); + update_fcsr0(env, GETPC()); + return dest; +} diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index b1a81c5..9ec2b53 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -69,6 +69,8 @@ DEF_HELPER_2(fp_rsqrt_s, i32, env, i32) DEF_HELPER_2(fp_rsqrt_d, i64, env, i64) DEF_HELPER_2(fp_recip_s, i32, env, i32) DEF_HELPER_2(fp_recip_d, i64, env, i64) +DEF_HELPER_2(fp_rint_s, i32, env, i32) +DEF_HELPER_2(fp_rint_d, i64, env, i64) DEF_HELPER_FLAGS_2(fp_class_s, TCG_CALL_NO_RWG_SE, i32, env, i32) DEF_HELPER_FLAGS_2(fp_class_d, TCG_CALL_NO_RWG_SE, i64, env, i64) @@ -121,3 +123,30 @@ DEF_HELPER_3(fp_cmp_sune_s, i32, env, i32, i32) DEF_HELPER_3(movreg2cf_i32, void, env, i32, i32) DEF_HELPER_3(movreg2cf_i64, void, env, i32, i64) + +DEF_HELPER_2(fp_cvt_d_s, i64, env, i32) +DEF_HELPER_2(fp_cvt_s_d, i32, env, i64) +DEF_HELPER_2(fp_fint_d_w, i64, env, i32) +DEF_HELPER_2(fp_fint_d_l, i64, env, i64) +DEF_HELPER_2(fp_fint_s_w, i32, env, i32) +DEF_HELPER_2(fp_fint_s_l, i32, env, i64) +DEF_HELPER_2(fp_tintrm_l_s, i64, env, i32) +DEF_HELPER_2(fp_tintrm_l_d, i64, env, i64) +DEF_HELPER_2(fp_tintrm_w_s, i32, env, i32) +DEF_HELPER_2(fp_tintrm_w_d, i32, env, i64) +DEF_HELPER_2(fp_tintrp_l_s, i64, env, i32) +DEF_HELPER_2(fp_tintrp_l_d, i64, env, i64) +DEF_HELPER_2(fp_tintrp_w_s, i32, env, i32) +DEF_HELPER_2(fp_tintrp_w_d, i32, env, i64) +DEF_HELPER_2(fp_tintrz_l_s, i64, env, i32) +DEF_HELPER_2(fp_tintrz_l_d, i64, env, i64) +DEF_HELPER_2(fp_tintrz_w_s, i32, env, i32) +DEF_HELPER_2(fp_tintrz_w_d, i32, env, i64) +DEF_HELPER_2(fp_tintrne_l_s, i64, env, i32) +DEF_HELPER_2(fp_tintrne_l_d, i64, env, i64) +DEF_HELPER_2(fp_tintrne_w_s, i32, env, i32) +DEF_HELPER_2(fp_tintrne_w_d, i32, env, i64) +DEF_HELPER_2(fp_tint_l_s, i64, env, i32) +DEF_HELPER_2(fp_tint_l_d, i64, env, i64) +DEF_HELPER_2(fp_tint_w_s, i32, env, i32) +DEF_HELPER_2(fp_tint_w_d, i32, env, i64) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 7bf4f0f..86ba7ea 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -354,3 +354,35 @@ fclass_d 0000 00010001 01000 01110 ..... ..... @fmt_fdfj # fcmp_cond_s 0000 11000001 ..... ..... ..... 00 ... @fmt_cdfjfkfcond fcmp_cond_d 0000 11000010 ..... ..... ..... 00 ... @fmt_cdfjfkfcond + +# +# Floating point conversion instruction +# +fcvt_s_d 0000 00010001 10010 00110 ..... ..... @fmt_fdfj +fcvt_d_s 0000 00010001 10010 01001 ..... ..... @fmt_fdfj +ftintrm_w_s 0000 00010001 10100 00001 ..... ..... @fmt_fdfj +ftintrm_w_d 0000 00010001 10100 00010 ..... ..... @fmt_fdfj +ftintrm_l_s 0000 00010001 10100 01001 ..... ..... @fmt_fdfj +ftintrm_l_d 0000 00010001 10100 01010 ..... ..... @fmt_fdfj +ftintrp_w_s 0000 00010001 10100 10001 ..... ..... @fmt_fdfj +ftintrp_w_d 0000 00010001 10100 10010 ..... ..... @fmt_fdfj +ftintrp_l_s 0000 00010001 10100 11001 ..... ..... @fmt_fdfj +ftintrp_l_d 0000 00010001 10100 11010 ..... ..... @fmt_fdfj +ftintrz_w_s 0000 00010001 10101 00001 ..... ..... @fmt_fdfj +ftintrz_w_d 0000 00010001 10101 00010 ..... ..... @fmt_fdfj +ftintrz_l_s 0000 00010001 10101 01001 ..... ..... @fmt_fdfj +ftintrz_l_d 0000 00010001 10101 01010 ..... ..... @fmt_fdfj +ftintrne_w_s 0000 00010001 10101 10001 ..... ..... @fmt_fdfj +ftintrne_w_d 0000 00010001 10101 10010 ..... ..... @fmt_fdfj +ftintrne_l_s 0000 00010001 10101 11001 ..... ..... @fmt_fdfj +ftintrne_l_d 0000 00010001 10101 11010 ..... ..... @fmt_fdfj +ftint_w_s 0000 00010001 10110 00001 ..... ..... @fmt_fdfj +ftint_w_d 0000 00010001 10110 00010 ..... ..... @fmt_fdfj +ftint_l_s 0000 00010001 10110 01001 ..... ..... @fmt_fdfj +ftint_l_d 0000 00010001 10110 01010 ..... ..... @fmt_fdfj +ffint_s_w 0000 00010001 11010 00100 ..... ..... @fmt_fdfj +ffint_s_l 0000 00010001 11010 00110 ..... ..... @fmt_fdfj +ffint_d_w 0000 00010001 11010 01000 ..... ..... @fmt_fdfj +ffint_d_l 0000 00010001 11010 01010 ..... ..... @fmt_fdfj +frint_s 0000 00010001 11100 10001 ..... ..... @fmt_fdfj +frint_d 0000 00010001 11100 10010 ..... ..... @fmt_fdfj diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h index f562e32..2f231c2 100644 --- a/target/loongarch/instmap.h +++ b/target/loongarch/instmap.h @@ -81,6 +81,35 @@ enum { LA_OPC_FRECIP_D = (0x004516 << 10), LA_OPC_FRSQRT_S = (0x004519 << 10), LA_OPC_FRSQRT_D = (0x00451A << 10), + LA_OPC_FCVT_S_D = (0x004646 << 10), + LA_OPC_FCVT_D_S = (0x004649 << 10), + LA_OPC_FTINTRM_W_S = (0x004681 << 10), + LA_OPC_FTINTRM_W_D = (0x004682 << 10), + LA_OPC_FTINTRM_L_S = (0x004689 << 10), + LA_OPC_FTINTRM_L_D = (0x00468A << 10), + LA_OPC_FTINTRP_W_S = (0x004691 << 10), + LA_OPC_FTINTRP_W_D = (0x004692 << 10), + LA_OPC_FTINTRP_L_S = (0x004699 << 10), + LA_OPC_FTINTRP_L_D = (0x00469A << 10), + LA_OPC_FTINTRZ_W_S = (0x0046A1 << 10), + LA_OPC_FTINTRZ_W_D = (0x0046A2 << 10), + LA_OPC_FTINTRZ_L_S = (0x0046A9 << 10), + LA_OPC_FTINTRZ_L_D = (0x0046AA << 10), + LA_OPC_FTINTRNE_W_S = (0x0046B1 << 10), + LA_OPC_FTINTRNE_W_D = (0x0046B2 << 10), + LA_OPC_FTINTRNE_L_S = (0x0046B9 << 10), + LA_OPC_FTINTRNE_L_D = (0x0046BA << 10), + LA_OPC_FTINT_W_S = (0x0046C1 << 10), + LA_OPC_FTINT_W_D = (0x0046C2 << 10), + LA_OPC_FTINT_L_S = (0x0046C9 << 10), + LA_OPC_FTINT_L_D = (0x0046CA << 10), + LA_OPC_FFINT_S_W = (0x004744 << 10), + LA_OPC_FFINT_S_L = (0x004746 << 10), + LA_OPC_FFINT_D_W = (0x004748 << 10), + LA_OPC_FFINT_D_L = (0x00474A << 10), + LA_OPC_FRINT_S = (0x004791 << 10), + LA_OPC_FRINT_D = (0x004792 << 10), + LA_OPC_FADD_S = (0x00201 << 15), LA_OPC_FADD_D = (0x00202 << 15), LA_OPC_FSUB_S = (0x00205 << 15), diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index fab2805..095e9d2 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -1886,3 +1886,172 @@ static bool trans_fcmp_cond_d(DisasContext *ctx, arg_fcmp_cond_d *a) gen_loongarch_fp_cmp_d(ctx, a->fcond, a->fk, a->fj, a->cd); return true; } + +/* Floating point conversion instruction */ +static bool trans_fcvt_s_d(DisasContext *ctx, arg_fcvt_s_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FCVT_S_D, a->fj, a->fd); + return true; +} + +static bool trans_fcvt_d_s(DisasContext *ctx, arg_fcvt_d_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FCVT_D_S, a->fj, a->fd); + return true; +} + +static bool trans_ftintrm_w_s(DisasContext *ctx, arg_ftintrm_l_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRM_W_S, a->fj, a->fd); + return true; +} + +static bool trans_ftintrm_w_d(DisasContext *ctx, arg_ftintrm_l_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRM_W_D, a->fj, a->fd); + return true; +} + +static bool trans_ftintrm_l_s(DisasContext *ctx, arg_ftintrm_l_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRM_L_S, a->fj, a->fd); + return true; +} + +static bool trans_ftintrm_l_d(DisasContext *ctx, arg_ftintrm_l_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRM_L_D, a->fj, a->fd); + return true; +} + +static bool trans_ftintrp_w_s(DisasContext *ctx, arg_ftintrp_w_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRP_W_S, a->fj, a->fd); + return true; +} + +static bool trans_ftintrp_w_d(DisasContext *ctx, arg_ftintrp_w_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRP_W_D, a->fj, a->fd); + return true; +} + +static bool trans_ftintrp_l_s(DisasContext *ctx, arg_ftintrp_l_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRP_L_S, a->fj, a->fd); + return true; +} + +static bool trans_ftintrp_l_d(DisasContext *ctx, arg_ftintrp_l_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRP_L_D, a->fj, a->fd); + return true; +} + +static bool trans_ftintrz_w_s(DisasContext *ctx, arg_ftintrz_w_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRZ_W_S, a->fj, a->fd); + return true; +} + +static bool trans_ftintrz_w_d(DisasContext *ctx, arg_ftintrz_w_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRZ_W_D, a->fj, a->fd); + return true; +} + +static bool trans_ftintrz_l_s(DisasContext *ctx, arg_ftintrz_l_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRZ_L_S, a->fj, a->fd); + return true; +} + +static bool trans_ftintrz_l_d(DisasContext *ctx, arg_ftintrz_l_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRZ_L_D, a->fj, a->fd); + return true; +} + +static bool trans_ftintrne_w_s(DisasContext *ctx, arg_ftintrne_w_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRNE_W_S, a->fj, a->fd); + return true; +} + +static bool trans_ftintrne_w_d(DisasContext *ctx, arg_ftintrne_w_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRNE_W_D, a->fj, a->fd); + return true; +} + +static bool trans_ftintrne_l_s(DisasContext *ctx, arg_ftintrne_l_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRNE_L_S, a->fj, a->fd); + return true; +} + +static bool trans_ftintrne_l_d(DisasContext *ctx, arg_ftintrne_l_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINTRNE_L_D, a->fj, a->fd); + return true; +} + +static bool trans_ftint_w_s(DisasContext *ctx, arg_ftint_w_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINT_W_S, a->fj, a->fd); + return true; +} + +static bool trans_ftint_w_d(DisasContext *ctx, arg_ftint_w_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINT_W_D, a->fj, a->fd); + return true; +} + +static bool trans_ftint_l_s(DisasContext *ctx, arg_ftint_l_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINT_L_S, a->fj, a->fd); + return true; +} + +static bool trans_ftint_l_d(DisasContext *ctx, arg_ftint_l_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FTINT_L_D, a->fj, a->fd); + return true; +} + +static bool trans_ffint_s_w(DisasContext *ctx, arg_ffint_s_w *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FFINT_S_W, a->fj, a->fd); + return true; +} + +static bool trans_ffint_s_l(DisasContext *ctx, arg_ffint_s_l *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FFINT_S_L, a->fj, a->fd); + return true; +} + +static bool trans_ffint_d_w(DisasContext *ctx, arg_ffint_d_w *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FFINT_D_W, a->fj, a->fd); + return true; +} + +static bool trans_ffint_d_l(DisasContext *ctx, arg_ffint_d_l *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FFINT_D_L, a->fj, a->fd); + return true; +} + +static bool trans_frint_s(DisasContext *ctx, arg_frint_s *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FRINT_S, a->fj, a->fd); + return true; +} + +static bool trans_frint_d(DisasContext *ctx, arg_frint_d *a) +{ + gen_loongarch_fp_conv(ctx, LA_OPC_FRINT_D, a->fj, a->fd); + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 4e7b687..52faf73 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -1769,6 +1769,324 @@ FP_CMP(d, 64, gen_helper_movreg2cf_i64(cpu_env, fcc, fp0)) FP_CMP(s, 32, gen_helper_movreg2cf_i32(cpu_env, fcc, fp0)) #undef FP_CMP +/* loongarch floating-point conversion */ +static void gen_loongarch_fp_conv(DisasContext *ctx, uint32_t opc, + int fj, int fd) +{ + check_fpu_enabled(ctx); + switch (opc) { + case LA_OPC_FCVT_S_D: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fj); + gen_helper_fp_cvt_s_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(ctx, fp32, fd); + tcg_temp_free_i32(fp32); + } + break; + case LA_OPC_FCVT_D_S: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(ctx, fp32, fj); + gen_helper_fp_cvt_d_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } + break; + case LA_OPC_FTINTRM_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_tintrm_w_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FTINTRM_W_D: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fj); + gen_helper_fp_tintrm_w_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(ctx, fp32, fd); + tcg_temp_free_i32(fp32); + } + break; + case LA_OPC_FTINTRM_L_S: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(ctx, fp32, fj); + gen_helper_fp_tintrm_l_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } + break; + case LA_OPC_FTINTRM_L_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_tintrm_l_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FTINTRP_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_tintrp_w_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FTINTRP_W_D: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fj); + gen_helper_fp_tintrp_w_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(ctx, fp32, fd); + tcg_temp_free_i32(fp32); + } + break; + case LA_OPC_FTINTRP_L_S: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(ctx, fp32, fj); + gen_helper_fp_tintrp_l_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } + break; + case LA_OPC_FTINTRP_L_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_tintrp_l_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FTINTRZ_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_tintrz_w_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FTINTRZ_W_D: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fj); + gen_helper_fp_tintrz_w_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(ctx, fp32, fd); + tcg_temp_free_i32(fp32); + } + break; + case LA_OPC_FTINTRZ_L_S: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(ctx, fp32, fj); + gen_helper_fp_tintrz_l_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } + break; + case LA_OPC_FTINTRZ_L_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_tintrz_l_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FTINTRNE_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_tintrne_w_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FTINTRNE_W_D: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fj); + gen_helper_fp_tintrne_w_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(ctx, fp32, fd); + tcg_temp_free_i32(fp32); + } + break; + case LA_OPC_FTINTRNE_L_S: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(ctx, fp32, fj); + gen_helper_fp_tintrne_l_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } + break; + case LA_OPC_FTINTRNE_L_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_tintrne_l_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FTINT_W_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_tint_w_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FTINT_W_D: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fj); + gen_helper_fp_tint_w_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(ctx, fp32, fd); + tcg_temp_free_i32(fp32); + } + break; + case LA_OPC_FTINT_L_S: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(ctx, fp32, fj); + gen_helper_fp_tint_l_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } + break; + case LA_OPC_FTINT_L_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_tint_l_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FFINT_S_W: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_fint_s_w(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FFINT_S_L: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fj); + gen_helper_fp_fint_s_l(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(ctx, fp32, fd); + tcg_temp_free_i32(fp32); + } + break; + case LA_OPC_FFINT_D_W: + { + TCGv_i32 fp32 = tcg_temp_new_i32(); + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(ctx, fp32, fj); + gen_helper_fp_fint_d_w(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); + } + break; + case LA_OPC_FFINT_D_L: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_fint_d_l(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FRINT_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, fj); + gen_helper_fp_rint_s(fp0, cpu_env, fp0); + gen_store_fpr32(ctx, fp0, fd); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FRINT_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fj); + gen_helper_fp_rint_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } + break; + default: + generate_exception_end(ctx, EXCP_INE); + return; + } +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347853 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 8F17FC2B9F4 for ; Mon, 28 Jun 2021 12:21:32 +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 2FCF761584 for ; Mon, 28 Jun 2021 12:21:32 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2FCF761584 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:42056 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqGZ-0006P4-A1 for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:21:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51320) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0x-0002lp-Mw for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:24 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45626 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0s-0001Er-Ck for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:23 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S18; Mon, 28 Jun 2021 20:05:03 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 16/20] target/loongarch: Add floating point move instruction translation Date: Mon, 28 Jun 2021 20:04:41 +0800 Message-Id: <1624881885-31692-17-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S18 X-Coremail-Antispam: 1UD129KBjvAXoW3tF4Dtw43JFW8Gr45Cw48WFg_yoW8Jw1xGo WUAa45AF48Gw13WrnI9ws8X3y2qr1UCFs7Jr9Y9a4kWFs7Gr47KF1UW3Z5Aa1fXrWvgrW5 JFyaqFn3tw43Gr95n29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement floationg point move instruction translation. This includes: - FMOV.{S/D} - FSEL - MOVGR2FR.{W/D}, MOVGR2FRH.W - MOVFR2GR.{S/D}, MOVFRH2GR.S - MOVGR2FCSR, MOVFCSR2GR - MOVFR2CF, MOVCF2FR - MOVGR2CF, MOVCF2GR Signed-off-by: Song Gao --- target/loongarch/fpu_helper.c | 80 ++++++++++++++++++++++ target/loongarch/helper.h | 6 ++ target/loongarch/insns.decode | 41 +++++++++++ target/loongarch/instmap.h | 6 ++ target/loongarch/trans.inc.c | 154 ++++++++++++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 60 ++++++++++++++++ 6 files changed, 347 insertions(+) diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c index e72fbc4..ddeae72 100644 --- a/target/loongarch/fpu_helper.c +++ b/target/loongarch/fpu_helper.c @@ -380,6 +380,11 @@ uint64_t helper_fp_logb_d(CPULoongArchState *env, uint64_t fp) return fp1; } +void helper_movreg2cf(CPULoongArchState *env, uint32_t cd, target_ulong src) +{ + env->active_fpu.cf[cd & 0x7] = src & 0x1; +} + void helper_movreg2cf_i32(CPULoongArchState *env, uint32_t cd, uint32_t src) { env->active_fpu.cf[cd & 0x7] = src & 0x1; @@ -1354,3 +1359,78 @@ uint64_t helper_fp_rint_d(CPULoongArchState *env, uint64_t src) update_fcsr0(env, GETPC()); return dest; } + +target_ulong helper_fsel(CPULoongArchState *env, target_ulong fj, + target_ulong fk, uint32_t ca) +{ + if (env->active_fpu.cf[ca & 0x7]) { + return fk; + } else { + return fj; + } +} + +void helper_movgr2fcsr(CPULoongArchState *env, target_ulong arg1, + uint32_t fcsr) +{ + switch (fcsr) { + case 0: + env->active_fpu.fcsr0 = arg1; + break; + case 1: + env->active_fpu.fcsr0 = (arg1 & FCSR0_M1) | + (env->active_fpu.fcsr0 & ~FCSR0_M1); + break; + case 2: + env->active_fpu.fcsr0 = (arg1 & FCSR0_M2) | + (env->active_fpu.fcsr0 & ~FCSR0_M2); + break; + case 3: + env->active_fpu.fcsr0 = (arg1 & FCSR0_M3) | + (env->active_fpu.fcsr0 & ~FCSR0_M3); + break; + case 16: + env->active_fpu.vcsr16 = arg1; + break; + default: + printf("%s: warning, fcsr '%d' not supported\n", __func__, fcsr); + assert(0); + break; + } + restore_fp_status(env); + set_float_exception_flags(0, &env->active_fpu.fp_status); +} + +target_ulong helper_movfcsr2gr(CPULoongArchState *env, uint32_t reg) +{ + target_ulong r = 0; + + switch (reg) { + case 0: + r = (uint32_t)env->active_fpu.fcsr0; + break; + case 1: + r = (env->active_fpu.fcsr0 & FCSR0_M1); + break; + case 2: + r = (env->active_fpu.fcsr0 & FCSR0_M2); + break; + case 3: + r = (env->active_fpu.fcsr0 & FCSR0_M3); + break; + case 16: + r = (uint32_t)env->active_fpu.vcsr16; + break; + default: + printf("%s: warning, fcsr '%d' not supported\n", __func__, reg); + assert(0); + break; + } + + return r; +} + +target_ulong helper_movcf2reg(CPULoongArchState *env, uint32_t cj) +{ + return (target_ulong)env->active_fpu.cf[cj & 0x7]; +} diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 9ec2b53..eedf174 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -150,3 +150,9 @@ DEF_HELPER_2(fp_tint_l_s, i64, env, i32) DEF_HELPER_2(fp_tint_l_d, i64, env, i64) DEF_HELPER_2(fp_tint_w_s, i32, env, i32) DEF_HELPER_2(fp_tint_w_d, i32, env, i64) + +DEF_HELPER_4(fsel, i64, env, i64, i64, i32) +DEF_HELPER_3(movreg2cf, void, env, i32, tl) +DEF_HELPER_2(movcf2reg, tl, env, i32) +DEF_HELPER_2(movfcsr2gr, tl, env, i32) +DEF_HELPER_3(movgr2fcsr, void, env, tl, i32) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index 86ba7ea..a9d8530 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -34,6 +34,10 @@ %fa 15:5 %cd 0:3 %fcond 15:5 +%cj 5:3 +%ca 15:3 +%fcsrd 0:5 +%fcsrs 5:5 # # Argument sets @@ -60,6 +64,15 @@ &fmt_fdfjfkfa fd fj fk fa &fmt_fdfj fd fj &fmt_cdfjfkfcond cd fj fk fcond +&fmt_fdfjfkca fd fj fk ca +&fmt_fdrj fd rj +&fmt_rdfj rd fj +&fmt_fcsrdrj fcsrd rj +&fmt_rdfcsrs rd fcsrs +&fmt_cdfj cd fj +&fmt_fdcj fd cj +&fmt_cdrj cd rj +&fmt_rdcj rd cj # # Formats @@ -86,6 +99,15 @@ @fmt_fdfjfkfa .... ........ ..... ..... ..... ..... &fmt_fdfjfkfa %fd %fj %fk %fa @fmt_fdfj .... ........ ..... ..... ..... ..... &fmt_fdfj %fd %fj @fmt_cdfjfkfcond .... ........ ..... ..... ..... .. ... &fmt_cdfjfkfcond %cd %fj %fk %fcond +@fmt_fdfjfkca .... ........ .. ... ..... ..... ..... &fmt_fdfjfkca %fd %fj %fk %ca +@fmt_fdrj .... ........ ..... ..... ..... ..... &fmt_fdrj %fd %rj +@fmt_rdfj .... ........ ..... ..... ..... ..... &fmt_rdfj %rd %fj +@fmt_fcsrdrj .... ........ ..... ..... ..... ..... &fmt_fcsrdrj %fcsrd %rj +@fmt_rdfcsrs .... ........ ..... ..... ..... ..... &fmt_rdfcsrs %rd %fcsrs +@fmt_cdfj .... ........ ..... ..... ..... .. ... &fmt_cdfj %cd %fj +@fmt_fdcj .... ........ ..... ..... .. ... ..... &fmt_fdcj %fd %cj +@fmt_cdrj .... ........ ..... ..... ..... .. ... &fmt_cdrj %cd %rj +@fmt_rdcj .... ........ ..... ..... .. ... ..... &fmt_rdcj %rd %cj # # Fixed point arithmetic operation instruction @@ -386,3 +408,22 @@ ffint_d_w 0000 00010001 11010 01000 ..... ..... @fmt_fdfj ffint_d_l 0000 00010001 11010 01010 ..... ..... @fmt_fdfj frint_s 0000 00010001 11100 10001 ..... ..... @fmt_fdfj frint_d 0000 00010001 11100 10010 ..... ..... @fmt_fdfj + +# +# Floating point move instruction +# +fmov_s 0000 00010001 01001 00101 ..... ..... @fmt_fdfj +fmov_d 0000 00010001 01001 00110 ..... ..... @fmt_fdfj +fsel 0000 11010000 00 ... ..... ..... ..... @fmt_fdfjfkca +movgr2fr_w 0000 00010001 01001 01001 ..... ..... @fmt_fdrj +movgr2fr_d 0000 00010001 01001 01010 ..... ..... @fmt_fdrj +movgr2frh_w 0000 00010001 01001 01011 ..... ..... @fmt_fdrj +movfr2gr_s 0000 00010001 01001 01101 ..... ..... @fmt_rdfj +movfr2gr_d 0000 00010001 01001 01110 ..... ..... @fmt_rdfj +movfrh2gr_s 0000 00010001 01001 01111 ..... ..... @fmt_rdfj +movgr2fcsr 0000 00010001 01001 10000 ..... ..... @fmt_fcsrdrj +movfcsr2gr 0000 00010001 01001 10010 ..... ..... @fmt_rdfcsrs +movfr2cf 0000 00010001 01001 10100 ..... 00 ... @fmt_cdfj +movcf2fr 0000 00010001 01001 10101 00 ... ..... @fmt_fdcj +movgr2cf 0000 00010001 01001 10110 ..... 00 ... @fmt_cdrj +movcf2gr 0000 00010001 01001 10111 00 ... ..... @fmt_rdcj diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h index 2f231c2..c031ec5 100644 --- a/target/loongarch/instmap.h +++ b/target/loongarch/instmap.h @@ -81,6 +81,12 @@ enum { LA_OPC_FRECIP_D = (0x004516 << 10), LA_OPC_FRSQRT_S = (0x004519 << 10), LA_OPC_FRSQRT_D = (0x00451A << 10), + LA_OPC_GR2FR_W = (0x004529 << 10), + LA_OPC_GR2FR_D = (0x00452A << 10), + LA_OPC_GR2FRH_W = (0x00452B << 10), + LA_OPC_FR2GR_S = (0x00452D << 10), + LA_OPC_FR2GR_D = (0x00452E << 10), + LA_OPC_FRH2GR_S = (0x00452F << 10), LA_OPC_FCVT_S_D = (0x004646 << 10), LA_OPC_FCVT_D_S = (0x004649 << 10), LA_OPC_FTINTRM_W_S = (0x004681 << 10), diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index 095e9d2..110b724 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -2055,3 +2055,157 @@ static bool trans_frint_d(DisasContext *ctx, arg_frint_d *a) gen_loongarch_fp_conv(ctx, LA_OPC_FRINT_D, a->fj, a->fd); return true; } + +/* Floating point move instruction translation */ +static bool trans_fmov_s(DisasContext *ctx, arg_fmov_s *a) +{ + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, a->fj); + gen_store_fpr32(ctx, fp0, a->fd); + tcg_temp_free_i32(fp0); + return true; +} + +static bool trans_fmov_d(DisasContext *ctx, arg_fmov_d *a) +{ + TCGv_i64 fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, a->fj); + gen_store_fpr64(ctx, fp0, a->fd); + tcg_temp_free_i64(fp0); + return true; +} + +static bool trans_fsel(DisasContext *ctx, arg_fsel *a) +{ + TCGv_i64 fj = tcg_temp_new_i64(); + TCGv_i64 fk = tcg_temp_new_i64(); + TCGv_i64 fd = tcg_temp_new_i64(); + TCGv_i32 ca = tcg_const_i32(a->ca); + check_fpu_enabled(ctx); + gen_load_fpr64(ctx, fj, a->fj); + gen_load_fpr64(ctx, fk, a->fk); + gen_helper_fsel(fd, cpu_env, fj, fk, ca); + gen_store_fpr64(ctx, fd, a->fd); + tcg_temp_free_i64(fj); + tcg_temp_free_i64(fk); + tcg_temp_free_i64(fd); + tcg_temp_free_i32(ca); + return true; +} + +static bool trans_movgr2fr_w(DisasContext *ctx, arg_movgr2fr_w *a) +{ + gen_loongarch_fp_mov(ctx, LA_OPC_GR2FR_W, a->rj, a->fd); + return true; +} + +static bool trans_movgr2fr_d(DisasContext *ctx, arg_movgr2fr_d *a) +{ + gen_loongarch_fp_mov(ctx, LA_OPC_GR2FR_D, a->rj, a->fd); + return true; +} + +static bool trans_movgr2frh_w(DisasContext *ctx, arg_movgr2frh_w *a) +{ + gen_loongarch_fp_mov(ctx, LA_OPC_GR2FRH_W, a->rj, a->fd); + return true; +} + +static bool trans_movfr2gr_s(DisasContext *ctx, arg_movfr2gr_s *a) +{ + gen_loongarch_fp_mov(ctx, LA_OPC_FR2GR_S, a->fj, a->rd); + return true; +} + +static bool trans_movfr2gr_d(DisasContext *ctx, arg_movfr2gr_d *a) +{ + gen_loongarch_fp_mov(ctx, LA_OPC_FR2GR_D, a->fj, a->rd); + return true; +} + +static bool trans_movfrh2gr_s(DisasContext *ctx, arg_movfrh2gr_s *a) +{ + gen_loongarch_fp_mov(ctx, LA_OPC_FRH2GR_S, a->fj, a->rd); + return true; +} + +static bool trans_movgr2fcsr(DisasContext *ctx, arg_movgr2fcsr *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv_i32 fs_tmp = tcg_const_i32(a->fcsrd); + + check_fpu_enabled(ctx); + gen_load_gpr(t0, a->rj); + save_cpu_state(ctx, 0); + gen_helper_movgr2fcsr(cpu_env, t0, fs_tmp); + /* Stop translation as we may have changed hflags */ + ctx->base.is_jmp = DISAS_STOP; + + tcg_temp_free(t0); + tcg_temp_free_i32(fs_tmp); + return true; +} + +static bool trans_movfcsr2gr(DisasContext *ctx, arg_movfcsr2gr *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv_i32 reg = tcg_const_i32(a->fcsrs); + gen_helper_movfcsr2gr(t0, cpu_env, reg); + gen_store_gpr(t0, a->rd); + tcg_temp_free(t0); + tcg_temp_free_i32(reg); + return true; +} + +static bool trans_movfr2cf(DisasContext *ctx, arg_movfr2cf *a) +{ + TCGv_i64 fp0 = tcg_temp_new_i64(); + TCGv_i32 cd = tcg_const_i32(a->cd); + + check_fpu_enabled(ctx); + gen_load_fpr64(ctx, fp0, a->fj); + gen_helper_movreg2cf(cpu_env, cd, fp0); + + tcg_temp_free_i64(fp0); + tcg_temp_free_i32(cd); + return true; +} + +static bool trans_movcf2fr(DisasContext *ctx, arg_movcf2fr *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv_i32 cj = tcg_const_i32(a->cj); + + check_fpu_enabled(ctx); + gen_helper_movcf2reg(t0, cpu_env, cj); + gen_store_fpr64(ctx, t0, a->fd); + + tcg_temp_free(t0); + tcg_temp_free_i32(cj); + return true; +} + +static bool trans_movgr2cf(DisasContext *ctx, arg_movgr2cf *a) +{ + TCGv t0 = tcg_temp_new(); + TCGv_i32 cd = tcg_const_i32(a->cd); + + check_fpu_enabled(ctx); + gen_load_gpr(t0, a->rj); + gen_helper_movreg2cf(cpu_env, cd, t0); + + tcg_temp_free(t0); + tcg_temp_free_i32(cd); + return true; +} + +static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) +{ + TCGv_i32 cj = tcg_const_i32(a->cj); + + check_fpu_enabled(ctx); + gen_helper_movcf2reg(cpu_gpr[a->rd], cpu_env, cj); + + tcg_temp_free_i32(cj); + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 52faf73..4efcaa6 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -2087,6 +2087,66 @@ static void gen_loongarch_fp_conv(DisasContext *ctx, uint32_t opc, } } +/* floating point move */ +static void gen_loongarch_fp_mov(DisasContext *ctx, uint32_t opc, + int src, int dest) +{ + TCGv t0 = tcg_temp_new(); + check_fpu_enabled(ctx); + switch (opc) { + case LA_OPC_GR2FR_W: + { + gen_load_gpr(t0, src); + TCGv_i32 fp0 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32(ctx, fp0, dest); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_GR2FR_D: + gen_load_gpr(t0, src); + gen_store_fpr64(ctx, t0, dest); + break; + case LA_OPC_GR2FRH_W: + { + gen_load_gpr(t0, src); + TCGv_i32 fp0 = tcg_temp_new_i32(); + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32h(ctx, fp0, dest); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FR2GR_D: + gen_load_fpr64(ctx, t0, src); + gen_store_gpr(t0, dest); + break; + case LA_OPC_FRH2GR_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32h(ctx, fp0, src); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free_i32(fp0); + gen_store_gpr(t0, dest); + } + break; + case LA_OPC_FR2GR_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, src); + tcg_gen_ext_i32_tl(t0, fp0); + tcg_temp_free_i32(fp0); + gen_store_gpr(t0, dest); + } + break; + default: + generate_exception_end(ctx, EXCP_INE); + goto out; + } + + out: + tcg_temp_free(t0); +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347851 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 BEE08C2B9F4 for ; Mon, 28 Jun 2021 12:21:06 +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 5C8CD61584 for ; Mon, 28 Jun 2021 12:21:06 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 5C8CD61584 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:39646 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqG9-0004i0-9M for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:21:05 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51368) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq14-0002t0-HN for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:31 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45640 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0u-0001Ez-9Q for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:30 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S19; Mon, 28 Jun 2021 20:05:05 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 17/20] target/loongarch: Add floating point load/store instruction translation Date: Mon, 28 Jun 2021 20:04:42 +0800 Message-Id: <1624881885-31692-18-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S19 X-Coremail-Antispam: 1UD129KBjvJXoW3CF15tr4rtF17ZF17WF13twb_yoWDXF47pr 1Iyry3Wr48try3X3s3K345tF98XFs7CF1jg3sIv3WrCF4xJF1UZF1rt3yagF4jgws7XFyY qFyDCF9FgFy8JwUanT9S1TB71UUUUjDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UUUUUUUUU== X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement floating point load/store instruction translation. This includes: - FLD.{S/D}, FST.{S/D} - FLDX.{S/D}, FSTX.{S/D} - FLD{GT/LE}.{S/D}, FST{GT/LE}.{S/D} Signed-off-by: Song Gao --- target/loongarch/insns.decode | 24 +++++++++ target/loongarch/instmap.h | 17 +++++++ target/loongarch/trans.inc.c | 105 ++++++++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 116 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 262 insertions(+) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index a9d8530..cff0955 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -73,6 +73,8 @@ &fmt_fdcj fd cj &fmt_cdrj cd rj &fmt_rdcj rd cj +&fmt_fdrjrk fd rj rk +&fmt_fdrjsi12 fd rj si12 # # Formats @@ -108,6 +110,8 @@ @fmt_fdcj .... ........ ..... ..... .. ... ..... &fmt_fdcj %fd %cj @fmt_cdrj .... ........ ..... ..... ..... .. ... &fmt_cdrj %cd %rj @fmt_rdcj .... ........ ..... ..... .. ... ..... &fmt_rdcj %rd %cj +@fmt_fdrjrk .... ........ ..... ..... ..... ..... &fmt_fdrjrk %fd %rj %rk +@fmt_fdrjsi12 .... ...... ............ ..... ..... &fmt_fdrjsi12 %fd %rj %si12 # # Fixed point arithmetic operation instruction @@ -427,3 +431,23 @@ movfr2cf 0000 00010001 01001 10100 ..... 00 ... @fmt_cdfj movcf2fr 0000 00010001 01001 10101 00 ... ..... @fmt_fdcj movgr2cf 0000 00010001 01001 10110 ..... 00 ... @fmt_cdrj movcf2gr 0000 00010001 01001 10111 00 ... ..... @fmt_rdcj + +# +# Floating point load/store instruction +# +fld_s 0010 101100 ............ ..... ..... @fmt_fdrjsi12 +fst_s 0010 101101 ............ ..... ..... @fmt_fdrjsi12 +fld_d 0010 101110 ............ ..... ..... @fmt_fdrjsi12 +fst_d 0010 101111 ............ ..... ..... @fmt_fdrjsi12 +fldx_s 0011 10000011 00000 ..... ..... ..... @fmt_fdrjrk +fldx_d 0011 10000011 01000 ..... ..... ..... @fmt_fdrjrk +fstx_s 0011 10000011 10000 ..... ..... ..... @fmt_fdrjrk +fstx_d 0011 10000011 11000 ..... ..... ..... @fmt_fdrjrk +fldgt_s 0011 10000111 01000 ..... ..... ..... @fmt_fdrjrk +fldgt_d 0011 10000111 01001 ..... ..... ..... @fmt_fdrjrk +fldle_s 0011 10000111 01010 ..... ..... ..... @fmt_fdrjrk +fldle_d 0011 10000111 01011 ..... ..... ..... @fmt_fdrjrk +fstgt_s 0011 10000111 01100 ..... ..... ..... @fmt_fdrjrk +fstgt_d 0011 10000111 01101 ..... ..... ..... @fmt_fdrjrk +fstle_s 0011 10000111 01110 ..... ..... ..... @fmt_fdrjrk +fstle_d 0011 10000111 01111 ..... ..... ..... @fmt_fdrjrk diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h index c031ec5..eb8e354 100644 --- a/target/loongarch/instmap.h +++ b/target/loongarch/instmap.h @@ -147,6 +147,19 @@ enum { /* load/store opcodes */ enum { + LA_OPC_FLDX_S = (0x07060 << 15), + LA_OPC_FLDX_D = (0x07068 << 15), + LA_OPC_FSTX_S = (0x07070 << 15), + LA_OPC_FSTX_D = (0x07078 << 15), + LA_OPC_FLDGT_S = (0x070E8 << 15), + LA_OPC_FLDGT_D = (0x070E9 << 15), + LA_OPC_FLDLE_S = (0x070EA << 15), + LA_OPC_FLDLE_D = (0x070EB << 15), + LA_OPC_FSTGT_S = (0x070EC << 15), + LA_OPC_FSTGT_D = (0x070ED << 15), + LA_OPC_FSTLE_S = (0x070EE << 15), + LA_OPC_FSTLE_D = (0x070EF << 15), + LA_OPC_LD_B = (0x0A0 << 22), LA_OPC_LD_H = (0x0A1 << 22), LA_OPC_LD_W = (0x0A2 << 22), @@ -158,6 +171,10 @@ enum { LA_OPC_LD_BU = (0x0A8 << 22), LA_OPC_LD_HU = (0x0A9 << 22), LA_OPC_LD_WU = (0x0AA << 22), + LA_OPC_FLD_S = (0x0AC << 22), + LA_OPC_FST_S = (0x0AD << 22), + LA_OPC_FLD_D = (0x0AE << 22), + LA_OPC_FST_D = (0x0AF << 22), LA_OPC_LL_W = (0x20 << 24), LA_OPC_LL_D = (0x22 << 24), diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index 110b724..d95101b 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -2209,3 +2209,108 @@ static bool trans_movcf2gr(DisasContext *ctx, arg_movcf2gr *a) tcg_temp_free_i32(cj); return true; } + +/* Floating point load/store instruction translation */ +static bool trans_fld_s(DisasContext *ctx, arg_fld_s *a) +{ + gen_loongarch_fldst(ctx, LA_OPC_FLD_S, a->fd, a->rj, a->si12); + return true; +} + +static bool trans_fst_s(DisasContext *ctx, arg_fst_s *a) +{ + gen_loongarch_fldst(ctx, LA_OPC_FST_S, a->fd, a->rj, a->si12); + return true; +} + +static bool trans_fld_d(DisasContext *ctx, arg_fld_d *a) +{ + gen_loongarch_fldst(ctx, LA_OPC_FLD_D, a->fd, a->rj, a->si12); + return true; +} + +static bool trans_fst_d(DisasContext *ctx, arg_fst_d *a) +{ + gen_loongarch_fldst(ctx, LA_OPC_FST_D, a->fd, a->rj, a->si12); + return true; +} + +static bool trans_fldx_s(DisasContext *ctx, arg_fldx_s *a) +{ + gen_loongarch_fldst_extra(ctx, LA_OPC_FLDX_S, a->fd, 0, a->rj, a->rk); + return true; +} + +static bool trans_fldx_d(DisasContext *ctx, arg_fldx_d *a) +{ + gen_loongarch_fldst_extra(ctx, LA_OPC_FLDX_D, a->fd, 0, a->rj, a->rk); + return true; +} + +static bool trans_fstx_s(DisasContext *ctx, arg_fstx_s *a) +{ + gen_loongarch_fldst_extra(ctx, LA_OPC_FSTX_S, 0, a->fd, a->rj, a->rk); + return true; +} + +static bool trans_fstx_d(DisasContext *ctx, arg_fstx_d *a) +{ + gen_loongarch_fldst_extra(ctx, LA_OPC_FSTX_D, 0, a->fd, a->rj, a->rk); + return true; +} + +static bool trans_fldgt_s(DisasContext *ctx, arg_fldgt_s *a) +{ + ASRTGT; + gen_loongarch_fldst_extra(ctx, LA_OPC_FLDGT_S, a->fd, 0, a->rj, a->rk); + return true; +} + +static bool trans_fldgt_d(DisasContext *ctx, arg_fldgt_d *a) +{ + ASRTGT; + gen_loongarch_fldst_extra(ctx, LA_OPC_FLDGT_D, a->fd, 0, a->rj, a->rk); + return true; +} + +static bool trans_fldle_s(DisasContext *ctx, arg_fldle_s *a) +{ + ASRTLE; + gen_loongarch_fldst_extra(ctx, LA_OPC_FLDLE_S, a->fd, 0, a->rj, a->rk); + return true; +} + +static bool trans_fldle_d(DisasContext *ctx, arg_fldle_d *a) +{ + ASRTLE; + gen_loongarch_fldst_extra(ctx, LA_OPC_FLDLE_D, a->fd, 0, a->rj, a->rk); + return true; +} + +static bool trans_fstgt_s(DisasContext *ctx, arg_fstgt_s *a) +{ + ASRTGT; + gen_loongarch_fldst_extra(ctx, LA_OPC_FSTGT_S, 0, a->fd, a->rj, a->rk); + return true; +} + +static bool trans_fstgt_d(DisasContext *ctx, arg_fstgt_d *a) +{ + ASRTGT; + gen_loongarch_fldst_extra(ctx, LA_OPC_FSTGT_D, 0, a->fd, a->rj, a->rk); + return true; +} + +static bool trans_fstle_s(DisasContext *ctx, arg_fstle_s *a) +{ + ASRTLE; + gen_loongarch_fldst_extra(ctx, LA_OPC_FSTLE_S, 0, a->fd, a->rj, a->rk); + return true; +} + +static bool trans_fstle_d(DisasContext *ctx, arg_fstle_d *a) +{ + ASRTLE; + gen_loongarch_fldst_extra(ctx, LA_OPC_FSTLE_D, 0, a->fd, a->rj, a->rk); + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index 4efcaa6..c1d89d8 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -2147,6 +2147,122 @@ static void gen_loongarch_fp_mov(DisasContext *ctx, uint32_t opc, tcg_temp_free(t0); } +/* floating point load/store */ +static void gen_loongarch_fp_ldst(DisasContext *ctx, uint32_t opc, + int ft, TCGv t0) +{ + switch (opc) { + case LA_OPC_FLD_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL | + ctx->default_tcg_memop_mask); + gen_store_fpr32(ctx, fp0, ft); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FST_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, ft); + tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL | + ctx->default_tcg_memop_mask); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FLD_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + gen_store_fpr64(ctx, fp0, ft); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FST_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, ft); + tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ | + ctx->default_tcg_memop_mask); + tcg_temp_free_i64(fp0); + } + break; + default: + generate_exception_end(ctx, EXCP_INE); + break; + } +} + +static void gen_loongarch_fldst(DisasContext *ctx, uint32_t op, int fd, + int rj, int16_t imm) +{ + TCGv t0 = tcg_temp_new(); + check_fpu_enabled(ctx); + gen_base_offset_addr(ctx, t0, rj, imm); + gen_loongarch_fp_ldst(ctx, op, fd, t0); + tcg_temp_free(t0); +} + +static void gen_loongarch_fldst_extra(DisasContext *ctx, uint32_t opc, + int fld, int fst, int base, int index) +{ + TCGv t0 = tcg_temp_new(); + + if (base == 0) { + gen_load_gpr(t0, index); + } else if (index == 0) { + gen_load_gpr(t0, base); + } else { + gen_op_addr_add(ctx, t0, cpu_gpr[base], cpu_gpr[index]); + } + + switch (opc) { + case LA_OPC_FLDX_S: + case LA_OPC_FLDGT_S: + case LA_OPC_FLDLE_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL); + tcg_gen_trunc_tl_i32(fp0, t0); + gen_store_fpr32(ctx, fp0, fld); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FLDX_D: + case LA_OPC_FLDGT_D: + case LA_OPC_FLDLE_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + tcg_gen_qemu_ld_i64(fp0, t0, ctx->mem_idx, MO_TEQ); + gen_store_fpr64(ctx, fp0, fld); + tcg_temp_free_i64(fp0); + } + break; + case LA_OPC_FSTX_S: + case LA_OPC_FSTGT_S: + case LA_OPC_FSTLE_S: + { + TCGv_i32 fp0 = tcg_temp_new_i32(); + gen_load_fpr32(ctx, fp0, fst); + tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL); + tcg_temp_free_i32(fp0); + } + break; + case LA_OPC_FSTX_D: + case LA_OPC_FSTGT_D: + case LA_OPC_FSTLE_D: + { + TCGv_i64 fp0 = tcg_temp_new_i64(); + gen_load_fpr64(ctx, fp0, fst); + tcg_gen_qemu_st_i64(fp0, t0, ctx->mem_idx, MO_TEQ); + tcg_temp_free_i64(fp0); + } + break; + } + tcg_temp_free(t0); +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347837 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 63A94C49EA3 for ; Mon, 28 Jun 2021 12:14:01 +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 DAAA361C49 for ; Mon, 28 Jun 2021 12:14:00 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DAAA361C49 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:50632 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq9H-0000z2-Vv for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:14:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51328) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq0z-0002oi-Gw for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:26 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45662 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0v-0001Fv-8K for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:25 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S20; Mon, 28 Jun 2021 20:05:06 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 18/20] target/loongarch: Add branch instruction translation Date: Mon, 28 Jun 2021 20:04:43 +0800 Message-Id: <1624881885-31692-19-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S20 X-Coremail-Antispam: 1UD129KBjvJXoW3WF43GF1DtFy3Jry3GF4UArb_yoWfCF1Upr 10yryUXrWUtFy3JF9xKw15Jr98Jrs7Cr17GwnIqw1fAw1SgFyDZr1Fy34agF4Yg3ykXryj vFy5Aa47KFyUWwUanT9S1TB71UUUUjDqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnUUvcSsGvfC2KfnxnUUI43ZEXa7xR_UUUUUUUUU== X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch implement branch instruction translation. This includes: - BEQ, BNE, BLT[U], BGE[U] - BEQZ, BNEZ - B - BL - JIRL - BCEQZ, BCNEZ Signed-off-by: Song Gao --- target/loongarch/insns.decode | 30 ++++++++++++ target/loongarch/instmap.h | 13 +++++ target/loongarch/trans.inc.c | 110 ++++++++++++++++++++++++++++++++++++++++++ target/loongarch/translate.c | 96 ++++++++++++++++++++++++++++++++++++ 4 files changed, 249 insertions(+) diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode index cff0955..37fd8e5 100644 --- a/target/loongarch/insns.decode +++ b/target/loongarch/insns.decode @@ -38,6 +38,9 @@ %ca 15:3 %fcsrd 0:5 %fcsrs 5:5 +%offs21 0:s5 10:16 +%offs16 10:s16 +%offs 0:s10 10:16 # # Argument sets @@ -75,6 +78,11 @@ &fmt_rdcj rd cj &fmt_fdrjrk fd rj rk &fmt_fdrjsi12 fd rj si12 +&fmt_rjoffs21 rj offs21 +&fmt_cjoffs21 cj offs21 +&fmt_rdrjoffs16 rd rj offs16 +&fmt_offs offs +&fmt_rjrdoffs16 rj rd offs16 # # Formats @@ -112,6 +120,11 @@ @fmt_rdcj .... ........ ..... ..... .. ... ..... &fmt_rdcj %rd %cj @fmt_fdrjrk .... ........ ..... ..... ..... ..... &fmt_fdrjrk %fd %rj %rk @fmt_fdrjsi12 .... ...... ............ ..... ..... &fmt_fdrjsi12 %fd %rj %si12 +@fmt_rjoffs21 .... .. ................ ..... ..... &fmt_rjoffs21 %rj %offs21 +@fmt_cjoffs21 .... .. ................ .. ... ..... &fmt_cjoffs21 %cj %offs21 +@fmt_rdrjoffs16 .... .. ................ ..... ..... &fmt_rdrjoffs16 %rd %rj %offs16 +@fmt_offs .... .. .......................... &fmt_offs %offs +@fmt_rjrdoffs16 .... .. ................ ..... ..... &fmt_rjrdoffs16 %rj %rd %offs16 # # Fixed point arithmetic operation instruction @@ -451,3 +464,20 @@ fstgt_s 0011 10000111 01100 ..... ..... ..... @fmt_fdrjrk fstgt_d 0011 10000111 01101 ..... ..... ..... @fmt_fdrjrk fstle_s 0011 10000111 01110 ..... ..... ..... @fmt_fdrjrk fstle_d 0011 10000111 01111 ..... ..... ..... @fmt_fdrjrk + +# +# Branch instructions +# +beqz 0100 00 ................ ..... ..... @fmt_rjoffs21 +bnez 0100 01 ................ ..... ..... @fmt_rjoffs21 +bceqz 0100 10 ................ 00 ... ..... @fmt_cjoffs21 +bcnez 0100 10 ................ 01 ... ..... @fmt_cjoffs21 +jirl 0100 11 ................ ..... ..... @fmt_rdrjoffs16 +b 0101 00 .......................... @fmt_offs +bl 0101 01 .......................... @fmt_offs +beq 0101 10 ................ ..... ..... @fmt_rjrdoffs16 +bne 0101 11 ................ ..... ..... @fmt_rjrdoffs16 +blt 0110 00 ................ ..... ..... @fmt_rjrdoffs16 +bge 0110 01 ................ ..... ..... @fmt_rjrdoffs16 +bltu 0110 10 ................ ..... ..... @fmt_rjrdoffs16 +bgeu 0110 11 ................ ..... ..... @fmt_rjrdoffs16 diff --git a/target/loongarch/instmap.h b/target/loongarch/instmap.h index eb8e354..0e703c9 100644 --- a/target/loongarch/instmap.h +++ b/target/loongarch/instmap.h @@ -184,4 +184,17 @@ enum { LA_OPC_STPTR_D = (0x27 << 24) }; +/* Branch opcodes */ +enum { + LA_OPC_BEQZ = (0x10 << 26), + LA_OPC_BNEZ = (0x11 << 26), + LA_OPC_B = (0x14 << 26), + LA_OPC_BEQ = (0x16 << 26), + LA_OPC_BNE = (0x17 << 26), + LA_OPC_BLT = (0x18 << 26), + LA_OPC_BGE = (0x19 << 26), + LA_OPC_BLTU = (0x1A << 26), + LA_OPC_BGEU = (0x1B << 26) +}; + #endif diff --git a/target/loongarch/trans.inc.c b/target/loongarch/trans.inc.c index d95101b..782f26c 100644 --- a/target/loongarch/trans.inc.c +++ b/target/loongarch/trans.inc.c @@ -2314,3 +2314,113 @@ static bool trans_fstle_d(DisasContext *ctx, arg_fstle_d *a) gen_loongarch_fldst_extra(ctx, LA_OPC_FSTLE_D, 0, a->fd, a->rj, a->rk); return true; } + +/* Branch Instructions translation */ +static bool trans_beqz(DisasContext *ctx, arg_beqz *a) +{ + gen_loongarch_jump(ctx, LA_OPC_BEQZ, 4, a->rj, 0, a->offs21 << 2); + return true; +} + +static bool trans_bnez(DisasContext *ctx, arg_bnez *a) +{ + gen_loongarch_jump(ctx, LA_OPC_BNEZ, 4, a->rj, 0, a->offs21 << 2); + return true; +} + +static bool trans_bceqz(DisasContext *ctx, arg_bceqz *a) +{ + TCGv_i32 cj = tcg_const_i32(a->cj); + TCGv v0 = tcg_temp_new(); + TCGv v1 = tcg_const_i64(0); + + gen_helper_movcf2reg(v0, cpu_env, cj); + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, v0, v1); + ctx->hflags |= LOONGARCH_HFLAG_BC; + ctx->btarget = ctx->base.pc_next + (a->offs21 << 2); + + tcg_temp_free_i32(cj); + tcg_temp_free(v0); + tcg_temp_free(v1); + return true; +} + +static bool trans_bcnez(DisasContext *ctx, arg_bcnez *a) +{ + TCGv_i32 cj = tcg_const_i32(a->cj); + TCGv v0 = tcg_temp_new(); + TCGv v1 = tcg_const_i64(0); + + gen_helper_movcf2reg(v0, cpu_env, cj); + tcg_gen_setcond_tl(TCG_COND_NE, bcond, v0, v1); + ctx->hflags |= LOONGARCH_HFLAG_BC; + ctx->btarget = ctx->base.pc_next + (a->offs21 << 2); + + tcg_temp_free_i32(cj); + tcg_temp_free(v0); + tcg_temp_free(v1); + return true; +} + +static bool trans_b(DisasContext *ctx, arg_b *a) +{ + gen_loongarch_jump(ctx, LA_OPC_B, 4, 0, 0, a->offs << 2); + return true; +} + +static bool trans_bl(DisasContext *ctx, arg_bl *a) +{ + ctx->btarget = ctx->base.pc_next + (a->offs << 2); + tcg_gen_movi_tl(cpu_gpr[1], ctx->base.pc_next + 4); + ctx->hflags |= LOONGARCH_HFLAG_B; + gen_branch(ctx, 4); + return true; +} + +static bool trans_blt(DisasContext *ctx, arg_blt *a) +{ + gen_loongarch_jump(ctx, LA_OPC_BLT, 4, a->rj, a->rd, a->offs16 << 2); + return true; +} + +static bool trans_bge(DisasContext *ctx, arg_bge *a) +{ + gen_loongarch_jump(ctx, LA_OPC_BGE, 4, a->rj, a->rd, a->offs16 << 2); + return true; +} + +static bool trans_bltu(DisasContext *ctx, arg_bltu *a) +{ + gen_loongarch_jump(ctx, LA_OPC_BLTU, 4, a->rj, a->rd, a->offs16 << 2); + return true; +} + +static bool trans_bgeu(DisasContext *ctx, arg_bgeu *a) +{ + gen_loongarch_jump(ctx, LA_OPC_BGEU, 4, a->rj, a->rd, a->offs16 << 2); + return true; +} + +static bool trans_beq(DisasContext *ctx, arg_beq *a) +{ + gen_loongarch_jump(ctx, LA_OPC_BEQ, 4, a->rj, a->rd, a->offs16 << 2); + return true; +} + +static bool trans_bne(DisasContext *ctx, arg_bne *a) +{ + gen_loongarch_jump(ctx, LA_OPC_BNE, 4, a->rj, a->rd, a->offs16 << 2); + return true; +} + +static bool trans_jirl(DisasContext *ctx, arg_jirl *a) +{ + gen_base_offset_addr(ctx, btarget, a->rj, a->offs16 << 2); + if (a->rd != 0) { + tcg_gen_movi_tl(cpu_gpr[a->rd], ctx->base.pc_next + 4); + } + ctx->hflags |= LOONGARCH_HFLAG_BR; + gen_branch(ctx, 4); + + return true; +} diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c index c1d89d8..9338f7f 100644 --- a/target/loongarch/translate.c +++ b/target/loongarch/translate.c @@ -2263,6 +2263,102 @@ static void gen_loongarch_fldst_extra(DisasContext *ctx, uint32_t opc, tcg_temp_free(t0); } +static void gen_loongarch_jump(DisasContext *ctx, uint32_t opc, + int insn_bytes, + int rj, int rd, int32_t offset) +{ + target_ulong btgt = -1; + int bcond_flag = 0; + TCGv t0 = tcg_temp_new(); + TCGv t1 = tcg_temp_new(); + + if (ctx->hflags & LOONGARCH_HFLAG_BMASK) { + generate_exception_end(ctx, EXCP_INE); + goto out; + } + + /* Load needed operands */ + switch (opc) { + case LA_OPC_BLT: + case LA_OPC_BGE: + case LA_OPC_BLTU: + case LA_OPC_BGEU: + gen_load_gpr(t0, rj); + gen_load_gpr(t1, rd); + bcond_flag = 1; + btgt = ctx->base.pc_next + offset; + break; + case LA_OPC_BEQZ: + case LA_OPC_B: + case LA_OPC_BEQ: + case LA_OPC_BNEZ: + case LA_OPC_BNE: + /* Compare two registers */ + if (rj != rd) { + gen_load_gpr(t0, rj); + gen_load_gpr(t1, rd); + bcond_flag = 1; + } + btgt = ctx->base.pc_next + offset; + break; + default: + generate_exception_end(ctx, EXCP_INE); + goto out; + } + if (bcond_flag == 0) { + /* No condition to be computed */ + switch (opc) { + case LA_OPC_BEQZ: + case LA_OPC_B: + case LA_OPC_BEQ: + ctx->hflags |= LOONGARCH_HFLAG_B; + break; + case LA_OPC_BNEZ: + case LA_OPC_BNE: + /* Treat as NOP. */ + goto out; + default: + generate_exception_end(ctx, EXCP_INE); + goto out; + } + } else { + switch (opc) { + case LA_OPC_BLT: + tcg_gen_setcond_tl(TCG_COND_LT, bcond, t0, t1); + goto not_likely; + case LA_OPC_BGE: + tcg_gen_setcond_tl(TCG_COND_GE, bcond, t0, t1); + goto not_likely; + case LA_OPC_BLTU: + tcg_gen_setcond_tl(TCG_COND_LTU, bcond, t0, t1); + goto not_likely; + case LA_OPC_BGEU: + tcg_gen_setcond_tl(TCG_COND_GEU, bcond, t0, t1); + goto not_likely; + case LA_OPC_BEQZ: + case LA_OPC_B: + case LA_OPC_BEQ: + tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); + goto not_likely; + case LA_OPC_BNEZ: + case LA_OPC_BNE: + tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); + goto not_likely; + not_likely: + ctx->hflags |= LOONGARCH_HFLAG_BC; + break; + default: + generate_exception_end(ctx, EXCP_INE); + goto out; + } + } + ctx->btarget = btgt; + + out: + tcg_temp_free(t0); + tcg_temp_free(t1); +} + static void loongarch_tr_tb_start(DisasContextBase *dcbase, CPUState *cs) { } From patchwork Mon Jun 28 12:04:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347863 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.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,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 2C817C2B9F4 for ; Mon, 28 Jun 2021 12:28:19 +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 4EAAC61279 for ; Mon, 28 Jun 2021 12:28:18 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4EAAC61279 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:58202 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqN7-0000aZ-Bb for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:28:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51378) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq15-0002tB-KY for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:32 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45680 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0w-0001GG-AL for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:31 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S21; Mon, 28 Jun 2021 20:05:08 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 19/20] target/loongarch: Add disassembler Date: Mon, 28 Jun 2021 20:04:44 +0800 Message-Id: <1624881885-31692-20-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S21 X-Coremail-Antispam: 1UD129KBjvAXoWDWFy7Zw4DGF1xZF1rZrWUJwb_yoW7tFWxWo WUJrs5Xws5Ar4DXFZFyF1akayrGr95XFy7Jry8Zwnrtrs3Aw1DWr98Jas5AFy3AFs0krWx G3Z7Cry8KrZ7GFW8n29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" This patch add support for disassembling via option '-d in_asm'. Signed-off-by: Song Gao --- MAINTAINERS | 1 + disas/loongarch.c | 2528 +++++++++++++++++++++++++++++++++++++++++++++++ disas/meson.build | 1 + include/disas/dis-asm.h | 2 + meson.build | 1 + 5 files changed, 2533 insertions(+) create mode 100644 disas/loongarch.c diff --git a/MAINTAINERS b/MAINTAINERS index f207805..f987e2b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -213,6 +213,7 @@ LoongArch TCG CPUS M: Song Gao S: Maintained F: target/loongarch/ +F: disas/loongarch.c M68K TCG CPUs M: Laurent Vivier diff --git a/disas/loongarch.c b/disas/loongarch.c new file mode 100644 index 0000000..be9a47c --- /dev/null +++ b/disas/loongarch.c @@ -0,0 +1,2528 @@ +/* + * QEMU LoongArch Disassembler + * + * Copyright (c) 2021 Loongson Technology Corporation Limited. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "disas/dis-asm.h" + +#define INSNLEN 4 + +/* enums */ +typedef enum { + la_op_illegal = 0, + la_op_clo_w = 1, + la_op_clz_w = 2, + la_op_cto_w = 3, + la_op_ctz_w = 4, + la_op_clo_d = 5, + la_op_clz_d = 6, + la_op_cto_d = 7, + la_op_ctz_d = 8, + la_op_revb_2h = 9, + la_op_revb_4h = 10, + la_op_revb_2w = 11, + la_op_revb_d = 12, + la_op_revh_2w = 13, + la_op_revh_d = 14, + la_op_bitrev_4b = 15, + la_op_bitrev_8b = 16, + la_op_bitrev_w = 17, + la_op_bitrev_d = 18, + la_op_ext_w_h = 19, + la_op_ext_w_b = 20, + la_op_rdtime_d = 21, + la_op_cpucfg = 22, + la_op_asrtle_d = 23, + la_op_asrtgt_d = 24, + la_op_alsl_w = 25, + la_op_alsl_wu = 26, + la_op_bytepick_w = 27, + la_op_bytepick_d = 28, + la_op_add_w = 29, + la_op_add_d = 30, + la_op_sub_w = 31, + la_op_sub_d = 32, + la_op_slt = 33, + la_op_sltu = 34, + la_op_maskeqz = 35, + la_op_masknez = 36, + la_op_nor = 37, + la_op_and = 38, + la_op_or = 39, + la_op_xor = 40, + la_op_orn = 41, + la_op_andn = 42, + la_op_sll_w = 43, + la_op_srl_w = 44, + la_op_sra_w = 45, + la_op_sll_d = 46, + la_op_srl_d = 47, + la_op_sra_d = 48, + la_op_rotr_w = 49, + la_op_rotr_d = 50, + la_op_mul_w = 51, + la_op_mulh_w = 52, + la_op_mulh_wu = 53, + la_op_mul_d = 54, + la_op_mulh_d = 55, + la_op_mulh_du = 56, + la_op_mulw_d_w = 57, + la_op_mulw_d_wu = 58, + la_op_div_w = 59, + la_op_mod_w = 60, + la_op_div_wu = 61, + la_op_mod_wu = 62, + la_op_div_d = 63, + la_op_mod_d = 64, + la_op_div_du = 65, + la_op_mod_du = 66, + la_op_crc_w_b_w = 67, + la_op_crc_w_h_w = 68, + la_op_crc_w_w_w = 69, + la_op_crc_w_d_w = 70, + la_op_crcc_w_b_w = 71, + la_op_crcc_w_h_w = 72, + la_op_crcc_w_w_w = 73, + la_op_crcc_w_d_w = 74, + la_op_break = 75, + la_op_syscall = 76, + la_op_alsl_d = 77, + la_op_slli_w = 78, + la_op_slli_d = 79, + la_op_srli_w = 80, + la_op_srli_d = 81, + la_op_srai_w = 82, + la_op_srai_d = 83, + la_op_rotri_w = 84, + la_op_rotri_d = 85, + la_op_bstrins_w = 86, + la_op_bstrpick_w = 87, + la_op_bstrins_d = 88, + la_op_bstrpick_d = 89, + la_op_fadd_s = 90, + la_op_fadd_d = 91, + la_op_fsub_s = 92, + la_op_fsub_d = 93, + la_op_fmul_s = 94, + la_op_fmul_d = 95, + la_op_fdiv_s = 96, + la_op_fdiv_d = 97, + la_op_fmax_s = 98, + la_op_fmax_d = 99, + la_op_fmin_s = 100, + la_op_fmin_d = 101, + la_op_fmaxa_s = 102, + la_op_fmaxa_d = 103, + la_op_fmina_s = 104, + la_op_fmina_d = 105, + la_op_fscaleb_s = 106, + la_op_fscaleb_d = 107, + la_op_fcopysign_s = 108, + la_op_fcopysign_d = 109, + la_op_fabs_s = 110, + la_op_fabs_d = 111, + la_op_fneg_s = 112, + la_op_fneg_d = 113, + la_op_flogb_s = 114, + la_op_flogb_d = 115, + la_op_fclass_s = 116, + la_op_fclass_d = 117, + la_op_fsqrt_s = 118, + la_op_fsqrt_d = 119, + la_op_frecip_s = 120, + la_op_frecip_d = 121, + la_op_frsqrt_s = 122, + la_op_frsqrt_d = 123, + la_op_fmov_s = 124, + la_op_fmov_d = 125, + la_op_movgr2fr_w = 126, + la_op_movgr2fr_d = 127, + la_op_movgr2frh_w = 128, + la_op_movfr2gr_s = 129, + la_op_movfr2gr_d = 130, + la_op_movfrh2gr_s = 131, + la_op_movgr2fcsr = 132, + la_op_movfcsr2gr = 133, + la_op_movfr2cf = 134, + la_op_movcf2fr = 135, + la_op_movgr2cf = 136, + la_op_movcf2gr = 137, + la_op_fcvt_s_d = 138, + la_op_fcvt_d_s = 139, + la_op_ftintrm_w_s = 140, + la_op_ftintrm_w_d = 141, + la_op_ftintrm_l_s = 142, + la_op_ftintrm_l_d = 143, + la_op_ftintrp_w_s = 144, + la_op_ftintrp_w_d = 145, + la_op_ftintrp_l_s = 146, + la_op_ftintrp_l_d = 147, + la_op_ftintrz_w_s = 148, + la_op_ftintrz_w_d = 149, + la_op_ftintrz_l_s = 150, + la_op_ftintrz_l_d = 151, + la_op_ftintrne_w_s = 152, + la_op_ftintrne_w_d = 153, + la_op_ftintrne_l_s = 154, + la_op_ftintrne_l_d = 155, + la_op_ftint_w_s = 156, + la_op_ftint_w_d = 157, + la_op_ftint_l_s = 158, + la_op_ftint_l_d = 159, + la_op_ffint_s_w = 160, + la_op_ffint_s_l = 161, + la_op_ffint_d_w = 162, + la_op_ffint_d_l = 163, + la_op_frint_s = 164, + la_op_frint_d = 165, + la_op_slti = 166, + la_op_sltui = 167, + la_op_addi_w = 168, + la_op_addi_d = 169, + la_op_lu52i_d = 170, + la_op_addi = 171, + la_op_ori = 172, + la_op_xori = 173, + la_op_rdtimel_w = 174, + la_op_rdtimeh_w = 175, + la_op_fmadd_s = 176, + la_op_fmadd_d = 177, + la_op_fmsub_s = 178, + la_op_fmsub_d = 179, + la_op_fnmadd_s = 180, + la_op_fnmadd_d = 181, + la_op_fnmsub_s = 182, + la_op_fnmsub_d = 183, + la_op_fcmp_cond_s = 184, + la_op_fcmp_cond_d = 185, + la_op_fsel = 186, + la_op_addu16i_d = 187, + la_op_lu12i_w = 188, + la_op_lu32i_d = 189, + la_op_pcaddi = 190, + la_op_pcalau12i = 191, + la_op_pcaddu12i = 192, + la_op_pcaddu18i = 193, + la_op_ll_w = 194, + la_op_sc_w = 195, + la_op_ll_d = 196, + la_op_sc_d = 197, + la_op_ldptr_w = 198, + la_op_stptr_w = 199, + la_op_ldptr_d = 200, + la_op_stptr_d = 201, + la_op_ld_b = 202, + la_op_ld_h = 203, + la_op_ld_w = 204, + la_op_ld_d = 205, + la_op_st_b = 206, + la_op_st_h = 207, + la_op_st_w = 208, + la_op_st_d = 209, + la_op_ld_bu = 210, + la_op_ld_hu = 211, + la_op_ld_wu = 212, + la_op_preld = 213, + la_op_fld_s = 214, + la_op_fst_s = 215, + la_op_fld_d = 216, + la_op_fst_d = 217, + la_op_ldx_b = 218, + la_op_ldx_h = 219, + la_op_ldx_w = 220, + la_op_ldx_d = 221, + la_op_stx_b = 222, + la_op_stx_h = 223, + la_op_stx_w = 224, + la_op_stx_d = 225, + la_op_ldx_bu = 226, + la_op_ldx_hu = 227, + la_op_ldx_wu = 228, + la_op_preldx = 229, + la_op_fldx_s = 230, + la_op_fldx_d = 231, + la_op_fstx_s = 232, + la_op_fstx_d = 233, + la_op_amswap_w = 234, + la_op_amswap_d = 235, + la_op_amadd_w = 236, + la_op_amadd_d = 237, + la_op_amand_w = 238, + la_op_amand_d = 239, + la_op_amor_w = 240, + la_op_amor_d = 241, + la_op_amxor_w = 242, + la_op_amxor_d = 243, + la_op_ammax_w = 244, + la_op_ammax_d = 245, + la_op_ammin_w = 246, + la_op_ammin_d = 247, + la_op_ammax_wu = 248, + la_op_ammax_du = 249, + la_op_ammin_wu = 250, + la_op_ammin_du = 251, + la_op_amswap_db_w = 252, + la_op_amswap_db_d = 253, + la_op_amadd_db_w = 254, + la_op_amadd_db_d = 255, + la_op_amand_db_w = 256, + la_op_amand_db_d = 257, + la_op_amor_db_w = 258, + la_op_amor_db_d = 259, + la_op_amxor_db_w = 260, + la_op_amxor_db_d = 261, + la_op_ammax_db_w = 262, + la_op_ammax_db_d = 263, + la_op_ammin_db_w = 264, + la_op_ammin_db_d = 265, + la_op_ammax_db_wu = 266, + la_op_ammax_db_du = 267, + la_op_ammin_db_wu = 268, + la_op_ammin_db_du = 269, + la_op_dbar = 270, + la_op_ibar = 271, + la_op_fldgt_s = 272, + la_op_fldgt_d = 273, + la_op_fldle_s = 274, + la_op_fldle_d = 275, + la_op_fstgt_s = 276, + la_op_fstgt_d = 277, + ls_op_fstle_s = 278, + la_op_fstle_d = 279, + la_op_ldgt_b = 280, + la_op_ldgt_h = 281, + la_op_ldgt_w = 282, + la_op_ldgt_d = 283, + la_op_ldle_b = 284, + la_op_ldle_h = 285, + la_op_ldle_w = 286, + la_op_ldle_d = 287, + la_op_stgt_b = 288, + la_op_stgt_h = 289, + la_op_stgt_w = 290, + la_op_stgt_d = 291, + la_op_stle_b = 292, + la_op_stle_h = 293, + la_op_stle_w = 294, + la_op_stle_d = 295, + la_op_beqz = 296, + la_op_bnez = 297, + la_op_bceqz = 298, + la_op_bcnez = 299, + la_op_jirl = 300, + la_op_b = 301, + la_op_bl = 302, + la_op_beq = 303, + la_op_bne = 304, + la_op_blt = 305, + la_op_bge = 306, + la_op_bltu = 307, + la_op_bgeu = 308, + +} la_op; + +typedef enum { + la_codec_illegal, + la_codec_empty, + la_codec_2r, + la_codec_2r_u5, + la_codec_2r_u6, + la_codec_2r_2bw, + la_codec_2r_2bd, + la_codec_3r, + la_codec_3r_rd0, + la_codec_3r_sa2, + la_codec_3r_sa3, + la_codec_4r, + la_codec_r_im20, + la_codec_2r_im16, + la_codec_2r_im14, + la_codec_r_im14, + la_codec_2r_im12, + la_codec_im5_r_im12, + la_codec_2r_im8, + la_codec_2r_hint, + la_codec_r_sd, + la_codec_r_sj, + la_codec_r_cd, + la_codec_r_cj, + la_codec_r_seq, + la_codec_code, + la_codec_whint, + la_codec_invtlb, + la_codec_r_ofs21, + la_codec_cj_ofs21, + la_codec_ofs26, + la_codec_cond, + la_codec_sel, + +} la_codec; + +#define la_fmt_illegal "nte" +#define la_fmt_empty "nt" +#define la_fmt_sd_rj "ntA,1" +#define la_fmt_rd_sj "nt0,B" +#define la_fmt_rd_rj "nt0,1" +#define la_fmt_rj_rk "nt1,2" +#define la_fmt_rj_seq "nt1,x" +#define la_fmt_rd_si20 "nt0,i(x)" +#define la_fmt_rd_rj_ui5 "nt0,1,C" +#define la_fmt_rd_rj_ui6 "nt0,1.C" +#define la_fmt_rd_rj_level "nt0,1,x" +#define la_fmt_rd_rj_msbw_lsbw "nt0,1,C,D" +#define la_fmt_rd_rj_msbd_lsbd "nt0,1,C,D" +#define la_fmt_rd_rj_si12 "nt0,1,i(x)" +#define la_fmt_hint_rj_si12 "ntE,1,i(x)" +#define la_fmt_hint_rj_rk "ntE,1,2" +#define la_fmt_rd_rj_csr "nt0,1,x" +#define la_fmt_rd_csr "nt0,x" +#define la_fmt_rd_rj_si14 "nt0,1,i(x)" +#define la_fmt_rd_rj_si16 "nt0,1,i(x)" +#define la_fmt_rd_rj_rk "nt0,1,2" +#define la_fmt_fd_rj_rk "nt3,1,2" +#define la_fmt_rd_rj_rk_sa2 "nt0,1,2,D" +#define la_fmt_rd_rj_rk_sa3 "nt0,1,2,D" +#define la_fmt_fd_rj "nt3,1" +#define la_fmt_rd_fj "nt0,4" +#define la_fmt_fd_fj "nt3,4" +#define la_fmt_fd_fj_si12 "nt3,4,i(x)" +#define la_fmt_fcsrd_rj "ntF,1" +#define la_fmt_rd_fcsrs "nt0,G" +#define la_fmt_cd_fj "ntH,4" +#define la_fmt_fd_cj "nt3,I" +#define la_fmt_fd_fj_fk "nt3,4,5" +#define la_fmt_code "ntJ" +#define la_fmt_whint "ntx" +#define la_fmt_invtlb "ntx,1,2" +#define la_fmt_offs26 "nto(X)p" +#define la_fmt_rj_offs21 "nt1,o(X)p" +#define la_fmt_cj_offs21 "ntQ,o(X)p" +#define la_fmt_rd_rj_offs16 "nt0,1,o(X)" +#define la_fmt_rj_rd_offs16 "nt1,0,o(X)p" +#define la_fmt_s_cd_fj_fk "K.stH,4,5" +#define la_fmt_d_cd_fj_fk "K.dtH,4,5" +#define la_fmt_fd_fj_fk_fa "nt3,4,5,6" +#define la_fmt_fd_fj_fk_ca "nt3,4,5,L" +#define la_fmt_cop_rj_si12 "ntM,1,i(x)" + +/* structures */ +typedef struct { + uint32_t pc; + uint32_t insn; + int32_t imm; + int32_t imm2; + uint16_t op; + uint16_t code; + uint8_t codec; + uint8_t r1; + uint8_t r2; + uint8_t r3; + uint8_t r4; + uint8_t bit; +} la_decode; + +typedef struct { + const char * const name; + const la_codec codec; + const char * const format; +} la_opcode_data; + +/* reg names */ +const char * const loongarch_r_normal_name[32] = { + "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", "$r6", "$r7", + "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", + "$r16", "$r17", "$r18", "$r19", "$r20", "$r21", "$r22", "$r23", + "$r24", "$r25", "$r26", "$r27", "$r28", "$r29", "$r30", "$r31", +}; + +const char * const loongarch_f_normal_name[32] = { + "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", + "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", + "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", + "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", +}; + +const char * const loongarch_cr_normal_name[4] = { + "$scr0", "$scr1", "$scr2", "$scr3", +}; + +const char * const loongarch_c_normal_name[8] = { + "$fcc0", "$fcc1", "$fcc2", "$fcc3", "$fcc4", "$fcc5", "$fcc6", "$fcc7", +}; + +/* instruction data */ +const la_opcode_data opcode_data[] = { + { "illegal", la_codec_illegal, la_fmt_illegal }, + { "clo.w", la_codec_2r, la_fmt_rd_rj }, + { "clz.w", la_codec_2r, la_fmt_rd_rj }, + { "cto.w", la_codec_2r, la_fmt_rd_rj }, + { "ctz.w", la_codec_2r, la_fmt_rd_rj }, + { "clo.d", la_codec_2r, la_fmt_rd_rj }, + { "clz.d", la_codec_2r, la_fmt_rd_rj }, + { "cto.d", la_codec_2r, la_fmt_rd_rj }, + { "ctz_d", la_codec_2r, la_fmt_rd_rj }, + { "revb.2h", la_codec_2r, la_fmt_rd_rj }, + { "revb.4h", la_codec_2r, la_fmt_rd_rj }, + { "revb.2w", la_codec_2r, la_fmt_rd_rj }, + { "revb.d", la_codec_2r, la_fmt_rd_rj }, + { "revh.2w", la_codec_2r, la_fmt_rd_rj }, + { "revh.d", la_codec_2r, la_fmt_rd_rj }, + { "bitrev.4b", la_codec_2r, la_fmt_rd_rj }, + { "bitrev.8b", la_codec_2r, la_fmt_rd_rj }, + { "bitrev.w", la_codec_2r, la_fmt_rd_rj }, + { "bitrev.d", la_codec_2r, la_fmt_rd_rj }, + { "ext.w.h", la_codec_2r, la_fmt_rd_rj }, + { "ext.w.b", la_codec_2r, la_fmt_rd_rj }, + { "rdtime.d", la_codec_2r, la_fmt_rd_rj }, + { "cpucfg", la_codec_2r, la_fmt_rd_rj }, + { "asrtle.d", la_codec_3r_rd0, la_fmt_rj_rk }, + { "asrtgt.d", la_codec_3r_rd0, la_fmt_rj_rk }, + { "alsl.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, + { "alsl.wu", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, + { "bytepick.w", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, + { "bytepick.d", la_codec_3r_sa3, la_fmt_rd_rj_rk_sa3 }, + { "add.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "add.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "sub.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "sub.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "slt", la_codec_3r, la_fmt_rd_rj_rk }, + { "sltu", la_codec_3r, la_fmt_rd_rj_rk }, + { "maskeqz", la_codec_3r, la_fmt_rd_rj_rk }, + { "masknez", la_codec_3r, la_fmt_rd_rj_rk }, + { "nor", la_codec_3r, la_fmt_rd_rj_rk }, + { "and", la_codec_3r, la_fmt_rd_rj_rk }, + { "or", la_codec_3r, la_fmt_rd_rj_rk }, + { "xor", la_codec_3r, la_fmt_rd_rj_rk }, + { "orn", la_codec_3r, la_fmt_rd_rj_rk }, + { "andn", la_codec_3r, la_fmt_rd_rj_rk }, + { "sll.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "srl.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "sra.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "sll.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "srl.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "sra.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "rotr.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "rotr.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "mul.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "mulh.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "mulh.wu", la_codec_3r, la_fmt_rd_rj_rk }, + { "mul.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "mulh.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "mulh.du", la_codec_3r, la_fmt_rd_rj_rk }, + { "mulw.d.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "mulw.d.wu", la_codec_3r, la_fmt_rd_rj_rk }, + { "div.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "mod.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "div.wu", la_codec_3r, la_fmt_rd_rj_rk }, + { "mod.wu", la_codec_3r, la_fmt_rd_rj_rk }, + { "div.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "mod.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "div.du", la_codec_3r, la_fmt_rd_rj_rk }, + { "mod.du", la_codec_3r, la_fmt_rd_rj_rk }, + { "crc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "crc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "crc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "crc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "crcc.w.b.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "crcc.w.h.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "crcc.w.w.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "crcc.w.d.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "break", la_codec_code, la_fmt_code }, + { "syscall", la_codec_code, la_fmt_code }, + { "alsl.d", la_codec_3r_sa2, la_fmt_rd_rj_rk_sa2 }, + { "slli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, + { "slli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, + { "srli.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, + { "srli.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, + { "srai.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, + { "srai.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, + { "rotri.w", la_codec_2r_u5, la_fmt_rd_rj_ui5 }, + { "rotri.d", la_codec_2r_u6, la_fmt_rd_rj_ui6 }, + { "bstrins.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw }, + { "bstrpick.w", la_codec_2r_2bw, la_fmt_rd_rj_msbw_lsbw }, + { "bstrins.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd }, + { "bstrpick.d", la_codec_2r_2bd, la_fmt_rd_rj_msbd_lsbd }, + { "fadd.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fadd.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fsub.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fsub.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmul.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmul.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fdiv.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fdiv.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmax.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmax.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmin.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmin.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmaxa.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmaxa.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmina.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fmina.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fscaleb.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fscaleb.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fcopysign.s", la_codec_3r, la_fmt_fd_fj_fk }, + { "fcopysign.d", la_codec_3r, la_fmt_fd_fj_fk }, + { "fabs.s", la_codec_2r, la_fmt_fd_fj }, + { "fabs.d", la_codec_2r, la_fmt_fd_fj }, + { "fneg.s", la_codec_2r, la_fmt_fd_fj }, + { "fneg.d", la_codec_2r, la_fmt_fd_fj }, + { "flogb.s", la_codec_2r, la_fmt_fd_fj }, + { "flogb.d", la_codec_2r, la_fmt_fd_fj }, + { "fclass.s", la_codec_2r, la_fmt_fd_fj }, + { "fclass.d", la_codec_2r, la_fmt_fd_fj }, + { "fsqrt.s", la_codec_2r, la_fmt_fd_fj }, + { "fsqrt.d", la_codec_2r, la_fmt_fd_fj }, + { "frecip.s", la_codec_2r, la_fmt_fd_fj }, + { "frecip.d", la_codec_2r, la_fmt_fd_fj }, + { "frsqrt.s", la_codec_2r, la_fmt_fd_fj }, + { "frsqrt.d", la_codec_2r, la_fmt_fd_fj }, + { "fmov.s", la_codec_2r, la_fmt_fd_fj }, + { "fmov.d", la_codec_2r, la_fmt_fd_fj }, + { "movgr2fr.w", la_codec_2r, la_fmt_fd_rj }, + { "movgr2fr.d", la_codec_2r, la_fmt_fd_rj }, + { "movgr2frh.w", la_codec_2r, la_fmt_fd_rj }, + { "movfr2gr.s", la_codec_2r, la_fmt_rd_fj }, + { "movfr2gr.d", la_codec_2r, la_fmt_rd_fj }, + { "movfrh2gr.s", la_codec_2r, la_fmt_rd_fj }, + { "movgr2fcsr", la_codec_2r, la_fmt_fcsrd_rj }, + { "movfcsr2gr", la_codec_2r, la_fmt_rd_fcsrs }, + { "movfr2cf", la_codec_r_cd, la_fmt_cd_fj }, + { "movcf2fr", la_codec_r_cj, la_fmt_fd_cj }, + { "movgr2cf", la_codec_r_cd, la_fmt_cd_fj }, + { "movcf2gr", la_codec_r_cj, la_fmt_fd_cj }, + { "fcvt.s.d", la_codec_2r, la_fmt_fd_fj }, + { "fcvt.d.s", la_codec_2r, la_fmt_fd_fj }, + { "ftintrm.w.s", la_codec_2r, la_fmt_fd_fj }, + { "ftintrm.w.d", la_codec_2r, la_fmt_fd_fj }, + { "ftintrm.l.s", la_codec_2r, la_fmt_fd_fj }, + { "ftintrm.l.d", la_codec_2r, la_fmt_fd_fj }, + { "ftintrp.w.s", la_codec_2r, la_fmt_fd_fj }, + { "ftintrp.w.d", la_codec_2r, la_fmt_fd_fj }, + { "ftintrp.l.s", la_codec_2r, la_fmt_fd_fj }, + { "ftintrp.l.d", la_codec_2r, la_fmt_fd_fj }, + { "ftintrz.w.s", la_codec_2r, la_fmt_fd_fj }, + { "ftintrz.w.d", la_codec_2r, la_fmt_fd_fj }, + { "ftintrz.l.s", la_codec_2r, la_fmt_fd_fj }, + { "ftintrz.l.d", la_codec_2r, la_fmt_fd_fj }, + { "ftintrne.w.s", la_codec_2r, la_fmt_fd_fj }, + { "ftintrne.w.d", la_codec_2r, la_fmt_fd_fj }, + { "ftintrne.l.s", la_codec_2r, la_fmt_fd_fj }, + { "ftintrne.l.d", la_codec_2r, la_fmt_fd_fj }, + { "ftint.w.s", la_codec_2r, la_fmt_fd_fj }, + { "ftint.w.d", la_codec_2r, la_fmt_fd_fj }, + { "ftint.l.s", la_codec_2r, la_fmt_fd_fj }, + { "ftint.l.d", la_codec_2r, la_fmt_fd_fj }, + { "ffint.s.w", la_codec_2r, la_fmt_fd_fj }, + { "ffint.s.l", la_codec_2r, la_fmt_fd_fj }, + { "ffint.d.w", la_codec_2r, la_fmt_fd_fj }, + { "ffint.d.l", la_codec_2r, la_fmt_fd_fj }, + { "frint.s", la_codec_2r, la_fmt_fd_fj }, + { "frint.d", la_codec_2r, la_fmt_fd_fj }, + { "slti", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "sltui", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "addi.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "addi.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "lu52i.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "addi", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "ori", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "xori", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "rdtimel.w", la_codec_2r, la_fmt_rd_rj }, + { "rdtimeh.w", la_codec_2r, la_fmt_rd_rj }, + { "fmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, + { "fmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, + { "fmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, + { "fmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, + { "fnmadd.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, + { "fnmadd.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, + { "fnmsub.s", la_codec_4r, la_fmt_fd_fj_fk_fa }, + { "fnmsub.d", la_codec_4r, la_fmt_fd_fj_fk_fa }, + { "fcmp.cond.s", la_codec_cond, la_fmt_s_cd_fj_fk }, + { "fcmp.cond.d", la_codec_cond, la_fmt_d_cd_fj_fk }, + { "fsel", la_codec_sel, la_fmt_fd_fj_fk_ca }, + { "addu16i.d", la_codec_2r_im16, la_fmt_rd_rj_si16 }, + { "lu12i.w", la_codec_r_im20, la_fmt_rd_si20 }, + { "lu32i.d", la_codec_r_im20, la_fmt_rd_si20 }, + { "pcaddi", la_codec_r_im20, la_fmt_rd_si20 }, + { "pcalau12i", la_codec_r_im20, la_fmt_rd_si20 }, + { "pcaddu12i", la_codec_r_im20, la_fmt_rd_si20 }, + { "pcaddu18i", la_codec_r_im20, la_fmt_rd_si20 }, + { "ll.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, + { "sc.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, + { "ll.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, + { "sc.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, + { "ldptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, + { "stptr.w", la_codec_2r_im14, la_fmt_rd_rj_si14 }, + { "ldptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, + { "stptr.d", la_codec_2r_im14, la_fmt_rd_rj_si14 }, + { "ld.b", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "ld.h", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "ld.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "ld.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "st.b", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "st.h", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "st.w", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "st.d", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "ld.bu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "ld.hu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "ld.wu", la_codec_2r_im12, la_fmt_rd_rj_si12 }, + { "preld", la_codec_2r_im12, la_fmt_hint_rj_si12 }, + { "fld.s", la_codec_2r_im12, la_fmt_fd_fj_si12 }, + { "fst.s", la_codec_2r_im12, la_fmt_fd_fj_si12 }, + { "fld.d", la_codec_2r_im12, la_fmt_fd_fj_si12 }, + { "fst.d", la_codec_2r_im12, la_fmt_fd_fj_si12 }, + { "ldx.b", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldx.h", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldx.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldx.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "stx.b", la_codec_3r, la_fmt_rd_rj_rk }, + { "stx.h", la_codec_3r, la_fmt_rd_rj_rk }, + { "stx.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "stx.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldx.bu", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldx.hu", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldx.wu", la_codec_3r, la_fmt_rd_rj_rk }, + { "preldx", la_codec_2r_hint, la_fmt_hint_rj_rk }, + { "fldx.s", la_codec_3r, la_fmt_fd_rj_rk }, + { "fldx.d", la_codec_3r, la_fmt_fd_rj_rk }, + { "fstx.s", la_codec_3r, la_fmt_fd_rj_rk }, + { "fstx.d", la_codec_3r, la_fmt_fd_rj_rk }, + { "amswap.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amswap.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "amadd.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amadd.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "amand.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amand.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "amor.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amor.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "amxor.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amxor.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammax.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammax.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammin.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammin.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammax.wu", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammax.du", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammin.wu", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammin.du", la_codec_3r, la_fmt_rd_rj_rk }, + { "amswap.db.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amswap.db.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "amadd.db.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amadd.db.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "amand.db.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amand.db.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "amor.db.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amor.db.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "amxor.db.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "amxor.db.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammax.db.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammax.db.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammin.db.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammin.db.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammax.db.wu", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammax.db.du", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammin.db.wu", la_codec_3r, la_fmt_rd_rj_rk }, + { "ammin.db.du", la_codec_3r, la_fmt_rd_rj_rk }, + { "dbar", la_codec_whint, la_fmt_whint }, + { "ibar", la_codec_whint, la_fmt_whint }, + { "fldgt.s", la_codec_3r, la_fmt_fd_rj_rk }, + { "fldgt.d", la_codec_3r, la_fmt_fd_rj_rk }, + { "fldle.s", la_codec_3r, la_fmt_fd_rj_rk }, + { "fldle.d", la_codec_3r, la_fmt_fd_rj_rk }, + { "fstgt.s", la_codec_3r, la_fmt_fd_rj_rk }, + { "fstgt.d", la_codec_3r, la_fmt_fd_rj_rk }, + { "fstle.s", la_codec_3r, la_fmt_fd_rj_rk }, + { "fstle.d", la_codec_3r, la_fmt_fd_rj_rk }, + { "ldgt.b", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldgt.h", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldgt.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldgt.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldle.b", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldle.h", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldle.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "ldle.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "stgt.b", la_codec_3r, la_fmt_rd_rj_rk }, + { "stgt.h", la_codec_3r, la_fmt_rd_rj_rk }, + { "stgt.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "stgt.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "stle.b", la_codec_3r, la_fmt_rd_rj_rk }, + { "stle.h", la_codec_3r, la_fmt_rd_rj_rk }, + { "stle.w", la_codec_3r, la_fmt_rd_rj_rk }, + { "stle.d", la_codec_3r, la_fmt_rd_rj_rk }, + { "beqz", la_codec_r_ofs21, la_fmt_rj_offs21 }, + { "bnez", la_codec_r_ofs21, la_fmt_rj_offs21 }, + { "bceqz", la_codec_cj_ofs21, la_fmt_cj_offs21 }, + { "bcnez", la_codec_cj_ofs21, la_fmt_cj_offs21 }, + { "jirl", la_codec_2r_im16, la_fmt_rd_rj_offs16 }, + { "b", la_codec_ofs26, la_fmt_offs26 }, + { "bl", la_codec_ofs26, la_fmt_offs26 }, + { "beq", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, + { "bne", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, + { "blt", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, + { "bge", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, + { "bltu", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, + { "bgeu", la_codec_2r_im16, la_fmt_rj_rd_offs16 }, + +}; + + +/* decode opcode */ +static void decode_insn_opcode(la_decode *dec) +{ + uint32_t insn = dec->insn; + uint16_t op = la_op_illegal; + switch ((insn >> 26) & 0x3f) { + case 0x0: + switch ((insn >> 22) & 0xf) { + case 0x0: + switch ((insn >> 18) & 0xf) { + case 0x0: + switch ((insn >> 15) & 0x7) { + case 0x0: + switch ((insn >> 10) & 0x1f) { + case 0x4: + op = la_op_clo_w; + break; + case 0x5: + op = la_op_clz_w; + break; + case 0x6: + op = la_op_cto_w; + break; + case 0x7: + op = la_op_ctz_w; + break; + case 0x8: + op = la_op_clo_d; + break; + case 0x9: + op = la_op_clz_d; + break; + case 0xa: + op = la_op_cto_d; + break; + case 0xb: + op = la_op_ctz_d; + break; + case 0xc: + op = la_op_revb_2h; + break; + case 0xd: + op = la_op_revb_4h; + break; + case 0xe: + op = la_op_revb_2w; + break; + case 0xf: + op = la_op_revb_d; + break; + case 0x10: + op = la_op_revh_2w; + break; + case 0x11: + op = la_op_revh_d; + break; + case 0x12: + op = la_op_bitrev_4b; + break; + case 0x13: + op = la_op_bitrev_8b; + break; + case 0x14: + op = la_op_bitrev_w; + break; + case 0x15: + op = la_op_bitrev_d; + break; + case 0x16: + op = la_op_ext_w_h; + break; + case 0x17: + op = la_op_ext_w_b; + break; + case 0x18: + op = la_op_rdtimel_w; + break; + case 0x19: + op = la_op_rdtimeh_w; + break; + case 0x1a: + op = la_op_rdtime_d; + break; + case 0x1b: + op = la_op_cpucfg; + break; + } + break; + case 0x2: + switch (insn & 0x0000001f) { + case 0x00000000: + op = la_op_asrtle_d; + break; + } + break; + case 0x3: + switch (insn & 0x0000001f) { + case 0x00000000: + op = la_op_asrtgt_d; + break; + } + break; + } + break; + case 0x1: + switch ((insn >> 17) & 0x1) { + case 0x0: + op = la_op_alsl_w; + break; + case 0x1: + op = la_op_alsl_wu; + break; + } + break; + case 0x2: + switch ((insn >> 17) & 0x1) { + case 0x0: + op = la_op_bytepick_w; + break; + } + break; + case 0x3: + op = la_op_bytepick_d; + break; + case 0x4: + switch ((insn >> 15) & 0x7) { + case 0x0: + op = la_op_add_w; + break; + case 0x1: + op = la_op_add_d; + break; + case 0x2: + op = la_op_sub_w; + break; + case 0x3: + op = la_op_sub_d; + break; + case 0x4: + op = la_op_slt; + break; + case 0x5: + op = la_op_sltu; + break; + case 0x6: + op = la_op_maskeqz; + break; + case 0x7: + op = la_op_masknez; + break; + } + break; + case 0x5: + switch ((insn >> 15) & 0x7) { + case 0x0: + op = la_op_nor; + break; + case 0x1: + op = la_op_and; + break; + case 0x2: + op = la_op_or; + break; + case 0x3: + op = la_op_xor; + break; + case 0x4: + op = la_op_orn; + break; + case 0x5: + op = la_op_andn; + break; + case 0x6: + op = la_op_sll_w; + break; + case 0x7: + op = la_op_srl_w; + break; + } + break; + case 0x6: + switch ((insn >> 15) & 0x7) { + case 0x0: + op = la_op_sra_w; + break; + case 0x1: + op = la_op_sll_d; + break; + case 0x2: + op = la_op_srl_d; + break; + case 0x3: + op = la_op_sra_d; + break; + case 0x6: + op = la_op_rotr_w; + break; + case 0x7: + op = la_op_rotr_d; + break; + } + break; + case 0x7: + switch ((insn >> 15) & 0x7) { + case 0x0: + op = la_op_mul_w; + break; + case 0x1: + op = la_op_mulh_w; + break; + case 0x2: + op = la_op_mulh_wu; + break; + case 0x3: + op = la_op_mul_d; + break; + case 0x4: + op = la_op_mulh_d; + break; + case 0x5: + op = la_op_mulh_du; + break; + case 0x6: + op = la_op_mulw_d_w; + break; + case 0x7: + op = la_op_mulw_d_wu; + break; + } + break; + case 0x8: + switch ((insn >> 15) & 0x7) { + case 0x0: + op = la_op_div_w; + break; + case 0x1: + op = la_op_mod_w; + break; + case 0x2: + op = la_op_div_wu; + break; + case 0x3: + op = la_op_mod_wu; + break; + case 0x4: + op = la_op_div_d; + break; + case 0x5: + op = la_op_mod_d; + break; + case 0x6: + op = la_op_div_du; + break; + case 0x7: + op = la_op_mod_du; + break; + } + break; + case 0x9: + switch ((insn >> 15) & 0x7) { + case 0x0: + op = la_op_crc_w_b_w; + break; + case 0x1: + op = la_op_crc_w_h_w; + break; + case 0x2: + op = la_op_crc_w_w_w; + break; + case 0x3: + op = la_op_crc_w_d_w; + break; + case 0x4: + op = la_op_crcc_w_b_w; + break; + case 0x5: + op = la_op_crcc_w_h_w; + break; + case 0x6: + op = la_op_crcc_w_w_w; + break; + case 0x7: + op = la_op_crcc_w_d_w; + break; + } + break; + case 0xa: + switch ((insn >> 15) & 0x7) { + case 0x4: + op = la_op_break; + break; + case 0x6: + op = la_op_syscall; + break; + } + break; + case 0xb: + switch ((insn >> 17) & 0x1) { + case 0x0: + op = la_op_alsl_d; + break; + } + break; + } + break; + case 0x1: + switch ((insn >> 21) & 0x1) { + case 0x0: + switch ((insn >> 16) & 0x1f) { + case 0x0: + switch ((insn >> 15) & 0x1) { + case 0x1: + op = la_op_slli_w; + break; + } + break; + case 0x1: + op = la_op_slli_d; + break; + case 0x4: + switch ((insn >> 15) & 0x1) { + case 0x1: + op = la_op_srli_w; + break; + } + break; + case 0x5: + op = la_op_srli_d; + break; + case 0x8: + switch ((insn >> 15) & 0x1) { + case 0x1: + op = la_op_srai_w; + break; + } + break; + case 0x9: + op = la_op_srai_d; + break; + case 0xc: + switch ((insn >> 15) & 0x1) { + case 0x1: + op = la_op_rotri_w; + break; + } + break; + case 0xd: + op = la_op_rotri_d; + break; + } + break; + case 0x1: + switch ((insn >> 15) & 0x1) { + case 0x0: + op = la_op_bstrins_w; + break; + case 0x1: + op = la_op_bstrpick_w; + break; + } + break; + } + break; + case 0x2: + op = la_op_bstrins_d; + break; + case 0x3: + op = la_op_bstrpick_d; + break; + case 0x4: + switch ((insn >> 15) & 0x7f) { + case 0x1: + op = la_op_fadd_s; + break; + case 0x2: + op = la_op_fadd_d; + break; + case 0x5: + op = la_op_fsub_s; + break; + case 0x6: + op = la_op_fsub_d; + break; + case 0x9: + op = la_op_fmul_s; + break; + case 0xa: + op = la_op_fmul_d; + break; + case 0xd: + op = la_op_fdiv_s; + break; + case 0xe: + op = la_op_fdiv_d; + break; + case 0x11: + op = la_op_fmax_s; + break; + case 0x12: + op = la_op_fmax_d; + break; + case 0x15: + op = la_op_fmin_s; + break; + case 0x16: + op = la_op_fmin_d; + break; + case 0x19: + op = la_op_fmaxa_s; + break; + case 0x1a: + op = la_op_fmaxa_d; + break; + case 0x1d: + op = la_op_fmina_s; + break; + case 0x1e: + op = la_op_fmina_d; + break; + case 0x21: + op = la_op_fscaleb_s; + break; + case 0x22: + op = la_op_fscaleb_d; + break; + case 0x25: + op = la_op_fcopysign_s; + break; + case 0x26: + op = la_op_fcopysign_d; + break; + case 0x28: + switch ((insn >> 10) & 0x1f) { + case 0x1: + op = la_op_fabs_s; + break; + case 0x2: + op = la_op_fabs_d; + break; + case 0x5: + op = la_op_fneg_s; + break; + case 0x6: + op = la_op_fneg_d; + break; + case 0x9: + op = la_op_flogb_s; + break; + case 0xa: + op = la_op_flogb_d; + break; + case 0xd: + op = la_op_fclass_s; + break; + case 0xe: + op = la_op_fclass_d; + break; + case 0x11: + op = la_op_fsqrt_s; + break; + case 0x12: + op = la_op_fsqrt_d; + break; + case 0x15: + op = la_op_frecip_s; + break; + case 0x16: + op = la_op_frecip_d; + break; + case 0x19: + op = la_op_frsqrt_s; + break; + case 0x1a: + op = la_op_frsqrt_d; + break; + } + break; + case 0x29: + switch ((insn >> 10) & 0x1f) { + case 0x5: + op = la_op_fmov_s; + break; + case 0x6: + op = la_op_fmov_d; + break; + case 0x9: + op = la_op_movgr2fr_w; + break; + case 0xa: + op = la_op_movgr2fr_d; + break; + case 0xb: + op = la_op_movgr2frh_w; + break; + case 0xd: + op = la_op_movfr2gr_s; + break; + case 0xe: + op = la_op_movfr2gr_d; + break; + case 0xf: + op = la_op_movfrh2gr_s; + break; + case 0x10: + op = la_op_movgr2fcsr; + break; + case 0x12: + op = la_op_movfcsr2gr; + break; + case 0x14: + switch ((insn >> 3) & 0x3) { + case 0x0: + op = la_op_movfr2cf; + break; + } + break; + case 0x15: + switch ((insn >> 8) & 0x3) { + case 0x0: + op = la_op_movcf2fr; + break; + } + break; + case 0x16: + switch ((insn >> 3) & 0x3) { + case 0x0: + op = la_op_movgr2cf; + break; + } + break; + case 0x17: + switch ((insn >> 8) & 0x3) { + case 0x0: + op = la_op_movcf2gr; + break; + } + break; + } + break; + case 0x32: + switch ((insn >> 10) & 0x1f) { + case 0x6: + op = la_op_fcvt_s_d; + break; + case 0x9: + op = la_op_fcvt_d_s; + break; + } + break; + case 0x34: + switch ((insn >> 10) & 0x1f) { + case 0x1: + op = la_op_ftintrm_w_s; + break; + case 0x2: + op = la_op_ftintrm_w_d; + break; + case 0x9: + op = la_op_ftintrm_l_s; + break; + case 0xa: + op = la_op_ftintrm_l_d; + break; + case 0x11: + op = la_op_ftintrp_w_s; + break; + case 0x12: + op = la_op_ftintrp_w_d; + break; + case 0x19: + op = la_op_ftintrp_l_s; + break; + case 0x1a: + op = la_op_ftintrp_l_d; + break; + } + break; + case 0x35: + switch ((insn >> 10) & 0x1f) { + case 0x1: + op = la_op_ftintrz_w_s; + break; + case 0x2: + op = la_op_ftintrz_w_d; + break; + case 0x9: + op = la_op_ftintrz_l_s; + break; + case 0xa: + op = la_op_ftintrz_l_d; + break; + case 0x11: + op = la_op_ftintrne_w_s; + break; + case 0x12: + op = la_op_ftintrne_w_d; + break; + case 0x19: + op = la_op_ftintrne_l_s; + break; + case 0x1a: + op = la_op_ftintrne_l_d; + break; + } + break; + case 0x36: + switch ((insn >> 10) & 0x1f) { + case 0x1: + op = la_op_ftint_w_s; + break; + case 0x2: + op = la_op_ftint_w_d; + break; + case 0x9: + op = la_op_ftint_l_s; + break; + case 0xa: + op = la_op_ftint_l_d; + break; + } + break; + case 0x3a: + switch ((insn >> 10) & 0x1f) { + case 0x4: + op = la_op_ffint_s_w; + break; + case 0x6: + op = la_op_ffint_s_l; + break; + case 0x8: + op = la_op_ffint_d_w; + break; + case 0xa: + op = la_op_ffint_d_l; + break; + } + break; + case 0x3c: + switch ((insn >> 10) & 0x1f) { + case 0x11: + op = la_op_frint_s; + break; + case 0x12: + op = la_op_frint_d; + break; + } + break; + } + break; + case 0x8: + op = la_op_slti; + break; + case 0x9: + op = la_op_sltui; + break; + case 0xa: + op = la_op_addi_w; + break; + case 0xb: + op = la_op_addi_d; + break; + case 0xc: + op = la_op_lu52i_d; + break; + case 0xd: + op = la_op_addi; + break; + case 0xe: + op = la_op_ori; + break; + case 0xf: + op = la_op_xori; + break; + } + break; + case 0x2: + switch ((insn >> 20) & 0x3f) { + case 0x1: + op = la_op_fmadd_s; + break; + case 0x2: + op = la_op_fmadd_d; + break; + case 0x5: + op = la_op_fmsub_s; + break; + case 0x6: + op = la_op_fmsub_d; + break; + case 0x9: + op = la_op_fnmadd_s; + break; + case 0xa: + op = la_op_fnmadd_d; + break; + case 0xd: + op = la_op_fnmsub_s; + break; + case 0xe: + op = la_op_fnmsub_d; + break; + } + break; + case 0x3: + switch ((insn >> 20) & 0x3f) { + case 0x1: + switch ((insn >> 3) & 0x3) { + case 0x0: + op = la_op_fcmp_cond_s; + break; + } + break; + case 0x2: + switch ((insn >> 3) & 0x3) { + case 0x0: + op = la_op_fcmp_cond_d; + break; + } + break; + case 0x10: + switch ((insn >> 18) & 0x3) { + case 0x0: + op = la_op_fsel; + break; + } + break; + } + break; + case 0x4: + op = la_op_addu16i_d; + break; + case 0x5: + switch ((insn >> 25) & 0x1) { + case 0x0: + op = la_op_lu12i_w; + break; + case 0x1: + op = la_op_lu32i_d; + break; + } + break; + case 0x6: + switch ((insn >> 25) & 0x1) { + case 0x0: + op = la_op_pcaddi; + break; + case 0x1: + op = la_op_pcalau12i; + break; + } + break; + case 0x7: + switch ((insn >> 25) & 0x1) { + case 0x0: + op = la_op_pcaddu12i; + break; + case 0x1: + op = la_op_pcaddu18i; + break; + } + break; + case 0x8: + switch ((insn >> 24) & 0x3) { + case 0x0: + op = la_op_ll_w; + break; + case 0x1: + op = la_op_sc_w; + break; + case 0x2: + op = la_op_ll_d; + break; + case 0x3: + op = la_op_sc_d; + break; + } + break; + case 0x9: + switch ((insn >> 24) & 0x3) { + case 0x0: + op = la_op_ldptr_w; + break; + case 0x1: + op = la_op_stptr_w; + break; + case 0x2: + op = la_op_ldptr_d; + break; + case 0x3: + op = la_op_stptr_d; + break; + } + break; + case 0xa: + switch ((insn >> 22) & 0xf) { + case 0x0: + op = la_op_ld_b; + break; + case 0x1: + op = la_op_ld_h; + break; + case 0x2: + op = la_op_ld_w; + break; + case 0x3: + op = la_op_ld_d; + break; + case 0x4: + op = la_op_st_b; + break; + case 0x5: + op = la_op_st_h; + break; + case 0x6: + op = la_op_st_w; + break; + case 0x7: + op = la_op_st_d; + break; + case 0x8: + op = la_op_ld_bu; + break; + case 0x9: + op = la_op_ld_hu; + break; + case 0xa: + op = la_op_ld_wu; + break; + case 0xb: + op = la_op_preld; + break; + case 0xc: + op = la_op_fld_s; + break; + case 0xd: + op = la_op_fst_s; + break; + case 0xe: + op = la_op_fld_d; + break; + case 0xf: + op = la_op_fst_d; + break; + } + break; + case 0xe: + switch ((insn >> 15) & 0x7ff) { + case 0x0: + op = la_op_ldx_b; + break; + case 0x8: + op = la_op_ldx_h; + break; + case 0x10: + op = la_op_ldx_w; + break; + case 0x18: + op = la_op_ldx_d; + break; + case 0x20: + op = la_op_stx_b; + break; + case 0x28: + op = la_op_stx_h; + break; + case 0x30: + op = la_op_stx_w; + break; + case 0x38: + op = la_op_stx_d; + break; + case 0x40: + op = la_op_ldx_bu; + break; + case 0x48: + op = la_op_ldx_hu; + break; + case 0x50: + op = la_op_ldx_wu; + break; + case 0x58: + op = la_op_preldx; + break; + case 0x60: + op = la_op_fldx_s; + break; + case 0x68: + op = la_op_fldx_d; + break; + case 0x70: + op = la_op_fstx_s; + break; + case 0x78: + op = la_op_fstx_d; + break; + case 0xc0: + op = la_op_amswap_w; + break; + case 0xc1: + op = la_op_amswap_d; + break; + case 0xc2: + op = la_op_amadd_w; + break; + case 0xc3: + op = la_op_amadd_d; + break; + case 0xc4: + op = la_op_amand_w; + break; + case 0xc5: + op = la_op_amand_d; + break; + case 0xc6: + op = la_op_amor_w; + break; + case 0xc7: + op = la_op_amor_d; + break; + case 0xc8: + op = la_op_amxor_w; + break; + case 0xc9: + op = la_op_amxor_d; + break; + case 0xca: + op = la_op_ammax_w; + break; + case 0xcb: + op = la_op_ammax_d; + break; + case 0xcc: + op = la_op_ammin_w; + break; + case 0xcd: + op = la_op_ammin_d; + break; + case 0xce: + op = la_op_ammax_wu; + break; + case 0xcf: + op = la_op_ammax_du; + break; + case 0xd0: + op = la_op_ammin_wu; + break; + case 0xd1: + op = la_op_ammin_du; + break; + case 0xd2: + op = la_op_amswap_db_w; + break; + case 0xd3: + op = la_op_amswap_db_d; + break; + case 0xd4: + op = la_op_amadd_db_w; + break; + case 0xd5: + op = la_op_amadd_db_d; + break; + case 0xd6: + op = la_op_amand_db_w; + break; + case 0xd7: + op = la_op_amand_db_d; + break; + case 0xd8: + op = la_op_amor_db_w; + break; + case 0xd9: + op = la_op_amor_db_d; + break; + case 0xda: + op = la_op_amxor_db_w; + break; + case 0xdb: + op = la_op_amxor_db_d; + break; + case 0xdc: + op = la_op_ammax_db_w; + break; + case 0xdd: + op = la_op_ammax_db_d; + break; + case 0xde: + op = la_op_ammin_db_w; + break; + case 0xdf: + op = la_op_ammin_db_d; + break; + case 0xe0: + op = la_op_ammax_db_wu; + break; + case 0xe1: + op = la_op_ammax_db_du; + break; + case 0xe2: + op = la_op_ammin_db_wu; + break; + case 0xe3: + op = la_op_ammin_db_du; + break; + case 0xe4: + op = la_op_dbar; + break; + case 0xe5: + op = la_op_ibar; + break; + case 0xe8: + op = la_op_fldgt_s; + break; + case 0xe9: + op = la_op_fldgt_d; + break; + case 0xea: + op = la_op_fldle_s; + break; + case 0xeb: + op = la_op_fldle_d; + break; + case 0xec: + op = la_op_fstgt_s; + break; + case 0xed: + op = la_op_fstgt_d; + break; + case 0xee: + op = ls_op_fstle_s; + break; + case 0xef: + op = la_op_fstle_d; + break; + case 0xf0: + op = la_op_ldgt_b; + break; + case 0xf1: + op = la_op_ldgt_h; + break; + case 0xf2: + op = la_op_ldgt_w; + break; + case 0xf3: + op = la_op_ldgt_d; + break; + case 0xf4: + op = la_op_ldle_b; + break; + case 0xf5: + op = la_op_ldle_h; + break; + case 0xf6: + op = la_op_ldle_w; + break; + case 0xf7: + op = la_op_ldle_d; + break; + case 0xf8: + op = la_op_stgt_b; + break; + case 0xf9: + op = la_op_stgt_h; + break; + case 0xfa: + op = la_op_stgt_w; + break; + case 0xfb: + op = la_op_stgt_d; + break; + case 0xfc: + op = la_op_stle_b; + break; + case 0xfd: + op = la_op_stle_h; + break; + case 0xfe: + op = la_op_stle_w; + break; + case 0xff: + op = la_op_stle_d; + break; + } + break; + case 0x10: + op = la_op_beqz; + break; + case 0x11: + op = la_op_bnez; + break; + case 0x12: + switch ((insn >> 8) & 0x3) { + case 0x0: + op = la_op_bceqz; + break; + case 0x1: + op = la_op_bcnez; + break; + } + break; + case 0x13: + op = la_op_jirl; + break; + case 0x14: + op = la_op_b; + break; + case 0x15: + op = la_op_bl; + break; + case 0x16: + op = la_op_beq; + break; + case 0x17: + op = la_op_bne; + break; + case 0x18: + op = la_op_blt; + break; + case 0x19: + op = la_op_bge; + break; + case 0x1a: + op = la_op_bltu; + break; + case 0x1b: + op = la_op_bgeu; + break; + default: + op = la_op_illegal; + break; + } + dec->op = op; +} + +/* operand extractors */ +#define IM_5 5 +#define IM_8 8 +#define IM_12 12 +#define IM_14 14 +#define IM_15 15 +#define IM_16 16 +#define IM_20 20 +#define IM_21 21 +#define IM_26 26 + +static uint32_t operand_r1(uint32_t insn) +{ + return insn & 0x1f; +} + +static uint32_t operand_r2(uint32_t insn) +{ + return (insn >> 5) & 0x1f; +} + +static uint32_t operand_r3(uint32_t insn) +{ + return (insn >> 10) & 0x1f; +} + +static uint32_t operand_r4(uint32_t insn) +{ + return (insn >> 15) & 0x1f; +} + +static uint32_t operand_u6(uint32_t insn) +{ + return (insn >> 10) & 0x3f; +} + +static uint32_t operand_bw1(uint32_t insn) +{ + return (insn >> 10) & 0x1f; +} + +static uint32_t operand_bw2(uint32_t insn) +{ + return (insn >> 16) & 0x1f; +} + +static uint32_t operand_bd1(uint32_t insn) +{ + return (insn >> 10) & 0x3f; +} + +static uint32_t operand_bd2(uint32_t insn) +{ + return (insn >> 16) & 0x3f; +} + +static uint32_t operand_sa2(uint32_t insn) +{ + return (insn >> 15) & 0x3; +} + +static uint32_t operand_sa3(uint32_t insn) +{ + return (insn >> 15) & 0x3; +} + +static int32_t operand_im20(uint32_t insn) +{ + int32_t imm = (int32_t)((insn >> 5) & 0xfffff); + return imm > (1 << 19) ? imm - (1 << 20) : imm; +} + +static int32_t operand_im16(uint32_t insn) +{ + int32_t imm = (int32_t)((insn >> 10) & 0xffff); + return imm > (1 << 15) ? imm - (1 << 16) : imm; +} + +static int32_t operand_im14(uint32_t insn) +{ + int32_t imm = (int32_t)((insn >> 10) & 0x3fff); + return imm > (1 << 13) ? imm - (1 << 14) : imm; +} + +static int32_t operand_im12(uint32_t insn) +{ + int32_t imm = (int32_t)((insn >> 10) & 0xfff); + return imm > (1 << 11) ? imm - (1 << 12) : imm; +} + +static int32_t operand_im8(uint32_t insn) +{ + int32_t imm = (int32_t)((insn >> 10) & 0xff); + return imm > (1 << 7) ? imm - (1 << 8) : imm; +} + +static uint32_t operand_hint(uint32_t insn) +{ + return insn & 0x1f; +} + +static uint32_t operand_sd(uint32_t insn) +{ + return insn & 0x3; +} + +static uint32_t operand_sj(uint32_t insn) +{ + return (insn >> 5) & 0x3; +} + +static uint32_t operand_cd(uint32_t insn) +{ + return insn & 0x7; +} + +static uint32_t operand_cj(uint32_t insn) +{ + return (insn >> 5) & 0x7; +} + +static uint32_t operand_code(uint32_t insn) +{ + return insn & 0x7fff; +} + +static int32_t operand_whint(uint32_t insn) +{ + int32_t imm = (int32_t)(insn & 0x7fff); + return imm > (1 << 14) ? imm - (1 << 15) : imm; +} + +static int32_t operand_invop(uint32_t insn) +{ + int32_t imm = (int32_t)(insn & 0x1f); + return imm > (1 << 4) ? imm - (1 << 5) : imm; +} + +static int32_t operand_ofs21(uint32_t insn) +{ + int32_t imm = (((int32_t)insn & 0x1f) << 16) | + ((insn >> 10) & 0xffff); + return imm > (1 << 20) ? imm - (1 << 21) : imm; +} + +static int32_t operand_ofs26(uint32_t insn) +{ + int32_t imm = (((int32_t)insn & 0x3ff) << 16) | + ((insn >> 10) & 0xffff); + return imm > (1 << 25) ? imm - (1 << 26) : imm; +} + +static uint32_t operand_fcond(uint32_t insn) +{ + return (insn >> 15) & 0x1f; +} + +static uint32_t operand_sel(uint32_t insn) +{ + return (insn >> 15) & 0x7; +} + +/* decode operands */ +static void decode_insn_operands(la_decode *dec) +{ + uint32_t insn = dec->insn; + dec->codec = opcode_data[dec->op].codec; + switch (dec->codec) { + case la_codec_illegal: + case la_codec_empty: + break; + case la_codec_2r: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + break; + case la_codec_2r_u5: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + break; + case la_codec_2r_u6: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_u6(insn); + break; + case la_codec_2r_2bw: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_bw1(insn); + dec->r4 = operand_bw2(insn); + break; + case la_codec_2r_2bd: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_bd1(insn); + dec->r4 = operand_bd2(insn); + break; + case la_codec_3r: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + break; + case la_codec_3r_rd0: + dec->r1 = 0; + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + break; + case la_codec_3r_sa2: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + dec->r4 = operand_sa2(insn); + break; + case la_codec_3r_sa3: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + dec->r4 = operand_sa3(insn); + break; + case la_codec_4r: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + dec->r4 = operand_r4(insn); + break; + case la_codec_r_im20: + dec->r1 = operand_r1(insn); + dec->imm = operand_im20(insn); + dec->bit = IM_20; + break; + case la_codec_2r_im16: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->imm = operand_im16(insn); + dec->bit = IM_16; + break; + case la_codec_2r_im14: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->imm = operand_im14(insn); + dec->bit = IM_14; + break; + case la_codec_r_im14: + dec->r1 = operand_r1(insn); + dec->imm = operand_im14(insn); + dec->bit = IM_14; + break; + case la_codec_im5_r_im12: + dec->imm2 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->imm = operand_im12(insn); + dec->bit = IM_12; + break; + case la_codec_2r_im12: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->imm = operand_im12(insn); + dec->bit = IM_12; + break; + case la_codec_2r_im8: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->imm = operand_im8(insn); + dec->bit = IM_8; + break; + case la_codec_2r_hint: + dec->r1 = operand_hint(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + break; + case la_codec_r_sd: + dec->r1 = operand_sd(insn); + dec->r2 = operand_r2(insn); + break; + case la_codec_r_sj: + dec->r1 = operand_r1(insn); + dec->r2 = operand_sj(insn); + break; + case la_codec_r_cd: + dec->r1 = operand_cd(insn); + dec->r2 = operand_r2(insn); + break; + case la_codec_r_cj: + dec->r1 = operand_r1(insn); + dec->r2 = operand_cj(insn); + break; + case la_codec_r_seq: + dec->r1 = 0; + dec->r2 = operand_r1(insn); + dec->imm = operand_im8(insn); + dec->bit = IM_8; + break; + case la_codec_code: + dec->code = operand_code(insn); + break; + case la_codec_whint: + dec->imm = operand_whint(insn); + dec->bit = IM_15; + break; + case la_codec_invtlb: + dec->imm = operand_invop(insn); + dec->bit = IM_5; + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + break; + case la_codec_r_ofs21: + dec->imm = operand_ofs21(insn); + dec->bit = IM_21; + dec->r2 = operand_r2(insn); + break; + case la_codec_cj_ofs21: + dec->imm = operand_ofs21(insn); + dec->bit = IM_21; + dec->r2 = operand_cj(insn); + break; + case la_codec_ofs26: + dec->imm = operand_ofs26(insn); + dec->bit = IM_26; + break; + case la_codec_cond: + dec->r1 = operand_cd(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + dec->r4 = operand_fcond(insn); + break; + case la_codec_sel: + dec->r1 = operand_r1(insn); + dec->r2 = operand_r2(insn); + dec->r3 = operand_r3(insn); + dec->r4 = operand_sel(insn); + break; + } +} + +/* format instruction */ +static void append(char *s1, const char *s2, size_t n) +{ + size_t l1 = strlen(s1); + if (n - l1 - 1 > 0) { + strncat(s1, s2, n - l1); + } +} + +static void format_insn(char *buf, size_t buflen, size_t tab, la_decode *dec) +{ + char tmp[16]; + const char *fmt; + + fmt = opcode_data[dec->op].format; + while (*fmt) { + switch (*fmt) { + case 'n': /* name */ + append(buf, opcode_data[dec->op].name, buflen); + break; + case 's': + append(buf, "s", buflen); + break; + case 'd': + append(buf, "d", buflen); + break; + case 'e': /* illegal */ + snprintf(tmp, sizeof(tmp), "%x", dec->insn); + append(buf, tmp, buflen); + break; + case 't': + while (strlen(buf) < tab) { + append(buf, " ", buflen); + } + break; + case '(': + append(buf, "(", buflen); + break; + case ',': + append(buf, ",", buflen); + break; + case '.': + append(buf, ".", buflen); + break; + case ')': + append(buf, ")", buflen); + break; + case '0': /* rd */ + append(buf, loongarch_r_normal_name[dec->r1], buflen); + break; + case '1': /* rj */ + append(buf, loongarch_r_normal_name[dec->r2], buflen); + break; + case '2': /* rk */ + append(buf, loongarch_r_normal_name[dec->r3], buflen); + break; + case '3': /* fd */ + append(buf, loongarch_f_normal_name[dec->r1], buflen); + break; + case '4': /* fj */ + append(buf, loongarch_f_normal_name[dec->r2], buflen); + break; + case '5': /* fk */ + append(buf, loongarch_f_normal_name[dec->r3], buflen); + break; + case '6': /* fa */ + append(buf, loongarch_f_normal_name[dec->r4], buflen); + break; + case 'A': /* sd */ + append(buf, loongarch_cr_normal_name[dec->r1], buflen); + break; + case 'B': /* sj */ + append(buf, loongarch_cr_normal_name[dec->r2], buflen); + break; + case 'C': /* r3 */ + snprintf(tmp, sizeof(tmp), "%x", dec->r3); + append(buf, tmp, buflen); + break; + case 'D': /* r4 */ + snprintf(tmp, sizeof(tmp), "%x", dec->r4); + append(buf, tmp, buflen); + break; + case 'E': /* r1 */ + snprintf(tmp, sizeof(tmp), "%x", dec->r1); + append(buf, tmp, buflen); + break; + case 'F': /* fcsrd */ + append(buf, loongarch_r_normal_name[dec->r1], buflen); + break; + case 'G': /* fcsrs */ + append(buf, loongarch_r_normal_name[dec->r2], buflen); + break; + case 'H': /* cd */ + append(buf, loongarch_c_normal_name[dec->r1], buflen); + break; + case 'I': /* cj */ + append(buf, loongarch_c_normal_name[dec->r2], buflen); + break; + case 'J': /* code */ + snprintf(tmp, sizeof(tmp), "0x%x", dec->code); + append(buf, tmp, buflen); + break; + case 'K': /* cond */ + switch (dec->r4) { + case 0x0: + append(buf, "caf", buflen); + break; + case 0x1: + append(buf, "saf", buflen); + break; + case 0x2: + append(buf, "clt", buflen); + break; + case 0x3: + append(buf, "slt", buflen); + break; + case 0x4: + append(buf, "ceq", buflen); + break; + case 0x5: + append(buf, "seq", buflen); + break; + case 0x6: + append(buf, "cle", buflen); + break; + case 0x7: + append(buf, "sle", buflen); + break; + case 0x8: + append(buf, "cun", buflen); + break; + case 0x9: + append(buf, "sun", buflen); + break; + case 0xA: + append(buf, "cult", buflen); + break; + case 0xB: + append(buf, "sult", buflen); + break; + case 0xC: + append(buf, "cueq", buflen); + break; + case 0xD: + append(buf, "sueq", buflen); + break; + case 0xE: + append(buf, "cule", buflen); + break; + case 0xF: + append(buf, "sule", buflen); + break; + case 0x10: + append(buf, "cne", buflen); + break; + case 0x11: + append(buf, "sne", buflen); + break; + case 0x14: + append(buf, "cor", buflen); + break; + case 0x15: + append(buf, "sor", buflen); + break; + case 0x18: + append(buf, "cune", buflen); + break; + case 0x19: + append(buf, "sune", buflen); + break; + } + break; + case 'L': /* ca */ + append(buf, loongarch_c_normal_name[dec->r4], buflen); + break; + case 'M': /* cop */ + snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm2) & 0x1f); + append(buf, tmp, buflen); + break; + case 'i': /* sixx d */ + snprintf(tmp, sizeof(tmp), "%d", dec->imm); + append(buf, tmp, buflen); + break; + case 'o': /* offset */ + snprintf(tmp, sizeof(tmp), "%d", (dec->imm) << 2); + append(buf, tmp, buflen); + break; + case 'x': /* sixx x */ + switch (dec->bit) { + case IM_5: + snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x1f); + append(buf, tmp, buflen); + break; + case IM_8: + snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xff); + append(buf, tmp, buflen); + break; + case IM_12: + snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfff); + append(buf, tmp, buflen); + break; + case IM_14: + snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x3fff); + append(buf, tmp, buflen); + break; + case IM_15: + snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0x7fff); + append(buf, tmp, buflen); + break; + case IM_16: + snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xffff); + append(buf, tmp, buflen); + break; + case IM_20: + snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) & 0xfffff); + append(buf, tmp, buflen); + break; + default: + snprintf(tmp, sizeof(tmp), "0x%x", dec->imm); + append(buf, tmp, buflen); + break; + } + break; + case 'X': /* offset x*/ + switch (dec->bit) { + case IM_16: + snprintf(tmp, sizeof(tmp), "0x%x", + ((dec->imm) << 2) & 0xffff); + append(buf, tmp, buflen); + break; + case IM_21: + snprintf(tmp, sizeof(tmp), "0x%x", + ((dec->imm) << 2) & 0x1fffff); + append(buf, tmp, buflen); + break; + case IM_26: + snprintf(tmp, sizeof(tmp), "0x%x", + ((dec->imm) << 2) & 0x3ffffff); + append(buf, tmp, buflen); + break; + default: + snprintf(tmp, sizeof(tmp), "0x%x", (dec->imm) << 2); + append(buf, tmp, buflen); + break; + } + break; + case 'p': /* pc */ + snprintf(tmp, sizeof(tmp), " # 0x%"PRIx32"", + dec->pc + ((dec->imm) << 2)); + append(buf, tmp, buflen); + break; + default: + break; + } + fmt++; + } +} + +/* disassemble instruction */ +static void +disasm_insn(char *buf, size_t buflen, bfd_vma pc, unsigned long int insn) +{ + la_decode dec = { 0 }; + dec.pc = pc; + dec.insn = insn; + decode_insn_opcode(&dec); + decode_insn_operands(&dec); + format_insn(buf, buflen, 16, &dec); +} + +int +print_insn_loongarch(bfd_vma memaddr, struct disassemble_info *info) +{ + char buf[128] = { 0 }; + bfd_byte buffer[INSNLEN]; + unsigned long insn; + int status; + + status = (*info->read_memory_func)(memaddr, buffer, INSNLEN, info); + if (status == 0) { + insn = (uint32_t) bfd_getl32(buffer); + (*info->fprintf_func)(info->stream, "%08" PRIx64 " ", insn); + } else { + (*info->memory_error_func)(status, memaddr, info); + return -1; + } + disasm_insn(buf, sizeof(buf), memaddr, insn); + (*info->fprintf_func)(info->stream, "\t%s", buf); + return INSNLEN; +} diff --git a/disas/meson.build b/disas/meson.build index 449f99e..a1bd8b8 100644 --- a/disas/meson.build +++ b/disas/meson.build @@ -9,6 +9,7 @@ common_ss.add(when: 'CONFIG_CRIS_DIS', if_true: files('cris.c')) common_ss.add(when: 'CONFIG_HEXAGON_DIS', if_true: files('hexagon.c')) common_ss.add(when: 'CONFIG_HPPA_DIS', if_true: files('hppa.c')) common_ss.add(when: 'CONFIG_I386_DIS', if_true: files('i386.c')) +common_ss.add(when: 'CONFIG_LOONGARCH_DIS', if_true: files('loongarch.c')) common_ss.add(when: 'CONFIG_M68K_DIS', if_true: files('m68k.c')) common_ss.add(when: 'CONFIG_MICROBLAZE_DIS', if_true: files('microblaze.c')) common_ss.add(when: 'CONFIG_MIPS_DIS', if_true: files('mips.c')) diff --git a/include/disas/dis-asm.h b/include/disas/dis-asm.h index 524f291..009a03a 100644 --- a/include/disas/dis-asm.h +++ b/include/disas/dis-asm.h @@ -253,6 +253,7 @@ enum bfd_architecture #define bfd_mach_rx 0x75 #define bfd_mach_rx_v2 0x76 #define bfd_mach_rx_v3 0x77 + bfd_arch_loongarch, bfd_arch_last }; #define bfd_mach_s390_31 31 @@ -462,6 +463,7 @@ int print_insn_riscv32 (bfd_vma, disassemble_info*); int print_insn_riscv64 (bfd_vma, disassemble_info*); int print_insn_rx(bfd_vma, disassemble_info *); int print_insn_hexagon(bfd_vma, disassemble_info *); +int print_insn_loongarch(bfd_vma, disassemble_info *); #ifdef CONFIG_CAPSTONE bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size); diff --git a/meson.build b/meson.build index d8a9266..0211442 100644 --- a/meson.build +++ b/meson.build @@ -1244,6 +1244,7 @@ disassemblers = { 'sh4' : ['CONFIG_SH4_DIS'], 'sparc' : ['CONFIG_SPARC_DIS'], 'xtensa' : ['CONFIG_XTENSA_DIS'], + 'loongarch' : ['CONFIG_LOONGARCH_DIS'], } if link_language == 'cpp' disassemblers += { From patchwork Mon Jun 28 12:04:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gaosong X-Patchwork-Id: 12347859 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=-13.9 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, URIBL_BLOCKED,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 429E3C49EA3 for ; Mon, 28 Jun 2021 12:25:36 +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 CBD4961584 for ; Mon, 28 Jun 2021 12:25:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CBD4961584 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=loongson.cn Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Received: from localhost ([::1]:50824 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxqKU-0003zJ-U1 for qemu-devel@archiver.kernel.org; Mon, 28 Jun 2021 08:25:34 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:51382) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lxq16-0002tW-Dc for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:32 -0400 Received: from mail.loongson.cn ([114.242.206.163]:45696 helo=loongson.cn) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lxq0x-0001GN-AB for qemu-devel@nongnu.org; Mon, 28 Jun 2021 08:05:32 -0400 Received: from kvm-dev1.localdomain (unknown [10.2.5.134]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxL0LdutlgOrYZAA--.8747S22; Mon, 28 Jun 2021 20:05:09 +0800 (CST) From: Song Gao To: qemu-devel@nongnu.org Subject: [PATCH 20/20] target/loongarch: Add linux-user emulation support Date: Mon, 28 Jun 2021 20:04:45 +0800 Message-Id: <1624881885-31692-21-git-send-email-gaosong@loongson.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> References: <1624881885-31692-1-git-send-email-gaosong@loongson.cn> X-CM-TRANSID: AQAAf9DxL0LdutlgOrYZAA--.8747S22 X-Coremail-Antispam: 1UD129KBjvAXoWDWFW7Kr1DuryktF4kZr47urg_yoWrCw43Ko WxJF1aqw1kGr1fua1kWw17Wr1UZF9rJF48Jr4UAFy8GFnFqr1DWr13tay8WFn3ArySgFy5 tFyjqr1qya9YyF1kn29KB7ZKAUJUUUU3529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UjIYCTnIWjDUYxBIdaVFxhVjvjDU0xZFpf9x0zRUUUUUUUUU= X-CM-SenderInfo: 5jdr20tqj6z05rqj20fqof0/ Received-SPF: pass client-ip=114.242.206.163; envelope-from=gaosong@loongson.cn; helo=loongson.cn X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham 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: peter.maydell@linaro.org, thuth@redhat.com, richard.henderson@linaro.org, laurent@vivier.eu, maobibo@loongson.cn, alistair.francis@wdc.com, pbonzini@redhat.com, philmd@redhat.com Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Add files to linux-user/loongarch64 Add file to default-configs Add loongarch to target/meson.build Signed-off-by: Song Gao --- MAINTAINERS | 1 + default-configs/targets/loongarch64-linux-user.mak | 4 + include/elf.h | 2 + linux-user/elfload.c | 58 ++++ linux-user/loongarch64/cpu_loop.c | 177 ++++++++++++ linux-user/loongarch64/signal.c | 193 +++++++++++++ linux-user/loongarch64/sockbits.h | 1 + linux-user/loongarch64/syscall_nr.h | 307 +++++++++++++++++++++ linux-user/loongarch64/target_cpu.h | 36 +++ linux-user/loongarch64/target_elf.h | 14 + linux-user/loongarch64/target_fcntl.h | 12 + linux-user/loongarch64/target_signal.h | 28 ++ linux-user/loongarch64/target_structs.h | 49 ++++ linux-user/loongarch64/target_syscall.h | 46 +++ linux-user/loongarch64/termbits.h | 229 +++++++++++++++ linux-user/syscall_defs.h | 8 +- meson.build | 2 +- qapi/machine-target.json | 4 +- target/loongarch/meson.build | 19 ++ target/meson.build | 1 + 20 files changed, 1185 insertions(+), 6 deletions(-) create mode 100644 default-configs/targets/loongarch64-linux-user.mak create mode 100644 linux-user/loongarch64/cpu_loop.c create mode 100644 linux-user/loongarch64/signal.c create mode 100644 linux-user/loongarch64/sockbits.h create mode 100644 linux-user/loongarch64/syscall_nr.h create mode 100644 linux-user/loongarch64/target_cpu.h create mode 100644 linux-user/loongarch64/target_elf.h create mode 100644 linux-user/loongarch64/target_fcntl.h create mode 100644 linux-user/loongarch64/target_signal.h create mode 100644 linux-user/loongarch64/target_structs.h create mode 100644 linux-user/loongarch64/target_syscall.h create mode 100644 linux-user/loongarch64/termbits.h create mode 100644 target/loongarch/meson.build diff --git a/MAINTAINERS b/MAINTAINERS index f987e2b..36dacf5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -214,6 +214,7 @@ M: Song Gao S: Maintained F: target/loongarch/ F: disas/loongarch.c +F: linux-user/loongarch64/ M68K TCG CPUs M: Laurent Vivier diff --git a/default-configs/targets/loongarch64-linux-user.mak b/default-configs/targets/loongarch64-linux-user.mak new file mode 100644 index 0000000..5af380a --- /dev/null +++ b/default-configs/targets/loongarch64-linux-user.mak @@ -0,0 +1,4 @@ +# Default configuration for loongson64-linux-user +TARGET_LOONGARCH64=y +TARGET_ARCH=loongarch64 +TARGET_BASE_ARCH=loongarch diff --git a/include/elf.h b/include/elf.h index 811bf4a..3a4bcb6 100644 --- a/include/elf.h +++ b/include/elf.h @@ -182,6 +182,8 @@ typedef struct mips_elf_abiflags_v0 { #define EM_NANOMIPS 249 /* Wave Computing nanoMIPS */ +#define EM_LOONGARCH 258 /* LoongArch */ + /* * This is an interim value that we will use until the committee comes * up with a final number. diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 598ab8a..08bc9dc 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -909,6 +909,64 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en #endif +#ifdef TARGET_LOONGARCH64 + +#define ELF_START_MMAP 0x80000000 + +#define ELF_CLASS ELFCLASS64 +#define ELF_ARCH EM_LOONGARCH + +#define elf_check_arch(x) ((x) == EM_LOONGARCH) +static inline void init_thread(struct target_pt_regs *regs, + struct image_info *infop) +{ + regs->csr_crmd = 2 << 3; + regs->csr_era = infop->entry; + regs->regs[3] = infop->start_stack; +} + +/* See linux kernel: arch/loongarch/include/asm/elf.h. */ +#define ELF_NREG 45 +typedef target_elf_greg_t target_elf_gregset_t[ELF_NREG]; + +/* See linux kernel: arch/loongarch/include/asm/reg.h. */ +enum { + TARGET_EF_R0 = 0, + TARGET_EF_CSR_ERA = TARGET_EF_R0 + 32, + TARGET_EF_CSR_BADVADDR = TARGET_EF_R0 + 33, +}; + +/* See linux kernel: arch/loongarch/kernel/process.c:loongarch_dump_regs64. */ +static void elf_core_copy_regs(target_elf_gregset_t *regs, + const CPULoongArchState *env) +{ + int i; + + for (i = 0; i < TARGET_EF_R0; i++) { + (*regs)[i] = 0; + } + (*regs)[TARGET_EF_R0] = 0; + + for (i = 1; i < ARRAY_SIZE(env->active_tc.gpr); i++) { + (*regs)[TARGET_EF_R0 + i] = tswapreg(env->active_tc.gpr[i]); + } + + (*regs)[TARGET_EF_CSR_ERA] = tswapreg(env->active_tc.PC); + (*regs)[TARGET_EF_CSR_BADVADDR] = tswapreg(env->CSR_BADV); +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#define ELF_HWCAP get_elf_hwcap() + +static uint32_t get_elf_hwcap(void) +{ + return 0; +} + +#endif /* TARGET_LOONGARCH64 */ + #ifdef TARGET_MIPS #define ELF_START_MMAP 0x80000000 diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c new file mode 100644 index 0000000..91f35bc --- /dev/null +++ b/linux-user/loongarch64/cpu_loop.c @@ -0,0 +1,177 @@ +/* + * QEMU LoongArch user cpu loop. + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "qemu.h" +#include "qemu-common.h" +#include "cpu_loop-common.h" +#include "elf.h" + +/* Break codes */ +enum { + BRK_OVERFLOW = 6, + BRK_DIVZERO = 7 +}; + +static int do_break(CPULoongArchState *env, target_siginfo_t *info, + unsigned int code) +{ + int ret = -1; + + switch (code) { + case BRK_OVERFLOW: + case BRK_DIVZERO: + info->si_signo = TARGET_SIGFPE; + info->si_errno = 0; + info->si_code = (code == BRK_OVERFLOW) ? FPE_INTOVF : FPE_INTDIV; + queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); + ret = 0; + break; + default: + info->si_signo = TARGET_SIGTRAP; + info->si_errno = 0; + queue_signal(env, info->si_signo, QEMU_SI_FAULT, &*info); + ret = 0; + break; + } + + return ret; +} + +void cpu_loop(CPULoongArchState *env) +{ + CPUState *cs = CPU(loongarch_env_get_cpu(env)); + target_siginfo_t info; + int trapnr; + abi_long ret; + + for (;;) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + + switch (trapnr) { + case EXCP_SYSCALL: + env->active_tc.PC += 4; + ret = do_syscall(env, env->active_tc.gpr[11], + env->active_tc.gpr[4], env->active_tc.gpr[5], + env->active_tc.gpr[6], env->active_tc.gpr[7], + env->active_tc.gpr[8], env->active_tc.gpr[9], + -1, -1); + if (ret == -TARGET_ERESTARTSYS) { + env->active_tc.PC -= 4; + break; + } + if (ret == -TARGET_QEMU_ESIGRETURN) { + /* + * Returning from a successful sigreturn syscall. + * Avoid clobbering register state. + */ + break; + } + env->active_tc.gpr[4] = ret; + break; + case EXCP_TLBL: + case EXCP_TLBS: + case EXCP_ADE: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = env->CSR_BADV; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + case EXCP_FPDIS: + case EXCP_INE: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = 0; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + case EXCP_FPE: + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_FLTUNK; + if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_INVALID) { + info.si_code = TARGET_FPE_FLTINV; + } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_DIV0) { + info.si_code = TARGET_FPE_FLTDIV; + } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_OVERFLOW) { + info.si_code = TARGET_FPE_FLTOVF; + } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_UNDERFLOW) { + info.si_code = TARGET_FPE_FLTUND; + } else if (GET_FP_CAUSE(env->active_fpu.fcsr0) & FP_INEXACT) { + info.si_code = TARGET_FPE_FLTRES; + } + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + case EXCP_BREAK: + { + abi_ulong trap_instr; + unsigned int code; + + ret = get_user_u32(trap_instr, env->active_tc.PC); + if (ret != 0) { + abort(); + goto error; + } + + code = trap_instr & 0x7fff; + + if (do_break(env, &info, code) != 0) { + abort(); + goto error; + } + } + break; + case EXCP_TRAP: + { + abi_ulong trap_instr; + unsigned int code = 0; + + ret = get_user_u32(trap_instr, env->active_tc.PC); + + if (ret != 0) { + abort(); + goto error; + } + + /* The immediate versions don't provide a code. */ + if (!(trap_instr & 0xFC000000)) { + code = ((trap_instr >> 6) & ((1 << 10) - 1)); + } + + if (do_break(env, &info, code) != 0) { + abort(); + goto error; + } + } + break; + case EXCP_ATOMIC: + cpu_exec_step_atomic(cs); + break; + default: +error: + EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", + trapnr); + abort(); + } + process_pending_signals(env); + } +} + +void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) +{ + int i; + + for (i = 0; i < 32; i++) { + env->active_tc.gpr[i] = regs->regs[i]; + } + env->active_tc.PC = regs->csr_era & ~(target_ulong)1; + +} diff --git a/linux-user/loongarch64/signal.c b/linux-user/loongarch64/signal.c new file mode 100644 index 0000000..716cee3 --- /dev/null +++ b/linux-user/loongarch64/signal.c @@ -0,0 +1,193 @@ +/* + * LoongArch emulation of Linux signals + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "qemu/osdep.h" +#include "qemu.h" +#include "signal-common.h" +#include "linux-user/trace.h" + +#define FPU_REG_WIDTH 256 +union fpureg { + uint32_t val32[FPU_REG_WIDTH / 32]; + uint64_t val64[FPU_REG_WIDTH / 64]; +}; + +struct target_sigcontext { + uint64_t sc_pc; + uint64_t sc_regs[32]; + uint32_t sc_flags; + + uint32_t sc_fcsr; + uint32_t sc_vcsr; + uint64_t sc_fcc; + union fpureg sc_fpregs[32] __attribute__((aligned(32))); + + uint32_t sc_reserved; + +}; + +struct sigframe { + uint32_t sf_ass[4]; /* argument save space for o32 */ + uint32_t sf_code[2]; /* signal trampoline */ + struct target_sigcontext sf_sc; + target_sigset_t sf_mask; +}; + +struct target_ucontext { + target_ulong tuc_flags; + target_ulong tuc_link; + target_stack_t tuc_stack; + target_ulong pad0; + struct target_sigcontext tuc_mcontext; + target_sigset_t tuc_sigmask; +}; + +struct target_rt_sigframe { + uint32_t rs_ass[4]; /* argument save space for o32 */ + uint32_t rs_code[2]; /* signal trampoline */ + struct target_siginfo rs_info; + struct target_ucontext rs_uc; +}; + +/* Install trampoline to jump back from signal handler */ +static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall) +{ + int err = 0; + + /* + * Set up the return code ... + * + * li a7, 139 + * syscall + */ + + __put_user(0x03822c0b, tramp + 0); /* ori a7, a7, 0x8b */ + __put_user(0x002b0000, tramp + 1); /* syscall 0 */ + return err; +} + +static inline void setup_sigcontext(CPULoongArchState *regs, + struct target_sigcontext *sc) +{ + int i; + + __put_user(exception_resume_pc(regs), &sc->sc_pc); + regs->hflags &= ~LOONGARCH_HFLAG_BMASK; + + __put_user(0, &sc->sc_regs[0]); + for (i = 1; i < 32; ++i) { + __put_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); + } + + for (i = 0; i < 32; ++i) { + __put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i].val64[0]); + } +} + +static inline void +restore_sigcontext(CPULoongArchState *regs, struct target_sigcontext *sc) +{ + int i; + + __get_user(regs->CSR_ERA, &sc->sc_pc); + + for (i = 1; i < 32; ++i) { + __get_user(regs->active_tc.gpr[i], &sc->sc_regs[i]); + } + + for (i = 0; i < 32; ++i) { + __get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i].val64[0]); + } +} + +/* + * Determine which stack to use.. + */ +static inline abi_ulong +get_sigframe(struct target_sigaction *ka, CPULoongArchState *regs, + size_t frame_size) +{ + unsigned long sp; + + sp = target_sigsp(get_sp_from_cpustate(regs) - 32, ka); + + return (sp - frame_size) & ~7; +} + +void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPULoongArchState *env) +{ + struct target_rt_sigframe *frame; + abi_ulong frame_addr; + int i; + + frame_addr = get_sigframe(ka, env, sizeof(*frame)); + trace_user_setup_rt_frame(env, frame_addr); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { + goto give_sigsegv; + } + + install_sigtramp(frame->rs_code, TARGET_NR_rt_sigreturn); + + tswap_siginfo(&frame->rs_info, info); + + __put_user(0, &frame->rs_uc.tuc_flags); + __put_user(0, &frame->rs_uc.tuc_link); + target_save_altstack(&frame->rs_uc.tuc_stack, env); + + setup_sigcontext(env, &frame->rs_uc.tuc_mcontext); + + for (i = 0; i < TARGET_NSIG_WORDS; i++) { + __put_user(set->sig[i], &frame->rs_uc.tuc_sigmask.sig[i]); + } + + env->active_tc.gpr[4] = sig; + env->active_tc.gpr[5] = frame_addr + + offsetof(struct target_rt_sigframe, rs_info); + env->active_tc.gpr[6] = frame_addr + + offsetof(struct target_rt_sigframe, rs_uc); + env->active_tc.gpr[3] = frame_addr; + env->active_tc.gpr[1] = frame_addr + + offsetof(struct target_rt_sigframe, rs_code); + + env->active_tc.PC = env->active_tc.gpr[20] = ka->_sa_handler; + unlock_user_struct(frame, frame_addr, 1); + return; + +give_sigsegv: + unlock_user_struct(frame, frame_addr, 1); + force_sigsegv(sig); +} + +long do_rt_sigreturn(CPULoongArchState *env) +{ + struct target_rt_sigframe *frame; + abi_ulong frame_addr; + sigset_t blocked; + + frame_addr = env->active_tc.gpr[3]; + trace_user_do_rt_sigreturn(env, frame_addr); + if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) { + goto badframe; + } + + target_to_host_sigset(&blocked, &frame->rs_uc.tuc_sigmask); + set_sigmask(&blocked); + + restore_sigcontext(env, &frame->rs_uc.tuc_mcontext); + target_restore_altstack(&frame->rs_uc.tuc_stack, env); + + env->active_tc.PC = env->CSR_ERA; + env->CSR_ERA = 0; + return -TARGET_QEMU_ESIGRETURN; + +badframe: + force_sig(TARGET_SIGSEGV); + return -TARGET_QEMU_ESIGRETURN; +} diff --git a/linux-user/loongarch64/sockbits.h b/linux-user/loongarch64/sockbits.h new file mode 100644 index 0000000..0e4c8f0 --- /dev/null +++ b/linux-user/loongarch64/sockbits.h @@ -0,0 +1 @@ +#include "../generic/sockbits.h" diff --git a/linux-user/loongarch64/syscall_nr.h b/linux-user/loongarch64/syscall_nr.h new file mode 100644 index 0000000..64cb17d --- /dev/null +++ b/linux-user/loongarch64/syscall_nr.h @@ -0,0 +1,307 @@ +#ifndef LINUX_USER_LOONGARCH_SYSCALL_NR_H +#define LINUX_USER_LOONGARCH_SYSCALL_NR_H + +/* copy from kernel: include/uapi/asm-generic/unistd.h */ +#define TARGET_NR_io_setup 0 +#define TARGET_NR_io_destroy 1 +#define TARGET_NR_io_submit 2 +#define TARGET_NR_io_cancel 3 +#define TARGET_NR_io_getevents 4 +#define TARGET_NR_setxattr 5 +#define TARGET_NR_lsetxattr 6 +#define TARGET_NR_fsetxattr 7 +#define TARGET_NR_getxattr 8 +#define TARGET_NR_lgetxattr 9 +#define TARGET_NR_fgetxattr 10 +#define TARGET_NR_listxattr 11 +#define TARGET_NR_llistxattr 12 +#define TARGET_NR_flistxattr 13 +#define TARGET_NR_removexattr 14 +#define TARGET_NR_lremovexattr 15 +#define TARGET_NR_fremovexattr 16 +#define TARGET_NR_getcwd 17 +#define TARGET_NR_lookup_dcookie 18 +#define TARGET_NR_eventfd2 19 +#define TARGET_NR_epoll_create1 20 +#define TARGET_NR_epoll_ctl 21 +#define TARGET_NR_epoll_pwait 22 +#define TARGET_NR_dup 23 +#define TARGET_NR_dup3 24 +#define TARGET_NR_fcntl 25 +#define TARGET_NR_inotify_init1 26 +#define TARGET_NR_inotify_add_watch 27 +#define TARGET_NR_inotify_rm_watch 28 +#define TARGET_NR_ioctl 29 +#define TARGET_NR_ioprio_set 30 +#define TARGET_NR_ioprio_get 31 +#define TARGET_NR_flock 32 +#define TARGET_NR_mknodat 33 +#define TARGET_NR_mkdirat 34 +#define TARGET_NR_unlinkat 35 +#define TARGET_NR_symlinkat 36 +#define TARGET_NR_linkat 37 +#define TARGET_NR_renameat 38 +#define TARGET_NR_umount2 39 +#define TARGET_NR_mount 40 +#define TARGET_NR_pivot_root 41 +#define TARGET_NR_nfsservctl 42 +#define TARGET_NR_statfs 43 +#define TARGET_NR_fstatfs 44 +#define TARGET_NR_truncate 45 +#define TARGET_NR_ftruncate 46 +#define TARGET_NR_fallocate 47 +#define TARGET_NR_faccessat 48 +#define TARGET_NR_chdir 49 +#define TARGET_NR_fchdir 50 +#define TARGET_NR_chroot 51 +#define TARGET_NR_fchmod 52 +#define TARGET_NR_fchmodat 53 +#define TARGET_NR_fchownat 54 +#define TARGET_NR_fchown 55 +#define TARGET_NR_openat 56 +#define TARGET_NR_close 57 +#define TARGET_NR_vhangup 58 +#define TARGET_NR_pipe2 59 +#define TARGET_NR_quotactl 60 +#define TARGET_NR_getdents64 61 +#define TARGET_NR_lseek 62 +#define TARGET_NR_read 63 +#define TARGET_NR_write 64 +#define TARGET_NR_readv 65 +#define TARGET_NR_writev 66 +#define TARGET_NR_pread64 67 +#define TARGET_NR_pwrite64 68 +#define TARGET_NR_preadv 69 +#define TARGET_NR_pwritev 70 +#define TARGET_NR_sendfile 71 +#define TARGET_NR_pselect6 72 +#define TARGET_NR_ppoll 73 +#define TARGET_NR_signalfd4 74 +#define TARGET_NR_vmsplice 75 +#define TARGET_NR_splice 76 +#define TARGET_NR_tee 77 +#define TARGET_NR_readlinkat 78 +#define TARGET_NR_newfstatat 79 +#define TARGET_NR_fstat 80 +#define TARGET_NR_sync 81 +#define TARGET_NR_fsync 82 +#define TARGET_NR_fdatasync 83 +#define TARGET_NR_sync_file_range 84 +#define TARGET_NR_timerfd_create 85 +#define TARGET_NR_timerfd_settime 86 +#define TARGET_NR_timerfd_gettime 87 +#define TARGET_NR_utimensat 88 +#define TARGET_NR_acct 89 +#define TARGET_NR_capget 90 +#define TARGET_NR_capset 91 +#define TARGET_NR_personality 92 +#define TARGET_NR_exit 93 +#define TARGET_NR_exit_group 94 +#define TARGET_NR_waitid 95 +#define TARGET_NR_set_tid_address 96 +#define TARGET_NR_unshare 97 +#define TARGET_NR_futex 98 +#define TARGET_NR_set_robust_list 99 +#define TARGET_NR_get_robust_list 100 +#define TARGET_NR_nanosleep 101 +#define TARGET_NR_getitimer 102 +#define TARGET_NR_setitimer 103 +#define TARGET_NR_kexec_load 104 +#define TARGET_NR_init_module 105 +#define TARGET_NR_delete_module 106 +#define TARGET_NR_timer_create 107 +#define TARGET_NR_timer_gettime 108 +#define TARGET_NR_timer_getoverrun 109 +#define TARGET_NR_timer_settime 110 +#define TARGET_NR_timer_delete 111 +#define TARGET_NR_clock_settime 112 +#define TARGET_NR_clock_gettime 113 +#define TARGET_NR_clock_getres 114 +#define TARGET_NR_clock_nanosleep 115 +#define TARGET_NR_syslog 116 +#define TARGET_NR_ptrace 117 +#define TARGET_NR_sched_setparam 118 +#define TARGET_NR_sched_setscheduler 119 +#define TARGET_NR_sched_getscheduler 120 +#define TARGET_NR_sched_getparam 121 +#define TARGET_NR_sched_setaffinity 122 +#define TARGET_NR_sched_getaffinity 123 +#define TARGET_NR_sched_yield 124 +#define TARGET_NR_sched_get_priority_max 125 +#define TARGET_NR_sched_get_priority_min 126 +#define TARGET_NR_sched_rr_get_interval 127 +#define TARGET_NR_restart_syscall 128 +#define TARGET_NR_kill 129 +#define TARGET_NR_tkill 130 +#define TARGET_NR_tgkill 131 +#define TARGET_NR_sigaltstack 132 +#define TARGET_NR_rt_sigsuspend 133 +#define TARGET_NR_rt_sigaction 134 +#define TARGET_NR_rt_sigprocmask 135 +#define TARGET_NR_rt_sigpending 136 +#define TARGET_NR_rt_sigtimedwait 137 +#define TARGET_NR_rt_sigqueueinfo 138 +#define TARGET_NR_rt_sigreturn 139 +#define TARGET_NR_setpriority 140 +#define TARGET_NR_getpriority 141 +#define TARGET_NR_reboot 142 +#define TARGET_NR_setregid 143 +#define TARGET_NR_setgid 144 +#define TARGET_NR_setreuid 145 +#define TARGET_NR_setuid 146 +#define TARGET_NR_setresuid 147 +#define TARGET_NR_getresuid 148 +#define TARGET_NR_setresgid 149 +#define TARGET_NR_getresgid 150 +#define TARGET_NR_setfsuid 151 +#define TARGET_NR_setfsgid 152 +#define TARGET_NR_times 153 +#define TARGET_NR_setpgid 154 +#define TARGET_NR_getpgid 155 +#define TARGET_NR_getsid 156 +#define TARGET_NR_setsid 157 +#define TARGET_NR_getgroups 158 +#define TARGET_NR_setgroups 159 +#define TARGET_NR_uname 160 +#define TARGET_NR_sethostname 161 +#define TARGET_NR_setdomainname 162 +#define TARGET_NR_getrlimit 163 +#define TARGET_NR_setrlimit 164 +#define TARGET_NR_getrusage 165 +#define TARGET_NR_umask 166 +#define TARGET_NR_prctl 167 +#define TARGET_NR_getcpu 168 +#define TARGET_NR_gettimeofday 169 +#define TARGET_NR_settimeofday 170 +#define TARGET_NR_adjtimex 171 +#define TARGET_NR_getpid 172 +#define TARGET_NR_getppid 173 +#define TARGET_NR_getuid 174 +#define TARGET_NR_geteuid 175 +#define TARGET_NR_getgid 176 +#define TARGET_NR_getegid 177 +#define TARGET_NR_gettid 178 +#define TARGET_NR_sysinfo 179 +#define TARGET_NR_mq_open 180 +#define TARGET_NR_mq_unlink 181 +#define TARGET_NR_mq_timedsend 182 +#define TARGET_NR_mq_timedreceive 183 +#define TARGET_NR_mq_notify 184 +#define TARGET_NR_mq_getsetattr 185 +#define TARGET_NR_msgget 186 +#define TARGET_NR_msgctl 187 +#define TARGET_NR_msgrcv 188 +#define TARGET_NR_msgsnd 189 +#define TARGET_NR_semget 190 +#define TARGET_NR_semctl 191 +#define TARGET_NR_semtimedop 192 +#define TARGET_NR_semop 193 +#define TARGET_NR_shmget 194 +#define TARGET_NR_shmctl 195 +#define TARGET_NR_shmat 196 +#define TARGET_NR_shmdt 197 +#define TARGET_NR_socket 198 +#define TARGET_NR_socketpair 199 +#define TARGET_NR_bind 200 +#define TARGET_NR_listen 201 +#define TARGET_NR_accept 202 +#define TARGET_NR_connect 203 +#define TARGET_NR_getsockname 204 +#define TARGET_NR_getpeername 205 +#define TARGET_NR_sendto 206 +#define TARGET_NR_recvfrom 207 +#define TARGET_NR_setsockopt 208 +#define TARGET_NR_getsockopt 209 +#define TARGET_NR_shutdown 210 +#define TARGET_NR_sendmsg 211 +#define TARGET_NR_recvmsg 212 +#define TARGET_NR_readahead 213 +#define TARGET_NR_brk 214 +#define TARGET_NR_munmap 215 +#define TARGET_NR_mremap 216 +#define TARGET_NR_add_key 217 +#define TARGET_NR_request_key 218 +#define TARGET_NR_keyctl 219 +#define TARGET_NR_clone 220 +#define TARGET_NR_execve 221 +#define TARGET_NR_mmap 222 +#define TARGET_NR_fadvise64 223 +#define TARGET_NR_swapon 224 +#define TARGET_NR_swapoff 225 +#define TARGET_NR_mprotect 226 +#define TARGET_NR_msync 227 +#define TARGET_NR_mlock 228 +#define TARGET_NR_munlock 229 +#define TARGET_NR_mlockall 230 +#define TARGET_NR_munlockall 231 +#define TARGET_NR_mincore 232 +#define TARGET_NR_madvise 233 +#define TARGET_NR_remap_file_pages 234 +#define TARGET_NR_mbind 235 +#define TARGET_NR_get_mempolicy 236 +#define TARGET_NR_set_mempolicy 237 +#define TARGET_NR_migrate_pages 238 +#define TARGET_NR_move_pages 239 +#define TARGET_NR_rt_tgsigqueueinfo 240 +#define TARGET_NR_perf_event_open 241 +#define TARGET_NR_accept4 242 +#define TARGET_NR_recvmmsg 243 +#define TARGET_NR_arch_specific_syscall 244 +#define TARGET_NR_wait4 260 +#define TARGET_NR_prlimit64 261 +#define TARGET_NR_fanotify_init 262 +#define TARGET_NR_fanotify_mark 263 +#define TARGET_NR_name_to_handle_at 264 +#define TARGET_NR_open_by_handle_at 265 +#define TARGET_NR_clock_adjtime 266 +#define TARGET_NR_syncfs 267 +#define TARGET_NR_setns 268 +#define TARGET_NR_sendmmsg 269 +#define TARGET_NR_process_vm_readv 270 +#define TARGET_NR_process_vm_writev 271 +#define TARGET_NR_kcmp 272 +#define TARGET_NR_finit_module 273 +#define TARGET_NR_sched_setattr 274 +#define TARGET_NR_sched_getattr 275 +#define TARGET_NR_renameat2 276 +#define TARGET_NR_seccomp 277 +#define TARGET_NR_getrandom 278 +#define TARGET_NR_memfd_create 279 +#define TARGET_NR_bpf 280 +#define TARGET_NR_execveat 281 +#define TARGET_NR_userfaultfd 282 +#define TARGET_NR_membarrier 283 +#define TARGET_NR_mlock2 284 +#define TARGET_NR_copy_file_range 285 +#define TARGET_NR_preadv2 286 +#define TARGET_NR_pwritev2 287 +#define TARGET_NR_pkey_mprotect 288 +#define TARGET_NR_pkey_alloc 289 +#define TARGET_NR_pkey_free 290 +#define TARGET_NR_statx 291 +#define TARGET_NR_io_pgetevents 292 +#define TARGET_NR_rseq 293 +#define TARGET_NR_kexec_file_load 294 +#define TARGET_NR_pidfd_send_signal 424 +#define TARGET_NR_io_uring_setup 425 +#define TARGET_NR_io_uring_enter 426 +#define TARGET_NR_io_uring_register 427 +#define TARGET_NR_open_tree 428 +#define TARGET_NR_move_mount 429 +#define TARGET_NR_fsopen 430 +#define TARGET_NR_fsconfig 431 +#define TARGET_NR_fsmount 432 +#define TARGET_NR_fspick 433 +#define TARGET_NR_pidfd_open 434 +#define TARGET_NR_clone3 435 +#define TARGET_NR_close_range 436 +#define TARGET_NR_openat2 437 +#define TARGET_NR_pidfd_getfd 438 +#define TARGET_NR_faccessat2 439 +#define TARGET_NR_process_madvise 440 +#define TARGET_NR_epoll_pwait2 441 +#define TARGET_NR_mount_setattr 442 + +#define TARGET_NR_syscalls 443 + +#endif diff --git a/linux-user/loongarch64/target_cpu.h b/linux-user/loongarch64/target_cpu.h new file mode 100644 index 0000000..c4c06dd --- /dev/null +++ b/linux-user/loongarch64/target_cpu.h @@ -0,0 +1,36 @@ +/* + * LoongArch specific CPU ABI and functions for linux-user + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef LOONGARCH_TARGET_CPU_H +#define LOONGARCH_TARGET_CPU_H + +static inline void cpu_clone_regs_child(CPULoongArchState *env, + target_ulong newsp, unsigned flags) +{ + if (newsp) { + env->active_tc.gpr[3] = newsp; + } + env->active_tc.gpr[7] = 0; + env->active_tc.gpr[4] = 0; +} + +static inline void cpu_clone_regs_parent(CPULoongArchState *env, + unsigned flags) +{ +} + +static inline void cpu_set_tls(CPULoongArchState *env, target_ulong newtls) +{ + env->active_tc.gpr[2] = newtls; +} + +static inline abi_ulong get_sp_from_cpustate(CPULoongArchState *state) +{ + return state->active_tc.gpr[3]; +} +#endif diff --git a/linux-user/loongarch64/target_elf.h b/linux-user/loongarch64/target_elf.h new file mode 100644 index 0000000..7c88394 --- /dev/null +++ b/linux-user/loongarch64/target_elf.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + + +#ifndef LOONGARCH_TARGET_ELF_H +#define LOONGARCH_TARGET_ELF_H +static inline const char *cpu_get_model(uint32_t eflags) +{ + return "Loongson-3A5000"; +} +#endif diff --git a/linux-user/loongarch64/target_fcntl.h b/linux-user/loongarch64/target_fcntl.h new file mode 100644 index 0000000..b810293 --- /dev/null +++ b/linux-user/loongarch64/target_fcntl.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef LOONGARCH_TARGET_FCNTL_H +#define LOONGARCH_TARGET_FCNTL_H + +#include "../generic/fcntl.h" + +#endif /* LOONGARCH_TARGET_FCNTL_H */ diff --git a/linux-user/loongarch64/target_signal.h b/linux-user/loongarch64/target_signal.h new file mode 100644 index 0000000..713c26a --- /dev/null +++ b/linux-user/loongarch64/target_signal.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef LOONGARCH_TARGET_SIGNAL_H +#define LOONGARCH_TARGET_SIGNAL_H + +/* this struct defines a stack used during syscall handling */ +typedef struct target_sigaltstack { + abi_long ss_sp; + abi_int ss_flags; + abi_ulong ss_size; +} target_stack_t; + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +#include "../generic/signal.h" + +#endif /* LOONGARCH_TARGET_SIGNAL_H */ diff --git a/linux-user/loongarch64/target_structs.h b/linux-user/loongarch64/target_structs.h new file mode 100644 index 0000000..818e8d6 --- /dev/null +++ b/linux-user/loongarch64/target_structs.h @@ -0,0 +1,49 @@ +/* + * LoongArch specific structures for linux-user + * + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef LOONGARCH_TARGET_STRUCTS_H +#define LOONGARCH_TARGET_STRUCTS_H + +struct target_ipc_perm { + abi_int __key; /* Key. */ + abi_uint uid; /* Owner's user ID. */ + abi_uint gid; /* Owner's group ID. */ + abi_uint cuid; /* Creator's user ID. */ + abi_uint cgid; /* Creator's group ID. */ + abi_uint mode; /* Read/write permission. */ + abi_ushort __seq; /* Sequence number. */ + abi_ushort __pad1; + abi_ulong __unused1; + abi_ulong __unused2; +}; + +struct target_shmid_ds { + struct target_ipc_perm shm_perm; /* operation permission struct */ + abi_long shm_segsz; /* size of segment in bytes */ + abi_ulong shm_atime; /* time of last shmat() */ + abi_ulong shm_dtime; /* time of last shmdt() */ + abi_ulong shm_ctime; /* time of last change by shmctl() */ + abi_int shm_cpid; /* pid of creator */ + abi_int shm_lpid; /* pid of last shmop */ + abi_ulong shm_nattch; /* number of current attaches */ + abi_ulong __unused1; + abi_ulong __unused2; +}; + +#define TARGET_SEMID64_DS + +struct target_semid64_ds { + struct target_ipc_perm sem_perm; + abi_ulong sem_otime; + abi_ulong sem_ctime; + abi_ulong sem_nsems; + abi_ulong __unused1; + abi_ulong __unused2; +}; + +#endif diff --git a/linux-user/loongarch64/target_syscall.h b/linux-user/loongarch64/target_syscall.h new file mode 100644 index 0000000..b98ac12 --- /dev/null +++ b/linux-user/loongarch64/target_syscall.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#ifndef LOONGARCH_TARGET_SYSCALL_H +#define LOONGARCH_TARGET_SYSCALL_H + +/* + * this struct defines the way the registers are stored on the + * stack during a system call. + */ + +struct target_pt_regs { + /* Saved main processor registers. */ + target_ulong regs[32]; + + /* Saved special registers. */ + target_ulong csr_crmd; + target_ulong csr_prmd; + target_ulong csr_euen; + target_ulong csr_ecfg; + target_ulong csr_estat; + target_ulong csr_era; + target_ulong csr_badvaddr; + target_ulong orig_a0; + target_ulong __last[0]; +}; + +#define UNAME_MACHINE "loongarch" +#define UNAME_MINIMUM_RELEASE "4.19.0" + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_MCL_CURRENT 1 +#define TARGET_MCL_FUTURE 2 +#define TARGET_MCL_ONFAULT 4 + +#define TARGET_FORCE_SHMLBA + +static inline abi_ulong target_shmlba(CPULoongArchState *env) +{ + return 0x40000; +} + +#endif diff --git a/linux-user/loongarch64/termbits.h b/linux-user/loongarch64/termbits.h new file mode 100644 index 0000000..33e74ed --- /dev/null +++ b/linux-user/loongarch64/termbits.h @@ -0,0 +1,229 @@ +#ifndef LINUX_USER_LOONGARCH_TERMBITS_H +#define LINUX_USER_LOONGARCH_TERMBITS_H + +#define TARGET_NCCS 19 + +typedef unsigned char target_cc_t; /* cc_t */ +typedef unsigned int target_speed_t; /* speed_t */ +typedef unsigned int target_tcflag_t; /* tcflag_t */ + +struct target_termios { + target_tcflag_t c_iflag; /* input mode flags */ + target_tcflag_t c_oflag; /* output mode flags */ + target_tcflag_t c_cflag; /* control mode flags */ + target_tcflag_t c_lflag; /* local mode flags */ + target_cc_t c_line; /* line discipline */ + target_cc_t c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 +#define TARGET_IUTF8 0040000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 +#define TARGET_EXTPROC 0200000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T', 0x30, unsigned int) + /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T', 0x31, int) + /* Lock/unlock Pty */ +#define TARGET_TIOCGPTPEER TARGET_IO('T', 0x41) + /* Safely open the slave */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C + /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D + /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +#endif diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 18b031a..cc263e9 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -74,7 +74,7 @@ || defined(TARGET_M68K) || defined(TARGET_CRIS) \ || defined(TARGET_S390X) || defined(TARGET_OPENRISC) \ || defined(TARGET_NIOS2) || defined(TARGET_RISCV) \ - || defined(TARGET_XTENSA) + || defined(TARGET_XTENSA) || defined(TARGET_LOONGARCH64) #define TARGET_IOC_SIZEBITS 14 #define TARGET_IOC_DIRBITS 2 @@ -2129,7 +2129,8 @@ struct target_stat64 { abi_ulong __unused5; }; -#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || defined(TARGET_RISCV) +#elif defined(TARGET_OPENRISC) || defined(TARGET_NIOS2) || \ + defined(TARGET_RISCV) || defined(TARGET_LOONGARCH64) /* These are the asm-generic versions of the stat and stat64 structures */ @@ -2327,7 +2328,8 @@ struct target_statfs64 { }; #elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \ defined(TARGET_SPARC64) || defined(TARGET_AARCH64) || \ - defined(TARGET_RISCV)) && !defined(TARGET_ABI32) + defined(TRAGET_RISCV) || defined(TARGET_LOONGARCH64)) && \ + !defined(TARGET_ABI32) struct target_statfs { abi_long f_type; abi_long f_bsize; diff --git a/meson.build b/meson.build index 0211442..5f46f21 100644 --- a/meson.build +++ b/meson.build @@ -57,7 +57,7 @@ python = import('python').find_installation() supported_oses = ['windows', 'freebsd', 'netbsd', 'openbsd', 'darwin', 'sunos', 'linux'] supported_cpus = ['ppc', 'ppc64', 's390x', 'riscv32', 'riscv64', 'x86', 'x86_64', - 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64'] + 'arm', 'aarch64', 'mips', 'mips64', 'sparc', 'sparc64', 'loongarch64'] cpu = host_machine.cpu_family() targetos = host_machine.system() diff --git a/qapi/machine-target.json b/qapi/machine-target.json index e781165..22a4c4a 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -316,7 +316,7 @@ 'typename': 'str', '*alias-of' : 'str', 'deprecated' : 'bool' }, - 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS)' } + 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS) || defined(TARGET_LOONGARCH)' } ## # @query-cpu-definitions: @@ -328,4 +328,4 @@ # Since: 1.2 ## { 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'], - 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS)' } + 'if': 'defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_I386) || defined(TARGET_S390X) || defined(TARGET_MIPS) || defined(TARGET_LOONGARCH)' } diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build new file mode 100644 index 0000000..54d5ca2 --- /dev/null +++ b/target/loongarch/meson.build @@ -0,0 +1,19 @@ +gen = decodetree.process('insns.decode') + +loongarch_ss = ss.source_set() +loongarch_ss.add(files( + 'cpu.c', +)) +loongarch_tcg_ss = ss.source_set() +loongarch_tcg_ss.add(gen) +loongarch_tcg_ss.add(files( + 'fpu_helper.c', + 'op_helper.c', + 'tlb_helper.c', + 'translate.c', +)) +loongarch_tcg_ss.add(zlib) + +loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss]) + +target_arch += {'loongarch': loongarch_ss} diff --git a/target/meson.build b/target/meson.build index 2f69402..a53a604 100644 --- a/target/meson.build +++ b/target/meson.build @@ -5,6 +5,7 @@ subdir('cris') subdir('hexagon') subdir('hppa') subdir('i386') +subdir('loongarch') subdir('m68k') subdir('microblaze') subdir('mips')