1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /**********************************************************************
4
5 Commodore 9060/9090 Hard Disk Drive emulation
6
7 **********************************************************************/
8
9 /*
10
11 Use the CHDMAN utility to create a 5MB image for D9060:
12
13 $ chdman createhd -o tm602s.chd -chs 153,4,32 -ss 256
14
15 or a 10MB image for D9090:
16
17 $ chdman createhd -o tm603s.chd -chs 153,6,32 -ss 256
18
19 Start the PET emulator with the D9060 attached on the IEEE-488 bus,
20 with the new CHD mounted:
21
22 $ mess pet8032 -ieee8 d9060 -hard tm602s.chd
23 $ mess pet8032 -ieee8 d9090 -hard tm603s.chd
24
25 Enter 'HEADER "LABEL",D0,I01' to format the hard drive.
26 Wait up to 1 hour and 20 minutes.
27
28 */
29
30 #include "emu.h"
31 #include "d9060.h"
32 #include "bus/scsi/d9060hd.h"
33
34
35
36 //**************************************************************************
37 // MACROS / CONSTANTS
38 //**************************************************************************
39
40 #define M6502_DOS_TAG "7e"
41 #define M6532_0_TAG "7f"
42 #define M6532_1_TAG "7g"
43
44 #define M6502_HDC_TAG "4a"
45 #define M6522_TAG "4b"
46
47 #define AM2910_TAG "9d"
48
49 #define SASIBUS_TAG "sasi"
50
51 enum
52 {
53 LED_POWER = 0,
54 LED_READY,
55 LED_ERROR
56 };
57
58
59
60 //**************************************************************************
61 // DEVICE DEFINITIONS
62 //**************************************************************************
63
64 DEFINE_DEVICE_TYPE(D9060, d9060_device, "d9060", "Commodore D9060")
65 DEFINE_DEVICE_TYPE(D9090, d9090_device, "d9090", "Commodore D9090")
66
67
68 //-------------------------------------------------
69 // ROM( d9060 )
70 //-------------------------------------------------
71
ROM_START(d9060)72 ROM_START( d9060 )
73 ROM_REGION( 0x4000, M6502_DOS_TAG, 0 )
74 ROM_DEFAULT_BIOS("rc")
75 ROM_SYSTEM_BIOS( 0, "ra", "Revision A" )
76 ROMX_LOAD( "300516-001.7c", 0x0000, 0x2000, NO_DUMP, ROM_BIOS(0) )
77 ROMX_LOAD( "300517-001.7d", 0x2000, 0x2000, CRC(566df630) SHA1(b1602dfff408b165ee52a6a4ca3e2ec27e689ba9), ROM_BIOS(0) )
78 ROM_SYSTEM_BIOS( 1, "rb", "Revision B" )
79 ROMX_LOAD( "300516-002.7c", 0x0000, 0x2000, CRC(2d758a14) SHA1(c959cc9dde84fc3d64e95e58a0a096a26d8107fd), ROM_BIOS(1) )
80 ROMX_LOAD( "300517-002.7d", 0x2000, 0x2000, CRC(f0382bc3) SHA1(0b0a8dc520f5b41ffa832e4a636b3d226ccbb7f1), ROM_BIOS(1) )
81 ROM_SYSTEM_BIOS( 2, "rc", "Revision C" )
82 ROMX_LOAD( "300516-003.7c", 0x0000, 0x2000, CRC(d6a3e88f) SHA1(bb1ddb5da94a86266012eca54818aa21dc4cef6a), ROM_BIOS(2) )
83 ROMX_LOAD( "300517-003.7d", 0x2000, 0x2000, CRC(2a9ad4ad) SHA1(4c17d014de48c906871b9b6c7d037d8736b1fd52), ROM_BIOS(2) )
84
85 ROM_REGION( 0x800, M6502_HDC_TAG, 0 )
86 ROM_LOAD( "300515-001.4c", 0x000, 0x800, CRC(99e096f7) SHA1(a3d1deb27bf5918b62b89c27fa3e488eb8f717a4) ) // Revision A
87 ROM_LOAD( "300515-002.4c", 0x000, 0x800, CRC(49adf4fb) SHA1(59dafbd4855083074ba8dc96a04d4daa5b76e0d6) ) // Revision B
88
89 ROM_REGION( 0x1400, AM2910_TAG, 0 )
90 ROM_LOAD( "44_1.5b", 0x0000, 0x0400, CRC(67a49dd3) SHA1(be39f55bc0ff9a508ec55224c52549856ad3270a) ) // 82S137
91 ROM_LOAD( "44_2.6b", 0x0400, 0x0400, CRC(f6d1bdbc) SHA1(bca7a96a60144c36eff1124485ec26df7cfa8143) ) // 82S137
92 ROM_LOAD( "44_3.7b", 0x0800, 0x0400, CRC(68af3a1f) SHA1(d3823a0d23e828a2dff6d89211fbcd7034112298) ) // 82S137
93 ROM_LOAD( "44_4.8b", 0x0c00, 0x0400, CRC(a767b1dc) SHA1(fff11b662c74040981822ccdcc8cbd0e22b517a9) ) // 82S137
94 ROM_LOAD( "44_5.9b", 0x1000, 0x0400, CRC(85743073) SHA1(95a48835bc2bd1c79fb1a63778de3807fb731ac6) ) // 82S137
95 ROM_END
96
97
98 //-------------------------------------------------
99 // rom_region - device-specific ROM region
100 //-------------------------------------------------
101
102 const tiny_rom_entry *d9060_device_base::device_rom_region() const
103 {
104 return ROM_NAME( d9060 );
105 }
106
107
main_mem(address_map & map)108 void d9060_device_base::main_mem(address_map &map)
109 {
110 map(0x0000, 0x007f).mirror(0x0100).m(m_riot0, FUNC(mos6532_new_device::ram_map));
111 map(0x0080, 0x00ff).mirror(0x0100).m(m_riot1, FUNC(mos6532_new_device::ram_map));
112 map(0x0200, 0x021f).mirror(0x0d60).m(m_riot0, FUNC(mos6532_new_device::io_map));
113 map(0x0280, 0x029f).mirror(0x0d60).m(m_riot1, FUNC(mos6532_new_device::io_map));
114 map(0x1000, 0x13ff).mirror(0x0c00).ram().share("share1");
115 map(0x2000, 0x23ff).mirror(0x0c00).ram().share("share2");
116 map(0x3000, 0x33ff).mirror(0x0c00).ram().share("share3");
117 map(0x4000, 0x43ff).mirror(0x0c00).ram().share("share4");
118 map(0xc000, 0xffff).rom().region(M6502_DOS_TAG, 0);
119 }
120
121
hdc_mem(address_map & map)122 void d9060_device_base::hdc_mem(address_map &map)
123 {
124 map.global_mask(0x1fff);
125 map(0x0000, 0x007f).mirror(0x300).ram();
126 map(0x0080, 0x008f).mirror(0x370).m(m_via, FUNC(via6522_device::map));
127 map(0x0400, 0x07ff).ram().share("share1");
128 map(0x0800, 0x0bff).ram().share("share2");
129 map(0x0c00, 0x0fff).ram().share("share3");
130 map(0x1000, 0x13ff).ram().share("share4");
131 map(0x1800, 0x1fff).rom().region(M6502_HDC_TAG, 0);
132 }
133
134
135 //-------------------------------------------------
136 // riot6532 0
137 //-------------------------------------------------
138
dio_r()139 uint8_t d9060_device_base::dio_r()
140 {
141 /*
142
143 bit description
144
145 PA0 DI0
146 PA1 DI1
147 PA2 DI2
148 PA3 DI3
149 PA4 DI4
150 PA5 DI5
151 PA6 DI6
152 PA7 DI7
153
154 */
155
156 return m_bus->dio_r();
157 }
158
159
dio_w(uint8_t data)160 void d9060_device_base::dio_w(uint8_t data)
161 {
162 /*
163
164 bit description
165
166 PB0 DO0
167 PB1 DO1
168 PB2 DO2
169 PB3 DO3
170 PB4 DO4
171 PB5 DO5
172 PB6 DO6
173 PB7 DO7
174
175 */
176
177 m_bus->dio_w(this, data);
178 }
179
180
181 //-------------------------------------------------
182 // riot6532 1
183 //-------------------------------------------------
184
riot1_pa_r()185 uint8_t d9060_device_base::riot1_pa_r()
186 {
187 /*
188
189 bit description
190
191 PA0
192 PA1
193 PA2
194 PA3
195 PA4
196 PA5 EOII
197 PA6 DAVI
198 PA7 _ATN
199
200 */
201
202 uint8_t data = 0;
203
204 // end or identify in
205 data |= m_bus->eoi_r() << 5;
206
207 // data valid in
208 data |= m_bus->dav_r() << 6;
209
210 // attention
211 data |= !m_bus->atn_r() << 7;
212
213 return data;
214 }
215
riot1_pa_w(uint8_t data)216 void d9060_device_base::riot1_pa_w(uint8_t data)
217 {
218 /*
219
220 bit description
221
222 PA0 ATNA
223 PA1 DACO
224 PA2 RFDO
225 PA3 EOIO
226 PA4 DAVO
227 PA5
228 PA6
229 PA7
230
231 */
232
233 // attention acknowledge
234 m_atna = BIT(data, 0);
235
236 // data accepted out
237 m_daco = BIT(data, 1);
238
239 // not ready for data out
240 m_rfdo = BIT(data, 2);
241
242 // end or identify out
243 m_bus->eoi_w(this, BIT(data, 3));
244
245 // data valid out
246 m_bus->dav_w(this, BIT(data, 4));
247
248 update_ieee_signals();
249 }
250
riot1_pb_r()251 uint8_t d9060_device_base::riot1_pb_r()
252 {
253 /*
254
255 bit description
256
257 PB0 device #
258 PB1 device #
259 PB2 device #
260 PB3
261 PB4
262 PB5
263 PB6 DACI
264 PB7 RFDI
265
266 */
267
268 uint8_t data = 0;
269
270 // device number selection
271 data |= m_slot->get_address() - 8;
272
273 // data accepted in
274 data |= m_bus->ndac_r() << 6;
275
276 // ready for data in
277 data |= m_bus->nrfd_r() << 7;
278
279 return data;
280 }
281
riot1_pb_w(uint8_t data)282 void d9060_device_base::riot1_pb_w(uint8_t data)
283 {
284 /*
285
286 bit description
287
288 PB0
289 PB1
290 PB2
291 PB3
292 PB4 DRIVE RDY
293 PB5 PWR ON AND NO ERRORS
294 PB6
295 PB7
296
297 */
298
299 // ready led
300 m_leds[LED_READY] = BIT(data, 4);
301
302 // power led
303 m_leds[LED_POWER] = BIT(data, 5);
304
305 // error led
306 m_leds[LED_ERROR] = !BIT(data, 5);
307 }
308
309
via_pb_w(uint8_t data)310 void d9060_device_base::via_pb_w(uint8_t data)
311 {
312 /*
313
314 bit description
315
316 PB0 SEL
317 PB1 RST
318 PB2 C/D
319 PB3 BUSY
320 PB4 J14 (1=9060, 0=9090)
321 PB5 J13
322 PB6 I/O
323 PB7 MSG
324
325 */
326
327 m_sasibus->write_sel(BIT(data, 0));
328 m_sasibus->write_rst(BIT(data, 1));
329 }
330
WRITE_LINE_MEMBER(d9060_device_base::ack_w)331 WRITE_LINE_MEMBER( d9060_device_base::ack_w )
332 {
333 m_sasibus->write_ack(!state);
334 }
335
WRITE_LINE_MEMBER(d9060_device_base::enable_w)336 WRITE_LINE_MEMBER( d9060_device_base::enable_w )
337 {
338 m_enable = state;
339
340 if( !m_enable )
341 {
342 m_sasi_data_out->write( m_data );
343 }
344 else
345 {
346 m_sasi_data_out->write( 0 );
347 }
348 }
349
scsi_data_w(uint8_t data)350 void d9060_device_base::scsi_data_w(uint8_t data)
351 {
352 m_data = data;
353
354 if( !m_enable )
355 {
356 m_sasi_data_out->write( m_data );
357 }
358 }
359
360
361 //-------------------------------------------------
362 // device_add_mconfig - add device configuration
363 //-------------------------------------------------
364
device_add_mconfig(machine_config & config)365 void d9060_device_base::device_add_mconfig(machine_config &config)
366 {
367 // DOS
368 M6502(config, m_maincpu, XTAL(4'000'000)/4);
369 m_maincpu->set_addrmap(AS_PROGRAM, &d9060_device::main_mem);
370
371 MOS6532_NEW(config, m_riot0, XTAL(4'000'000)/4);
372 m_riot0->pa_rd_callback().set(FUNC(d9060_device_base::dio_r));
373 m_riot0->pb_wr_callback().set(FUNC(d9060_device_base::dio_w));
374
375 MOS6532_NEW(config, m_riot1, XTAL(4'000'000)/4);
376 m_riot1->pa_rd_callback().set(FUNC(d9060_device_base::riot1_pa_r));
377 m_riot1->pa_wr_callback().set(FUNC(d9060_device_base::riot1_pa_w));
378 m_riot1->pb_rd_callback().set(FUNC(d9060_device_base::riot1_pb_r));
379 m_riot1->pb_wr_callback().set(FUNC(d9060_device_base::riot1_pb_w));
380 m_riot1->irq_wr_callback().set_inputline(m_maincpu, INPUT_LINE_IRQ0);
381
382 // controller
383 M6502(config, m_hdccpu, XTAL(4'000'000)/4);
384 m_hdccpu->set_addrmap(AS_PROGRAM, &d9060_device::hdc_mem);
385
386 VIA6522(config, m_via, XTAL(4'000'000)/4);
387 m_via->writepa_handler().set(FUNC(d9060_device_base::scsi_data_w));
388 m_via->writepb_handler().set(FUNC(d9060_device_base::via_pb_w));
389 m_via->ca2_handler().set(FUNC(d9060_device_base::ack_w));
390 m_via->cb2_handler().set(FUNC(d9060_device_base::enable_w));
391 m_via->irq_handler().set_inputline(m_hdccpu, M6502_IRQ_LINE);
392
393 SCSI_PORT(config, m_sasibus);
394 m_sasibus->req_handler().set(M6522_TAG, FUNC(via6522_device::write_ca1));
395 m_sasibus->cd_handler().set(M6522_TAG, FUNC(via6522_device::write_pb2));
396 m_sasibus->bsy_handler().set(M6522_TAG, FUNC(via6522_device::write_pb3));
397 m_sasibus->io_handler().set(M6522_TAG, FUNC(via6522_device::write_pb6));
398 m_sasibus->msg_handler().set(M6522_TAG, FUNC(via6522_device::write_pb7));
399 m_sasibus->data0_handler().set(M6522_TAG, FUNC(via6522_device::write_pa0));
400 m_sasibus->data1_handler().set(M6522_TAG, FUNC(via6522_device::write_pa1));
401 m_sasibus->data2_handler().set(M6522_TAG, FUNC(via6522_device::write_pa2));
402 m_sasibus->data3_handler().set(M6522_TAG, FUNC(via6522_device::write_pa3));
403 m_sasibus->data4_handler().set(M6522_TAG, FUNC(via6522_device::write_pa4));
404 m_sasibus->data5_handler().set(M6522_TAG, FUNC(via6522_device::write_pa5));
405 m_sasibus->data6_handler().set(M6522_TAG, FUNC(via6522_device::write_pa6));
406 m_sasibus->data7_handler().set(M6522_TAG, FUNC(via6522_device::write_pa7));
407
408 OUTPUT_LATCH(config, m_sasi_data_out);
409 m_sasibus->set_output_latch(*m_sasi_data_out);
410
411 m_sasibus->set_slot_device(1, "harddisk", D9060HD, DEVICE_INPUT_DEFAULTS_NAME(SCSI_ID_0));
412 }
413
414
415 //-------------------------------------------------
416 // INPUT_PORTS( d9060 )
417 //-------------------------------------------------
418
419 static INPUT_PORTS_START( d9060 )
420 PORT_START("ADDRESS")
421 PORT_DIPNAME( 0x07, 0x01, "Device Address" )
422 PORT_DIPSETTING( 0x00, "8" )
423 PORT_DIPSETTING( 0x01, "9" )
424 PORT_DIPSETTING( 0x02, "10" )
425 PORT_DIPSETTING( 0x03, "11" )
426 PORT_DIPSETTING( 0x04, "12" )
427 PORT_DIPSETTING( 0x05, "13" )
428 PORT_DIPSETTING( 0x06, "14" )
429 PORT_DIPSETTING( 0x07, "15" )
430 INPUT_PORTS_END
431
432
433 //-------------------------------------------------
434 // input_ports - device-specific input ports
435 //-------------------------------------------------
436
device_input_ports() const437 ioport_constructor d9060_device_base::device_input_ports() const
438 {
439 return INPUT_PORTS_NAME( d9060 );
440 }
441
442
443
444 //**************************************************************************
445 // INLINE HELPERS
446 //**************************************************************************
447
448 //-------------------------------------------------
449 // update_ieee_signals -
450 //-------------------------------------------------
451
update_ieee_signals()452 inline void d9060_device_base::update_ieee_signals()
453 {
454 int atn = m_bus->atn_r();
455 int nrfd = !(!(!(atn && m_atna) && m_rfdo) || !(atn || m_atna));
456 int ndac = !(m_daco || !(atn || m_atna));
457
458 m_bus->nrfd_w(this, nrfd);
459 m_bus->ndac_w(this, ndac);
460 }
461
462
463
464 //**************************************************************************
465 // LIVE DEVICE
466 //**************************************************************************
467
468 //-------------------------------------------------
469 // d9060_device_base - constructor
470 //-------------------------------------------------
471
d9060_device_base(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock,uint32_t variant)472 d9060_device_base::d9060_device_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, uint32_t variant)
473 : device_t(mconfig, type, tag, owner, clock)
474 , device_ieee488_interface(mconfig, *this)
475 , m_maincpu(*this, M6502_DOS_TAG)
476 , m_hdccpu(*this, M6502_HDC_TAG)
477 , m_riot0(*this, M6532_0_TAG)
478 , m_riot1(*this, M6532_1_TAG)
479 , m_via(*this, M6522_TAG)
480 , m_sasibus(*this, SASIBUS_TAG)
481 , m_sasi_data_out(*this, "sasi_data_out")
482 , m_address(*this, "ADDRESS")
483 , m_leds(*this, "led%u", 0U)
484 , m_rfdo(1)
485 , m_daco(1)
486 , m_atna(1)
487 , m_ifc(0)
488 , m_enable(0)
489 , m_data(0)
490 , m_variant(variant)
491 {
492 }
493
494
495 //-------------------------------------------------
496 // d9060_device - constructor
497 //-------------------------------------------------
498
d9060_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)499 d9060_device::d9060_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
500 : d9060_device_base(mconfig, D9060, tag, owner, clock, TYPE_9060)
501 {
502 }
503
504
505 //-------------------------------------------------
506 // d9090_device - constructor
507 //-------------------------------------------------
508
d9090_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)509 d9090_device::d9090_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
510 : d9060_device_base(mconfig, D9090, tag, owner, clock, TYPE_9090)
511 {
512 }
513
514
515 //-------------------------------------------------
516 // device_start - device-specific startup
517 //-------------------------------------------------
518
device_start()519 void d9060_device_base::device_start()
520 {
521 m_leds.resolve();
522
523 // state saving
524 save_item(NAME(m_rfdo));
525 save_item(NAME(m_daco));
526 save_item(NAME(m_atna));
527 save_item(NAME(m_enable));
528
529 m_via->write_pb4(!(m_variant == TYPE_9090)); // J14 (6 HEADS)
530 m_via->write_pb5(!(m_variant == TYPE_9060)); // J13 (4 HEADS)
531 }
532
533
534 //-------------------------------------------------
535 // device_reset - device-specific reset
536 //-------------------------------------------------
537
device_reset()538 void d9060_device_base::device_reset()
539 {
540 m_maincpu->set_input_line(M6502_SET_OVERFLOW, ASSERT_LINE);
541 m_maincpu->set_input_line(M6502_SET_OVERFLOW, CLEAR_LINE);
542
543 m_hdccpu->set_input_line(M6502_SET_OVERFLOW, ASSERT_LINE);
544
545 m_riot1->pa7_w(1);
546 }
547
548
549 //-------------------------------------------------
550 // ieee488_atn - attention
551 //-------------------------------------------------
552
ieee488_atn(int state)553 void d9060_device_base::ieee488_atn(int state)
554 {
555 update_ieee_signals();
556
557 m_riot1->pa7_w(state);
558 }
559
560
561 //-------------------------------------------------
562 // ieee488_ifc - interface clear
563 //-------------------------------------------------
564
ieee488_ifc(int state)565 void d9060_device_base::ieee488_ifc(int state)
566 {
567 if (!m_ifc && state)
568 {
569 device_reset();
570 }
571
572 m_ifc = state;
573 }
574