openMSX
YamahaSKW01.cc
Go to the documentation of this file.
1#include "YamahaSKW01.hh"
3#include "CacheLine.hh"
4#include "MSXException.hh"
5#include "checked_cast.hh"
6#include "serialize.hh"
7
8// Implementation based on reverse-engineering of 'acet'/'uniabis', see:
9// https://www.msx.org/forum/msx-talk/hardware/trying-to-dump-yamaha-skw-01
10// https://github.com/uniabis/msxrawl/tree/main/dumpskw1
11// The printer port is assumed to work the same as a standard MSX printer port.
12// This seems to be OK, because when printing with the SKW-01 software and
13// selecting the "HR-5X" printer and an emulated MSX Printer plugged in, sane
14// output is produced.
15// As the emulation is purely based on reverse engineering based on the built
16// in software, there may be plenty of details wrong.
17// Also note that the delay that is apparently present when writing the font
18// address registers (other wise the READY bit wouldn't need to be read out) is
19// not emulated. Because of that, the READY bit will always just be enabled.
20
21namespace openmsx {
22
24 : MSXDevice(config)
25 , Connector(MSXDevice::getPluggingController(), MSXDevice::getName() + " printerport",
26 std::make_unique<DummyPrinterPortDevice>())
27 , mainRom(MSXDevice::getName() + " main" , "rom", config, "main")
28 , fontRom(MSXDevice::getName() + " kanjifont", "rom", config, "kanjifont")
29 , dataRom(MSXDevice::getName() + " data" , "rom", config, "data")
30 , sram(MSXDevice::getName() + " SRAM", 0x800, config)
31{
32 if (mainRom.size() != 32 * 1024) {
33 throw MSXException("Main ROM must be exactly 32kB in size.");
34 }
35 if (fontRom.size() != 128 * 1024) {
36 throw MSXException("Font ROM must be exactly 128kB in size.");
37 }
38 if (dataRom.size() != 32 * 1024) {
39 throw MSXException("Data ROM must be exactly 32kB in size.");
40 }
41
42 reset(EmuTime::dummy());
43}
44
45void YamahaSKW01::reset(EmuTime::param time)
46{
47 fontAddress = {0, 0, 0, 0};
48 dataAddress = 0;
49
50 writeData(0, time); // TODO check this, see MSXPrinterPort
51 setStrobe(true, time); // TODO check this, see MSXPrinterPort
52}
53
54byte YamahaSKW01::readMem(word address, EmuTime::param time)
55{
56 return peekMem(address, time);
57}
58
59byte YamahaSKW01::peekMem(word address, EmuTime::param time) const
60{
61 if (address == one_of(0x7FC0, 0x7FC2, 0x7FC4, 0x7FC6)) {
62 return 0x01; // for now, always READY to read
63 } else if (address == one_of(0x7FC1, 0x7FC3, 0x7FC5, 0x7FC7)) {
64 unsigned group = (address - 0x7FC1) / 2;
65 unsigned base = 0x8000 * group;
66 unsigned offset = fontAddress[group] & 0x7FFF;
67 return fontRom[base + offset];
68 } else if (address == 0x7FC8 || address == 0x7FC9) {
69 return 0xFF;
70 } else if (address == 0x7FCA || address == 0x7FCB) {
71 if ((dataAddress & (1 << 15)) == 0) {
72 return dataRom[dataAddress & 0x7FFF];
73 } else {
74 return sram[dataAddress & 0x7FF];
75 }
76 } else if (address == 0x7FCC) {
77 // bit 1 = status / other bits always 1
78 return getPluggedPrintDev().getStatus(time)
79 ? 0xFF : 0xFD;
80 } else if (address < 0x8000) {
81 return mainRom[address];
82 } else {
83 return 0xFF;
84 }
85}
86
87void YamahaSKW01::writeMem(word address, byte value, EmuTime::param time)
88{
89 if (0x7FC0 <= address && address <= 0x7FC7) {
90 unsigned group = (address - 0x7FC0) / 2;
91 if ((address & 1) == 0) {
92 // LSB address
93 fontAddress[group] = (fontAddress[group] & 0xFF00) | uint16_t(value << 0);
94 } else {
95 // MSB address
96 fontAddress[group] = (fontAddress[group] & 0x00FF) | uint16_t(value << 8);
97 }
98 } else if (address == 0x7FC8) {
99 dataAddress = (dataAddress & 0xFF00) | uint16_t(value << 0);
100 } else if (address == 0x7FC9) {
101 dataAddress = (dataAddress & 0x00FF) | uint16_t(value << 8);
102 } else if (address == 0x7FCA || address == 0x7FCB) {
103 if ((dataAddress & (1 << 15)) != 0) {
104 sram.write(dataAddress & 0x7FF, value);
105 }
106 } else if (address == 0x7FCC) {
107 setStrobe(value & 1, time);
108 } else if (address == 0x7FCE) {
109 writeData(value, time);
110 }
111}
112
113const byte* YamahaSKW01::getReadCacheLine(word start) const
114{
115 if ((start & CacheLine::HIGH) == (0x7FC0 & CacheLine::HIGH)) {
116 // 0x7FC0-0x7FCF memory mapped registers
117 return nullptr; // not cacheable
118 } else if (start < 0x8000) {
119 return &mainRom[start];
120 } else {
121 return unmappedRead.data();
122 }
123}
124
126{
127 if ((start & CacheLine::HIGH) == (0x7FC0 & CacheLine::HIGH)) {
128 // 0x7FC0-0x7FCF memory mapped registers
129 return nullptr; // not cacheable
130 } else {
131 return unmappedWrite.data();
132 }
133}
134
135void YamahaSKW01::setStrobe(bool newStrobe, EmuTime::param time)
136{
137 if (newStrobe != strobe) {
138 strobe = newStrobe;
139 getPluggedPrintDev().setStrobe(strobe, time);
140 }
141}
142
143void YamahaSKW01::writeData(uint8_t newData, EmuTime::param time)
144{
145 if (newData != data) {
146 data = newData;
147 getPluggedPrintDev().writeData(data, time);
148 }
149}
150
151std::string_view YamahaSKW01::getDescription() const
152{
153 return "Yamaha SKW-01 printer port";
154}
155
156std::string_view YamahaSKW01::getClass() const
157{
158 return "Printer Port";
159}
160
161void YamahaSKW01::plug(Pluggable& dev, EmuTime::param time)
162{
163 Connector::plug(dev, time);
164 getPluggedPrintDev().writeData(data, time);
165 getPluggedPrintDev().setStrobe(strobe, time);
166}
167
168PrinterPortDevice& YamahaSKW01::getPluggedPrintDev() const
169{
170 return *checked_cast<PrinterPortDevice*>(&getPlugged());
171}
172
173template<typename Archive>
174void YamahaSKW01::serialize(Archive& ar, unsigned /*version*/)
175{
176 ar.template serializeBase<MSXDevice>(*this);
177 ar.serialize("fontAddress", fontAddress,
178 "dataAddress", dataAddress,
179 "SRAM" , sram,
180 "strobe" , strobe,
181 "data" , data);
182 // TODO force writing data to port?? (See MSXPrinterPort)
183}
186
187} // namespace openmsx
Definition: one_of.hh:7
Represents something you can plug devices into.
Definition: Connector.hh:21
Pluggable & getPlugged() const
Returns the Pluggable currently plugged in.
Definition: Connector.hh:59
virtual void plug(Pluggable &device, EmuTime::param time)
This plugs a Pluggable in this Connector.
Definition: Connector.cc:25
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:304
static std::array< byte, 0x10000 > unmappedWrite
Definition: MSXDevice.hh:305
virtual bool getStatus(EmuTime::param time)=0
Returns the STATUS signal: false = low = ready, true = high = not ready.
virtual void writeData(uint8_t data, EmuTime::param time)=0
Sets the data signals.
virtual void setStrobe(bool strobe, EmuTime::param time)=0
Sets the strobe signal: false = low, true = high.
auto size() const
Definition: Rom.hh:36
void write(size_t addr, byte value)
Definition: SRAM.cc:63
YamahaSKW01(const DeviceConfig &config)
Definition: YamahaSKW01.cc:23
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition: YamahaSKW01.cc:59
void plug(Pluggable &dev, EmuTime::param time) override
This plugs a Pluggable in this Connector.
Definition: YamahaSKW01.cc:161
byte * getWriteCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition: YamahaSKW01.cc:125
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.
Definition: YamahaSKW01.cc:87
void reset(EmuTime::param time) override
This method is called on reset.
Definition: YamahaSKW01.cc:45
std::string_view getDescription() const override
Get a description for this connector.
Definition: YamahaSKW01.cc:151
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition: YamahaSKW01.cc:54
void serialize(Archive &ar, unsigned version)
Definition: YamahaSKW01.cc:174
std::string_view getClass() const override
A Connector belong to a certain class.
Definition: YamahaSKW01.cc:156
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition: YamahaSKW01.cc:113
constexpr unsigned HIGH
Definition: CacheLine.hh:10
std::string getName(KeyCode keyCode)
Translate key code to key name.
Definition: Keys.cc:730
This file implemented 3 utility functions:
Definition: Autofire.cc:9
REGISTER_MSXDEVICE(ChakkariCopy, "ChakkariCopy")
uint16_t word
16 bit unsigned integer
Definition: openmsx.hh:29
STL namespace.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1021