Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/attic/PsxHawk.Core/psx.cpp
2 views
1
/*
2
this file contains the core psx system and cpu emulation.
3
where readily possible, components have been split off into separate modules.
4
*/
5
6
//http://www.d.umn.edu/~gshute/spimsal/talref.html
7
8
#include "psx.h"
9
#include "dis.h"
10
#include <stdio.h>
11
#include <assert.h>
12
#include <string.h>
13
#include <intrin.h>
14
#include <Windows.h>
15
16
bool dotrace = false;
17
18
void PSX::reset()
19
{
20
cpu.p_fetch.in_fetch_addr = 0xbfc00000; //this is the reset vector
21
}
22
23
void PSX::poweron(eConsoleType type)
24
{
25
//the psx struct only contains blittable data, so we can just memset it here to make sure we've got complete coverage
26
//(we'll put any non-blittable stuff behind one pointer later so we can reconstruct it as necessary)
27
memset(this,0,sizeof(this));
28
29
//reset cp0 regs (should this be in reset?)
30
memset(&cpu.cp0,0,sizeof(cpu.cp0));
31
cpu.cp0.SR.BEV = 1; //taken from mednafen
32
cpu.cp0.SR.TS = 1; //taken from mednafen
33
cpu.cp0.PRid = 0x300; // PRId: FIXME(test on real thing) //taken from mednafen
34
35
//clear cpu state: pipeline setup
36
cpu.unit_muldiv.timer = 0;
37
//p_fetch will be taken care of by the bootstrapper
38
cpu.p_alu.out_pc.enabled = false;
39
cpu.p_alu.in_pc = 0;
40
cpu.p_alu.decode.instr.value = 0;
41
cpu.p_alu.decode.op = eOP_NULL;
42
cpu.p_mem.in_from_alu.op = CPU::eMemOp_None;
43
44
//clear sio
45
sio[0].Reset();
46
sio[1].Reset();
47
48
//reset the scheduling system
49
sched.null.time = 0xFFFFFFFF; //this item will never happen so it will float at the end as a sentinel (it will continually get rebased)
50
//actually, its already at the end due to the memset
51
sched.head = eScheduleItemType_null;
52
sched.gpu.time = PSX_CLOCK / 60;
53
sched.insert(eScheduleItemType_gpu);
54
55
//setup the system configuration
56
//programs built targeting DTL units will ask for memory near the end of 8MB at program boot-up time (maybe other times?). maybe it puts the heap there? not sure about it.
57
//anyway, we need to handle that much memory if we want those to work.
58
//be aware that right now, psxhawk will mirror 2MB across the 8MB region for retail consoles, until we get better memory mapping
59
if(type == eConsoleType_DTL) config.ram_size = 8*1024*1024;
60
else config.ram_size = 2*1024*1024;
61
config.ram_mask = config.ram_size - 1;
62
}
63
64
PSX::eScheduleItemType PSX::SCHED::dequeue()
65
{
66
eScheduleItemType ret = head;
67
head = items[head].next;
68
//todo - rmeove this for a trivial optimization (but not from debug builds)
69
items[ret].next = eScheduleItemType_NIL;
70
items[ret].prev = eScheduleItemType_NIL;
71
return ret;
72
}
73
74
void PSX::SCHED::remove(eScheduleItemType todoType)
75
{
76
IScheduleItem &todo = items[todoType];
77
eScheduleItemType prevType = todo.prev;
78
eScheduleItemType nextType = todo.next;
79
if(prevType != eScheduleItemType_NIL) items[prevType].next = nextType;
80
if(nextType != eScheduleItemType_NIL) items[nextType].prev = prevType;
81
if(head == todoType)
82
head = nextType;
83
}
84
85
void PSX::SCHED::insert(eScheduleItemType todoType)
86
{
87
IScheduleItem &todo = items[todoType];
88
89
//ensure that it isnt already in the list
90
assert(todo.prev == eScheduleItemType_NIL && todo.next == eScheduleItemType_NIL);
91
92
//insert this schedule item into the list in sorted order
93
u32 todo_time = todo.time;
94
eScheduleItemType prevType = eScheduleItemType_NIL;
95
eScheduleItemType currType = head;
96
while(items[currType].time < todo_time) //TODO - tiebreaker priorities?
97
{
98
prevType = currType;
99
currType = items[currType].next;
100
}
101
//now, currType and prevType are pointing correctly.
102
if(prevType == eScheduleItemType_NIL)
103
{
104
//handle the case where this is the new head
105
items[todoType].next = head;
106
items[head].prev = todoType;
107
head = todoType;
108
}
109
else
110
{
111
//handle the case where it isnt the new head
112
items[todoType].next = items[prevType].next;
113
items[prevType].next = todoType;
114
items[todoType].prev = prevType;
115
items[currType].prev = todoType;
116
}
117
}
118
119
void PSX::exec_shed(eScheduleItemType type)
120
{
121
switch(type)
122
{
123
case eScheduleItemType_null:
124
break;
125
case eScheduleItemType_test:
126
printf("TEST!!!\n");
127
sched.test.time += 100000;
128
sched.insert(eScheduleItemType_test);
129
break;
130
case eScheduleItemType_gpu:
131
sched.gpu.time += PSX_CLOCK / 60;
132
sched.insert(eScheduleItemType_gpu);
133
vblank_trigger();
134
break;
135
}
136
}
137
138
void PSX::exec_cycle()
139
{
140
while(counter >= sched.items[sched.head].time)
141
{
142
eScheduleItemType todo = sched.dequeue();
143
exec_shed(todo);
144
}
145
sched.nextTime = sched.items[sched.head].time;
146
147
if(irq.flags.value & irq.mask.value)
148
{
149
dotrace = true;
150
cpu_exception(CPU::eException_INT, cpu.p_alu.in_pc);
151
//nullify instructions which will be rerun.
152
//in this emulator, interrupts cancel the instruction in the alu (notice we set it as the victim in the exception logic above)
153
//instructions in MEM and WB will proceed normally
154
//this was chosen because we didnt want to have to drag the PC down the pipeline and give it to the MEM stage
155
//HOWEVER -- this is maybe unrealistic (maybe we should nullify MEM and ALU and make MEM the victim)
156
//and maybe we'll have to drag the PC down later anyway for other proper exception handling
157
//(see pg 94 of see mips run)
158
cpu.p_alu.decode.op = eOP_NULLIFIED;
159
}
160
161
while(counter < sched.nextTime)
162
cpu_exec_cycle();
163
}
164
165
void PSX::vblank_trigger()
166
{
167
irq.flags.vsync = 1;
168
irq_update();
169
}
170
171
void PSX::cpu_wr_quick(u8* const buf, const int size, const u32 addr, const u32 val)
172
{
173
if(size==1) buf[addr] = val;
174
else if(size==2) {
175
*(u16*)&buf[addr] = val;
176
}
177
else {
178
*(u32*)&buf[addr] = val;
179
}
180
}
181
u32 PSX::cpu_rd_quick(const u8* const buf, const int size, const u32 addr)
182
{
183
if(size==1) return buf[addr];
184
else if(size==2) {
185
return *(u16*)&buf[addr];
186
}
187
else {
188
return *(u32*)&buf[addr];
189
}
190
}
191
192
u32 PSX::cpu_rd_ram(const int size, const u32 addr)
193
{
194
if(size==1)
195
return ram[addr];
196
else if(size==2) {
197
return *(u16*)&ram[addr];
198
}
199
else {
200
return *(u32*)&ram[addr];
201
}
202
}
203
204
void PSX::cpu_wr_ram(const int size, const u32 addr, const u32 val)
205
{
206
if(size==1)
207
ram[addr] = val;
208
else if(size==2) {
209
*(u16*)&ram[addr] = val;
210
}
211
else {
212
*(u32*)&ram[addr] = val;
213
}
214
}
215
216
void PSX::cpu_wr_scratch(const int size, const u32 addr, const u32 val) { cpu_wr_quick(scratch,size,addr,val); }
217
u32 PSX::cpu_rd_scratch(const int size, const u32 addr) { return cpu_rd_quick(scratch,size,addr); }
218
void PSX::cpu_wr_bios(const int size, const u32 addr, const u32 val) { cpu_wr_quick(bios,size,addr,val); }
219
u32 PSX::cpu_rd_bios(const int size, const u32 addr) { return cpu_rd_quick(bios,size,addr); }
220
void PSX::cpu_wr_pio(const int size, const u32 addr, const u32 val) { cpu_wr_quick(pio,size,addr,val); }
221
u32 PSX::cpu_rd_pio(const int size, const u32 addr) { return cpu_rd_quick(pio,size,addr); }
222
223
template<int size> void PSX::cpu_wrmem(u32 addr, const u32 val) { cpu_wrmem<size,false>(addr,val); }
224
template<int size, bool POKE> void PSX::cpu_wrmem(u32 addr, const u32 val)
225
{
226
if(!POKE && cpu.cp0.SR.IsC)
227
return; //IsC (isolate [data] cache is set). theres no data cache here, so discard write
228
229
if(addr<0x00800000) { cpu_wr_ram(size,addr&config.ram_mask,val); return; }
230
if(addr<0x1F000000) goto BUS_ERROR;
231
if(addr<0x1F010000) { cpu_wr_pio(size,addr&PIO_MASK,val); return; }
232
if(addr<0x1F800000) goto BUS_ERROR;
233
if(addr<0x1F800400) { cpu_wr_scratch(size,addr&SCRATCH_MASK,val); return; }
234
if(addr<0x1F801000) goto BUS_ERROR;
235
if(addr<0x1FC00000) { cpu_wr_hwreg(size,addr,val); return; }
236
if(addr<0x1FC80000) goto BUS_ERROR; //can't write to bios?
237
if(addr<0x80000000) goto BUS_ERROR;
238
239
if(addr<0x80800000) { cpu_wr_ram(size,addr&config.ram_mask,val); return; }
240
if(addr<0x9F000000) goto BUS_ERROR;
241
if(addr<0x9F010000) { cpu_wr_pio(size,addr&PIO_MASK,val); return; }
242
if(addr<0x9FC00000) goto BUS_ERROR;
243
if(addr<0x9FC80000) goto BUS_ERROR; //can't write to bios?
244
if(addr<0xA0000000) goto BUS_ERROR;
245
246
if(addr<0xA0800000) { cpu_wr_ram(size,addr&config.ram_mask,val); return; }
247
if(addr<0xBF000000) goto BUS_ERROR;
248
if(addr<0xBF010000) { cpu_wr_pio(size,addr&PIO_MASK,val); return; }
249
if(addr<0xBFC00000) goto BUS_ERROR;
250
if(addr<0xBFC80000) { if(POKE) { cpu_wr_bios(size,addr&BIOS_MASK,val); return; } else goto BUS_ERROR; } //can't write to bios?
251
252
if(addr == 0xFFFE0130)
253
{
254
//check psx sources for information on this. it seems to make everything read only?
255
//DEBUG("mystery 0xFFFE0130 reg set to 0x%08X\n",val);
256
return;
257
}
258
259
goto BUS_ERROR;
260
261
BUS_ERROR:
262
DEBUG("bus error exception (write) at 0x%08X\n",addr);
263
}
264
265
void PSX::patch(const u32 addr, const u32 val)
266
{
267
//should use the poke versions one day
268
cpu_wrmem<4,true>(addr,val);
269
}
270
271
void PSX::spu_wr(const int size, const u32 addr, const u32 val)
272
{
273
//1d80/1d82 main volume left / right
274
//1d84/1d86 reverberation depth left / right
275
DEBUG_HWREG("spu write size %d addr %08X = %08X\n",size,addr,val);
276
}
277
278
u32 PSX::spu_rd(const int size, const u32 addr)
279
{
280
u32 ret = 0;
281
DEBUG_HWREG("spu read size %d addr %08X = %08X\n",size,addr,ret);
282
return 0;
283
}
284
285
void PSX::irq_wr(const int size, const u32 addr, const u32 val)
286
{
287
if(addr == 0)
288
{
289
//acknowledge the specified irq bits
290
irq.flags.value &= ~(val&IRQ::WIRE_MASK);
291
}
292
else if(addr == 4)
293
{
294
//set the irq mask directly
295
irq.mask.value = val & IRQ::WIRE_MASK;
296
}
297
else assert(false);
298
irq_update();
299
}
300
301
u32 PSX::irq_rd(const int size, const u32 addr)
302
{
303
if(addr == 0)
304
return irq.flags.value;
305
else if(addr == 4)
306
return irq.mask.value;
307
else assert(false);
308
}
309
310
void PSX::irq_update()
311
{
312
sched.escape();
313
}
314
315
void PSX::cpu_wr_hwreg(const int size, const u32 addr, const u32 val)
316
{
317
if(addr>=0x1F801C00 && addr <= 0x1F801DFF)
318
{
319
spu_wr(size,addr,val);
320
return;
321
}
322
else if(addr>=0x1F801040 && addr < 0x1F80105F)
323
{
324
sio_wr(size,addr,val);
325
return;
326
}
327
else switch(addr)
328
{
329
case 0x1F801000: sysregs.biosInit[0] = val; break;
330
case 0x1F801004: sysregs.biosInit[1] = val; break;
331
case 0x1F801008: sysregs.biosInit[2] = val; break;
332
case 0x1F80100C: sysregs.biosInit[3] = val; break;
333
case 0x1F801010: sysregs.biosInit[4] = val; break;
334
case 0x1F801014: sysregs.biosInit[5] = val; break;
335
case 0x1F801018: sysregs.biosInit[6] = val; break;
336
case 0x1F80101C: sysregs.biosInit[7] = val; break;
337
case 0x1F801020: sysregs.biosInit[8] = val; break;
338
//case 0x1f801080-0x1f8010ff dma
339
//case 0x1F801100/10/20/30 root counters
340
case 0x1F801070: irq_wr(size, 0, val); break;
341
case 0x1F801071: assert(false);
342
case 0x1F801072: assert(false);
343
case 0x1F801073: assert(false);
344
case 0x1F801074: irq_wr(size, 4, val); break;
345
case 0x1F801075: assert(false);
346
case 0x1F801076: assert(false);
347
case 0x1F801077: assert(false);
348
//1F801060 // unknown
349
//1F801D80 // unknown
350
//1f802041 // unknown
351
default:
352
DEBUG_HWREG("UNKNOWN ");
353
}
354
DEBUG_HWREG("hwreg write size %d addr %08X = %08X\n",size,addr,val);
355
}
356
u32 PSX::cpu_rd_hwreg(const int size, const u32 addr)
357
{
358
u32 ret = 0;
359
if(addr>=0x1F801C00 && addr <= 0x1F801DFF)
360
{
361
return spu_rd(size,addr);
362
}
363
else if(addr>=0x1F801040 && addr < 0x1F80105F)
364
{
365
return sio_rd(size,addr);
366
}
367
else switch(addr)
368
{
369
case 0x1F801000: ret = sysregs.biosInit[0]; break;
370
case 0x1F801004: ret = sysregs.biosInit[1]; break;
371
case 0x1F801008: ret = sysregs.biosInit[2]; break;
372
case 0x1F80100C: ret = sysregs.biosInit[3]; break;
373
case 0x1F801010: ret = sysregs.biosInit[4]; break;
374
case 0x1F801014: ret = sysregs.biosInit[5]; break;
375
case 0x1F801018: ret = sysregs.biosInit[6]; break;
376
case 0x1F80101C: ret = sysregs.biosInit[7]; break;
377
case 0x1F801020: ret = sysregs.biosInit[8]; break;
378
case 0x1F801070: ret = irq_rd(size, 0); break;
379
case 0x1F801071: assert(false);
380
case 0x1F801072: assert(false);
381
case 0x1F801073: assert(false);
382
case 0x1F801074: ret = irq_rd(size, 4); break;
383
case 0x1F801075: assert(false);
384
case 0x1F801076: assert(false);
385
case 0x1F801077: assert(false);
386
default:
387
DEBUG_HWREG("UNKNOWN ");
388
break;
389
}
390
DEBUG_HWREG("hwreg read size %d addr %08X = %08X\n",size,addr,ret);
391
return ret;
392
}
393
394
template<int size> u32 PSX::cpu_rdmem(const u32 addr)
395
{
396
if(addr<0x00800000) return cpu_rd_ram(size,addr&config.ram_mask);
397
if(addr<0x1F000000) goto BUS_ERROR;
398
if(addr<0x1F010000) return cpu_rd_pio(size,addr&PIO_MASK);
399
if(addr<0x1F800000) goto BUS_ERROR;
400
if(addr<0x1F800400) return cpu_rd_scratch(size,addr&SCRATCH_MASK);
401
if(addr<0x1F801000) goto BUS_ERROR;
402
if(addr<0x1FC00000) return cpu_rd_hwreg(size,addr);
403
if(addr<0x1FC80000) return cpu_rd_bios(size,addr&BIOS_MASK);
404
if(addr<0x80000000) goto BUS_ERROR;
405
406
if(addr<0x80800000) return cpu_rd_ram(size,addr&config.ram_mask);
407
if(addr<0x9F000000) goto BUS_ERROR;
408
if(addr<0x9F010000) return cpu_rd_pio(size,addr&PIO_MASK);
409
if(addr<0x9FC00000) goto BUS_ERROR;
410
if(addr<0x9FC80000) return cpu_rd_bios(size,addr&BIOS_MASK);
411
if(addr<0xA0000000) goto BUS_ERROR;
412
413
if(addr<0xA0800000) return cpu_rd_ram(size,addr&config.ram_mask);
414
if(addr<0xBF000000) goto BUS_ERROR;
415
if(addr<0xBF010000) return cpu_rd_pio(size,addr&PIO_MASK);
416
if(addr<0xBFC00000) goto BUS_ERROR;
417
if(addr<0xBFC80000) return cpu_rd_bios(size,addr&BIOS_MASK);
418
419
goto BUS_ERROR;
420
421
BUS_ERROR:
422
DEBUG("bus error exception (read) at 0x%08X\n",addr);
423
return 0;
424
}
425
426
void PSX::cpu_copz_mtc(const u32 z, const u32 rd, const u32 value)
427
{
428
//DEBUG("Writing cop%d, %d = 0x%08X\n",z,rd,value);
429
if(z==0) cpu_cop0_mtc(rd,value);
430
}
431
432
void PSX::cpu_cop0_mtc(const u32 rd, const u32 value)
433
{
434
cpu.cp0.r[rd] = value;
435
cpu.cp0.SR.value &= ~CPU::SR_REG::ZERO_MASK;
436
//TODO - other register masks
437
}
438
439
u32 PSX::cpu_copz_mfc(const u32 z, const u32 rd)
440
{
441
//DEBUG("Reading cop%d, %d\n",z,rd);
442
if(z==0) return cpu_cop0_mfc(rd);
443
return 0;
444
}
445
446
u32 PSX::cpu_cop0_mfc(const u32 rd)
447
{
448
return cpu.cp0.r[rd];
449
}
450
451
u32 PSX::cpu_fetch(const u32 addr)
452
{
453
return cpu_rdmem<4>(addr);
454
}
455
456
void PSX::cpu_run_alu_bioshack()
457
{
458
const u32 ram_pc = cpu.p_alu.in_pc & 0x0FFFFFFF;
459
460
const u32 function = cpu.regs.t1;
461
switch(function)
462
{
463
case 0x00: break; //open
464
case 0x16: break; //strncat
465
case 0x18: break; //strncmp
466
case 0x35: //lsearch?? but yet the sdk uses this for printf. maybe it depends on the bios version
467
//also the putchar() stdlib function uses this by dropping a character in some kind of buffer that is reserved for it
468
if(ENABLE_CONOUT)
469
{
470
//TODO - make this safer, if necessary, by not going straight into main ram
471
//a1 = address of string
472
//a2 = length of string
473
u8* const raw_addr = ram + (cpu.regs.a1 & config.ram_mask);
474
const u32 len = cpu.regs.a2;
475
for(u32 i=0;i<len;i++)
476
fputc(raw_addr[i],stdout);
477
}
478
break;
479
case 0x3C: //putchar
480
if(ENABLE_CONOUT) cpu_run_alu_bioshack_putchar(cpu.regs.a0);
481
break;
482
case 0x3D: //gets... ? but yet, the kernel uses this to print
483
if(ENABLE_CONOUT) cpu_run_alu_bioshack_putchar(cpu.regs.a0);
484
case 0x3F: //printf. i think putchar will get used internally, no need to handle this
485
break;
486
default:
487
printf("unknown bios call: 0x%02X\n", function);
488
break;
489
}
490
return;
491
}
492
493
void PSX::cpu_run_alu_bioshack_putchar(const u32 regval)
494
{
495
char c = regval;
496
fputc(c,stdout);
497
return;
498
}
499
500
void PSX::cpu_break(const u32 code)
501
{
502
switch(code)
503
{
504
case eFakeBreakOp_BootEXE:
505
{
506
//perform basic exe booting steps
507
//the program has already been loaded. all we need to do is setup the regs specified in the header
508
cpu.p_fetch.in_fetch_addr = exeBootHeader.init_pc;
509
cpu.regs.gp = exeBootHeader.init_gp;
510
cpu.regs.sp = exeBootHeader.stack_load_addr; //aka init_sp
511
break;
512
}
513
case eFakeBreakOp_BiosHack:
514
//first, run the effect of the patched instruction, which was: lui t0, 0x0000
515
cpu.regs.t0 = 0;
516
cpu_run_alu_bioshack();
517
break;
518
default:
519
break;
520
}
521
}
522
523
#define SIGNBIT(x) ((x) & 0x80000000)
524
525
void PSX::cpu_exception(CPU::eException ex, u32 pc_victim)
526
{
527
cpu.cp0.EPC = pc_victim;
528
529
cpu.cp0.Cause.ExcCode = ex;
530
cpu.cp0.Cause.Sw = 0; //?
531
cpu.cp0.Cause.IP = 0; //?
532
cpu.cp0.Cause.CE = 0; //TBD
533
cpu.cp0.Cause.BD = 0; //TODO - BD flag
534
535
//choose the rom or ram handler according to this flag
536
u32 handler = 0x80000080;
537
if(cpu.cp0.SR.BEV)
538
handler = 0xBFC00180;
539
540
cpu.cp0.SR.KUo = cpu.cp0.SR.KUp;
541
cpu.cp0.SR.IEo = cpu.cp0.SR.IEp;
542
cpu.cp0.SR.KUp = cpu.cp0.SR.KUc;
543
cpu.cp0.SR.IEp = cpu.cp0.SR.IEc;
544
cpu.cp0.SR.KUc = 0;
545
cpu.cp0.SR.IEc = 0;
546
547
cpu.p_fetch.in_fetch_addr = handler;
548
}
549
550
void PSX::cpu_run_muldiv()
551
{
552
if(cpu.unit_muldiv.timer > 0)
553
{
554
//TODO - think about whether this is the exactly right amount of time (maybe off by one)
555
cpu.unit_muldiv.timer--;
556
if(cpu.unit_muldiv.timer == 0)
557
{
558
cpu.regs.lo = cpu.unit_muldiv.lo;
559
cpu.regs.hi = cpu.unit_muldiv.hi;
560
cpu.stall_depends &= ~CPU::eStall_MulDiv;
561
}
562
}
563
}
564
565
void PSX::cpu_run_mem()
566
{
567
CPU::ALU_OUTPUT &input = cpu.p_mem.in_from_alu;
568
569
//mem stage
570
switch(input.op)
571
{
572
case CPU::eMemOp_StoreWord:
573
DEBUG_STORE("{%12lld} MEM: StoreWord [%08X] = %08X\n",abscounter,input.addr,input.value);
574
cpu_wrmem<4>(input.addr,input.value);
575
break;
576
case CPU::eMemOp_StoreHalfword:
577
DEBUG_STORE("{%12lld} MEM: StoreWord [%08X] = %04X\n",abscounter,input.addr,input.value);
578
cpu_wrmem<2>(input.addr,input.value);
579
break;
580
case CPU::eMemOp_StoreByte:
581
DEBUG_STORE("{%12lld} MEM: StoreByte [%08X] = %02X\n",abscounter,input.addr,input.value);
582
cpu_wrmem<1>(input.addr,input.value);
583
break;
584
case CPU::eMemOp_LoadWord:
585
{
586
const u32 temp = cpu_rdmem<4>(input.addr);
587
DEBUG_LOAD("{%12lld} MEM: LoadWord [%08X] == %08X\n",abscounter,input.addr,temp);
588
cpu.regs.r[input.rt] = temp;
589
break;
590
}
591
case CPU::eMemOp_LoadHalfwordSigned:
592
{
593
const u32 temp = (s16)cpu_rdmem<2>(input.addr);
594
DEBUG_LOAD("{%12lld} MEM: LoadHalfwordSigned [%08X] == %04X\n",abscounter,input.addr,temp);
595
cpu.regs.r[input.rt] = temp;
596
break;
597
}
598
case CPU::eMemOp_LoadHalfwordUnsigned:
599
{
600
const u32 temp = cpu_rdmem<2>(input.addr);
601
DEBUG_LOAD("{%12lld} MEM: LoadHalfwordUnsigned [%08X] == %04X\n",abscounter,input.addr,temp);
602
cpu.regs.r[input.rt] = temp;
603
break;
604
}
605
case CPU::eMemOp_LoadByteSigned:
606
{
607
const u32 temp = (s8)cpu_rdmem<1>(input.addr);
608
DEBUG_LOAD("{%12lld} MEM: LoadByte [%08X] == %02X\n",abscounter,input.addr,temp);
609
cpu.regs.r[input.rt] = temp;
610
break;
611
}
612
case CPU::eMemOp_LoadByteUnsigned:
613
{
614
const u32 temp = cpu_rdmem<1>(input.addr);
615
DEBUG_LOAD("{%12lld} MEM: LoadByteUnsigned [%08X] == %02X\n",abscounter,input.addr,temp);
616
cpu.regs.r[input.rt] = temp;
617
break;
618
}
619
620
case CPU::eMemOp_MTC:
621
{
622
const CPU::Instruction_CTYPE instr = cpu.p_mem.decode.instr.CTYPE;
623
cpu_copz_mtc(instr.cpnum,instr.rd,input.value);
624
break;
625
}
626
case CPU::eMemOp_MFC:
627
{
628
const CPU::Instruction_CTYPE instr = cpu.p_mem.decode.instr.CTYPE;
629
cpu.regs.r[instr.rt] = cpu_copz_mfc(instr.cpnum,instr.rd);
630
break;
631
}
632
633
case CPU::eMemOp_None:
634
break;
635
case CPU::eMemOp_Unset:
636
printf("*** UNHANDLED MEM OP ***\n");
637
break;
638
default:
639
NOCASE();
640
}
641
642
cpu.regs.r0 = 0;
643
}
644
645
void PSX::TraceALU()
646
{
647
DEBUG_TRACE("{%12lld} %08X: [%08X] (%d,%d) %s\n",abscounter,cpu.p_alu.in_pc,cpu.p_alu.decode.instr.value,
648
cpu.p_alu.decode.instr.value>>26,
649
cpu.p_alu.decode.instr.value&0x3F,
650
MDFN_IEN_PSX::DisassembleMIPS(cpu.p_alu.in_pc,cpu.p_alu.decode.instr.value).c_str()
651
);
652
}
653
654
void PSX::cpu_run_wb()
655
{
656
//TBD
657
}
658
659
static const eOp DecodeTable[] =
660
{
661
eOP_SLL, eOP_ILL, eOP_SRL, eOP_SRA, eOP_SLLV, eOP_ILL, eOP_SRLV, eOP_SRAV,
662
eOP_JR, eOP_JALR, eOP_ILL, eOP_ILL, eOP_SYSCALL, eOP_BREAK, eOP_ILL, eOP_ILL,
663
eOP_MFHI, eOP_MTHI, eOP_MFLO, eOP_MTLO, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL,
664
eOP_MULT, eOP_MULTU, eOP_DIV, eOP_DIVU, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL,
665
eOP_ADD, eOP_ADDU, eOP_SUB, eOP_SUBU, eOP_AND, eOP_OR, eOP_XOR, eOP_NOR,
666
eOP_ILL, eOP_ILL, eOP_SLT, eOP_SLTU, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL,
667
eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL,
668
eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL,
669
670
eOP_NULL, eOP_BCOND, eOP_J, eOP_JAL, eOP_BEQ, eOP_BNE, eOP_BLEZ, eOP_BGTZ,
671
eOP_ADDI, eOP_ADDIU, eOP_SLTI, eOP_SLTIU, eOP_ANDI, eOP_ORI, eOP_XORI, eOP_LUI,
672
eOP_COPROC, eOP_COPROC, eOP_COPROC, eOP_COPROC, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL,
673
eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL,
674
eOP_LB, eOP_LH, eOP_LWL, eOP_LW, eOP_LBU, eOP_LHU, eOP_LWR, eOP_ILL,
675
eOP_SB, eOP_SH, eOP_SWL, eOP_SW, eOP_ILL, eOP_ILL, eOP_SWR, eOP_ILL,
676
eOP_LWC0, eOP_LWC1, eOP_LWC2, eOP_LWC3, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL,
677
eOP_SWC0, eOP_SWC1, eOP_SWC2, eOP_SWC3, eOP_ILL, eOP_ILL, eOP_ILL, eOP_ILL,
678
};
679
680
void PSX::cpu_run_fetch()
681
{
682
const u32 _pc = cpu.p_fetch.in_fetch_addr;
683
const u32 instr = cpu_fetch(cpu.p_fetch.in_fetch_addr);
684
const u32 opc = instr>>26;
685
cpu.p_fetch.decode.instr.value = instr;
686
687
const u32 _opc = instr>>26;
688
const u32 _func = instr&0x3F;
689
if(dotrace) DEBUG_TRACE("{%12lld} %08X: [%08X] (%d,%d) %s\n",abscounter, _pc, instr,_opc,_func,MDFN_IEN_PSX::DisassembleMIPS(_pc,instr).c_str());
690
691
//this decode table approach was taken from mednafen.
692
u32 opf = instr & 0x3F;
693
if(instr & (0x3F << 26))
694
opf = 0x40 | (instr >> 26);
695
696
cpu.p_fetch.decode.op = DecodeTable[opf];
697
698
//dont try to pad out these switches, it wont help
699
switch(cpu.p_fetch.decode.op)
700
{
701
case eOP_MFLO:
702
case eOP_MFHI:
703
cpu.stall_user |= CPU::eStall_MulDiv;
704
break;
705
}
706
}
707
708
#define BRANCH_SET_PC() { cpu.p_alu.out_pc.enabled = true, cpu.p_alu.out_pc.pc = cpu.p_alu.in_pc + instr.signed_target(); }
709
void PSX::cpu_run_alu()
710
{
711
//most alu instructions will not set the out PC
712
cpu.p_alu.out_pc.enabled = false;
713
714
//alu needs to have registers ready before it begins.
715
//some of these will write their results at the end of this stage
716
#ifndef NDEBUG
717
cpu.p_alu.out_mem.op = CPU::eMemOp_Unset;
718
#endif
719
cpu.p_alu.exception = CPU::eException_None;
720
switch(cpu.p_alu.decode.op)
721
{
722
case eOP_ILL:
723
default:
724
//NOCASE();
725
printf("*** UNHANDLED ALU OP***\n");
726
TraceALU();
727
break;
728
729
case eOP_NULLIFIED:
730
case eOP_NULL:
731
{
732
//?? whats this?
733
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
734
break;
735
}
736
737
case eOP_J: //j (jump)
738
{
739
const CPU::Instruction_JTYPE instr = cpu.p_alu.decode.instr.JTYPE;
740
cpu.p_alu.out_pc.enabled = true;
741
cpu.p_alu.out_pc.pc = (cpu.p_alu.in_pc&0xF0000000) | (instr.target << 2);
742
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
743
break;
744
}
745
case eOP_JAL: //jal (jump and link)
746
{
747
const CPU::Instruction_JTYPE instr = cpu.p_alu.decode.instr.JTYPE;
748
cpu.p_alu.out_pc.enabled = true;
749
cpu.p_alu.out_pc.pc = (cpu.p_alu.in_pc&0xF0000000) | (instr.target << 2);
750
cpu.regs.ra = cpu.p_alu.in_pc + 8;
751
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
752
break;
753
}
754
755
case eOP_COPROC: //coproc operations
756
{
757
const CPU::Instruction_CTYPE instr = cpu.p_alu.decode.instr.CTYPE;
758
switch(instr.format)
759
{
760
case 0: //mfcz (move from coprocessor z)
761
//TODO - should these have a delay? the psx is supposed to hav a delay for cp1, does that mean there is a delay for cp0?
762
cpu.p_alu.out_mem.op = CPU::eMemOp_MFC;
763
break;
764
case 4: //mtcz (move to coprocessor z)
765
//TODO - should these have a delay? the psx is supposed to hav a delay for cp1, does that mean there is a delay for cp0?
766
cpu.p_alu.out_mem.value = cpu.regs.r[instr.rt];
767
cpu.p_alu.out_mem.op = CPU::eMemOp_MTC;
768
break;
769
case 16: //a whole bunch of junk, maybe associated with cp0?
770
switch(instr.function)
771
{
772
case 16: //rfe (return from exception)
773
cpu.cp0.SR.IEc = cpu.cp0.SR.IEp;
774
cpu.cp0.SR.KUc = cpu.cp0.SR.KUp;
775
cpu.cp0.SR.IEp = cpu.cp0.SR.IEo;
776
cpu.cp0.SR.KUp = cpu.cp0.SR.KUo;
777
//KUo and IEo unchanged
778
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
779
break;
780
default:
781
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
782
break;
783
}
784
break;
785
default:
786
NOCASE();
787
printf("*** UNHANDLED ALU CTYPE ***\n");
788
TraceALU();
789
}
790
break;
791
}
792
793
case eOP_SLL: //sll (shift left logical) //nop
794
{
795
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
796
cpu.regs.r[instr.rd] = cpu.regs.r[instr.rt] << instr.sa;
797
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
798
break;
799
}
800
case eOP_SRL: //srl (shift right logical)
801
{
802
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
803
cpu.regs.r[instr.rd] = cpu.regs.r[instr.rt] >> instr.sa;
804
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
805
break;
806
}
807
case eOP_SRA: //sra (shift right arithmetic)
808
{
809
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
810
cpu.regs.r[instr.rd] = (s32)cpu.regs.r[instr.rt] >> instr.sa;
811
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
812
break;
813
}
814
case eOP_SLLV: //sllv (shift left logical variable)
815
{
816
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
817
cpu.regs.r[instr.rd] = cpu.regs.r[instr.rt] << (cpu.regs.r[instr.rs] & 0x1F);
818
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
819
break;
820
}
821
case eOP_SRLV: //srlv (shift right logical variable)
822
{
823
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
824
cpu.regs.r[instr.rd] = cpu.regs.r[instr.rt] >> (cpu.regs.r[instr.rs] & 0x1F);
825
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
826
break;
827
}
828
case eOP_SRAV: //srav (shift right arithmetic variable)
829
{
830
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
831
cpu.regs.r[instr.rd] = (s32)cpu.regs.r[instr.rt] >> (cpu.regs.r[instr.rs] & 0x1F);
832
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
833
break;
834
}
835
case eOP_JR: //jr (jump register)
836
{
837
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
838
cpu.p_alu.out_pc.enabled = true;
839
cpu.p_alu.out_pc.pc = cpu.regs.r[instr.rs];
840
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
841
break;
842
}
843
case eOP_JALR: //jalr (jump and link register)
844
{
845
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
846
cpu.p_alu.out_pc.enabled = true;
847
cpu.p_alu.out_pc.pc = cpu.regs.r[instr.rs];
848
cpu.regs.ra = cpu.p_alu.in_pc + 8;
849
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
850
break;
851
}
852
case eOP_SYSCALL: //syscall
853
{
854
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
855
cpu.p_alu.exception = CPU::eException_SYSCALL;
856
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
857
break;
858
}
859
case eOP_BREAK: //break
860
{
861
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
862
cpu_break(instr.break_code());
863
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
864
break;
865
}
866
case eOP_MFHI: //mfhi (move from hi)
867
{
868
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
869
cpu.regs.r[instr.rd] = cpu.regs.hi;
870
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
871
break;
872
}
873
case eOP_MTHI: //mthi (move to hi)
874
{
875
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
876
cpu.regs.hi = cpu.regs.r[instr.rs];
877
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
878
break;
879
}
880
case eOP_MFLO: //mflo (move from lo)
881
{
882
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
883
cpu.regs.r[instr.rd] = cpu.regs.lo;
884
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
885
break;
886
}
887
case eOP_MTLO: //mtlo (move to lo)
888
{
889
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
890
cpu.regs.lo = cpu.regs.r[instr.rs];
891
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
892
break;
893
}
894
case eOP_MULT: //mult (multiply)
895
{
896
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
897
const u32 a = cpu.regs.r[instr.rs];
898
const u32 b = cpu.regs.r[instr.rt];
899
s64 product = (s64)a * (s32)b;
900
cpu.unit_muldiv.lo = ((u32*)&product)[0];
901
cpu.unit_muldiv.hi = ((u32*)&product)[1];
902
cpu.unit_muldiv.timer = 12;
903
cpu.stall_depends |= CPU::eStall_MulDiv;
904
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
905
break;
906
}
907
case eOP_MULTU: //multu (multiply unsigned)
908
{
909
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
910
const u32 a = cpu.regs.r[instr.rs];
911
const u32 b = cpu.regs.r[instr.rt];
912
u64 product = (u64)a * b;
913
cpu.unit_muldiv.lo = ((u32*)&product)[0];
914
cpu.unit_muldiv.hi = ((u32*)&product)[1];
915
cpu.unit_muldiv.timer = 12;
916
cpu.stall_depends |= CPU::eStall_MulDiv;
917
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
918
break;
919
}
920
case eOP_DIV: //div
921
{
922
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
923
//TODO - special handling for divide by zero and such (take from mednafen)
924
const u32 dividend = cpu.regs.r[instr.rs];
925
const u32 divisor = cpu.regs.r[instr.rt];
926
cpu.unit_muldiv.lo = (s32)dividend / (s32)divisor;
927
cpu.unit_muldiv.hi = (s32)dividend % (s32)divisor;
928
cpu.unit_muldiv.timer = 35;
929
cpu.stall_depends |= CPU::eStall_MulDiv;
930
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
931
break;
932
}
933
case eOP_DIVU: //divu
934
{
935
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
936
//TODO - special handling for divide by zero and such (take from mednafen)
937
const u32 dividend = cpu.regs.r[instr.rs];
938
const u32 divisor = cpu.regs.r[instr.rt];
939
cpu.unit_muldiv.lo = dividend / divisor;
940
cpu.unit_muldiv.hi = dividend % divisor;
941
cpu.unit_muldiv.timer = 35;
942
cpu.stall_depends |= CPU::eStall_MulDiv;
943
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
944
break;
945
}
946
case eOP_ADD: //add [overflow (TBD)]
947
{
948
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
949
cpu.regs.r[instr.rd] = cpu.regs.r[instr.rs] + cpu.regs.r[instr.rt];
950
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
951
break;
952
}
953
case eOP_ADDU: //addu (add unsigned) [no overflow]
954
{
955
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
956
cpu.regs.r[instr.rd] = cpu.regs.r[instr.rs] + cpu.regs.r[instr.rt];
957
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
958
break;
959
}
960
case eOP_SUBU: //subu (subtract unsigned) [no overflow]
961
{
962
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
963
cpu.regs.r[instr.rd] = cpu.regs.r[instr.rs] - cpu.regs.r[instr.rt];
964
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
965
break;
966
}
967
case eOP_AND: //and
968
{
969
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
970
cpu.regs.r[instr.rd] = cpu.regs.r[instr.rs] & cpu.regs.r[instr.rt];
971
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
972
break;
973
}
974
case eOP_OR: //or
975
{
976
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
977
cpu.regs.r[instr.rd] = cpu.regs.r[instr.rs] | cpu.regs.r[instr.rt];
978
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
979
break;
980
}
981
case eOP_NOR: //nor
982
{
983
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
984
cpu.regs.r[instr.rd] = ~(cpu.regs.r[instr.rs] | cpu.regs.r[instr.rt]);
985
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
986
break;
987
}
988
case eOP_SLT: //slt (set on less than) [signed]
989
{
990
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
991
cpu.regs.r[instr.rd] = ((s32)cpu.regs.r[instr.rs] < (s32)cpu.regs.r[instr.rt]) ? 1 : 0;
992
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
993
break;
994
}
995
case eOP_SLTU://sltu (set on less than unsigned)
996
{
997
const CPU::Instruction_RTYPE instr = cpu.p_alu.decode.instr.RTYPE;
998
cpu.regs.r[instr.rd] = (cpu.regs.r[instr.rs] < cpu.regs.r[instr.rt]) ? 1 : 0;
999
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1000
break;
1001
}
1002
case eOP_BCOND:
1003
{
1004
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1005
switch(instr.rt)
1006
{
1007
case 0: //bltz (branch on less than zero)
1008
if(SIGNBIT(cpu.regs.r[instr.rs])!=0)
1009
BRANCH_SET_PC();
1010
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1011
break;
1012
case 1: //bgez (branch on greater than or equal to zero)
1013
if(SIGNBIT(cpu.regs.r[instr.rs])==0)
1014
BRANCH_SET_PC();
1015
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1016
break;
1017
}
1018
break;
1019
}
1020
case eOP_BEQ: //beq (branch on equal)
1021
{
1022
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1023
if(cpu.regs.r[instr.rs] == cpu.regs.r[instr.rt])
1024
BRANCH_SET_PC();
1025
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1026
break;
1027
}
1028
case eOP_BNE: //bne (branch on not equal)
1029
{
1030
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1031
if(cpu.regs.r[instr.rs] != cpu.regs.r[instr.rt])
1032
BRANCH_SET_PC();
1033
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1034
break;
1035
}
1036
case eOP_BLEZ: //blez (branch on less than or equal to zero)
1037
{
1038
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1039
if(SIGNBIT(cpu.regs.r[instr.rs])!=0 || cpu.regs.r[instr.rs] == 0)
1040
BRANCH_SET_PC();
1041
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1042
break;
1043
}
1044
case eOP_BGTZ: //bgtz (branch on greater than zero)
1045
{
1046
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1047
if(SIGNBIT(cpu.regs.r[instr.rs])==0 && cpu.regs.r[instr.rs] != 0)
1048
BRANCH_SET_PC();
1049
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1050
break;
1051
}
1052
case eOP_ADDI: //addi (add immediate) [sign extend immediate and throw overflow exception (TBD)]
1053
{
1054
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1055
cpu.regs.r[instr.rt] = cpu.regs.r[instr.rs] + (s16)instr.immediate;
1056
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1057
break;
1058
}
1059
case eOP_ADDIU: //addiu (add immediate unsigned) [sign extend immediate and no overflow exception]
1060
{
1061
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1062
cpu.regs.r[instr.rt] = cpu.regs.r[instr.rs] + (s16)instr.immediate;
1063
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1064
break;
1065
}
1066
case eOP_SLTI: //slti (set on less than immediate)
1067
{
1068
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1069
if((s32)cpu.regs.r[instr.rs] < (s16)instr.immediate) cpu.regs.r[instr.rt] = 1;
1070
else cpu.regs.r[instr.rt] = 0;
1071
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1072
break;
1073
}
1074
case eOP_SLTIU: //sltiu (set on less than immediate unsigned)
1075
{
1076
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1077
if(cpu.regs.r[instr.rs] < (u32)(s16)instr.immediate) cpu.regs.r[instr.rt] = 1;
1078
else cpu.regs.r[instr.rt] = 0;
1079
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1080
break;
1081
}
1082
case eOP_ANDI: //andi (and immediate)
1083
{
1084
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1085
cpu.regs.r[instr.rt] = cpu.regs.r[instr.rs] & instr.immediate;
1086
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1087
break;
1088
}
1089
case eOP_ORI: //ori (or immediate)
1090
{
1091
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1092
cpu.regs.r[instr.rt] = cpu.regs.r[instr.rs] | instr.immediate;
1093
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1094
break;
1095
}
1096
case eOP_LUI: //lui (load upper immediate)
1097
{
1098
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1099
cpu.regs.r[instr.rt] = instr.immediate<<16;
1100
cpu.p_alu.out_mem.op = CPU::eMemOp_None;
1101
break;
1102
}
1103
case eOP_LB: //lb (load byte)
1104
{
1105
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1106
cpu.p_alu.out_mem.addr = cpu.regs.r[instr.base()] + (s16)instr.immediate;
1107
cpu.p_alu.out_mem.rt = instr.rt;
1108
cpu.p_alu.out_mem.op = CPU::eMemOp_LoadByteSigned;
1109
break;
1110
}
1111
case eOP_LH: //lh (load halfword)
1112
{
1113
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1114
cpu.p_alu.out_mem.addr = cpu.regs.r[instr.base()] + (s16)instr.immediate;
1115
cpu.p_alu.out_mem.rt = instr.rt;
1116
cpu.p_alu.out_mem.op = CPU::eMemOp_LoadHalfwordSigned;
1117
break;
1118
}
1119
case eOP_LW: //lw (load word)
1120
{
1121
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1122
cpu.p_alu.out_mem.addr = cpu.regs.r[instr.base()] + (s16)instr.immediate;
1123
cpu.p_alu.out_mem.rt = instr.rt;
1124
cpu.p_alu.out_mem.op = CPU::eMemOp_LoadWord;
1125
break;
1126
}
1127
case eOP_LBU: //lbu (load byte unsigned)
1128
{
1129
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1130
cpu.p_alu.out_mem.addr = cpu.regs.r[instr.base()] + (s16)instr.immediate;
1131
cpu.p_alu.out_mem.rt = instr.rt;
1132
cpu.p_alu.out_mem.op = CPU::eMemOp_LoadByteUnsigned;
1133
break;
1134
}
1135
case eOP_LHU: //lhu (load halfword unsigned)
1136
{
1137
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1138
cpu.p_alu.out_mem.addr = cpu.regs.r[instr.base()] + (s16)instr.immediate;
1139
cpu.p_alu.out_mem.rt = instr.rt;
1140
cpu.p_alu.out_mem.op = CPU::eMemOp_LoadHalfwordUnsigned;
1141
break;
1142
}
1143
case eOP_SB: //sb (store byte)
1144
{
1145
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1146
cpu.p_alu.out_mem.addr = cpu.regs.r[instr.base()] + (s16)instr.immediate;
1147
cpu.p_alu.out_mem.value = cpu.regs.r[instr.rt] & 0xFF;
1148
cpu.p_alu.out_mem.op = CPU::eMemOp_StoreByte;
1149
break;
1150
}
1151
case eOP_SH: //sh (store halfword)
1152
{
1153
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1154
cpu.p_alu.out_mem.addr = cpu.regs.r[instr.base()] + (s16)instr.immediate;
1155
cpu.p_alu.out_mem.value = cpu.regs.r[instr.rt] & 0xFFFF;
1156
cpu.p_alu.out_mem.op = CPU::eMemOp_StoreHalfword;
1157
break;
1158
}
1159
case eOP_SW: //sw (store word)
1160
{
1161
const CPU::Instruction_ITYPE instr = cpu.p_alu.decode.instr.ITYPE;
1162
cpu.p_alu.out_mem.addr = cpu.regs.r[instr.base()] + (s16)instr.immediate;
1163
cpu.p_alu.out_mem.value = cpu.regs.r[instr.rt];
1164
cpu.p_alu.out_mem.op = CPU::eMemOp_StoreWord;
1165
break;
1166
}
1167
}
1168
1169
cpu.regs.r0 = 0;
1170
1171
//handle exceptions from alu
1172
//if(cpu.p_alu.exception != CPU::eException_None)
1173
//{
1174
// cpu_exception(cpu.p_alu.exception, cpu.p_alu.in_pc);
1175
//}
1176
}
1177
1178
void PSX::cpu_exec_cycle()
1179
{
1180
counter++;
1181
abscounter++;
1182
1183
//rd can sample registers after alu completes
1184
//rd can sample registers after mem completes
1185
//fetch can sample PC after first half of alu completes (branches need to be done in one early)
1186
1187
//we sort of pretend the RD stage isnt there, and the fetch stage is shifted over, so we have
1188
//| IF | ALU | MEM | WB |
1189
//the chief consequences are:
1190
//RD can latch registers that the ALU is asserting
1191
// (so, we will pretend RD doesnt exist and have ALU latch registers that the previous ALU cycle asserted)
1192
// (we'll do this by having an extra buffer of registers)
1193
//we don't worry much about the branch addresses getting passed to IF: we're logically shifted the IF to the right,
1194
//so the ALU will naturally be asserting them
1195
1196
cpu_run_muldiv();
1197
1198
if(cpu.stall_depends & cpu.stall_user)
1199
{
1200
//stalled
1201
}
1202
else
1203
{
1204
cpu_run_fetch();
1205
cpu_run_alu();
1206
cpu_run_mem();
1207
cpu_run_wb();
1208
1209
//latch mem<-alu
1210
cpu.p_mem.decode = cpu.p_alu.decode;
1211
cpu.p_mem.in_from_alu = cpu.p_alu.out_mem;
1212
1213
//latch alu<-fetch
1214
cpu.p_alu.decode = cpu.p_fetch.decode;
1215
cpu.p_alu.in_pc = cpu.p_fetch.in_fetch_addr;
1216
1217
//latch fetch<-alu
1218
cpu.p_fetch.in_fetch_addr = cpu.p_alu.out_pc.enabled ? cpu.p_alu.out_pc.pc : (cpu.p_fetch.in_fetch_addr + 4);
1219
1220
//check for exceptions. this should be more sophisticated
1221
if(cpu.p_alu.exception != CPU::eException_None)
1222
{
1223
cpu_exception(cpu.p_alu.exception,cpu.p_alu.in_pc);
1224
}
1225
}
1226
}
1227
1228
void PSX::RunForever()
1229
{
1230
static const int work = 33*1024*1024*20;
1231
DWORD a = timeGetTime();
1232
for(;;)
1233
{
1234
exec_cycle();
1235
if(counter == work) break;
1236
}
1237
DWORD b = timeGetTime();
1238
printf("%d ms\n",b-a);
1239
}
1240
1241