openMSX
ColecoSuperGameModule.cc
Go to the documentation of this file.
3#include "MSXCPUInterface.hh"
4#include "MSXException.hh"
5#include "serialize.hh"
6
7namespace openmsx {
8
9// Disabling the SGM RAM has no effect on 0-0x1FFF, according to Oscar Toledo.
10// So, if the BIOS is disabled to show RAM and the SGM RAM is disabled, is
11// there is 8kB SGM RAM on 0-0x1FFF.
12
13static constexpr unsigned MAIN_RAM_AREA_START = 0x6000;
14static constexpr unsigned MAIN_RAM_SIZE = 0x400; // 1kB
15static constexpr unsigned SGM_RAM_SIZE = 0x8000; // 32kB
16static constexpr unsigned BIOS_ROM_SIZE = 0x2000; // 8kB
17
19 : MSXDevice(config)
20 , psg(getName() + " PSG", DummyAY8910Periphery::instance(), config, getCurrentTime())
21 , sgmRam(config, getName() + " RAM", "SGM RAM", SGM_RAM_SIZE)
22 , mainRam(config, "Main RAM", "Main RAM", MAIN_RAM_SIZE)
23 , biosRom(getName(), "BIOS ROM", config)
24{
25 if (biosRom.size() != BIOS_ROM_SIZE) {
26 throw MSXException("ColecoVision BIOS ROM must be exactly 8kB in size.");
27 }
28 auto& cpuInterface = getCPUInterface();
29 for (auto port : {0x50, 0x51, 0x53, 0x7F}) {
30 cpuInterface.register_IO_Out(narrow_cast<byte>(port), this);
31 }
32 cpuInterface.register_IO_In(0x52, this);
34}
35
37{
38 auto& cpuInterface = getCPUInterface();
39 for (auto port : {0x50, 0x51, 0x53, 0x7F}) {
40 cpuInterface.unregister_IO_Out(narrow_cast<byte>(port), this);
41 }
42 cpuInterface.unregister_IO_In(0x52, this);
43}
44
45static constexpr unsigned translateMainRamAddress(unsigned address)
46{
47 return address & (MAIN_RAM_SIZE - 1);
48}
49
50void ColecoSuperGameModule::reset(EmuTime::param time)
51{
52 ramEnabled = false;
53 ramAtBiosEnabled = false;
54 psgLatch = 0;
55 psg.reset(time);
56 invalidateDeviceRWCache(); // flush all to be sure
57}
58
59byte ColecoSuperGameModule::readIO(word port, EmuTime::param time)
60{
61 if ((port & 0xFF) == 0x52) {
62 return psg.readRegister(psgLatch, time);
63 }
64 return 0xFF;
65}
66
67byte ColecoSuperGameModule::peekIO(word port, EmuTime::param time) const
68{
69 if ((port & 0xFF) == 0x52) {
70 return psg.peekRegister(psgLatch, time);
71 }
72 return 0xFF;
73}
74
75void ColecoSuperGameModule::writeIO(word port, byte value, EmuTime::param time)
76{
77 switch (port & 0xFF) {
78 case 0x50: // PSG address (latch?)
79 psgLatch = value & 0x0F;
80 break;
81 case 0x51: // PSG data (register write?)
82 psg.writeRegister(psgLatch, value, time);
83 break;
84 case 0x53: // bit0=1 means enable SGM RAM in 0x2000-0x7FFF range
85 ramEnabled = (value & 1) != 0;
86 invalidateDeviceRWCache(0x0000, SGM_RAM_SIZE); // just flush the whole area
87 break;
88 case 0x7F: // bit1=0 means enable SGM RAM in BIOS area (0-0x1FFF), 1 means BIOS
89 ramAtBiosEnabled = (value & 2) == 0;
90 invalidateDeviceRWCache(0x0000, BIOS_ROM_SIZE);
91 break;
92 default:
93 // ignore
94 break;
95 }
96}
97
98byte ColecoSuperGameModule::peekMem(word address, EmuTime::param /*time*/) const
99{
100 if (address < BIOS_ROM_SIZE) {
101 return ramAtBiosEnabled ? sgmRam.peek(address) : biosRom[address];
102 } else if (address < SGM_RAM_SIZE) {
103 if (ramEnabled) {
104 return sgmRam.peek(address);
105 } else if (address >= MAIN_RAM_AREA_START) {
106 return mainRam.peek(translateMainRamAddress(address));
107 }
108 }
109 return 0xFF;
110}
111
112byte ColecoSuperGameModule::readMem(word address, EmuTime::param /*time*/)
113{
114 if (address < BIOS_ROM_SIZE) {
115 return ramAtBiosEnabled ? sgmRam.read(address) : biosRom[address];
116 } else if (address < SGM_RAM_SIZE) {
117 if (ramEnabled) {
118 return sgmRam.read(address);
119 } else if (address >= MAIN_RAM_AREA_START) {
120 return mainRam.read(translateMainRamAddress(address));
121 }
122 }
123 return 0xFF;
124}
125
126void ColecoSuperGameModule::writeMem(word address, byte value, EmuTime::param /*time*/)
127{
128 if (address < BIOS_ROM_SIZE) {
129 if (ramAtBiosEnabled) {
130 sgmRam.write(address, value);
131 }
132 } else if (address < SGM_RAM_SIZE) {
133 if (ramEnabled) {
134 sgmRam.write(address, value);
135 } else if (address >= MAIN_RAM_AREA_START) {
136 mainRam.write(translateMainRamAddress(address), value);
137 }
138 }
139}
140
142{
143 if (start < BIOS_ROM_SIZE) {
144 return ramAtBiosEnabled ? sgmRam.getReadCacheLine(start) : &biosRom[start];
145 } else if (start < SGM_RAM_SIZE) {
146 if (ramEnabled) {
147 return sgmRam.getReadCacheLine(start);
148 } else if (start >= MAIN_RAM_AREA_START) {
149 return mainRam.getReadCacheLine(translateMainRamAddress(start));
150 }
151 }
152 return unmappedRead.data();
153}
154
156{
157 if (start < BIOS_ROM_SIZE) {
158 if (ramAtBiosEnabled) {
159 return sgmRam.getWriteCacheLine(start);
160 }
161 } else if (start < SGM_RAM_SIZE) {
162 if (ramEnabled) {
163 return sgmRam.getWriteCacheLine(start);
164 } else if (start >= MAIN_RAM_AREA_START) {
165 return mainRam.getWriteCacheLine(translateMainRamAddress(start));
166 }
167 }
168 return unmappedWrite.data();
169}
170
171template<typename Archive>
172void ColecoSuperGameModule::serialize(Archive& ar, unsigned /*version*/)
173{
174 ar.serialize("mainRam", mainRam.getUncheckedRam(),
175 "sgmRam", sgmRam.getUncheckedRam(),
176 "psg", psg,
177 "psgLatch", psgLatch,
178 "ramEnabled", ramEnabled,
179 "ramAtBiosEnabled", ramAtBiosEnabled);
180}
183
184} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
uint8_t readRegister(unsigned reg, EmuTime::param time)
Definition AY8910.cc:534
void reset(EmuTime::param time)
Definition AY8910.cc:521
void writeRegister(unsigned reg, uint8_t value, EmuTime::param time)
Definition AY8910.cc:578
uint8_t peekRegister(unsigned reg, EmuTime::param time) const
Definition AY8910.cc:559
byte * getWriteCacheLine(size_t addr)
Definition CheckedRam.cc:45
Ram & getUncheckedRam()
Give access to the unchecked Ram.
Definition CheckedRam.hh:51
void write(size_t addr, byte value)
Definition CheckedRam.cc:64
byte peek(size_t addr) const
Definition CheckedRam.hh:35
const byte * getReadCacheLine(size_t addr) const
Definition CheckedRam.cc:39
byte read(size_t addr)
Definition CheckedRam.cc:28
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
void serialize(Archive &ar, unsigned version)
byte readIO(word port, EmuTime::param time) override
Read a byte from an IO port at a certain time from this device.
ColecoSuperGameModule(const DeviceConfig &config)
void writeIO(word port, byte value, EmuTime::param time) override
Write a byte to a given IO port at a certain time to this device.
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
void reset(EmuTime::param time) override
This method is called on reset.
byte * getWriteCacheLine(word start) override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
byte peekIO(word port, EmuTime::param time) const override
Read a byte from a given IO port.
void writeMem(word address, byte value, EmuTime::param time) override
Write a given byte to a given location at a certain time to this device.
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
static std::array< byte, 0x10000 > unmappedRead
Definition MSXDevice.hh:306
static std::array< byte, 0x10000 > unmappedWrite
Definition MSXDevice.hh:307
void invalidateDeviceRWCache()
Calls MSXCPUInterface::invalidateXXCache() for the specific (part of) the slot that this device is lo...
Definition MSXDevice.hh:214
EmuTime::param getCurrentTime() const
Definition MSXDevice.cc:125
MSXCPUInterface & getCPUInterface() const
Definition MSXDevice.cc:133
auto size() const
Definition Rom.hh:36
This file implemented 3 utility functions:
Definition Autofire.cc:11
uint16_t word
16 bit unsigned integer
Definition openmsx.hh:29
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)