mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
976 lines
31 KiB
C++
976 lines
31 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Aaron Giles
|
|
/***************************************************************************
|
|
|
|
mips3.h
|
|
|
|
Interface file for the universal machine language-based
|
|
MIPS III/IV emulator.
|
|
|
|
***************************************************************************/
|
|
|
|
#ifndef MAME_CPU_MIPS_MIPS3_H
|
|
#define MAME_CPU_MIPS_MIPS3_H
|
|
|
|
#pragma once
|
|
|
|
|
|
#include "divtlb.h"
|
|
#include "cpu/drcfe.h"
|
|
#include "cpu/drcuml.h"
|
|
#include "ps2vu.h"
|
|
|
|
#define ENABLE_O2_DPRINTF (0)
|
|
|
|
DECLARE_DEVICE_TYPE(R4000BE, r4000be_device)
|
|
DECLARE_DEVICE_TYPE(R4000LE, r4000le_device)
|
|
DECLARE_DEVICE_TYPE(R4400BE, r4400be_device)
|
|
DECLARE_DEVICE_TYPE(R4400LE, r4400le_device)
|
|
// NEC VR4300 series is MIPS III with 32-bit address bus and slightly custom COP0/TLB
|
|
DECLARE_DEVICE_TYPE(VR4300BE, vr4300be_device)
|
|
DECLARE_DEVICE_TYPE(VR4300LE, vr4300le_device)
|
|
// VR4310 = VR4300 with different speed bin
|
|
DECLARE_DEVICE_TYPE(VR4310BE, vr4310be_device)
|
|
DECLARE_DEVICE_TYPE(VR4310LE, vr4310le_device)
|
|
DECLARE_DEVICE_TYPE(R4600BE, r4600be_device)
|
|
DECLARE_DEVICE_TYPE(R4600LE, r4600le_device)
|
|
DECLARE_DEVICE_TYPE(R4650BE, r4650be_device)
|
|
DECLARE_DEVICE_TYPE(R4650LE, r4650le_device)
|
|
DECLARE_DEVICE_TYPE(R4700BE, r4700be_device)
|
|
DECLARE_DEVICE_TYPE(R4700LE, r4700le_device)
|
|
DECLARE_DEVICE_TYPE(TX4925BE, tx4925be_device)
|
|
DECLARE_DEVICE_TYPE(TX4925LE, tx4925le_device)
|
|
DECLARE_DEVICE_TYPE(R5000BE, r5000be_device)
|
|
DECLARE_DEVICE_TYPE(R5000LE, r5000le_device)
|
|
DECLARE_DEVICE_TYPE(VR5500BE, vr5500be_device)
|
|
DECLARE_DEVICE_TYPE(VR5500LE, vr5500le_device)
|
|
DECLARE_DEVICE_TYPE(QED5271BE, qed5271be_device)
|
|
DECLARE_DEVICE_TYPE(QED5271LE, qed5271le_device)
|
|
DECLARE_DEVICE_TYPE(RM7000BE, rm7000be_device)
|
|
DECLARE_DEVICE_TYPE(RM7000LE, rm7000le_device)
|
|
DECLARE_DEVICE_TYPE(R5900LE, r5900le_device)
|
|
|
|
|
|
/***************************************************************************
|
|
REGISTER ENUMERATION
|
|
***************************************************************************/
|
|
|
|
enum {
|
|
MIPS3_PC = STATE_GENPC,
|
|
MIPS3_R0 = 1,
|
|
MIPS3_R1,
|
|
MIPS3_R2,
|
|
MIPS3_R3,
|
|
MIPS3_R4,
|
|
MIPS3_R5,
|
|
MIPS3_R6,
|
|
MIPS3_R7,
|
|
MIPS3_R8,
|
|
MIPS3_R9,
|
|
MIPS3_R10,
|
|
MIPS3_R11,
|
|
MIPS3_R12,
|
|
MIPS3_R13,
|
|
MIPS3_R14,
|
|
MIPS3_R15,
|
|
MIPS3_R16,
|
|
MIPS3_R17,
|
|
MIPS3_R18,
|
|
MIPS3_R19,
|
|
MIPS3_R20,
|
|
MIPS3_R21,
|
|
MIPS3_R22,
|
|
MIPS3_R23,
|
|
MIPS3_R24,
|
|
MIPS3_R25,
|
|
MIPS3_R26,
|
|
MIPS3_R27,
|
|
MIPS3_R28,
|
|
MIPS3_R29,
|
|
MIPS3_R30,
|
|
MIPS3_R31,
|
|
MIPS3_HI,
|
|
MIPS3_LO,
|
|
MIPS3_FPR0,
|
|
MIPS3_FPS0,
|
|
MIPS3_FPD0,
|
|
MIPS3_FPR1,
|
|
MIPS3_FPS1,
|
|
MIPS3_FPD1,
|
|
MIPS3_FPR2,
|
|
MIPS3_FPS2,
|
|
MIPS3_FPD2,
|
|
MIPS3_FPR3,
|
|
MIPS3_FPS3,
|
|
MIPS3_FPD3,
|
|
MIPS3_FPR4,
|
|
MIPS3_FPS4,
|
|
MIPS3_FPD4,
|
|
MIPS3_FPR5,
|
|
MIPS3_FPS5,
|
|
MIPS3_FPD5,
|
|
MIPS3_FPR6,
|
|
MIPS3_FPS6,
|
|
MIPS3_FPD6,
|
|
MIPS3_FPR7,
|
|
MIPS3_FPS7,
|
|
MIPS3_FPD7,
|
|
MIPS3_FPR8,
|
|
MIPS3_FPS8,
|
|
MIPS3_FPD8,
|
|
MIPS3_FPR9,
|
|
MIPS3_FPS9,
|
|
MIPS3_FPD9,
|
|
MIPS3_FPR10,
|
|
MIPS3_FPS10,
|
|
MIPS3_FPD10,
|
|
MIPS3_FPR11,
|
|
MIPS3_FPS11,
|
|
MIPS3_FPD11,
|
|
MIPS3_FPR12,
|
|
MIPS3_FPS12,
|
|
MIPS3_FPD12,
|
|
MIPS3_FPR13,
|
|
MIPS3_FPS13,
|
|
MIPS3_FPD13,
|
|
MIPS3_FPR14,
|
|
MIPS3_FPS14,
|
|
MIPS3_FPD14,
|
|
MIPS3_FPR15,
|
|
MIPS3_FPS15,
|
|
MIPS3_FPD15,
|
|
MIPS3_FPR16,
|
|
MIPS3_FPS16,
|
|
MIPS3_FPD16,
|
|
MIPS3_FPR17,
|
|
MIPS3_FPS17,
|
|
MIPS3_FPD17,
|
|
MIPS3_FPR18,
|
|
MIPS3_FPS18,
|
|
MIPS3_FPD18,
|
|
MIPS3_FPR19,
|
|
MIPS3_FPS19,
|
|
MIPS3_FPD19,
|
|
MIPS3_FPR20,
|
|
MIPS3_FPS20,
|
|
MIPS3_FPD20,
|
|
MIPS3_FPR21,
|
|
MIPS3_FPS21,
|
|
MIPS3_FPD21,
|
|
MIPS3_FPR22,
|
|
MIPS3_FPS22,
|
|
MIPS3_FPD22,
|
|
MIPS3_FPR23,
|
|
MIPS3_FPS23,
|
|
MIPS3_FPD23,
|
|
MIPS3_FPR24,
|
|
MIPS3_FPS24,
|
|
MIPS3_FPD24,
|
|
MIPS3_FPR25,
|
|
MIPS3_FPS25,
|
|
MIPS3_FPD25,
|
|
MIPS3_FPR26,
|
|
MIPS3_FPS26,
|
|
MIPS3_FPD26,
|
|
MIPS3_FPR27,
|
|
MIPS3_FPS27,
|
|
MIPS3_FPD27,
|
|
MIPS3_FPR28,
|
|
MIPS3_FPS28,
|
|
MIPS3_FPD28,
|
|
MIPS3_FPR29,
|
|
MIPS3_FPS29,
|
|
MIPS3_FPD29,
|
|
MIPS3_FPR30,
|
|
MIPS3_FPS30,
|
|
MIPS3_FPD30,
|
|
MIPS3_FPR31,
|
|
MIPS3_FPS31,
|
|
MIPS3_FPD31,
|
|
MIPS3_CCR1_31,
|
|
MIPS3_SR,
|
|
MIPS3_EPC,
|
|
MIPS3_CAUSE,
|
|
MIPS3_COUNT,
|
|
MIPS3_COMPARE,
|
|
MIPS3_INDEX,
|
|
MIPS3_RANDOM,
|
|
MIPS3_ENTRYHI,
|
|
MIPS3_ENTRYLO0,
|
|
MIPS3_ENTRYLO1,
|
|
MIPS3_PAGEMASK,
|
|
MIPS3_WIRED,
|
|
MIPS3_BADVADDR,
|
|
MIPS3_R0H,
|
|
MIPS3_R1H,
|
|
MIPS3_R2H,
|
|
MIPS3_R3H,
|
|
MIPS3_R4H,
|
|
MIPS3_R5H,
|
|
MIPS3_R6H,
|
|
MIPS3_R7H,
|
|
MIPS3_R8H,
|
|
MIPS3_R9H,
|
|
MIPS3_R10H,
|
|
MIPS3_R11H,
|
|
MIPS3_R12H,
|
|
MIPS3_R13H,
|
|
MIPS3_R14H,
|
|
MIPS3_R15H,
|
|
MIPS3_R16H,
|
|
MIPS3_R17H,
|
|
MIPS3_R18H,
|
|
MIPS3_R19H,
|
|
MIPS3_R20H,
|
|
MIPS3_R21H,
|
|
MIPS3_R22H,
|
|
MIPS3_R23H,
|
|
MIPS3_R24H,
|
|
MIPS3_R25H,
|
|
MIPS3_R26H,
|
|
MIPS3_R27H,
|
|
MIPS3_R28H,
|
|
MIPS3_R29H,
|
|
MIPS3_R30H,
|
|
MIPS3_R31H,
|
|
};
|
|
|
|
#define MIPS3_MAX_FASTRAM 3
|
|
#define MIPS3_MAX_HOTSPOTS 16
|
|
|
|
/***************************************************************************
|
|
INTERRUPT CONSTANTS
|
|
***************************************************************************/
|
|
|
|
#define MIPS3_IRQ0 0 /* IRQ0 */
|
|
#define MIPS3_IRQ1 1 /* IRQ1 */
|
|
#define MIPS3_IRQ2 2 /* IRQ2 */
|
|
#define MIPS3_IRQ3 3 /* IRQ3 */
|
|
#define MIPS3_IRQ4 4 /* IRQ4 */
|
|
#define MIPS3_IRQ5 5 /* IRQ5 */
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
STRUCTURES
|
|
***************************************************************************/
|
|
|
|
/* MIPS3 TLB entry */
|
|
struct mips3_tlb_entry {
|
|
uint64_t page_mask;
|
|
uint64_t entry_hi;
|
|
uint64_t entry_lo[2];
|
|
};
|
|
|
|
#define MIPS3_MAX_TLB_ENTRIES 48
|
|
|
|
class mips3_frontend;
|
|
|
|
class mips3_device : public cpu_device, public device_vtlb_interface {
|
|
friend class mips3_frontend;
|
|
|
|
protected:
|
|
/* MIPS flavors */
|
|
enum mips3_flavor {
|
|
/* MIPS III variants */
|
|
MIPS3_TYPE_MIPS_III,
|
|
MIPS3_TYPE_R4000,
|
|
MIPS3_TYPE_R4400,
|
|
MIPS3_TYPE_VR4300,
|
|
MIPS3_TYPE_R4600,
|
|
MIPS3_TYPE_R4650,
|
|
MIPS3_TYPE_R4700,
|
|
MIPS3_TYPE_TX4925,
|
|
|
|
/* MIPS IV variants */
|
|
MIPS3_TYPE_MIPS_IV,
|
|
MIPS3_TYPE_R5000,
|
|
MIPS3_TYPE_VR5500,
|
|
MIPS3_TYPE_QED5271,
|
|
MIPS3_TYPE_R5900,
|
|
MIPS3_TYPE_RM7000
|
|
};
|
|
|
|
public:
|
|
// construction/destruction
|
|
mips3_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, mips3_flavor flavor, endianness_t endiannes, uint32_t data_bits);
|
|
|
|
void set_icache_size(size_t icache_size) { c_icache_size = icache_size; }
|
|
void set_dcache_size(size_t dcache_size) { c_dcache_size = dcache_size; }
|
|
void set_secondary_cache_line_size(uint8_t secondary_cache_line_size) { c_secondary_cache_line_size = secondary_cache_line_size; }
|
|
void set_system_clock(uint32_t system_clock) { c_system_clock = system_clock; }
|
|
|
|
TIMER_CALLBACK_MEMBER(compare_int_callback);
|
|
|
|
void add_fastram(offs_t start, offs_t end, uint8_t readonly, void *base);
|
|
void clear_fastram(uint32_t select_start);
|
|
void mips3drc_set_options(uint32_t options);
|
|
void mips3drc_add_hotspot(offs_t pc, uint32_t opcode, uint32_t cycles);
|
|
void burn_cycles(int32_t cycles);
|
|
|
|
protected:
|
|
// device-level overrides
|
|
virtual void device_start() override;
|
|
virtual void device_reset() override;
|
|
virtual void device_stop() override;
|
|
|
|
// device_execute_interface overrides
|
|
virtual uint32_t execute_min_cycles() const override { return 1; }
|
|
virtual uint32_t execute_max_cycles() const override { return 40; }
|
|
virtual uint32_t execute_input_lines() const override { return 6; }
|
|
virtual void execute_run() override;
|
|
virtual void execute_set_input(int inputnum, int state) override;
|
|
virtual void execute_burn(int32_t cycles) override { m_totalcycles += cycles; }
|
|
|
|
// device_memory_interface overrides
|
|
virtual space_config_vector memory_space_config() const override;
|
|
virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
|
|
|
|
// device_state_interface overrides
|
|
virtual void state_export(const device_state_entry &entry) override;
|
|
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
|
|
|
|
// device_disasm_interface overrides
|
|
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
|
|
|
|
void invalid_instruction(uint32_t op);
|
|
|
|
virtual bool RBYTE(offs_t address, uint32_t *result);
|
|
virtual bool RHALF(offs_t address, uint32_t *result);
|
|
virtual bool RWORD(offs_t address, uint32_t *result, bool insn = false);
|
|
virtual bool RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask);
|
|
virtual bool RDOUBLE(offs_t address, uint64_t *result);
|
|
virtual bool RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask);
|
|
virtual void WBYTE(offs_t address, uint8_t data);
|
|
virtual void WHALF(offs_t address, uint16_t data);
|
|
virtual void WWORD(offs_t address, uint32_t data);
|
|
virtual void WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask);
|
|
virtual void WDOUBLE(offs_t address, uint64_t data);
|
|
virtual void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask);
|
|
|
|
struct internal_mips3_state {
|
|
/* core registers */
|
|
uint32_t pc;
|
|
int icount;
|
|
uint64_t r[35];
|
|
uint32_t sa;
|
|
|
|
/* upper 64 bits of 128-bit GPRs (R5900 only) */
|
|
uint64_t rh[35];
|
|
|
|
/* COP registers */
|
|
uint64_t cpr[3][32];
|
|
uint64_t ccr[3][32];
|
|
uint32_t llbit;
|
|
float acc;
|
|
|
|
/* VU0 registers (R5900 only) */
|
|
float vfr[32][4]; // 0..3 = x..w
|
|
uint32_t vcr[32];
|
|
float vumem[0x1000];
|
|
float* vfmem;
|
|
uint32_t* vimem;
|
|
float vacc[4];
|
|
float p;
|
|
|
|
uint32_t* vr;
|
|
float* i;
|
|
float* q;
|
|
|
|
uint32_t mode; /* current global mode */
|
|
|
|
/* parameters for subroutines */
|
|
uint64_t numcycles; /* return value from gettotalcycles */
|
|
const char * format; /* format string for print_debug */
|
|
uint32_t arg0; /* print_debug argument 1 */
|
|
uint32_t arg1; /* print_debug argument 2 */
|
|
|
|
uint64_t count_zero_time;
|
|
uint32_t compare_armed;
|
|
uint32_t jmpdest; /* destination jump target */
|
|
};
|
|
|
|
/* core state */
|
|
internal_mips3_state *m_core;
|
|
uint8_t *m_dcache;
|
|
uint8_t *m_icache;
|
|
|
|
address_space_config m_program_config;
|
|
mips3_flavor m_flavor;
|
|
|
|
/* internal stuff */
|
|
uint32_t m_ppc;
|
|
uint32_t m_nextpc;
|
|
uint32_t m_pcbase;
|
|
uint8_t m_cf[4][8];
|
|
bool m_delayslot;
|
|
int m_op;
|
|
int m_interrupt_cycles;
|
|
uint32_t m_ll_value;
|
|
uint64_t m_lld_value;
|
|
uint32_t m_badcop_value;
|
|
|
|
/* endian-dependent load/store */
|
|
typedef void (mips3_device::*loadstore_func)(uint32_t op);
|
|
loadstore_func m_lwl;
|
|
loadstore_func m_lwr;
|
|
loadstore_func m_swl;
|
|
loadstore_func m_swr;
|
|
loadstore_func m_ldl;
|
|
loadstore_func m_ldr;
|
|
loadstore_func m_sdl;
|
|
loadstore_func m_sdr;
|
|
|
|
address_space * m_program;
|
|
uint32_t m_data_bits;
|
|
std::function<u32(offs_t)> m_pr32;
|
|
std::function<const void * (offs_t)> m_prptr;
|
|
uint32_t c_system_clock;
|
|
uint32_t m_cpu_clock;
|
|
emu_timer * m_compare_int_timer;
|
|
|
|
/* derived info based on flavor */
|
|
uint32_t m_pfnmask;
|
|
uint8_t m_tlbentries;
|
|
|
|
/* memory accesses */
|
|
bool m_bigendian;
|
|
uint32_t m_byte_xor;
|
|
uint32_t m_word_xor;
|
|
uint32_t m_dword_xor;
|
|
data_accessors m_memory;
|
|
|
|
/* cache memory */
|
|
size_t c_icache_size;
|
|
size_t c_dcache_size;
|
|
uint8_t c_secondary_cache_line_size;
|
|
|
|
/* MMU */
|
|
mips3_tlb_entry m_tlb[MIPS3_MAX_TLB_ENTRIES];
|
|
|
|
/* fast RAM */
|
|
uint32_t m_fastram_select;
|
|
struct {
|
|
offs_t start; /* start of the RAM block */
|
|
offs_t end; /* end of the RAM block */
|
|
bool readonly; /* true if read-only */
|
|
void * base; /* base in memory where the RAM lives */
|
|
uint8_t * offset_base8; /* base in memory where the RAM lives, 8-bit pointer, with the start offset pre-applied */
|
|
uint16_t * offset_base16; /* base in memory where the RAM lives, 16-bit pointer, with the start offset pre-applied */
|
|
uint32_t * offset_base32; /* base in memory where the RAM lives, 32-bit pointer, with the start offset pre-applied */
|
|
} m_fastram[MIPS3_MAX_FASTRAM];
|
|
|
|
uint32_t m_debugger_temp;
|
|
|
|
/* core state */
|
|
drc_cache m_drc_cache; /* pointer to the DRC code cache */
|
|
std::unique_ptr<drcuml_state> m_drcuml;/* DRC UML generator state */
|
|
std::unique_ptr<mips3_frontend> m_drcfe; /* pointer to the DRC front-end state */
|
|
uint32_t m_drcoptions; /* configurable DRC options */
|
|
|
|
/* internal stuff */
|
|
uint8_t m_drc_cache_dirty; /* true if we need to flush the cache */
|
|
|
|
/* tables */
|
|
uint8_t m_fpmode[4]; /* FPU mode table */
|
|
|
|
/* register mappings */
|
|
uml::parameter m_regmap[34]; /* parameter to register mappings for all 32 integer registers */
|
|
uml::parameter m_regmaplo[34]; /* parameter to register mappings for all 32 integer registers */
|
|
|
|
/* subroutines */
|
|
uml::code_handle * m_entry; /* entry point */
|
|
uml::code_handle * m_nocode; /* nocode exception handler */
|
|
uml::code_handle * m_out_of_cycles; /* out of cycles exception handler */
|
|
uml::code_handle * m_tlb_mismatch; /* tlb mismatch handler */
|
|
uml::code_handle * m_read8[3]; /* read byte */
|
|
uml::code_handle * m_write8[3]; /* write byte */
|
|
uml::code_handle * m_read16[3]; /* read half */
|
|
uml::code_handle * m_write16[3]; /* write half */
|
|
uml::code_handle * m_read32[3]; /* read word */
|
|
uml::code_handle * m_read32mask[3]; /* read word masked */
|
|
uml::code_handle * m_write32[3]; /* write word */
|
|
uml::code_handle * m_write32mask[3]; /* write word masked */
|
|
uml::code_handle * m_read64[3]; /* read double */
|
|
uml::code_handle * m_read64mask[3]; /* read double masked */
|
|
uml::code_handle * m_write64[3]; /* write double */
|
|
uml::code_handle * m_write64mask[3]; /* write double masked */
|
|
uml::code_handle * m_exception[18/*EXCEPTION_COUNT*/]; /* array of exception handlers */
|
|
uml::code_handle * m_exception_norecover[18/*EXCEPTION_COUNT*/]; /* array of no-recover exception handlers */
|
|
|
|
/* hotspots */
|
|
uint32_t m_hotspot_select;
|
|
struct {
|
|
offs_t pc; /* PC to consider */
|
|
uint32_t opcode; /* required opcode at that PC */
|
|
uint32_t cycles; /* number of cycles to eat when hit */
|
|
} m_hotspot[MIPS3_MAX_HOTSPOTS];
|
|
bool m_isdrc;
|
|
|
|
|
|
void generate_exception(int exception, int backup);
|
|
void generate_tlb_exception(int exception, offs_t address);
|
|
virtual void check_irqs();
|
|
virtual void handle_mult(uint32_t op);
|
|
virtual void handle_multu(uint32_t op);
|
|
|
|
public:
|
|
void mips3com_update_cycle_counting();
|
|
void mips3com_asid_changed();
|
|
void mips3com_tlbr();
|
|
void mips3com_tlbwi();
|
|
void mips3com_tlbwr();
|
|
void mips3com_tlbp();
|
|
private:
|
|
uint32_t compute_config_register();
|
|
uint32_t compute_prid_register();
|
|
|
|
void tlb_map_entry(int tlbindex);
|
|
void tlb_write_common(int tlbindex);
|
|
|
|
uint64_t get_cop0_reg(int idx);
|
|
void set_cop0_reg(int idx, uint64_t val);
|
|
uint64_t get_cop0_creg(int idx);
|
|
void set_cop0_creg(int idx, uint64_t val);
|
|
void handle_cop0(uint32_t op);
|
|
|
|
uint32_t get_cop1_reg32(int idx);
|
|
uint64_t get_cop1_reg64(int idx);
|
|
void set_cop1_reg32(int idx, uint32_t val);
|
|
void set_cop1_reg64(int idx, uint64_t val);
|
|
uint64_t get_cop1_creg(int idx);
|
|
void set_cop1_creg(int idx, uint64_t val);
|
|
void handle_cop1_fr0(uint32_t op);
|
|
void handle_cop1_fr1(uint32_t op);
|
|
void handle_cop1x_fr0(uint32_t op);
|
|
void handle_cop1x_fr1(uint32_t op);
|
|
|
|
virtual uint64_t get_cop2_reg(int idx);
|
|
virtual void set_cop2_reg(int idx, uint64_t val);
|
|
virtual uint64_t get_cop2_creg(int idx);
|
|
virtual void set_cop2_creg(int idx, uint64_t val);
|
|
void handle_cop2(uint32_t op);
|
|
|
|
void handle_special(uint32_t op);
|
|
void handle_regimm(uint32_t op);
|
|
virtual void handle_extra_base(uint32_t op);
|
|
virtual void handle_extra_special(uint32_t op);
|
|
virtual void handle_extra_regimm(uint32_t op);
|
|
virtual void handle_extra_cop0(uint32_t op);
|
|
virtual void handle_extra_cop1(uint32_t op);
|
|
virtual void handle_extra_cop2(uint32_t op);
|
|
virtual void handle_idt(uint32_t op);
|
|
virtual void handle_ldc2(uint32_t op);
|
|
virtual void handle_sdc2(uint32_t op);
|
|
virtual void handle_dmfc2(uint32_t op);
|
|
virtual void handle_dmtc2(uint32_t op);
|
|
virtual void handle_cache(uint32_t op) { /* Handle as a no-op in most implementations */ }
|
|
|
|
void lwl_be(uint32_t op);
|
|
void lwr_be(uint32_t op);
|
|
void ldl_be(uint32_t op);
|
|
void ldr_be(uint32_t op);
|
|
void swl_be(uint32_t op);
|
|
void swr_be(uint32_t op);
|
|
void sdl_be(uint32_t op);
|
|
void sdr_be(uint32_t op);
|
|
void lwl_le(uint32_t op);
|
|
void lwr_le(uint32_t op);
|
|
void ldl_le(uint32_t op);
|
|
void ldr_le(uint32_t op);
|
|
void swl_le(uint32_t op);
|
|
void swr_le(uint32_t op);
|
|
void sdl_le(uint32_t op);
|
|
void sdr_le(uint32_t op);
|
|
void load_fast_iregs(drcuml_block &block);
|
|
void save_fast_iregs(drcuml_block &block);
|
|
void code_flush_cache();
|
|
void code_compile_block(uint8_t mode, offs_t pc);
|
|
public:
|
|
void func_get_cycles();
|
|
void func_printf_exception();
|
|
void func_printf_debug();
|
|
void func_printf_probe();
|
|
void func_unimplemented();
|
|
private:
|
|
/* internal compiler state */
|
|
struct compiler_state
|
|
{
|
|
compiler_state &operator=(compiler_state &) = delete;
|
|
|
|
uint32_t cycles; /* accumulated cycles */
|
|
uint8_t checkints; /* need to check interrupts before next instruction */
|
|
uint8_t checksoftints; /* need to check software interrupts before next instruction */
|
|
uml::code_label labelnum; /* index for local labels */
|
|
};
|
|
|
|
void static_generate_entry_point();
|
|
void static_generate_nocode_handler();
|
|
void static_generate_out_of_cycles();
|
|
void static_generate_tlb_mismatch();
|
|
void static_generate_exception(uint8_t exception, int recover, const char *name);
|
|
void static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle *&handleptr);
|
|
|
|
void generate_update_mode(drcuml_block &block);
|
|
void generate_update_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param, bool allow_exception);
|
|
void generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast);
|
|
void generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
|
|
void generate_delay_slot_and_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t linkreg);
|
|
|
|
bool generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
|
|
bool generate_special(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
|
|
bool generate_regimm(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
|
|
bool generate_idt(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
|
|
|
|
bool generate_set_cop0_reg(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t reg);
|
|
bool generate_get_cop0_reg(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint8_t reg);
|
|
bool generate_cop0(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
|
|
bool generate_cop1(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
|
|
bool generate_cop1x(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
|
|
|
|
void check_cop0_access(drcuml_block &block);
|
|
void check_cop1_access(drcuml_block &block);
|
|
void generate_badcop(drcuml_block &block, const int cop);
|
|
|
|
void log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op);
|
|
const char *log_desc_flags_to_string(uint32_t flags);
|
|
void log_register_list(const char *string, const uint32_t *reglist, const uint32_t *regnostarlist);
|
|
void log_opcode_desc(const opcode_desc *desclist, int indent);
|
|
|
|
void load_elf();
|
|
#if ENABLE_O2_DPRINTF
|
|
void do_o2_dprintf(uint32_t fmt_addr, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t stack);
|
|
#endif
|
|
};
|
|
|
|
|
|
class r4000be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4000be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4000BE, tag, owner, clock, MIPS3_TYPE_R4000, ENDIANNESS_BIG, 64)
|
|
{
|
|
}
|
|
};
|
|
|
|
class r4000le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4000le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4000LE, tag, owner, clock, MIPS3_TYPE_R4000, ENDIANNESS_LITTLE, 64)
|
|
{
|
|
}
|
|
};
|
|
|
|
class r4400be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4400be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4400BE, tag, owner, clock, MIPS3_TYPE_R4400, ENDIANNESS_BIG, 64)
|
|
{
|
|
}
|
|
};
|
|
|
|
class r4400le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4400le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4400LE, tag, owner, clock, MIPS3_TYPE_R4400, ENDIANNESS_LITTLE, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class vr4300be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
vr4300be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, VR4300BE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_BIG, 32)
|
|
{
|
|
}
|
|
};
|
|
|
|
class vr4300le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
vr4300le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, VR4300LE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_LITTLE, 32)
|
|
{
|
|
}
|
|
};
|
|
|
|
class vr4310be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
vr4310be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, VR4310BE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_BIG, 32)
|
|
{
|
|
}
|
|
};
|
|
|
|
class vr4310le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
vr4310le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, VR4310LE, tag, owner, clock, MIPS3_TYPE_VR4300, ENDIANNESS_LITTLE, 32)
|
|
{
|
|
}
|
|
};
|
|
|
|
class r4600be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4600be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4600BE, tag, owner, clock, MIPS3_TYPE_R4600, ENDIANNESS_BIG, 64)
|
|
{
|
|
}
|
|
};
|
|
|
|
class r4600le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4600le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4600LE, tag, owner, clock, MIPS3_TYPE_R4600, ENDIANNESS_LITTLE, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class r4650be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4650be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4650BE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_BIG, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class r4650le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4650le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4650LE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_LITTLE, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class r4700be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4700be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4700BE, tag, owner, clock, MIPS3_TYPE_R4700, ENDIANNESS_BIG, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class r4700le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r4700le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R4700LE, tag, owner, clock, MIPS3_TYPE_R4700, ENDIANNESS_LITTLE, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class tx4925be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
tx4925be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, TX4925BE, tag, owner, clock, MIPS3_TYPE_TX4925, ENDIANNESS_BIG, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class tx4925le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
tx4925le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, TX4925LE, tag, owner, clock, MIPS3_TYPE_TX4925, ENDIANNESS_LITTLE, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class r5000be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r5000be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R5000BE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_BIG, 64)
|
|
{
|
|
}
|
|
|
|
protected:
|
|
void handle_cache(uint32_t op) override;
|
|
};
|
|
|
|
class r5000le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
r5000le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R5000LE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_LITTLE, 32) // FIXME: Should be 64 bits, Galileo blows up though
|
|
{
|
|
}
|
|
};
|
|
|
|
class vr5500be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
vr5500be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, VR5500BE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_BIG, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class vr5500le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
vr5500le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, VR5500LE, tag, owner, clock, MIPS3_TYPE_R5000, ENDIANNESS_LITTLE, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class r5900le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
template <typename T>
|
|
r5900le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&vu0_tag)
|
|
: r5900le_device(mconfig, tag, owner, clock)
|
|
{
|
|
m_vu0.set_tag(std::forward<T>(vu0_tag));
|
|
}
|
|
|
|
r5900le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, R5900LE, tag, owner, clock, MIPS3_TYPE_R5900, ENDIANNESS_LITTLE, 64)
|
|
, m_vu0(*this, finder_base::DUMMY_TAG)
|
|
{
|
|
}
|
|
|
|
protected:
|
|
virtual void device_start() override;
|
|
|
|
// device_disasm_interface overrides
|
|
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
|
|
|
|
bool RBYTE(offs_t address, uint32_t *result) override;
|
|
bool RHALF(offs_t address, uint32_t *result) override;
|
|
bool RWORD(offs_t address, uint32_t *result, bool insn = false) override;
|
|
bool RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask) override;
|
|
bool RDOUBLE(offs_t address, uint64_t *result) override;
|
|
bool RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask) override;
|
|
void WBYTE(offs_t address, uint8_t data) override;
|
|
void WHALF(offs_t address, uint16_t data) override;
|
|
void WWORD(offs_t address, uint32_t data) override;
|
|
void WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask) override;
|
|
void WDOUBLE(offs_t address, uint64_t data) override;
|
|
void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask) override;
|
|
|
|
bool RQUAD(offs_t address, uint64_t *result_hi, uint64_t *result_lo);
|
|
void WQUAD(offs_t address, uint64_t data_hi, uint64_t data_lo);
|
|
|
|
uint64_t get_cop2_reg(int idx) override;
|
|
void set_cop2_reg(int idx, uint64_t val) override;
|
|
uint64_t get_cop2_creg(int idx) override;
|
|
void set_cop2_creg(int idx, uint64_t val) override;
|
|
|
|
void handle_extra_base(uint32_t op) override;
|
|
void handle_extra_special(uint32_t op) override;
|
|
void handle_extra_regimm(uint32_t op) override;
|
|
void handle_extra_cop0(uint32_t op) override;
|
|
void handle_extra_cop1(uint32_t op) override;
|
|
void handle_extra_cop2(uint32_t op) override;
|
|
void handle_idt(uint32_t op) override;
|
|
void handle_mult(uint32_t op) override;
|
|
void handle_multu(uint32_t op) override;
|
|
void handle_mmi0(uint32_t op);
|
|
void handle_mmi1(uint32_t op);
|
|
void handle_mmi2(uint32_t op);
|
|
void handle_mmi3(uint32_t op);
|
|
void handle_ldc2(uint32_t op) override;
|
|
void handle_sdc2(uint32_t op) override;
|
|
void handle_dmfc2(uint32_t op) override;
|
|
void handle_dmtc2(uint32_t op) override;
|
|
|
|
void check_irqs() override;
|
|
|
|
required_device<sonyvu0_device> m_vu0;
|
|
};
|
|
|
|
class qed5271be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
qed5271be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, QED5271BE, tag, owner, clock, MIPS3_TYPE_QED5271, ENDIANNESS_BIG, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class qed5271le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
qed5271le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, QED5271LE, tag, owner, clock, MIPS3_TYPE_QED5271, ENDIANNESS_LITTLE, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class rm7000be_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
rm7000be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, RM7000BE, tag, owner, clock, MIPS3_TYPE_RM7000, ENDIANNESS_BIG, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
class rm7000le_device : public mips3_device {
|
|
public:
|
|
// construction/destruction
|
|
rm7000le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
|
: mips3_device(mconfig, RM7000LE, tag, owner, clock, MIPS3_TYPE_RM7000, ENDIANNESS_LITTLE, 32) // Should be 64 bits
|
|
{
|
|
}
|
|
};
|
|
|
|
|
|
|
|
class mips3_frontend : public drc_frontend {
|
|
public:
|
|
// construction/destruction
|
|
mips3_frontend(mips3_device *mips3, uint32_t window_start, uint32_t window_end, uint32_t max_sequence);
|
|
|
|
protected:
|
|
// required overrides
|
|
virtual bool describe(opcode_desc &desc, const opcode_desc *prev) override;
|
|
|
|
private:
|
|
// internal helpers
|
|
bool describe_special(uint32_t op, opcode_desc &desc);
|
|
bool describe_regimm(uint32_t op, opcode_desc &desc);
|
|
bool describe_idt(uint32_t op, opcode_desc &desc);
|
|
bool describe_cop0(uint32_t op, opcode_desc &desc);
|
|
bool describe_cop1(uint32_t op, opcode_desc &desc);
|
|
bool describe_cop1x(uint32_t op, opcode_desc &desc);
|
|
bool describe_cop2(uint32_t op, opcode_desc &desc);
|
|
|
|
// internal state
|
|
mips3_device *m_mips3;
|
|
};
|
|
|
|
|
|
/***************************************************************************
|
|
COMPILER-SPECIFIC OPTIONS
|
|
***************************************************************************/
|
|
|
|
/* fix me -- how do we make this work?? */
|
|
#define MIPS3DRC_STRICT_VERIFY 0x0001 /* verify all instructions */
|
|
#define MIPS3DRC_STRICT_COP0 0x0002 /* validate all COP0 instructions */
|
|
#define MIPS3DRC_STRICT_COP1 0x0004 /* validate all COP1 instructions */
|
|
#define MIPS3DRC_STRICT_COP2 0x0008 /* validate all COP2 instructions */
|
|
#define MIPS3DRC_FLUSH_PC 0x0010 /* flush the PC value before each memory access */
|
|
#define MIPS3DRC_CHECK_OVERFLOWS 0x0020 /* actually check overflows on add/sub instructions */
|
|
#define MIPS3DRC_ACCURATE_DIVZERO 0x0040 /* load correct values into HI/LO on integer divide-by-zero */
|
|
|
|
#define MIPS3DRC_COMPATIBLE_OPTIONS (MIPS3DRC_STRICT_VERIFY | MIPS3DRC_STRICT_COP1 | MIPS3DRC_STRICT_COP0 | MIPS3DRC_STRICT_COP2 | MIPS3DRC_FLUSH_PC)
|
|
#define MIPS3DRC_FASTEST_OPTIONS (0)
|
|
|
|
|
|
#endif // MAME_CPU_MIPS_MIPS3_H
|