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 "CartCV.hxx" |
20 | |
21 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
22 | CartridgeCV::CartridgeCV(const ByteBuffer& image, size_t size, |
23 | const string& md5, const Settings& settings) |
24 | : Cartridge(settings, md5), |
25 | mySize(size) |
26 | { |
27 | if(mySize == myImage.size()) |
28 | { |
29 | // Copy the ROM data into my buffer |
30 | std::copy_n(image.get(), myImage.size(), myImage.begin()); |
31 | } |
32 | else if(mySize == 4_KB) |
33 | { |
34 | // The game has something saved in the RAM |
35 | // Useful for MagiCard program listings |
36 | |
37 | // Copy the ROM data into my buffer |
38 | std::copy_n(image.get() + myImage.size(), myImage.size(), myImage.begin()); |
39 | |
40 | // Copy the RAM image into a buffer for use in reset() |
41 | std::copy_n(image.get(), myInitialRAM.size(), myInitialRAM.begin()); |
42 | } |
43 | createCodeAccessBase(myImage.size() + myRAM.size()); |
44 | } |
45 | |
46 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
47 | void CartridgeCV::reset() |
48 | { |
49 | if(mySize == 4_KB) |
50 | { |
51 | // Copy the RAM image into my buffer |
52 | myRAM = myInitialRAM; |
53 | } |
54 | else |
55 | initializeRAM(myRAM.data(), myRAM.size()); |
56 | |
57 | myBankChanged = true; |
58 | } |
59 | |
60 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
61 | void CartridgeCV::install(System& system) |
62 | { |
63 | mySystem = &system; |
64 | |
65 | System::PageAccess access(this, System::PageAccessType::READ); |
66 | |
67 | // Map ROM image into the system |
68 | for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) |
69 | { |
70 | access.directPeekBase = &myImage[addr & 0x07FF]; |
71 | access.codeAccessBase = &myCodeAccessBase[addr & 0x07FF]; |
72 | mySystem->setPageAccess(addr, access); |
73 | } |
74 | |
75 | // Set the page accessing method for the RAM writing pages |
76 | // Map access to this class, since we need to inspect all accesses to |
77 | // check if RWP happens |
78 | access.directPeekBase = nullptr; |
79 | access.codeAccessBase = nullptr; |
80 | access.type = System::PageAccessType::WRITE; |
81 | for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) |
82 | mySystem->setPageAccess(addr, access); |
83 | |
84 | // Set the page accessing method for the RAM reading pages |
85 | access.directPokeBase = nullptr; |
86 | access.type = System::PageAccessType::READ; |
87 | for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) |
88 | { |
89 | access.directPeekBase = &myRAM[addr & 0x03FF]; |
90 | access.codeAccessBase = &myCodeAccessBase[2048 + (addr & 0x03FF)]; |
91 | mySystem->setPageAccess(addr, access); |
92 | } |
93 | } |
94 | |
95 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
96 | uInt8 CartridgeCV::peek(uInt16 address) |
97 | { |
98 | // The only way we can get to this method is if we attempt to read from |
99 | // the write port (0xF400 - 0xF7FF, 1024 bytes), in which case an |
100 | // unwanted write is potentially triggered |
101 | return peekRAM(myRAM[address & 0x03FF], address); |
102 | } |
103 | |
104 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
105 | bool CartridgeCV::poke(uInt16 address, uInt8 value) |
106 | { |
107 | pokeRAM(myRAM[address & 0x03FF], address, value); |
108 | return true; |
109 | } |
110 | |
111 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
112 | bool CartridgeCV::patch(uInt16 address, uInt8 value) |
113 | { |
114 | address &= 0x0FFF; |
115 | |
116 | if(address < 0x0800) |
117 | { |
118 | // Normally, a write to the read port won't do anything |
119 | // However, the patch command is special in that ignores such |
120 | // cart restrictions |
121 | // The following will work for both reads and writes |
122 | myRAM[address & 0x03FF] = value; |
123 | } |
124 | else |
125 | myImage[address & 0x07FF] = value; |
126 | |
127 | return myBankChanged = true; |
128 | } |
129 | |
130 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
131 | const uInt8* CartridgeCV::getImage(size_t& size) const |
132 | { |
133 | size = myImage.size(); |
134 | return myImage.data(); |
135 | } |
136 | |
137 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
138 | bool CartridgeCV::save(Serializer& out) const |
139 | { |
140 | try |
141 | { |
142 | out.putByteArray(myRAM.data(), myRAM.size()); |
143 | } |
144 | catch(...) |
145 | { |
146 | cerr << "ERROR: CartridgeCV::save" << endl; |
147 | return false; |
148 | } |
149 | |
150 | return true; |
151 | } |
152 | |
153 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
154 | bool CartridgeCV::load(Serializer& in) |
155 | { |
156 | try |
157 | { |
158 | in.getByteArray(myRAM.data(), myRAM.size()); |
159 | } |
160 | catch(...) |
161 | { |
162 | cerr << "ERROR: CartridgeCV::load" << endl; |
163 | return false; |
164 | } |
165 | |
166 | return true; |
167 | } |
168 | |