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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22CartridgeCV::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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
47void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
61void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
96uInt8 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
105bool CartridgeCV::poke(uInt16 address, uInt8 value)
106{
107 pokeRAM(myRAM[address & 0x03FF], address, value);
108 return true;
109}
110
111// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
112bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
131const uInt8* CartridgeCV::getImage(size_t& size) const
132{
133 size = myImage.size();
134 return myImage.data();
135}
136
137// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
138bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
154bool 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