mirror of
https://github.com/holub/mame
synced 2025-04-25 17:56:43 +03:00
mips1: fpu emulation
Code refactoring makes the changes hard to isolate, but the main improvements are: * implemented fpu instructions and exceptions * corrected swl/swr implementation * tlb mru lookup optimization * interrupt and privilege debugger breakpoints
This commit is contained in:
parent
330c498e5d
commit
e02a5cf1f5
File diff suppressed because it is too large
Load Diff
@ -9,21 +9,8 @@
|
|||||||
class mips1core_device_base : public cpu_device
|
class mips1core_device_base : public cpu_device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// floating point coprocessor revision numbers recognised by RISC/os 4.52 and IRIX
|
|
||||||
enum fpu_rev_t : u32
|
|
||||||
{
|
|
||||||
MIPS_R2360 = 0x0100, // MIPS R2360 Floating Point Board
|
|
||||||
MIPS_R2010 = 0x0200, // MIPS R2010 VLSI Floating Point Chip
|
|
||||||
MIPS_R2010A = 0x0310, // MIPS R2010A VLSI Floating Point Chip
|
|
||||||
MIPS_R3010 = 0x0320, // MIPS R3010 VLSI Floating Point Chip
|
|
||||||
MIPS_R3010A = 0x0330, // MIPS R3010A VLSI Floating Point Chip
|
|
||||||
MIPS_R3010Av4 = 0x0340, // MIPS R3010A VLSI Floating Point Chip
|
|
||||||
MIPS_R6010 = 0x0400, // MIPS R6010 Floating Point Chip
|
|
||||||
};
|
|
||||||
|
|
||||||
// device configuration
|
// device configuration
|
||||||
void set_endianness(endianness_t endianness) { m_endianness = endianness; }
|
void set_endianness(endianness_t endianness) { m_endianness = endianness; }
|
||||||
void set_fpurev(u32 revision) { m_hasfpu = true; m_fpurev = revision; }
|
|
||||||
|
|
||||||
// input lines
|
// input lines
|
||||||
template <unsigned Coprocessor> auto in_brcond() { return m_in_brcond[Coprocessor].bind(); }
|
template <unsigned Coprocessor> auto in_brcond() { return m_in_brcond[Coprocessor].bind(); }
|
||||||
@ -31,35 +18,17 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
mips1core_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
|
mips1core_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
|
||||||
|
|
||||||
enum registers
|
enum registers : unsigned
|
||||||
{
|
{
|
||||||
// general purpose cpu registers
|
MIPS1_R0 = 0,
|
||||||
MIPS1_R0, MIPS1_R1, MIPS1_R2, MIPS1_R3, MIPS1_R4, MIPS1_R5, MIPS1_R6, MIPS1_R7,
|
MIPS1_COP0 = 32,
|
||||||
MIPS1_R8, MIPS1_R9, MIPS1_R10, MIPS1_R11, MIPS1_R12, MIPS1_R13, MIPS1_R14, MIPS1_R15,
|
MIPS1_F0 = 64,
|
||||||
MIPS1_R16, MIPS1_R17, MIPS1_R18, MIPS1_R19, MIPS1_R20, MIPS1_R21, MIPS1_R22, MIPS1_R23,
|
|
||||||
MIPS1_R24, MIPS1_R25, MIPS1_R26, MIPS1_R27, MIPS1_R28, MIPS1_R29, MIPS1_R30, MIPS1_R31,
|
|
||||||
|
|
||||||
// other cpu registers
|
MIPS1_PC = 80,
|
||||||
MIPS1_HI,
|
MIPS1_HI,
|
||||||
MIPS1_LO,
|
MIPS1_LO,
|
||||||
MIPS1_PC,
|
MIPS1_FCR30,
|
||||||
|
MIPS1_FCR31,
|
||||||
// coprocessor 0 registers
|
|
||||||
MIPS1_COP0_INDEX, // reg 0, tlb only
|
|
||||||
MIPS1_COP0_RANDOM, // reg 1, tlb only
|
|
||||||
MIPS1_COP0_ENTRYLO, // reg 2, tlb only
|
|
||||||
MIPS1_COP0_BUSCTRL, // reg 2, r3041 only
|
|
||||||
MIPS1_COP0_CONFIG, // reg 3, r3041/r3071/r3081 only
|
|
||||||
MIPS1_COP0_CONTEXT, // reg 4, tlb only
|
|
||||||
MIPS1_COP0_BADVADDR, // reg 8
|
|
||||||
MIPS1_COP0_COUNT, // reg 9, r3041 only
|
|
||||||
MIPS1_COP0_ENTRYHI, // reg 10, tlb only
|
|
||||||
MIPS1_COP0_PORTSIZE, // reg 10, r3041 only
|
|
||||||
MIPS1_COP0_COMPARE, // reg 11, r3041 only
|
|
||||||
MIPS1_COP0_SR, // reg 12
|
|
||||||
MIPS1_COP0_CAUSE, // reg 13
|
|
||||||
MIPS1_COP0_EPC, // reg 14
|
|
||||||
MIPS1_COP0_PRID, // reg 15
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum exception : u32
|
enum exception : u32
|
||||||
@ -75,12 +44,14 @@ protected:
|
|||||||
EXCEPTION_SYSCALL = 0x00000020,
|
EXCEPTION_SYSCALL = 0x00000020,
|
||||||
EXCEPTION_BREAK = 0x00000024,
|
EXCEPTION_BREAK = 0x00000024,
|
||||||
EXCEPTION_INVALIDOP = 0x00000028,
|
EXCEPTION_INVALIDOP = 0x00000028,
|
||||||
|
EXCEPTION_BADCOP = 0x0000002c,
|
||||||
|
EXCEPTION_OVERFLOW = 0x00000030,
|
||||||
|
EXCEPTION_TRAP = 0x00000034,
|
||||||
|
|
||||||
EXCEPTION_BADCOP0 = 0x0000002c,
|
EXCEPTION_BADCOP0 = 0x0000002c,
|
||||||
EXCEPTION_BADCOP1 = 0x1000002c,
|
EXCEPTION_BADCOP1 = 0x1000002c,
|
||||||
EXCEPTION_BADCOP2 = 0x2000002c,
|
EXCEPTION_BADCOP2 = 0x2000002c,
|
||||||
EXCEPTION_BADCOP3 = 0x3000002c,
|
EXCEPTION_BADCOP3 = 0x3000002c,
|
||||||
EXCEPTION_OVERFLOW = 0x00000030,
|
|
||||||
EXCEPTION_TRAP = 0x00000034,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum cop0_reg : u8
|
enum cop0_reg : u8
|
||||||
@ -184,7 +155,7 @@ protected:
|
|||||||
virtual u32 execute_max_cycles() const override { return 40; }
|
virtual u32 execute_max_cycles() const override { return 40; }
|
||||||
virtual u32 execute_input_lines() const override { return 6; }
|
virtual u32 execute_input_lines() const override { return 6; }
|
||||||
virtual void execute_run() override;
|
virtual void execute_run() override;
|
||||||
virtual void execute_set_input(int inputnum, int state) override { set_irq_line(inputnum, state); }
|
virtual void execute_set_input(int inputnum, int state) override;
|
||||||
|
|
||||||
// device_memory_interface overrides
|
// device_memory_interface overrides
|
||||||
virtual space_config_vector memory_space_config() const override;
|
virtual space_config_vector memory_space_config() const override;
|
||||||
@ -199,23 +170,16 @@ protected:
|
|||||||
// interrupts
|
// interrupts
|
||||||
void generate_exception(u32 exception, bool refill = false);
|
void generate_exception(u32 exception, bool refill = false);
|
||||||
void check_irqs();
|
void check_irqs();
|
||||||
void set_irq_line(int irqline, int state);
|
|
||||||
|
|
||||||
// cop0
|
// cop0
|
||||||
virtual u32 get_cop0_reg(int const index);
|
|
||||||
void set_cop0_reg(int const index, u32 const data);
|
|
||||||
virtual void handle_cop0(u32 const op);
|
virtual void handle_cop0(u32 const op);
|
||||||
|
virtual u32 get_cop0_reg(unsigned const reg);
|
||||||
|
virtual void set_cop0_reg(unsigned const reg, u32 const data);
|
||||||
|
|
||||||
// cop1
|
// other coprocessors
|
||||||
void set_cop1_creg(int const index, u32 const data);
|
virtual void handle_cop1(u32 const op);
|
||||||
void handle_cop1(u32 const op);
|
virtual void handle_cop2(u32 const op);
|
||||||
|
virtual void handle_cop3(u32 const op);
|
||||||
// generic coprocessor implementation
|
|
||||||
template <unsigned Coprocessor> void handle_cop(u32 const op);
|
|
||||||
template <unsigned Coprocessor> u32 get_cop_reg(int const index) { return m_cpr[Coprocessor][index]; }
|
|
||||||
template <unsigned Coprocessor> void set_cop_reg(int const index, u32 const data) { m_cpr[Coprocessor][index] = data; }
|
|
||||||
template <unsigned Coprocessor> u32 get_cop_creg(int const index) { return m_ccr[Coprocessor][index]; }
|
|
||||||
template <unsigned Coprocessor> void set_cop_creg(int const index, u32 const data) { m_ccr[Coprocessor][index] = data; }
|
|
||||||
|
|
||||||
// load/store left/right opcodes
|
// load/store left/right opcodes
|
||||||
void lwl(u32 const op);
|
void lwl(u32 const op);
|
||||||
@ -224,12 +188,12 @@ protected:
|
|||||||
void swr(u32 const op);
|
void swr(u32 const op);
|
||||||
|
|
||||||
// memory accessors
|
// memory accessors
|
||||||
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u32 program_address, U &&apply);
|
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u32 address, U &&apply);
|
||||||
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> store(u32 program_address, U data);
|
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> store(u32 address, U data, T mem_mask = ~T(0));
|
||||||
bool fetch(u32 program_address, std::function<void(u32)> &&apply);
|
bool fetch(u32 address, std::function<void(u32)> &&apply);
|
||||||
|
|
||||||
// debug helpers
|
// debug helpers
|
||||||
std::string debug_string(u32 string_pointer, int const limit = 0);
|
std::string debug_string(u32 string_pointer, unsigned const limit = 0);
|
||||||
std::string debug_string_array(u32 array_pointer);
|
std::string debug_string_array(u32 array_pointer);
|
||||||
|
|
||||||
// address spaces
|
// address spaces
|
||||||
@ -242,19 +206,16 @@ protected:
|
|||||||
|
|
||||||
// configuration
|
// configuration
|
||||||
u32 m_cpurev;
|
u32 m_cpurev;
|
||||||
bool m_hasfpu;
|
|
||||||
u32 m_fpurev;
|
|
||||||
endianness_t m_endianness;
|
endianness_t m_endianness;
|
||||||
|
|
||||||
// core registers
|
// core registers
|
||||||
u32 m_pc;
|
u32 m_pc;
|
||||||
|
u32 m_r[32];
|
||||||
u32 m_hi;
|
u32 m_hi;
|
||||||
u32 m_lo;
|
u32 m_lo;
|
||||||
u32 m_r[32];
|
|
||||||
|
|
||||||
// COP registers
|
// cop0 registers
|
||||||
u32 m_cpr[4][32];
|
u32 m_cop0[32];
|
||||||
u32 m_ccr[4][32];
|
|
||||||
|
|
||||||
// internal stuff
|
// internal stuff
|
||||||
int m_icount;
|
int m_icount;
|
||||||
@ -278,9 +239,54 @@ protected:
|
|||||||
|
|
||||||
class mips1_device_base : public mips1core_device_base
|
class mips1_device_base : public mips1core_device_base
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
// floating point coprocessor revision numbers recognised by RISC/os 4.52 and IRIX
|
||||||
|
enum fpu_rev_t : u32
|
||||||
|
{
|
||||||
|
MIPS_R2360 = 0x0100, // MIPS R2360 Floating Point Board
|
||||||
|
MIPS_R2010 = 0x0200, // MIPS R2010 VLSI Floating Point Chip
|
||||||
|
MIPS_R2010A = 0x0310, // MIPS R2010A VLSI Floating Point Chip
|
||||||
|
MIPS_R3010 = 0x0320, // MIPS R3010 VLSI Floating Point Chip
|
||||||
|
MIPS_R3010A = 0x0330, // MIPS R3010A VLSI Floating Point Chip
|
||||||
|
MIPS_R3010Av4 = 0x0340, // MIPS R3010A VLSI Floating Point Chip
|
||||||
|
MIPS_R6010 = 0x0400, // MIPS R6010 Floating Point Chip
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_fpu(u32 revision, unsigned interrupt = 3) { m_fcr0 = revision; m_fpu_irq = interrupt; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mips1_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
|
mips1_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
|
||||||
|
|
||||||
|
enum cp1_fcr31_mask : u32
|
||||||
|
{
|
||||||
|
FCR31_RM = 0x00000003, // rounding mode
|
||||||
|
|
||||||
|
FCR31_FI = 0x00000004, // inexact operation flag
|
||||||
|
FCR31_FU = 0x00000008, // underflow flag
|
||||||
|
FCR31_FO = 0x00000010, // overflow flag
|
||||||
|
FCR31_FZ = 0x00000020, // divide by zero flag
|
||||||
|
FCR31_FV = 0x00000040, // invalid operation flag
|
||||||
|
|
||||||
|
FCR31_EI = 0x00000080, // inexact operation enable
|
||||||
|
FCR31_EU = 0x00000100, // underflow enable
|
||||||
|
FCR31_EO = 0x00000200, // overflow enable
|
||||||
|
FCR31_EZ = 0x00000400, // divide by zero enable
|
||||||
|
FCR31_EV = 0x00000800, // invalid operation enable
|
||||||
|
|
||||||
|
FCR31_CI = 0x00001000, // inexact operation cause
|
||||||
|
FCR31_CU = 0x00002000, // underflow cause
|
||||||
|
FCR31_CO = 0x00004000, // overflow cause
|
||||||
|
FCR31_CZ = 0x00008000, // divide by zero cause
|
||||||
|
FCR31_CV = 0x00010000, // invalid operation cause
|
||||||
|
FCR31_CE = 0x00020000, // unimplemented operation cause
|
||||||
|
|
||||||
|
FCR31_C = 0x00800000, // condition
|
||||||
|
|
||||||
|
FCR31_FM = 0x0000007c, // flag mask
|
||||||
|
FCR31_EM = 0x00000f80, // enable mask
|
||||||
|
FCR31_CM = 0x0001f000, // cause mask (except unimplemented)
|
||||||
|
};
|
||||||
|
|
||||||
// device_t overrides
|
// device_t overrides
|
||||||
virtual void device_start() override;
|
virtual void device_start() override;
|
||||||
virtual void device_reset() override;
|
virtual void device_reset() override;
|
||||||
@ -288,12 +294,24 @@ protected:
|
|||||||
// device_memory_interface overrides
|
// device_memory_interface overrides
|
||||||
virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
|
virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
|
||||||
|
|
||||||
virtual u32 get_cop0_reg(int idx) override;
|
|
||||||
virtual void handle_cop0(u32 const op) override;
|
virtual void handle_cop0(u32 const op) override;
|
||||||
|
virtual u32 get_cop0_reg(unsigned const reg) override;
|
||||||
|
|
||||||
|
virtual void handle_cop1(u32 const op) override;
|
||||||
|
virtual void set_cop1_reg(unsigned const reg, u64 const data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u64 m_reset_time;
|
u64 m_reset_time;
|
||||||
u32 m_tlb[64][2]; // 0 is hi, 1 is lo
|
u32 m_tlb[64][2]; // 0 is hi, 1 is lo
|
||||||
|
unsigned m_tlb_mru[3][64];
|
||||||
|
|
||||||
|
// cop1 registers
|
||||||
|
u64 m_f[16];
|
||||||
|
u32 m_fcr0;
|
||||||
|
u32 m_fcr30;
|
||||||
|
u32 m_fcr31;
|
||||||
|
|
||||||
|
unsigned m_fpu_irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
class r2000_device : public mips1_device_base
|
class r2000_device : public mips1_device_base
|
||||||
@ -347,13 +365,13 @@ public:
|
|||||||
r3052e_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
r3052e_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||||
};
|
};
|
||||||
|
|
||||||
class r3071_device : public mips1core_device_base
|
class r3071_device : public mips1_device_base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
r3071_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
|
r3071_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
|
||||||
};
|
};
|
||||||
|
|
||||||
class r3081_device : public mips1core_device_base
|
class r3081_device : public mips1_device_base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
r3081_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
|
r3081_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
|
||||||
|
@ -133,7 +133,7 @@ private:
|
|||||||
uint32_t kn01_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
uint32_t kn01_screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||||
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||||
|
|
||||||
required_device<mips1core_device_base> m_maincpu;
|
required_device<mips1_device_base> m_maincpu;
|
||||||
required_device<screen_device> m_screen;
|
required_device<screen_device> m_screen;
|
||||||
optional_device<timer_device> m_scantimer;
|
optional_device<timer_device> m_scantimer;
|
||||||
optional_device<decsfb_device> m_sfb;
|
optional_device<decsfb_device> m_sfb;
|
||||||
@ -546,7 +546,7 @@ static void dec_scsi_devices(device_slot_interface &device)
|
|||||||
MACHINE_CONFIG_START(decstation_state::kn01)
|
MACHINE_CONFIG_START(decstation_state::kn01)
|
||||||
R2000(config, m_maincpu, 16.67_MHz_XTAL, 65536, 131072);
|
R2000(config, m_maincpu, 16.67_MHz_XTAL, 65536, 131072);
|
||||||
m_maincpu->set_endianness(ENDIANNESS_LITTLE);
|
m_maincpu->set_endianness(ENDIANNESS_LITTLE);
|
||||||
m_maincpu->set_fpurev(0x340);
|
m_maincpu->set_fpu(mips1_device_base::MIPS_R3010Av4);
|
||||||
m_maincpu->in_brcond<0>().set(FUNC(decstation_state::brcond0_r));
|
m_maincpu->in_brcond<0>().set(FUNC(decstation_state::brcond0_r));
|
||||||
m_maincpu->set_addrmap(AS_PROGRAM, &decstation_state::kn01_map);
|
m_maincpu->set_addrmap(AS_PROGRAM, &decstation_state::kn01_map);
|
||||||
|
|
||||||
@ -570,7 +570,7 @@ MACHINE_CONFIG_END
|
|||||||
MACHINE_CONFIG_START(decstation_state::kn02ba)
|
MACHINE_CONFIG_START(decstation_state::kn02ba)
|
||||||
R3000A(config, m_maincpu, 33.333_MHz_XTAL, 65536, 131072);
|
R3000A(config, m_maincpu, 33.333_MHz_XTAL, 65536, 131072);
|
||||||
m_maincpu->set_endianness(ENDIANNESS_LITTLE);
|
m_maincpu->set_endianness(ENDIANNESS_LITTLE);
|
||||||
m_maincpu->set_fpurev(0x340); // should be R3010A v4.0
|
m_maincpu->set_fpu(mips1_device_base::MIPS_R3010Av4);
|
||||||
m_maincpu->in_brcond<0>().set(FUNC(decstation_state::brcond0_r));
|
m_maincpu->in_brcond<0>().set(FUNC(decstation_state::brcond0_r));
|
||||||
m_maincpu->set_addrmap(AS_PROGRAM, &decstation_state::threemin_map);
|
m_maincpu->set_addrmap(AS_PROGRAM, &decstation_state::threemin_map);
|
||||||
|
|
||||||
|
@ -499,8 +499,7 @@ static void mips_scsi_devices(device_slot_interface &device)
|
|||||||
void rx2030_state::rx2030(machine_config &config)
|
void rx2030_state::rx2030(machine_config &config)
|
||||||
{
|
{
|
||||||
R2000A(config, m_cpu, 33.333_MHz_XTAL / 2, 32768, 32768);
|
R2000A(config, m_cpu, 33.333_MHz_XTAL / 2, 32768, 32768);
|
||||||
// TODO: FPU disabled until properly emulated
|
m_cpu->set_fpu(mips1_device_base::MIPS_R2010A);
|
||||||
//m_cpu->set_fpurev(mips1_device_base::MIPS_R2010A);
|
|
||||||
m_cpu->in_brcond<0>().set([]() { return 1; }); // writeback complete
|
m_cpu->in_brcond<0>().set([]() { return 1; }); // writeback complete
|
||||||
|
|
||||||
V50(config, m_iop, 20_MHz_XTAL / 2);
|
V50(config, m_iop, 20_MHz_XTAL / 2);
|
||||||
@ -772,7 +771,7 @@ void rx3230_state::rx3230(machine_config &config)
|
|||||||
{
|
{
|
||||||
R3000A(config, m_cpu, 50_MHz_XTAL / 2, 32768, 32768);
|
R3000A(config, m_cpu, 50_MHz_XTAL / 2, 32768, 32768);
|
||||||
m_cpu->set_addrmap(AS_PROGRAM, &rx3230_state::rx3230_map);
|
m_cpu->set_addrmap(AS_PROGRAM, &rx3230_state::rx3230_map);
|
||||||
//m_cpu->set_fpurev(mips1_device_base::MIPS_R3010A);
|
m_cpu->set_fpu(mips1_device_base::MIPS_R3010A);
|
||||||
m_cpu->in_brcond<0>().set([]() { return 1; }); // writeback complete
|
m_cpu->in_brcond<0>().set([]() { return 1; }); // writeback complete
|
||||||
|
|
||||||
// 32 SIMM slots, 8-128MB memory, banks of 8 1MB or 4MB SIMMs
|
// 32 SIMM slots, 8-128MB memory, banks of 8 1MB or 4MB SIMMs
|
||||||
|
Loading…
Reference in New Issue
Block a user