// license:BSD-3-Clause // copyright-holders:Krzysztof Strzecha /*************************************************************************** lviv.cpp Functions to emulate general aspects of PK-01 Lviv (RAM, ROM, interrupts, I/O ports) Krzysztof Strzecha ***************************************************************************/ #include "emu.h" #include "includes/lviv.h" #include "cpu/i8085/i8085.h" #define LVIV_SNAPSHOT_SIZE 82219 void lviv_state::update_memory() { uint8_t *ram = m_ram->pointer(); if (m_ppi_port_outputs[0][2] & 0x02) { m_bank[0]->set_base(ram); m_bank[1]->set_base(ram + 0x4000); } else { m_bank[0]->set_base(ram + 0x8000); m_bank[1]->set_base(ram + 0xc000); } } INPUT_CHANGED_MEMBER(lviv_state::reset_button) { machine().schedule_soft_reset(); } READ8_MEMBER(lviv_state::ppi_0_porta_r) { return 0xff; } READ8_MEMBER(lviv_state::ppi_0_portb_r) { return 0xff; } READ8_MEMBER(lviv_state::ppi_0_portc_r) { uint8_t data = m_ppi_port_outputs[0][2] & 0x0f; if (m_cassette->input() > 0.038) data |= 0x10; if (m_ppi_port_outputs[0][0] & m_joy_port->read()) data |= 0x80; return data; } WRITE8_MEMBER(lviv_state::ppi_0_porta_w) { m_ppi_port_outputs[0][0] = data; } WRITE8_MEMBER(lviv_state::ppi_0_portb_w) { m_ppi_port_outputs[0][1] = data; update_palette(data&0x7f); } WRITE8_MEMBER(lviv_state::ppi_0_portc_w)/* tape in/out, video memory on/off */ { m_ppi_port_outputs[0][2] = data; if (m_ppi_port_outputs[0][1]&0x80) m_speaker->level_w(data & 0x01); m_cassette->output((data & 0x01) ? -1.0 : 1.0); update_memory(); } READ8_MEMBER(lviv_state::ppi_1_porta_r) { return 0xff; } READ8_MEMBER(lviv_state::ppi_1_portb_r)/* keyboard reading */ { return ((m_ppi_port_outputs[1][0] & 0x01) ? 0xff : m_key[0]->read()) & ((m_ppi_port_outputs[1][0] & 0x02) ? 0xff : m_key[1]->read()) & ((m_ppi_port_outputs[1][0] & 0x04) ? 0xff : m_key[2]->read()) & ((m_ppi_port_outputs[1][0] & 0x08) ? 0xff : m_key[3]->read()) & ((m_ppi_port_outputs[1][0] & 0x10) ? 0xff : m_key[4]->read()) & ((m_ppi_port_outputs[1][0] & 0x20) ? 0xff : m_key[5]->read()) & ((m_ppi_port_outputs[1][0] & 0x40) ? 0xff : m_key[6]->read()) & ((m_ppi_port_outputs[1][0] & 0x80) ? 0xff : m_key[7]->read()); } READ8_MEMBER(lviv_state::ppi_1_portc_r)/* keyboard reading */ { return ((m_ppi_port_outputs[1][2] & 0x01) ? 0xff : m_key[ 8]->read()) & ((m_ppi_port_outputs[1][2] & 0x02) ? 0xff : m_key[ 9]->read()) & ((m_ppi_port_outputs[1][2] & 0x04) ? 0xff : m_key[10]->read()) & ((m_ppi_port_outputs[1][2] & 0x08) ? 0xff : m_key[11]->read()); } WRITE8_MEMBER(lviv_state::ppi_1_porta_w)/* kayboard scaning */ { m_ppi_port_outputs[1][0] = data; } WRITE8_MEMBER(lviv_state::ppi_1_portb_w) { m_ppi_port_outputs[1][1] = data; } WRITE8_MEMBER(lviv_state::ppi_1_portc_w)/* kayboard scaning */ { m_ppi_port_outputs[1][2] = data; } /* I/O */ READ8_MEMBER(lviv_state::io_r) { if (m_startup_mem_map) { return 0; /* ??? */ } else { const uint8_t switch_val = (offset >> 4) & 0x3; switch (switch_val) { case 0: case 1: return m_ppi[switch_val]->read(offset & 3); case 2: case 3: default: /* reserved for extension? */ return 0; /* ??? */ } } } WRITE8_MEMBER(lviv_state::io_w) { address_space &cpuspace = m_maincpu->space(AS_PROGRAM); if (m_startup_mem_map) { uint8_t *ram = m_ram->pointer(); m_startup_mem_map = 0; cpuspace.install_write_bank(0x0000, 0x3fff, "bank1"); cpuspace.install_write_bank(0x4000, 0x7fff, "bank2"); cpuspace.install_write_bank(0x8000, 0xbfff, "bank3"); cpuspace.unmap_write(0xC000, 0xffff); m_bank[0]->set_base(ram); m_bank[1]->set_base(ram + 0x4000); m_bank[2]->set_base(ram + 0x8000); m_bank[3]->set_base(m_maincpu_region->base() + 0x010000); } else { const uint8_t switch_val = (offset >> 4) & 0x3; switch (switch_val) { case 0: case 1: m_ppi[switch_val]->write(offset & 3, data); break; case 2: case 3: /* reserved for extension? */ break; } } } void lviv_state::machine_reset() { address_space &space = m_maincpu->space(AS_PROGRAM); m_video_ram = m_ram->pointer() + 0xc000; m_startup_mem_map = 1; space.unmap_write(0x0000, 0x3fff); space.unmap_write(0x4000, 0x7fff); space.unmap_write(0x8000, 0xbfff); space.unmap_write(0xC000, 0xffff); uint8_t *mem = m_maincpu_region->base(); m_bank[0]->set_base(mem + 0x010000); m_bank[1]->set_base(mem + 0x010000); m_bank[2]->set_base(mem + 0x010000); m_bank[3]->set_base(mem + 0x010000); /*memset(m_ram->pointer(), 0, sizeof(unsigned char)*0xffff);*/ } /******************************************************************************* Lviv snapshot files (SAV) ------------------------- 00000 - 0000D: 'LVOV/DUMP/2.0/' (like LVT-header) 0000E - 0000F: 'H+' (something additional) 00010 00h 00011 - 0C010: RAM (0000 - BFFF) 0C011 - 10010: ROM (C000 - FFFF) 10011 - 14010: Video RAM (4000 - 7FFF) 14011 - 14110: Ports map (00 - FF) 14111 - 1411C: Registers (B,C,D,E,H,L,A,F,SP,PC) 1411D - 1412A: ??? (something additional) *******************************************************************************/ void lviv_state::setup_snapshot(uint8_t * data) { /* Set registers */ uint8_t lo = data[0x14112] & 0x0ff; uint8_t hi = data[0x14111] & 0x0ff; m_maincpu->set_state_int(i8080_cpu_device::I8085_BC, (hi << 8) | lo); lo = data[0x14114] & 0x0ff; hi = data[0x14113] & 0x0ff; m_maincpu->set_state_int(i8080_cpu_device::I8085_DE, (hi << 8) | lo); lo = data[0x14116] & 0x0ff; hi = data[0x14115] & 0x0ff; m_maincpu->set_state_int(i8080_cpu_device::I8085_HL, (hi << 8) | lo); lo = data[0x14118] & 0x0ff; hi = data[0x14117] & 0x0ff; m_maincpu->set_state_int(i8080_cpu_device::I8085_AF, (hi << 8) | lo); lo = data[0x14119] & 0x0ff; hi = data[0x1411a] & 0x0ff; m_maincpu->set_state_int(i8080_cpu_device::I8085_SP, (hi << 8) | lo); lo = data[0x1411b] & 0x0ff; hi = data[0x1411c] & 0x0ff; m_maincpu->set_state_int(i8080_cpu_device::I8085_PC, (hi << 8) | lo); /* Memory dump */ memcpy (m_ram->pointer(), data+0x0011, 0xc000); memcpy (m_ram->pointer()+0xc000, data+0x10011, 0x4000); /* Ports */ m_ppi_port_outputs[0][0] = data[0x14011+0xc0]; m_ppi_port_outputs[0][1] = data[0x14011+0xc1]; update_palette(m_ppi_port_outputs[0][1]&0x7f); m_ppi_port_outputs[0][2] = data[0x14011+0xc2]; update_memory(); } void lviv_state::dump_registers() { logerror("PC = %04x\n", (unsigned) m_maincpu->state_int(i8080_cpu_device::I8085_PC)); logerror("SP = %04x\n", (unsigned) m_maincpu->state_int(i8080_cpu_device::I8085_SP)); logerror("AF = %04x\n", (unsigned) m_maincpu->state_int(i8080_cpu_device::I8085_AF)); logerror("BC = %04x\n", (unsigned) m_maincpu->state_int(i8080_cpu_device::I8085_BC)); logerror("DE = %04x\n", (unsigned) m_maincpu->state_int(i8080_cpu_device::I8085_DE)); logerror("HL = %04x\n", (unsigned) m_maincpu->state_int(i8080_cpu_device::I8085_HL)); } image_verify_result lviv_state::verify_snapshot(uint8_t * data, uint32_t size) { const char* tag = "LVOV/DUMP/2.0/"; if (strncmp(tag, (char*)data, strlen(tag))) { logerror("Not a Lviv snapshot\n"); return image_verify_result::FAIL; } if (size != LVIV_SNAPSHOT_SIZE) { logerror ("Incomplete snapshot file\n"); return image_verify_result::FAIL; } logerror("returning ID_OK\n"); return image_verify_result::PASS; } SNAPSHOT_LOAD_MEMBER(lviv_state::snapshot_cb) { std::vector snapshot_data(LVIV_SNAPSHOT_SIZE); image.fread(&snapshot_data[0], LVIV_SNAPSHOT_SIZE); if (verify_snapshot(&snapshot_data[0], snapshot_size) != image_verify_result::PASS) { return image_init_result::FAIL; } setup_snapshot(&snapshot_data[0]); dump_registers(); logerror("Snapshot file loaded\n"); return image_init_result::PASS; }