Skip to content

Commit a4cf363

Browse files
committed
nes-fix bug in mmc5 (fixes mmc5exram test) and add support for ex1 mode (fixes gemfire)
1 parent efd5bca commit a4cf363

File tree

1 file changed

+83
-21
lines changed
  • BizHawk.Emulation/Consoles/Nintendo/NES/Boards

1 file changed

+83
-21
lines changed

BizHawk.Emulation/Consoles/Nintendo/NES/Boards/ExROM.cs

+83-21
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public class ExROM : NES.NESBoardBase
4141
IntBuffer b_banks_1k = new IntBuffer(8);
4242
IntBuffer prg_banks_8k = new IntBuffer(4);
4343
byte product_low, product_high;
44+
int last_nt_read;
4445

4546
public override void SyncState(Serializer ser)
4647
{
@@ -54,14 +55,15 @@ public override void SyncState(Serializer ser)
5455
ser.Sync("chr_mode", ref chr_mode);
5556
ser.Sync("prg_mode", ref prg_mode);
5657
ser.Sync("chr_reg_high", ref chr_reg_high);
57-
ser.Sync("ab_mode", ref chr_reg_high);
58+
ser.Sync("ab_mode", ref ab_mode);
5859
ser.Sync("regs_a", ref regs_a);
5960
ser.Sync("regs_b", ref regs_b);
6061
ser.Sync("regs_prg", ref regs_prg);
6162
ser.Sync("nt_modes", ref nt_modes);
6263
ser.Sync("nt_fill_tile", ref nt_fill_tile);
6364
ser.Sync("nt_fill_attrib", ref nt_fill_attrib);
6465
ser.Sync("wram_bank", ref wram_bank);
66+
ser.Sync("last_nt_read", ref last_nt_read);
6567
ser.Sync("EXRAM", ref EXRAM, false);
6668

6769
if (ser.IsReader)
@@ -91,6 +93,9 @@ public override bool Configure(NES.EDetectionOrigin origin)
9193
case "NES-ELROM": //Castlevania 3 - Dracula's Curse (U)
9294
AssertPrg(128,256); AssertChr(128);
9395
break;
96+
case "NES-EKROM": //Gemfire (U)
97+
AssertPrg(256); AssertChr(256);
98+
break;
9499
case "MAPPER5":
95100
break;
96101
default:
@@ -139,12 +144,40 @@ int MapPRG(int addr, out bool ram)
139144
return (bank_8k << 13) | ofs;
140145
}
141146

147+
//this could be handy, but probably not. I did it on accident.
148+
//TileCoord ComputeTXTYFromPPUTiming(int visible_scanline, int cycle)
149+
//{
150+
// int py = visible_scanline;
151+
// int px = cycle;
152+
// if (cycle > 260)
153+
// {
154+
// py++;
155+
// px -= 322;
156+
// }
157+
// else px += 16;
158+
// int tx = px / 8;
159+
// int ty = py / 8;
160+
// return new TileCoord(tx, ty);
161+
//}
162+
142163
int MapCHR(int addr)
143164
{
144165
int bank_1k = addr >> 10;
145166
int ofs = addr & ((1 << 10) - 1);
146167

168+
if (exram_mode == 1 && NES.ppu.ppuphase == Nintendo.NES.PPU.PPUPHASE.BG)
169+
{
170+
int exram_addr = last_nt_read;
171+
int bank_4k = EXRAM[exram_addr] & 0x3F;
172+
173+
bank_1k = bank_4k * 4;
174+
bank_1k += chr_reg_high<<2;
175+
ofs = addr & (4 * 1024 - 1);
176+
goto MAPPED;
177+
}
178+
147179
//wish this logic could be smaller..
180+
//how does this KNOW that its in 8x16 sprites? the pattern of reads... emulate it that way..
148181
if (NES.ppu.reg_2000.obj_size_16)
149182
{
150183
if (NES.ppu.ppuphase == NES.PPU.PPUPHASE.OBJ)
@@ -157,11 +190,8 @@ int MapCHR(int addr)
157190
bank_1k = a_banks_1k[bank_1k];
158191
else
159192
bank_1k = b_banks_1k[bank_1k];
160-
161-
//something like this..?
162-
//bool special_sel = NES.ppu.reg_2000.obj_size_16 && NES.ppu.ppuphase == NES.PPU.PPUPHASE.OBJ;
163-
//bool a_sel = special_sel || (!a_sel && ab_mode == 0);
164-
193+
194+
MAPPED:
165195
bank_1k &= chr_bank_mask_1k;
166196
addr = (bank_1k<<10)|ofs;
167197
return addr;
@@ -177,6 +207,33 @@ public override byte ReadPPU(int addr)
177207
else
178208
{
179209
addr -= 0x2000;
210+
int nt_entry = addr & 0x3FF;
211+
if (nt_entry < 0x3C0)
212+
{
213+
//track the last nametable entry read so that subsequent pattern and attribute reads will know which exram address to use
214+
last_nt_read = nt_entry;
215+
}
216+
else
217+
{
218+
//attribute table
219+
if (exram_mode == 1)
220+
{
221+
//attribute will be in the top 2 bits of the exram byte
222+
int exram_addr = last_nt_read;
223+
int attribute = EXRAM[exram_addr] >> 6;
224+
//calculate tile address by getting x/y from last nametable
225+
int tx = last_nt_read & 0x1F;
226+
int ty = last_nt_read / 32;
227+
//attribute table address is just these coords shifted
228+
int atx = tx >> 1;
229+
int aty = ty >> 1;
230+
//figure out how we need to shift the attribute to fake out the ppu
231+
int at_shift = ((aty & 1) << 1) + (atx & 1);
232+
at_shift <<= 1;
233+
attribute <<= at_shift;
234+
return (byte)attribute;
235+
}
236+
}
180237
int nt = addr >> 10;
181238
int offset = addr & ((1<<10)-1);
182239
nt = nt_modes[nt];
@@ -473,24 +530,28 @@ void SyncCHRBanks()
473530
//MASTER LOGIC: something like this this might be enough to work, but i'll play with it later
474531
//bank_1k >> (3 - chr_mode) << chr_mode | bank_1k & ( etc.etc.
475532

533+
//TODO - do these need to have the last arguments multiplied by 8,4,2 to map to the right banks?
476534
switch (chr_mode)
477535
{
478536
case 0:
479-
SetBank(a_banks_1k, 0, 8, regs_a[7]);
480-
SetBank(b_banks_1k, 0, 8, regs_a[7]);
537+
SetBank(a_banks_1k, 0, 8, regs_a[7] * 8);
538+
SetBank(b_banks_1k, 0, 8, regs_b[3] * 8);
481539
break;
482540
case 1:
483-
SetBank(a_banks_1k, 0, 4, regs_a[3]);
484-
SetBank(a_banks_1k, 4, 4, regs_a[7]);
485-
SetBank(b_banks_1k, 0, 4, regs_b[3]);
541+
SetBank(a_banks_1k, 0, 4, regs_a[3] * 4);
542+
SetBank(a_banks_1k, 4, 4, regs_a[7] * 4);
543+
SetBank(b_banks_1k, 0, 4, regs_b[3] * 4);
544+
SetBank(b_banks_1k, 4, 4, regs_b[3] * 4);
486545
break;
487546
case 2:
488-
SetBank(a_banks_1k, 0, 2, regs_a[1]);
489-
SetBank(a_banks_1k, 2, 2, regs_a[3]);
490-
SetBank(a_banks_1k, 4, 2, regs_a[5]);
491-
SetBank(a_banks_1k, 6, 2, regs_a[7]);
492-
SetBank(b_banks_1k, 0, 2, regs_b[1]);
493-
SetBank(b_banks_1k, 2, 2, regs_b[3]);
547+
SetBank(a_banks_1k, 0, 2, regs_a[1] * 2);
548+
SetBank(a_banks_1k, 2, 2, regs_a[3] * 2);
549+
SetBank(a_banks_1k, 4, 2, regs_a[5] * 2);
550+
SetBank(a_banks_1k, 6, 2, regs_a[7] * 2);
551+
SetBank(b_banks_1k, 0, 2, regs_b[1] * 2);
552+
SetBank(b_banks_1k, 2, 2, regs_b[3] * 2);
553+
SetBank(b_banks_1k, 4, 2, regs_b[1] * 2);
554+
SetBank(b_banks_1k, 6, 2, regs_b[3] * 2);
494555
break;
495556
case 3:
496557
SetBank(a_banks_1k, 0, 1, regs_a[0]);
@@ -505,12 +566,13 @@ void SyncCHRBanks()
505566
SetBank(b_banks_1k, 1, 1, regs_b[1]);
506567
SetBank(b_banks_1k, 2, 1, regs_b[2]);
507568
SetBank(b_banks_1k, 3, 1, regs_b[3]);
569+
SetBank(b_banks_1k, 4, 1, regs_b[0]);
570+
SetBank(b_banks_1k, 5, 1, regs_b[1]);
571+
SetBank(b_banks_1k, 6, 1, regs_b[2]);
572+
SetBank(b_banks_1k, 7, 1, regs_b[3]);
508573
break;
509574
}
510-
b_banks_1k[4] = b_banks_1k[0];
511-
b_banks_1k[5] = b_banks_1k[1];
512-
b_banks_1k[6] = b_banks_1k[2];
513-
b_banks_1k[7] = b_banks_1k[3];
575+
514576

515577
}
516578

0 commit comments

Comments
 (0)