openMSX
VictorFDC.cc
Go to the documentation of this file.
1 #include "VictorFDC.hh"
2 #include "CacheLine.hh"
3 #include "DriveMultiplexer.hh"
4 #include "WD2793.hh"
5 #include "serialize.hh"
6 
7 // This implementation is documented in the HC-95 service manual:
8 //
9 // FDD interface:
10 // 7FF8 I/O FDC STATUS/COMMAND
11 // 7FF9 I/O FDC TRACK REGISTER
12 // 7FFA I/O FDC SECTOR REGISTER
13 // 7FFB I/O FDC DATA REGISTER
14 // 7FFC I/O bit 0 A DRIVE MOTOR ON/OFF "1" ON
15 // I/O bit 1 B DRIVE MOTOR ON/OFF "1" ON
16 // I/O bit 2 DRIVE SELECT "0" A DRIVE "1" B DRIVE
17 // O bit 3 SIDE SELECT "0" SIDE 0 "1" SIDE 1
18 // I SIDE SELECT "1" SIDE 0 "0" SIDE 1
19 // I/O bit 4 DRIVE ENABLE "0" ENABLE
20 // bit 5 unused
21 // I bit 6 FDC DATA REQUEST "1" REQUEST
22 // I bit 7 FDC INTERRUPT REQUEST "1" REQUEST
23 
24 namespace openmsx {
25 
26 static const int DRIVE_A_MOTOR = 0x01;
27 static const int DRIVE_B_MOTOR = 0x02;
28 static const int DRIVE_SELECT = 0x04;
29 static const int SIDE_SELECT = 0x08;
30 static const int DRIVE_DISABLE = 0x10; // renamed due to inverse logic
31 static const int DATA_REQUEST = 0x40;
32 static const int INTR_REQUEST = 0x80;
33 
34 
36  : WD2793BasedFDC(config)
37 {
39 }
40 
42 {
44  // initialize in such way that drives are disabled
45  // (and motors off, etc.)
46  // TODO: test on real machine (this is an assumption)
47  writeMem(0x7FFC, DRIVE_DISABLE, time);
48 }
49 
51 {
52  byte value;
53  switch (address) {
54  case 0x7FF8:
55  value = controller->getStatusReg(time);
56  break;
57  case 0x7FF9:
58  value = controller->getTrackReg(time);
59  break;
60  case 0x7FFA:
61  value = controller->getSectorReg(time);
62  break;
63  case 0x7FFB:
64  value = controller->getDataReg(time);
65  break;
66  case 0x7FFC:
67  value = driveControls;
68  if (controller->getIRQ(time)) value |= INTR_REQUEST;
69  if (controller->getDTRQ(time)) value |= DATA_REQUEST;
70  value ^= SIDE_SELECT; // inverted
71  break;
72  default:
73  value = VictorFDC::peekMem(address, time);
74  break;
75  }
76  return value;
77 }
78 
80 {
81  byte value;
82  switch (address) {
83  case 0x7FF8:
84  value = controller->peekStatusReg(time);
85  break;
86  case 0x7FF9:
87  value = controller->peekTrackReg(time);
88  break;
89  case 0x7FFA:
90  value = controller->peekSectorReg(time);
91  break;
92  case 0x7FFB:
93  value = controller->peekDataReg(time);
94  break;
95  case 0x7FFC:
96  value = driveControls;
97  if (controller->peekIRQ(time)) value |= INTR_REQUEST;
98  if (controller->peekDTRQ(time)) value |= DATA_REQUEST;
99  value ^= SIDE_SELECT; // inverted
100  break;
101  default:
102  if ((0x4000 <= address) && (address < 0x8000)) {
103  // ROM only visible in 0x4000-0x7FFF
104  value = MSXFDC::peekMem(address, time);
105  } else {
106  value = 255;
107  }
108  break;
109  }
110  //PRT_DEBUG("VictorFDC read 0x" << hex << (int)address << " 0x" << (int)value << dec);
111  return value;
112 }
113 
115 {
116  if ((start & CacheLine::HIGH) == (0x7FF8 & CacheLine::HIGH)) {
117  // FDC at 0x7FF8-0x7FFC
118  return nullptr;
119  } else if ((0x4000 <= start) && (start < 0x8000)) {
120  // ROM at 0x4000-0x7FFF
121  return MSXFDC::getReadCacheLine(start);
122  } else {
123  return unmappedRead;
124  }
125 }
126 
127 void VictorFDC::writeMem(word address, byte value, EmuTime::param time)
128 {
129  //PRT_DEBUG("VictorFDC write 0x" << hex << (int)address << " 0x" << (int)value << dec);
130  switch (address) {
131  case 0x7FF8:
132  controller->setCommandReg(value, time);
133  break;
134  case 0x7FF9:
135  controller->setTrackReg(value, time);
136  break;
137  case 0x7FFA:
138  controller->setSectorReg(value, time);
139  break;
140  case 0x7FFB:
141  controller->setDataReg(value, time);
142  break;
143  case 0x7FFC:
145  if ((value & DRIVE_DISABLE) != 0) {
147  } else {
148  drive = ((value & DRIVE_SELECT) != 0) ? DriveMultiplexer::DRIVE_B : DriveMultiplexer::DRIVE_A;
149  }
150  multiplexer->selectDrive(drive, time);
151  multiplexer->setSide((value & SIDE_SELECT) != 0);
152  multiplexer->setMotor((drive == DriveMultiplexer::DRIVE_A) ? ((value & DRIVE_A_MOTOR) != 0) : ((value & DRIVE_B_MOTOR) != 0), time); // this is not 100% correct: the motors can be controlled independently via bit 0 and 1
153  // back up for reading:
154  driveControls = value & (DRIVE_A_MOTOR | DRIVE_B_MOTOR | DRIVE_SELECT | SIDE_SELECT | DRIVE_DISABLE);
155  break;
156  }
157 }
158 
160 {
161  if ((address & CacheLine::HIGH) == (0x7FF8 & CacheLine::HIGH)) {
162  // FDC at 0x7FF8-0x7FFC
163  return nullptr;
164  } else {
165  return unmappedWrite;
166  }
167 }
168 
169 
170 template<typename Archive>
171 void VictorFDC::serialize(Archive& ar, unsigned /*version*/)
172 {
173  ar.template serializeBase<WD2793BasedFDC>(*this);
174  ar.serialize("driveControls", driveControls);
175 }
177 REGISTER_MSXDEVICE(VictorFDC, "VictorFDC");
178 
179 } // namespace openmsx