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