Atari 2600 - start Supercharger emulation (and mapper AR)
This commit is contained in:
parent
f04210c5c9
commit
d1e7ed9d91
|
@ -17,8 +17,17 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
public MOS6502X Cpu { get; private set; }
|
||||
public M6532 M6532 { get; private set; }
|
||||
|
||||
public int LastAddress;
|
||||
public int NumberOfDistinctAddresses;
|
||||
|
||||
public byte BaseReadMemory(ushort addr)
|
||||
{
|
||||
if (addr != LastAddress)
|
||||
{
|
||||
NumberOfDistinctAddresses++;
|
||||
LastAddress = addr;
|
||||
}
|
||||
|
||||
addr = (ushort)(addr & 0x1FFF);
|
||||
if ((addr & 0x1080) == 0)
|
||||
{
|
||||
|
@ -51,6 +60,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
|
||||
public void BaseWriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if (addr != LastAddress)
|
||||
{
|
||||
NumberOfDistinctAddresses++;
|
||||
LastAddress = addr;
|
||||
}
|
||||
|
||||
addr = (ushort)(addr & 0x1FFF);
|
||||
if ((addr & 0x1080) == 0)
|
||||
{
|
||||
|
@ -129,7 +144,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
_mapper = SetMultiCartMapper(Rom.Length, 32);
|
||||
break;
|
||||
case "AR":
|
||||
_mapper = new mAR();
|
||||
_mapper = new mAR(this); // This mapper has to set up configurations in the contructor.
|
||||
break;
|
||||
case "4K":
|
||||
_mapper = new m4K();
|
||||
|
|
|
@ -31,17 +31,34 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
{
|
||||
internal class mAR : MapperBase
|
||||
{
|
||||
public mAR()
|
||||
// TODO: can we set the defaults instead of do it in the constructor?
|
||||
// TODO: fastscbios setting
|
||||
// TODO: var names, savestates, hard reset, dispose, cart ram
|
||||
public mAR(Atari2600 core)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
Core = core;
|
||||
InitializeRom();
|
||||
BankConfiguration(0);
|
||||
}
|
||||
|
||||
private int _bank2k;
|
||||
private ByteBuffer _ram = new ByteBuffer(6144);
|
||||
private IntBuffer _offsets = new IntBuffer(2);
|
||||
//private ByteBuffer _ram = new ByteBuffer(6144);
|
||||
ByteBuffer myImage = new ByteBuffer(8192);
|
||||
private IntBuffer _imageOffsets = new IntBuffer(2);
|
||||
private bool _writePending = false;
|
||||
int myNumberOfDistinctAccesses = 0;
|
||||
bool myWriteEnabled = false;
|
||||
byte myDataHoldRegister;
|
||||
|
||||
private readonly byte[] _RomCode = {
|
||||
// Indicates if the ROM's power is on or off
|
||||
private bool myPower;
|
||||
|
||||
// Indicates when the power was last turned on
|
||||
int myPowerRomCycle;
|
||||
|
||||
private ulong _elapsedCycles;
|
||||
|
||||
private readonly byte[] DummyRomCode = {
|
||||
0xa5, 0xfa, 0x85, 0x80, 0x4c, 0x18, 0xf8, 0xff,
|
||||
0xff, 0xff, 0x78, 0xd8, 0xa0, 0x00, 0xa2, 0x00,
|
||||
0x94, 0x00, 0xe8, 0xd0, 0xfb, 0x4c, 0x50, 0xf8,
|
||||
|
@ -81,7 +98,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
0xfa, 0x00, 0xcd, 0xf8, 0xff, 0x4c
|
||||
};
|
||||
|
||||
private readonly byte[] RomHeader = {
|
||||
private readonly byte[] DefaultHeader = {
|
||||
0xac, 0xfa, 0x0f, 0x18, 0x62, 0x00, 0x24, 0x02,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
|
||||
|
@ -116,34 +133,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
|
||||
};
|
||||
|
||||
public override bool HasCartRam
|
||||
public override void ClockCpu()
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override ByteBuffer CartRam
|
||||
{
|
||||
get { return _ram; }
|
||||
}
|
||||
|
||||
public override void SyncState(Serializer ser)
|
||||
{
|
||||
base.SyncState(ser);
|
||||
ser.Sync("bank4k", ref _bank2k);
|
||||
ser.Sync("ram", ref _ram);
|
||||
}
|
||||
|
||||
public override void HardReset()
|
||||
{
|
||||
_bank2k = 0;
|
||||
_ram = new ByteBuffer(6144);
|
||||
base.HardReset();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
_ram.Dispose();
|
||||
_elapsedCycles++;
|
||||
|
||||
}
|
||||
|
||||
private byte ReadMem(ushort addr, bool peek)
|
||||
|
@ -158,22 +151,57 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
return base.ReadMemory(addr);
|
||||
}
|
||||
|
||||
if (addr == 0x1850 && _offsets[1] == (3 << 11))
|
||||
if (addr == 0x1850 && _imageOffsets[1] == (3 << 11))
|
||||
{
|
||||
/// TODO: weird stuff goes here
|
||||
///
|
||||
return Core.Rom[(addr & 0x7FF) + _offsets[1]];
|
||||
return myImage[(addr & 0x7FF) + _imageOffsets[1]];
|
||||
}
|
||||
|
||||
// TODO: cancel pending writes
|
||||
if (addr == 0x1FF8)
|
||||
|
||||
// Cancel any pending write if more than 5 distinct accesses have occurred
|
||||
// TODO: Modify to handle when the distinct counter wraps around...
|
||||
if (_writePending &&
|
||||
(Core.NumberOfDistinctAddresses > myNumberOfDistinctAccesses + 5))
|
||||
{
|
||||
_writePending = false;
|
||||
}
|
||||
|
||||
if (!((addr & 0x0F00) > 0) && (!myWriteEnabled || !_writePending))
|
||||
{
|
||||
myDataHoldRegister = (byte)addr;
|
||||
myNumberOfDistinctAccesses = Core.NumberOfDistinctAddresses;
|
||||
_writePending = true;
|
||||
|
||||
}
|
||||
|
||||
// Is the bank configuration hotspot being accessed?
|
||||
else if (addr == 0x1FF8)
|
||||
{
|
||||
// Yes, so handle the bank configuration
|
||||
_writePending = false;
|
||||
BankConfiguration(myDataHoldRegister);
|
||||
|
||||
return Core.Rom[(_bank2k << 12) + (addr & 0xFFF)];
|
||||
}
|
||||
|
||||
else if (myWriteEnabled &&
|
||||
_writePending &&
|
||||
Core.NumberOfDistinctAddresses == (myNumberOfDistinctAccesses + 5))
|
||||
{
|
||||
if ((addr & 0x800) == 0)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
else if (_imageOffsets[1] != (3 << 11)) // Don't poke Rom
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
_writePending = false;
|
||||
}
|
||||
|
||||
var tempVal = (addr & 0x07FF) + _imageOffsets[((addr & 0x800) > 0) ? 1 : 0];
|
||||
return myImage[(addr & 0x07FF) + _imageOffsets[((addr & 0x800) > 0) ? 1 : 0]];
|
||||
}
|
||||
|
||||
public override byte ReadMemory(ushort addr)
|
||||
|
@ -197,5 +225,105 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
|
|||
_bank2k = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeRom()
|
||||
{
|
||||
/* scrom.asm data borrowed from Stella:
|
||||
// Note that the following offsets depend on the 'scrom.asm' file
|
||||
// in src/emucore/misc. If that file is ever recompiled (and its
|
||||
// contents placed in the ourDummyROMCode array), the offsets will
|
||||
// almost definitely change
|
||||
*/
|
||||
|
||||
// The scrom.asm code checks a value at offset 109 as follows:
|
||||
// 0xFF -> do a complete jump over the SC BIOS progress bars code
|
||||
// 0x00 -> show SC BIOS progress bars as normal
|
||||
DummyRomCode[109] = 0x00; // TODO: fastscbios setting
|
||||
|
||||
// Stella does this, but randomness is bad for determinacy! Hopefully we don't really need it
|
||||
//ourDummyROMCode[281] = mySystem->randGenerator().next();
|
||||
|
||||
// Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam
|
||||
for (int i = 0; i < 2048; i++)
|
||||
{
|
||||
myImage[(3 << 11) + i] = 0x02;
|
||||
}
|
||||
|
||||
// Copy the "dummy" Supercharger BIOS code into the ROM area
|
||||
for (int i = 0; i < DummyRomCode.Length; i++)
|
||||
{
|
||||
myImage[(3 << 11) + i] = DummyRomCode[i];
|
||||
}
|
||||
|
||||
// Finally set 6502 vectors to point to initial load code at 0xF80A of BIOS
|
||||
myImage[(3 << 11) + 2044] = 0x0A;
|
||||
myImage[(3 << 11) + 2045] = 0xF8;
|
||||
myImage[(3 << 11) + 2046] = 0x0A;
|
||||
myImage[(3 << 11) + 2047] = 0xF8;
|
||||
}
|
||||
|
||||
private void BankConfiguration(byte configuration)
|
||||
{
|
||||
// D7-D5 of this byte: Write Pulse Delay (n/a for emulator)
|
||||
//
|
||||
// D4-D0: RAM/ROM configuration:
|
||||
// $F000-F7FF $F800-FFFF Address range that banks map into
|
||||
// 000wp 2 ROM
|
||||
// 001wp 0 ROM
|
||||
// 010wp 2 0 as used in Commie Mutants and many others
|
||||
// 011wp 0 2 as used in Suicide Mission
|
||||
// 100wp 2 ROM
|
||||
// 101wp 1 ROM
|
||||
// 110wp 2 1 as used in Killer Satellites
|
||||
// 111wp 1 2 as we use for 2k/4k ROM cloning
|
||||
//
|
||||
// w = Write Enable (1 = enabled; accesses to $F000-$F0FF cause writes
|
||||
// to happen. 0 = disabled, and the cart acts like ROM.)
|
||||
// p = ROM Power (0 = enabled, 1 = off.) Only power the ROM if you're
|
||||
// wanting to access the ROM for multiloads. Otherwise set to 1.
|
||||
|
||||
_bank2k = configuration & 0x1F; // remember for the bank() method
|
||||
myPower = !((configuration & 0x01) > 0);
|
||||
if (myPower)
|
||||
{
|
||||
myPowerRomCycle = (int)_elapsedCycles;
|
||||
}
|
||||
|
||||
switch ((configuration >> 2) & 0x07)
|
||||
{
|
||||
case 0x00:
|
||||
_imageOffsets[0] = 2 << 11;
|
||||
_imageOffsets[1] = 3 << 11;
|
||||
break;
|
||||
case 0x01:
|
||||
_imageOffsets[0] = 0;
|
||||
_imageOffsets[1] = 3 << 11;
|
||||
break;
|
||||
case 0x02:
|
||||
_imageOffsets[0] = 2 << 11;
|
||||
_imageOffsets[1] = 0;
|
||||
break;
|
||||
case 0x03:
|
||||
_imageOffsets[0] = 0;
|
||||
_imageOffsets[1] = 2 << 11;
|
||||
break;
|
||||
case 0x04:
|
||||
_imageOffsets[0] = 2 << 11;
|
||||
_imageOffsets[1] = 3 << 11;
|
||||
break;
|
||||
case 0x05:
|
||||
_imageOffsets[0] = 1 << 11;
|
||||
_imageOffsets[1] = 3 << 11;
|
||||
break;
|
||||
case 0x06:
|
||||
_imageOffsets[0] = 2 << 11;
|
||||
_imageOffsets[1] = 1 << 11;
|
||||
break;
|
||||
case 0x07:
|
||||
_imageOffsets[0] = 1 << 11;
|
||||
_imageOffsets[1] = 2 << 11;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
;;============================================================================
|
||||
;;
|
||||
;; SSSS tt lll lll
|
||||
;; SS SS tt ll ll
|
||||
;; SS tttttt eeee ll ll aaaa
|
||||
;; SSSS tt ee ee ll ll aa
|
||||
;; SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
;; SS SS tt ee ll ll aa aa
|
||||
;; SSSS ttt eeeee llll llll aaaaa
|
||||
;;
|
||||
;; Copyright (c) 1995-2012 by Bradford W. Mott, Stephen Anthony
|
||||
;; and the Stella Team
|
||||
;;
|
||||
;; See the file "License.txt" for information on usage and redistribution of
|
||||
;; this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
;;
|
||||
;; $Id: scrom.asm,v 1.3 2005-06-16 01:11:29 stephena Exp $
|
||||
;;============================================================================
|
||||
;;
|
||||
;; This file contains a "dummy" Supercharger BIOS for Stella. It is based
|
||||
;; on routines developed by Eckhard Stolberg.
|
||||
;;
|
||||
;;============================================================================
|
||||
|
||||
processor 6502
|
||||
|
||||
VSYNC equ $00
|
||||
VBLANK equ $01
|
||||
WSYNC equ $02
|
||||
COLUPF equ $08
|
||||
COLUBK equ $09
|
||||
CTRLPF equ $0a
|
||||
PF0 equ $0d
|
||||
PF1 equ $0e
|
||||
PF2 equ $0f
|
||||
RESP0 equ $10
|
||||
RESP1 equ $11
|
||||
AUDC0 equ $15
|
||||
AUDF0 equ $17
|
||||
AUDV0 equ $19
|
||||
AUDV1 equ $1a
|
||||
GRP0 equ $1b
|
||||
GRP1 equ $1c
|
||||
ENAM0 equ $1d
|
||||
ENAM1 equ $1e
|
||||
ENABL equ $1f
|
||||
HMP0 equ $20
|
||||
HMP1 equ $21
|
||||
HMOVE equ $2a
|
||||
|
||||
;;
|
||||
;; Entry point for multi-load reading
|
||||
;;
|
||||
org $F800
|
||||
|
||||
LDA $FA ; Grab the load number and store it in $80 where the
|
||||
STA $80 ; emulator will grab it when it does the loading
|
||||
JMP clrp7 ; Go clear page 7 of RAM bank 1 like the real SC
|
||||
|
||||
;;
|
||||
;; Entry point for initial load (invoked when the system is reset)
|
||||
;;
|
||||
org $F80A
|
||||
|
||||
start SEI
|
||||
CLD
|
||||
|
||||
;;
|
||||
;; Clear page zero routine for initial load (e.g., RAM and TIA registers)
|
||||
;;
|
||||
LDY #$00
|
||||
LDX #$00
|
||||
ilclr STY $00,X
|
||||
INX
|
||||
BNE ilclr
|
||||
|
||||
JMP load
|
||||
|
||||
;;
|
||||
;; Clear page 7 of RAM bank 1 (used for stars in the real SC)
|
||||
;;
|
||||
clrp7 LDX #$00
|
||||
LDA $F006,X
|
||||
LDA $FFF8
|
||||
LDX #$00
|
||||
mlclr3 LDA $F000
|
||||
NOP
|
||||
LDA $F700,X
|
||||
DEX
|
||||
BNE mlclr3
|
||||
JMP load
|
||||
|
||||
;;
|
||||
;; NOTE: The emulator does the actual reading of the new load when the
|
||||
;; next instruction is accessed. The emulator expects the load number to
|
||||
;; to be stored in location $80. As a side-effect the emulator sets $80
|
||||
;; to contain the bank selection byte from the load's header and sets
|
||||
;; $FE and $FF to contain the starting address from the load's header.
|
||||
;;
|
||||
load org $F850
|
||||
|
||||
;;
|
||||
;; Copy code into page zero to do the bank switching
|
||||
;;
|
||||
LDX #$03
|
||||
copy LDY code,X
|
||||
STY $FA,X
|
||||
DEX
|
||||
BPL copy
|
||||
|
||||
;;
|
||||
;; Clear some of the 2600's RAM and TIA registers like the real SC BIOS does
|
||||
;;
|
||||
LDY #$00
|
||||
LDX #$28
|
||||
mlclr1 STY $04,X
|
||||
DEX
|
||||
BPL mlclr1
|
||||
|
||||
LDX #$1C
|
||||
mlclr2 STY $81,X
|
||||
DEX
|
||||
BPL mlclr2
|
||||
|
||||
;;
|
||||
;; Display the "emulated" Supercharger loading progress bar
|
||||
;;
|
||||
;; Check if we should skip the loading progress bar
|
||||
;; Note that the following code seems to never do a jump
|
||||
;; However, the comparison value can be patched outside this code
|
||||
;;
|
||||
LDA #$FF
|
||||
CMP #$00 ; patch this value to $FF outside ROM to do a jump
|
||||
BNE startbars
|
||||
JMP skipbars
|
||||
|
||||
;; Otherwise we display them
|
||||
startbars:
|
||||
LDA #$00
|
||||
STA GRP0
|
||||
STA GRP1
|
||||
STA ENAM0
|
||||
STA ENAM1
|
||||
STA ENABL
|
||||
STA AUDV0
|
||||
STA AUDV1
|
||||
STA COLUPF
|
||||
STA VBLANK
|
||||
|
||||
LDA #$10
|
||||
STA HMP1
|
||||
STA WSYNC
|
||||
LDX #$07
|
||||
DEX
|
||||
pos DEX
|
||||
BNE pos
|
||||
LDA #$00
|
||||
STA HMP0
|
||||
STA RESP0
|
||||
STA RESP1
|
||||
STA WSYNC
|
||||
STA HMOVE
|
||||
|
||||
LDA #%00000101
|
||||
STA CTRLPF
|
||||
LDA #$FF
|
||||
STA PF0
|
||||
STA PF1
|
||||
STA PF2
|
||||
STA $84
|
||||
STA $85
|
||||
LDA #$F0
|
||||
STA $83
|
||||
LDA #$74
|
||||
STA COLUBK
|
||||
LDA #$0C
|
||||
STA AUDC0
|
||||
LDA #$1F
|
||||
STA AUDF0
|
||||
STA $82
|
||||
LDA #$07
|
||||
STA AUDV0
|
||||
a1
|
||||
LDX #$08
|
||||
LDY #$00
|
||||
a2
|
||||
STA WSYNC
|
||||
DEY
|
||||
BNE a2
|
||||
STA WSYNC
|
||||
STA WSYNC
|
||||
LDA #$02
|
||||
STA WSYNC
|
||||
STA VSYNC
|
||||
STA WSYNC
|
||||
STA WSYNC
|
||||
STA WSYNC
|
||||
LDA #$00
|
||||
STA VSYNC
|
||||
DEX
|
||||
BPL a2
|
||||
ASL $83
|
||||
ROR $84
|
||||
ROL $85
|
||||
LDA $83
|
||||
STA PF0
|
||||
LDA $84
|
||||
STA PF1
|
||||
LDA $85
|
||||
STA PF2
|
||||
LDX $82
|
||||
DEX
|
||||
STX $82
|
||||
STX AUDF0
|
||||
CPX #$0A
|
||||
BNE a1
|
||||
|
||||
LDA #%00000010
|
||||
STA VBLANK
|
||||
|
||||
LDX #$1C
|
||||
LDY #$00
|
||||
STY AUDV0
|
||||
STY COLUBK
|
||||
clear:
|
||||
STY $81,x
|
||||
DEX
|
||||
BPL clear
|
||||
skipbars:
|
||||
|
||||
;;
|
||||
;; Setup value to be stored in the bank switching control register
|
||||
;;
|
||||
LDX $80
|
||||
CMP $F000,X
|
||||
|
||||
;;
|
||||
;; Initialize A, X, Y, and SP registers
|
||||
;;
|
||||
LDA #$9a ;; This is patched outside the ROM to a random value
|
||||
LDX #$FF
|
||||
LDY #$00
|
||||
TXS
|
||||
|
||||
;;
|
||||
;; Execute the code to do bank switch and start running cartridge code
|
||||
;;
|
||||
JMP $FA
|
||||
|
||||
code dc.b $cd, $f8, $ff ;; CMP $fff8
|
||||
dc.b $4c ;; JMP $????
|
||||
|
Loading…
Reference in New Issue