openMSX
SpectravideoFDC.cc
Go to the documentation of this file.
1#include "SpectravideoFDC.hh"
2#include "CacheLine.hh"
3#include "DriveMultiplexer.hh"
4#include "WD2793.hh"
5#include "MSXException.hh"
6#include "serialize.hh"
7
8// Note: although this implementation seems to work, it has not been checked on
9// real hardware how the FDC registers are mirrored across the slot, nor how
10// the ROM is visible in the slot. Currently FDC registers are implemented to
11// be mirrored all over the slot (as it seems that the MSX-DOS that came with
12// the SVI-707 needs that), and ROMs are implemented to be visible in page 1.
13//
14// This implementation is solely based on the MSX SVI-728 Service and Technical
15// Manual [Vol.1], page 3-7 (memory mapping of registers) and page 3-1 (ROM).
16// Thanks to Leonard Oliveira for interpreting some of the hardware schematics
17// in that same manual.
18// Thanks to Benoit Delvaux for providing some extra info and software to test
19// with.
20
21namespace openmsx {
22
24 : WD2793BasedFDC(config, "msxdos")
25 , cpmRom(getName() + " CP/M ROM", "rom", config, "cpm")
26{
27 if (cpmRom.size() != 0x1000) {
28 throw MSXException("CP/M ROM must be exactly 4kB in size.");
29 }
31}
32
33void SpectravideoFDC::reset(EmuTime::param /*time*/)
34{
35 cpmRomEnabled = true;
36}
37
38byte SpectravideoFDC::readMem(word address, EmuTime::param time)
39{
40 switch (address & 0x3FFF) {
41 case 0x3FB8:
42 return controller.getStatusReg(time);
43 case 0x3FB9:
44 return controller.getTrackReg(time);
45 case 0x3FBA:
46 return controller.getSectorReg(time);
47 case 0x3FBB:
48 return controller.getDataReg(time);
49 case 0x3FBC: {
50 byte value = 0;
51 if ( controller.getIRQ (time)) value |= 0x80;
52 if (!controller.getDTRQ(time)) value |= 0x40;
53 return value;
54 }
55 case 0x3FBE: // Software switch to turn on CP/M,
56 // boot ROM and turn off MSX DOS ROM.
57 cpmRomEnabled = true;
58 return 0xFF;
59 case 0x3FBF: // Software switch to turn off CP/M,
60 // boot ROM and turn on MSX DOS ROM.
61 cpmRomEnabled = false;
62 return 0xFF;
63 default:
64 return SpectravideoFDC::peekMem(address, time);
65 }
66}
67
68byte SpectravideoFDC::peekMem(word address, EmuTime::param time) const
69{
70 switch (address & 0x3FFF) {
71 case 0x3FB8:
72 return controller.peekStatusReg(time);
73 case 0x3FB9:
74 return controller.peekTrackReg(time);
75 case 0x3FBA:
76 return controller.peekSectorReg(time);
77 case 0x3FBB:
78 return controller.peekDataReg(time);
79 case 0x3FBC: {
80 // Drive control IRQ and DRQ lines are not connected to Z80 interrupt request
81 // bit 7: interrupt of 1793 (1 for interrupt)
82 // bit 6: data request of 1793 (0 for request)
83 // TODO: other bits read 0?
84 byte value = 0;
85 if ( controller.peekIRQ (time)) value |= 0x80;
86 if (!controller.peekDTRQ(time)) value |= 0x40;
87 return value;
88 }
89 default:
90 if ((0x4000 <= address) && (address < 0x8000) && !cpmRomEnabled) {
91 // MSX-DOS ROM only visible in 0x4000-0x7FFF
92 return MSXFDC::peekMem(address, time);
93 } else if ((0x4000 <= address) && (address < 0x5000) && cpmRomEnabled) {
94 // CP/M ROM only visible in 0x4000-0x4FFF
95 return cpmRom[address & 0x0FFF];
96 } else {
97 return 0xFF;
98 }
99 }
100}
101
103{
104 if ((start & 0x3FFF & CacheLine::HIGH) == (0x3FB8 & CacheLine::HIGH)) {
105 // FDC at 0x7FB8-0x7FBF, and mirrored in other pages
106 return nullptr;
107 } else if ((0x4000 <= start) && (start < 0x8000) && !cpmRomEnabled) {
108 // MSX-DOS ROM at 0x4000-0x7FFF
109 return MSXFDC::getReadCacheLine(start);
110 } else if ((0x4000 <= start) && (start < 0x5000) && cpmRomEnabled) {
111 // CP/M ROM at 0x4000-0x4FFF
112 return &cpmRom[start & 0x0FFF];
113 } else {
114 return unmappedRead.data();
115 }
116}
117
118void SpectravideoFDC::writeMem(word address, byte value, EmuTime::param time)
119{
120 switch (address & 0x3FFF) {
121 case 0x3FB8:
122 controller.setCommandReg(value, time);
123 break;
124 case 0x3FB9:
125 controller.setTrackReg(value, time);
126 break;
127 case 0x3FBA:
128 controller.setSectorReg(value, time);
129 break;
130 case 0x3FBB:
131 controller.setDataReg(value, time);
132 break;
133 case 0x3FBC:
134 // bit 0 -> enable drive (1 for ENABLE)
135 // bit 2 -> side select (0 for side 0)
136 // bit 3 -> motor on (1 for ON)
138 multiplexer.setSide ((value & 0x04) != 0);
139 multiplexer.setMotor ((value & 0x08) != 0, time);
140 break;
141 case 0x3FBE: // Software switch to turn on CP/M,
142 // boot ROM and turn off MSX DOS ROM.
143 cpmRomEnabled = true;
144 break;
145 case 0x3FBF: // Software switch to turn off CP/M,
146 // boot ROM and turn on MSX DOS ROM.
147 cpmRomEnabled = false;
148 break;
149 }
150}
151
153{
154 if ((address & 0x3FFF & CacheLine::HIGH) == (0x3FB8 & CacheLine::HIGH)) {
155 // FDC at 0x7FB8-0x7FBF - mirrored
156 return nullptr;
157 } else {
158 return unmappedWrite.data();
159 }
160}
161
162template<typename Archive>
163void SpectravideoFDC::serialize(Archive& ar, unsigned /*version*/)
164{
165 ar.template serializeBase<WD2793BasedFDC>(*this);
166 ar.serialize("cpmRomEnabled", cpmRomEnabled);
167}
170
171} // namespace openmsx
#define REGISTER_MSXDEVICE(CLASS, NAME)
Definition MSXDevice.hh:356
void setMotor(bool status, EmuTime::param time) override
Set motor on/off.
void selectDrive(DriveNum num, EmuTime::param time)
void setSide(bool side) override
Side select.
static std::array< byte, 0x10000 > unmappedRead
Definition MSXDevice.hh:306
static std::array< byte, 0x10000 > unmappedWrite
Definition MSXDevice.hh:307
EmuTime::param getCurrentTime() const
Definition MSXDevice.cc:125
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
Definition MSXFDC.cc:55
const byte * getReadCacheLine(word start) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for reading.
Definition MSXFDC.cc:60
auto size() const
Definition Rom.hh:36
byte * getWriteCacheLine(word address) const override
Test that the memory in the interval [start, start + CacheLine::SIZE) is cacheable for writing.
void reset(EmuTime::param time) override
This method is called on reset.
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)
SpectravideoFDC(const DeviceConfig &config)
byte peekMem(word address, EmuTime::param time) const override
Read a byte from a given memory location.
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.
byte readMem(word address, EmuTime::param time) override
Read a byte from a location at a certain time from this device.
DriveMultiplexer multiplexer
uint8_t peekDataReg(EmuTime::param time) const
Definition WD2793.cc:314
bool peekIRQ(EmuTime::param time) const
Definition WD2793.cc:99
uint8_t getStatusReg(EmuTime::param time)
Definition WD2793.cc:159
void setTrackReg(uint8_t value, EmuTime::param time)
Definition WD2793.cc:205
void setSectorReg(uint8_t value, EmuTime::param time)
Definition WD2793.cc:220
uint8_t getTrackReg(EmuTime::param time) const
Definition WD2793.cc:210
uint8_t peekSectorReg(EmuTime::param time) const
Definition WD2793.cc:230
bool peekDTRQ(EmuTime::param time) const
Definition WD2793.cc:84
void setCommandReg(uint8_t value, EmuTime::param time)
Definition WD2793.cc:111
uint8_t peekTrackReg(EmuTime::param time) const
Definition WD2793.cc:215
bool getDTRQ(EmuTime::param time) const
Definition WD2793.cc:79
uint8_t peekStatusReg(EmuTime::param time) const
Definition WD2793.cc:199
uint8_t getDataReg(EmuTime::param time)
Definition WD2793.cc:249
void setDataReg(uint8_t value, EmuTime::param time)
Definition WD2793.cc:235
bool getIRQ(EmuTime::param time) const
Definition WD2793.cc:94
uint8_t getSectorReg(EmuTime::param time) const
Definition WD2793.cc:225
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)