Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/attic/PsxHawk.Core/psx.h
2 views
1
/*
2
this file contains the core psx system and cpu emulation declarations.
3
implementations may be in several places.
4
*/
5
6
#pragma once
7
8
//#define NOCASE() __assume(0);
9
#define NOCASE()
10
#define ENABLE_CONOUT true
11
12
//#define DPRINT(...)
13
#define NOPRINT(...)
14
#define DPRINT(...) { fprintf(__VA_ARGS__); }
15
#define DEBUG(...) { DPRINT(stdout,__VA_ARGS__); }
16
#define DEBUG_PRINT(...) { NOPRINT(stderr,__VA_ARGS__); }
17
#define DEBUG_LOAD(...) { NOPRINT(stdout,__VA_ARGS__); }
18
#define DEBUG_STORE(...) { NOPRINT(stdout,__VA_ARGS__); }
19
#define DEBUG_TRACE(...) { DPRINT(stdout,__VA_ARGS__); }
20
#define DEBUG_HWREG(...) { DPRINT(stdout,__VA_ARGS__); }
21
#define DEBUG_SIO(...) { DPRINT(stdout,__VA_ARGS__); }
22
23
#define PSX_CLOCK 33868800
24
25
#include "types.h"
26
27
enum eOp
28
{
29
eOP_NULLIFIED, //nullified by exception
30
eOP_ILL,
31
eOP_SLL, eOP_SRL, eOP_SRA, eOP_SLLV,
32
eOP_SRLV, eOP_SRAV,
33
eOP_JR, eOP_JALR,
34
eOP_SYSCALL, eOP_BREAK,
35
eOP_MFHI, eOP_MTHI, eOP_MFLO, eOP_MTLO,
36
eOP_MULT, eOP_MULTU, eOP_DIV, eOP_DIVU,
37
eOP_ADD, eOP_ADDU,
38
eOP_SUB, eOP_SUBU,
39
eOP_AND, eOP_OR,
40
eOP_XOR, eOP_NOR,
41
eOP_SLT, eOP_SLTU,
42
eOP_NULL,
43
eOP_BCOND,
44
eOP_J, eOP_JAL,
45
eOP_BEQ, eOP_BNE, eOP_BLEZ, eOP_BGTZ,
46
eOP_ADDI, eOP_ADDIU,
47
eOP_SLTI, eOP_SLTIU,
48
eOP_ANDI, eOP_ORI,
49
eOP_XORI, eOP_LUI,
50
eOP_COPROC,
51
eOP_LB, eOP_LH, eOP_LWL, eOP_LW, eOP_LBU, eOP_LHU, eOP_LWR, eOP_SB, eOP_SH, eOP_SWL, eOP_SW, eOP_SWR,
52
eOP_LWC0, eOP_LWC1, eOP_LWC2, eOP_LWC3,
53
eOP_SWC0, eOP_SWC1, eOP_SWC2, eOP_SWC3
54
};
55
56
57
//reference PSXJIN sources for this
58
#pragma pack(push,1)
59
struct PSX_EXE_Header
60
{
61
char magic[8]; //PS-X EXE
62
u32 text_exe_offset; //location of text section in exe image
63
u32 data_exe_offset; //location of data section in exe image
64
u32 init_pc; //initial PC of program
65
u32 init_gp; //initial GP of program
66
u32 text_load_addr; //detination load address of text section
67
u32 text_size; //size of text section
68
u32 data_load_addr; //detination load address of data section
69
u32 data_size; //size of data section
70
u32 b_addr, b_size; //unknown
71
u32 stack_load_addr; //aka init_sp; initial SP of program
72
u32 stack_size; //stack size (not used?)
73
u32 saved_sp, saved_fp, saved_gp, saved_ra, saved_so; //not used
74
};
75
#pragma pack(pop)
76
77
#define RAM_SIZE (8*1024*1024)
78
#define RAM_MASK (RAM_SIZE-1)
79
#define VRAM_SIZE (1024*1024)
80
#define VRAM_MASK (VRAM_SIZE-1)
81
#define BIOS_SIZE (512*1024)
82
#define BIOS_MASK (BIOS_SIZE-1)
83
#define SCRATCH_SIZE (1024)
84
#define SCRATCH_MASK (SCRATCH_SIZE-1)
85
#define PIO_SIZE (65536)
86
#define PIO_MASK (PIO_SIZE-1)
87
88
//this class should try to organize all psx system state and methods as compactly as possible.
89
//let's not mix up anything else in here.
90
class __declspec(dllexport) PSX
91
{
92
public:
93
u8 vram[VRAM_SIZE];
94
u8 bios[BIOS_SIZE];
95
u8 scratch[SCRATCH_SIZE];
96
u8 pio[PIO_SIZE];
97
u8 ram[RAM_SIZE];
98
99
enum eScheduleItemType
100
{
101
eScheduleItemType_NIL, //used as a sentinel for list processing
102
eScheduleItemType_null,
103
eScheduleItemType_test, //to be removed later
104
eScheduleItemType_sio0,
105
eScheduleItemType_sio1,
106
eScheduleItemType_gpu,
107
eScheduleItemType_NUM
108
};
109
struct SCHED
110
{
111
struct IScheduleItem
112
{
113
u32 time;
114
eScheduleItemType next, prev;
115
};
116
117
union
118
{
119
IScheduleItem items[eScheduleItemType_NUM];
120
struct
121
{
122
IScheduleItem NIL, null, test;
123
IScheduleItem sio[2];
124
IScheduleItem gpu;
125
};
126
};
127
eScheduleItemType head;
128
u32 nextTime;
129
void escape() { nextTime = 0; }
130
131
//dequeues the head item from the list.
132
eScheduleItemType dequeue();
133
//removes the specified item from the list
134
void remove(eScheduleItemType todoType);
135
//inserts this item to the list in sorted order by timestamp
136
void insert(eScheduleItemType todoType);
137
138
} sched;
139
140
141
struct IRQ
142
{
143
static const u16 WIRE_MASK = 0x3FD;
144
union
145
{
146
struct
147
{
148
u16 vsync:1, gpu:1, cd:1, dma:1, rcnt0:1, rcnt1:1, rcnt2:1, sio0:1, sio1:1, spu:1, extcd:1;
149
u16 unknown2:6;
150
};
151
u16 value;
152
} flags;
153
union
154
{
155
struct
156
{
157
u16 vsync:1, gpu:1, cd:1, dma:1, rcnt0:1, rcnt1:1, rcnt2:1, sio0:1, sio1:1, spu:1, extcd:1;
158
u16 unknown2:6;
159
};
160
u16 value;
161
} mask;
162
} irq;
163
164
struct SystemRegs
165
{
166
//regs starting at 0x1f801000 accessed at bios init and maybe other times.
167
u32 biosInit[9]; //mednafen knows a little bit about these but doesnt use them for anything
168
} sysregs;
169
170
struct SioController
171
{
172
union
173
{
174
struct
175
{
176
u16 prescaler_type:2;
177
};
178
u16 value;
179
} mode;
180
181
union StatusReg
182
{
183
struct
184
{
185
u16 TX_RDY:1;
186
u16 RX_RDY:1;
187
u16 TX_EMPTY:1;
188
u16 nothing:1;
189
u16 OVERRUN:1;
190
u16 nothing2:2;
191
u16 DSR:1;
192
u16 nothing3:1;
193
u16 IRQ:1;
194
};
195
u16 value;
196
};
197
198
union ControlReg
199
{
200
struct
201
{
202
u16 TX_ENA:1;
203
u16 DTR:1; //this differs from mame's code (this seems to be the actual DTR signal. )
204
u16 nothing:2;
205
u16 IACK:1;
206
u16 nothing2:1;
207
u16 RESET:1;
208
u16 nothing3:3;
209
u16 TX_IENA:1;
210
u16 RX_IENA:1;
211
u16 DSR_IENA:1;
212
u16 PORT_SEL:1; //this differs from mame's code (this seems to be the port select). but that doesnt make sense because the 5x registers should be used for the other port. is the other port the actual serial i/o module?
213
};
214
u16 value;
215
};
216
217
StatusReg status;
218
ControlReg control;
219
u16 baud_reg;
220
//this is just used for diagnostic purposes (maybe it should be labeled as such?)
221
float CalculateBaud();
222
223
void Reset();
224
225
} sio[2];
226
227
struct CPU
228
{
229
enum eException //taken from mednafen
230
{
231
eException_INT = 0,
232
eException_MOD = 1,
233
eException_TLBL = 2,
234
eException_TLBS = 3,
235
eException_ADEL = 4, // Address error on load
236
eException_ADES = 5, // Address error on store
237
eException_IBE = 6, // Instruction bus error
238
eException_DBE = 7, // Data bus error
239
eException_SYSCALL = 8, // System call
240
eException_BP = 9, // Breakpoint
241
eException_RI = 10, // Reserved instruction
242
eException_COPU = 11, // Coprocessor unusable
243
eException_OV = 12, // Arithmetic overflow
244
eException_None = 16
245
};
246
247
union
248
{
249
struct
250
{
251
u32 r0, //should this be called zero or r0? well, psxjin and mednafen call it r0 so we'll stick with it
252
at, v0, v1, a0, a1, a2, a3,
253
t0, t1, t2, t3, t4, t5, t6, t7,
254
s0, s1, s2, s3, s4, s5, s6, s7,
255
t8, t9, k0, k1, gp,
256
sp, //29 - stack pointer
257
s8, //30 - ??
258
ra, //31 - return address (link register)
259
lo, hi;
260
//pc;
261
};
262
263
//Lo, Hi in r[33] and r[34];
264
//PC in r[35]
265
u32 r[34];
266
} regs;
267
268
union SR_REG
269
{
270
//these bits must be zero when read from the register (not wired to anything) [todo - check whether they cache values]
271
static const int ZERO_MASK = 0x8D8000C0;
272
273
//info taken from http://psx.rules.org/system.txt
274
struct
275
{
276
u32
277
IEc:1, //Interrupts Enabled current (0=enabled, 1=disabled)
278
KUc:1, //KUcurrent: privilege level (0=user, 1=kernel)
279
IEp:1, //?
280
KUp:1, //KUpushed: KUc pushes here on an exception, rfe pops KUo here
281
IEo:1, //Interrupts Enabled (0=enabled, 1=disabled) (rfe pops KUp here)
282
KUo:1, //KUother?: KUp gets pushed here on an exception
283
zeros:2,
284
IM:8, //interrupt mask fields (are these used in any way? im not sure. you would expect at least one of them to be) [bit2 maybe?]
285
IsC:1, //Isolate [data] Cache: unhook data cache from memory. PSX has no data cache, so this causes memory writes to get discarded
286
SwC:1, //Swap Cache: Not sure what this does on PSX but its suggested to use with IsC to invalidate the I-Cache. May need to investigate this.
287
PZ:1, //When set cache parity bits are written as 0
288
CM:1, //something relating to data cache
289
PE:1, //Cache parity error. Does not cause exception.
290
TS:1, //TLB shutdown. Gets set if a programm address simultaniously matches 2 TLB entries.
291
BEV:1, //boot exception vectors (0=ram, 1=rom [kseg1])
292
zeros_2:2,
293
RE:1, //reverse endianness. hope nobody uses this!
294
zeros_3:2,
295
CU0:1, //coprocessor 0 control (0=kernel mode, 1=user mode); controls access to certain instructions
296
CU1:1, //coprocessor 1 enabled (does nothing in PSX. should it return zeros?)
297
CU2:1, //coprocessor 2 enabled
298
zeros_4:1;
299
};
300
u32 value;
301
};
302
union CAUSE_REG
303
{
304
struct
305
{
306
u32 zeros_1:2;
307
u32 ExcCode:4;
308
u32 zeros_2:2;
309
u32 Sw:2; //software interrupts ?
310
u32 IP:6; //interrupts pending (external interrupts latched? IP[5..0] = Interrupt[5..0] according to r2000 arch doc)
311
u32 zeros_3:12;
312
u32 CE:2; //coprocessor error-which coprocessor threw a Coprocessor Unusable exception?
313
u32 zeros_4:1;
314
u32 BD:1; //set to 1 if the last exception was taken while executing in a branch delay slot
315
};
316
u32 value;
317
};
318
319
union
320
{
321
struct
322
{
323
u32
324
Index, Random, EntryLo0, EntryLo1,
325
Context, PageMask, Wired, Reserved0,
326
BadVAddr, Count, EntryHi, Compare;
327
328
SR_REG SR; //12 - status register
329
CAUSE_REG Cause; //13 - cause register
330
331
u32 EPC; //14 - the PC of the victim
332
u32 PRid; //15 - ??
333
334
u32
335
Config, LLAddr, WatchLO, WatchHI,
336
XContext, Reserved1, Reserved2, Reserved3,
337
Reserved4, Reserved5, ECC, CacheErr,
338
TagLo, TagHi, ErrorEPC, Reserved6;
339
};
340
u32 r[32];
341
} cp0;
342
343
enum eFormat
344
{
345
eFormat_IType, eFormat_RType, eFormat_JType_J, eFormat_JType_JAL, eFormat_CType, eFormat_Other
346
};
347
348
struct Instruction_ITYPE
349
{
350
u32 immediate:16;
351
s32 signed_offset() const { return (s16)immediate; }
352
s32 signed_target() const { return (signed_offset()<<2) + 4; /*hack!!! dunno how this PC accounting is supposed to work*/ }
353
u32 rt:5;
354
u32 rs:5;
355
u32 base() const { return rs; }
356
u32 opcode:6;
357
};
358
359
struct Instruction_CTYPE
360
{
361
u32 function:6;
362
u32 zeros:5;
363
u32 rd:5;
364
u32 rt:5;
365
u32 format:5;
366
u32 cpnum:2;
367
u32 opcode_hi:4;
368
};
369
370
union Instruction_RTYPE
371
{
372
struct
373
{
374
u32 function:6;
375
u32 sa:5;
376
u32 rd:5;
377
u32 rt:5;
378
u32 rs:5;
379
u32 opcode:6;
380
};
381
u32 value;
382
u32 break_code() const { return (value>>6)&0xFFFFF; }
383
};
384
385
struct Instruction_JTYPE
386
{
387
u32 target:26;
388
u32 opcode:6;
389
};
390
391
union Instruction
392
{
393
Instruction_ITYPE ITYPE;
394
Instruction_RTYPE RTYPE;
395
Instruction_JTYPE JTYPE;
396
Instruction_CTYPE CTYPE;
397
u32 value;
398
};
399
400
struct DecodedInstruction
401
{
402
Instruction instr;
403
eOp op;
404
};
405
406
struct {
407
bool IsRunning() const { return timer>0; }
408
u32 timer;
409
u32 lo, hi;
410
} unit_muldiv;
411
412
struct
413
{
414
u32 in_fetch_addr;
415
DecodedInstruction decode; //call this output?
416
} p_fetch;
417
418
struct
419
{
420
u32 instr;
421
u32 regs[3];
422
} p_rd;
423
424
enum eMemOp
425
{
426
eMemOp_Unset, eMemOp_None,
427
eMemOp_StoreWord, eMemOp_StoreHalfword, eMemOp_StoreByte,
428
eMemOp_LoadWord, eMemOp_LoadHalfwordSigned, eMemOp_LoadHalfwordUnsigned, eMemOp_LoadByteSigned, eMemOp_LoadByteUnsigned,
429
eMemOp_MTC, eMemOp_MFC,
430
};
431
432
struct ALU_OUTPUT
433
{
434
union
435
{
436
u32 addr;
437
};
438
union {
439
u32 value;
440
u32 rt;
441
};
442
eMemOp op;
443
};
444
445
struct ALU_PC_OUTPUT
446
{
447
u32 pc;
448
bool enabled;
449
};
450
451
struct P_ALU
452
{
453
DecodedInstruction decode;
454
//TODO its a shame to copy a big alu output every time.. try to avoid that somehow? thats a serious micro-optimization though..
455
ALU_OUTPUT out_mem;
456
ALU_PC_OUTPUT out_pc;
457
u32 in_pc;
458
CPU::eException exception;
459
} p_alu;
460
461
enum eStall
462
{
463
eStall_None=0,
464
eStall_MulDiv=1,
465
};
466
467
u32 stall_depends;
468
u32 stall_user;
469
470
struct
471
{
472
DecodedInstruction decode;
473
ALU_OUTPUT in_from_alu;
474
} p_mem;
475
476
477
enum eDelayState
478
{
479
eDelayState_None,
480
eDelayState_Branch, //set PC to a branch target arg
481
eDelayState_BranchRelative, //set PC relative (arg as s32) to current PC (that will be the PC of the instruction in the branch delay slot)
482
eDelayState_StoreWord, //store a word arg2 to memory at arg
483
eDelayState_StoreHalfword, //store a halfword arg2 to memory at arg
484
eDelayState_StoreByte, //store a byte arg2 to memory at arg
485
eDelayState_SetGPR, //set GPR arg to value arg2
486
eDelayState_MTCz, //set MTCz, reg # arg, to value arg2 (z and reg are packed into arg)
487
};
488
489
struct DelayState
490
{
491
eDelayState state;
492
u32 arg,arg2;
493
} delay;
494
} cpu;
495
496
enum eConsoleType
497
{
498
eConsoleType_Normal,
499
eConsoleType_DTL
500
};
501
502
struct
503
{
504
u32 ram_size;
505
u32 ram_mask;
506
} config;
507
508
void poweron(eConsoleType type);
509
void reset();
510
511
//execs one psx cycle
512
void exec_cycle();
513
void exec_shed(eScheduleItemType type);
514
515
static CPU::eFormat util_decode_format(u32 opcode);
516
void TraceALU();
517
void cpu_break(const u32 code);
518
void cpu_run_alu_bioshack(); //called once per cycle to implement bios hacks (stdout mostly)
519
void cpu_run_alu_bioshack_putchar(const u32 regval);
520
521
//debug-pokes a value into the psx address space (maybe rename to poke)
522
//TODO - make a check argument for sanity checking (to keep from patching the wrong thing)
523
void patch(const u32 addr, const u32 val);
524
525
//executes one cpu cycle
526
void cpu_exec_cycle();
527
528
//run each of the pipeline stages
529
void cpu_run_fetch();
530
void cpu_run_muldiv();
531
void cpu_run_alu();
532
void cpu_run_mem();
533
void cpu_run_wb();
534
535
//trigger an exception
536
void cpu_exception(CPU::eException ex, u32 pc_victim);
537
538
//coprocessor interfaces to be called from the alu pipeline
539
void cpu_copz_mtc(const u32 z, const u32 rd, const u32 value);
540
void cpu_cop0_mtc(const u32 rd, const u32 value);
541
u32 cpu_copz_mfc(const u32 z, const u32 rd);
542
u32 cpu_cop0_mfc(const u32 rd);
543
544
//main memory io interfaces
545
u32 cpu_fetch(const u32 addr);
546
template<int size> u32 cpu_rdmem(const u32 addr);
547
template<int size, bool POKE> void cpu_wrmem(const u32 addr, const u32 val);
548
template<int size> void cpu_wrmem(const u32 addr, const u32 val);
549
550
//memory mapping handlers
551
void cpu_wr_ram(const int size, const u32 addr, const u32 val);
552
u32 cpu_rd_ram(const int size, const u32 addr);
553
void cpu_wr_scratch(const int size, const u32 addr, const u32 val);
554
u32 cpu_rd_scratch(const int size, const u32 addr);
555
void cpu_wr_bios(const int size, const u32 addr, const u32 val);
556
u32 cpu_rd_bios(const int size, const u32 addr);
557
void cpu_wr_pio(const int size, const u32 addr, const u32 val);
558
u32 cpu_rd_pio(const int size, const u32 addr);
559
void cpu_wr_quick(u8* const buf, const int size, const u32 addr, const u32 val);
560
u32 cpu_rd_quick(const u8* const buf, const int size, const u32 addr);
561
void cpu_wr_hwreg(const int size, const u32 addr, const u32 val);
562
u32 cpu_rd_hwreg(const int size, const u32 addr);
563
564
void spu_wr(const int size, const u32 addr, const u32 val);
565
u32 spu_rd(const int size, const u32 addr);
566
567
void sio_wr(const int size, const u32 addr, const u32 val);
568
u32 sio_rd(const int size, const u32 addr);
569
//sets the dtr rising edge signal for the specified port (e.g. strobe signal; port should latch its values then presumably)
570
void sio_dtr(const u32 port);
571
572
u32 irq_rd(const int size, const u32 addr);
573
void irq_wr(const int size, const u32 addr, const u32 val);
574
void irq_update();
575
576
//miscellaneous not real stuff
577
u32 counter;
578
u64 abscounter;
579
//this will be used to boot the game if an appropriate signal is received
580
PSX_EXE_Header exeBootHeader;
581
582
enum eFakeBreakOp
583
{
584
eFakeBreakOp_None=0,
585
eFakeBreakOp_BootEXE=1,
586
eFakeBreakOp_BiosHack=2,
587
};
588
589
void RunForever();
590
void vblank_trigger();
591
};
592
593
594