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
|
#ifndef M68K__HEADER
#define M68K__HEADER
struct m68ki_cpu_core_s;
/* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */
/*
* MUSASHI
* Version 3.3
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
*
* This code may be freely used for non-commercial purposes as long as this
* copyright notice remains unaltered in the source code and any binary files
* containing this code in compiled form.
*
* All other lisencing terms must be negotiated with the author
* (Karl Stenerud).
*
* The latest version of this code can be obtained at:
* http://kstenerud.cjb.net
*/
/* ======================================================================== */
/* ============================ GENERAL DEFINES =========================== */
/* ======================================================================== */
/* There are 7 levels of interrupt to the 68K.
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
*/
#define M68K_IRQ_NONE 0
#define M68K_IRQ_1 1
#define M68K_IRQ_2 2
#define M68K_IRQ_3 3
#define M68K_IRQ_4 4
#define M68K_IRQ_5 5
#define M68K_IRQ_6 6
#define M68K_IRQ_7 7
/* Special interrupt acknowledge values.
* Use these as special returns from the interrupt acknowledge callback
* (specified later in this header).
*/
/* Causes an interrupt autovector (0x18 + interrupt level) to be taken.
* This happens in a real 68K if VPA or AVEC is asserted during an interrupt
* acknowledge cycle instead of DTACK.
*/
#define M68K_INT_ACK_AUTOVECTOR 0xffffffff
/* Causes the spurious interrupt vector (0x18) to be taken
* This happens in a real 68K if BERR is asserted during the interrupt
* acknowledge cycle (i.e. no devices responded to the acknowledge).
*/
#define M68K_INT_ACK_SPURIOUS 0xfffffffe
/* CPU types for use in m68k_set_cpu_type() */
enum
{
M68K_CPU_TYPE_INVALID,
M68K_CPU_TYPE_68000,
M68K_CPU_TYPE_68010,
M68K_CPU_TYPE_68EC020,
M68K_CPU_TYPE_68020,
M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */
M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */
};
/* Registers used by m68k_get_reg() and m68k_set_reg() */
typedef enum
{
/* Real registers */
M68K_REG_D0, /* Data registers */
M68K_REG_D1,
M68K_REG_D2,
M68K_REG_D3,
M68K_REG_D4,
M68K_REG_D5,
M68K_REG_D6,
M68K_REG_D7,
M68K_REG_A0, /* Address registers */
M68K_REG_A1,
M68K_REG_A2,
M68K_REG_A3,
M68K_REG_A4,
M68K_REG_A5,
M68K_REG_A6,
M68K_REG_A7,
M68K_REG_PC, /* Program Counter */
M68K_REG_SR, /* Status Register */
M68K_REG_SP, /* The current Stack Pointer (located in A7) */
M68K_REG_USP, /* User Stack Pointer */
M68K_REG_ISP, /* Interrupt Stack Pointer */
M68K_REG_MSP, /* Master Stack Pointer */
M68K_REG_SFC, /* Source Function Code */
M68K_REG_DFC, /* Destination Function Code */
M68K_REG_VBR, /* Vector Base Register */
M68K_REG_CACR, /* Cache Control Register */
M68K_REG_CAAR, /* Cache Address Register */
/* Assumed registers */
/* These are cheat registers which emulate the 1-longword prefetch
* present in the 68000 and 68010.
*/
M68K_REG_PREF_ADDR, /* Last prefetch address */
M68K_REG_PREF_DATA, /* Last prefetch data */
/* Convenience registers */
M68K_REG_PPC, /* Previous value in the program counter */
M68K_REG_IR, /* Instruction register */
M68K_REG_CPU_TYPE /* Type of CPU being run */
} m68k_register_t;
/* ======================================================================== */
/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
/* ======================================================================== */
/* You will have to implement these functions */
/* read/write functions called by the CPU to access memory.
* while values used are 32 bits, only the appropriate number
* of bits are relevant (i.e. in write_memory_8, only the lower 8 bits
* of value should be written to memory).
*
* NOTE: I have separated the immediate and PC-relative memory fetches
* from the other memory fetches because some systems require
* differentiation between PROGRAM and DATA fetches (usually
* for security setups such as encryption).
* This separation can either be achieved by setting
* M68K_SEPARATE_READS in m68kconf.h and defining
* the read functions, or by setting M68K_EMULATE_FC and
* making a function code callback function.
* Using the callback offers better emulation coverage
* because you can also monitor whether the CPU is in SYSTEM or
* USER mode, but it is also slower.
*/
/* Read from anywhere */
unsigned int m68k_read_memory_8(struct m68ki_cpu_core_s *cpu, unsigned int address);
unsigned int m68k_read_memory_16(struct m68ki_cpu_core_s *cpu, unsigned int address);
unsigned int m68k_read_memory_32(struct m68ki_cpu_core_s *cpu, unsigned int address);
/* Read data immediately following the PC */
//INLINE unsigned int m68k_read_immediate_16(unsigned int address);
//INLINE unsigned int m68k_read_immediate_32(unsigned int address);
/* Read data relative to the PC */
//INLINE unsigned int m68k_read_pcrelative_8(unsigned int address);
//INLINE unsigned int m68k_read_pcrelative_16(unsigned int address);
//INLINE unsigned int m68k_read_pcrelative_32(unsigned int address);
/* Memory access for the disassembler */
unsigned int m68k_read_disassembler_8 (struct m68ki_cpu_core_s *cpu, unsigned int address);
unsigned int m68k_read_disassembler_16 (struct m68ki_cpu_core_s *cpu, unsigned int address);
unsigned int m68k_read_disassembler_32 (struct m68ki_cpu_core_s *cpu, unsigned int address);
/* Write to anywhere */
void m68k_write_memory_8(struct m68ki_cpu_core_s *cpu, unsigned int address, unsigned int value);
void m68k_write_memory_16(struct m68ki_cpu_core_s *cpu, unsigned int address, unsigned int value);
void m68k_write_memory_32(struct m68ki_cpu_core_s *cpu, unsigned int address, unsigned int value);
/* Special call to simulate undocumented 68k behavior when move.l with a
* predecrement destination mode is executed.
* To simulate real 68k behavior, first write the high word to
* [address+2], and then write the low word to [address].
*
* Enable this functionality with M68K_SIMULATE_PD_WRITES in m68kconf.h.
*/
//INLINE void m68k_write_memory_32_pd(unsigned int address, unsigned int value);
/* ======================================================================== */
/* ============================== CALLBACKS =============================== */
/* ======================================================================== */
/* These functions allow you to set callbacks to the host when specific events
* occur. Note that you must enable the corresponding value in m68kconf.h
* in order for these to do anything useful.
* Note: I have defined default callbacks which are used if you have enabled
* the corresponding #define in m68kconf.h but either haven't assigned a
* callback or have assigned a callback of NULL.
*/
/* Set the callback for an interrupt acknowledge.
* You must enable M68K_EMULATE_INT_ACK in m68kconf.h.
* The CPU will call the callback with the interrupt level being acknowledged.
* The host program must return either a vector from 0x02-0xff, or one of the
* special interrupt acknowledge values specified earlier in this header.
* If this is not implemented, the CPU will always assume an autovectored
* interrupt, and will automatically clear the interrupt request when it
* services the interrupt.
* Default behavior: return M68K_INT_ACK_AUTOVECTOR.
*/
void m68k_set_int_ack_callback(struct m68ki_cpu_core_s *cpu, int (*callback)(struct m68ki_cpu_core_s *cpu, int int_level));
/* Set the callback for a breakpoint acknowledge (68010+).
* You must enable M68K_EMULATE_BKPT_ACK in m68kconf.h.
* The CPU will call the callback with whatever was in the data field of the
* BKPT instruction for 68020+, or 0 for 68010.
* Default behavior: do nothing.
*/
void m68k_set_bkpt_ack_callback(struct m68ki_cpu_core_s *cpu, void (*callback)(struct m68ki_cpu_core_s *cpu, unsigned int data));
/* Set the callback for the RESET instruction.
* You must enable M68K_EMULATE_RESET in m68kconf.h.
* The CPU calls this callback every time it encounters a RESET instruction.
* Default behavior: do nothing.
*/
void m68k_set_reset_instr_callback(struct m68ki_cpu_core_s *cpu, void (*callback)(struct m68ki_cpu_core_s *cpu));
/* Set the callback for informing of a large PC change.
* You must enable M68K_MONITOR_PC in m68kconf.h.
* The CPU calls this callback with the new PC value every time the PC changes
* by a large value (currently set for changes by longwords).
* Default behavior: do nothing.
*/
void m68k_set_pc_changed_callback(struct m68ki_cpu_core_s *cpu, void (*callback)(struct m68ki_cpu_core_s *cpu, unsigned int new_pc));
/* Set the callback for CPU function code changes.
* You must enable M68K_EMULATE_FC in m68kconf.h.
* The CPU calls this callback with the function code before every memory
* access to set the CPU's function code according to what kind of memory
* access it is (supervisor/user, program/data and such).
* Default behavior: do nothing.
*/
void m68k_set_fc_callback(struct m68ki_cpu_core_s *cpu, void (*callback)(struct m68ki_cpu_core_s *cpu, unsigned int new_fc));
/* Set a callback for the instruction cycle of the CPU.
* You must enable M68K_INSTRUCTION_HOOK in m68kconf.h.
* The CPU calls this callback just before fetching the opcode in the
* instruction cycle.
* Default behavior: do nothing.
*/
void m68k_set_instr_hook_callback(struct m68ki_cpu_core_s *cpu, void (*callback)(struct m68ki_cpu_core_s *cpu));
/* ======================================================================== */
/* ====================== FUNCTIONS TO ACCESS THE CPU ===================== */
/* ======================================================================== */
/* Use this function to set the CPU type you want to emulate.
* Currently supported types are: M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68010,
* M68K_CPU_TYPE_EC020, and M68K_CPU_TYPE_68020.
*/
void m68k_set_cpu_type(struct m68ki_cpu_core_s *cpu, unsigned int cpu_type);
/* Do whatever initialisations the core requires. Should be called
* at least once at init time.
*/
struct m68ki_cpu_core_s *m68k_init(void);
/* Pulse the RESET pin on the CPU.
* You *MUST* reset the CPU at least once to initialize the emulation
* Note: If you didn't call m68k_set_cpu_type() before resetting
* the CPU for the first time, the CPU will be set to
* M68K_CPU_TYPE_68000.
*/
void m68k_pulse_reset(struct m68ki_cpu_core_s *cpu);
/* execute num_cycles worth of instructions. returns number of cycles used */
int m68k_execute(struct m68ki_cpu_core_s *cpu, int num_cycles);
/* These functions let you read/write/modify the number of cycles left to run
* while m68k_execute() is running.
* These are useful if the 68k accesses a memory-mapped port on another device
* that requires immediate processing by another CPU.
*/
int m68k_cycles_run(struct m68ki_cpu_core_s *cpu); /* Number of cycles run so far */
int m68k_cycles_remaining(struct m68ki_cpu_core_s *cpu); /* Number of cycles left */
void m68k_modify_timeslice(struct m68ki_cpu_core_s *cpu, int cycles); /* Modify cycles left */
void m68k_end_timeslice(struct m68ki_cpu_core_s *cpu); /* End timeslice now */
/* Set the IPL0-IPL2 pins on the CPU (IRQ).
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
* Setting IRQ to 0 will clear an interrupt request.
*/
void m68k_set_irq(struct m68ki_cpu_core_s *cpu, unsigned int int_level);
/* Halt the CPU as if you pulsed the HALT pin. */
void m68k_pulse_halt(struct m68ki_cpu_core_s *cpu);
#if 0
/* Context switching to allow multiple CPUs */
/* Get the size of the cpu context in bytes */
unsigned int m68k_context_size(struct m68ki_cpu_core_s *cpu);
/* Get a cpu context */
unsigned int m68k_get_context(struct m68ki_cpu_core_s *cpu, void* dst);
/* set the current cpu context */
void m68k_set_context(struct m68ki_cpu_core_s *cpu, void* dst);
#endif
/* Register the CPU state information */
void m68k_state_register(struct m68ki_cpu_core_s *cpu, const char *type);
/* Peek at the internals of a CPU context. This can either be a context
* retrieved using m68k_get_context() or the currently running context.
* If context is NULL, the currently running CPU context will be used.
*/
unsigned int m68k_get_reg(struct m68ki_cpu_core_s *cpu, void* context, m68k_register_t reg);
/* Poke values into the internals of the currently running CPU context */
void m68k_set_reg(struct m68ki_cpu_core_s *cpu, m68k_register_t reg, unsigned int value);
/* Check if an instruction is valid for the specified CPU type */
unsigned int m68k_is_valid_instruction(struct m68ki_cpu_core_s *cpu, unsigned int instruction, unsigned int cpu_type);
/* Disassemble 1 instruction using the epecified CPU type at pc. Stores
* disassembly in str_buff and returns the size of the instruction in bytes.
*/
unsigned int m68k_disassemble(struct m68ki_cpu_core_s *cpu, char* str_buff, unsigned int pc, unsigned int cpu_type);
/* ======================================================================== */
/* ============================= CONFIGURATION ============================ */
/* ======================================================================== */
/* Import the configuration for this build */
#include "m68kconf.h"
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */
#endif /* M68K__HEADER */
|