1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#include "M6532.hxx"
19#include "System.hxx"
20#include "CartFE.hxx"
21
22// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
23CartridgeFE::CartridgeFE(const ByteBuffer& image, size_t size,
24 const string& md5, const Settings& settings)
25 : Cartridge(settings, md5),
26 myBankOffset(0),
27 myLastAccessWasFE(false)
28{
29 // Copy the ROM image into my buffer
30 std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
31 createCodeAccessBase(myImage.size());
32}
33
34// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35void CartridgeFE::reset()
36{
37 // Decathlon requires this, since there is no startup vector in bank 1
38 initializeStartBank(0);
39
40 bank(startBank());
41 myLastAccessWasFE = false;
42}
43
44// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
45void CartridgeFE::install(System& system)
46{
47 mySystem = &system;
48
49 // The hotspot $01FE is in a mirror of zero-page RAM
50 // We need to claim access to it here, and deal with it in peek/poke below
51 System::PageAccess access(this, System::PageAccessType::READWRITE);
52 for(uInt16 addr = 0x180; addr < 0x200; addr += System::PAGE_SIZE)
53 mySystem->setPageAccess(addr, access);
54
55 // Map all of the cart accesses to call peek and poke
56 access.type = System::PageAccessType::READ;
57 for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
58 mySystem->setPageAccess(addr, access);
59}
60
61// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62uInt8 CartridgeFE::peek(uInt16 address)
63{
64 uInt8 value = (address < 0x200) ? mySystem->m6532().peek(address) :
65 myImage[myBankOffset + (address & 0x0FFF)];
66
67 // Check if we hit hotspot
68 checkBankSwitch(address, value);
69
70 return value;
71}
72
73// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
74bool CartridgeFE::poke(uInt16 address, uInt8 value)
75{
76 if(address < 0x200)
77 mySystem->m6532().poke(address, value);
78
79 // Check if we hit hotspot
80 checkBankSwitch(address, value);
81
82 return false;
83}
84
85// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
86void CartridgeFE::checkBankSwitch(uInt16 address, uInt8 value)
87{
88 if(bankLocked())
89 return;
90
91 // Did we detect $01FE on the last address bus access?
92 // If so, we bankswitch according to the upper 3 bits of the data bus
93 // NOTE: see the header file for the significance of 'value & 0x20'
94 if(myLastAccessWasFE)
95 bank((value & 0x20) ? 0 : 1);
96
97 // On the next cycle, we use the (then) current data bus value to decode
98 // the bank to use
99 myLastAccessWasFE = address == 0x01FE;
100}
101
102// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
103bool CartridgeFE::bank(uInt16 bank)
104{
105 if(bankLocked())
106 return false;
107
108 myBankOffset = bank << 12;
109 return myBankChanged = true;
110}
111
112// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
113uInt16 CartridgeFE::getBank(uInt16) const
114{
115 return myBankOffset >> 12;
116}
117
118// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
119uInt16 CartridgeFE::bankCount() const
120{
121 return 2;
122}
123
124// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
125bool CartridgeFE::patch(uInt16 address, uInt8 value)
126{
127 myImage[myBankOffset + (address & 0x0FFF)] = value;
128 return myBankChanged = true;
129}
130
131// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
132const uInt8* CartridgeFE::getImage(size_t& size) const
133{
134 size = myImage.size();
135 return myImage.data();
136}
137
138// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
139bool CartridgeFE::save(Serializer& out) const
140{
141 try
142 {
143 out.putShort(myBankOffset);
144 out.putBool(myLastAccessWasFE);
145 }
146 catch(...)
147 {
148 cerr << "ERROR: CartridgeFE::save" << endl;
149 return false;
150 }
151
152 return true;
153}
154
155// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
156bool CartridgeFE::load(Serializer& in)
157{
158 try
159 {
160 myBankOffset = in.getShort();
161 myLastAccessWasFE = in.getBool();
162 }
163 catch(...)
164 {
165 cerr << "ERROR: CartridgeF8SC::load" << endl;
166 return false;
167 }
168
169 return true;
170}
171