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