1 // license:BSD-3-Clause
2 // copyright-holders:Nigel Barnes
3 /**********************************************************************
4 
5     Acorn SCSI Host Adaptor
6 
7     Known SCSI controller boards used:
8       Adaptec ACB-4000A
9 
10     Known SCSI devices using adaptor:
11       SCSI ID 0 - Acorn Winchester 110: Seagate ST412 + Adaptec ACB-4000A
12                   Acorn Winchester 120: NEC D5126 + Adaptec ACB-4000A
13                   Acorn Winchester 130: Rodime R0203E + Adaptec ACB-4000A
14       SCSI ID 1 - Digistore Tape Streamer: Archive 2060S
15 
16     Compatible 3rd party Winchesters using Akhter Host Adaptor:
17       Technomatic 20MB: Seagate ST225 + Adaptec ACB-4070
18       Technomatic 30MB:
19       Technomatic 40MB:
20 
21     Additional notes:
22       The Digistore used a modified Acorn Host Adaptor, it re-mapped
23       the device to &FC44-47, from &FC40-43. This allows both the
24       Digistore and Winchester to co-exist.
25 
26     Useful CHD parameters:
27       10MB -chs 306,4,33   -ss=256
28       20MB -chs 612,4,33   -ss=256
29       30MB -chs 640,6,33   -ss=256
30      512MB -chs 3971,16,33 -ss 256
31 
32     TODO:
33     - test formatting, may require specific ACB-4000A commands.
34 
35 **********************************************************************/
36 
37 #include "emu.h"
38 #include "scsi.h"
39 #include "machine/nscsi_bus.h"
40 #include "bus/nscsi/devices.h"
41 
42 
43 //**************************************************************************
44 //  DEVICE DEFINITIONS
45 //**************************************************************************
46 
47 DEFINE_DEVICE_TYPE(BBC_SCSI, bbc_scsi_device, "bbc_scsi", "Acorn SCSI Host Adaptor");
48 DEFINE_DEVICE_TYPE(BBC_AWHD, bbc_awhd_device, "bbc_awhd", "Acorn Winchester Disc");
49 
50 
51 //-------------------------------------------------
52 //  device_add_mconfig - add device configuration
53 //-------------------------------------------------
54 
device_add_mconfig(machine_config & config)55 void bbc_scsi_device::device_add_mconfig(machine_config& config)
56 {
57 	NSCSI_BUS(config, "scsi");
58 	NSCSI_CONNECTOR(config, "scsi:0", default_scsi_devices, nullptr);
59 	NSCSI_CONNECTOR(config, "scsi:1", default_scsi_devices, nullptr);
60 	NSCSI_CONNECTOR(config, "scsi:7", default_scsi_devices, "scsicb", true)
61 		.option_add_internal("scsicb", NSCSI_CB)
62 		.machine_config([this](device_t* device) {
63 			downcast<nscsi_callback_device&>(*device).bsy_callback().set(*this, FUNC(bbc_scsi_device::bsy_w));
64 			downcast<nscsi_callback_device&>(*device).req_callback().set(*this, FUNC(bbc_scsi_device::req_w));
65 		});
66 }
67 
device_add_mconfig(machine_config & config)68 void bbc_awhd_device::device_add_mconfig(machine_config &config)
69 {
70 	bbc_scsi_device::device_add_mconfig(config);
71 
72 	/* Adaptec ACB-4000A */
73 	subdevice<nscsi_connector>("scsi:0")->set_default_option("harddisk");
74 	subdevice<nscsi_connector>("scsi:0")->set_fixed(true);
75 
76 	BBC_1MHZBUS_SLOT(config, m_1mhzbus, DERIVED_CLOCK(1, 1), bbc_1mhzbus_devices, nullptr);
77 	m_1mhzbus->irq_handler().set(m_1mhzbus, FUNC(bbc_1mhzbus_slot_device::irq_w));
78 	m_1mhzbus->nmi_handler().set(m_1mhzbus, FUNC(bbc_1mhzbus_slot_device::nmi_w));
79 }
80 
81 
82 //**************************************************************************
83 //  LIVE DEVICE
84 //**************************************************************************
85 
86 //-------------------------------------------------
87 //  bbc_scsi_device - constructor
88 //-------------------------------------------------
89 
bbc_scsi_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)90 bbc_scsi_device::bbc_scsi_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
91 	: device_t(mconfig, type, tag, owner, clock)
92 	, device_bbc_1mhzbus_interface(mconfig, *this)
93 	, m_scsi(*this, "scsi:7:scsicb")
94 {
95 }
96 
bbc_scsi_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)97 bbc_scsi_device::bbc_scsi_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock)
98 	: bbc_scsi_device(mconfig, BBC_SCSI, tag, owner, clock)
99 {
100 }
101 
bbc_awhd_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)102 bbc_awhd_device::bbc_awhd_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
103 	: bbc_scsi_device(mconfig, BBC_AWHD, tag, owner, clock)
104 	, m_1mhzbus(*this, "1mhzbus")
105 {
106 }
107 
108 //-------------------------------------------------
109 //  device_start - device-specific startup
110 //-------------------------------------------------
111 
device_start()112 void bbc_scsi_device::device_start()
113 {
114 	/* register for save states */
115 	save_item(NAME(m_irq_enable));
116 	save_item(NAME(m_irq_state));
117 }
118 
119 //**************************************************************************
120 //  IMPLEMENTATION
121 //**************************************************************************
122 
fred_r(offs_t offset)123 uint8_t bbc_scsi_device::fred_r(offs_t offset)
124 {
125 	uint8_t data = 0xff;
126 
127 	switch (offset)
128 	{
129 	case 0x40:
130 		data = m_scsi->read();
131 		m_scsi->ack_w(1);
132 		break;
133 	case 0x41:
134 		data = (m_scsi->msg_r() << 0)
135 			| (m_scsi->bsy_r() << 1)
136 			| (m_irq_state << 4)
137 			| (m_scsi->req_r() << 5)
138 			| (m_scsi->io_r() << 6)
139 			| (m_scsi->cd_r() << 7);
140 		break;
141 	}
142 
143 	return data;
144 }
145 
fred_w(offs_t offset,uint8_t data)146 void bbc_scsi_device::fred_w(offs_t offset, uint8_t data)
147 {
148 	switch (offset)
149 	{
150 	case 0x40:
151 		m_scsi->write(data);
152 		m_scsi->ack_w(1);
153 		break;
154 	case 0x42:
155 		m_scsi->sel_w(1);
156 		break;
157 	case 0x43:
158 		m_irq_enable = BIT(data, 0);
159 		break;
160 	}
161 }
162 
WRITE_LINE_MEMBER(bbc_scsi_device::bsy_w)163 WRITE_LINE_MEMBER(bbc_scsi_device::bsy_w)
164 {
165 	m_scsi->sel_w(0);
166 }
167 
WRITE_LINE_MEMBER(bbc_scsi_device::req_w)168 WRITE_LINE_MEMBER(bbc_scsi_device::req_w)
169 {
170 	m_scsi->ack_w(0);
171 
172 	m_irq_state = (m_irq_enable && !state) ? 0 : 1;
173 	m_slot->irq_w(m_irq_state ? CLEAR_LINE : ASSERT_LINE);
174 }
175 
176 
fred_r(offs_t offset)177 uint8_t bbc_awhd_device::fred_r(offs_t offset)
178 {
179 	uint8_t data = 0xff;
180 
181 	data &= bbc_scsi_device::fred_r(offset);
182 	data &= m_1mhzbus->fred_r(offset);
183 
184 	return data;
185 }
186 
fred_w(offs_t offset,uint8_t data)187 void bbc_awhd_device::fred_w(offs_t offset, uint8_t data)
188 {
189 	bbc_scsi_device::fred_w(offset, data);
190 	m_1mhzbus->fred_w(offset, data);
191 }
192 
jim_r(offs_t offset)193 uint8_t bbc_awhd_device::jim_r(offs_t offset)
194 {
195 	return m_1mhzbus->jim_r(offset);
196 }
197 
jim_w(offs_t offset,uint8_t data)198 void bbc_awhd_device::jim_w(offs_t offset, uint8_t data)
199 {
200 	m_1mhzbus->jim_w(offset, data);
201 }
202