mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-05 07:17:45 -04:00
sh2 drc: add mipsel backend for MIPS32 Release 1 (for JZ47xx)
This commit is contained in:
parent
1747b6712d
commit
d80a5fd2ab
13 changed files with 1922 additions and 23 deletions
5
Makefile
5
Makefile
|
@ -55,6 +55,9 @@ use_cz80 ?= 1
|
|||
ifneq (,$(findstring 86,$(ARCH)))
|
||||
use_sh2drc ?= 1
|
||||
endif
|
||||
ifneq (,$(findstring mips,$(ARCH)))
|
||||
use_sh2drc ?= 1
|
||||
endif
|
||||
endif
|
||||
|
||||
-include Makefile.local
|
||||
|
@ -245,7 +248,7 @@ pico/carthw_cfg.c: pico/carthw.cfg
|
|||
# random deps
|
||||
pico/carthw/svp/compiler.o : cpu/drc/emit_arm.c
|
||||
cpu/sh2/compiler.o : cpu/drc/emit_arm.c
|
||||
cpu/sh2/compiler.o : cpu/drc/emit_x86.c
|
||||
cpu/sh2/compiler.o : cpu/drc/emit_x86.c cpu/drc/emit_mips.c
|
||||
cpu/sh2/mame/sh2pico.o : cpu/sh2/mame/sh2.c
|
||||
pico/pico.o pico/cd/mcd.o pico/32x/32x.o : pico/pico_cmn.c pico/pico_int.h
|
||||
pico/memory.o pico/cd/memory.o pico/32x/memory.o : pico/pico_int.h pico/memory.h
|
||||
|
|
16
config.gcw0
Normal file
16
config.gcw0
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Automatically generated by configure
|
||||
# Configured with: './configure' '--platform=generic'
|
||||
CC = mipsel-gcw0-linux-uclibc-gcc
|
||||
CXX = mipsel-gcw0-linux-uclibc-g++
|
||||
AS = mipsel-gcw0-linux-uclibc-as
|
||||
STRIP = mipsel-gcw0-linux-uclibc-strip
|
||||
CFLAGS += -I${HOME}/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/include/
|
||||
CFLAGS += -I${HOME}/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/include/SDL
|
||||
CFLAGS += -D_GNU_SOURCE=1 -D_REENTRANT -Wno-unused-result -fno-stack-protector
|
||||
ASFLAGS +=
|
||||
LDFLAGS +=
|
||||
LDLIBS += -B${HOME}/opt/gcw0-toolchain/usr/lib -Wl,-rpath-link=${HOME}/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/usr/lib -Wl,-rpath-link=${HOME}/opt/gcw0-toolchain/usr/mipsel-gcw0-linux-uclibc/sysroot/lib -lSDL -lasound -lpng -lz -lm -lstdc++ -ldl
|
||||
|
||||
ARCH = mipsel
|
||||
PLATFORM = opendingux
|
||||
SOUND_DRIVERS = sdl
|
|
@ -1098,11 +1098,14 @@ static inline void emith_pool_adjust(int pool_index, int move_offs)
|
|||
#define emith_jump_cond_patchable(cond, target) \
|
||||
emith_jump_cond(cond, target)
|
||||
|
||||
#define emith_jump_patch(ptr, target) do { \
|
||||
#define emith_jump_patch(ptr, target) ({ \
|
||||
u32 *ptr_ = ptr; \
|
||||
u32 val_ = (u32 *)(target) - ptr_ - 2; \
|
||||
*ptr_ = (*ptr_ & 0xff000000) | (val_ & 0x00ffffff); \
|
||||
} while (0)
|
||||
(u8 *)ptr; \
|
||||
})
|
||||
|
||||
#define emith_jump_patch_size() 4
|
||||
|
||||
#define emith_jump_at(ptr, target) do { \
|
||||
u32 val_ = (u32 *)(target) - (u32 *)(ptr) - 2; \
|
||||
|
|
1464
cpu/drc/emit_mips.c
Normal file
1464
cpu/drc/emit_mips.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -869,11 +869,14 @@ enum { xAX = 0, xCX, xDX, xBX, xSP, xBP, xSI, xDI, // x86-64,i386 common
|
|||
#define emith_jump_cond_patchable(cond, target) \
|
||||
emith_jump_cond(cond, target)
|
||||
|
||||
#define emith_jump_patch(ptr, target) do { \
|
||||
#define emith_jump_patch(ptr, target) ({ \
|
||||
u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 4); \
|
||||
u32 offs_ = (*(u8 *)(ptr) == 0x0f) ? 2 : 1; \
|
||||
EMIT_PTR((u8 *)(ptr) + offs_, disp_ - offs_, u32); \
|
||||
} while (0)
|
||||
ptr; \
|
||||
})
|
||||
|
||||
#define emith_jump_patch_size() 6
|
||||
|
||||
#define emith_jump_at(ptr, target) do { \
|
||||
u32 disp_ = (u8 *)(target) - ((u8 *)(ptr) + 5); \
|
||||
|
|
|
@ -466,6 +466,47 @@ static cache_reg_t cache_regs[] = {
|
|||
{ 7, HRF_REG },
|
||||
};
|
||||
|
||||
#elif defined(__mips__)
|
||||
#include "../drc/emit_mips.c"
|
||||
|
||||
static guest_reg_t guest_regs[] = {
|
||||
// SHR_R0 .. SHR_SP
|
||||
{GRF_STATIC, 20} , {GRF_STATIC, 21} , { 0 } , { 0 } ,
|
||||
{ 0 } , { 0 } , { 0 } , { 0 } ,
|
||||
{ 0 } , { 0 } , { 0 } , { 0 } ,
|
||||
{ 0 } , { 0 } , { 0 } , { 0 } ,
|
||||
// SHR_PC, SHR_PPC, SHR_PR, SHR_SR,
|
||||
// SHR_GBR, SHR_VBR, SHR_MACH, SHR_MACL,
|
||||
{ 0 } , { 0 } , { 0 } , {GRF_STATIC, 22} ,
|
||||
{ 0 } , { 0 } , { 0 } , { 0 } ,
|
||||
};
|
||||
|
||||
// MIPS ABI: params: r4-r7, return: r2-r3, temp: r1(at),r8-r15,r24-r25,r31(ra),
|
||||
// saved: r16-r23,r30, reserved: r0(zero), r26-r27(irq), r28(gp), r29(sp)
|
||||
// r1,r15,r24,r25 are used internally by the code emitter
|
||||
static cache_reg_t cache_regs[] = {
|
||||
{ 14, HRF_TEMP }, // temps
|
||||
{ 13, HRF_TEMP },
|
||||
{ 12, HRF_TEMP },
|
||||
{ 11, HRF_TEMP },
|
||||
{ 10, HRF_TEMP },
|
||||
{ 9, HRF_TEMP },
|
||||
{ 8, HRF_TEMP },
|
||||
{ 7, HRF_TEMP }, // params
|
||||
{ 6, HRF_TEMP },
|
||||
{ 5, HRF_TEMP },
|
||||
{ 4, HRF_TEMP },
|
||||
{ 3, HRF_TEMP }, // RET_REG
|
||||
{ 2, HRF_TEMP },
|
||||
{ 22, HRF_LOCKED }, // statics
|
||||
{ 21, HRF_LOCKED },
|
||||
{ 20, HRF_LOCKED },
|
||||
{ 19, HRF_REG }, // other regs
|
||||
{ 18, HRF_REG },
|
||||
{ 17, HRF_REG },
|
||||
{ 16, HRF_REG },
|
||||
};
|
||||
|
||||
#elif defined(__i386__)
|
||||
#include "../drc/emit_x86.c"
|
||||
|
||||
|
@ -1050,9 +1091,12 @@ static void dr_block_link(struct block_entry *be, struct block_link *bl, int emi
|
|||
dbg(2, "- %slink from %p to pc %08x entry %p", emit_jump ? "":"early ",
|
||||
bl->jump, bl->target_pc, be->tcache_ptr);
|
||||
|
||||
if (emit_jump)
|
||||
emith_jump_patch(bl->jump, be->tcache_ptr);
|
||||
// could sync arm caches here, but that's unnecessary
|
||||
if (emit_jump) {
|
||||
u8 *jump = emith_jump_patch(bl->jump, be->tcache_ptr);
|
||||
// only needs sync if patch is possibly crossing cacheline (assume 16 byte)
|
||||
if ((uintptr_t)jump >>4 != ((uintptr_t)jump+emith_jump_patch_size()-1) >>4)
|
||||
host_instructions_updated(jump, jump+emith_jump_patch_size());
|
||||
}
|
||||
|
||||
// move bl to block_entry
|
||||
bl->target = be;
|
||||
|
@ -1069,9 +1113,9 @@ static void dr_block_unlink(struct block_link *bl, int emit_jump)
|
|||
|
||||
if (bl->target) {
|
||||
if (emit_jump) {
|
||||
emith_jump_patch(bl->jump, sh2_drc_dispatcher);
|
||||
u8 *jump = emith_jump_patch(bl->jump, sh2_drc_dispatcher);
|
||||
// update cpu caches since the previous jump target doesn't exist anymore
|
||||
host_instructions_updated(bl->jump, bl->jump+4);
|
||||
host_instructions_updated(jump, jump+emith_jump_patch_size());
|
||||
}
|
||||
|
||||
if (bl->prev)
|
||||
|
@ -4128,8 +4172,9 @@ end_op:
|
|||
struct op_data *opd_b = (op_flags[i] & OF_DELAY_OP) ? opd-1 : opd;
|
||||
u32 target_pc = opd_b->imm;
|
||||
int cond = -1;
|
||||
void *target = NULL;
|
||||
int ctaken = 0;
|
||||
void *target = NULL;
|
||||
int patchable = 0;
|
||||
|
||||
if (OP_ISBRACND(opd_b->op))
|
||||
ctaken = (op_flags[i] & OF_DELAY_OP) ? 1 : 2;
|
||||
|
@ -4182,11 +4227,12 @@ end_op:
|
|||
branch_patch_pc[branch_patch_count] = target_pc;
|
||||
branch_patch_ptr[branch_patch_count] = target;
|
||||
branch_patch_count++;
|
||||
}
|
||||
else
|
||||
patchable = 1;
|
||||
} else
|
||||
dbg(1, "warning: too many local branches");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (target == NULL)
|
||||
{
|
||||
// can't resolve branch locally, make a block exit
|
||||
|
@ -4204,15 +4250,25 @@ end_op:
|
|||
} else
|
||||
#endif
|
||||
target = dr_prepare_ext_branch(block->entryp, target_pc, sh2->is_slave, tcache_id);
|
||||
patchable = 1;
|
||||
}
|
||||
|
||||
if (cond != -1) {
|
||||
// create branch
|
||||
if (patchable) {
|
||||
if (cond != -1)
|
||||
emith_jump_cond_patchable(cond, target);
|
||||
}
|
||||
else if (target != NULL) {
|
||||
rcache_invalidate();
|
||||
emith_jump_patchable(target);
|
||||
}
|
||||
} else {
|
||||
if (cond != -1)
|
||||
emith_jump_cond(cond, target);
|
||||
else if (target != NULL) {
|
||||
rcache_invalidate();
|
||||
emith_jump(target);
|
||||
}
|
||||
}
|
||||
|
||||
// branch not taken, correct cycle count
|
||||
if (ctaken)
|
||||
|
|
|
@ -36,6 +36,8 @@ unsigned short scan_block(unsigned int base_pc, int is_slave,
|
|||
// XXX MUST match definitions in cpu/sh2/compiler.c
|
||||
#if defined(__arm__)
|
||||
#define DRC_SR_REG r10
|
||||
#elif defined(__mips__)
|
||||
#define DRC_SR_REG s6
|
||||
#elif defined(__i386__)
|
||||
#define DRC_SR_REG edi
|
||||
#elif defined(__x86_64__)
|
||||
|
|
|
@ -169,7 +169,7 @@ DEFINES += DRC_DEBUG=$(drc_debug)
|
|||
SRCS_COMMON += $(R)cpu/sh2/mame/sh2dasm.c
|
||||
DASM = $(R)platform/libpicofe/linux/host_dasm.c
|
||||
DASMLIBS = -lbfd -lopcodes -liberty
|
||||
ifeq "$(ARCH)" "arm"
|
||||
ifeq ("$(ARCH)",$(filter "$(ARCH)","arm" "mipsel"))
|
||||
ifeq ($(filter_out $(shell $(CC) --print-file-name=libbfd.so),"/"),)
|
||||
DASM = $(R)platform/common/host_dasm.c
|
||||
DASMLIBS =
|
||||
|
|
|
@ -435,7 +435,7 @@ static int software_interrupt(unsigned int pc, unsigned int insn, char *buf, siz
|
|||
return 1;
|
||||
}
|
||||
|
||||
int disarm(unsigned int pc, unsigned int insn, char *buf, size_t buf_len)
|
||||
int disarm(uintptr_t pc, uint32_t insn, char *buf, size_t buf_len)
|
||||
{
|
||||
if ((insn & 0x0fffffd0) == 0x012fff10)
|
||||
return branch_and_exchange(pc, insn, buf, buf_len);
|
||||
|
|
|
@ -23,6 +23,6 @@
|
|||
#ifndef DISARM_H
|
||||
#define DISARM_H
|
||||
|
||||
int disarm(unsigned int pc, unsigned int insn, char *buf, unsigned int buf_len);
|
||||
int disarm(uintptr_t long pc, uint32_t, char *buf, unsigned int buf_len);
|
||||
|
||||
#endif /* DISARM_H */
|
||||
|
|
346
platform/common/dismips.c
Normal file
346
platform/common/dismips.c
Normal file
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* very basic mips disassembler for MIPS32/MIPS64 Release 1, only for picodrive
|
||||
* Copyright (C) 2019 kub
|
||||
*
|
||||
* This work is licensed under the terms of MAME license.
|
||||
* See COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
// XXX unimplemented: SYSCALL, BREAK, SYNC, SDBBP, T*, CACHE, PREF,
|
||||
// MOVF/MOVT, LWC*/LDC*, SWC*/SDC*, COP*.
|
||||
// however, it's certainly good enough for anything picodrive DRC throws at it.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dismips.h"
|
||||
|
||||
|
||||
static char *const register_names[32] = {
|
||||
"$zero",
|
||||
"$at",
|
||||
"$v0",
|
||||
"$v1",
|
||||
"$a0",
|
||||
"$a1",
|
||||
"$a2",
|
||||
"$a3",
|
||||
"$t0",
|
||||
"$t1",
|
||||
"$t2",
|
||||
"$t3",
|
||||
"$t4",
|
||||
"$t5",
|
||||
"$t6",
|
||||
"$t7",
|
||||
"$s0",
|
||||
"$s1",
|
||||
"$s2",
|
||||
"$s3",
|
||||
"$s4",
|
||||
"$s5",
|
||||
"$s6",
|
||||
"$s7",
|
||||
"$t8",
|
||||
"$t9",
|
||||
"$k0",
|
||||
"$k1",
|
||||
"$gp",
|
||||
"$sp",
|
||||
"$fp",
|
||||
"$ra"
|
||||
};
|
||||
|
||||
|
||||
enum insn_type {
|
||||
REG_DTS, REG_TS, // 3, 2, or 1 regs
|
||||
REG_DS, REG_D, REG_S,
|
||||
S_IMM_DT, // 2 regs with shift amount
|
||||
B_IMM_S, B_IMM_TS, // pc-relative branches with 1 or 2 regs
|
||||
J_IMM, // region-relative jump
|
||||
A_IMM_TS, // arithmetic immediate with 1 or 2 regs
|
||||
L_IMM_T, L_IMM_TS, // logical immediate with 2 regs
|
||||
M_IMM_TS, // memory indexed with 2 regs
|
||||
};
|
||||
|
||||
struct insn {
|
||||
unsigned char op;
|
||||
enum insn_type type;
|
||||
char *name;
|
||||
};
|
||||
|
||||
// ATTN: these array MUST be sorted by op (decode relies on it)
|
||||
|
||||
// instructions with opcode SPECIAL (R-type)
|
||||
#define OP_SPECIAL 0x00
|
||||
static const struct insn special_insns[] = {
|
||||
{0x00, S_IMM_DT, "sll"},
|
||||
{0x02, S_IMM_DT, "srl"},
|
||||
{0x03, S_IMM_DT, "sra"},
|
||||
{0x04, REG_DTS, "sllv"},
|
||||
{0x06, REG_DTS, "srlv"},
|
||||
{0x07, REG_DTS, "srav"},
|
||||
{0x08, REG_S, "jr"},
|
||||
{0x09, REG_DS, "jalr"},
|
||||
{0x0a, REG_DTS, "movz"},
|
||||
{0x0b, REG_DTS, "movn"},
|
||||
// {0x0c, , "syscall"},
|
||||
// {0x0d, , "break"},
|
||||
// {0x0f, , "sync"},
|
||||
{0x10, REG_D, "mfhi"},
|
||||
{0x11, REG_S, "mthi"},
|
||||
{0x12, REG_D, "mflo"},
|
||||
{0x13, REG_S, "mtlo"},
|
||||
{0x14, REG_DTS, "dsllv"},
|
||||
{0x16, REG_DTS, "dslrv"},
|
||||
{0x17, REG_DTS, "dsrav"},
|
||||
{0x18, REG_TS, "mult"},
|
||||
{0x19, REG_TS, "multu"},
|
||||
{0x1A, REG_TS, "div"},
|
||||
{0x1B, REG_TS, "divu"},
|
||||
{0x1C, REG_TS, "dmult"},
|
||||
{0x1D, REG_TS, "dmultu"},
|
||||
{0x1E, REG_TS, "ddiv"},
|
||||
{0x1F, REG_TS, "ddivu"},
|
||||
{0x20, REG_DTS, "add"},
|
||||
{0x21, REG_DTS, "addu"},
|
||||
{0x22, REG_DTS, "sub"},
|
||||
{0x23, REG_DTS, "subu"},
|
||||
{0x24, REG_DTS, "and"},
|
||||
{0x25, REG_DTS, "or"},
|
||||
{0x26, REG_DTS, "xor"},
|
||||
{0x27, REG_DTS, "nor"},
|
||||
{0x2A, REG_DTS, "slt"},
|
||||
{0x2B, REG_DTS, "sltu"},
|
||||
{0x2C, REG_DTS, "dadd"},
|
||||
{0x2D, REG_DTS, "daddu"},
|
||||
{0x2E, REG_DTS, "dsub"},
|
||||
{0x2F, REG_DTS, "dsubu"},
|
||||
// {0x30, REG_TS, "tge" },
|
||||
// {0x31, REG_TS, "tgeu" },
|
||||
// {0x32, REG_TS, "tlt" },
|
||||
// {0x33, REG_TS, "tltu" },
|
||||
// {0x34, REG_TS, "teq" },
|
||||
// {0x36, REG_TS, "tne" },
|
||||
{0x38, S_IMM_DT, "dsll"},
|
||||
{0x3A, S_IMM_DT, "dsrl"},
|
||||
{0x3B, S_IMM_DT, "dsra"},
|
||||
{0x3D, S_IMM_DT, "dsll32"},
|
||||
{0x3E, S_IMM_DT, "dsrl32"},
|
||||
{0x3F, S_IMM_DT, "dsra32"},
|
||||
};
|
||||
|
||||
// instructions with opcode SPECIAL2 (R-type)
|
||||
#define OP_SPECIAL2 0x1C
|
||||
static const struct insn special2_insns[] = {
|
||||
{0x00, REG_TS, "madd" },
|
||||
{0x01, REG_TS, "maddu" },
|
||||
{0x02, REG_TS, "mul" },
|
||||
{0x04, REG_TS, "msub" },
|
||||
{0x05, REG_TS, "msubu" },
|
||||
{0x20, REG_DS, "clz" },
|
||||
{0x21, REG_DS, "clo" },
|
||||
{0x24, REG_DS, "dclz" },
|
||||
{0x25, REG_DS, "dclo" },
|
||||
};
|
||||
|
||||
// instructions with opcode REGIMM (I-type)
|
||||
#define OP_REGIMM 0x01
|
||||
static const struct insn regimm_insns[] = {
|
||||
{0x00, B_IMM_S, "bltz"},
|
||||
{0x01, B_IMM_S, "bgez"},
|
||||
{0x02, B_IMM_S, "bltzl"},
|
||||
{0x03, B_IMM_S, "bgezl"},
|
||||
// {0x08, , "tgei"},
|
||||
// {0x09, , "tgeiu"},
|
||||
// {0x0a, , "tlti"},
|
||||
// {0x0b, , "tltiu"},
|
||||
// {0x0c, , "teqi"},
|
||||
// {0x0e, , "tnei"},
|
||||
{0x10, B_IMM_S, "bltzal"},
|
||||
{0x11, B_IMM_S, "bgezal"},
|
||||
{0x12, B_IMM_S, "bltzall"},
|
||||
{0x13, B_IMM_S, "bgezall"},
|
||||
{0x13, B_IMM_S, "bgezall"},
|
||||
};
|
||||
|
||||
// instructions with other opcodes (I-type)
|
||||
static const struct insn immediate_insns[] = {
|
||||
{0x02, J_IMM, "j"},
|
||||
{0x03, J_IMM, "jal"},
|
||||
{0x04, B_IMM_TS, "beq"},
|
||||
{0x05, B_IMM_TS, "bne"},
|
||||
{0x06, B_IMM_S, "blez"},
|
||||
{0x07, B_IMM_S, "bgtz"},
|
||||
{0x08, A_IMM_TS, "addi"},
|
||||
{0x09, A_IMM_TS, "addiu"},
|
||||
{0x0A, A_IMM_TS, "slti"},
|
||||
{0x0B, A_IMM_TS, "sltiu"},
|
||||
{0x0C, L_IMM_TS, "andi"},
|
||||
{0x0D, L_IMM_TS, "ori"},
|
||||
{0x0E, L_IMM_TS, "xori"},
|
||||
{0x0F, L_IMM_T, "lui"},
|
||||
{0x14, B_IMM_TS, "beql"},
|
||||
{0x15, B_IMM_TS, "bnel"},
|
||||
{0x16, B_IMM_S, "blezl"},
|
||||
{0x17, B_IMM_S, "bgtzl"},
|
||||
{0x18, A_IMM_TS, "daddi"},
|
||||
{0x19, A_IMM_TS, "daddiu"},
|
||||
{0x1A, M_IMM_TS, "ldl"},
|
||||
{0x1B, M_IMM_TS, "ldr"},
|
||||
{0x20, M_IMM_TS, "lb"},
|
||||
{0x21, M_IMM_TS, "lh"},
|
||||
{0x22, M_IMM_TS, "lwl"},
|
||||
{0x23, M_IMM_TS, "lw"},
|
||||
{0x24, M_IMM_TS, "lbu"},
|
||||
{0x25, M_IMM_TS, "lhu"},
|
||||
{0x26, M_IMM_TS, "lwr"},
|
||||
{0x27, M_IMM_TS, "lwu"},
|
||||
{0x28, M_IMM_TS, "sb"},
|
||||
{0x29, M_IMM_TS, "sh"},
|
||||
{0x2A, M_IMM_TS, "swl"},
|
||||
{0x2B, M_IMM_TS, "sw"},
|
||||
{0x2C, M_IMM_TS, "sdl"},
|
||||
{0x2D, M_IMM_TS, "sdr"},
|
||||
{0x2E, M_IMM_TS, "swr"},
|
||||
// {0x2F, , "cache"},
|
||||
{0x30, M_IMM_TS, "ll"},
|
||||
// {0x31, , "lwc1"},
|
||||
// {0x32, , "lwc2"},
|
||||
// {0x33, , "pref"},
|
||||
{0x34, M_IMM_TS, "lld"},
|
||||
// {0x35, , "ldc1"},
|
||||
// {0x36, , "ldc2"},
|
||||
{0x37, M_IMM_TS, "ld"},
|
||||
{0x38, M_IMM_TS, "sc"},
|
||||
// {0x39, , "swc1"},
|
||||
// {0x3A, , "swc2"},
|
||||
{0x3C, M_IMM_TS, "scd"},
|
||||
// {0x3D, , "sdc1"},
|
||||
// {0x3E, , "sdc2"},
|
||||
{0x3F, M_IMM_TS, "sd"},
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*a))
|
||||
|
||||
// find instruction description for insn
|
||||
static const struct insn *decode_insn(uint32_t insn)
|
||||
{
|
||||
uint32_t op = insn >> 26;
|
||||
const struct insn *pi;
|
||||
int l = 0, r = 0;
|
||||
|
||||
if (op == OP_SPECIAL) {
|
||||
op = insn & 0x3f;
|
||||
pi = special_insns;
|
||||
r = ARRAY_SIZE(special_insns)-1;
|
||||
} else if (op == OP_SPECIAL2) {
|
||||
op = insn & 0x3f;
|
||||
pi = special2_insns;
|
||||
r = ARRAY_SIZE(special2_insns)-1;
|
||||
} else if (op == OP_REGIMM) {
|
||||
op = (insn>>16) & 0x1f;
|
||||
pi = regimm_insns;
|
||||
r = ARRAY_SIZE(regimm_insns)-1;
|
||||
} else {
|
||||
pi = immediate_insns;
|
||||
r = ARRAY_SIZE(immediate_insns)-1;
|
||||
}
|
||||
|
||||
while (l <= r) {
|
||||
int m = (l+r) / 2;
|
||||
if (pi[m].op == op)
|
||||
return pi+m;
|
||||
else if (pi[m].op < op)
|
||||
l = m+1;
|
||||
else
|
||||
r = m-1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// calculate target for pc-relative branches
|
||||
static unsigned long b_target(unsigned long pc, uint32_t insn)
|
||||
{
|
||||
return pc + 4 + (int16_t)insn * 4;
|
||||
}
|
||||
|
||||
// calculate target for region-relative branches
|
||||
static unsigned long j_target(unsigned long pc, uint32_t insn)
|
||||
{
|
||||
return (pc & ~0x0fffffffL) | ((insn & 0x03ffffff) << 2);
|
||||
}
|
||||
|
||||
// main disassembler function
|
||||
int dismips(uintptr_t pc, uint32_t insn, char *buf, unsigned int buflen)
|
||||
{
|
||||
const struct insn *pi = decode_insn(insn);
|
||||
char *rs = register_names[(insn >> 21) & 0x1f];
|
||||
char *rt = register_names[(insn >> 16) & 0x1f];
|
||||
char *rd = register_names[(insn >> 11) & 0x1f];
|
||||
int sa = (insn >> 6) & 0x1f;
|
||||
int imm = (int16_t) insn;
|
||||
|
||||
if (pi == NULL) {
|
||||
snprintf(buf, buflen, "0x%x", insn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (pi->type) {
|
||||
case REG_DTS:
|
||||
if ((insn & 0x3f) == 0x25 /*OR*/ && (insn & 0x1f0000) == 0 /*zero*/)
|
||||
snprintf(buf, buflen, "move %s, %s", rd, rs);
|
||||
else
|
||||
snprintf(buf, buflen, "%s %s, %s, %s", pi->name, rd, rs, rt);
|
||||
break;
|
||||
case REG_TS:
|
||||
snprintf(buf, buflen, "%s %s, %s", pi->name, rs, rt);
|
||||
break;
|
||||
case REG_DS:
|
||||
snprintf(buf, buflen, "%s %s, %s", pi->name, rd, rs);
|
||||
break;
|
||||
case REG_D:
|
||||
snprintf(buf, buflen, "%s %s", pi->name, rd);
|
||||
break;
|
||||
case REG_S:
|
||||
snprintf(buf, buflen, "%s %s", pi->name, rs);
|
||||
break;
|
||||
case S_IMM_DT:
|
||||
if (insn == 0x00000000)
|
||||
snprintf(buf, buflen, "nop");
|
||||
else
|
||||
snprintf(buf, buflen, "%s %s, %s, %d", pi->name, rd, rt, sa);
|
||||
break;
|
||||
case B_IMM_S:
|
||||
snprintf(buf, buflen, "%s %s, 0x%lx", pi->name, rs, b_target(pc, insn));
|
||||
break;
|
||||
case B_IMM_TS:
|
||||
snprintf(buf, buflen, "%s %s, %s, 0x%lx", pi->name, rs, rt, b_target(pc, insn));
|
||||
break;
|
||||
case J_IMM:
|
||||
snprintf(buf, buflen, "%s 0x%lx", pi->name, j_target(pc, insn));
|
||||
break;
|
||||
case A_IMM_TS:
|
||||
if (abs(imm) < 1000)
|
||||
snprintf(buf, buflen, "%s %s, %s, %d", pi->name, rt, rs, imm);
|
||||
else
|
||||
snprintf(buf, buflen, "%s %s, %s, 0x%x", pi->name, rt, rs, imm);
|
||||
break;
|
||||
case L_IMM_T:
|
||||
snprintf(buf, buflen, "%s %s, 0x%x", pi->name, rt, (uint16_t)imm);
|
||||
break;
|
||||
case L_IMM_TS:
|
||||
if ((insn >> 26) == 0x34 /*ORI*/ && (insn & 0x03e00000) == 0 /*zero*/)
|
||||
snprintf(buf, buflen, "li %s, 0x%x", rt, (uint16_t)imm);
|
||||
else
|
||||
snprintf(buf, buflen, "%s %s, %s, 0x%x", pi->name, rt, rs, (uint16_t)imm);
|
||||
break;
|
||||
case M_IMM_TS:
|
||||
snprintf(buf, buflen, "%s %s, %d(%s)", pi->name, rt, imm, rs);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
6
platform/common/dismips.h
Normal file
6
platform/common/dismips.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef DISMIPS_H
|
||||
#define DISMIPS_H
|
||||
|
||||
int dismips(uintptr_t pc, uint32_t insn, char *buf, unsigned int buf_len);
|
||||
|
||||
#endif /* DISMIPS_H */
|
|
@ -29,7 +29,7 @@ void pemu_prep_defconfig(void)
|
|||
|
||||
void pemu_validate_config(void)
|
||||
{
|
||||
#if !defined(__arm__) && !defined(__i386__) && !defined(__x86_64__)
|
||||
#if !defined(__arm__) && !defined(__aarch64__) && !defined(__mips__) && !defined(__i386__) && !defined(__x86_64__)
|
||||
PicoIn.opt &= ~POPT_EN_DRC;
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue