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 "CartF8SC.hxx"
20
21// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22CartridgeF8SC::CartridgeF8SC(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 CartridgeF8SC::reset()
34{
35 initializeRAM(myRAM.data(), myRAM.size());
36 initializeStartBank(1);
37
38 // Upon reset we switch to the startup bank
39 bank(startBank());
40}
41
42// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
43void CartridgeF8SC::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 CartridgeF8SC::peek(uInt16 address)
74{
75 uInt16 peekAddress = address;
76 address &= 0x0FFF;
77
78 // Switch banks if necessary
79 switch(address)
80 {
81 case 0x0FF8:
82 // Set the current bank to the lower 4k bank
83 bank(0);
84 break;
85
86 case 0x0FF9:
87 // Set the current bank to the upper 4k bank
88 bank(1);
89 break;
90
91 default:
92 break;
93 }
94
95 if(address < 0x0080) // Write port is at 0xF000 - 0xF07F (128 bytes)
96 return peekRAM(myRAM[address], peekAddress);
97 else
98 return myImage[myBankOffset + address];
99}
100
101// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
102bool CartridgeF8SC::poke(uInt16 address, uInt8 value)
103{
104 // Switch banks if necessary
105 switch(address & 0x0FFF)
106 {
107 case 0x0FF8:
108 // Set the current bank to the lower 4k bank
109 bank(0);
110 return false;
111
112 case 0x0FF9:
113 // Set the current bank to the upper 4k bank
114 bank(1);
115 return false;
116
117 default:
118 break;
119 }
120
121 if (!(address & 0x080))
122 {
123 pokeRAM(myRAM[address & 0x007F], address, value);
124 return true;
125 }
126 else
127 {
128 // Writing to the read port should be ignored, but trigger a break if option enabled
129 uInt8 dummy;
130
131 pokeRAM(dummy, address, value);
132 myRamWriteAccess = address;
133 return false;
134 }
135}
136
137// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
138bool CartridgeF8SC::bank(uInt16 bank)
139{
140 if(bankLocked()) return false;
141
142 // Remember what bank we're in
143 myBankOffset = bank << 12;
144
145 System::PageAccess access(this, System::PageAccessType::READ);
146
147 // Set the page accessing methods for the hot spots
148 for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
149 addr += System::PAGE_SIZE)
150 {
151 access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
152 mySystem->setPageAccess(addr, access);
153 }
154
155 // Setup the page access methods for the current bank
156 for(uInt16 addr = 0x1100; addr < (0x1FF8U & ~System::PAGE_MASK);
157 addr += System::PAGE_SIZE)
158 {
159 access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
160 access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
161 mySystem->setPageAccess(addr, access);
162 }
163 return myBankChanged = true;
164}
165
166// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
167uInt16 CartridgeF8SC::getBank(uInt16) const
168{
169 return myBankOffset >> 12;
170}
171
172// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
173uInt16 CartridgeF8SC::bankCount() const
174{
175 return 2;
176}
177
178// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
179bool CartridgeF8SC::patch(uInt16 address, uInt8 value)
180{
181 address &= 0x0FFF;
182
183 if(address < 0x0100)
184 {
185 // Normally, a write to the read port won't do anything
186 // However, the patch command is special in that ignores such
187 // cart restrictions
188 myRAM[address & 0x007F] = value;
189 }
190 else
191 myImage[myBankOffset + address] = value;
192
193 return myBankChanged = true;
194}
195
196// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
197const uInt8* CartridgeF8SC::getImage(size_t& size) const
198{
199 size = myImage.size();
200 return myImage.data();
201}
202
203// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
204bool CartridgeF8SC::save(Serializer& out) const
205{
206 try
207 {
208 out.putShort(myBankOffset);
209 out.putByteArray(myRAM.data(), myRAM.size());
210 }
211 catch(...)
212 {
213 cerr << "ERROR: CartridgeF8SC::save" << endl;
214 return false;
215 }
216
217 return true;
218}
219
220// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
221bool CartridgeF8SC::load(Serializer& in)
222{
223 try
224 {
225 myBankOffset = in.getShort();
226 in.getByteArray(myRAM.data(), myRAM.size());
227 }
228 catch(...)
229 {
230 cerr << "ERROR: CartridgeF8SC::load" << endl;
231 return false;
232 }
233
234 // Remember what bank we were in
235 bank(myBankOffset >> 12);
236
237 return true;
238}
239