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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
|
// license:GPL-2.0+
// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
/*****************************************************************************
SunPlus µ'nSP emulator
Copyright 2008-2017 Segher Boessenkool <segher@kernel.crashing.org>
Licensed under the terms of the GNU GPL, version 2
http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
Ported to MAME framework by Ryan Holtz
*****************************************************************************/
#ifndef MAME_CPU_UNSP_UNSP_H
#define MAME_CPU_UNSP_UNSP_H
#pragma once
#include "cpu/drcfe.h"
#include "cpu/drcuml.h"
#include "cpu/drcumlsh.h"
#include "unspdefs.h"
/***************************************************************************
CONSTANTS
***************************************************************************/
/* map variables */
#define MAPVAR_PC M0
#define MAPVAR_CYCLES M1
#define SINGLE_INSTRUCTION_MODE (0)
#define ENABLE_UNSP_DRC (1)
#define UNSP_LOG_OPCODES (0)
#define UNSP_LOG_REGS (0)
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class unsp_frontend;
// ======================> unsp_device
enum
{
UNSP_SP = 1,
UNSP_R1,
UNSP_R2,
UNSP_R3,
UNSP_R4,
UNSP_BP,
UNSP_SR,
UNSP_PC,
UNSP_GPR_COUNT = UNSP_PC,
UNSP_IRQ_EN,
UNSP_FIQ_EN,
UNSP_IRQ,
UNSP_FIQ,
#if UNSP_LOG_OPCODES || UNSP_LOG_REGS
UNSP_SB,
UNSP_LOG_OPS
#else
UNSP_SB
#endif
};
enum
{
UNSP_FIQ_LINE = 0,
UNSP_IRQ0_LINE,
UNSP_IRQ1_LINE,
UNSP_IRQ2_LINE,
UNSP_IRQ3_LINE,
UNSP_IRQ4_LINE,
UNSP_IRQ5_LINE,
UNSP_IRQ6_LINE,
UNSP_IRQ7_LINE,
UNSP_BRK_LINE,
UNSP_NUM_LINES
};
class unsp_device : public cpu_device
{
friend class unsp_frontend;
public:
// construction/destruction
unsp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
virtual ~unsp_device();
uint8_t get_csb();
void set_ds(uint16_t ds);
uint16_t get_ds();
inline void ccfunc_unimplemented();
void invalidate_cache();
#if UNSP_LOG_REGS
void log_regs();
void log_write(uint32_t addr, uint32_t data);
void cfunc_log_write();
#endif
protected:
unsp_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal);
// 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 noexcept override { return 5; }
virtual uint32_t execute_max_cycles() const noexcept override { return 5; }
virtual uint32_t execute_input_lines() const noexcept override { return 0; }
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
// device_state_interface overrides
virtual void state_import(const device_state_entry& entry) override;
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;
// HACK: IRQ line state can only be modified directly by hardware on-board the SPG SoC itself.
// Therefore, to avoid an unnecessary scheduler sync when the derived spg2xx_device sets or
// clears an interrupt line, we provide this direct accessor.
void set_state_unsynced(int inputnum, int state);
enum : uint32_t
{
REG_SP = 0,
REG_R1,
REG_R2,
REG_R3,
REG_R4,
REG_BP,
REG_SR,
REG_PC
};
/* internal compiler state */
struct compiler_state
{
compiler_state(compiler_state const&) = delete;
compiler_state& operator=(compiler_state const&) = delete;
uint32_t m_cycles; /* accumulated cycles */
uml::code_label m_labelnum; /* index for local labels */
};
struct internal_unsp_state
{
uint32_t m_r[8]; // why are these 32-bit? they're 16-bit regs? (changing to uint16_t causes crashes tho, so something is depending on this)
uint32_t m_enable_irq;
uint32_t m_enable_fiq;
uint32_t m_irq;
uint32_t m_fiq;
uint32_t m_curirq;
uint32_t m_sirq;
uint32_t m_sb;
uint32_t m_saved_sb[3];
uint32_t m_arg0;
uint32_t m_arg1;
uint32_t m_jmpdest;
int m_icount;
};
/* core state */
internal_unsp_state* m_core;
protected:
uint16_t read16(uint32_t address) { return m_program->read_word(address); }
void write16(uint32_t address, uint16_t data)
{
#if UNSP_LOG_REGS
log_write(address, data);
#endif
m_program->write_word(address, data);
}
void add_lpc(const int32_t offset)
{
const uint32_t new_lpc = UNSP_LPC + offset;
m_core->m_r[REG_PC] = (uint16_t)new_lpc;
m_core->m_r[REG_SR] &= 0xffc0;
m_core->m_r[REG_SR] |= (new_lpc >> 16) & 0x3f;
}
void execute_fxxx_000_group(uint16_t op);
void execute_fxxx_001_group(uint16_t op);
void execute_fxxx_010_group(uint16_t op);
void execute_fxxx_011_group(uint16_t op);
virtual void execute_fxxx_101_group(uint16_t op);
void execute_fxxx_110_group(uint16_t op);
void execute_fxxx_111_group(uint16_t op);
void execute_fxxx_group(uint16_t op);;
void execute_fxxx_100_group(uint16_t op);
virtual void execute_extended_group(uint16_t op);
virtual void execute_exxx_group(uint16_t op);
void unimplemented_opcode(uint16_t op);
void unimplemented_opcode(uint16_t op, uint16_t ximm);
void unimplemented_opcode(uint16_t op, uint16_t ximm, uint16_t ximm_2);
int m_iso;
static char const *const regs[];
static char const *const extregs[];
static char const *const bitops[];
static char const *const lsft[];
static char const *const aluops[];
static char const *const forms[];
void push(uint32_t value, uint32_t *reg);
uint16_t pop(uint32_t *reg);
void update_nz(uint32_t value);
void update_nzsc(uint32_t value, uint16_t r0, uint16_t r1);
private:
// compilation boundaries -- how far back/forward does the analysis extend?
enum : uint32_t
{
COMPILE_BACKWARDS_BYTES = 128,
COMPILE_FORWARDS_BYTES = 512,
COMPILE_MAX_INSTRUCTIONS = (COMPILE_BACKWARDS_BYTES / 4) + (COMPILE_FORWARDS_BYTES / 4),
COMPILE_MAX_SEQUENCE = 64
};
// exit codes
enum : int
{
EXECUTE_OUT_OF_CYCLES = 0,
EXECUTE_MISSING_CODE = 1,
EXECUTE_UNMAPPED_CODE = 2,
EXECUTE_RESET_CACHE = 3
};
void execute_jumps(const uint16_t op);
void execute_remaining(const uint16_t op);
void execute_one(const uint16_t op);
address_space_config m_program_config;
address_space *m_program;
std::function<u16 (offs_t)> m_pr16;
std::function<const void * (offs_t)> m_prptr;
uint32_t m_debugger_temp;
#if UNSP_LOG_OPCODES || UNSP_LOG_REGS
uint32_t m_log_ops;
#endif
inline void trigger_fiq();
inline void trigger_irq(int line);
void check_irqs();
drc_cache m_cache;
std::unique_ptr<drcuml_state> m_drcuml;
std::unique_ptr<unsp_frontend> m_drcfe;
uint32_t m_drcoptions;
uint8_t m_cache_dirty;
uml::parameter m_regmap[16];
uml::code_handle *m_entry;
uml::code_handle *m_nocode;
uml::code_handle *m_out_of_cycles;
uml::code_handle *m_check_interrupts;
uml::code_handle *m_trigger_fiq;
uml::code_handle *m_trigger_irq;
uml::code_handle *m_mem_read;
uml::code_handle *m_mem_write;
bool m_enable_drc;
void execute_run_drc();
void flush_drc_cache();
void code_flush_cache();
void code_compile_block(offs_t pc);
void load_fast_iregs(drcuml_block &block);
void save_fast_iregs(drcuml_block &block);
void static_generate_entry_point();
void static_generate_nocode_handler();
void static_generate_out_of_cycles();
void static_generate_check_interrupts();
void static_generate_trigger_fiq();
void static_generate_trigger_irq();
void static_generate_memory_accessor(bool iswrite, const char *name, uml::code_handle *&handleptr);
void generate_branch(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
void generate_check_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param);
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_add_lpc(drcuml_block &block, int32_t offset);
void generate_update_nzsc(drcuml_block &block);
void generate_update_nz(drcuml_block &block);
void log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op);
bool generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
#if UNSP_LOG_REGS
FILE *m_log_file;
#endif
};
class unsp_11_device : public unsp_device
{
public:
// construction/destruction
unsp_11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
unsp_11_device(const machine_config& mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal);
private:
};
class unsp_12_device : public unsp_11_device
{
public:
// construction/destruction
unsp_12_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
unsp_12_device(const machine_config& mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal);
virtual void execute_fxxx_101_group(uint16_t op) override;
virtual void execute_exxx_group(uint16_t op) override;
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
};
class unsp_20_device : public unsp_12_device
{
public:
// construction/destruction
unsp_20_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
unsp_20_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal);
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
virtual void execute_extended_group(uint16_t op) override;
virtual void device_start() override;
virtual void device_reset() override;
private:
uint32_t m_secondary_r[8];
enum
{
UNSP20_R8 = 0,
UNSP20_R9,
UNSP20_R10,
UNSP20_R11,
UNSP20_R12,
UNSP20_R13,
UNSP20_R14,
UNSP20_R15
};
};
DECLARE_DEVICE_TYPE(UNSP, unsp_device)
DECLARE_DEVICE_TYPE(UNSP_11, unsp_11_device)
DECLARE_DEVICE_TYPE(UNSP_12, unsp_12_device)
DECLARE_DEVICE_TYPE(UNSP_20, unsp_20_device)
#endif // MAME_CPU_UNSP_UNSP_H
|