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 "System.hxx"
19#include "CartUA.hxx"
20
21// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22CartridgeUA::CartridgeUA(const ByteBuffer& image, size_t size,
23 const string& md5, const Settings& settings,
24 bool swapHotspots)
25 : Cartridge(settings, md5),
26 myBankOffset(0),
27 mySwappedHotspots(swapHotspots)
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 CartridgeUA::reset()
36{
37 // Upon reset we switch to the startup bank
38 initializeStartBank(0);
39 bank(startBank());
40}
41
42// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
43void CartridgeUA::install(System& system)
44{
45 mySystem = &system;
46
47 // Get the page accessing methods for the hot spots since they overlap
48 // areas within the TIA we'll need to forward requests to the TIA
49 myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0220);
50 myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0220 | 0x80);
51
52 // Set the page accessing methods for the hot spots
53 System::PageAccess access(this, System::PageAccessType::READ);
54 mySystem->setPageAccess(0x0220, access);
55 mySystem->setPageAccess(0x0240, access);
56 mySystem->setPageAccess(0x0220 | 0x80, access);
57 mySystem->setPageAccess(0x0240 | 0x80, access);
58
59 // Install pages for the startup bank
60 bank(startBank());
61}
62
63// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
64uInt8 CartridgeUA::peek(uInt16 address)
65{
66 address &= 0x1FFF;
67
68 // Switch banks if necessary
69 switch(address & 0x1260)
70 {
71 case 0x0220:
72 // Set the current bank to the lower 4k bank
73 bank(mySwappedHotspots ? 1 : 0);
74 break;
75
76 case 0x0240:
77 // Set the current bank to the upper 4k bank
78 bank(mySwappedHotspots ? 0 : 1);
79 break;
80
81 default:
82 break;
83 }
84
85 // Because of the way accessing is set up, we will only get here
86 // when doing a TIA read
87 int hotspot = ((address & 0x80) >> 7);
88 return myHotSpotPageAccess[hotspot].device->peek(address);
89}
90
91// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
92bool CartridgeUA::poke(uInt16 address, uInt8 value)
93{
94 address &= 0x1FFF;
95
96 // Switch banks if necessary
97 switch(address & 0x1260)
98 {
99 case 0x0220:
100 // Set the current bank to the lower 4k bank
101 bank(mySwappedHotspots ? 1 : 0);
102 break;
103
104 case 0x0240:
105 // Set the current bank to the upper 4k bank
106 bank(mySwappedHotspots ? 0 : 1);
107 break;
108
109 default:
110 break;
111 }
112
113 // Because of the way accessing is set up, we will may get here by
114 // doing a write to TIA or cart; we ignore the cart write
115 if (!(address & 0x1000))
116 {
117 int hotspot = ((address & 0x80) >> 7);
118 myHotSpotPageAccess[hotspot].device->poke(address, value);
119 }
120
121 return false;
122}
123
124// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
125bool CartridgeUA::bank(uInt16 bank)
126{
127 if(bankLocked()) return false;
128
129 // Remember what bank we're in
130 myBankOffset = bank << 12;
131
132 // Setup the page access methods for the current bank
133 System::PageAccess access(this, System::PageAccessType::READ);
134
135 // Map ROM image into the system
136 for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE)
137 {
138 access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
139 access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
140 mySystem->setPageAccess(addr, access);
141 }
142 return myBankChanged = true;
143}
144
145// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
146uInt16 CartridgeUA::getBank(uInt16) const
147{
148 return myBankOffset >> 12;
149}
150
151// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
152uInt16 CartridgeUA::bankCount() const
153{
154 return 2;
155}
156
157// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
158bool CartridgeUA::patch(uInt16 address, uInt8 value)
159{
160 myImage[myBankOffset + (address & 0x0FFF)] = value;
161 return myBankChanged = true;
162}
163
164// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
165const uInt8* CartridgeUA::getImage(size_t& size) const
166{
167 size = myImage.size();
168 return myImage.data();
169}
170
171// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
172bool CartridgeUA::save(Serializer& out) const
173{
174 try
175 {
176 out.putShort(myBankOffset);
177 }
178 catch(...)
179 {
180 cerr << "ERROR: " << name() << "::save" << endl;
181 return false;
182 }
183
184 return true;
185}
186
187// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
188bool CartridgeUA::load(Serializer& in)
189{
190 try
191 {
192 myBankOffset = in.getShort();
193 }
194 catch(...)
195 {
196 cerr << "ERROR: " << name() << "::load" << endl;
197 return false;
198 }
199
200 // Remember what bank we were in
201 bank(myBankOffset >> 12);
202
203 return true;
204}
205