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