// license:BSD-3-Clause // copyright-holders:Krzysztof Strzecha /*************************************************************************** machine.c Functions to emulate general aspects of PMD-85 (RAM, ROM, interrupts, I/O ports) Krzysztof Strzecha ***************************************************************************/ #include "emu.h" #include "cpu/i8085/i8085.h" #include "includes/pmd85.h" #include "machine/pit8253.h" enum {PMD85_LED_1 = 0, PMD85_LED_2, PMD85_LED_3}; enum {PMD85_1, PMD85_2, PMD85_2A, PMD85_2B, PMD85_3, ALFA, MATO, C2717}; void pmd85_state::pmd851_update_memory() { address_space& space = m_maincpu->space(AS_PROGRAM); uint8_t *ram = m_ram->pointer(); if (m_startup_mem_map) { uint8_t *mem = m_region_maincpu->base(); space.unmap_write(0x0000, 0x0fff); space.nop_write(0x1000, 0x1fff); space.unmap_write(0x2000, 0x2fff); space.nop_write(0x3000, 0x3fff); space.nop_read(0x1000, 0x1fff); space.nop_read(0x3000, 0x3fff); m_bank1->set_base(mem + 0x010000); m_bank3->set_base(mem + 0x010000); m_bank5->set_base(ram + 0xc000); m_bank6->set_base(mem + 0x010000); m_bank7->set_base(mem + 0x010000); m_bank8->set_base(ram + 0xc000); } else { space.install_write_bank(0x0000, 0x0fff, "bank1"); space.install_write_bank(0x1000, 0x1fff, "bank2"); space.install_write_bank(0x2000, 0x2fff, "bank3"); space.install_write_bank(0x3000, 0x3fff, "bank4"); space.install_write_bank(0x4000, 0x7fff, "bank5"); space.install_read_bank(0x1000, 0x1fff, "bank2"); space.install_read_bank(0x3000, 0x3fff, "bank4"); m_bank1->set_base(ram); m_bank2->set_base(ram + 0x1000); m_bank3->set_base(ram + 0x2000); m_bank4->set_base(ram + 0x3000); m_bank5->set_base(ram + 0x4000); } } void pmd85_state::pmd852a_update_memory() { address_space& space = m_maincpu->space(AS_PROGRAM); uint8_t *ram = m_ram->pointer(); if (m_startup_mem_map) { uint8_t *mem = m_region_maincpu->base(); space.unmap_write(0x0000, 0x0fff); space.unmap_write(0x2000, 0x2fff); m_bank1->set_base(mem + 0x010000); m_bank2->set_base(ram + 0x9000); m_bank3->set_base(mem + 0x010000); m_bank4->set_base(ram + 0xb000); m_bank5->set_base(ram + 0xc000); m_bank6->set_base(mem + 0x010000); m_bank7->set_base(ram + 0x9000); m_bank8->set_base(mem + 0x010000); m_bank9->set_base(ram + 0xb000); m_bank10->set_base(ram + 0xc000); } else { space.install_write_bank(0x0000, 0x0fff, "bank1"); space.install_write_bank(0x2000, 0x2fff, "bank3"); m_bank1->set_base(ram); m_bank2->set_base(ram + 0x1000); m_bank3->set_base(ram + 0x2000); m_bank4->set_base(ram + 0x5000); m_bank5->set_base(ram + 0x4000); } } void pmd85_state::pmd853_update_memory() { uint8_t *mem = m_region_maincpu->base(); uint8_t *ram = m_ram->pointer(); if (m_startup_mem_map) { m_bank1->set_base(mem + 0x010000); m_bank2->set_base(mem + 0x010000); m_bank3->set_base(mem + 0x010000); m_bank4->set_base(mem + 0x010000); m_bank5->set_base(mem + 0x010000); m_bank6->set_base(mem + 0x010000); m_bank7->set_base(mem + 0x010000); m_bank8->set_base(mem + 0x010000); m_bank9->set_base(ram); m_bank10->set_base(ram + 0x2000); m_bank11->set_base(ram + 0x4000); m_bank12->set_base(ram + 0x6000); m_bank13->set_base(ram + 0x8000); m_bank14->set_base(ram + 0xa000); m_bank15->set_base(ram + 0xc000); m_bank16->set_base(ram + 0xe000); } else { m_bank1->set_base(ram); m_bank2->set_base(ram + 0x2000); m_bank3->set_base(ram + 0x4000); m_bank4->set_base(ram + 0x6000); m_bank5->set_base(ram + 0x8000); m_bank6->set_base(ram + 0xa000); m_bank7->set_base(ram + 0xc000); m_bank8->set_base(m_pmd853_memory_mapping ? mem + 0x010000 : ram + 0xe000); } } void pmd85_state::alfa_update_memory() { address_space& space = m_maincpu->space(AS_PROGRAM); uint8_t *ram = m_ram->pointer(); if (m_startup_mem_map) { uint8_t *mem = m_region_maincpu->base(); space.unmap_write(0x0000, 0x0fff); space.unmap_write(0x1000, 0x33ff); space.nop_write(0x3400, 0x3fff); m_bank1->set_base(mem + 0x010000); m_bank2->set_base(mem + 0x011000); m_bank4->set_base(ram + 0xc000); m_bank5->set_base(mem + 0x010000); m_bank6->set_base(mem + 0x011000); m_bank7->set_base(ram + 0xc000); } else { space.install_write_bank(0x0000, 0x0fff, "bank1"); space.install_write_bank(0x1000, 0x33ff, "bank2"); space.install_write_bank(0x3400, 0x3fff, "bank3"); m_bank1->set_base(ram); m_bank2->set_base(ram + 0x1000); m_bank3->set_base(ram + 0x3400); m_bank4->set_base(ram + 0x4000); } } void pmd85_state::mato_update_memory() { address_space& space = m_maincpu->space(AS_PROGRAM); uint8_t *ram = m_ram->pointer(); if (m_startup_mem_map) { uint8_t *mem = m_region_maincpu->base(); space.unmap_write(0x0000, 0x3fff); m_bank1->set_base(mem + 0x010000); m_bank2->set_base(ram + 0xc000); m_bank3->set_base(mem + 0x010000); m_bank4->set_base(ram + 0xc000); } else { space.install_write_bank(0x0000, 0x3fff, "bank1"); m_bank1->set_base(ram); m_bank2->set_base(ram + 0x4000); } } void pmd85_state::c2717_update_memory() { address_space& space = m_maincpu->space(AS_PROGRAM); uint8_t *mem = m_region_maincpu->base(); uint8_t *ram = m_ram->pointer(); if (m_startup_mem_map) { space.unmap_write(0x0000, 0x3fff); m_bank1->set_base(mem + 0x010000); m_bank2->set_base(ram + 0x4000); m_bank3->set_base(mem + 0x010000); m_bank4->set_base(ram + 0xc000); } else { space.install_write_bank(0x0000, 0x3fff, "bank1"); m_bank1->set_base(ram); m_bank2->set_base(ram + 0x4000); } } /******************************************************************************* Motherboard 8255 (PMD-85.1, PMD-85.2, PMD-85.3, Didaktik Alfa) -------------------------------------------------------------- keyboard, speaker, LEDs *******************************************************************************/ READ8_MEMBER(pmd85_state::pmd85_ppi_0_porta_r) { return 0xff; } READ8_MEMBER(pmd85_state::pmd85_ppi_0_portb_r) { return m_io_port[(m_ppi_port_outputs[0][0] & 0x0f)]->read() & m_io_port[15]->read(); } READ8_MEMBER(pmd85_state::pmd85_ppi_0_portc_r) { return 0xff; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_0_porta_w) { m_ppi_port_outputs[0][0] = data; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_0_portb_w) { m_ppi_port_outputs[0][1] = data; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_0_portc_w) { m_ppi_port_outputs[0][2] = data; m_led[PMD85_LED_2] = BIT(data, 3); m_led[PMD85_LED_3] = BIT(data, 2); } /******************************************************************************* Motherboard 8255 (Mato) ----------------------- keyboard, speaker, LEDs, tape *******************************************************************************/ READ8_MEMBER(pmd85_state::mato_ppi_0_portb_r) { int i; uint8_t data = 0xff; for (i = 0; i < 8; i++) { if (!BIT(m_ppi_port_outputs[0][0], i)) data &= m_io_port[i]->read(); } return data; } READ8_MEMBER(pmd85_state::mato_ppi_0_portc_r) { return m_io_port[8]->read() | 0x8f; } WRITE8_MEMBER(pmd85_state::mato_ppi_0_portc_w) { m_ppi_port_outputs[0][2] = data; m_led[PMD85_LED_2] = BIT(data, 3); m_led[PMD85_LED_3] = BIT(data, 2); } /******************************************************************************* I/O board 8255 -------------- GPIO/0 (K3 connector), GPIO/1 (K4 connector) *******************************************************************************/ READ8_MEMBER(pmd85_state::pmd85_ppi_1_porta_r) { return 0xff; } READ8_MEMBER(pmd85_state::pmd85_ppi_1_portb_r) { return 0xff; } READ8_MEMBER(pmd85_state::pmd85_ppi_1_portc_r) { return 0xff; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_1_porta_w) { m_ppi_port_outputs[1][0] = data; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_1_portb_w) { m_ppi_port_outputs[1][1] = data; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_1_portc_w) { m_ppi_port_outputs[1][2] = data; } /******************************************************************************* I/O board 8255 -------------- IMS-2 (K5 connector) - 8251 - cassette recorder and V.24/IFSS (selectable by switch) - external interfaces connector (K2) *******************************************************************************/ READ8_MEMBER(pmd85_state::pmd85_ppi_2_porta_r) { return 0xff; } READ8_MEMBER(pmd85_state::pmd85_ppi_2_portb_r) { return 0xff; } READ8_MEMBER(pmd85_state::pmd85_ppi_2_portc_r) { return 0xff; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_2_porta_w) { m_ppi_port_outputs[2][0] = data; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_2_portb_w) { m_ppi_port_outputs[2][1] = data; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_2_portc_w) { m_ppi_port_outputs[2][2] = data; } /******************************************************************************* I/O board 8251 -------------- cassette recorder and V.24/IFSS (selectable by switch) *******************************************************************************/ /******************************************************************************* I/O board external interfaces connector (K2) -------------------------------------------- *******************************************************************************/ /******************************************************************************* ROM Module 8255 --------------- port A - data read ports B, C - address select *******************************************************************************/ READ8_MEMBER(pmd85_state::pmd85_ppi_3_porta_r) { if (memregion("user1")->base() != nullptr) return memregion("user1")->base()[m_ppi_port_outputs[3][1] | (m_ppi_port_outputs[3][2] << 8)]; else return 0; } READ8_MEMBER(pmd85_state::pmd85_ppi_3_portb_r) { return 0xff; } READ8_MEMBER(pmd85_state::pmd85_ppi_3_portc_r) { return 0xff; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_3_porta_w) { m_ppi_port_outputs[3][0] = data; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_3_portb_w) { m_ppi_port_outputs[3][1] = data; } WRITE8_MEMBER(pmd85_state::pmd85_ppi_3_portc_w) { m_ppi_port_outputs[3][2] = data; } /******************************************************************************* I/O ports (PMD-85.1, PMD-85.2, PMD-85.3, Didaktik Alfa) ------------------------------------------------------- I/O board 1xxx11aa external interfaces connector (K2) 0xxx11aa I/O board interfaces 000111aa 8251 (casette recorder, V24) 010011aa 8255 (GPIO/0, GPIO/1) 010111aa 8253 011111aa 8255 (IMS-2) Motherboard 1xxx01aa 8255 (keyboard, speaker, LEDs) PMD-85.3 memory banking ROM Module 1xxx10aa 8255 (ROM reading) *******************************************************************************/ READ8_MEMBER(pmd85_state::pmd85_io_r) { if (m_startup_mem_map) { return 0xff; } switch (offset & 0x0c) { case 0x04: /* Motherboard */ switch (offset & 0x80) { case 0x80: /* Motherboard 8255 */ return m_ppi8255_0->read(space, offset & 0x03); } break; case 0x08: /* ROM module connector */ switch (m_model) { case PMD85_1: case PMD85_2: case PMD85_2A: case C2717: case PMD85_3: if (m_rom_module_present) { switch (offset & 0x80) { case 0x80: /* ROM module 8255 */ return m_ppi8255_3->read(space, offset & 0x03); } } break; } break; case 0x0c: /* I/O board */ switch (offset & 0x80) { case 0x00: /* I/O board interfaces */ switch (offset & 0x70) { case 0x10: /* 8251 (casette recorder, V24) */ switch (offset & 0x01) { case 0x00: return m_uart->data_r(space, offset & 0x01); case 0x01: return m_uart->status_r(space, offset & 0x01); } break; case 0x40: /* 8255 (GPIO/0, GPIO/1) */ return m_ppi8255_1->read(space, offset & 0x03); case 0x50: /* 8253 */ return m_pit8253->read(space, offset & 0x03); case 0x70: /* 8255 (IMS-2) */ return m_ppi8255_2->read(space, offset & 0x03); } break; case 0x80: /* external interfaces */ break; } break; } logerror ("Reading from unmapped port: %02x\n", offset); return 0xff; } WRITE8_MEMBER(pmd85_state::pmd85_io_w) { if (m_startup_mem_map) { m_startup_mem_map = 0; (this->*update_memory)(); } switch (offset & 0x0c) { case 0x04: /* Motherboard */ switch (offset & 0x80) { case 0x80: /* Motherboard 8255 */ m_ppi8255_0->write(space, offset & 0x03, data); /* PMD-85.3 memory banking */ if ((offset & 0x03) == 0x03) { m_pmd853_memory_mapping = data & 0x01; (this->*update_memory)(); } break; } break; case 0x08: /* ROM module connector */ switch (m_model) { case PMD85_1: case PMD85_2: case PMD85_2A: case C2717: case PMD85_3: if (m_rom_module_present) { switch (offset & 0x80) { case 0x80: /* ROM module 8255 */ m_ppi8255_3->write(space, offset & 0x03, data); break; } } break; } break; case 0x0c: /* I/O board */ switch (offset & 0x80) { case 0x00: /* I/O board interfaces */ switch (offset & 0x70) { case 0x10: /* 8251 (casette recorder, V24) */ switch (offset & 0x01) { case 0x00: m_uart->data_w(space, offset & 0x01, data); break; case 0x01: m_uart->control_w(space, offset & 0x01, data); break; } break; case 0x40: /* 8255 (GPIO/0, GPIO/0) */ m_ppi8255_1->write(space, offset & 0x03, data); break; case 0x50: /* 8253 */ m_pit8253->write(space, offset & 0x03, data); logerror ("8253 writing. Address: %02x, Data: %02x\n", offset, data); break; case 0x70: /* 8255 (IMS-2) */ m_ppi8255_2->write(space, offset & 0x03, data); break; } break; case 0x80: /* external interfaces */ break; } break; } } /******************************************************************************* I/O ports (Mato) ---------------- Motherboard 1xxx01aa 8255 (keyboard, speaker, LEDs, tape) *******************************************************************************/ READ8_MEMBER(pmd85_state::mato_io_r) { if (m_startup_mem_map) { return 0xff; } switch (offset & 0x0c) { case 0x04: /* Motherboard */ switch (offset & 0x80) { case 0x80: /* Motherboard 8255 */ return m_ppi8255_0->read(space, offset & 0x03); } break; } logerror ("Reading from unmapped port: %02x\n", offset); return 0xff; } WRITE8_MEMBER(pmd85_state::mato_io_w) { if (m_startup_mem_map) { m_startup_mem_map = 0; (this->*update_memory)(); } switch (offset & 0x0c) { case 0x04: /* Motherboard */ switch (offset & 0x80) { case 0x80: /* Motherboard 8255 */ return m_ppi8255_0->write(space, offset & 0x03, data); } break; } } void pmd85_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { switch (id) { case TIMER_CASSETTE: pmd85_cassette_timer_callback(ptr, param); break; default: assert_always(false, "Unknown id in pmd85_state::device_timer"); } } WRITE_LINE_MEMBER(pmd85_state::write_cas_tx) { m_cas_tx = state; } TIMER_CALLBACK_MEMBER(pmd85_state::pmd85_cassette_timer_callback) { int data; int current_level; if (!(m_io_dsw0->read() & 0x02)) /* V.24 / Tape Switch */ { /* tape reading */ if (m_cassette->get_state()&CASSETTE_PLAY) { switch (m_model) { case PMD85_1: if (m_clk_level_tape) { m_previous_level = (m_cassette->input() > 0.038) ? 1 : 0; m_clk_level_tape = 0; } else { current_level = (m_cassette->input() > 0.038) ? 1 : 0; if (m_previous_level!=current_level) { data = (!m_previous_level && current_level) ? 1 : 0; m_uart->write_rxd(data); m_clk_level_tape = 1; } } m_uart->write_rxc(m_clk_level_tape); return; case PMD85_2: case PMD85_2A: case C2717: case PMD85_3: case ALFA: /* not hardware data decoding */ return; } } /* tape writing */ if (m_cassette->get_state()&CASSETTE_RECORD) { data = m_cas_tx; data ^= m_clk_level_tape; m_cassette->output(data&0x01 ? 1 : -1); m_clk_level_tape = m_clk_level_tape ? 0 : 1; m_uart->write_txc(m_clk_level_tape); return; } m_clk_level_tape = 1; m_clk_level = m_clk_level ? 0 : 1; m_uart->write_txc(m_clk_level); } } INPUT_CHANGED_MEMBER(pmd85_state::pmd85_reset) { machine().schedule_soft_reset(); } void pmd85_state::pmd85_common_driver_init() { static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7", "KEY8", "KEY9", "KEY10", "KEY11", "KEY12", "KEY13", "KEY14", "KEY15" }; for ( int i = 0; i < 16; i++ ) { m_io_port[i] = ioport( keynames[i] ); } m_previous_level = 0; m_clk_level = m_clk_level_tape = 1; m_cassette_timer = timer_alloc(TIMER_CASSETTE); m_cassette_timer->adjust(attotime::zero, 0, attotime::from_hz(2400)); } void pmd85_state::init_pmd851() { m_model = PMD85_1; update_memory = &pmd85_state::pmd851_update_memory; pmd85_common_driver_init(); } void pmd85_state::init_pmd852a() { m_model = PMD85_2A; update_memory = &pmd85_state::pmd852a_update_memory; pmd85_common_driver_init(); } void pmd85_state::init_pmd853() { m_model = PMD85_3; update_memory = &pmd85_state::pmd853_update_memory; pmd85_common_driver_init(); } void pmd85_state::init_alfa() { m_model = ALFA; update_memory = &pmd85_state::alfa_update_memory; pmd85_common_driver_init(); } void pmd85_state::init_mato() { m_model = MATO; update_memory = &pmd85_state::mato_update_memory; static const char *const keynames[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4", "KEY5", "KEY6", "KEY7", "KEY8" }; for ( int i = 0; i < 9; i++ ) { m_io_port[i] = ioport( keynames[i] ); } for ( int i = 9; i < 16; i++ ) { m_io_port[i] = nullptr; } } void pmd85_state::init_c2717() { m_model = C2717; update_memory = &pmd85_state::c2717_update_memory; pmd85_common_driver_init(); } void pmd85_state::machine_reset() { int i, j; /* checking for Rom Module */ switch (m_model) { case PMD85_1: case PMD85_2A: case PMD85_3: case C2717: m_rom_module_present = (m_io_dsw0->read() & 0x01) ? 1 : 0; break; case ALFA: case MATO: break; } for (i = 0; i < 4; i++) for (j = 0; j < 3; j++) m_ppi_port_outputs[i][j] = 0; /* memory initialization */ memset(m_ram->pointer(), 0, sizeof(unsigned char)*0x10000); m_pmd853_memory_mapping = 1; m_startup_mem_map = 1; (this->*update_memory)(); }