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