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 "TIA.hxx" |
20 | #include "Cart3F.hxx" |
21 | |
22 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
23 | Cartridge3F::Cartridge3F(const ByteBuffer& image, size_t size, |
24 | const string& md5, const Settings& settings) |
25 | : Cartridge(settings, md5), |
26 | mySize(size), |
27 | myCurrentBank(0) |
28 | { |
29 | // Allocate array for the ROM image |
30 | myImage = make_unique<uInt8[]>(mySize); |
31 | |
32 | // Copy the ROM image into my buffer |
33 | std::copy_n(image.get(), mySize, myImage.get()); |
34 | createCodeAccessBase(mySize); |
35 | } |
36 | |
37 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
38 | void Cartridge3F::reset() |
39 | { |
40 | initializeStartBank(bankCount() - 1); |
41 | |
42 | bank(startBank()); |
43 | } |
44 | |
45 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
46 | void Cartridge3F::install(System& system) |
47 | { |
48 | mySystem = &system; |
49 | |
50 | System::PageAccess access(this, System::PageAccessType::READWRITE); |
51 | |
52 | // The hotspot ($3F) is in TIA address space, so we claim it here |
53 | for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) |
54 | mySystem->setPageAccess(addr, access); |
55 | |
56 | // Setup the second segment to always point to the last ROM slice |
57 | access.type = System::PageAccessType::READ; |
58 | for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) |
59 | { |
60 | access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; |
61 | access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (addr & 0x07FF)]; |
62 | mySystem->setPageAccess(addr, access); |
63 | } |
64 | |
65 | bank(startBank()); |
66 | } |
67 | |
68 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
69 | uInt8 Cartridge3F::peek(uInt16 address) |
70 | { |
71 | address &= 0x0FFF; |
72 | |
73 | if(address < 0x0800) |
74 | return myImage[(address & 0x07FF) + (myCurrentBank << 11)]; |
75 | else |
76 | return myImage[(address & 0x07FF) + mySize - 2048]; |
77 | } |
78 | |
79 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
80 | bool Cartridge3F::poke(uInt16 address, uInt8 value) |
81 | { |
82 | address &= 0x0FFF; |
83 | |
84 | // Switch banks if necessary |
85 | if(address <= 0x003F) |
86 | bank(value); |
87 | |
88 | // Handle TIA space that we claimed above |
89 | mySystem->tia().poke(address, value); |
90 | |
91 | return false; |
92 | } |
93 | |
94 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
95 | bool Cartridge3F::bank(uInt16 bank) |
96 | { |
97 | if(bankLocked()) |
98 | return false; |
99 | |
100 | // Make sure the bank they're asking for is reasonable |
101 | if((uInt32(bank) << 11) < mySize) |
102 | { |
103 | myCurrentBank = bank; |
104 | } |
105 | else |
106 | { |
107 | // Oops, the bank they're asking for isn't valid so let's wrap it |
108 | // around to a valid bank number |
109 | myCurrentBank = bank % (mySize >> 11); |
110 | } |
111 | |
112 | uInt32 offset = myCurrentBank << 11; |
113 | |
114 | // Setup the page access methods for the current bank |
115 | System::PageAccess access(this, System::PageAccessType::READ); |
116 | |
117 | // Map ROM image into the system |
118 | for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE) |
119 | { |
120 | access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; |
121 | access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)]; |
122 | mySystem->setPageAccess(addr, access); |
123 | } |
124 | return myBankChanged = true; |
125 | } |
126 | |
127 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
128 | uInt16 Cartridge3F::getBank(uInt16 address) const |
129 | { |
130 | if (address & 0x800) |
131 | return uInt16((mySize >> 11) - 1); // 2K slices, fixed bank |
132 | else |
133 | return myCurrentBank; |
134 | } |
135 | |
136 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
137 | uInt16 Cartridge3F::bankCount() const |
138 | { |
139 | return uInt16(mySize >> 11); // 2K slices |
140 | } |
141 | |
142 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
143 | bool Cartridge3F::patch(uInt16 address, uInt8 value) |
144 | { |
145 | address &= 0x0FFF; |
146 | |
147 | if(address < 0x0800) |
148 | myImage[(address & 0x07FF) + (myCurrentBank << 11)] = value; |
149 | else |
150 | myImage[(address & 0x07FF) + mySize - 2048] = value; |
151 | |
152 | return myBankChanged = true; |
153 | } |
154 | |
155 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
156 | const uInt8* Cartridge3F::getImage(size_t& size) const |
157 | { |
158 | size = mySize; |
159 | return myImage.get(); |
160 | } |
161 | |
162 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
163 | bool Cartridge3F::save(Serializer& out) const |
164 | { |
165 | try |
166 | { |
167 | out.putShort(myCurrentBank); |
168 | } |
169 | catch(...) |
170 | { |
171 | cerr << "ERROR: Cartridge3F::save" << endl; |
172 | return false; |
173 | } |
174 | |
175 | return true; |
176 | } |
177 | |
178 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
179 | bool Cartridge3F::load(Serializer& in) |
180 | { |
181 | try |
182 | { |
183 | myCurrentBank = in.getShort(); |
184 | } |
185 | catch(...) |
186 | { |
187 | cerr << "ERROR: Cartridge3F::load" << endl; |
188 | return false; |
189 | } |
190 | |
191 | // Now, go to the current bank |
192 | bank(myCurrentBank); |
193 | |
194 | return true; |
195 | } |
196 | |