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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
23Cartridge3F::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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
38void Cartridge3F::reset()
39{
40 initializeStartBank(bankCount() - 1);
41
42 bank(startBank());
43}
44
45// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
46void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
69uInt8 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
80bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
95bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
128uInt16 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
137uInt16 Cartridge3F::bankCount() const
138{
139 return uInt16(mySize >> 11); // 2K slices
140}
141
142// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
143bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
156const uInt8* Cartridge3F::getImage(size_t& size) const
157{
158 size = mySize;
159 return myImage.get();
160}
161
162// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
163bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
179bool 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