openMSX
ChakkariCopy.cc
Go to the documentation of this file.
1#include "ChakkariCopy.hh"
2#include "MSXCliComm.hh"
3#include "serialize.hh"
4
5// The cartridge has 2 buttons with 2 LEDs, marked PAUSE and COPY. It also has
6// a toggle switch with the options COPY and RAM. Setting this toggle to RAM
7// makes the cartridge a 16kB RAM expansion.
8//
9// The following information is provided by Rudolf Lechleitner, who devised it
10// together with Enrico Barbisan.
11//
12// ----------------------------------------------------------------------------
13//
14// The memory layout:
15//
16// +--------------------------------------------+
17// | 0000-3FFF: 16 KB RAM in COPY mode |
18// | Page 0: available in COPY mode only |
19// | can be toggled to read-only |
20// +--------------------------------------------+
21// | 4000-5FFF: 8KB ROM code |
22// | Page 1: + |
23// | 6000-67FF: 2KB internal RAM |
24// +--------------------------------------------+
25//
26// The shown 16KB RAM in page 0 are only available in COPY mode, but can be
27// toggled to read-only. The location of the RAM in RAM mode is unknown.
28//
29// The memory at 6800-7FFF is unused by the cartridge.
30//
31// Internal handling: during cartridge initialisation Chakkari Copy copies the
32// contents of BIOS page 0 into its own RAM and patches some entries to
33// capture the input of PAUSE and COPY buttons of the cartridge. Afterwards the
34// patched memory is set to read-only.
35// PAUSE and COPY itself are processed by the routines in the ROM. In case the
36// page 0 is (for any reason) switched to the original MSX-BIOS the cartridge
37// buttons are no longer working. In this case CALL SCHANGE switches the BIOS
38// to the patched version again.
39//
40// In case a program switches screen modes in a way that prevents Chakkari Copy
41// from detecting the correct parameters Chakkari Copy can be started by
42// keeping the COPY button pressed. In this case the screen-mode autodetect
43// will be skipped and the parameters can be entered manually.
44// This appears to be an undocumented feature, confirmed by typos and a very
45// rudimentary screen handling.
46//
47// In case the printer is not ready or not available the printing can be
48// aborted by pressing Ctrl+Stop.
49//
50// The Chakkari Copy cartridge has one register, which controls its complete
51// behavior. This register is available at MSX port &H7F.
52//
53// READ only:
54//
55// +-----------------------------------------+
56// | 1 | 1 | 1 | 1 | 1 | PSE | CPY |
57// +-----+-----+-----+-----+-----+-----+-----+
58// CPY: 0 = Copy button pressed, 1 = Copy button released
59// PSE: 0 = Pause button pressed, 1 = Pause button released
60//
61// WRITE only:
62//
63// +-----+-----+-----+-----+-----+-----+-----+
64// | 1 | 1 | 1 | 1 | RAM | PSE | CPY |
65// +-----+-----+-----+-----+-----+-----+-----+
66// CPY: 0 = Copy LED on, 1 = Copy LED off
67// PSE: 0 = Pause LED on, 1 = Pause LED off
68// RAM: 0 = Page 0 in RAM mode, 1 = Page 0 in ROM mode (applies to COPY mode only)
69//
70// ----------------------------------------------------------------------------
71
72// The RAM mode has now been implemented to switch the RAM to page 1. This
73// doesn't seem to be the most logical, but it's closest to the output of
74// MSXMEM2. It could still be useful for 32kB machines.
75//
76// The work RAM has been mirrored in the 0x6000-0x8000 area to match the output
77// of MSXMEM2.BAS which was run on a machine with the real cartridge inserted.
78// It showed 'R' on page 1 for both COPY and RAM mode. The only thing that
79// doesn't match yet is that it also showed 'R' in page 0 for COPY mode for
80// subslots 0 and 1. The latter is unexplained so far.
81
82namespace openmsx {
83
85 : MSXDevice(config)
86 , biosRam(config, getName() + " BIOS RAM", "Chakkari Copy BIOS RAM", 0x4000)
87 , workRam(config, getName() + " work RAM", "Chakkari Copy work RAM", 0x0800)
88 , rom(getName() + " ROM", "rom", config)
89 , pauseButtonPressedSetting(getCommandController(),
90 getName() + " PAUSE button pressed",
91 "controls the PAUSE button state", false, Setting::Save::NO)
92 , copyButtonPressedSetting(getCommandController(),
93 getName() + " COPY button pressed",
94 "controls the COPY button state", false, Setting::Save::NO)
95 , modeSetting(getCommandController(), getName() + " mode",
96 "Sets mode of the cartridge: in COPY mode you can hardcopy MSX1 screens, "
97 "in RAM mode you just have a 16kB RAM expansion", ChakkariCopy::COPY,
99 {"COPY", ChakkariCopy::COPY}, {"RAM", ChakkariCopy::RAM}})
100{
101 reset(getCurrentTime());
102 modeSetting.attach(*this);
103}
104
105ChakkariCopy::~ChakkariCopy()
106{
107 modeSetting.detach(*this);
108}
109
110void ChakkariCopy::reset(EmuTime::param time)
111{
112 writeIO(0, 0xFF, time);
113}
114
115void ChakkariCopy::writeIO(word /*port*/, byte value, EmuTime::param /*time*/)
116{
117 byte diff = reg ^ value;
118 reg = value;
119
120 if (diff & 0x01) {
121 getCliComm().printInfo(getName(), " COPY LED ",
122 (((value & 1) == 0x01) ? "OFF" : "ON"));
123 }
124 if (diff & 0x02) {
125 getCliComm().printInfo(getName(), " PAUSE LED ",
126 (((value & 2) == 0x02) ? "OFF" : "ON"));
127 }
128 if (diff & 0x04) {
129 if (modeSetting.getEnum() == COPY) {
130 // page 0 toggles writable/read-only
131 invalidateDeviceRWCache(0x0000, 0x4000);
132 }
133 }
134}
135
136byte ChakkariCopy::readIO(word port, EmuTime::param time)
137{
138 return peekIO(port, time);
139}
140
141byte ChakkariCopy::peekIO(word /*port*/, EmuTime::param /*time*/) const
142{
143 byte retVal = 0xFF;
144 if (copyButtonPressedSetting .getBoolean()) retVal &= ~0x01;
145 if (pauseButtonPressedSetting.getBoolean()) retVal &= ~0x02;
146 return retVal;
147}
148
149byte ChakkariCopy::readMem(word address, EmuTime::param time)
150{
151 return peekMem(address, time);
152}
153
154byte ChakkariCopy::peekMem(word address, EmuTime::param /*time*/) const
155{
156 return *getReadCacheLine(address);
157}
158
159const byte* ChakkariCopy::getReadCacheLine(word address) const
160{
161 if (modeSetting.getEnum() == COPY) {
162 // page 0
163 if (address < 0x4000) {
164 return &biosRam[address];
165 }
166 // page 1
167 if ((0x4000 <= address) && (address < 0x6000)) {
168 return &rom[address & 0x1FFF];
169 }
170 // the work RAM is mirrored in 0x6000-0x8000, see above
171 if ((0x6000 <= address) && (address < 0x8000)) {
172 return &workRam[address & 0x07FF];
173 }
174 } else {
175 // page 1 RAM mode
176 if ((0x4000 <= address) && (address < 0x8000)) {
177 return &biosRam[address & 0x3FFF];
178 }
179 }
180 return unmappedRead.data();
181}
182
183void ChakkariCopy::writeMem(word address, byte value, EmuTime::param /*time*/)
184{
185 *getWriteCacheLine(address) = value;
186}
187
188byte* ChakkariCopy::getWriteCacheLine(word address)
189{
190 if (modeSetting.getEnum() == COPY) {
191 // page 0
192 if ((address < 0x4000) && ((reg & 0x04) == 0)) {
193 return &biosRam[address & 0x3FFF];
194 }
195 // page 1
196 // the work RAM is mirrored in 0x6000-0x8000, see above
197 if ((0x6000 <= address) && (address < 0x8000)) {
198 return &workRam[address & 0x07FF];
199 }
200 } else {
201 // page 1 RAM mode
202 if ((0x4000 <= address) && (address < 0x8000)) {
203 return &biosRam[address & 0x3FFF];
204 }
205 }
206 return unmappedWrite.data();
207}
208
209void ChakkariCopy::update(const Setting& /*setting*/) noexcept
210{
211 // switch COPY <-> RAM mode, memory layout changes
212 invalidateDeviceRWCache();
213}
214
215template<typename Archive>
216void ChakkariCopy::serialize(Archive& ar, unsigned /*version*/)
217{
218 ar.template serializeBase<MSXDevice>(*this);
219 ar.serialize("biosRam", biosRam,
220 "workRam", workRam,
221 "reg", reg);
222 if constexpr (Archive::IS_LOADER) {
223 writeIO(0, reg, getCurrentTime());
224 }
225
226}
229
230} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
ChakkariCopy(const DeviceConfig &config)
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.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)