1 // license:BSD-3-Clause
2 // copyright-holders:AJR
3 /**********************************************************************
4 
5     SWTPC SS-50 I/O port interface
6 
7     The SS-50 bus is actually two buses in one: a 50-pin master bus
8     used by RAM boards and such, and a 30-pin I/O bus derived from it
9     either on the motherboard or a dedicated interface board, which
10     provides each of eight "interface" cards with its specific chip
11     select line and only a few address lines for register selection.
12     This 30-pin bus is what is emulated here.
13 
14     As originally introduced in the 6800 Computer System, the
15     interface bus only included two register select lines, just enough
16     to drive one MC6820 PIA. No defined signals were placed on the
17     first two lines, which cards were permitted to use for any
18     purpose. The original MP-B motherboard also quite wastefully
19     reserved 8K (technically 4K) of address space to map a maximum of
20     32 read/write registers. The later MC6809-oriented systems not
21     only reduced the I/O segment to a selectable 1K, but appropriated
22     the two formerly undefined lines for two additional register
23     select lines, making it possible to use more complex interface
24     cards but breaking compatibility with some earlier ones.
25 
26     An unusual feature of the SS-50 bus is the presence of five baud
27     rate frequencies, selected from among the (inverted) outputs of
28     a MC14411 Bit Rate Generator. The 6800 Computer System provided
29     only rates between 110 and 1200 (multiplied by 16), and also used
30     the MC14411's master frequency to generate the CPU clocks. The
31     MP-09 CPU board retained the MC14411 at first, but provided an
32     independent XTAL for the MC6809 and jumpers to select higher
33     baud rates. Later the MC14411 was removed from the CPU board so
34     the five baud rate lines on the 50-pin bus could be reused to
35     provide 20-bit addressing and DMA. This was accomplished by
36     adding a separate MP-ID Interface Driver Board to decode I/O
37     accesses (and optionally slow them down to allow old 1 MHz
38     peripherals to be used with a faster CPU), generate the baud
39     rates (whose selection was changed yet again) from a dedicated
40     MC14411, and provide a few I/O functions of its own.
41 
42 ***********************************************************************
43 
44                         +-+
45                      30 |o| RS2 (originally UD3)
46                      29 |o| RS3 (originally UD4)
47                      28 |o| -16V (originally -12V)
48                      27 |o| +16V (originally +12V)
49                      26 |o| GND
50                      25 |o| GND
51                      24 |o| INDEX
52                      23 |o| /FIRQ (6800: /NMI)
53                      22 |o| /IRQ
54                      21 |o| RS0
55                      20 |o| RS1
56                      19 |o| D0
57                      18 |o| D1
58                      17 |o| D2
59                      16 |o| D3
60                      15 |o| D4
61                      14 |o| D5
62                      13 |o| D6
63                      12 |o| D7
64                      11 |o| E (6800: ϕ2)
65                      10 |o| R/W
66                       9 |o| +8V (unregulated)
67                       8 |o| +8V (unregulated)
68                       7 |o| 600b/1200b (originally 1200b)
69                       6 |o| 4800b (originally 600b)
70                       5 |o| 300b
71                       4 |o| 150b/9600b (originally 150b)
72                       3 |o| 110b
73                       2 |o| /RESET
74                       1 |o| I/O #
75                         +-+
76 
77 **********************************************************************/
78 
79 #include "emu.h"
80 #include "bus/ss50/interface.h"
81 
82 #include "bus/ss50/dc5.h"
83 #include "bus/ss50/mpc.h"
84 //#include "bus/ss50/mpl.h"
85 //#include "bus/ss50/mpr.h"
86 #include "bus/ss50/mps.h"
87 #include "bus/ss50/mps2.h"
88 #include "bus/ss50/mpt.h"
89 #include "bus/ss50/piaide.h"
90 
91 //**************************************************************************
92 //  GLOBAL VARIABLES
93 //**************************************************************************
94 
95 // device type definition
96 DEFINE_DEVICE_TYPE(SS50_INTERFACE, ss50_interface_port_device, "ss50_interface", "SS-50 Interface Port")
97 
98 //**************************************************************************
99 //  SS-50 INTERFACE PORT DEVICE
100 //**************************************************************************
101 
102 //-------------------------------------------------
103 //  ss50_interface_port_device - construction
104 //-------------------------------------------------
105 
ss50_interface_port_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)106 ss50_interface_port_device::ss50_interface_port_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
107 	device_t(mconfig, SS50_INTERFACE, tag, owner, clock),
108 	device_single_card_slot_interface<ss50_card_interface>(mconfig, *this),
109 	m_irq_cb(*this),
110 	m_firq_cb(*this),
111 	m_card(nullptr)
112 {
113 }
114 
115 //-------------------------------------------------
116 //  device_resolve_objects - resolve objects that
117 //  may be needed for other devices to set
118 //  initial conditions at start time
119 //-------------------------------------------------
120 
device_resolve_objects()121 void ss50_interface_port_device::device_resolve_objects()
122 {
123 	m_irq_cb.resolve_safe();
124 	m_firq_cb.resolve_safe();
125 
126 	m_card = get_card_device();
127 	if (m_card != nullptr)
128 		m_card->m_slot = this;
129 }
130 
131 //-------------------------------------------------
132 //  device_start - device-specific startup
133 //-------------------------------------------------
134 
device_start()135 void ss50_interface_port_device::device_start()
136 {
137 }
138 
139 //-------------------------------------------------
140 //  read - interface read access (pre-decoded)
141 //-------------------------------------------------
142 
read(offs_t offset)143 u8 ss50_interface_port_device::read(offs_t offset)
144 {
145 	if (m_card == nullptr)
146 	{
147 		if (!machine().side_effects_disabled())
148 			logerror("%s: Read from unspecified interface (RS = %X)\n", machine().describe_context(), offset);
149 		return 0xff;
150 	}
151 
152 	return m_card->register_read(offset);
153 }
154 
155 //-------------------------------------------------
156 //  write - interface write access (pre-decoded)
157 //-------------------------------------------------
158 
write(offs_t offset,u8 data)159 void ss50_interface_port_device::write(offs_t offset, u8 data)
160 {
161 	if (m_card == nullptr)
162 	{
163 		logerror("%s: Write to unspecified interface (RS = %X, D = %02X)\n", machine().describe_context(), offset, data);
164 		return;
165 	}
166 
167 	m_card->register_write(offset, data);
168 }
169 
170 //-------------------------------------------------
171 //  fN_w - baud rate clocks for serial interfaces
172 //-------------------------------------------------
173 
WRITE_LINE_MEMBER(ss50_interface_port_device::f110_w)174 WRITE_LINE_MEMBER(ss50_interface_port_device::f110_w)
175 {
176 	if (m_card != nullptr)
177 		m_card->f110_w(state);
178 }
179 
WRITE_LINE_MEMBER(ss50_interface_port_device::f150_9600_w)180 WRITE_LINE_MEMBER(ss50_interface_port_device::f150_9600_w)
181 {
182 	if (m_card != nullptr)
183 		m_card->f150_9600_w(state);
184 }
185 
WRITE_LINE_MEMBER(ss50_interface_port_device::f300_w)186 WRITE_LINE_MEMBER(ss50_interface_port_device::f300_w)
187 {
188 	if (m_card != nullptr)
189 		m_card->f300_w(state);
190 }
191 
WRITE_LINE_MEMBER(ss50_interface_port_device::f600_4800_w)192 WRITE_LINE_MEMBER(ss50_interface_port_device::f600_4800_w)
193 {
194 	if (m_card != nullptr)
195 		m_card->f600_4800_w(state);
196 }
197 
WRITE_LINE_MEMBER(ss50_interface_port_device::f600_1200_w)198 WRITE_LINE_MEMBER(ss50_interface_port_device::f600_1200_w)
199 {
200 	if (m_card != nullptr)
201 		m_card->f600_1200_w(state);
202 }
203 
204 //**************************************************************************
205 //  SS-50 CARD INTERFACE
206 //**************************************************************************
207 
208 template class device_finder<ss50_card_interface, false>;
209 template class device_finder<ss50_card_interface, true>;
210 
211 //-------------------------------------------------
212 //  ss50_card_interface - construction
213 //-------------------------------------------------
214 
ss50_card_interface(const machine_config & mconfig,device_t & device)215 ss50_card_interface::ss50_card_interface(const machine_config &mconfig, device_t &device) :
216 	device_interface(device, "ss50card"),
217 	m_slot(nullptr)
218 {
219 }
220 
interface_pre_start()221 void ss50_card_interface::interface_pre_start()
222 {
223 	if (!m_slot)
224 		throw device_missing_dependencies();
225 }
226 
ss50_default_2rs_devices(device_slot_interface & device)227 void ss50_default_2rs_devices(device_slot_interface &device)
228 {
229 	device.option_add("dc5", SS50_DC5);
230 	device.option_add("mpc", SS50_MPC);
231 	//device.option_add("mpl", SS50_MPL);
232 	//device.option_add("mpn", SS50_MPN);
233 	device.option_add("mps", SS50_MPS);
234 	device.option_add("mps2", SS50_MPS2);
235 	device.option_add("mpt", SS50_MPT);
236 	device.option_add("piaide", SS50_PIAIDE);
237 }
238