1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
|
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Patrick Mackinlay
#ifndef MAME_CPU_MIPS_MIPS1_H
#define MAME_CPU_MIPS_MIPS1_H
#pragma once
class mips1core_device_base : public cpu_device
{
public:
// device configuration
void set_endianness(endianness_t endianness) { m_endianness = endianness; }
// input lines
template <unsigned Coprocessor> auto in_brcond() { return m_in_brcond[Coprocessor].bind(); }
void berr_w(int state) { m_bus_error = bool(state); }
protected:
mips1core_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size, bool cache_pws);
// device_t implementation
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
// device_execute_interface implementation
virtual u32 execute_min_cycles() const noexcept override { return 1; }
virtual u32 execute_max_cycles() const noexcept override { return 40; }
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
// device_memory_interface implementation
virtual space_config_vector memory_space_config() const override;
virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) override;
// device_disasm_interface implementation
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
// exceptions
void generate_exception(u32 exception, bool refill = false);
void address_error(int intention, u32 const address);
// cop0
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);
// other coprocessors
virtual void handle_cop1(u32 const op);
virtual void handle_cop2(u32 const op);
virtual void handle_cop3(u32 const op);
// load/store left/right opcodes
void lwl(u32 const op);
void lwr(u32 const op);
void swl(u32 const op);
void swr(u32 const op);
// memory
enum translate_result : unsigned { ERROR, UNCACHED, CACHED };
virtual translate_result translate(int intention, offs_t &address, bool debug);
template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u32 address, U &&apply);
template <typename T, bool Aligned = true> void store(u32 address, T data, T mem_mask = ~T(0));
void fetch(u32 address, std::function<void(u32)> &&apply);
// cache
template <typename T> unsigned shift_factor(u32 address) const;
struct cache
{
cache(size_t size)
: size(size)
{
}
struct line
{
enum tag_mask : u32
{
INV = 0x0000'0001, // cache line invalid
};
void invalidate() { tag = INV; }
void update(u32 data, u32 mask = 0xffff'ffffU)
{
this->tag &= ~INV;
this->data = (this->data & ~mask) | (data & mask);
}
u32 tag;
u32 data;
};
size_t lines() const { return size / 4; }
void start() { line = std::make_unique<struct line[]>(lines()); }
size_t const size;
std::unique_ptr<struct line[]> line;
};
std::tuple<struct cache::line &, bool> cache_lookup(u32 address, bool invalidate, bool icache = false);
// address spaces
address_space_config const m_program_config_be;
address_space_config const m_program_config_le;
// configuration
u32 const m_cpurev;
endianness_t m_endianness;
// core registers
u32 m_pc;
u32 m_r[32];
u32 m_hi;
u32 m_lo;
// cop0 registers
u32 m_cop0[32];
// internal stuff
int m_icount;
enum branch_state : unsigned
{
NONE = 0,
DELAY = 1, // delay slot instruction active
BRANCH = 2, // branch instruction active
EXCEPTION = 3, // exception triggered
}
m_branch_state;
u32 m_branch_target;
// cache memory
struct cache m_icache;
struct cache m_dcache;
translate_result const m_cache;
bool const m_cache_pws; // cache supports partial-word store
// I/O
devcb_read_line::array<4> m_in_brcond;
bool m_bus_error;
};
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 : 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:
mips1_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size, bool cache_pws);
// device_t implementation
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual translate_result translate(int intention, offs_t &address, bool debug) override;
virtual void handle_cop0(u32 const op) override;
virtual u32 get_cop0_reg(unsigned const reg) override;
virtual void set_cop0_reg(unsigned const reg, u32 const data) override;
virtual void handle_cop1(u32 const op) override;
template <typename T> void set_cop1_reg(unsigned const reg, T const data);
private:
u64 m_reset_time;
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
{
public:
r2000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
};
class r2000a_device : public mips1_device_base
{
public:
r2000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
};
class r3000_device : public mips1_device_base
{
public:
r3000_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
};
class r3000a_device : public mips1_device_base
{
public:
r3000a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 0, size_t dcache_size = 0);
};
class r3041_device : public mips1core_device_base
{
public:
r3041_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
protected:
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
};
class r3051_device : public mips1core_device_base
{
public:
r3051_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
class r3052_device : public mips1core_device_base
{
public:
r3052_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
class r3052e_device : public mips1_device_base
{
public:
r3052e_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
class r3071_device : public mips1_device_base
{
public:
r3071_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
};
class r3081_device : public mips1_device_base
{
public:
r3081_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock, size_t icache_size = 16384, size_t dcache_size = 4096);
};
class iop_device : public mips1core_device_base
{
public:
iop_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
};
DECLARE_DEVICE_TYPE(R2000, r2000_device)
DECLARE_DEVICE_TYPE(R2000A, r2000a_device)
DECLARE_DEVICE_TYPE(R3000, r3000_device)
DECLARE_DEVICE_TYPE(R3000A, r3000a_device)
DECLARE_DEVICE_TYPE(R3041, r3041_device)
DECLARE_DEVICE_TYPE(R3051, r3051_device)
DECLARE_DEVICE_TYPE(R3052, r3052_device)
DECLARE_DEVICE_TYPE(R3052E, r3052e_device)
DECLARE_DEVICE_TYPE(R3071, r3071_device)
DECLARE_DEVICE_TYPE(R3081, r3081_device)
DECLARE_DEVICE_TYPE(SONYPS2_IOP, iop_device)
#endif // MAME_CPU_MIPS_MIPS1_H
|