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