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 "CartF6SC.hxx"
20
21// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22CartridgeF6SC::CartridgeF6SC(const ByteBuffer& image, size_t size,
23 const string& md5, const Settings& settings)
24 : Cartridge(settings, md5),
25 myBankOffset(0)
26{
27 // Copy the ROM image into my buffer
28 std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
29 createCodeAccessBase(myImage.size());
30}
31
32// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33void CartridgeF6SC::reset()
34{
35 initializeRAM(myRAM.data(), myRAM.size());
36 initializeStartBank(0);
37
38 // Upon reset we switch to the startup bank
39 bank(startBank());
40}
41
42// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
43void CartridgeF6SC::install(System& system)
44{
45 mySystem = &system;
46
47 System::PageAccess access(this, System::PageAccessType::READ);
48
49 // Set the page accessing method for the RAM writing pages
50 // Map access to this class, since we need to inspect all accesses to
51 // check if RWP happens
52 access.type = System::PageAccessType::WRITE;
53 for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE)
54 {
55 access.codeAccessBase = &myCodeAccessBase[addr & 0x007F];
56 mySystem->setPageAccess(addr, access);
57 }
58
59 // Set the page accessing method for the RAM reading pages
60 access.type = System::PageAccessType::READ;
61 for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE)
62 {
63 access.directPeekBase = &myRAM[addr & 0x007F];
64 access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)];
65 mySystem->setPageAccess(addr, access);
66 }
67
68 // Install pages for the startup bank
69 bank(startBank());
70}
71
72// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
73uInt8 CartridgeF6SC::peek(uInt16 address)
74{
75 uInt16 peekAddress = address;
76 address &= 0x0FFF;
77
78 // Switch banks if necessary
79 switch(address)
80 {
81 case 0x0FF6:
82 // Set the current bank to the first 4k bank
83 bank(0);
84 break;
85
86 case 0x0FF7:
87 // Set the current bank to the second 4k bank
88 bank(1);
89 break;
90
91 case 0x0FF8:
92 // Set the current bank to the third 4k bank
93 bank(2);
94 break;
95
96 case 0x0FF9:
97 // Set the current bank to the forth 4k bank
98 bank(3);
99 break;
100
101 default:
102 break;
103 }
104
105 if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes)
106 return peekRAM(myRAM[address], peekAddress);
107 else
108 return myImage[myBankOffset + address];
109}
110
111// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
112bool CartridgeF6SC::poke(uInt16 address, uInt8 value)
113{
114 // Switch banks if necessary
115 switch(address & 0x0FFF)
116 {
117 case 0x0FF6:
118 // Set the current bank to the first 4k bank
119 bank(0);
120 return false;
121
122 case 0x0FF7:
123 // Set the current bank to the second 4k bank
124 bank(1);
125 return false;
126
127 case 0x0FF8:
128 // Set the current bank to the third 4k bank
129 bank(2);
130 return false;
131
132 case 0x0FF9:
133 // Set the current bank to the forth 4k bank
134 bank(3);
135 return false;
136
137 default:
138 break;
139 }
140
141 if(!(address & 0x080))
142 {
143 pokeRAM(myRAM[address & 0x007F], address, value);
144 return true;
145 }
146 else
147 {
148 // Writing to the read port should be ignored, but trigger a break if option enabled
149 uInt8 dummy;
150
151 pokeRAM(dummy, address, value);
152 myRamWriteAccess = address;
153 return false;
154 }
155}
156
157// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
158bool CartridgeF6SC::bank(uInt16 bank)
159{
160 if(bankLocked()) return false;
161
162 // Remember what bank we're in
163 myBankOffset = bank << 12;
164
165 System::PageAccess access(this, System::PageAccessType::READ);
166
167 // Set the page accessing methods for the hot spots
168 for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000;
169 addr += System::PAGE_SIZE)
170 {
171 access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
172 mySystem->setPageAccess(addr, access);
173 }
174
175 // Setup the page access methods for the current bank
176 for(uInt16 addr = 0x1100; addr < (0x1FF6U & ~System::PAGE_MASK);
177 addr += System::PAGE_SIZE)
178 {
179 access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
180 access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
181 mySystem->setPageAccess(addr, access);
182 }
183 return myBankChanged = true;
184}
185
186// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
187uInt16 CartridgeF6SC::getBank(uInt16) const
188{
189 return myBankOffset >> 12;
190}
191
192// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
193uInt16 CartridgeF6SC::bankCount() const
194{
195 return 4;
196}
197
198// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
199bool CartridgeF6SC::patch(uInt16 address, uInt8 value)
200{
201 address &= 0x0FFF;
202
203 if(address < 0x0100)
204 {
205 // Normally, a write to the read port won't do anything
206 // However, the patch command is special in that ignores such
207 // cart restrictions
208 myRAM[address & 0x007F] = value;
209 }
210 else
211 myImage[myBankOffset + address] = value;
212
213 return myBankChanged = true;
214}
215
216// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
217const uInt8* CartridgeF6SC::getImage(size_t& size) const
218{
219 size = myImage.size();
220 return myImage.data();
221}
222
223// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
224bool CartridgeF6SC::save(Serializer& out) const
225{
226 try
227 {
228 out.putShort(myBankOffset);
229 out.putByteArray(myRAM.data(), myRAM.size());
230 }
231 catch(...)
232 {
233 cerr << "ERROR: CartridgeF6SC::save" << endl;
234 return false;
235 }
236
237 return true;
238}
239
240// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
241bool CartridgeF6SC::load(Serializer& in)
242{
243 try
244 {
245 myBankOffset = in.getShort();
246 in.getByteArray(myRAM.data(), myRAM.size());
247 }
248 catch(...)
249 {
250 cerr << "ERROR: CartridgeF6SC::load" << endl;
251 return false;
252 }
253
254 // Remember what bank we were in
255 bank(myBankOffset >> 12);
256
257 return true;
258}
259