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 "CartE0.hxx"
20
21// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22CartridgeE0::CartridgeE0(const ByteBuffer& image, size_t size,
23 const string& md5, const Settings& settings)
24 : Cartridge(settings, md5)
25{
26 // Copy the ROM image into my buffer
27 std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
28 createCodeAccessBase(myImage.size());
29}
30
31// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
32void CartridgeE0::reset()
33{
34 // Setup segments to some default slices
35 if(randomStartBank())
36 {
37 segmentZero(mySystem->randGenerator().next() % 8);
38 segmentOne(mySystem->randGenerator().next() % 8);
39 segmentTwo(mySystem->randGenerator().next() % 8);
40 }
41 else
42 {
43 segmentZero(4);
44 segmentOne(5);
45 segmentTwo(6);
46 }
47 myCurrentSlice[3] = 7; // fixed
48
49 myBankChanged = true;
50}
51
52// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
53void CartridgeE0::install(System& system)
54{
55 mySystem = &system;
56
57 System::PageAccess access(this, System::PageAccessType::READ);
58
59 // Set the page acessing methods for the first part of the last segment
60 for(uInt16 addr = 0x1C00; addr < (0x1FE0U & ~System::PAGE_MASK);
61 addr += System::PAGE_SIZE)
62 {
63 access.directPeekBase = &myImage[0x1C00 + (addr & 0x03FF)];
64 access.codeAccessBase = &myCodeAccessBase[0x1C00 + (addr & 0x03FF)];
65 mySystem->setPageAccess(addr, access);
66 }
67
68 // Set the page accessing methods for the hot spots in the last segment
69 access.directPeekBase = nullptr;
70 access.codeAccessBase = &myCodeAccessBase[0x1FC0]; // TJ: is this the correct address (or 0x1FE0)?
71 access.type = System::PageAccessType::READ;
72 for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000;
73 addr += System::PAGE_SIZE)
74 mySystem->setPageAccess(addr, access);
75}
76
77// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
78uInt16 CartridgeE0::getBank(uInt16 address) const
79{
80 return myCurrentSlice[(address & 0xFFF) >> 10]; // 1K slices
81}
82
83// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
84uInt16 CartridgeE0::bankCount() const
85{
86 return 8;
87}
88
89// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
90uInt8 CartridgeE0::peek(uInt16 address)
91{
92 address &= 0x0FFF;
93
94 // Switch banks if necessary
95 if((address >= 0x0FE0) && (address <= 0x0FE7))
96 {
97 segmentZero(address & 0x0007);
98 }
99 else if((address >= 0x0FE8) && (address <= 0x0FEF))
100 {
101 segmentOne(address & 0x0007);
102 }
103 else if((address >= 0x0FF0) && (address <= 0x0FF7))
104 {
105 segmentTwo(address & 0x0007);
106 }
107
108 return myImage[(myCurrentSlice[address >> 10] << 10) + (address & 0x03FF)];
109}
110
111// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
112bool CartridgeE0::poke(uInt16 address, uInt8)
113{
114 address &= 0x0FFF;
115
116 // Switch banks if necessary
117 if((address >= 0x0FE0) && (address <= 0x0FE7))
118 {
119 segmentZero(address & 0x0007);
120 }
121 else if((address >= 0x0FE8) && (address <= 0x0FEF))
122 {
123 segmentOne(address & 0x0007);
124 }
125 else if((address >= 0x0FF0) && (address <= 0x0FF7))
126 {
127 segmentTwo(address & 0x0007);
128 }
129 return false;
130}
131
132// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
133void CartridgeE0::segmentZero(uInt16 slice)
134{
135 if(bankLocked()) return;
136
137 // Remember the new slice
138 myCurrentSlice[0] = slice;
139 uInt16 offset = slice << 10;
140
141 // Setup the page access methods for the current bank
142 System::PageAccess access(this, System::PageAccessType::READ);
143
144 for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE)
145 {
146 access.directPeekBase = &myImage[offset + (addr & 0x03FF)];
147 access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
148 mySystem->setPageAccess(addr, access);
149 }
150 myBankChanged = true;
151}
152
153// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
154void CartridgeE0::segmentOne(uInt16 slice)
155{
156 if(bankLocked()) return;
157
158 // Remember the new slice
159 myCurrentSlice[1] = slice;
160 uInt16 offset = slice << 10;
161
162 // Setup the page access methods for the current bank
163 System::PageAccess access(this, System::PageAccessType::READ);
164
165 for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE)
166 {
167 access.directPeekBase = &myImage[offset + (addr & 0x03FF)];
168 access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
169 mySystem->setPageAccess(addr, access);
170 }
171 myBankChanged = true;
172}
173
174// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
175void CartridgeE0::segmentTwo(uInt16 slice)
176{
177 if(bankLocked()) return;
178
179 // Remember the new slice
180 myCurrentSlice[2] = slice;
181 uInt16 offset = slice << 10;
182
183 // Setup the page access methods for the current bank
184 System::PageAccess access(this, System::PageAccessType::READ);
185
186 for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE)
187 {
188 access.directPeekBase = &myImage[offset + (addr & 0x03FF)];
189 access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)];
190 mySystem->setPageAccess(addr, access);
191 }
192 myBankChanged = true;
193}
194
195// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
196bool CartridgeE0::patch(uInt16 address, uInt8 value)
197{
198 address &= 0x0FFF;
199 myImage[(myCurrentSlice[address >> 10] << 10) + (address & 0x03FF)] = value;
200 return true;
201}
202
203// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
204const uInt8* CartridgeE0::getImage(size_t& size) const
205{
206 size = myImage.size();
207 return myImage.data();
208}
209
210// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
211bool CartridgeE0::save(Serializer& out) const
212{
213 try
214 {
215 out.putShortArray(myCurrentSlice.data(), myCurrentSlice.size());
216 }
217 catch(...)
218 {
219 cerr << "ERROR: CartridgeE0::save" << endl;
220 return false;
221 }
222
223 return true;
224}
225
226// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
227bool CartridgeE0::load(Serializer& in)
228{
229 try
230 {
231 in.getShortArray(myCurrentSlice.data(), myCurrentSlice.size());
232 }
233 catch(...)
234 {
235 cerr << "ERROR: CartridgeE0::load" << endl;
236 return false;
237 }
238
239 return true;
240}
241