Atari 2600: Modified how memory read/writes are handled, to better emulate the address bus. Cleaned up some comments. Turned off CPU debugging. Added functions to read console switches and player 2 buttons.

M6532: Mostly re-written, this time based on the datasheet. 
TIA: Removed console debug outputs.
This commit is contained in:
pjgat09 2012-03-21 20:28:26 +00:00
parent dcaf724dae
commit a56ddcdb15
3 changed files with 196 additions and 147 deletions

View File

@ -58,45 +58,32 @@ namespace BizHawk
// ROM
public byte ReadMemory(ushort addr)
{
ushort maskedAddr = (ushort)(addr & 0x1FFF);
ushort pageNum = (ushort)(maskedAddr >> 6);
if (pageNum < 0x40)
addr = (ushort)(addr & 0x1FFF);
if ((addr & 0x1080) == 0)
{
// if Page 0x02, or a mirror
if (pageNum % 4 > 1)
{
return m6532.ReadMemory(maskedAddr);
}
// if Page 0x01 or 0x02, or a mirror
else
{
return tia.ReadMemory(maskedAddr);
}
return tia.ReadMemory(addr);
}
else if ((addr & 0x1080) == 0x0080)
{
return m6532.ReadMemory(addr);
}
// ROM data
else
{
//Console.WriteLine("ROM read");
return rom[maskedAddr & 0x0FFF];
return rom[addr & 0x0FFF];
}
}
public void WriteMemory(ushort addr, byte value)
{
ushort maskedAddr = (ushort)(addr & 0x1FFF);
ushort pageNum = (ushort)(maskedAddr >> 6);
if (pageNum < 0x40)
addr = (ushort)(addr & 0x1FFF);
if ((addr & 0x1080) == 0)
{
if (pageNum % 4 > 1)
{
m6532.WriteMemory(maskedAddr, value);
}
else
{
tia.WriteMemory(maskedAddr, value);
}
tia.WriteMemory(addr, value);
}
else if ((addr & 0x1080) == 0x0080)
{
m6532.WriteMemory(addr, value);
}
// ROM data
else
{
Console.WriteLine("ROM write(?): " + addr.ToString("x"));
@ -106,7 +93,7 @@ namespace BizHawk
public void HardReset()
{
cpu = new MOS6507();
cpu.debug = true;
//cpu.debug = true;
cpu.ReadMemory = ReadMemory;
cpu.WriteMemory = WriteMemory;
@ -114,7 +101,7 @@ namespace BizHawk
//tia = new TIA(this, frameBuffer);
tia = new TIA(this);
// Setup 6532
m6532 = new M6532(cpu, ram, this);
m6532 = new M6532(this);
//setup the system state here. for instance..
// Read from the reset vector for where to start
@ -125,15 +112,6 @@ namespace BizHawk
public void FrameAdvance(bool render)
{
Frame++;
if (resetSignal)
{
//cpu.PC = cpu.ReadWord(MOS6507.ResetVector);
m6532.resetOccured = true;
//m6532.swchb &= 0xFE;
//cpu.FlagI = true;
}
//cpu.Execute(228);
//cpu.Execute(2000);
tia.frameComplete = false;
while (tia.frameComplete == false)
@ -154,23 +132,8 @@ namespace BizHawk
}
}
resetSignal = Controller["Reset"];
//clear the framebuffer (hack code)
if (render == false) return;
/*
for (int i = 0; i < 160 * 192; i++)
{
if (i < 64*256)
frameBuffer[i] = i % 256; //black
if (i >= 64*256 && i < 128*256)
frameBuffer[i] = (i % 256) << 8; //black
if (i >= 128*256)
frameBuffer[i] = (i % 256) << 16; //black
}
*/
//run one frame's worth of cpu cyclees (i.e. do the emulation!)
//this should generate the framebuffer as it goes.
//if (render == false) return;
}
public byte ReadControls1()
@ -184,5 +147,38 @@ namespace BizHawk
if (Controller["P1 Button"]) value &= 0xF7;
return value;
}
public byte ReadControls2()
{
byte value = 0xFF;
if (Controller["P2 Up"]) value &= 0xEF;
if (Controller["P2 Down"]) value &= 0xDF;
if (Controller["P2 Left"]) value &= 0xBF;
if (Controller["P2 Right"]) value &= 0x7F;
if (Controller["P2 Button"]) value &= 0xF7;
return value;
}
public byte ReadConsoleSwitches()
{
byte value = 0xFF;
bool select = false;
bool reset = Controller["Reset"];
bool bw = false;
bool p0difficulty = true;
bool p1difficulty = true;
if (reset) value &= 0xFE;
if (select) value &= 0xFD;
if (bw) value &= 0xF7;
if (p0difficulty) value &= 0xBF;
if (p1difficulty) value &= 0x7F;
return value;
}
}
}

View File

@ -8,104 +8,118 @@ namespace BizHawk.Emulation.Consoles.Atari
// Emulates the M6532 RIOT Chip
public partial class M6532
{
MOS6507 Cpu;
public byte[] ram;
public int timerStartValue;
public int timerFinishedCycles;
public int timerShift;
bool interruptEnabled = false;
bool interruptTriggered = false;
Atari2600 core;
public byte swchb = 0x0B;
public int timerCyclesRemaining = 0;
public int timerShift = 0;
bool interruptEnabled = false;
bool interruptFlag = false;
public byte ddra = 0x00;
public byte ddrb = 0x00;
public bool resetOccured = false;
public int totalCycles = 0;
public M6532(MOS6507 cpu, byte[] ram, Atari2600 core)
public M6532(Atari2600 core)
{
Cpu = cpu;
this.ram = ram;
this.core = core;
// Apparently this will break for some games (Solaris and H.E.R.O.). We shall see
timerFinishedCycles = 0;
// Apparently starting the timer at 0 will break for some games (Solaris and H.E.R.O.). We shall see
timerCyclesRemaining = 0;
interruptEnabled = false;
interruptFlag = false;
}
public void tick()
{
totalCycles++;
timerCyclesRemaining--;
if (timerCyclesRemaining == 0 && interruptEnabled)
{
interruptFlag = true;
}
}
public byte ReadMemory(ushort addr)
{
ushort maskedAddr;
// Register Select (?)
bool RS = (addr & 0x0200) != 0;
if ((addr & 0x1080) == 0x0080 && (addr & 0x0200) == 0x0000)
if (!RS)
{
maskedAddr = (ushort)(addr & 0x007f);
Console.WriteLine("6532 ram read: " + maskedAddr.ToString("x"));
return ram[maskedAddr];
// Read Ram
ushort maskedAddr = (ushort)(addr & 0x007f);
return core.ram[maskedAddr];
}
else
{
maskedAddr = (ushort)(addr & 0x0007);
if (maskedAddr == 0x04 || maskedAddr == 0x06)
ushort registerAddr = (ushort)(addr & 0x0007);
if (registerAddr == 0x00)
{
Console.WriteLine("6532 timer read: " + maskedAddr.ToString("x"));
// Read Output reg A
// Combine readings from player 1 and player 2
byte temp = (byte)(core.ReadControls1() & 0xF0 | ((core.ReadControls2() >> 4) & 0x0F));
temp = (byte)(temp & ~ddra);
return temp;
}
else if (registerAddr == 0x01)
{
// Read DDRA
return ddra;
}
else if (registerAddr == 0x02)
{
// Read Output reg B
byte temp = core.ReadConsoleSwitches();
temp = (byte)(temp & ~ddrb);
return temp;
// Calculate the current value on the timer
int timerCurrentValue = timerFinishedCycles - totalCycles;
/*
// TODO: Rewrite this!
bool temp = resetOccured;
resetOccured = false;
return (byte)(0x0A | (temp ? 0x00 : 0x01));
* */
}
else if (registerAddr == 0x03)
{
// Read DDRB
return ddrb;
}
else if ((registerAddr & 0x5) == 0x4)
{
// Bit 0x0080 contains interrupt enable/disable
interruptEnabled = (addr & 0x0080) != 0;
interruptTriggered = false;
// If the timer has not finished, shift the value down for the game
if (totalCycles < timerFinishedCycles)
// The interrupt flag will be reset whenever the Timer is access by a read or a write
// However, the reading of the timer at the same time the interrupt occurs will not reset the interrupt flag
// (M6532 Datasheet)
if (timerCyclesRemaining != 0)
{
return (byte)(((timerCurrentValue) >> timerShift) & 0xFF);
interruptFlag = false;
}
// If there is still time on the timer (or its 0), return the lowest byte
if (timerCyclesRemaining >= 0)
{
return (byte)(((timerCyclesRemaining) >> timerShift) & 0xFF);
}
// Other wise, return the last 8 bits from how long ago it triggered
else
{
interruptTriggered = true;
return (byte)(timerCurrentValue & 0xFF);
return (byte)(timerCyclesRemaining & 0xFF);
}
}
else
else if ((registerAddr & 0x5) == 0x5)
{
Console.WriteLine("6532 register read: " + maskedAddr.ToString("x"));
if (maskedAddr == 0x00) // SWCHA
// Read interrupt flag
if (interruptEnabled && interruptFlag)
{
return core.ReadControls1();
//return 0xFF;
return 0x00;
}
else if (maskedAddr == 0x01) // SWACNT
else
{
}
else if (maskedAddr == 0x02) // SWCHB
{
bool temp = resetOccured;
resetOccured = false;
return (byte)(0x0A | (temp ? 0x00 : 0x01));
}
else if (maskedAddr == 0x03) // SWBCNT
{
}
else if (maskedAddr == 0x05) // interrupt
{
if ((timerFinishedCycles - totalCycles >= 0)|| (interruptEnabled && interruptTriggered))
{
return 0x00;
}
else
{
return 0x80;
}
return 0x80;
}
}
}
@ -115,39 +129,81 @@ namespace BizHawk.Emulation.Consoles.Atari
public void WriteMemory(ushort addr, byte value)
{
ushort maskedAddr;
// Register Select (?)
bool RS = (addr & 0x0200) != 0;
if ((addr & 0x1080) == 0x0080 && (addr & 0x0200) == 0x0000)
// If the RS bit is not set, this is a ram write
if (!RS)
{
maskedAddr = (ushort)(addr & 0x007f);
Console.WriteLine("6532 ram write: " + maskedAddr.ToString("x"));
ram[maskedAddr] = value;
ushort maskedAddr = (ushort)(addr & 0x007f);
core.ram[maskedAddr] = value;
}
else
{
maskedAddr = (ushort)(addr & 0x0007);
if ((addr & 0x14) == 0x14)
// If bit 0x0010 is set, and bit 0x0004 is set, this is a timer write
if ((addr & 0x0014) == 0x0014)
{
int[] shift = new int[] {0,3,6,10};
timerShift = shift[addr & 0x03];
ushort registerAddr = (ushort)(addr & 0x0007);
// Store the number of cycles for the timer
timerStartValue = value << timerShift;
// Bit 0x0080 contains interrupt enable/disable
interruptEnabled = (addr & 0x0080) != 0;
// Calculate when the timer will be finished
timerFinishedCycles = timerStartValue + totalCycles;
// The interrupt flag will be reset whenever the Timer is access by a read or a write
// (M6532 datasheet)
Console.WriteLine("6532 timer write: " + maskedAddr.ToString("x"));
interruptEnabled = ((addr & 0x08) != 0);
if (registerAddr == 0x04)
{
// Write to Timer/1
timerShift = 0;
timerCyclesRemaining = value << timerShift;
interruptFlag = false;
}
else if (registerAddr == 0x05)
{
// Write to Timer/8
timerShift = 3;
timerCyclesRemaining = value << timerShift;
interruptFlag = false;
}
else if (registerAddr == 0x06)
{
// Write to Timer/64
timerShift = 6;
timerCyclesRemaining = value << timerShift;
interruptFlag = false;
}
else if (registerAddr == 0x07)
{
// Write to Timer/1024
timerShift = 10;
timerCyclesRemaining = value << timerShift;
interruptFlag = false;
}
}
else if ((addr & 0x04) == 0 && (maskedAddr & 0x03) == 0x02)
// If bit 0x0004 is not set, bit 0x0010 is ignored and
// these are register writes
else if ((addr & 0x0004) == 0)
{
swchb = value;
}
else
{
Console.WriteLine("6532 register write: " + maskedAddr.ToString("x"));
ushort registerAddr = (ushort)(addr & 0x0007);
if (registerAddr == 0x00)
{
// Write Output reg A
}
else if (registerAddr == 0x01)
{
// Write DDRA
ddra = value;
}
else if (registerAddr == 0x02)
{
// Write Output reg B
}
else if (registerAddr == 0x03)
{
// Write DDRB
ddrb = value;
}
}
}
}

View File

@ -642,7 +642,6 @@ namespace BizHawk.Emulation.Consoles.Atari
public byte ReadMemory(ushort addr)
{
ushort maskedAddr = (ushort)(addr & 0x000F);
Console.WriteLine("TIA read: " + maskedAddr.ToString("x"));
if (maskedAddr == 0x00) // CXM0P
{
return (byte)((((player0.missile.collisions & CXP1) != 0) ? 0x80 : 0x00) | (((player0.missile.collisions & CXP0) != 0) ? 0x40 : 0x00));
@ -686,7 +685,6 @@ namespace BizHawk.Emulation.Consoles.Atari
public void WriteMemory(ushort addr, byte value)
{
ushort maskedAddr = (ushort)(addr & 0x3f);
Console.WriteLine("TIA write: " + maskedAddr.ToString("x"));
if (maskedAddr == 0x00) // VSYNC
{
@ -698,7 +696,6 @@ namespace BizHawk.Emulation.Consoles.Atari
else
{
// When VSYNC is disabled, this will be the first line of the new frame
Console.WriteLine("TIA VSYNC Off");
// write to frame buffer
outputFrame();