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