Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/yabause/src/m68kq68.c
2 views
1
/* src/m68kpsp.c: Q68 emulator interface
2
Copyright 2009 Andrew Church
3
4
This file is part of Yabause.
5
6
Yabause is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
10
11
Yabause is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
15
16
You should have received a copy of the GNU General Public License
17
along with Yabause; if not, write to the Free Software
18
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
*/
20
21
#include "yabause.h"
22
#include "m68kcore.h"
23
24
#include "q68/q68.h"
25
26
/*************************************************************************/
27
28
/**
29
* NEED_TRAMPOLINE: Defined on platforms where we need trampoline
30
* functions to convert read/write calls from the native format to the
31
* FASTCALL format used by Yabause.
32
*/
33
#ifdef CPU_X86
34
# define NEED_TRAMPOLINE
35
#endif
36
37
/**
38
* PROFILE_68K: Perform simple profiling of the 68000 emulation, reporting
39
* the average time per 68000 clock cycle. (Realtime execution would be
40
* around 88.5 nsec/cycle.)
41
*
42
* Note that this profiling has an overhead of two YabauseGetTicks() calls
43
* for each M68K->Exec() call; on PSP, this amounts to about 3.8 usec per
44
* Exec(), or 52.8 nsec/cycle at 72 cycles/call.
45
*/
46
// #define PROFILE_68K
47
48
// #define COUNT_OPCODES // see COUNT_OPCODES in q68-core.c
49
50
/*************************************************************************/
51
52
/* Interface function declarations (must come before interface definition) */
53
54
static int m68kq68_init(void);
55
static void m68kq68_deinit(void);
56
static void m68kq68_reset(void);
57
58
static FASTCALL s32 m68kq68_exec(s32 cycles);
59
static void m68kq68_sync(void);
60
61
static u32 m68kq68_get_dreg(u32 num);
62
static u32 m68kq68_get_areg(u32 num);
63
static u32 m68kq68_get_pc(void);
64
static u32 m68kq68_get_sr(void);
65
static u32 m68kq68_get_usp(void);
66
static u32 m68kq68_get_ssp(void);
67
68
static void m68kq68_set_dreg(u32 num, u32 val);
69
static void m68kq68_set_areg(u32 num, u32 val);
70
static void m68kq68_set_pc(u32 val);
71
static void m68kq68_set_sr(u32 val);
72
static void m68kq68_set_usp(u32 val);
73
static void m68kq68_set_ssp(u32 val);
74
75
static FASTCALL void m68kq68_set_irq(s32 level);
76
static FASTCALL void m68kq68_write_notify(u32 address, u32 size);
77
78
static void m68kq68_set_fetch(u32 low_addr, u32 high_addr, pointer fetch_addr);
79
static void m68kq68_set_readb(M68K_READ *func);
80
static void m68kq68_set_readw(M68K_READ *func);
81
static void m68kq68_set_writeb(M68K_WRITE *func);
82
static void m68kq68_set_writew(M68K_WRITE *func);
83
84
static uint32_t dummy_read(uint32_t address);
85
static void dummy_write(uint32_t address, uint32_t data);
86
87
#ifdef NEED_TRAMPOLINE
88
static uint32_t readb_trampoline(uint32_t address);
89
static uint32_t readw_trampoline(uint32_t address);
90
static void writeb_trampoline(uint32_t address, uint32_t data);
91
static void writew_trampoline(uint32_t address, uint32_t data);
92
#endif
93
94
/*-----------------------------------------------------------------------*/
95
96
/* Module interface definition */
97
98
M68K_struct M68KQ68 = {
99
.id = M68KCORE_Q68,
100
.Name = "Q68 68k Emulator Interface",
101
102
.Init = m68kq68_init,
103
.DeInit = m68kq68_deinit,
104
.Reset = m68kq68_reset,
105
106
.Exec = m68kq68_exec,
107
.Sync = m68kq68_sync,
108
109
.GetDReg = m68kq68_get_dreg,
110
.GetAReg = m68kq68_get_areg,
111
.GetPC = m68kq68_get_pc,
112
.GetSR = m68kq68_get_sr,
113
.GetUSP = m68kq68_get_usp,
114
.GetMSP = m68kq68_get_ssp,
115
116
.SetDReg = m68kq68_set_dreg,
117
.SetAReg = m68kq68_set_areg,
118
.SetPC = m68kq68_set_pc,
119
.SetSR = m68kq68_set_sr,
120
.SetUSP = m68kq68_set_usp,
121
.SetMSP = m68kq68_set_ssp,
122
123
.SetIRQ = m68kq68_set_irq,
124
.WriteNotify = m68kq68_write_notify,
125
126
.SetFetch = m68kq68_set_fetch,
127
.SetReadB = m68kq68_set_readb,
128
.SetReadW = m68kq68_set_readw,
129
.SetWriteB = m68kq68_set_writeb,
130
.SetWriteW = m68kq68_set_writew,
131
};
132
133
/*-----------------------------------------------------------------------*/
134
135
/* Virtual processor state block */
136
137
static Q68State *state;
138
139
140
#ifdef NEED_TRAMPOLINE
141
142
/* Read/write functions passed to Set{Read,Write}[BW], called via the
143
* trampolines */
144
static M68K_READ *real_readb, *real_readw;
145
static M68K_WRITE *real_writeb, *real_writew;
146
147
#endif
148
149
/*************************************************************************/
150
/************************** Interface functions **************************/
151
/*************************************************************************/
152
153
/**
154
* m68kq68_init: Initialize the virtual processpr.
155
*
156
* [Parameters]
157
* None
158
* [Return value]
159
* Zero on success, negative on failure
160
*/
161
static int m68kq68_init(void)
162
{
163
if (!(state = q68_create())) {
164
return -1;
165
}
166
q68_set_irq(state, 0);
167
q68_set_readb_func(state, dummy_read);
168
q68_set_readw_func(state, dummy_read);
169
q68_set_writeb_func(state, dummy_write);
170
q68_set_writew_func(state, dummy_write);
171
172
return 0;
173
}
174
175
/*-----------------------------------------------------------------------*/
176
177
/**
178
* m68kq68_deinit: Destroy the virtual processor.
179
*
180
* [Parameters]
181
* None
182
* [Return value]
183
* None
184
*/
185
static void m68kq68_deinit(void)
186
{
187
q68_destroy(state);
188
state = NULL;
189
}
190
191
/*-----------------------------------------------------------------------*/
192
193
/**
194
* m68kq68_reset: Reset the virtual processor.
195
*
196
* [Parameters]
197
* None
198
* [Return value]
199
* None
200
*/
201
static void m68kq68_reset(void)
202
{
203
q68_reset(state);
204
}
205
206
/*************************************************************************/
207
208
/**
209
* m68kq68_exec: Execute instructions for the given number of clock cycles.
210
*
211
* [Parameters]
212
* cycles: Number of clock cycles to execute
213
* [Return value]
214
* Number of clock cycles actually executed
215
*/
216
static FASTCALL s32 m68kq68_exec(s32 cycles)
217
{
218
#ifdef PROFILE_68K
219
static uint32_t tot_cycles = 0, tot_usec = 0, tot_ticks = 0;
220
static uint32_t last_report = 0;
221
uint32_t start, end;
222
start = (uint32_t) YabauseGetTicks();
223
int retval = q68_run(state, cycles);
224
end = (uint32_t) YabauseGetTicks();
225
tot_cycles += cycles;
226
tot_ticks += end - start;
227
if (tot_cycles/1000000 > last_report) {
228
tot_usec += (uint64_t)tot_ticks * 1000000 / yabsys.tickfreq;
229
tot_ticks = 0;
230
fprintf(stderr, "%ld cycles in %.3f sec = %.3f nsec/cycle\n",
231
(long)tot_cycles, (double)tot_usec/1000000,
232
((double)tot_usec / (double)tot_cycles) * 1000);
233
last_report = tot_cycles/1000000;
234
# ifdef COUNT_OPCODES
235
if (last_report % 100 == 0) {
236
extern uint32_t q68_ops[128], q68_4xxx_ops[32];
237
int i;
238
fprintf(stderr, "Opcodes per 1M cycles:\n");
239
for (i = 0; i < 128; i++) {
240
fprintf(stderr, "%s%8ld%s", i%8==0 ? " " : "",
241
(long)((q68_ops[i] + last_report/2) / last_report),
242
i%8==7 ? "\n" : "");
243
}
244
fprintf(stderr, "$4xxx opcodes per 1M cycles:\n");
245
for (i = 0; i < 32; i++) {
246
fprintf(stderr, "%s%8ld%s", i%8==0 ? " " : "",
247
(long)((q68_4xxx_ops[i] + last_report/2) / last_report),
248
i%8==7 ? "\n" : "");
249
}
250
}
251
# endif // COUNT_OPCODES
252
}
253
return retval;
254
#else // !PROFILE_68K
255
return q68_run(state, cycles);
256
#endif
257
}
258
259
/*-----------------------------------------------------------------------*/
260
261
/**
262
* m68kq68_sync: Wait for background execution to finish.
263
*
264
* [Parameters]
265
* None
266
* [Return value]
267
* None
268
*/
269
static void m68kq68_sync(void)
270
{
271
/* Nothing to do */
272
}
273
274
/*************************************************************************/
275
276
/**
277
* m68kq68_get_{dreg,areg,pc,sr,usp,ssp}: Return the current value of
278
* the specified register.
279
*
280
* [Parameters]
281
* num: Register number (m68kq68_get_dreg(), m68kq68_get_areg() only)
282
* [Return value]
283
* None
284
*/
285
286
static u32 m68kq68_get_dreg(u32 num)
287
{
288
return q68_get_dreg(state, num);
289
}
290
291
static u32 m68kq68_get_areg(u32 num)
292
{
293
return q68_get_areg(state, num);
294
}
295
296
static u32 m68kq68_get_pc(void)
297
{
298
return q68_get_pc(state);
299
}
300
301
static u32 m68kq68_get_sr(void)
302
{
303
return q68_get_sr(state);
304
}
305
306
static u32 m68kq68_get_usp(void)
307
{
308
return q68_get_usp(state);
309
}
310
311
static u32 m68kq68_get_ssp(void)
312
{
313
return q68_get_ssp(state);
314
}
315
316
/*-----------------------------------------------------------------------*/
317
318
/**
319
* m68kq68_set_{dreg,areg,pc,sr,usp,ssp}: Set the value of the specified
320
* register.
321
*
322
* [Parameters]
323
* num: Register number (m68kq68_set_dreg(), m68kq68_set_areg() only)
324
* val: Value to set
325
* [Return value]
326
* None
327
*/
328
329
static void m68kq68_set_dreg(u32 num, u32 val)
330
{
331
q68_set_dreg(state, num, val);
332
}
333
334
static void m68kq68_set_areg(u32 num, u32 val)
335
{
336
q68_set_areg(state, num, val);
337
}
338
339
static void m68kq68_set_pc(u32 val)
340
{
341
q68_set_pc(state, val);
342
}
343
344
static void m68kq68_set_sr(u32 val)
345
{
346
q68_set_sr(state, val);
347
}
348
349
static void m68kq68_set_usp(u32 val)
350
{
351
q68_set_usp(state, val);
352
}
353
354
static void m68kq68_set_ssp(u32 val)
355
{
356
q68_set_ssp(state, val);
357
}
358
359
/*************************************************************************/
360
361
/**
362
* m68kq68_set_irq: Deliver an interrupt to the processor.
363
*
364
* [Parameters]
365
* level: Interrupt level (0-7)
366
* [Return value]
367
* None
368
*/
369
static FASTCALL void m68kq68_set_irq(s32 level)
370
{
371
q68_set_irq(state, level);
372
}
373
374
/*-----------------------------------------------------------------------*/
375
376
/**
377
* m68kq68_write_notify: Inform the 68k emulator that the given address
378
* range has been modified.
379
*
380
* [Parameters]
381
* address: 68000 address of modified data
382
* size: Size of modified data in bytes
383
* [Return value]
384
* None
385
*/
386
static FASTCALL void m68kq68_write_notify(u32 address, u32 size)
387
{
388
q68_touch_memory(state, address, size);
389
}
390
391
/*************************************************************************/
392
393
/**
394
* m68kq68_set_fetch: Set the instruction fetch pointer for a region of
395
* memory. Not used by Q68.
396
*
397
* [Parameters]
398
* low_addr: Low address of memory region to set
399
* high_addr: High address of memory region to set
400
* fetch_addr: Pointer to corresponding memory region (NULL to disable)
401
* [Return value]
402
* None
403
*/
404
static void m68kq68_set_fetch(u32 low_addr, u32 high_addr, pointer fetch_addr)
405
{
406
}
407
408
/*-----------------------------------------------------------------------*/
409
410
/**
411
* m68kq68_set_{readb,readw,writeb,writew}: Set functions for reading or
412
* writing bytes or words in memory.
413
*
414
* [Parameters]
415
* func: Function to set
416
* [Return value]
417
* None
418
*/
419
420
static void m68kq68_set_readb(M68K_READ *func)
421
{
422
#ifdef NEED_TRAMPOLINE
423
real_readb = func;
424
q68_set_readb_func(state, readb_trampoline);
425
#else
426
q68_set_readb_func(state, (Q68ReadFunc *)func);
427
#endif
428
}
429
430
static void m68kq68_set_readw(M68K_READ *func)
431
{
432
#ifdef NEED_TRAMPOLINE
433
real_readw = func;
434
q68_set_readw_func(state, readw_trampoline);
435
#else
436
q68_set_readw_func(state, (Q68ReadFunc *)func);
437
#endif
438
}
439
440
static void m68kq68_set_writeb(M68K_WRITE *func)
441
{
442
#ifdef NEED_TRAMPOLINE
443
real_writeb = func;
444
q68_set_writeb_func(state, writeb_trampoline);
445
#else
446
q68_set_writeb_func(state, (Q68WriteFunc *)func);
447
#endif
448
}
449
450
static void m68kq68_set_writew(M68K_WRITE *func)
451
{
452
#ifdef NEED_TRAMPOLINE
453
real_writew = func;
454
q68_set_writew_func(state, writew_trampoline);
455
#else
456
q68_set_writew_func(state, (Q68WriteFunc *)func);
457
#endif
458
}
459
460
/*************************************************************************/
461
462
/**
463
* dummy_read: Default read function, always returning 0 for any address.
464
*
465
* [Parameters]
466
* address: Address to read from
467
* [Return value]
468
* Value read (always zero)
469
*/
470
static uint32_t dummy_read(uint32_t address)
471
{
472
return 0;
473
}
474
475
/*-----------------------------------------------------------------------*/
476
477
/**
478
* dummy_write: Default write function, ignoring all writes.
479
*
480
* [Parameters]
481
* address: Address to write to
482
* data: Value to write
483
* [Return value]
484
* None
485
*/
486
static void dummy_write(uint32_t address, uint32_t data)
487
{
488
}
489
490
/*-----------------------------------------------------------------------*/
491
492
#ifdef NEED_TRAMPOLINE
493
494
/**
495
* read[bw]_trampoline, write[bw]_trampoline: Adjust calling conventions
496
* between the M68k emulator and Yabause's M68k core.
497
*
498
* [Parameters]
499
* address: Address to read from
500
* data: Value to write (only for write_trampoline)
501
* [Return value]
502
* Value read (only for read_trampoline)
503
*/
504
505
static uint32_t readb_trampoline(uint32_t address) {
506
return (*real_readb)(address);
507
}
508
509
static uint32_t readw_trampoline(uint32_t address) {
510
return (*real_readw)(address);
511
}
512
513
static void writeb_trampoline(uint32_t address, uint32_t data) {
514
return (*real_writeb)(address, data);
515
}
516
517
static void writew_trampoline(uint32_t address, uint32_t data) {
518
return (*real_writew)(address, data);
519
}
520
521
#endif // NEED_TRAMPOLINE
522
523
/*************************************************************************/
524
/*************************************************************************/
525
526
/*
527
* Local variables:
528
* c-file-style: "stroustrup"
529
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
530
* indent-tabs-mode: nil
531
* End:
532
*
533
* vim: expandtab shiftwidth=4:
534
*/
535
536