155 lines
3.2 KiB
C#
155 lines
3.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace BizHawk.Emulation.Consoles.Nintendo
|
|
{
|
|
// World Hero (Unl)
|
|
// 8k banked prgrom, 1k banked chrrom, scanline counter
|
|
// tried to copy behavior from fceux, but it doesn't work
|
|
public class Mapper027 : NES.NESBoardBase
|
|
{
|
|
// state
|
|
int[] chr = new int[8];
|
|
int[] prg = new int[4];
|
|
int prglatch;
|
|
int irqlatch;
|
|
int irqstat;
|
|
int irqcount;
|
|
|
|
// config
|
|
int chr_mask;
|
|
int prg_mask;
|
|
|
|
public override bool Configure(NES.EDetectionOrigin origin)
|
|
{
|
|
switch (Cart.board_type)
|
|
{
|
|
case "MAPPER027":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
AssertPrg(128);
|
|
AssertChr(512);
|
|
AssertVram(0);
|
|
AssertWram(0);
|
|
prg_mask = Cart.prg_size / 8 - 1;
|
|
chr_mask = Cart.chr_size / 1 - 1;
|
|
prg[3] = prg_mask;
|
|
return true;
|
|
}
|
|
|
|
public override byte ReadPRG(int addr)
|
|
{
|
|
return ROM[addr & 0x1fff | prg[addr >> 13] << 13];
|
|
}
|
|
|
|
public override byte ReadPPU(int addr)
|
|
{
|
|
if (addr < 0x2000)
|
|
return VROM[addr & 0x3ff | chr[addr >> 10] << 10];
|
|
else
|
|
return base.ReadPPU(addr);
|
|
}
|
|
|
|
public override void WritePRG(int addr, byte value)
|
|
{
|
|
addr &= 0xf00f;
|
|
//if (true)
|
|
// Console.WriteLine("{0:x4}:{1:x2}", addr + 0x8000, value);
|
|
if (addr >= 0x3000 && addr <= 0x6003)
|
|
{
|
|
int regnum = (addr >> 12) + 1 & 3;
|
|
regnum = regnum << 1 | (addr & 2) >> 1;
|
|
if ((addr & 1) != 0)
|
|
{
|
|
chr[regnum] &= 0x00f;
|
|
chr[regnum] |= value << 4 & chr_mask;
|
|
}
|
|
else
|
|
{
|
|
chr[regnum] &= 0x1f0;
|
|
chr[regnum] |= value & 0xf & chr_mask;
|
|
}
|
|
return;
|
|
}
|
|
|
|
switch (addr)
|
|
{
|
|
case 0x0000:
|
|
prg[prglatch] = value & prg_mask;
|
|
break;
|
|
case 0x1000:
|
|
switch (value & 3)
|
|
{
|
|
case 0: SetMirrorType(EMirrorType.Vertical); break;
|
|
case 1: SetMirrorType(EMirrorType.Horizontal); break;
|
|
case 2: SetMirrorType(EMirrorType.OneScreenA); break;
|
|
case 3: SetMirrorType(EMirrorType.OneScreenB); break;
|
|
}
|
|
prglatch = value & 2; // in fceux, this runs because of a lack of case break. bug?
|
|
break;
|
|
case 0x1002:
|
|
prglatch = value & 2;
|
|
break;
|
|
case 0x2000:
|
|
prg[1] = value & prg_mask;
|
|
break;
|
|
case 0x7000:
|
|
irqlatch &= 0xf0;
|
|
irqlatch |= value & 0x0f;
|
|
break;
|
|
case 0x7001:
|
|
irqlatch &= 0x0f;
|
|
irqlatch |= value << 4 & 0xf0;
|
|
break;
|
|
case 0x7002:
|
|
irqstat = value & 3;
|
|
if ((irqstat & 2) != 0)
|
|
irqcount = irqlatch - 1;
|
|
break;
|
|
case 0x7003:
|
|
irqstat = irqstat << 1 & 2 | irqstat & 1;
|
|
IRQSignal = false;
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// irq timing is entirely a guess; this bit improvised from ExROM
|
|
public override void ClockPPU()
|
|
{
|
|
if (NES.ppu.ppur.status.cycle != 336)
|
|
return;
|
|
if (!NES.ppu.reg_2001.PPUON)
|
|
return;
|
|
|
|
int sl = NES.ppu.ppur.status.sl + 1;
|
|
|
|
if (sl >= 241)
|
|
return;
|
|
hblanktrigger();
|
|
}
|
|
|
|
void hblanktrigger()
|
|
{
|
|
if ((irqstat & 2) != 0)
|
|
{
|
|
if (irqcount == 255)
|
|
{
|
|
IRQSignal = true;
|
|
irqcount = irqlatch + 1;
|
|
Console.WriteLine("Raise");
|
|
}
|
|
else
|
|
irqcount++;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|