1 // license:BSD-3-Clause
2 // copyright-holders:Lee Ward, Dirk Best, Curt Coder
3 /*************************************************************************
4 
5     Memotech MTX 500, MTX 512 and RS 128
6 
7 **************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/mtx.h"
11 
12 #include "formats/imageutl.h"
13 
14 /***************************************************************************
15     READ/WRITE HANDLERS
16 ***************************************************************************/
17 
18 /*-------------------------------------------------
19     mtx_strobe_r - centronics strobe
20 -------------------------------------------------*/
21 
mtx_strobe_r()22 uint8_t mtx_state::mtx_strobe_r()
23 {
24 	/* set STROBE low */
25 	m_centronics->write_strobe(false);
26 
27 	return 0xff;
28 }
29 
30 /*-------------------------------------------------
31     mtx_subpage_w - rom2 subpages
32 -------------------------------------------------*/
33 
34 /*
35     The original ROM card supported 4 8KB ROM chips. These appeared in
36     ROM slot 2 in subpages 0 to 3. The subpage register starts as 0, but
37     is changed by attempting to write to 0x0000-0x1fff whilst in RELCPMH=0
38     mode (ie. attempting to write to the OS ROM). Videowalls could use a
39     later ROM card with 4 32KB ROMs. These also appeared in ROM slot 2
40     in subpages 0 to 15.
41 */
42 
mtx_subpage_w(uint8_t data)43 void mtx_state::mtx_subpage_w(uint8_t data)
44 {
45 	if (m_extrom->exists())
46 	{
47 		if ((data * 0x2000) < m_extrom->get_rom_size())
48 			membank("rommap_bank1")->configure_entry(2, m_extrom->get_rom_base() + 0x2000 * data);
49 		else
50 			membank("rommap_bank1")->configure_entry(2, memregion("user2")->base() + 0x4000);
51 		membank("rommap_bank1")->set_entry(2);
52 	}
53 }
54 
55 /*-------------------------------------------------
56     mtx_bankswitch_w - bankswitch
57 -------------------------------------------------*/
58 
59 /*
60     There are two memory models on the MTX, the standard one and a
61     CBM mode. In standard mode, the memory map is defined as:
62 
63     0x0000 - 0x1fff  OSROM
64     0x2000 - 0x3fff  Paged ROM
65     0x4000 - 0x7fff  Paged RAM
66     0x8000 - 0xbfff  Paged RAM
67     0xc000 - 0xffff  RAM
68 
69     Banks are selected by output port 0. Bits 0-3 define the RAM page
70     and bits 4-6 the ROM page.
71 
72     CBM mode is selected by bit 7 of output port 0. ROM is replaced
73     by RAM in this mode.
74 */
75 
bankswitch(uint8_t data)76 void mtx_state::bankswitch(uint8_t data)
77 {
78 	/*
79 
80 	    bit     description
81 
82 	    0       P0
83 	    1       P1
84 	    2       P2
85 	    3       P3
86 	    4       R0
87 	    5       R1
88 	    6       R2
89 	    7       RELCPMH
90 
91 	*/
92 	address_space &program = m_maincpu->space(AS_PROGRAM);
93 
94 	uint8_t cbm_mode = (data >> 7) & 0x01;
95 	uint8_t rom_page = (data >> 4) & 0x07;
96 	uint8_t ram_page = (data >> 0) & 0x0f;
97 
98 	if (cbm_mode)
99 	{
100 		/* ram based memory map */
101 		program.install_readwrite_bank(0x0000, 0x3fff, "rammap_bank1");
102 		program.install_readwrite_bank(0x4000, 0x7fff, "rammap_bank2");
103 		program.install_readwrite_bank(0x8000, 0xbfff, "rammap_bank3");
104 
105 		/* set ram bank, for invalid pages a nop-handler will be installed */
106 		if ((ram_page == 0 && m_ram->size() > 0xc000) || (ram_page > 0 && m_ram->size() > 0x10000 + ram_page * 0xc000))
107 			membank("rammap_bank1")->set_entry(ram_page);
108 		else
109 			program.nop_readwrite(0x0000, 0x3fff);
110 		if ((ram_page == 0 && m_ram->size() > 0x8000) || (ram_page > 0 && m_ram->size() > 0x14000 + ram_page * 0xc000))
111 
112 			membank("rammap_bank2")->set_entry(ram_page);
113 		else
114 			program.nop_readwrite(0x4000, 0x7fff);
115 		if ((ram_page == 0 && m_ram->size() > 0x4000) || (ram_page > 0 && m_ram->size() > 0x18000 + ram_page * 0xc000))
116 
117 			membank("rammap_bank3")->set_entry(ram_page);
118 		else
119 			program.nop_readwrite(0x8000, 0xbfff);
120 	}
121 	else
122 	{
123 		/* rom based memory map */
124 		program.install_rom(0x0000, 0x1fff, memregion("user1")->base());
125 		program.install_write_handler(0x0000, 0x1fff, write8smo_delegate(*this, FUNC(mtx_state::mtx_subpage_w)));
126 		program.install_read_bank(0x2000, 0x3fff, "rommap_bank1");
127 		program.unmap_write(0x2000, 0x3fff);
128 		program.install_readwrite_bank(0x4000, 0x7fff, "rommap_bank2");
129 		program.install_readwrite_bank(0x8000, 0xbfff, "rommap_bank3");
130 
131 		/* set rom bank (switches between basic and assembler rom or cartridges) */
132 		membank("rommap_bank1")->set_entry(rom_page);
133 
134 		/* set ram bank, for invalid pages a nop-handler will be installed */
135 		if ((ram_page == 0 && m_ram->size() > 0x8000) || (ram_page > 0 && m_ram->size() > 0x10000 + ram_page * 0x8000))
136 			membank("rommap_bank2")->set_entry(ram_page);
137 		else
138 			program.nop_readwrite(0x4000, 0x7fff);
139 		if ((ram_page == 0 && m_ram->size() > 0x4000) || (ram_page == 1 && m_ram->size() > 0xc000) || (ram_page > 1 && m_ram->size() > 0x14000 + ram_page * 0x8000))
140 			membank("rommap_bank3")->set_entry(ram_page);
141 		else
142 			program.nop_readwrite(0x8000, 0xbfff);
143 	}
144 }
145 
mtx_bankswitch_w(uint8_t data)146 void mtx_state::mtx_bankswitch_w(uint8_t data)
147 {
148 	bankswitch(data);
149 }
150 
151 /*-------------------------------------------------
152     mtx_sound_strobe_r - sound strobe
153 -------------------------------------------------*/
154 
mtx_sound_strobe_r()155 uint8_t mtx_state::mtx_sound_strobe_r()
156 {
157 	m_sn->write(m_sound_latch);
158 	return 0xff;
159 }
160 
161 /*-------------------------------------------------
162     mtx_sound_latch_w - sound latch write
163 -------------------------------------------------*/
164 
mtx_sound_latch_w(uint8_t data)165 void mtx_state::mtx_sound_latch_w(uint8_t data)
166 {
167 	m_sound_latch = data;
168 }
169 
170 /*-------------------------------------------------
171     mtx_cst_w - cassette write
172 -------------------------------------------------*/
173 
mtx_cst_w(uint8_t data)174 void mtx_state::mtx_cst_w(uint8_t data)
175 {
176 	m_cassette->output( BIT(data, 0) ? -1 : 1);
177 }
178 
179 /*-------------------------------------------------
180     mtx_cst_motor_w - cassette motor
181 -------------------------------------------------*/
182 
mtx_cst_motor_w(uint8_t data)183 void mtx_state::mtx_cst_motor_w(uint8_t data)
184 {
185 	/* supported in the MTX ROM */
186 	switch (data)
187 	{
188 	case 0xaa:
189 		m_cassette->change_state(CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
190 		break;
191 	case 0x55:
192 		m_cassette->change_state(CASSETTE_MOTOR_DISABLED, CASSETTE_MASK_MOTOR);
193 		break;
194 	}
195 }
196 
197 /*-------------------------------------------------
198     mtx_prt_r - centronics status
199 -------------------------------------------------*/
200 
WRITE_LINE_MEMBER(mtx_state::write_centronics_busy)201 WRITE_LINE_MEMBER(mtx_state::write_centronics_busy)
202 {
203 	m_centronics_busy = state;
204 }
205 
WRITE_LINE_MEMBER(mtx_state::write_centronics_fault)206 WRITE_LINE_MEMBER(mtx_state::write_centronics_fault)
207 {
208 	m_centronics_fault = state;
209 }
210 
WRITE_LINE_MEMBER(mtx_state::write_centronics_perror)211 WRITE_LINE_MEMBER(mtx_state::write_centronics_perror)
212 {
213 	m_centronics_perror = state;
214 }
215 
WRITE_LINE_MEMBER(mtx_state::write_centronics_select)216 WRITE_LINE_MEMBER(mtx_state::write_centronics_select)
217 {
218 	m_centronics_select = state;
219 }
220 
mtx_prt_r()221 uint8_t mtx_state::mtx_prt_r()
222 {
223 	/*
224 
225 	    bit     description
226 
227 	    0       BUSY
228 	    1       ERROR
229 	    2       PE
230 	    3       SLCT
231 	    4
232 	    5
233 	    6
234 	    7
235 
236 	*/
237 
238 	uint8_t data = 0;
239 
240 	/* reset STROBE to high */
241 	m_centronics->write_strobe( true);
242 
243 	data |= m_centronics_busy << 0;
244 	data |= m_centronics_fault << 1;
245 	data |= m_centronics_perror << 2;
246 	data |= m_centronics_select << 3;
247 
248 	return data;
249 }
250 
251 /*-------------------------------------------------
252     mtx_sense_w - keyboard sense write
253 -------------------------------------------------*/
254 
mtx_sense_w(uint8_t data)255 void mtx_state::mtx_sense_w(uint8_t data)
256 {
257 	m_key_sense = data;
258 }
259 
260 /*-------------------------------------------------
261     mtx_key_lo_r - keyboard low read
262 -------------------------------------------------*/
263 
mtx_key_lo_r()264 uint8_t mtx_state::mtx_key_lo_r()
265 {
266 	uint8_t data = 0xff;
267 
268 	if (!(m_key_sense & 0x01)) data &= ioport("ROW0")->read();
269 	if (!(m_key_sense & 0x02)) data &= ioport("ROW1")->read();
270 	if (!(m_key_sense & 0x04)) data &= ioport("ROW2")->read();
271 	if (!(m_key_sense & 0x08)) data &= ioport("ROW3")->read();
272 	if (!(m_key_sense & 0x10)) data &= ioport("ROW4")->read();
273 	if (!(m_key_sense & 0x20)) data &= ioport("ROW5")->read();
274 	if (!(m_key_sense & 0x40)) data &= ioport("ROW6")->read();
275 	if (!(m_key_sense & 0x80)) data &= ioport("ROW7")->read();
276 
277 	return data;
278 }
279 
280 /*-------------------------------------------------
281     mtx_key_lo_r - keyboard high read
282 -------------------------------------------------*/
283 
mtx_key_hi_r()284 uint8_t mtx_state::mtx_key_hi_r()
285 {
286 	uint8_t data = ioport("country_code")->read();
287 
288 	if (!(m_key_sense & 0x01)) data &= ioport("ROW0")->read() >> 8;
289 	if (!(m_key_sense & 0x02)) data &= ioport("ROW1")->read() >> 8;
290 	if (!(m_key_sense & 0x04)) data &= ioport("ROW2")->read() >> 8;
291 	if (!(m_key_sense & 0x08)) data &= ioport("ROW3")->read() >> 8;
292 	if (!(m_key_sense & 0x10)) data &= ioport("ROW4")->read() >> 8;
293 	if (!(m_key_sense & 0x20)) data &= ioport("ROW5")->read() >> 8;
294 	if (!(m_key_sense & 0x40)) data &= ioport("ROW6")->read() >> 8;
295 	if (!(m_key_sense & 0x80)) data &= ioport("ROW7")->read() >> 8;
296 
297 	return data;
298 }
299 
300 /*-------------------------------------------------
301     hrx_address_w - HRX video RAM address
302 -------------------------------------------------*/
303 
hrx_address_w(offs_t offset,uint8_t data)304 void mtx_state::hrx_address_w(offs_t offset, uint8_t data)
305 {
306 	if (offset)
307 	{
308 		/*
309 
310 		    bit     description
311 
312 		    0       A8
313 		    1       A9
314 		    2       A10
315 		    3
316 		    4
317 		    5       attribute memory write enable
318 		    6       ASCII memory write enable
319 		    7       cycle (0=read/1=write)
320 
321 		*/
322 	}
323 	else
324 	{
325 		/*
326 
327 		    bit     description
328 
329 		    0       A0
330 		    1       A1
331 		    2       A2
332 		    3       A3
333 		    4       A4
334 		    5       A5
335 		    6       A6
336 		    7       A7
337 
338 		*/
339 	}
340 }
341 
342 /*-------------------------------------------------
343     hrx_data_r - HRX data read
344 -------------------------------------------------*/
345 
hrx_data_r()346 uint8_t mtx_state::hrx_data_r()
347 {
348 	return 0;
349 }
350 
351 /*-------------------------------------------------
352     hrx_data_w - HRX data write
353 -------------------------------------------------*/
354 
hrx_data_w(uint8_t data)355 void mtx_state::hrx_data_w(uint8_t data)
356 {
357 }
358 
359 /*-------------------------------------------------
360     hrx_attr_r - HRX attribute read
361 -------------------------------------------------*/
362 
hrx_attr_r()363 uint8_t mtx_state::hrx_attr_r()
364 {
365 	return 0;
366 }
367 
368 /*-------------------------------------------------
369     hrx_attr_r - HRX attribute write
370 -------------------------------------------------*/
371 
hrx_attr_w(uint8_t data)372 void mtx_state::hrx_attr_w(uint8_t data)
373 {
374 	/*
375 
376 	    bit     description
377 
378 	    0
379 	    1
380 	    2
381 	    3
382 	    4
383 	    5
384 	    6
385 	    7
386 
387 	*/
388 }
389 
390 /***************************************************************************
391     EXTENSION BOARD ROMS
392 ***************************************************************************/
393 
DEVICE_IMAGE_LOAD_MEMBER(mtx_state::extrom_load)394 DEVICE_IMAGE_LOAD_MEMBER( mtx_state::extrom_load )
395 {
396 	uint32_t size = m_extrom->common_get_size("rom");
397 
398 	if (size > 0x80000)
399 	{
400 		image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unsupported rom size");
401 		return image_init_result::FAIL;
402 	}
403 
404 	m_extrom->rom_alloc(size, GENERIC_ROM8_WIDTH, ENDIANNESS_LITTLE);
405 	m_extrom->common_load_rom(m_extrom->get_rom_base(), size, "rom");
406 
407 	return image_init_result::PASS;
408 }
409 
410 /***************************************************************************
411     ROMPAK ROMS
412 ***************************************************************************/
413 
DEVICE_IMAGE_LOAD_MEMBER(mtx_state::rompak_load)414 DEVICE_IMAGE_LOAD_MEMBER( mtx_state::rompak_load )
415 {
416 	uint32_t size = m_rompak->common_get_size("rom");
417 
418 	if (size > 0x2000)
419 	{
420 		image.seterror(IMAGE_ERROR_UNSPECIFIED, "Unsupported cartridge size");
421 		return image_init_result::FAIL;
422 	}
423 
424 	m_rompak->rom_alloc(size, GENERIC_ROM8_WIDTH, ENDIANNESS_LITTLE);
425 	m_rompak->common_load_rom(m_rompak->get_rom_base(), size, "rom");
426 
427 	return image_init_result::PASS;
428 }
429 
430 /***************************************************************************
431     SNAPSHOT
432 ***************************************************************************/
433 
434 // this only works for some of the files, nothing which tries to load
435 // more data from tape. todo: tapes which autorun after loading
SNAPSHOT_LOAD_MEMBER(mtx_state::snapshot_cb)436 SNAPSHOT_LOAD_MEMBER(mtx_state::snapshot_cb)
437 {
438 	address_space &program = m_maincpu->space(AS_PROGRAM);
439 	uint8_t *data = (uint8_t*)image.ptr();
440 
441 	// verify first byte
442 	if (data[0] != 0xff)
443 	{
444 		image.seterror(IMAGE_ERROR_INVALIDIMAGE, nullptr);
445 		return image_init_result::FAIL;
446 	}
447 
448 	// get tape name
449 	char tape_name[16];
450 	memcpy(&tape_name, &data[1], 15);
451 	tape_name[15] = '\0';
452 	image.message("Loading '%s'", tape_name);
453 
454 	// reset memory map
455 	bankswitch(0);
456 
457 	// start of system variables area
458 	uint16_t system_variables_base = pick_integer_le(data, 16, 2);
459 
460 	// write system variables
461 	uint16_t system_variables_size = 0;
462 
463 	if (system_variables_base != 0)
464 	{
465 		system_variables_size = 0xfb4b - system_variables_base;
466 		for (int i = 0; i < system_variables_size; i++)
467 			program.write_byte(system_variables_base + i, data[18 + i]);
468 	}
469 
470 	// write actual image data
471 	uint16_t data_size = snapshot_size - 18 - system_variables_size;
472 	for (int i = 0; i < data_size; i++)
473 		program.write_byte(0x4000 + i, data[18 + system_variables_size + i]);
474 
475 	logerror("snapshot name = '%s', system_size = 0x%04x, data_size = 0x%04x\n", tape_name, system_variables_size, data_size);
476 
477 	return image_init_result::PASS;
478 }
479 
480 /***************************************************************************
481     QUICKLOAD
482 ***************************************************************************/
483 
QUICKLOAD_LOAD_MEMBER(mtx_state::quickload_cb)484 QUICKLOAD_LOAD_MEMBER(mtx_state::quickload_cb)
485 {
486 	address_space &program = m_maincpu->space(AS_PROGRAM);
487 	uint8_t *data = (uint8_t*)image.ptr();
488 
489 	if (quickload_size < 4)
490 	{
491 		image.seterror(IMAGE_ERROR_INVALIDIMAGE, "File too short");
492 		return image_init_result::FAIL;
493 	}
494 
495 	uint16_t code_base = pick_integer_le(data, 0, 2);
496 	uint16_t code_length = pick_integer_le(data, 2, 2);
497 
498 	if (quickload_size < code_length)
499 	{
500 		image.seterror(IMAGE_ERROR_INVALIDIMAGE, "File too short");
501 		return image_init_result::FAIL;
502 	}
503 
504 	if (code_base < 0x4000 || (code_base + code_length) >= 0x10000)
505 	{
506 		image.seterror(IMAGE_ERROR_INVALIDIMAGE, "Invalid code base and length");
507 		return image_init_result::FAIL;
508 	}
509 
510 	// reset memory map
511 	bankswitch(0);
512 
513 	// write image data
514 	for (int i = 0; i < code_length; i++)
515 		program.write_byte(code_base + i, data[4 + i]);
516 
517 	m_maincpu->set_pc(code_base);
518 
519 	return image_init_result::PASS;
520 }
521 
522 /***************************************************************************
523     MACHINE INITIALIZATION
524 ***************************************************************************/
525 
526 /*-------------------------------------------------
527     MACHINE_START( mtx512 )
528 -------------------------------------------------*/
529 
machine_start()530 void mtx_state::machine_start()
531 {
532 	address_space &program = m_maincpu->space(AS_PROGRAM);
533 
534 	/* setup banks for rom based memory map */
535 	program.install_read_bank(0x2000, 0x3fff, "rommap_bank1");
536 	program.install_readwrite_bank(0x4000, 0x7fff, "rommap_bank2");
537 	program.install_readwrite_bank(0x8000, 0xbfff, "rommap_bank3");
538 
539 	membank("rommap_bank1")->configure_entries(0, 8, memregion("user2")->base(), 0x2000);
540 	membank("rommap_bank2")->configure_entry(0, m_ram->pointer() + 0x8000);
541 	membank("rommap_bank2")->configure_entries(1, 15, m_ram->pointer() + 0x10000, 0x8000);
542 	membank("rommap_bank3")->configure_entry(0, m_ram->pointer() + 0x4000);
543 	membank("rommap_bank3")->configure_entry(1, m_ram->pointer() + 0xc000);
544 	membank("rommap_bank3")->configure_entries(2, 14, m_ram->pointer() + 0x14000, 0x8000);
545 
546 	/* setup banks for ram based memory map */
547 	program.install_readwrite_bank(0x0000, 0x3fff, "rammap_bank1");
548 	program.install_readwrite_bank(0x4000, 0x7fff, "rammap_bank2");
549 	program.install_readwrite_bank(0x8000, 0xbfff, "rammap_bank3");
550 
551 	membank("rammap_bank1")->configure_entry(0, m_ram->pointer() + 0xc000);
552 	membank("rammap_bank1")->configure_entries(1, 15, m_ram->pointer() + 0x10000, 0xc000);
553 	membank("rammap_bank2")->configure_entry(0, m_ram->pointer() + 0x8000);
554 	membank("rammap_bank2")->configure_entries(1, 15, m_ram->pointer() + 0x14000, 0xc000);
555 	membank("rammap_bank3")->configure_entry(0, m_ram->pointer() + 0x4000);
556 	membank("rammap_bank3")->configure_entries(1, 15, m_ram->pointer() + 0x18000, 0xc000);
557 
558 	/* install 4000h bytes common block */
559 	program.install_ram(0xc000, 0xffff, m_ram->pointer());
560 }
561 
machine_reset()562 void mtx_state::machine_reset()
563 {
564 	/* extension board ROMs */
565 	if (m_extrom->exists())
566 		membank("rommap_bank1")->configure_entry(2, m_extrom->get_rom_base());
567 	/* keyboard ROMs */
568 	if (ioport("keyboard_rom")->read())
569 		membank("rommap_bank1")->configure_entry(7, memregion("keyboard_rom")->base() + (ioport("keyboard_rom")->read() - 1) * 0x2000);
570 	/* rompak ROMs */
571 	if (m_rompak->exists())
572 		membank("rommap_bank1")->configure_entry(7, m_rompak->get_rom_base());
573 
574 	/* bank switching */
575 	bankswitch(0);
576 }
577