1 // license:BSD-3-Clause
2 // copyright-holders:Curt Coder
3 /**********************************************************************
4 
5     Batteries Included BusCard cartridge emulation
6 
7     SYS 61000 -> Enable BASIC 4.0
8     SYS 61003 -> Disable BASIC 4.0
9     SYS 61006 -> Enter Machine Language Monitor
10 
11 **********************************************************************/
12 
13 #include "emu.h"
14 #include "buscard.h"
15 
16 
17 
18 //**************************************************************************
19 //  DEVICE DEFINITIONS
20 //**************************************************************************
21 
22 DEFINE_DEVICE_TYPE(C64_BUSCARD, c64_buscard_device, "c64_buscard", "C64 BusCard cartridge")
23 
24 
25 //-------------------------------------------------
26 //  ROM( buscard )
27 //-------------------------------------------------
28 
ROM_START(buscard)29 ROM_START( buscard )
30 	ROM_REGION( 0x8000, "rom", 0 )
31 	ROM_LOAD( "0.9.u1", 0x0000, 0x2000, CRC(175e8c96) SHA1(8fb4ba7e3d0b58dc01b66ef962955596f1b125b5) )
32 	//ROM_LOAD( "unpopulated.u13", 0x2000, 0x2000 )
33 	//ROM_LOAD( "unpopulated.u14", 0x4000, 0x2000 )
34 	//ROM_LOAD( "unpopulated.u15", 0x6000, 0x2000 )
35 ROM_END
36 
37 
38 //-------------------------------------------------
39 //  rom_region - device-specific ROM region
40 //-------------------------------------------------
41 
42 const tiny_rom_entry *c64_buscard_device::device_rom_region() const
43 {
44 	return ROM_NAME( buscard );
45 }
46 
47 
48 //-------------------------------------------------
49 //  INPUT_PORTS( buscard )
50 //-------------------------------------------------
51 
52 static INPUT_PORTS_START( buscard )
53 	PORT_START("S1")
54 	PORT_DIPNAME( 0x03, 0x00, "Device #4" ) PORT_DIPLOCATION("S1:1,2")
55 	PORT_DIPSETTING(    0x00, "Serial" )
56 	PORT_DIPSETTING(    0x01, "Parallel w/conv." )
57 	PORT_DIPSETTING(    0x02, "IEEE" )
58 	PORT_DIPSETTING(    0x03, "Parallel" )
59 	PORT_DIPNAME( 0x04, 0x04, "Device #5" ) PORT_DIPLOCATION("S1:3")
60 	PORT_DIPSETTING(    0x00, "IEEE" )
61 	PORT_DIPSETTING(    0x04, "Serial" )
62 	PORT_DIPNAME( 0x08, 0x08, "Device #6" ) PORT_DIPLOCATION("S1:4")
63 	PORT_DIPSETTING(    0x00, "IEEE" )
64 	PORT_DIPSETTING(    0x08, "Serial" )
65 	PORT_DIPNAME( 0x10, 0x10, "Device #7" ) PORT_DIPLOCATION("S1:5")
66 	PORT_DIPSETTING(    0x00, "IEEE" )
67 	PORT_DIPSETTING(    0x10, "Serial" )
68 	PORT_DIPNAME( 0x20, 0x20, "Device #8" ) PORT_DIPLOCATION("S1:6")
69 	PORT_DIPSETTING(    0x00, "IEEE" )
70 	PORT_DIPSETTING(    0x20, "Serial" )
71 	PORT_DIPNAME( 0x40, 0x40, "Device #9" ) PORT_DIPLOCATION("S1:7")
72 	PORT_DIPSETTING(    0x00, "IEEE" )
73 	PORT_DIPSETTING(    0x40, "Serial" )
74 	PORT_DIPNAME( 0x80, 0x80, "Device #10" ) PORT_DIPLOCATION("S1:8")
75 	PORT_DIPSETTING(    0x00, "IEEE" )
76 	PORT_DIPSETTING(    0x80, "Serial" )
77 INPUT_PORTS_END
78 
79 
80 //-------------------------------------------------
81 //  input_ports - device-specific input ports
82 //-------------------------------------------------
83 
device_input_ports() const84 ioport_constructor c64_buscard_device::device_input_ports() const
85 {
86 	return INPUT_PORTS_NAME( buscard );
87 }
88 
89 
90 //-------------------------------------------------
91 //  PPI interface
92 //-------------------------------------------------
93 
ppi_pa_r()94 uint8_t c64_buscard_device::ppi_pa_r()
95 {
96 	uint8_t data = 0xff;
97 
98 	if (!m_te)
99 	{
100 		data = m_ieee1->read();
101 	}
102 
103 	if (m_dipsw)
104 	{
105 		data = m_s1->read();
106 	}
107 
108 	return data;
109 }
110 
ppi_pa_w(uint8_t data)111 void c64_buscard_device::ppi_pa_w(uint8_t data)
112 {
113 	m_ieee1->write(data);
114 
115 	m_centronics->write_data0(BIT(data, 0));
116 	m_centronics->write_data1(BIT(data, 1));
117 	m_centronics->write_data2(BIT(data, 2));
118 	m_centronics->write_data3(BIT(data, 3));
119 	m_centronics->write_data4(BIT(data, 4));
120 	m_centronics->write_data5(BIT(data, 5));
121 	m_centronics->write_data6(BIT(data, 6));
122 	m_centronics->write_data7(BIT(data, 7));
123 }
124 
ppi_pb_w(uint8_t data)125 void c64_buscard_device::ppi_pb_w(uint8_t data)
126 {
127 	/*
128 
129 	    bit     description
130 
131 	    PB0     BASIC ROM bank bit 0
132 	    PB1     BASIC ROM bank bit 1
133 	    PB2
134 	    PB3     BASIC ROM enable
135 	    PB4
136 	    PB5
137 	    PB6     STROBE
138 	    PB7     DIP switch select
139 
140 	*/
141 
142 	m_bank = data & 0x03;
143 	m_basic = BIT(data, 3);
144 
145 	m_centronics->write_strobe(BIT(data, 6));
146 
147 	m_dipsw = BIT(data, 7);
148 }
149 
ppi_pc_r()150 uint8_t c64_buscard_device::ppi_pc_r()
151 {
152 	/*
153 
154 	    bit     description
155 
156 	    PC0     BUSY
157 	    PC1
158 	    PC2     DAV
159 	    PC3     EOI
160 	    PC4
161 	    PC5     ATN
162 	    PC6     NRFD
163 	    PC7     NDAC
164 
165 	*/
166 
167 	uint8_t data = 0;
168 
169 	data |= m_busy;
170 
171 	data |= m_ieee2->dav_r() << 2;
172 	data |= m_ieee2->eoi_r() << 3;
173 	data |= m_ieee2->atn_r() << 5;
174 	data |= m_ieee2->nrfd_r() << 6;
175 	data |= m_ieee2->ndac_r() << 7;
176 
177 	return data;
178 }
179 
ppi_pc_w(uint8_t data)180 void c64_buscard_device::ppi_pc_w(uint8_t data)
181 {
182 	/*
183 
184 	    bit     description
185 
186 	    PC0
187 	    PC1     ATN
188 	    PC2     DAV
189 	    PC3     EOI
190 	    PC4     TE
191 	    PC5
192 	    PC6     NRFD
193 	    PC7     NDAC
194 
195 	*/
196 
197 	m_te = BIT(data, 4);
198 	m_ieee1->te_w(m_te);
199 	m_ieee2->te_w(m_te);
200 
201 	m_ieee2->atn_w(BIT(data, 1));
202 	m_ieee2->dav_w(BIT(data, 2));
203 	m_ieee2->eoi_w(BIT(data, 3));
204 	m_ieee2->nrfd_w(BIT(data, 6));
205 	m_ieee2->ndac_w(BIT(data, 7));
206 }
207 
208 
209 //-------------------------------------------------
210 //  Centronics interface
211 //-------------------------------------------------
212 
WRITE_LINE_MEMBER(c64_buscard_device::busy_w)213 WRITE_LINE_MEMBER( c64_buscard_device::busy_w )
214 {
215 	m_busy = state;
216 }
217 
218 
219 //-------------------------------------------------
220 //  device_add_mconfig - add device configuration
221 //-------------------------------------------------
222 
device_add_mconfig(machine_config & config)223 void c64_buscard_device::device_add_mconfig(machine_config &config)
224 {
225 	I8255A(config, m_ppi, 0);
226 	m_ppi->in_pa_callback().set(FUNC(c64_buscard_device::ppi_pa_r));
227 	m_ppi->out_pa_callback().set(FUNC(c64_buscard_device::ppi_pa_w));
228 	m_ppi->in_pb_callback().set_constant(0xff);
229 	m_ppi->out_pb_callback().set(FUNC(c64_buscard_device::ppi_pb_w));
230 	m_ppi->in_pc_callback().set(FUNC(c64_buscard_device::ppi_pc_r));
231 	m_ppi->out_pc_callback().set(FUNC(c64_buscard_device::ppi_pc_w));
232 
233 	DS75160A(config, m_ieee1, 0);
234 	m_ieee1->read_callback().set(IEEE488_TAG, FUNC(ieee488_device::dio_r));
235 	m_ieee1->write_callback().set(IEEE488_TAG, FUNC(ieee488_device::host_dio_w));
236 
237 	DS75161A(config, m_ieee2, 0);
238 	m_ieee2->in_ren().set(IEEE488_TAG, FUNC(ieee488_device::ren_r));
239 	m_ieee2->in_ifc().set(IEEE488_TAG, FUNC(ieee488_device::ifc_r));
240 	m_ieee2->in_ndac().set(IEEE488_TAG, FUNC(ieee488_device::ndac_r));
241 	m_ieee2->in_nrfd().set(IEEE488_TAG, FUNC(ieee488_device::nrfd_r));
242 	m_ieee2->in_dav().set(IEEE488_TAG, FUNC(ieee488_device::dav_r));
243 	m_ieee2->in_eoi().set(IEEE488_TAG, FUNC(ieee488_device::eoi_r));
244 	m_ieee2->in_atn().set(IEEE488_TAG, FUNC(ieee488_device::atn_r));
245 	m_ieee2->in_srq().set(IEEE488_TAG, FUNC(ieee488_device::srq_r));
246 	m_ieee2->out_ren().set(IEEE488_TAG, FUNC(ieee488_device::host_ren_w));
247 	m_ieee2->out_ifc().set(IEEE488_TAG, FUNC(ieee488_device::host_ifc_w));
248 	m_ieee2->out_ndac().set(IEEE488_TAG, FUNC(ieee488_device::host_ndac_w));
249 	m_ieee2->out_nrfd().set(IEEE488_TAG, FUNC(ieee488_device::host_nrfd_w));
250 	m_ieee2->out_dav().set(IEEE488_TAG, FUNC(ieee488_device::host_dav_w));
251 	m_ieee2->out_eoi().set(IEEE488_TAG, FUNC(ieee488_device::host_eoi_w));
252 	m_ieee2->out_atn().set(IEEE488_TAG, FUNC(ieee488_device::host_atn_w));
253 	m_ieee2->out_srq().set(IEEE488_TAG, FUNC(ieee488_device::host_srq_w));
254 
255 	IEEE488(config, m_bus, 0);
256 	ieee488_slot_device::add_cbm_defaults(config, nullptr);
257 
258 	CENTRONICS(config, m_centronics, centronics_devices, nullptr);
259 	m_centronics->busy_handler().set(FUNC(c64_buscard_device::busy_w));
260 
261 	C64_EXPANSION_SLOT(config, m_exp, DERIVED_CLOCK(1, 1), c64_expansion_cards, nullptr);
262 	m_exp->set_passthrough();
263 }
264 
265 
266 
267 //**************************************************************************
268 //  LIVE DEVICE
269 //**************************************************************************
270 
271 //-------------------------------------------------
272 //  c64_buscard_device - constructor
273 //-------------------------------------------------
274 
c64_buscard_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)275 c64_buscard_device::c64_buscard_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
276 	device_t(mconfig, C64_BUSCARD, tag, owner, clock),
277 	device_c64_expansion_card_interface(mconfig, *this),
278 	m_ppi(*this, "u2"),
279 	m_ieee1(*this, "u3"),
280 	m_ieee2(*this, "u4"),
281 	m_bus(*this, IEEE488_TAG),
282 	m_centronics(*this, "p4"),
283 	m_exp(*this, "exp"),
284 	m_s1(*this, "S1"),
285 	m_rom(*this, "rom"),
286 	m_te(1),
287 	m_bank(3),
288 	m_basic(1),
289 	m_dipsw(1),
290 	m_busy(1)
291 {
292 }
293 
294 
295 //-------------------------------------------------
296 //  device_start - device-specific startup
297 //-------------------------------------------------
298 
device_start()299 void c64_buscard_device::device_start()
300 {
301 	m_ieee1->pe_w(0);
302 	m_ieee2->dc_w(0);
303 
304 	// state saving
305 	save_item(NAME(m_te));
306 	save_item(NAME(m_bank));
307 	save_item(NAME(m_basic));
308 	save_item(NAME(m_dipsw));
309 	save_item(NAME(m_busy));
310 }
311 
312 
313 //-------------------------------------------------
314 //  device_reset - device-specific reset
315 //-------------------------------------------------
316 
device_reset()317 void c64_buscard_device::device_reset()
318 {
319 	m_ppi->reset();
320 
321 	m_ieee2->ifc_w(0);
322 	m_ieee2->ifc_w(1);
323 }
324 
325 
326 //-------------------------------------------------
327 //  c64_cd_r - cartridge data read
328 //-------------------------------------------------
329 
c64_cd_r(offs_t offset,uint8_t data,int sphi2,int ba,int roml,int romh,int io1,int io2)330 uint8_t c64_buscard_device::c64_cd_r(offs_t offset, uint8_t data, int sphi2, int ba, int roml, int romh, int io1, int io2)
331 {
332 	int cs = BIT(offset, 6) && BIT(offset, 7);
333 
334 	if (sphi2 && !io1 && cs)
335 	{
336 		data = m_ppi->read(offset & 0x03);
337 	}
338 
339 	if (!pd_pgm1(offset, sphi2))
340 	{
341 		data = m_rom->base()[offset & 0x1fff];
342 	}
343 
344 	if (!pd_pgm234(offset, sphi2, 0x02))
345 	{
346 		data = m_rom->base()[0x2000 | (offset & 0x1fff)];
347 	}
348 
349 	if (!pd_pgm234(offset, sphi2, 0x01))
350 	{
351 		data = m_rom->base()[0x4000 | (offset & 0x1fff)];
352 	}
353 
354 	if (!pd_pgm234(offset, sphi2, 0x00))
355 	{
356 		data = m_rom->base()[0x6000 | (offset & 0x1fff)];
357 	}
358 
359 	return m_exp->cd_r(offset, data, sphi2, ba, roml, romh, io1 | cs, io2);
360 }
361 
362 
363 //-------------------------------------------------
364 //  c64_cd_w - cartridge data write
365 //-------------------------------------------------
366 
c64_cd_w(offs_t offset,uint8_t data,int sphi2,int ba,int roml,int romh,int io1,int io2)367 void c64_buscard_device::c64_cd_w(offs_t offset, uint8_t data, int sphi2, int ba, int roml, int romh, int io1, int io2)
368 {
369 	int cs = BIT(offset, 6) && BIT(offset, 7);
370 
371 	if (sphi2 && !io1 && cs)
372 	{
373 		m_ppi->write(offset & 0x03, data);
374 	}
375 
376 	m_exp->cd_w(offset, data, sphi2, ba, roml, romh, io1 | cs, io2);
377 }
378 
379 
380 //-------------------------------------------------
381 //  c64_game_r - cartridge GAME read
382 //-------------------------------------------------
383 
c64_game_r(offs_t offset,int sphi2,int ba,int rw)384 int c64_buscard_device::c64_game_r(offs_t offset, int sphi2, int ba, int rw)
385 {
386 	return pd_pgm1(offset, sphi2) & m_exp->game_r(offset, sphi2, ba, rw, m_slot->loram(), m_slot->hiram());
387 }
388 
389 
390 //-------------------------------------------------
391 //  c64_exrom_r - cartridge EXROM read
392 //-------------------------------------------------
393 
c64_exrom_r(offs_t offset,int sphi2,int ba,int rw)394 int c64_buscard_device::c64_exrom_r(offs_t offset, int sphi2, int ba, int rw)
395 {
396 	return (!pd_pgm1(offset, sphi2)) | m_exp->exrom_r(offset, sphi2, ba, rw, m_slot->loram(), m_slot->hiram());
397 }
398 
399 
400 //-------------------------------------------------
401 //  pd_pgm1 - ROM 1 enable
402 //-------------------------------------------------
403 
pd_pgm1(offs_t offset,int sphi2)404 bool c64_buscard_device::pd_pgm1(offs_t offset, int sphi2)
405 {
406 	if (sphi2 && m_slot->hiram())
407 	{
408 		if (offset >= 0xa000 && offset < 0xc000 && m_slot->loram() && !m_basic)
409 		{
410 			return 0;
411 		}
412 
413 		if (offset >= 0xec00 && offset < 0xf000)
414 		{
415 			return 0;
416 		}
417 	}
418 
419 	return 1;
420 }
421 
422 
423 //-------------------------------------------------
424 //  pd_pgm234 - ROM 2/3/4 enable
425 //-------------------------------------------------
426 
pd_pgm234(offs_t offset,int sphi2,int bank)427 bool c64_buscard_device::pd_pgm234(offs_t offset, int sphi2, int bank)
428 {
429 	return !(sphi2 && m_slot->hiram() && m_slot->loram() && offset >= 0xa000 && offset < 0xc000 && m_basic && (m_bank == bank));
430 }
431