-
Notifications
You must be signed in to change notification settings - Fork 8
/
Tlb.c
1418 lines (1273 loc) · 45.9 KB
/
Tlb.c
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
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*$T Tlb.c GC 1.136 03/09/02 17:29:32 */
/*$6
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Translation Lookaside Buffer (TLB) emulation. TLB converts virtual addresses to physical ones.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
/*
* 1964 Copyright (C) 1999-2002 Joel Middendorf, <[email protected]> This
* program is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version. This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. To contact the
* authors: email: [email protected], [email protected]
*/
#include <windows.h>
#include "globals.h"
#include "r4300i.h"
#include "hardware.h"
#include "interrupt.h"
#include "win32/windebug.h"
#include "debug_option.h"
#include "timer.h"
#include "memory.h"
#include "1964ini.h"
#include "emulator.h"
#include "plugins.h"
#include "compiler.h"
/* Local Definition and Variables */
#define MAXITLB 2
#define MAXDTLB 3
/* Debug Output */
#define DUMMYTLBINDEX (-1)
int ITLB_Index[MAXITLB];
int DTLB_Index[MAXDTLB];
int last_itlb_index;
int last_dtlb_index;
static BOOL newtlb;
/* Define the TLB Lookup Table */
uint32 Direct_TLB_Lookup_Table[0x100000];
uint32 TLB_Refill_Exception_Vector = 0x80000080;
uint32 TLB_Error_Vector = 0x80000000;
BOOL trigger_tlb_exception_faster = FALSE;
BOOL ITLB_Error = FALSE;
tlb_struct dummy_tlb;
void Build_Whole_Direct_TLB_Lookup_Table(void);
void Build_Direct_TLB_Lookup_Table(int index, BOOL tobuild);
void Refresh_Direct_TLB_Lookup_Table(int index);
uint32 Direct_TLB_Lookup(uint32 address, int operation);
/* TLB.c Internal Functions */
uint32 TLBMapErrorAddress(uint32 address);
uint32 Trigger_TLB_Refill_Exception(uint32 address, int operation);
uint32 Trigger_TLB_Invalid_Exception(uint32 address, int operation);
/*
=======================================================================================================================
Translation Lookaside Buffer Probe. The Index register is loaded with the address of the TLB entry whose contents
match the contents of the EntryHi register. If no TLB entry matches, the high-order bit of the Index register is
set. The architecture does not specify the operation of memory references associated with the instruction
immediately after a TLBP instruction, nor is the operation specified if more than one TLB entry matches.
=======================================================================================================================
*/
void r4300i_COP0_tlbp(uint32 Instruction)
{
/*~~~~~~~~~~*/
uint32 index;
/*~~~~~~~~~~*/
/* uint32 g; */
gHWS_COP0Reg[INDEX] |= 0x80000000; /* initially set high-order bit */
for(index = 0; index <= NTLBENTRIES; index++)
{
/*
* Not sure about here, if we should compare the all TLBHI_VPN2MASK, or need to
* mask with TLB.MyHiMask £
* I think should just mask with TLBHI_VPN2MASK, not with TLB.MyHiMask according
* to r4300i manual £
* But doing this, some game will give errors of TLBP lookup fail. £
* if( ( (gMS_TLB[index].EntryHi & TLBHI_VPN2MASK) == (gHWS_COP0Reg[ENTRYHI] &
* TLBHI_VPN2MASK) ) &&
*/
if
(
((gMS_TLB[index].EntryHi & gMS_TLB[index].MyHiMask) == (gHWS_COP0Reg[ENTRYHI] & gMS_TLB[index].MyHiMask))
&& (
(gMS_TLB[index].EntryLo0 & TLBLO_G & gMS_TLB[index].EntryLo1)
|| (gMS_TLB[index].EntryHi & TLBHI_PIDMASK) == (gHWS_COP0Reg[ENTRYHI] & TLBHI_PIDMASK)
)
)
{
gHWS_COP0Reg[INDEX] = index;
TLB_DETAIL_TRACE
(
TRACE2
(
"TLBP - Load INDEX register:%d, VPN2 = 0x%08X [bit 31-13]",
index,
((uint32) gHWS_COP0Reg[ENTRYHI] & TLBHI_VPN2MASK)
)
) return;
}
}
/*
* TLB_TRACE(TRACE1( "TLBP - no match, VPN2 = 0x%08X [bit 31-13]",
* ((uint32)gHWS_COP0Reg[ENTRYHI] & TLBHI_VPN2MASK)))
*/
TLB_TRACE(TRACE1("TLBP - no match, ENTRYHI = 0x%08X", ((uint32) gHWS_COP0Reg[ENTRYHI])))
}
/*
=======================================================================================================================
TLBR - Translation Lookaside Buffer Read. The G bit (which controls ASID matching) read from the TLB is written
into both of the EntryLo0 and EntryLo1 registers. The EntryHi and EntryLo registers are loaded with the contents of
the TLB entry pointed at by the contents of the TLB Index register. The operation is invalid (and the results are
unspecified) if the contents of the TLB Index register are greater than the number of TLB entries in the processor.
=======================================================================================================================
*/
void r4300i_COP0_tlbr(uint32 Instruction)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
uint32 index = gHWS_COP0Reg[INDEX] & 0x7FFFFFFF;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if(index > NTLBENTRIES)
{
TLB_TRACE(TRACE1("ERROR: tlbr received an invalid index=%08X", index));
}
index &= NTLBENTRIES;
TLB_DETAIL_TRACE(TRACE1("TLBR - Read from TLB[%d]", index)) gHWS_COP0Reg[PAGEMASK] = (uint32)
(gMS_TLB[index].PageMask);
gHWS_COP0Reg[ENTRYHI] = (uint32) (gMS_TLB[index].EntryHi);
gHWS_COP0Reg[ENTRYHI] &= (~(uint32) (gMS_TLB[index].PageMask));
gHWS_COP0Reg[ENTRYLO1] = (uint32) (gMS_TLB[index].EntryLo1);
gHWS_COP0Reg[ENTRYLO0] = (uint32) (gMS_TLB[index].EntryLo0);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void tlb_write_entry(int index)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
tlb_struct *theTLB;
int g = (gHWS_COP0Reg[ENTRYLO0] & gHWS_COP0Reg[ENTRYLO1]) & TLBLO_G; /* The g bit */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if(index == DUMMYTLBINDEX) /* please write to dummy tlb */
{
theTLB = &dummy_tlb;
}
else
theTLB = &gMS_TLB[index];
if(index > NTLBENTRIES)
{
DisplayError("ERROR: tlbwi called with invalid index");
return;
}
#ifdef DEBUG_TLB_DETAIL
if(debugoptions.debug_tlb_detail && index != DUMMYTLBINDEX)
{
TRACE1("TLBWI/TLBWR - Load TLB[%d]", index);
TRACE2("PAGEMASK = 0x%08X, ENTRYHI = 0x%08X", (uint32) gHWS_COP0Reg[PAGEMASK], (uint32) gHWS_COP0Reg[ENTRYHI]);
TRACE2
(
"ENTRYLO1 = 0x%08X, ENTRYLO0 = 0x%08X",
(uint32) gHWS_COP0Reg[ENTRYLO1],
(uint32) gHWS_COP0Reg[ENTRYLO0]
);
}
#endif
theTLB->valid = 0; /* Not sure if we should use this valid bit any more */
/*
* according to TLB comparasion, it is OK to have only EntryLo0 or EntryLo1 valid,
* not both of them £
* yes, still need in Direct TLB lookup
*/
if((gHWS_COP0Reg[ENTRYLO1] & TLBLO_V) || (gHWS_COP0Reg[ENTRYLO0] & TLBLO_V)) theTLB->valid = 1;
theTLB->PageMask = gHWS_COP0Reg[PAGEMASK];
theTLB->EntryLo1 = (gHWS_COP0Reg[ENTRYLO1] | g);
theTLB->EntryLo0 = (gHWS_COP0Reg[ENTRYLO0] | g);
theTLB->MyHiMask = ~(uint32) theTLB->PageMask & TLBHI_VPN2MASK;
/*
* theTLB->EntryHi = gHWS_COP0Reg[ENTRYHI]; // This EntryHi should just copy from
* the ENTRYHI register £
* we will not store the g bit in the EntryHi, but keep them in EntryLo0 and
* EntryLo1 £
* theTLB->EntryHi = (gHWS_COP0Reg[ENTRYHI] & (~(uint32)gHWS_COP0Reg[PAGEMASK])) |
* (gHWS_COP0Reg[PAGEMASK]&TLBHI_PIDMASK);
*/
theTLB->EntryHi = gHWS_COP0Reg[ENTRYHI] & (~(uint32) gHWS_COP0Reg[PAGEMASK]);
switch(theTLB->PageMask)
{
case 0x00000000: /* 4k */theTLB->LoCompare = 0x00001000; break;
case 0x00006000: /* 16k */theTLB->LoCompare = 0x00004000; break;
case 0x0001E000: /* 64k */theTLB->LoCompare = 0x00010000; break;
case 0x0007E000: /* 256k */theTLB->LoCompare = 0x00040000; break;
case 0x001FE000: /* 1M */theTLB->LoCompare = 0x00100000; break;
case 0x007FE000: /* 4M */theTLB->LoCompare = 0x00400000; break;
case 0x01FFE000: /* 16M */theTLB->LoCompare = 0x01000000; break;
default: DisplayError("ERROR: tlbwi - invalid page size"); break;
}
newtlb = TRUE;
}
/*
=======================================================================================================================
TLBWI - Translation Lookaside Buffer Write Index. The G bit of the TLB is written with the logical AND of the G
bits in the EntryLo0 and EntryLo1 registers. The TLB entry pointed at by the contents of the TLB Index register is
loaded with the contents of the EntryHi and EntryLo registers. The operation is invalid (and the results are
unspecified) if the contents of the TLB Index register are greater than the number of TLB entries in the processor.
=======================================================================================================================
*/
void r4300i_COP0_tlbwi(uint32 Instruction)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
int index = gHWS_COP0Reg[INDEX] & NTLBENTRIES;
int new_valid = ((gHWS_COP0Reg[ENTRYLO1] & TLBLO_V) || (gHWS_COP0Reg[ENTRYLO0] & TLBLO_V));
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
TLB_TRACE(TRACE1("TLBWI - Load TLB[%d]", index));
if(gMS_TLB[index].valid == 1)
{
/*~~*/
int i;
/*~~*/
for(i = 0; i < MAXDTLB; i++)
{
if(ITLB_Index[i] == index)
{
TLB_DETAIL_TRACE(TRACE1("TLB %d is unmapped while ITLB is still mapped to it", index));
break;
}
}
}
Refresh_Direct_TLB_Lookup_Table(index);
}
/*
=======================================================================================================================
TLBWR - Translation Lookaside Buffer Write Random. The G bit of the TLB is written with the logical AND of the G
bits in the EntryLo0 and EntryLo1 registers. The TLB entry pointed at by the contents of the TLB Random register is
loaded with the contents of the EntryHi and EntryLo registers
=======================================================================================================================
*/
void r4300i_COP0_tlbwr(uint32 Instruction)
{
/*~~~~~~~~~*/
int index, i;
/*~~~~~~~~~*/
/*
* gHWS_COP0Reg[RANDOM] = Get_COUNT_Register() %
* (0x40-(gHWS_COP0Reg[WIRED]&0x3f))+gHWS_COP0Reg[WIRED];
*/
gHWS_COP0Reg[RANDOM] = Get_COUNT_Register() % (0x20 - (gHWS_COP0Reg[WIRED] & 0x1f)) + gHWS_COP0Reg[WIRED];
index = gHWS_COP0Reg[RANDOM] & NTLBENTRIES;
/* hack, only use invalid entry */
if(gMS_TLB[index].valid == 1)
{
for(i = gHWS_COP0Reg[WIRED]; i <= NTLBENTRIES; i++)
{
if(gMS_TLB[i].valid == 0)
{
index = i;
break;
}
}
}
TLB_TRACE(TRACE1("TLBWR - Load TLB[%d]", index));
Refresh_Direct_TLB_Lookup_Table(index);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
uint32 TranslateITLBAddress(uint32 address)
{
return Direct_TLB_Lookup(address, TLB_INST);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
uint32 TranslateTLBAddressForLoad(uint32 address)
{
return Direct_TLB_Lookup(address, TLB_LOAD);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
uint32 TranslateTLBAddressForStore(uint32 address)
{
return Direct_TLB_Lookup(address, TLB_STORE);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
uint32 RedoTLBLookupAfterException(uint32 address, int operation)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
uint32 realAddress = 0x80000000;
_int32 c;
tlb_struct *theTLB;
uint32 EntryLo;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* search the tlb entries */
for(c = 0; c < MAXTLB; c++)
{
theTLB = &gMS_TLB[c];
/*
* skip unused entries £
* if (theTLB->valid == 0) continue; £
* if ( ((theTLB->EntryLo0 | theTLB->EntryLo1)) == 0) continue; £
* compare upper bits £
* if ((address & theTLB->MyHiMask & 0x1FFFFFFF) == (theTLB->EntryHi &
* theTLB->MyHiMask & 0x1FFFFFFF))
*/
if((address & theTLB->MyHiMask) == (theTLB->EntryHi & theTLB->MyHiMask))
{
/* check the global bit */
if
(
((0x01 & theTLB->EntryLo1 & theTLB->EntryLo0) == 1) /* g bit match */
|| ((theTLB->EntryHi & TLBHI_PIDMASK) == (gHWS_COP0Reg[ENTRYHI] & TLBHI_PIDMASK))
) /* ASID match */
{
/* select EntryLo depending on if we're in an even or odd page */
if(address & theTLB->LoCompare)
EntryLo = theTLB->EntryLo1;
else
EntryLo = theTLB->EntryLo0;
if(EntryLo & 0x02)
{
/* calculate the real address from EntryLo */
realAddress |= ((EntryLo << 6) & ((theTLB->MyHiMask) >> 1));
realAddress |= (address & ((theTLB->PageMask | 0x00001FFF) >> 1));
return realAddress;
}
else
{
continue;
}
}
}
}
TLB_TRACE(TRACE1("Redo TLB check still fail, mapped to dummy memory section, addr=%08x", address)) if(operation == TLB_INST)
{
DisplayError
(
"TLBL Missing Exception for Instruction Access, Bad VPN2 = 0x%8X, Bad Virtual Address = 0x%08X",
address >> 13,
address
);
}
return TLBMapErrorAddress(address);
}
/*
=======================================================================================================================
This is the main function to do mapped virtual address to physical address translation
=======================================================================================================================
*/
uint32 TranslateTLBAddress(uint32 address, int operation)
{
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
BOOL invalidmatched;
uint32 realAddress = 0x80000000;
_int32 c;
tlb_struct *theTLB;
uint32 EntryLo;
int maxtlb;
int *tlb_index_array;
int *lastused;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
if(operation == TLB_INST)
{
maxtlb = MAXITLB;
tlb_index_array = ITLB_Index;
lastused = &last_itlb_index;
}
else
{
maxtlb = MAXDTLB;
tlb_index_array = DTLB_Index;
lastused = &last_dtlb_index;
}
invalidmatched = FALSE;
/* search the tlb entries */
for(c = 0; c < MAXTLB + maxtlb; c++)
/* for (c = 0; c < MAXTLB; c++) */
{
if(c < maxtlb) theTLB = &gMS_TLB[*(tlb_index_array + (maxtlb +*lastused - c) % maxtlb)]; /* Check micro TLB
* first */
else
theTLB = &gMS_TLB[c - maxtlb];
/*
* skip unused entries £
* if (theTLB->valid == 0) continue; £
* if ( ((theTLB->EntryLo0 | theTLB->EntryLo1) & TLBLO_V ) == 0) continue; // Skip
* this entry if both EntroLo0 and EntryLo1 are invalid £
* compare upper bits £
* This is a unreasonable hack, I should not use this 0x1FFFFFFF mask, but £
* I cannot find the bugs in dyna, without this mask, many games will not work
* well £
* games like Snowboard Kids 2 £
* if ((address & theTLB->MyHiMask &0x1FFFFFFF ) == (theTLB->EntryHi &
* theTLB->MyHiMask & 0x1FFFFFFF))
*/
if((address & theTLB->MyHiMask) == (theTLB->EntryHi & theTLB->MyHiMask)) /* match, this line
* is correct */
{
/* check the global bit */
if
(
((0x01 & theTLB->EntryLo1 & theTLB->EntryLo0) == 1) /* g bit match */
|| ((theTLB->EntryHi & TLBHI_PIDMASK) == (gHWS_COP0Reg[ENTRYHI] & TLBHI_PIDMASK))
) /* ASID match */
{
/* select EntryLo depending on if we're in an even or odd page */
if(address & theTLB->LoCompare)
EntryLo = theTLB->EntryLo1;
else
EntryLo = theTLB->EntryLo0;
if(EntryLo & 0x02) /* Is the entry valid ?? */
{
/* calculate the real address from EntryLo */
realAddress |= ((EntryLo << 6) & ((theTLB->MyHiMask) >> 1));
realAddress |= (address & ((theTLB->PageMask | 0x00001FFF) >> 1));
Direct_TLB_Lookup_Table[address / 0x1000] = (realAddress & 0xFFFFF000);
/* TLB_sDWORD_R[address/0x1000] = sDWord[realAddress>>16]+(realAddress&0x0000F000); */
TLB_sDWORD_R[address / 0x1000] = TLB_sDWORD_R[realAddress / 0x1000];
TLB_DETAIL_TRACE
(
TRACE2
(
"Direct TLB Map: VA=%08X, PA=%08X",
(address & 0xFFFFF000),
(realAddress & 0xFFFFF000)
)
) if(c >= maxtlb)
{
/* Set the microTLB */
*lastused = (*lastused + 1) % maxtlb;
*(tlb_index_array +*lastused) = c - maxtlb;
TLB_DETAIL_TRACE
(
TRACE3
(
"%s remapped to TLB at %d, vaddr=%08x",
operation == TLB_INST ? "ITLB" : "DTLB",
c - maxtlb,
address
)
)
}
else
{
*lastused = c;
}
return realAddress;
}
else
{
invalidmatched = TRUE;
continue;
}
}
}
}
/*
* hack for golden eye £
* if( strncmp(currentromoptions.Game_Name, "GOLDENEYE", 9) == 0 &&
* (address&0xFF000000) == 0x7F000000 ) { if( rominfo.TV_System == TV_SYSTEM_NTSC
* ) { uint32 i; for( i=0; i<(gAllocationLength - 0x34b30)/0x1000; i++) {
* Direct_TLB_Lookup_Table[0x7f000+i] = 0x90034b30+i*0x1000;
* TLB_sDWORD_R[0x7f000+i] = &gMS_ROM_Image[0x34b30+i*0x1000]; } realAddress
* (address - 0x7f000000) + 0x90034b30; } else { uint32 i; for( i=0;
* i<(gAllocationLength - 0x329f0)/0x1000; i++) {
* Direct_TLB_Lookup_Table[0x7f000+i] = 0x900329f0+i*0x1000;
* TLB_sDWORD_R[0x7f000+i] = &gMS_ROM_Image[0x329f0+i*0x1000]; } realAddress
* (address - 0x7f000000) + 0x900329f0; } TLB_DETAIL_TRACE(TRACE2("Hack, mapping
* for GoldenEye: %08X ==> %08X", address, realAddress)); return realAddress; }
*/
if(invalidmatched)
return(Trigger_TLB_Invalid_Exception(address, operation));
else
/* Fire TLB refill exception here */
return(Trigger_TLB_Refill_Exception(address, operation));
}
extern uint32 TLB_Error_Vector;
void __cdecl error(char *Message, ...)
{
/*~~~~~~~~~~~~~*/
char Msg[400];
va_list ap;
/*~~~~~~~~~~~~~*/
va_start(ap, Message);
vsprintf(Msg, Message, ap);
va_end(ap);
MessageBox(NULL, Msg, "Error", MB_OK | MB_ICONINFORMATION);
}
/*
=======================================================================================================================
=======================================================================================================================
*/
uint32 Trigger_TLB_Refill_Exception(uint32 address, int operation)
{
/*~~~~~~~~~*/
uint32 addr;
/*~~~~~~~~~*/
#ifdef DEBUG_TLB
if(debugoptions.debug_tlb)
{
if(operation == TLB_LOAD)
{
TRACE2("0x%08X: TLBL Refill Exception, Bad Virtual Address = 0x%08X", gHWS_pc, address)
}
else if(operation == TLB_STORE)
{
TRACE2("0x%08X: TLBS Refill Exception, Bad Virtual Address = 0x%08X", gHWS_pc, address)
}
else
{
TRACE2("0x%08X: TLB Refill Exception for Instruction, VA=%08X", gHWS_pc, address)
}
}
#endif
gHWS_COP0Reg[BADVADDR] = address;
gHWS_COP0Reg[CONTEXT] &= 0xFF800000; /* Mask off bottom 23 bits */
gHWS_COP0Reg[CONTEXT] |= ((address >> 13) << 4);
gHWS_COP0Reg[ENTRYHI] &= 0x00001FFF; /* Mask off the top bit 13-31 */
gHWS_COP0Reg[ENTRYHI] |= (address & 0xFFFFE000);
if(operation == TLB_STORE)
SET_EXCEPTION(TLBS_Miss) else
SET_EXCEPTION(TLBL_Miss) newtlb = FALSE;
/*
* Test the TLB refill service vector £
* Hack for Turok: Rage War and for NFL QBC: 2000, donno why I need this £
* For the TLB service vector here, it is tricky. £
* I should use 0x80000000 to serve TLB_Refill for 32bit TLB, and use 0x80000080
* to serve £
* 64bit TLB. I believe I should use 0x80000000 for most of games, £
* Somehow, Golden Eye only work if I use 0x80000000, while Turok 2 only work if I
* use £
* 0x80000080, do I need to check the status register to decide the vector? £
* if( TLB_Refill_Exception_Vector != 0x80000000 )
*/
{
for(addr = 0x80000000; addr < 0x8000000C; addr += 4)
{
if(MEM_READ_UWORD(addr) != MEM_READ_UWORD(addr + 0x80))
{
if(TLB_Refill_Exception_Vector == 0x80000080)
{
TRACE0("");
TRACE0("Warning, Set TLB exception vector to 0x80000000");
TRACE0("");
TLB_Refill_Exception_Vector = 0x80000000;
}
goto step2;
}
}
if(TLB_Refill_Exception_Vector == 0x80000000)
{
TRACE0("");
TRACE0("Warning, Set TLB exception vector to 0x80000080");
TRACE0("");
TLB_Refill_Exception_Vector = 0x80000080;
}
}
step2:
if((gHWS_COP0Reg[STATUS] & 0xE0) != 0)
{
TRACE0("To trigger TLB refill exception, SX/UX/KX != 0");
DisplayError("To trigger TLB refill exception, SX/UX/KX != 0");
}
if(operation == TLB_INST)
{ /* here we have got a TLB error at compiling, need to invalidate the compiled block
* £
* and serve the TLB error */
ITLB_Error = TRUE;
TLB_Error_Vector = TLB_Refill_Exception_Vector;
return address;
}
else
{
TLB_Error_Vector = TLB_Refill_Exception_Vector;
HandleExceptions(TLB_Error_Vector);
if(emustatus.cpucore == DYNACOMPILER)
{
if(newtlb) /* if a new TLB entry is written in the TLB exception service routine */
{
/* Could make infinite loop, be careful here */
return(TranslateTLBAddress(address, operation));
}
else
{
//return(address);
/* Redo TLB lookup, of course, redo will still fail, need a little optimization here */
return(RedoTLBLookupAfterException(address, operation));
}
}
else
{
TRACE1("TLB Refill for load/store, vaddr=%08X", address);
return(0x80800000); /* return an address to guarante an invalid address */
/* so store opcode will not overwite any valid address */
}
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
uint32 Trigger_TLB_Invalid_Exception(uint32 address, int operation)
{
#ifdef DEBUG_TLB
if(debugoptions.debug_tlb)
{
if(operation == TLB_LOAD)
{
TRACE2("0x%08X: TLBL Invalid Exception, Bad Virtual Address = 0x%08X", gHWS_pc, address)
}
else if(operation == TLB_STORE)
{
TRACE2("0x%08X: TLBS Invalid Exception, Bad Virtual Address = 0x%08X", gHWS_pc, address)
}
else
{
TRACE2("0x%08X: TLB Invalid Exception for Instruction, VA=%08X", gHWS_pc, address)
}
TRACE1("Bad Virtual Address = 0x%08X", address);
}
#endif
gHWS_COP0Reg[BADVADDR] = address;
gHWS_COP0Reg[CONTEXT] &= 0xFF800000; /* Mask off bottom 23 bits */
gHWS_COP0Reg[CONTEXT] |= ((address >> 13) << 4);
gHWS_COP0Reg[ENTRYHI] &= 0x00001FFF; /* Mask off the top bit 13-31 */
gHWS_COP0Reg[ENTRYHI] |= (address & 0xFFFFE000);
if(operation == TLB_STORE)
SET_EXCEPTION(TLBS_Miss) else
SET_EXCEPTION(TLBL_Miss) newtlb = FALSE;
if(operation == TLB_INST)
{ /* here we have got a TLB error at compiling, need to invalidate the compiled block
* £
* and serve the TLB error */
ITLB_Error = TRUE;
TLB_Error_Vector = 0x80000180;
/* TLB_Error_Vector = 0x80000000; */
return address;
}
else
{
HandleExceptions(0x80000180);
TLB_Error_Vector = 0x80000180;
if(emustatus.cpucore == DYNACOMPILER)
{
if(newtlb) /* if a new TLB entry is written in the TLB exception service routine */
{
/* Could make infinite loop, be careful here */
return(TranslateTLBAddress(address, operation));
}
else
{
/* Redo TLB lookup, of course, redo will still fail, need a little optimize here */
return(RedoTLBLookupAfterException(address, operation));
}
}
else
{
TRACE1("TLB invalid for load/store, vaddr=%08X", address);
return(0x80800000); /* return a address to garante a invalid address */
/* so store opcode will not overwite any valid address */
}
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void InitTLBOther(void);
void InitTLB(void)
{
/*~~*/
int i;
/*~~*/
for(i = 0; i < MAXTLB; i++)
{
memset(&gMemoryState.TLB[i], 0, sizeof(tlb_struct));
}
last_itlb_index = 0;
for(i = 0; i < MAXITLB; i++)
{
ITLB_Index[i] = 0;
}
last_dtlb_index = 0;
for(i = 0; i < MAXDTLB; i++)
{
DTLB_Index[i] = 0;
}
/* Initialize the TLB Lookup Table */
for(i = 0; i < 0x100000; i++)
{
Direct_TLB_Lookup_Table[i] = DUMMYDIRECTTLBVALUE;
/* This is a magic number, to represent invalid TLB address */
}
/* we probably need to review a little bit here later */
for(i = 0; i < 0x100000; i++)
{
TLB_sDWORD_R[i] = sDWord[i >> 4] + 0x1000 * (i & 0xf);
}
InitTLBOther();
}
void InitTLBOther(void)
{
/* some TLB hacks to speed up some games, but fails at others */
trigger_tlb_exception_faster = FALSE;
if(emustatus.game_hack == GHACK_GE)
{
/* Hack for golden eye, game still work without hack, but will be faster with hack */
if(rominfo.TV_System == TV_SYSTEM_NTSC)
{
/*~~~~~~*/
uint32 i;
/*~~~~~~*/
for(i = 0; i < (gAllocationLength - 0x34b30) / 0x1000 && i < 0xFCB; i++)
{
Direct_TLB_Lookup_Table[0x7f000 + i] = 0x90034b30 + i * 0x1000;
TLB_sDWORD_R[0x7f000 + i] = &gMS_ROM_Image[0x34b30 + i * 0x1000];
}
}
else
{
/*~~~~~~*/
uint32 i;
/*~~~~~~*/
for(i = 0; i < (gAllocationLength - 0x329f0) / 0x1000; i++)
{
Direct_TLB_Lookup_Table[0x7f000 + i] = 0x900329f0 + i * 0x1000;
TLB_sDWORD_R[0x7f000 + i] = &gMS_ROM_Image[0x329f0 + i * 0x1000];
}
}
trigger_tlb_exception_faster = TRUE;
}
else if(strncmp(currentromoptions.Game_Name, "CONKER", 6) == 0)
{
trigger_tlb_exception_faster = TRUE;
}
}
/*
=======================================================================================================================
This function will try best to map a TLB error virtual address to its real address
=======================================================================================================================
*/
uint32 TLBMapErrorAddress(uint32 address)
{
/*~~~~~~~~~~~~~~*/
/* Check if the address is in any readable memory region */
uint32 dummyword;
/*~~~~~~~~~~~~~~*/
__try
{
dummyword = LOAD_UWORD_PARAM(address);
return((address & 0x1fffffff) | 0x80000000);
}
__except(NULL, EXCEPTION_EXECUTE_HANDLER)
{
__try
{
dummyword = LOAD_UWORD_PARAM_2(address);
return(address & 0x1fffffff);
}
__except(NULL, EXCEPTION_EXECUTE_HANDLER)
{
return((address & 0x0000FFFF + 0x1FFF0000) | 0x80000000); /* mapped to dummy segment */
}
}
}
/*
=======================================================================================================================
ERET - Return from Exception. ERET is the R4300 instruction for returning from an interrupt, exception, or error
trap. Unlike a branch or jump instruction, ERET does not execute the next instruction.
=======================================================================================================================
*/
void r4300i_COP0_eret(uint32 Instruction)
{
if((gHWS_COP0Reg[STATUS] & 0x00000004))
{
CPUdelayPC = gHWS_COP0Reg[ERROREPC]; /* dynarec use: pc = COP0Reg[ERROREPC]; */
/* clear the ERL bit to zero */
gHWS_COP0Reg[STATUS] &= 0xFFFFFFFB; /* 0xFFFFFFFB same as ~0x00000004; */
}
else
{
CPUdelayPC = gHWS_COP0Reg[EPC]; /* dynarec use: pc = COP0Reg[EPC]; */
/* clear the EXL bit of the status register to zero */
gHWS_COP0Reg[STATUS] &= 0xFFFFFFFD; /* 0xFFFFFFFD same as ~0x00000002 */
}
CPUdelay = 2; /* not used in dynarec */
gHWS_LLbit = 0;
}
/*
=======================================================================================================================
TRAPS
=======================================================================================================================
*/
void r4300i_teqi(uint32 Instruction)
{
DisplayError("In Trap TEQI");
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void r4300i_tgei(uint32 Instruction)
{
DisplayError("In Trap r4300i_tgei");
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void r4300i_tgeiu(uint32 Instruction)
{
DisplayError("In Trap r4300i_tgeiu");
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void r4300i_tlti(uint32 Instruction)
{
DisplayError("In Trap r4300i_tlti");
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void r4300i_tltiu(uint32 Instruction)
{
DisplayError("In Trap r4300i_tltiu");
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void r4300i_tnei(uint32 Instruction)
{
DisplayError("In Trap r4300i_tnei");
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void r4300i_teq(uint32 Instruction)
{
if(gRS == gRT)
{
#ifdef DEBUG_TRAP
if(debugoptions.debug_trap) TRACE0("Trap r4300i_teq");
#endif
SET_EXCEPTION(EXC_TRAP) HandleExceptions(0x80000180);
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void r4300i_tge(uint32 Instruction)
{
/* DisplayError("In Trap r4300i_tge"); */
if(gRS >= gRT)
{
#ifdef DEBUG_TRAP
if(debugoptions.debug_trap) TRACE0("Trap r4300i_tge");
#endif
SET_EXCEPTION(EXC_TRAP) HandleExceptions(0x80000180);
}
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void r4300i_tgeu(uint32 Instruction)
{
DisplayError("In Trap r4300i_tgeu");
}
/*
=======================================================================================================================
=======================================================================================================================
*/
void r4300i_tlt(uint32 Instruction)
{
DisplayError("In Trap r4300i_tlt");
}