summaryrefslogtreecommitdiffstats
path: root/target/mips/tcg/ldst_helper.c
diff options
context:
space:
mode:
authorPeter Maydell2021-05-03 13:05:11 +0200
committerPeter Maydell2021-05-03 13:05:12 +0200
commite93d8bcf9dbd5b8dd3b9ddbb1ece6a37e608f300 (patch)
tree2884b98954f0eb8572a467550fe4d9b43c1212d1 /target/mips/tcg/ldst_helper.c
parentMerge remote-tracking branch 'remotes/rth-gitlab/tags/pull-hex-20210502' into... (diff)
parentgitlab-ci: Add KVM mips64el cross-build jobs (diff)
downloadqemu-e93d8bcf9dbd5b8dd3b9ddbb1ece6a37e608f300.tar.gz
qemu-e93d8bcf9dbd5b8dd3b9ddbb1ece6a37e608f300.tar.xz
qemu-e93d8bcf9dbd5b8dd3b9ddbb1ece6a37e608f300.zip
Merge remote-tracking branch 'remotes/philmd/tags/mips-20210502' into staging
MIPS patches queue - Fix CACHEE opcode - Add missing CP0 checks to nanoMIPS RDPGPR / WRPGPR opcodes - Remove isa_get_irq() call in PIIX4 south bridge - Add various missing fields to the MIPS CPU migration vmstate - Lot of code moved around to allow TCG or KVM only builds - Restrict non-virtualized machines to TCG - Add KVM mips64el cross-build jobs to gitlab-ci # gpg: Signature made Sun 02 May 2021 15:56:51 BST # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] # Primary key fingerprint: FAAB E75E 1291 7221 DCFD 6BB2 E3E3 2C2C DEAD C0DE * remotes/philmd/tags/mips-20210502: (36 commits) gitlab-ci: Add KVM mips64el cross-build jobs hw/mips: Restrict non-virtualized machines to TCG target/mips: Move TCG source files under tcg/ sub directory target/mips: Move CP0 helpers to sysemu/cp0.c target/mips: Move exception management code to exception.c target/mips: Move TLB management helpers to tcg/sysemu/tlb_helper.c target/mips: Move helper_cache() to tcg/sysemu/special_helper.c target/mips: Move Special opcodes to tcg/sysemu/special_helper.c target/mips: Restrict CPUMIPSTLBContext::map_address() handlers scope target/mips: Move tlb_helper.c to tcg/sysemu/ target/mips: Restrict mmu_init() to TCG target/mips: Move sysemu TCG-specific code to tcg/sysemu/ subfolder target/mips: Restrict cpu_mips_get_random() / update_pagemask() to TCG target/mips: Move physical addressing code to sysemu/physaddr.c target/mips: Move sysemu specific files under sysemu/ subfolder target/mips: Move cpu_signal_handler definition around target/mips: Add simple user-mode mips_cpu_tlb_fill() target/mips: Add simple user-mode mips_cpu_do_interrupt() target/mips: Introduce tcg-internal.h for TCG specific declarations meson: Introduce meson_user_arch source set for arch-specific user-mode ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/mips/tcg/ldst_helper.c')
-rw-r--r--target/mips/tcg/ldst_helper.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/target/mips/tcg/ldst_helper.c b/target/mips/tcg/ldst_helper.c
new file mode 100644
index 0000000000..d42812b8a6
--- /dev/null
+++ b/target/mips/tcg/ldst_helper.c
@@ -0,0 +1,288 @@
+/*
+ * MIPS emulation load/store helpers for QEMU.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/memop.h"
+#include "internal.h"
+
+#ifndef CONFIG_USER_ONLY
+
+#define HELPER_LD_ATOMIC(name, insn, almask, do_cast) \
+target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \
+{ \
+ if (arg & almask) { \
+ if (!(env->hflags & MIPS_HFLAG_DM)) { \
+ env->CP0_BadVAddr = arg; \
+ } \
+ do_raise_exception(env, EXCP_AdEL, GETPC()); \
+ } \
+ env->CP0_LLAddr = cpu_mips_translate_address(env, arg, MMU_DATA_LOAD, \
+ GETPC()); \
+ env->lladdr = arg; \
+ env->llval = do_cast cpu_##insn##_mmuidx_ra(env, arg, mem_idx, GETPC()); \
+ return env->llval; \
+}
+HELPER_LD_ATOMIC(ll, ldl, 0x3, (target_long)(int32_t))
+#ifdef TARGET_MIPS64
+HELPER_LD_ATOMIC(lld, ldq, 0x7, (target_ulong))
+#endif
+#undef HELPER_LD_ATOMIC
+
+#endif /* !CONFIG_USER_ONLY */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK(v) ((v) & 3)
+#define GET_OFFSET(addr, offset) (addr + (offset))
+#else
+#define GET_LMASK(v) (((v) & 3) ^ 3)
+#define GET_OFFSET(addr, offset) (addr - (offset))
+#endif
+
+void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
+ int mem_idx)
+{
+ cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 24), mem_idx, GETPC());
+
+ if (GET_LMASK(arg2) <= 2) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK(arg2) <= 1) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK(arg2) == 0) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)arg1,
+ mem_idx, GETPC());
+ }
+}
+
+void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
+ int mem_idx)
+{
+ cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
+
+ if (GET_LMASK(arg2) >= 1) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK(arg2) >= 2) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK(arg2) == 3) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24),
+ mem_idx, GETPC());
+ }
+}
+
+#if defined(TARGET_MIPS64)
+/*
+ * "half" load and stores. We must do the memory access inline,
+ * or fault handling won't work.
+ */
+#ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK64(v) ((v) & 7)
+#else
+#define GET_LMASK64(v) (((v) & 7) ^ 7)
+#endif
+
+void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
+ int mem_idx)
+{
+ cpu_stb_mmuidx_ra(env, arg2, (uint8_t)(arg1 >> 56), mem_idx, GETPC());
+
+ if (GET_LMASK64(arg2) <= 6) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 5) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 4) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 3) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 2) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 1) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) <= 0) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, 7), (uint8_t)arg1,
+ mem_idx, GETPC());
+ }
+}
+
+void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2,
+ int mem_idx)
+{
+ cpu_stb_mmuidx_ra(env, arg2, (uint8_t)arg1, mem_idx, GETPC());
+
+ if (GET_LMASK64(arg2) >= 1) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 2) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 3) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 4) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 5) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) >= 6) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48),
+ mem_idx, GETPC());
+ }
+
+ if (GET_LMASK64(arg2) == 7) {
+ cpu_stb_mmuidx_ra(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56),
+ mem_idx, GETPC());
+ }
+}
+#endif /* TARGET_MIPS64 */
+
+static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
+
+void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
+ uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ env->active_tc.gpr[multiple_regs[i]] =
+ (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
+ addr += 4;
+ }
+ }
+
+ if (do_r31) {
+ env->active_tc.gpr[31] =
+ (target_long)cpu_ldl_mmuidx_ra(env, addr, mem_idx, GETPC());
+ }
+}
+
+void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
+ uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
+ mem_idx, GETPC());
+ addr += 4;
+ }
+ }
+
+ if (do_r31) {
+ cpu_stw_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
+ }
+}
+
+#if defined(TARGET_MIPS64)
+void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
+ uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ env->active_tc.gpr[multiple_regs[i]] =
+ cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
+ addr += 8;
+ }
+ }
+
+ if (do_r31) {
+ env->active_tc.gpr[31] =
+ cpu_ldq_mmuidx_ra(env, addr, mem_idx, GETPC());
+ }
+}
+
+void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist,
+ uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE(multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[multiple_regs[i]],
+ mem_idx, GETPC());
+ addr += 8;
+ }
+ }
+
+ if (do_r31) {
+ cpu_stq_mmuidx_ra(env, addr, env->active_tc.gpr[31], mem_idx, GETPC());
+ }
+}
+
+#endif /* TARGET_MIPS64 */