1 // license:BSD-3-Clause
2 // copyright-holders:MetalliC
3 /**********************************************************************
4
5 Didaktik D40/D80 disk interface
6 (C) 1991 Didaktik Skalica
7
8 useful commands:
9 RUN - boot disc
10 CAT - files list
11 LIST * - system information
12 LOAD *"filename" - load program
13
14 **********************************************************************/
15
16
17 #include "emu.h"
18 #include "d40.h"
19
20
21 //**************************************************************************
22 // DEVICE DEFINITIONS
23 //**************************************************************************
24
25 DEFINE_DEVICE_TYPE(SPECTRUM_D40, spectrum_d40_device, "spectrum_d40", "Didaktik D40")
26 DEFINE_DEVICE_TYPE(SPECTRUM_D80, spectrum_d80_device, "spectrum_d80", "Didaktik D80 (MDOS 1, 2793 FDC)")
27 DEFINE_DEVICE_TYPE(SPECTRUM_D80V2, spectrum_d80v2_device, "spectrum_d80v2", "Didaktik D80 (MDOS 2, 8272 FDC)")
28
29 //-------------------------------------------------
30 // INPUT_PORTS
31 //-------------------------------------------------
32
INPUT_PORTS_START(d40)33 INPUT_PORTS_START(d40)
34 PORT_START("BUTTON")
35 PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Snapshot Button") PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHANGED_MEMBER(DEVICE_SELF, spectrum_d40base_device, snapshot_button, 0)
36
37 PORT_START("JOY")
38 PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT) PORT_8WAY
39 PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT) PORT_8WAY
40 PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN) PORT_8WAY
41 PORT_BIT(0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP) PORT_8WAY
42 PORT_BIT(0x10, IP_ACTIVE_HIGH, IPT_BUTTON1)
43 PORT_BIT(0xe0, IP_ACTIVE_HIGH, IPT_UNUSED)
44 INPUT_PORTS_END
45
46 //-------------------------------------------------
47 // input_ports - device-specific input ports
48 //-------------------------------------------------
49
50 ioport_constructor spectrum_d40base_device::device_input_ports() const
51 {
52 return INPUT_PORTS_NAME(d40);
53 }
54
55 //-------------------------------------------------
56 // SLOT_INTERFACE( floppies )
57 //-------------------------------------------------
58
didaktik_floppies(device_slot_interface & device)59 static void didaktik_floppies(device_slot_interface &device)
60 {
61 device.option_add("35dd", FLOPPY_35_DD);
62 device.option_add("525dd", FLOPPY_525_DD);
63 }
64
65 //-------------------------------------------------
66 // floppy_format_type floppy_formats
67 //-------------------------------------------------
68
FLOPPY_FORMATS_MEMBER(spectrum_d40base_device::floppy_formats)69 FLOPPY_FORMATS_MEMBER(spectrum_d40base_device::floppy_formats)
70 FLOPPY_PC_FORMAT
71 FLOPPY_FORMATS_END
72
73 //-------------------------------------------------
74 // ROM
75 //-------------------------------------------------
76
77 ROM_START(d40)
78 ROM_REGION(0x4000, "rom", 0)
79 ROM_DEFAULT_BIOS("mdos11")
80 ROM_SYSTEM_BIOS(0, "mdos11", "MDOS 1.0 (1991)")
81 ROMX_LOAD("mdos10.bin", 0x0000, 0x4000, CRC(e6b70939) SHA1(308c4b5daf6bb1f05c68a447129d723da423326e), ROM_BIOS(0))
82 ROM_SYSTEM_BIOS(1, "mdos12", "MDOS 1.0+ (1992)") // possible unofficial modification
83 ROMX_LOAD("mdos10p.bin", 0x0000, 0x4000, CRC(92c45741) SHA1(b8473235feecff4eccbace56a90cf1d8c79506eb), ROM_BIOS(1))
84 ROM_END
85
86 ROM_START(d80v2)
87 ROM_REGION(0x4000, "rom", 0)
88 ROM_DEFAULT_BIOS("mdos2")
89 ROM_SYSTEM_BIOS(0, "mdos2", "MDOS 2.0 (1993)")
90 ROMX_LOAD("mdos20.bin", 0x0000, 0x4000, CRC(9e79d022) SHA1(e8d3355051fb287dd0dda34ba8824442130c8254), ROM_BIOS(0))
91 ROM_END
92
93 //-------------------------------------------------
94 // device_add_mconfig - add device configuration
95 //-------------------------------------------------
96
97 void spectrum_d40_device::device_add_mconfig(machine_config &config)
98 {
99 WD2797(config, m_fdc, 4_MHz_XTAL / 4);
100 m_fdc->intrq_wr_callback().set(FUNC(spectrum_d40_device::fdc_intrq_w));
101 m_fdc->drq_wr_callback().set(FUNC(spectrum_d40_device::fdc_drq_w));
102 FLOPPY_CONNECTOR(config, "fdc:0", didaktik_floppies, "525dd", spectrum_d40_device::floppy_formats).enable_sound(true);
103 FLOPPY_CONNECTOR(config, "fdc:1", didaktik_floppies, "525dd", spectrum_d40_device::floppy_formats).enable_sound(true);
104
105 I8255(config, m_ppi);
106 m_ppi->in_pa_callback().set_ioport("JOY");
107
108 /* software list */
109 //SOFTWARE_LIST(config, "flop_list").set_original("spectrum_d40_flop");
110 }
111
device_add_mconfig(machine_config & config)112 void spectrum_d80_device::device_add_mconfig(machine_config &config)
113 {
114 WD2797(config, m_fdc, 4_MHz_XTAL / 4);
115 m_fdc->intrq_wr_callback().set(FUNC(spectrum_d80_device::fdc_intrq_w));
116 m_fdc->drq_wr_callback().set(FUNC(spectrum_d80_device::fdc_drq_w));
117 FLOPPY_CONNECTOR(config, "fdc:0", didaktik_floppies, "35dd", spectrum_d80_device::floppy_formats).enable_sound(true);
118 FLOPPY_CONNECTOR(config, "fdc:1", didaktik_floppies, "35dd", spectrum_d80_device::floppy_formats).enable_sound(true);
119
120 I8255(config, m_ppi);
121
122 /* software list */
123 //SOFTWARE_LIST(config, "flop_list").set_original("spectrum_d40_flop");
124 }
125
device_add_mconfig(machine_config & config)126 void spectrum_d80v2_device::device_add_mconfig(machine_config &config)
127 {
128 WD37C65C(config, m_fdc, 16_MHz_XTAL); // actually GM82C765B
129 FLOPPY_CONNECTOR(config, "fdc:0", didaktik_floppies, "35dd", spectrum_d80v2_device::floppy_formats).enable_sound(true);
130 FLOPPY_CONNECTOR(config, "fdc:1", didaktik_floppies, "35dd", spectrum_d80v2_device::floppy_formats).enable_sound(true);
131
132 I8255(config, m_ppi);
133
134 /* software list */
135 //SOFTWARE_LIST(config, "flop_list").set_original("spectrum_d40_flop");
136 }
137
device_rom_region() const138 const tiny_rom_entry *spectrum_d40_device::device_rom_region() const
139 {
140 return ROM_NAME(d40);
141 }
142
device_rom_region() const143 const tiny_rom_entry *spectrum_d80v2_device::device_rom_region() const
144 {
145 return ROM_NAME(d80v2);
146 }
147
148 //**************************************************************************
149 // LIVE DEVICE
150 //**************************************************************************
151
152 //-------------------------------------------------
153 // spectrum_d40base_device - constructor
154 //-------------------------------------------------
155
spectrum_d40base_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)156 spectrum_d40base_device::spectrum_d40base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
157 : device_t(mconfig, type, tag, owner, clock)
158 , device_spectrum_expansion_interface(mconfig, *this)
159 , m_rom(*this, "rom")
160 , m_ppi(*this, "ppi")
161 , m_snap(*this, "BUTTON")
162 {
163 }
164
spectrum_d40_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)165 spectrum_d40_device::spectrum_d40_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
166 : spectrum_d40base_device(mconfig, SPECTRUM_D40, tag, owner, clock)
167 , m_fdc(*this, "fdc")
168 , m_floppy(*this, "fdc:%u", 0)
169 {
170 }
171
spectrum_d40_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)172 spectrum_d40_device::spectrum_d40_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
173 :spectrum_d40base_device(mconfig, type, tag, owner, clock)
174 , m_fdc(*this, "fdc")
175 , m_floppy(*this, "fdc:%u", 0)
176 {
177 }
178
spectrum_d80_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)179 spectrum_d80_device::spectrum_d80_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
180 : spectrum_d40_device(mconfig, SPECTRUM_D80, tag, owner, clock)
181 {
182 }
183
spectrum_d80v2_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)184 spectrum_d80v2_device::spectrum_d80v2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
185 : spectrum_d40base_device(mconfig, SPECTRUM_D80V2, tag, owner, clock)
186 , m_fdc(*this, "fdc")
187 , m_floppy(*this, "fdc:%u", 0)
188 {
189 }
190
191 //-------------------------------------------------
192 // device_start - device-specific startup
193 //-------------------------------------------------
194
device_start()195 void spectrum_d40base_device::device_start()
196 {
197 std::fill(std::begin(m_ram), std::end(m_ram), 0);
198 save_item(NAME(m_romcs));
199 save_item(NAME(m_ram));
200 save_item(NAME(m_snap_flag));
201 save_item(NAME(m_8255_reset));
202 save_item(NAME(m_8255_enable));
203 }
204
205 //-------------------------------------------------
206 // device_reset - device-specific reset
207 //-------------------------------------------------
208
device_reset()209 void spectrum_d40base_device::device_reset()
210 {
211 m_romcs = 0;
212 m_snap_flag = 0;
213 m_8255_reset = 0;
214 m_8255_enable = 0;
215 }
216
217
218 //**************************************************************************
219 // IMPLEMENTATION spectrum_d40base_device
220 //**************************************************************************
221
READ_LINE_MEMBER(spectrum_d40base_device::romcs)222 READ_LINE_MEMBER(spectrum_d40base_device::romcs)
223 {
224 return m_romcs;
225 }
226
pre_opcode_fetch(offs_t offset)227 void spectrum_d40base_device::pre_opcode_fetch(offs_t offset)
228 {
229 if (!machine().side_effects_disabled())
230 {
231 switch (offset)
232 {
233 case 0x0000:
234 case 0x0008:
235 m_romcs = 1;
236 nmi_check();
237 break;
238 case 0x0066:
239 if (!m_romcs)
240 {
241 m_romcs = 1;
242 m_snap_flag = 1;
243 nmi_check();
244 }
245 break;
246 case 0x1700:
247 if (!m_snap_flag)
248 m_romcs = 0;
249 nmi_check();
250 break;
251 }
252 }
253 }
254
iorq_r(offs_t offset)255 uint8_t spectrum_d40base_device::iorq_r(offs_t offset)
256 {
257 uint8_t data = 0xff;
258
259 switch (offset & 0xf9)
260 {
261 case 0x81: // FDC
262 data = fdc0_r(offset);
263 break;
264 case 0x89: // FDC
265 data = fdc1_r(offset);
266 break;
267 }
268
269 if (!BIT(offset, 7) && m_8255_enable) // 1F/3F/5F/7F
270 data = m_ppi->read((offset >> 5) & 3);
271
272 return data;
273 }
274
iorq_w(offs_t offset,uint8_t data)275 void spectrum_d40base_device::iorq_w(offs_t offset, uint8_t data)
276 {
277 switch (offset & 0xf9)
278 {
279 case 0x81: // FDC
280 fdc0_w(offset, data);
281 break;
282 case 0x89: // control port
283 fdc1_w(offset, data);
284 break;
285 case 0x91: // PPI reset
286 m_8255_reset = BIT(data, 5);
287 if (!m_8255_reset)
288 {
289 m_ppi->reset();
290 m_8255_enable = 0;
291 }
292 break;
293 case 0x99: // PPI enable
294 if (m_8255_reset)
295 m_8255_enable = BIT(data, 4);
296 break;
297 }
298
299 if (!BIT(offset, 7) && m_8255_enable) // 1F/3F/5F/7F
300 m_ppi->write((offset >> 5) & 3, data);
301 }
302
mreq_r(offs_t offset)303 uint8_t spectrum_d40base_device::mreq_r(offs_t offset)
304 {
305 if (m_snap_flag && offset == 0x66)
306 {
307 m_snap_flag = 0; // hacky, real hardware reset this latch by Z80 /WR line
308 return 0xc7; // RST 0 inject
309 }
310
311 uint8_t data = 0xff;
312
313 if (m_romcs)
314 {
315 if (offset < 0x3800)
316 data = m_rom->base()[offset];
317 else
318 data = m_ram[offset & 0x7ff];
319 }
320
321 return data;
322 }
323
mreq_w(offs_t offset,uint8_t data)324 void spectrum_d40base_device::mreq_w(offs_t offset, uint8_t data)
325 {
326 if (m_romcs)
327 {
328 if ((offset & 0xf800) == 0x3800)
329 m_ram[offset & 0x7ff] = data;
330 }
331 }
332
INPUT_CHANGED_MEMBER(spectrum_d40base_device::snapshot_button)333 INPUT_CHANGED_MEMBER(spectrum_d40base_device::snapshot_button)
334 {
335 nmi_check();
336 }
337
nmi_check()338 void spectrum_d40base_device::nmi_check()
339 {
340 int state = CLEAR_LINE;
341
342 if (!m_romcs && m_snap->read())
343 state = ASSERT_LINE;
344
345 m_slot->nmi_w(state);
346 }
347
348 //**************************************************************************
349 // IMPLEMENTATION spectrum_d40_device
350 //**************************************************************************
351
device_start()352 void spectrum_d40_device::device_start()
353 {
354 spectrum_d40base_device::device_start();
355 save_item(NAME(m_control));
356 save_item(NAME(m_intrq));
357 save_item(NAME(m_drq));
358 }
359
device_reset()360 void spectrum_d40_device::device_reset()
361 {
362 spectrum_d40base_device::device_reset();
363 m_control = 0;
364 m_intrq = 0;
365 m_drq = 0;
366 }
367
fdc0_r(offs_t offset)368 uint8_t spectrum_d40_device::fdc0_r(offs_t offset)
369 {
370 return m_fdc->read((offset >> 1) & 0x03);
371 }
372
fdc0_w(offs_t offset,uint8_t data)373 void spectrum_d40_device::fdc0_w(offs_t offset, uint8_t data)
374 {
375 m_fdc->write((offset >> 1) & 0x03, data);
376 }
377
fdc1_w(offs_t offset,uint8_t data)378 void spectrum_d40_device::fdc1_w(offs_t offset, uint8_t data)
379 {
380 m_control = data;
381
382 floppy_image_device* floppy = nullptr;
383 if (BIT(data, 0))
384 floppy = m_floppy[0]->get_device();
385 else if (BIT(data, 1))
386 floppy = m_floppy[1]->get_device();
387 m_fdc->set_floppy(floppy);
388
389 m_floppy[0]->get_device()->mon_w(BIT(data, 2) ? 0 : 1);
390 m_floppy[1]->get_device()->mon_w(BIT(data, 3) ? 0 : 1);
391
392 nmi_check();
393 }
394
fdc_intrq_w(int state)395 void spectrum_d40_device::fdc_intrq_w(int state)
396 {
397 m_intrq = state;
398 nmi_check();
399 }
400
fdc_drq_w(int state)401 void spectrum_d40_device::fdc_drq_w(int state)
402 {
403 m_drq = state;
404 nmi_check();
405 }
406
nmi_check()407 void spectrum_d40_device::nmi_check()
408 {
409 int state = CLEAR_LINE;
410
411 if (!m_romcs && m_snap->read())
412 state = ASSERT_LINE;
413
414 if (m_intrq && BIT(m_control, 7))
415 state = ASSERT_LINE;
416
417 if (m_drq && BIT(m_control, 6))
418 state = ASSERT_LINE;
419
420 m_slot->nmi_w(state);
421 }
422
423 //**************************************************************************
424 // IMPLEMENTATION spectrum_d80v2_device
425 //**************************************************************************
426
pre_opcode_fetch(offs_t offset)427 void spectrum_d80v2_device::pre_opcode_fetch(offs_t offset)
428 {
429 if (!machine().side_effects_disabled())
430 {
431 switch (offset)
432 {
433 case 0x0000:
434 case 0x0008:
435 case 0x0066:
436 m_romcs = 1;
437 nmi_check();
438 break;
439 case 0x1700:
440 m_romcs = 0;
441 nmi_check();
442 break;
443 }
444 }
445 }
446
fdc0_r(offs_t offset)447 uint8_t spectrum_d80v2_device::fdc0_r(offs_t offset)
448 {
449 return BIT(offset, 2) ? m_fdc->fifo_r() : m_fdc->msr_r();
450 }
451
fdc1_r(offs_t offset)452 uint8_t spectrum_d80v2_device::fdc1_r(offs_t offset)
453 {
454 return m_fdc->dor_r();
455 }
456
fdc0_w(offs_t offset,uint8_t data)457 void spectrum_d80v2_device::fdc0_w(offs_t offset, uint8_t data)
458 {
459 if (BIT(offset, 2))
460 m_fdc->fifo_w(data);
461 }
462
fdc1_w(offs_t offset,uint8_t data)463 void spectrum_d80v2_device::fdc1_w(offs_t offset, uint8_t data)
464 {
465 m_fdc->dor_w(data);
466 }
467
mreq_r(offs_t offset)468 uint8_t spectrum_d80v2_device::mreq_r(offs_t offset)
469 {
470 uint8_t data = 0xff;
471
472 if (m_romcs)
473 {
474 if (offset < 0x3800)
475 data = m_rom->base()[offset];
476 else
477 data = m_ram[offset & 0x7ff];
478 }
479
480 return data;
481 }
482