openMSX
MSXModem.cc
Go to the documentation of this file.
1#include "MSXModem.hh"
2#include "CacheLine.hh"
3#include "serialize.hh"
4#include "MSXException.hh"
5
6#include <iostream>
7
8// See also
9// https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/modem100/t600/t600-0.mac
10// for a disassembly of the code in the ROM. That disassembly source by A.
11// Zeilemaker is the technical source for this implementation.
12//
13// MSX-Modem seems to be specified here:
14// http://ngs.no.coocan.jp/doc/wiki.cgi/datapack?page=2%BE%CF+MSX+MODEM
15
16namespace openmsx {
17
19 : MSXDevice(config)
20 , rom(getName() + " ROM", "rom", config)
21 , sram(getName() + " SRAM", 0x2000, config)
22{
23 if (rom.size() != 0x10000) {
24 throw MSXException("ROM must be exactly 64kB in size!");
25 }
26 reset(EmuTime::dummy());
27}
28
29void MSXModem::reset(EmuTime::param /*time*/)
30{
31 bank = 0; // TODO: verify
32 selectedNCUreg = 0; // TODO: verify
33}
34
35void MSXModem::writeMem(word address, byte value, EmuTime::param /*time*/)
36{
37 if (address == 0x7FC0) {
38 // b2-b0 = ROM segment (4000H-5FFFH)
39 // b3 = off hook
40 // b4 = connect to modem
41 // b5 = speaker
42 if (byte newBank = value & 0b111; bank != newBank) {
43 bank = newBank;
45 //std::cerr << "Changed bank to " << int(bank) << "\n";
46 }
47 // other bits not implemented
48 } else if (address == 0x7F00) {
49 // TODO: write NCU data
50 // These registers are actually connected to the modem part... but faked here.
51 // NCU register 0, write
52 // NCU register 1, write
53 // b7 = send break disabled
54 // b3 = disable receiver
55 // NCU register 2, write
56 // NCU register 3, write
57 // transmitter data
58 //std::cerr << "Wrote to NCU reg " << int(selectedNCUreg & 0b11) << ": " << int(value) << "\n";
59 } else if (address == 0x7F40) {
60 // select NCU register
61 selectedNCUreg = value;
62 // std::cerr << "Changed selected NCU reg to " << int(selectedNCUreg) << "\n";
63 } else if ((0x6000 <= address) && (address < 0x8000)) {
64 sram.write(address & 0x1FFF, value);
65 }
66}
67
69{
70 if (address == (0x7FC0 & CacheLine::HIGH)) return nullptr;
71 if (address == (0x7F40 & CacheLine::HIGH)) return nullptr;
72 if (address == (0x7F00 & CacheLine::HIGH)) return nullptr;
73 if ((0x6000 <= address) && (address < 0x8000)) {
74 return nullptr;
75 }
76 return unmappedWrite.data();
77}
78
79byte MSXModem::readMem(word address, EmuTime::param time)
80{
81 return peekMem(address, time);
82}
83
84byte MSXModem::peekMem(word address, EmuTime::param /*time*/) const
85{
86 if (address == 0x7FC0) {
87 // b0 = line polarity
88 // b1 = line polarity
89 // b2 = pulse/tone dail
90 return 0; // not implemented
91 } else if (address == 0x7F00) {
92 // read NCU register data
93 // These registers are actually connected to the modem part... but faked here.
94 // NCU register 0, read
95 // b0 =
96 // b1 =
97 // b2 =
98 // b3 = break detected
99 // b4 = long loop detected
100 // b6 =
101 // b7 = dial tone detected
102 // NCU register 1, read
103 // b3 = empty transmitter
104 // b2 = data in receiver
105 // b1 =
106 // b0 =
107 // NCU register 2, read
108 // not used
109 // NCU register 3, read
110 // receiver data
111 static constexpr std::array<byte, 4> ncuRegsRead = {0x00, 0x08, 0x00, 0x00}; // set "empty transmitter" so software starts up...
112 //std::cerr << "Reading from NCU reg " << int(selectedNCUreg & 0b11) << "\n";
113 return ncuRegsRead[selectedNCUreg & 0b11];
114 } else if ((0x4000 <= address) && (address < 0x6000)) {
115 return rom[bank * 0x2000 + (address & 0x1FFF)];
116 } else if ((0x6000 <= address) && (address < 0x8000)) {
117 return sram[address & 0x1FFF];
118 } else {
119 return 0xFF;
120 }
121}
122
123const byte* MSXModem::getReadCacheLine(word address) const
124{
125 if (address == (0x7FC0 & CacheLine::HIGH)) return nullptr;
126 if (address == (0x7F00 & CacheLine::HIGH)) return nullptr;
127 if ((0x4000 <= address) && (address < 0x6000)) {
128 return &rom[bank * 0x2000 + (address & 0x1FFF)];
129 }
130 if ((0x6000 <= address) && (address < 0x8000)) {
131 return &sram[address & 0x1FFF];
132 }
133 return unmappedRead.data();
134}
135
136template<typename Archive>
137void MSXModem::serialize(Archive& ar, unsigned /*version*/)
138{
139 ar.template serializeBase<MSXDevice>(*this);
140 ar.serialize("SRAM", sram,
141 "bank", bank,
142 "selectedNCUreg", selectedNCUreg);
143}
146
147} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
An MSXDevice is an emulated hardware component connected to the bus of the emulated MSX.
Definition MSXDevice.hh:36
void invalidateDeviceRCache()
Definition MSXDevice.hh:215
static std::array< byte, 0x10000 > unmappedRead
Definition MSXDevice.hh:306
static std::array< byte, 0x10000 > unmappedWrite
Definition MSXDevice.hh:307
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
Definition MSXModem.cc:79
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition MSXModem.cc:84
byte * getWriteCacheLine(word address) override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
Definition MSXModem.cc:68
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 MSXModem.cc:35
const byte * getReadCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition MSXModem.cc:123
MSXModem(const DeviceConfig &config)
Definition MSXModem.cc:18
void reset(EmuTime::param time) override
This method is called on reset.
Definition MSXModem.cc:29
void serialize(Archive &ar, unsigned version)
Definition MSXModem.cc:137
auto size() const
Definition Rom.hh:36
void write(size_t addr, byte value)
Definition SRAM.cc:64
constexpr unsigned HIGH
Definition CacheLine.hh:10
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)