1 // license:BSD-3-Clause
2 // copyright-holders:MetalliC
3 /*********************************************************************
4
5 Kempston Disc Interface
6 (c) Abbeydale Designers ltd 1985
7
8 Known clones:
9 Sandy Disco Vers. 3
10
11 Few useful K-DOS commands (should be preceded with PRINT #4: ):
12 CAT - disc file list
13 LOAD "filename" - load and run program
14 COPY - tape to disc transfer utility
15 FORMAT "discname": PRINT drive#, tracks#, sides#, steprate - format disc
16
17 Manual https://archive.org/download/World_of_Spectrum_June_2017_Mirror/World%20of%20Spectrum%20June%202017%20Mirror.zip/World%20of%20Spectrum%20June%202017%20Mirror/sinclair/hardware-info/k/KempstonDiscInterface_Manual.pdf
18
19 Notes/TODO:
20 - schematics is missing, actual I/O ports decode might be not right
21 - find out port 0xDF 3 MSB bits wiring, probably FDC /DDEN, /MR
22 - implement onboard Kempston Centronics E interace and joystick port
23 - add more docs/information
24
25 *********************************************************************
26
27 Watford SP-DOS Interface
28 (c) Abbeydale Designers ltd 1984
29
30 Earlier version of Kempston Disc, uses 2Kbyte ROM with small boot loader, same FDC ports but slightly different paging.
31 Require "System disk" with DOS to function, which is not dumped / missing at the moment.
32
33 *********************************************************************/
34
35 #include "emu.h"
36 #include "kempdisc.h"
37
38
39 /***************************************************************************
40 DEVICE DEFINITIONS
41 ***************************************************************************/
42
43 DEFINE_DEVICE_TYPE(SPECTRUM_KEMPDISC, spectrum_kempdisc_device, "spectrum_kempdisc", "Kempston Disc Interface")
44 DEFINE_DEVICE_TYPE(SPECTRUM_SPDOS, spectrum_spdos_device, "spectrum_spdos", "Watford SP-DOS Interface")
45
46
47 //-------------------------------------------------
48 // SLOT_INTERFACE( floppies )
49 //-------------------------------------------------
50
kempdisc_floppies(device_slot_interface & device)51 static void kempdisc_floppies(device_slot_interface &device)
52 {
53 device.option_add("525dd", FLOPPY_525_DD);
54 device.option_add("525qd", FLOPPY_525_QD);
55 device.option_add("35dd", FLOPPY_35_DD);
56 device.option_add("3dsdd", FLOPPY_3_DSDD);
57 }
58
59 //-------------------------------------------------
60 // floppy_format_type floppy_formats
61 //-------------------------------------------------
62
FLOPPY_FORMATS_MEMBER(spectrum_kempdisc_device::floppy_formats)63 FLOPPY_FORMATS_MEMBER(spectrum_kempdisc_device::floppy_formats)
64 FLOPPY_DSK_FORMAT
65 FLOPPY_FORMATS_END
66
67 //-------------------------------------------------
68 // ROM( kempdisc )
69 //-------------------------------------------------
70
71 ROM_START(kempdisc)
72 ROM_REGION(0x2000, "rom", 0)
73 ROM_DEFAULT_BIOS("kd21")
74
75 // original
76 ROM_SYSTEM_BIOS(0, "kd20", "K-DOS v2.0")
77 ROMX_LOAD("kd20.rom", 0x0000, 0x2000, CRC(244816a7) SHA1(b08e0e30f1db4f57d38b112be0115256528c6621), ROM_BIOS(0))
78 ROM_SYSTEM_BIOS(1, "kd21", "K-DOS v2.1")
79 ROMX_LOAD("kd21.rom", 0x0000, 0x2000, CRC(3a0705eb) SHA1(adebc46c1b6718eaed7e2844506011787117cb05), ROM_BIOS(1))
80 //ROMX_LOAD("kd21.rom", 0x0000, 0x2000, CRC(d18fb812) SHA1(b3e00bc4111ef6311789159024fb4cd25c32a72f), ROM_BIOS(1)) // bad dump
81 ROM_SYSTEM_BIOS(2, "kd21it", "K-DOS v2.1 Italian") // copyrights and texts changed and translated
82 ROMX_LOAD("kd21it.rom", 0x0000, 0x2000, CRC(f8ccdf8a) SHA1(4a75fb4951d74e254c230d56b5566c924b3c38f6), ROM_BIOS(2))
83 ROM_END
84
85 ROM_START(spdos)
86 ROM_REGION(0x0800, "rom", 0)
87 ROM_LOAD("spdos.rom", 0x0000, 0x0800, CRC(87b954a3) SHA1(bb0706cf1538da8acd12b8c9cd2cd75ca689ec44))
88 ROM_END
89
90 //-------------------------------------------------
91 // device_add_mconfig - add device configuration
92 //-------------------------------------------------
93
94 void spectrum_kempdisc_device::device_add_mconfig(machine_config &config)
95 {
96 WD1770(config, m_fdc, 16_MHz_XTAL / 2);
97
98 FLOPPY_CONNECTOR(config, "fdc:0", kempdisc_floppies, "525qd", spectrum_kempdisc_device::floppy_formats).enable_sound(true);
99 FLOPPY_CONNECTOR(config, "fdc:1", kempdisc_floppies, "525qd", spectrum_kempdisc_device::floppy_formats).enable_sound(true);
100 FLOPPY_CONNECTOR(config, "fdc:2", kempdisc_floppies, nullptr, spectrum_kempdisc_device::floppy_formats).enable_sound(true);
101 FLOPPY_CONNECTOR(config, "fdc:3", kempdisc_floppies, nullptr, spectrum_kempdisc_device::floppy_formats).enable_sound(true);
102
103 // passthru
104 SPECTRUM_EXPANSION_SLOT(config, m_exp, spectrum_expansion_devices, nullptr);
105 m_exp->irq_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::irq_w));
106 m_exp->nmi_handler().set(DEVICE_SELF_OWNER, FUNC(spectrum_expansion_slot_device::nmi_w));
107 }
108
device_rom_region() const109 const tiny_rom_entry *spectrum_kempdisc_device::device_rom_region() const
110 {
111 return ROM_NAME(kempdisc);
112 }
113
device_rom_region() const114 const tiny_rom_entry *spectrum_spdos_device::device_rom_region() const
115 {
116 return ROM_NAME(spdos);
117 }
118
119
120 //**************************************************************************
121 // LIVE DEVICE
122 //**************************************************************************
123
124 //-------------------------------------------------
125 // spectrum_kempdisc_device - constructor
126 //-------------------------------------------------
127
spectrum_kempdisc_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)128 spectrum_kempdisc_device::spectrum_kempdisc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
129 : device_t(mconfig, type, tag, owner, clock)
130 , device_spectrum_expansion_interface(mconfig, *this)
131 , m_rom(*this, "rom")
132 , m_fdc(*this, "fdc")
133 , m_floppy(*this, "fdc:%u", 0)
134 , m_exp(*this, "exp")
135 // , m_control(0)
136 {
137 }
138
spectrum_kempdisc_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)139 spectrum_kempdisc_device::spectrum_kempdisc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
140 : spectrum_kempdisc_device(mconfig, SPECTRUM_KEMPDISC, tag, owner, clock)
141 {
142 }
143
spectrum_spdos_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)144 spectrum_spdos_device::spectrum_spdos_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
145 : spectrum_kempdisc_device(mconfig, SPECTRUM_SPDOS, tag, owner, clock)
146 {
147 }
148
149 //-------------------------------------------------
150 // device_start - device-specific startup
151 //-------------------------------------------------
152
device_start()153 void spectrum_kempdisc_device::device_start()
154 {
155 save_item(NAME(m_romcs));
156 // save_item(NAME(m_control));
157 }
158
159 //-------------------------------------------------
160 // device_reset - device-specific reset
161 //-------------------------------------------------
162
device_reset()163 void spectrum_kempdisc_device::device_reset()
164 {
165 m_romcs = 1;
166 }
167
168 //**************************************************************************
169 // IMPLEMENTATION
170 //**************************************************************************
171
READ_LINE_MEMBER(spectrum_kempdisc_device::romcs)172 READ_LINE_MEMBER(spectrum_kempdisc_device::romcs)
173 {
174 return m_romcs | m_exp->romcs();
175 }
176
177
iorq_r(offs_t offset)178 uint8_t spectrum_kempdisc_device::iorq_r(offs_t offset)
179 {
180 uint8_t data = m_exp->iorq_r(offset);
181
182 switch (offset & 0xff)
183 {
184 case 0xe5: case 0xe7: case 0xed: case 0xef:
185 data &= m_fdc->read(BIT(offset, 1) | (BIT(offset, 3) << 1));
186 break;
187 }
188
189 return data;
190 }
191
iorq_w(offs_t offset,uint8_t data)192 void spectrum_kempdisc_device::iorq_w(offs_t offset, uint8_t data)
193 {
194 switch (offset & 0xff)
195 {
196 case 0xe5: case 0xe7: case 0xed: case 0xef:
197 m_fdc->write(BIT(offset, 1) | (BIT(offset, 3) << 1), data);
198 break;
199 case 0xdf:
200 {
201 floppy_image_device* floppy = nullptr;
202 for (int i = 1; i < 5; i++)
203 if (BIT(data, i))
204 {
205 floppy = m_floppy[i - 1]->get_device();
206 break;
207 }
208
209 // m_control = data;
210 m_fdc->set_floppy(floppy);
211 if (floppy) floppy->ss_w(BIT(data, 0));
212 if (data & 0xe0)
213 logerror("port DF unhandled %02X\n", data);
214 }
215 break;
216 case 0xfd:
217 m_romcs = 1;
218 break;
219 case 0xd7:
220 m_romcs = 0;
221 break;
222 }
223
224 m_exp->iorq_w(offset, data);
225 }
226
mreq_r(offs_t offset)227 uint8_t spectrum_kempdisc_device::mreq_r(offs_t offset)
228 {
229 uint8_t data = 0xff;
230
231 if (m_romcs)
232 data = m_rom->base()[offset & 0x1fff];
233
234 if (m_exp->romcs())
235 data &= m_exp->mreq_r(offset);
236
237 return data;
238 }
239
240
iorq_w(offs_t offset,uint8_t data)241 void spectrum_spdos_device::iorq_w(offs_t offset, uint8_t data)
242 {
243 switch (offset & 0xff)
244 {
245 case 0xe5: case 0xe7: case 0xed: case 0xef:
246 m_fdc->write(BIT(offset, 1) | (BIT(offset, 3) << 1), data);
247 break;
248 case 0xdf:
249 {
250 floppy_image_device* floppy = nullptr;
251 for (int i = 1; i < 5; i++)
252 if (BIT(data, i))
253 {
254 floppy = m_floppy[i - 1]->get_device();
255 break;
256 }
257
258 // m_control = data;
259 m_fdc->set_floppy(floppy);
260 if (floppy) floppy->ss_w(BIT(data, 0));
261 if (data & 0xe0)
262 logerror("port DF unhandled %02X\n", data);
263 m_romcs = 0;
264 }
265 break;
266 // below probably is wrong/different for this device
267 case 0xfd:
268 m_romcs = 1;
269 break;
270 case 0xd7:
271 m_romcs = 0;
272 break;
273 }
274
275 m_exp->iorq_w(offset, data);
276 }
277
mreq_r(offs_t offset)278 uint8_t spectrum_spdos_device::mreq_r(offs_t offset)
279 {
280 uint8_t data = 0xff;
281
282 if (m_romcs)
283 data = m_rom->base()[offset & 0x7ff];
284
285 if (m_exp->romcs())
286 data &= m_exp->mreq_r(offset);
287
288 return data;
289 }
290