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 "CartFC.hxx"
20
21// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22CartridgeFC::CartridgeFC(const ByteBuffer& image, size_t size,
23 const string& md5, const Settings& settings)
24 : Cartridge(settings, md5),
25 mySize(size),
26 myBankOffset(0),
27 myCurrentBank(0),
28 myTargetBank(0)
29{
30 // Copy the ROM image into my buffer
31 std::copy_n(image.get(), std::min(myImage.size(), size), myImage.begin());
32 createCodeAccessBase(myImage.size());
33}
34
35// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
36void CartridgeFC::reset()
37{
38 initializeStartBank(0);
39 myTargetBank = 0;
40
41 // Upon reset we switch to the reset bank
42 bank(startBank());
43}
44
45// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
46void CartridgeFC::install(System& system)
47{
48 mySystem = &system;
49
50 // Install pages for the startup bank
51 bank(startBank());
52}
53
54// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
55uInt8 CartridgeFC::peek(uInt16 address)
56{
57 address &= 0x0FFF;
58
59 // Switch banks if necessary
60 switch (address)
61 {
62 case 0x0FFC:
63 // Trigger the bank switch
64 bank(myTargetBank);
65 break;
66
67 default:
68 break;
69 }
70
71 return myImage[myBankOffset + address];
72}
73
74// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
75bool CartridgeFC::poke(uInt16 address, uInt8 value)
76{
77 address &= 0x0FFF;
78
79 // Switch banks if necessary
80 switch (address)
81 {
82 case 0x0FF8:
83 // Set the two lowest bits of target 4k bank
84 myTargetBank = value & 0b11;
85 break;
86
87 case 0x0FF9:
88 // Set the high bits of target 4k bank
89 myTargetBank += value << 2;
90 myTargetBank %= bankCount();
91 break;
92
93 case 0x0FFC:
94 // Trigger the bank switch
95 bank(myTargetBank);
96 break;
97
98 default:
99 break;
100 }
101 return false;
102}
103
104// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
105bool CartridgeFC::bank(uInt16 bank)
106{
107 if (bankLocked()) return false;
108
109 // Remember what bank we're in
110 myBankOffset = bank << 12;
111
112 System::PageAccess access(this, System::PageAccessType::READ);
113
114 // Set the page accessing methods for the hot spots
115 for (uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000;
116 addr += System::PAGE_SIZE)
117 {
118 access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
119 mySystem->setPageAccess(addr, access);
120 }
121
122 // Setup the page access methods for the current bank
123 for (uInt16 addr = 0x1000; addr < (0x1FF8U & ~System::PAGE_MASK);
124 addr += System::PAGE_SIZE)
125 {
126 access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)];
127 access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)];
128 mySystem->setPageAccess(addr, access);
129 }
130 myCurrentBank = myTargetBank;
131 return myBankChanged = true;
132}
133
134// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
135uInt16 CartridgeFC::getBank(uInt16) const
136{
137 return myBankOffset >> 12;
138}
139
140// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
141uInt16 CartridgeFC::bankCount() const
142{
143 return uInt16(mySize >> 12);
144}
145
146// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
147bool CartridgeFC::patch(uInt16 address, uInt8 value)
148{
149 myImage[myBankOffset + (address & 0x0FFF)] = value;
150 return myBankChanged = true;
151}
152
153// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
154const uInt8* CartridgeFC::getImage(size_t& size) const
155{
156 size = mySize;
157 return myImage.data();
158}
159
160// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
161bool CartridgeFC::save(Serializer& out) const
162{
163 try
164 {
165 out.putShort(myBankOffset);
166 }
167 catch (...)
168 {
169 cerr << "ERROR: CartridgeFC::save" << endl;
170 return false;
171 }
172
173 return true;
174}
175
176// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
177bool CartridgeFC::load(Serializer& in)
178{
179 try
180 {
181 myBankOffset = in.getShort();
182 }
183 catch (...)
184 {
185 cerr << "ERROR: CartridgeFC::load" << endl;
186 return false;
187 }
188
189 // Remember what bank we were in
190 bank(myBankOffset >> 12);
191
192 return true;
193}
194