// license:BSD-3-Clause // copyright-holders:R. Belmont /*************************************************************************** apple2.c Machine file to handle emulation of the Apple II series. ***************************************************************************/ #include "emu.h" #include "includes/apple2.h" #include "imagedev/flopdrv.h" #include "machine/appldriv.h" #include "machine/applefdc.h" #include "machine/sonydriv.h" #include "debugger.h" #ifdef MAME_DEBUG #define VERBOSE 1 #else #define VERBOSE 0 #endif /* MAME_DEBUG */ #define LOG(x) do { if (VERBOSE) logerror x; } while (0) #define PROFILER_C00X PROFILER_USER2 #define PROFILER_C01X PROFILER_USER2 #define PROFILER_C08X PROFILER_USER2 #define PROFILER_A2INT PROFILER_USER2 /* ----------------------------------------------------------------------- * New Apple II memory manager * ----------------------------------------------------------------------- */ READ8_MEMBER(apple2_state::read_floatingbus) { return apple2_getfloatingbusvalue(); } void apple2_state::apple2_setup_memory(const apple2_memmap_config *config) { m_mem_config = *config; m_current_meminfo = nullptr; apple2_update_memory(); } void apple2_state::langcard_touch(offs_t offset) { uint32_t val, mask; //logerror("language card bankswitch read, offset: $c08%0x\n", offset); // determine which flags to change mask = VAR_LCWRITE | VAR_LCRAM | VAR_LCRAM2; val = 0; if (offset & 0x01) val |= VAR_LCWRITE; switch(offset & 0x03) { case 0x03: case 0x00: val |= VAR_LCRAM; break; } if ((offset & 0x08) == 0) val |= VAR_LCRAM2; // change the flags apple2_setvar(val, mask); } void apple2_state::apple2_update_memory() { address_space& space = m_maincpu->space(AS_PROGRAM); int i, bank; char rbank[10], wbank[10]; int full_update = 0; apple2_meminfo meminfo; read8_delegate *rh; write8_delegate *wh; offs_t begin, end_r, end_w; uint8_t *rbase, *wbase; uint32_t offset; bank_disposition_t bank_disposition; int wh_nop = 0; /* need to build list of current info? */ if (!m_current_meminfo) { for (i = 0; m_mem_config.memmap[i].end; i++) ; m_current_meminfo = std::make_unique(i); full_update = 1; } /* loop through the entire memory map */ bank = m_mem_config.first_bank; for (i = 0; m_mem_config.memmap[i].get_meminfo; i++) { /* retrieve information on this entry */ memset(&meminfo, 0, sizeof(meminfo)); m_mem_config.memmap[i].get_meminfo(machine(),m_mem_config.memmap[i].begin, m_mem_config.memmap[i].end, &meminfo); bank_disposition = m_mem_config.memmap[i].bank_disposition; /* do we need to memory reading? */ if (full_update || (meminfo.read_mem != m_current_meminfo[i].read_mem) || (meminfo.read_handler != m_current_meminfo[i].read_handler)) { rbase = nullptr; sprintf(rbank,"bank%d",bank); begin = m_mem_config.memmap[i].begin; end_r = m_mem_config.memmap[i].end; rh = nullptr; LOG(("apple2_update_memory(): Updating RD {%06X..%06X} [#%02d] --> %08X\n", begin, end_r, bank, meminfo.read_mem)); /* read handling */ if (meminfo.read_handler) { /* handler */ rh = meminfo.read_handler; } else if (meminfo.read_mem == APPLE2_MEM_FLOATING) { /* floating RAM */ rh = &read_delegates_master[0]; } else if ((meminfo.read_mem & 0xC0000000) == APPLE2_MEM_AUX) { /* auxillary memory */ assert(m_mem_config.auxmem); offset = meminfo.read_mem & APPLE2_MEM_MASK; rbase = &m_mem_config.auxmem[offset]; } else if ((meminfo.read_mem & 0xC0000000) == APPLE2_MEM_SLOT) { // slots 1-2 if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0) { rh = &read_delegates_master[1]; } else if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0x200) { // slot 3 rh = &read_delegates_master[2]; } else if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0x300) { // slots 4-7 rh = &read_delegates_master[3]; } else { printf("ERROR: Unhandled case for APPLE2_MEM_SLOT write_mem = %x!\n", (meminfo.write_mem & APPLE2_MEM_MASK)); } } else if ((meminfo.read_mem & 0xC0000000) == APPLE2_MEM_ROM) { /* ROM */ offset = meminfo.read_mem & APPLE2_MEM_MASK; rbase = &m_rom[offset % m_rom_length]; } else { /* RAM */ if (end_r >= m_ram->size()) end_r = m_ram->size() - 1; offset = meminfo.read_mem & APPLE2_MEM_MASK; if (end_r >= begin) rbase = &m_ram->pointer()[offset]; } /* install the actual handlers */ if (begin <= end_r) { if (rh) { space.install_read_handler(begin, end_r, *rh); } else { space.install_read_bank(begin, end_r, rbank); } } /* did we 'go past the end?' */ if (end_r < m_mem_config.memmap[i].end) space.nop_read(end_r + 1, m_mem_config.memmap[i].end); /* set the memory bank */ if (rbase) { membank(rbank)->set_base(rbase); } /* record the current settings */ m_current_meminfo[i].read_mem = meminfo.read_mem; m_current_meminfo[i].read_handler = meminfo.read_handler; } /* do we need to memory writing? */ if (full_update || (meminfo.write_mem != m_current_meminfo[i].write_mem) || (meminfo.write_handler != m_current_meminfo[i].write_handler)) { wbase = nullptr; if (bank_disposition == A2MEM_MONO) sprintf(wbank,"bank%d",bank); else if (bank_disposition == A2MEM_DUAL) sprintf(wbank,"bank%d",bank+1); begin = m_mem_config.memmap[i].begin; end_w = m_mem_config.memmap[i].end; wh = nullptr; LOG(("apple2_update_memory(): Updating WR {%06X..%06X} [#%02d] --> %08X\n", begin, end_w, bank, meminfo.write_mem)); /* write handling */ if (meminfo.write_handler) { /* handler */ wh = meminfo.write_handler; } else if ((meminfo.write_mem & 0xC0000000) == APPLE2_MEM_AUX) { /* auxillary memory */ assert(m_mem_config.auxmem); offset = meminfo.write_mem & APPLE2_MEM_MASK; wbase = &m_mem_config.auxmem[offset]; } else if ((meminfo.write_mem & 0xC0000000) == APPLE2_MEM_SLOT) { /* slot RAM/ROM */ // slots 1-2 if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0) { wh = &write_delegates_master[0]; } else if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0x200) { // slot 3 wh = &write_delegates_master[1]; } else if ((meminfo.write_mem & APPLE2_MEM_MASK) == 0x300) { // slots 4-7 wh = &write_delegates_master[2]; } } else if ((meminfo.write_mem & 0xC0000000) == APPLE2_MEM_ROM) { /* ROM */ wh_nop = 1; } else { /* RAM */ if (end_w >= m_ram->size()) end_w = m_ram->size() - 1; offset = meminfo.write_mem & APPLE2_MEM_MASK; if (end_w >= begin) wbase = &m_ram->pointer()[offset]; } /* install the actual handlers */ if (begin <= end_w) { if (wh) { space.install_write_handler(begin, end_w, *wh); } else { if (wh_nop) { space.nop_write(begin, end_w); } else { space.install_write_bank(begin, end_w, wbank); } } } /* did we 'go past the end?' */ if (end_w < m_mem_config.memmap[i].end) space.nop_write(end_w + 1, m_mem_config.memmap[i].end); /* set the memory bank */ if (wbase) { membank(wbank)->set_base(wbase); } /* record the current settings */ m_current_meminfo[i].write_mem = meminfo.write_mem; m_current_meminfo[i].write_handler = meminfo.write_handler; } bank += bank_disposition; } } void apple2_state::apple2_update_memory_postload() { apple2_update_memory(); } /* ----------------------------------------------------------------------- * Apple II memory map * ----------------------------------------------------------------------- */ READ8_MEMBER(apple2_state::apple2_c0xx_r) { if(!machine().side_effects_disabled()) { read8_delegate handlers[] = { read8_delegate(FUNC(apple2_state::apple2_c00x_r), this), read8_delegate(FUNC(apple2_state::apple2_c01x_r), this), read8_delegate(FUNC(apple2_state::apple2_c02x_r), this), read8_delegate(FUNC(apple2_state::apple2_c03x_r), this), read8_delegate(FUNC(apple2_state::apple2_c03x_r), this), // not called here, handled elsewhere read8_delegate(FUNC(apple2_state::apple2_c05x_r), this), read8_delegate(FUNC(apple2_state::apple2_c06x_r), this), read8_delegate(FUNC(apple2_state::apple2_c07x_r), this) }; offset &= 0x7F; /* normal handler */ if (offset / 0x10 != 4) { return handlers[offset / 0x10](space, offset % 0x10, 0); } } return 0; } WRITE8_MEMBER(apple2_state::apple2_c0xx_w) { write8_delegate handlers[] = { write8_delegate(FUNC(apple2_state::apple2_c00x_w), this), write8_delegate(FUNC(apple2_state::apple2_c01x_w), this), write8_delegate(FUNC(apple2_state::apple2_c02x_w), this), write8_delegate(FUNC(apple2_state::apple2_c03x_w), this), write8_delegate(FUNC(apple2_state::apple2_c03x_w), this), // unused write8_delegate(FUNC(apple2_state::apple2_c05x_w), this), write8_delegate(FUNC(apple2_state::apple2_c05x_w), this), // unused write8_delegate(FUNC(apple2_state::apple2_c07x_w), this) }; offset &= 0x7F; /* normal handler */ if (((offset / 0x10) != 4) && (offset / 0x10) != 6) { handlers[offset / 0x10](space, offset % 0x10, data, 0); } } READ8_MEMBER(apple2_state::apple2_c080_r) { if(!machine().side_effects_disabled()) { device_a2bus_card_interface *slotdevice; int slot; offset &= 0x7F; slot = offset / 0x10; if (slot == 0) { langcard_touch(offset); return 0; } /* now identify the device */ slotdevice = m_a2bus->get_a2bus_card(slot); /* and if we can, read from the slot */ if (slotdevice != nullptr) { return slotdevice->read_c0nx(offset % 0x10); } } return 0; } WRITE8_MEMBER(apple2_state::apple2_c080_w) { device_a2bus_card_interface *slotdevice; int slot; offset &= 0x7F; slot = offset / 0x10; if (slot == 0) { langcard_touch(offset); return; } /* now identify the device */ slotdevice = m_a2bus->get_a2bus_card(slot); /* and if we can, write to the slot */ if (slotdevice != nullptr) { slotdevice->write_c0nx(offset % 0x10, data); } } /* returns default CnXX slotram for a slot space */ int8_t apple2_state::apple2_slotram_r(int slotnum, int offset) { if (m_slot_ram) { if (!machine().side_effects_disabled()) { // printf("slotram_r: taking cnxx_slot to -1\n"); m_a2_cnxx_slot = -1; apple2_update_memory(); } return m_slot_ram[offset]; } // else fall through to floating bus return apple2_getfloatingbusvalue(); } READ8_MEMBER(apple2_state::apple2_c1xx_r ) { int slotnum; device_a2bus_card_interface *slotdevice; slotnum = ((offset>>8) & 0xf) + 1; slotdevice = m_a2bus->get_a2bus_card(slotnum); if (slotdevice != nullptr) { if ((slotdevice->take_c800()) && (!machine().side_effects_disabled())) { // printf("c1xx_r: taking cnxx_slot to %d\n", slotnum); m_a2_cnxx_slot = slotnum; apple2_update_memory(); } return slotdevice->read_cnxx(offset&0xff); } else { return apple2_slotram_r(slotnum, offset); } // else fall through to floating bus // never executed //return apple2_getfloatingbusvalue(); } WRITE8_MEMBER(apple2_state::apple2_c1xx_w ) { int slotnum; device_a2bus_card_interface *slotdevice; slotnum = ((offset>>8) & 0xf) + 1; slotdevice = m_a2bus->get_a2bus_card(slotnum); if (slotdevice != nullptr) { slotdevice->write_cnxx(offset&0xff, data); } else { if (m_slot_ram) m_slot_ram[offset] = data; } } READ8_MEMBER(apple2_state::apple2_c3xx_r ) { int slotnum; device_a2bus_card_interface *slotdevice; slotnum = 3; slotdevice = m_a2bus->get_a2bus_card(slotnum); // is a card installed in this slot? if (slotdevice != nullptr) { if ((slotdevice->take_c800()) && (!machine().side_effects_disabled())) { // printf("c3xx_r: taking cnxx_slot to %d\n", slotnum); m_a2_cnxx_slot = slotnum; apple2_update_memory(); } return slotdevice->read_cnxx(offset&0xff); } else { return apple2_slotram_r(slotnum, offset); } // else fall through to floating bus // never executed //return apple2_getfloatingbusvalue(); } WRITE8_MEMBER(apple2_state::apple2_c3xx_w ) { int slotnum; device_a2bus_card_interface *slotdevice; slotnum = 3; slotdevice = m_a2bus->get_a2bus_card(slotnum); if (slotdevice != nullptr) { if ((slotdevice->take_c800()) && (!machine().side_effects_disabled())) { // printf("c3xx_w: taking cnxx_slot to %d\n", slotnum); m_a2_cnxx_slot = slotnum; apple2_update_memory(); } slotdevice->write_cnxx(offset&0xff, data); } else { if (m_slot_ram) m_slot_ram[offset] = data; } } READ8_MEMBER(apple2_state::apple2_c4xx_r ) { int slotnum; device_a2bus_card_interface *slotdevice; slotnum = ((offset>>8) & 0xf) + 4; slotdevice = m_a2bus->get_a2bus_card(slotnum); // is a card installed in this slot? if (slotdevice != nullptr) { if (slotdevice->take_c800() && (m_a2_cnxx_slot != slotnum) && (!machine().side_effects_disabled())) { m_a2_cnxx_slot = slotnum; apple2_update_memory(); } return slotdevice->read_cnxx(offset&0xff); } else { return apple2_slotram_r(slotnum, offset); } // else fall through to floating bus // never executed //return apple2_getfloatingbusvalue(); } WRITE8_MEMBER ( apple2_state::apple2_c4xx_w ) { int slotnum; device_a2bus_card_interface *slotdevice; slotnum = ((offset>>8) & 0xf) + 4; slotdevice = m_a2bus->get_a2bus_card(slotnum); if (slotdevice != nullptr) { if ((slotdevice->take_c800()) && (!machine().side_effects_disabled())) { // printf("c4xx_w: taking cnxx_slot to %d\n", slotnum); m_a2_cnxx_slot = slotnum; apple2_update_memory(); } slotdevice->write_cnxx(offset&0xff, data); } else { if (m_slot_ram) m_slot_ram[offset] = data; } } READ8_MEMBER(apple2_state::apple2_cfff_r) { // debugger guard if (!machine().side_effects_disabled()) { // printf("cfff_r: taking cnxx_slot to -1\n"); m_a2_cnxx_slot = -1; apple2_update_memory(); } return apple2_getfloatingbusvalue(); } WRITE8_MEMBER(apple2_state::apple2_cfff_w) { if (!machine().side_effects_disabled()) { // printf("cfff_w: taking cnxx_slot to -1\n"); m_a2_cnxx_slot = -1; apple2_update_memory(); } } READ8_MEMBER(apple2_state::apple2_c800_r ) { device_a2bus_card_interface *slotdevice; slotdevice = m_a2bus->get_a2bus_card(m_a2_cnxx_slot); if (slotdevice != nullptr) { return slotdevice->read_c800(offset&0xfff); } return apple2_getfloatingbusvalue(); } WRITE8_MEMBER(apple2_state::apple2_c800_w ) { device_a2bus_card_interface *slotdevice; slotdevice = m_a2bus->get_a2bus_card(m_a2_cnxx_slot); if (slotdevice != nullptr) { slotdevice->write_c800(offset&0xfff, data); } } READ8_MEMBER(apple2_state::apple2_ce00_r ) { device_a2bus_card_interface *slotdevice; slotdevice = m_a2bus->get_a2bus_card(m_a2_cnxx_slot); if (slotdevice != nullptr) { return slotdevice->read_c800((offset&0xfff) + 0x600); } return apple2_getfloatingbusvalue(); } WRITE8_MEMBER(apple2_state::apple2_ce00_w ) { device_a2bus_card_interface *slotdevice; slotdevice = m_a2bus->get_a2bus_card(m_a2_cnxx_slot); if (slotdevice != nullptr) { slotdevice->write_c800((offset&0xfff)+0x600, data); } } READ8_MEMBER(apple2_state::apple2_inh_d000_r ) { device_a2bus_card_interface *slotdevice; slotdevice = m_a2bus->get_a2bus_card(m_inh_slot); if (slotdevice != nullptr) { return slotdevice->read_inh_rom(offset & 0xfff); } return apple2_getfloatingbusvalue(); } WRITE8_MEMBER(apple2_state::apple2_inh_d000_w ) { device_a2bus_card_interface *slotdevice; slotdevice = m_a2bus->get_a2bus_card(m_inh_slot); if (slotdevice != nullptr) { return slotdevice->write_inh_rom(offset & 0xfff, data); } } READ8_MEMBER(apple2_state::apple2_inh_e000_r ) { device_a2bus_card_interface *slotdevice; slotdevice = m_a2bus->get_a2bus_card(m_inh_slot); if (slotdevice != nullptr) { return slotdevice->read_inh_rom((offset & 0x1fff) + 0x1000); } return apple2_getfloatingbusvalue(); } WRITE8_MEMBER(apple2_state::apple2_inh_e000_w ) { device_a2bus_card_interface *slotdevice; slotdevice = m_a2bus->get_a2bus_card(m_inh_slot); if (slotdevice != nullptr) { slotdevice->write_inh_rom((offset & 0x1fff) + 0x1000, data); } } static void apple2_mem_0000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); meminfo->read_handler = (state->m_flags & VAR_ALTZP) ? &state->read_delegates_0000[0] : &state->read_delegates_0000[1]; meminfo->write_handler = (state->m_flags & VAR_ALTZP) ? &state->write_delegates_0000[0] : &state->write_delegates_0000[1]; } static void apple2_mem_0200(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); meminfo->read_handler = (state->m_flags & VAR_RAMRD) ? &state->read_delegates_0200[0] : &state->read_delegates_0200[1]; meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_0200[0] : &state->write_delegates_0200[1]; } static void apple2_mem_0400(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); if (state->m_flags & VAR_80STORE) { meminfo->read_handler = (state->m_flags & VAR_PAGE2) ? &state->read_delegates_0400[0] : &state->read_delegates_0400[1]; meminfo->write_handler = (state->m_flags & VAR_PAGE2) ? &state->write_delegates_0400[0] : &state->write_delegates_0400[1]; } else { meminfo->read_handler = (state->m_flags & VAR_RAMRD) ? &state->read_delegates_0400[0] : &state->read_delegates_0400[1]; meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_0400[0] : &state->write_delegates_0400[1]; } } static void apple2_mem_0800(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); meminfo->read_handler = (state->m_flags & VAR_RAMRD) ? &state->read_delegates_0800[0] : &state->read_delegates_0800[1]; meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_0800[0] : &state->write_delegates_0800[1]; } static void apple2_mem_2000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); if ((state->m_flags & (VAR_80STORE|VAR_HIRES)) == (VAR_80STORE|VAR_HIRES)) { meminfo->read_handler = (state->m_flags & VAR_PAGE2) ? &state->read_delegates_2000[0] : &state->read_delegates_2000[1]; meminfo->write_handler = (state->m_flags & VAR_PAGE2) ? &state->write_delegates_2000[0] : &state->write_delegates_2000[1]; } else { meminfo->read_handler = (state->m_flags & VAR_RAMRD) ? &state->read_delegates_2000[0] : &state->read_delegates_2000[1]; meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_2000[0] : &state->write_delegates_2000[1]; } } static void apple2_mem_4000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); meminfo->read_handler = (state->m_flags & VAR_RAMRD) ? &state->read_delegates_4000[0] : &state->read_delegates_4000[1]; meminfo->write_handler = (state->m_flags & VAR_RAMWRT) ? &state->write_delegates_4000[0] : &state->write_delegates_4000[1]; } static void apple2_mem_C000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); meminfo->read_handler = &state->rd_c000; meminfo->write_handler = &state->wd_c000; } static void apple2_mem_C080(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); meminfo->read_handler = &state->rd_c080; meminfo->write_handler = &state->wd_c080; } static void tk2000_mem_C100(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); if (state->m_flags & VAR_TK2000RAM) { meminfo->read_mem = 0x00C100; meminfo->write_mem = 0x00C100; } else { meminfo->read_mem = (begin & 0x3fff) | APPLE2_MEM_ROM; meminfo->write_mem = 0x00C100; } } static void apple2_mem_CFFF(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); meminfo->read_handler = &state->rd_cfff; meminfo->write_handler = &state->wd_cfff; } static void apple2_mem_Cx00(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); if (state->m_flags & VAR_INTCXROM) { meminfo->read_mem = (begin & 0x0FFF) | (state->m_flags & VAR_ROMSWITCH ? 0x4000 : 0x0000) | APPLE2_MEM_ROM; meminfo->write_mem = APPLE2_MEM_FLOATING; } else { meminfo->read_mem = ((begin & 0x0FFF) - 0x100) | APPLE2_MEM_SLOT; meminfo->write_mem = ((begin & 0x0FFF) - 0x100) | APPLE2_MEM_SLOT; } } static void apple2_mem_C300(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); if (((state->m_flags & (VAR_INTCXROM|VAR_SLOTC3ROM)) != VAR_SLOTC3ROM) && !(state->m_flags_mask & VAR_SLOTC3ROM)) { meminfo->read_mem = (begin & 0x0FFF) | (state->m_flags & VAR_ROMSWITCH ? 0x4000 : 0x0000) | APPLE2_MEM_ROM; meminfo->write_mem = APPLE2_MEM_FLOATING; } else { meminfo->read_mem = ((begin & 0x0FFF) - 0x100) | APPLE2_MEM_SLOT; meminfo->write_mem = ((begin & 0x0FFF) - 0x100) | APPLE2_MEM_SLOT; } } static void apple2_mem_C800(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); if ((state->m_flags & VAR_INTCXROM) || (state->m_a2_cnxx_slot == -1)) { meminfo->read_mem = (begin & 0x0FFF) | (state->m_flags & VAR_ROMSWITCH ? 0x4000 : 0x0000) | APPLE2_MEM_ROM; meminfo->write_mem = APPLE2_MEM_FLOATING; } else { meminfo->read_handler = &state->rd_c800; meminfo->write_handler = &state->wd_c800; } } static void apple2_mem_CE00(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); if ((state->m_flags & VAR_ROMSWITCH) && !strcmp(machine.system().name, "apple2cp")) { meminfo->read_mem = APPLE2_MEM_AUX; meminfo->write_mem = APPLE2_MEM_AUX; } else { if ((state->m_flags & VAR_INTCXROM) || (state->m_a2_cnxx_slot == -1)) { meminfo->read_mem = (begin & 0x0FFF) | (state->m_flags & VAR_ROMSWITCH ? 0x4000 : 0x0000) | APPLE2_MEM_ROM; meminfo->write_mem = APPLE2_MEM_FLOATING; } else { meminfo->read_handler = &state->rd_ce00; meminfo->write_handler = &state->wd_ce00; } } } static void apple2_mem_D000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); if (state->m_inh_slot == -1) { if (state->m_flags & VAR_LCRAM) { if (state->m_flags & VAR_LCRAM2) { meminfo->read_handler = (state->m_flags & VAR_ALTZP) ? &state->read_delegates_c000[0] : &state->read_delegates_c000[1]; } else { meminfo->read_handler = (state->m_flags & VAR_ALTZP) ? &state->read_delegates_d000[0] : &state->read_delegates_d000[1]; } } else { meminfo->read_mem = (state->m_flags & VAR_ROMSWITCH) ? 0x005000 : 0x001000; meminfo->read_mem |= APPLE2_MEM_ROM; } if (state->m_flags & VAR_LCWRITE) { if (state->m_flags & VAR_LCRAM2) { meminfo->write_handler = (state->m_flags & VAR_ALTZP) ? &state->write_delegates_c000[0] : &state->write_delegates_c000[1]; } else { meminfo->write_handler = (state->m_flags & VAR_ALTZP) ? &state->write_delegates_d000[0] : &state->write_delegates_d000[1]; } } else { meminfo->write_mem = APPLE2_MEM_FLOATING; } } else { meminfo->read_handler = &state->rd_inh_d000; meminfo->write_handler = &state->wd_inh_d000; } } static void apple2_mem_E000(running_machine &machine, offs_t begin, offs_t end, apple2_meminfo *meminfo) { apple2_state *state = machine.driver_data(); if (state->m_inh_slot == -1) { if (state->m_flags & VAR_LCRAM) { meminfo->read_handler = (state->m_flags & VAR_ALTZP) ? &state->read_delegates_e000[0] : &state->read_delegates_e000[1]; } else { meminfo->read_mem = (state->m_flags & VAR_ROMSWITCH) ? 0x006000 : 0x002000; meminfo->read_mem |= APPLE2_MEM_ROM; } if (state->m_flags & VAR_LCWRITE) { meminfo->write_handler = (state->m_flags & VAR_ALTZP) ? &state->write_delegates_e000[0] : &state->write_delegates_e000[1]; } else { meminfo->write_mem = APPLE2_MEM_FLOATING; } } else { meminfo->read_handler = &state->rd_inh_e000; meminfo->write_handler = &state->wd_inh_e000; } } static const apple2_memmap_entry apple2_memmap_entries[] = { { 0x0000, 0x01FF, apple2_mem_0000, A2MEM_MONO }, { 0x0200, 0x03FF, apple2_mem_0200, A2MEM_DUAL }, { 0x0400, 0x07FF, apple2_mem_0400, A2MEM_DUAL }, { 0x0800, 0x1FFF, apple2_mem_0800, A2MEM_DUAL }, { 0x2000, 0x3FFF, apple2_mem_2000, A2MEM_DUAL }, { 0x4000, 0xBFFF, apple2_mem_4000, A2MEM_DUAL }, { 0xC000, 0xC07F, apple2_mem_C000, A2MEM_IO }, { 0xC080, 0xC0FF, apple2_mem_C080, A2MEM_IO }, { 0xC100, 0xC2FF, apple2_mem_Cx00, A2MEM_MONO }, { 0xC300, 0xC3FF, apple2_mem_C300, A2MEM_MONO }, { 0xC400, 0xC7FF, apple2_mem_Cx00, A2MEM_MONO }, { 0xC800, 0xCDFF, apple2_mem_C800, A2MEM_MONO }, { 0xCE00, 0xCFFE, apple2_mem_CE00, A2MEM_MONO }, { 0xCFFF, 0xCFFF, apple2_mem_CFFF, A2MEM_IO }, { 0xD000, 0xDFFF, apple2_mem_D000, A2MEM_DUAL }, { 0xE000, 0xFFFF, apple2_mem_E000, A2MEM_DUAL }, { 0 } }; static const apple2_memmap_entry tk2000_memmap_entries[] = { { 0x0000, 0x01FF, apple2_mem_0000, A2MEM_MONO }, { 0x0200, 0x03FF, apple2_mem_0200, A2MEM_DUAL }, { 0x0400, 0x07FF, apple2_mem_0400, A2MEM_DUAL }, { 0x0800, 0x1FFF, apple2_mem_0800, A2MEM_DUAL }, { 0x2000, 0x3FFF, apple2_mem_2000, A2MEM_DUAL }, { 0x4000, 0xBFFF, apple2_mem_4000, A2MEM_DUAL }, { 0xC000, 0xC07F, apple2_mem_C000, A2MEM_IO }, { 0xC080, 0xC0FF, apple2_mem_C080, A2MEM_IO }, { 0xC100, 0xFFFF, tk2000_mem_C100, A2MEM_DUAL }, { 0 } }; void apple2_state::apple2_setvar(uint32_t val, uint32_t mask) { LOG(("apple2_setvar(): val=0x%06x mask=0x%06x pc=0x%04x\n", val, mask, (unsigned int) m_maincpu->pc())); assert((val & mask) == val); /* apply mask and set */ val &= m_a2_mask; val |= m_a2_set; /* change the softswitch */ m_flags &= ~mask; m_flags |= val; // disable flags that don't apply (INTCXROM/SLOTC3ROM on II/II+ for instance) m_flags &= ~m_flags_mask; apple2_update_memory(); } /* ----------------------------------------------------------------------- * Floating bus code * * preliminary floating bus video scanner code - look for comments * with FIX: * ----------------------------------------------------------------------- */ uint8_t apple2_state::apple2_getfloatingbusvalue() { enum { // scanner types kScannerNone = 0, kScannerApple2, kScannerApple2e, // scanner constants kHBurstClock = 53, // clock when Color Burst starts kHBurstClocks = 4, // clocks per Color Burst duration kHClock0State = 0x18, // H[543210] = 011000 kHClocks = 65, // clocks per horizontal scan (including HBL) kHPEClock = 40, // clock when HPE (horizontal preset enable) goes low kHPresetClock = 41, // clock when H state presets kHSyncClock = 49, // clock when HSync starts kHSyncClocks = 4, // clocks per HSync duration kNTSCScanLines = 262, // total scan lines including VBL (NTSC) kNTSCVSyncLine = 224, // line when VSync starts (NTSC) kPALScanLines = 312, // total scan lines including VBL (PAL) kPALVSyncLine = 264, // line when VSync starts (PAL) kVLine0State = 0x100, // V[543210CBA] = 100000000 kVPresetLine = 256, // line when V state presets kVSyncLines = 4, // lines per VSync duration kClocksPerVSync = kHClocks * kNTSCScanLines // FIX: NTSC only? }; // vars // int i, Hires, Mixed, Page2, _80Store, ScanLines, /* VSyncLine, ScanCycles,*/ h_clock, h_state, h_0, h_1, h_2, h_3, h_4, h_5, v_line, v_state, v_A, v_B, v_C, v_0, v_1, v_2, v_3, v_4, /* v_5, */ _hires, addend0, addend1, addend2, sum, address; // video scanner data // i = m_maincpu->total_cycles() % kClocksPerVSync; // cycles into this VSync // machine state switches // Hires = (m_flags & VAR_HIRES) ? 1 : 0; Mixed = (m_flags & VAR_MIXED) ? 1 : 0; Page2 = (m_flags & VAR_PAGE2) ? 1 : 0; _80Store = (m_flags & VAR_80STORE) ? 1 : 0; // calculate video parameters according to display standard // ScanLines = 1 ? kNTSCScanLines : kPALScanLines; // FIX: NTSC only? // VSyncLine = 1 ? kNTSCVSyncLine : kPALVSyncLine; // FIX: NTSC only? // ScanCycles = ScanLines * kHClocks; // calculate horizontal scanning state // h_clock = (i + kHPEClock) % kHClocks; // which horizontal scanning clock h_state = kHClock0State + h_clock; // H state bits if (h_clock >= kHPresetClock) // check for horizontal preset { h_state -= 1; // correct for state preset (two 0 states) } h_0 = (h_state >> 0) & 1; // get horizontal state bits h_1 = (h_state >> 1) & 1; h_2 = (h_state >> 2) & 1; h_3 = (h_state >> 3) & 1; h_4 = (h_state >> 4) & 1; h_5 = (h_state >> 5) & 1; // calculate vertical scanning state // v_line = i / kHClocks; // which vertical scanning line v_state = kVLine0State + v_line; // V state bits if ((v_line >= kVPresetLine)) // check for previous vertical state preset { v_state -= ScanLines; // compensate for preset } v_A = (v_state >> 0) & 1; // get vertical state bits v_B = (v_state >> 1) & 1; v_C = (v_state >> 2) & 1; v_0 = (v_state >> 3) & 1; v_1 = (v_state >> 4) & 1; v_2 = (v_state >> 5) & 1; v_3 = (v_state >> 6) & 1; v_4 = (v_state >> 7) & 1; //v_5 = (v_state >> 8) & 1; // calculate scanning memory address // _hires = Hires; if (Hires && Mixed && (v_4 & v_2)) { _hires = 0; // (address is in text memory) } addend0 = 0x68; // 1 1 0 1 addend1 = (h_5 << 5) | (h_4 << 4) | (h_3 << 3); addend2 = (v_4 << 6) | (v_3 << 5) | (v_4 << 4) | (v_3 << 3); sum = (addend0 + addend1 + addend2) & (0x0F << 3); address = 0; address |= h_0 << 0; // a0 address |= h_1 << 1; // a1 address |= h_2 << 2; // a2 address |= sum; // a3 - aa6 address |= v_0 << 7; // a7 address |= v_1 << 8; // a8 address |= v_2 << 9; // a9 address |= ((_hires) ? v_A : (1 ^ (Page2 & (1 ^ _80Store)))) << 10; // a10 address |= ((_hires) ? v_B : (Page2 & (1 ^ _80Store))) << 11; // a11 if (_hires) // hires? { // Y: insert hires only address bits // address |= v_C << 12; // a12 address |= (1 ^ (Page2 & (1 ^ _80Store))) << 13; // a13 address |= (Page2 & (1 ^ _80Store)) << 14; // a14 } else { // N: text, so no higher address bits unless Apple ][, not Apple //e // if ((1) && // Apple ][? // FIX: check for Apple ][? (FB is most useful in old games) (kHPEClock <= h_clock) && // Y: HBL? (h_clock <= (kHClocks - 1))) { address |= 1 << 12; // Y: a12 (add $1000 to address!) } } // update VBL' state // if (v_4 & v_3) // VBL? { //CMemory::mState &= ~CMemory::kVBLBar; // Y: VBL' is false // FIX: MESS? } else { //CMemory::mState |= CMemory::kVBLBar; // N: VBL' is true // FIX: MESS? } return m_ram->pointer()[address % m_ram->size()]; // FIX: this seems to work, but is it right!? } /* ----------------------------------------------------------------------- * Machine reset * ----------------------------------------------------------------------- */ void apple2_state::machine_reset() { int need_intcxrom; m_reset_flag = 0; m_rambase = m_ram->pointer(); apple2_refresh_delegates(); need_intcxrom = !strcmp(machine().system().name, "apple2c") || !strcmp(machine().system().name, "apple2c0") || !strcmp(machine().system().name, "apple2c3") || !strcmp(machine().system().name, "apple2c4") || !strcmp(machine().system().name, "prav8c") || !strcmp(machine().system().name, "apple2cp") || !strncmp(machine().system().name, "apple2g", 7); apple2_setvar(need_intcxrom ? VAR_INTCXROM : 0, ~0); // IIgs ROM 0 cannot boot unless language card bank 2 is write-enabled (but read ROM) on startup // Peter Ferrie reports this is also the default on the IIe/IIc at least apple2_setvar(VAR_LCWRITE|VAR_LCRAM2, VAR_LCWRITE | VAR_LCRAM | VAR_LCRAM2); m_a2_speaker_state = 0; m_a2_cnxx_slot = -1; // bank in ROM at C800 on reset m_joystick_x1_time = m_joystick_y1_time = 0; m_joystick_x2_time = m_joystick_y2_time = 0; memset(m_exp_regs, 0, sizeof(uint8_t) * 0x10); m_exp_wptr = m_exp_liveptr = 0; } int apple2_state::a2_no_ctrl_reset() { return ((m_kbrepeat.found() && !m_resetdip.found()) || (m_resetdip.found() && !m_resetdip->read())); } /* ----------------------------------------------------------------------- * Apple II interrupt; used to force partial updates * ----------------------------------------------------------------------- */ TIMER_DEVICE_CALLBACK_MEMBER(apple2_state::apple2_interrupt) { int scanline = param; if((scanline % 8) == 0) m_screen->update_partial(m_screen->vpos()); if ((m_kbspecial->read() & 0x80) && (a2_no_ctrl_reset() || (m_kbspecial->read() & 0x08))) { if (!m_reset_flag) { m_reset_flag = 1; /* using PULSE_LINE does not allow us to press and hold key */ m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); } return; } if (m_reset_flag) { m_reset_flag = 0; m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); machine().schedule_soft_reset(); } } /*************************************************************************** apple2_mainramxx00_r apple2_mainramxx00_w apple2_auxramxx00_r apple2_auxramxx00_w ***************************************************************************/ READ8_MEMBER ( apple2_state::apple2_mainram0000_r ) { return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_mainram0200_r ) { offset += 0x200; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_mainram0400_r ) { offset += 0x400; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_mainram0800_r ) { offset += 0x800; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_mainram2000_r ) { offset += 0x2000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_mainram4000_r ) { offset += 0x4000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_mainramc000_r ) { offset += 0xc000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_mainramd000_r ) { offset += 0xd000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_mainrame000_r ) { offset += 0xe000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_auxram0000_r ) { if (m_auxslotdevice) { return m_auxslotdevice->read_auxram(offset); } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return 0xff; } offset += 0x10000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_auxram0200_r ) { if (m_auxslotdevice) { return m_auxslotdevice->read_auxram(offset+0x200); } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return 0xff; } offset += 0x10200; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_auxram0400_r ) { if (m_auxslotdevice) { return m_auxslotdevice->read_auxram(offset+0x400); } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return 0xff; } offset += 0x10400; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_auxram0800_r ) { if (m_auxslotdevice) { return m_auxslotdevice->read_auxram(offset+0x800); } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return 0xff; } offset += 0x10800; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_auxram2000_r ) { if (m_auxslotdevice) { return m_auxslotdevice->read_auxram(offset+0x2000); } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return 0xff; } offset += 0x12000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_auxram4000_r ) { if (m_auxslotdevice) { return m_auxslotdevice->read_auxram(offset+0x4000); } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return 0xff; } offset += 0x14000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_auxramc000_r ) { if (m_auxslotdevice) { return m_auxslotdevice->read_auxram(offset+0xc000); } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return 0xff; } offset += 0x1c000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_auxramd000_r ) { if (m_auxslotdevice) { return m_auxslotdevice->read_auxram(offset+0xd000); } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return 0xff; } offset += 0x1d000; return m_rambase[offset]; } READ8_MEMBER ( apple2_state::apple2_auxrame000_r ) { if (m_auxslotdevice) { return m_auxslotdevice->read_auxram(offset+0xe000); } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return 0xff; } offset += 0x1e000; return m_rambase[offset]; } WRITE8_MEMBER ( apple2_state::apple2_mainram0000_w ) { m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_mainram0200_w ) { offset += 0x200; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_mainram0400_w ) { offset += 0x400; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_mainram0800_w ) { offset += 0x800; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_mainram2000_w ) { offset += 0x2000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_mainram4000_w ) { offset += 0x4000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_mainramc000_w ) { offset += 0xc000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_mainramd000_w ) { offset += 0xd000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_mainrame000_w ) { offset += 0xe000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_auxram0000_w ) { if (m_auxslotdevice) { m_auxslotdevice->write_auxram(offset, data); return; } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return; } offset += 0x10000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_auxram0200_w ) { if (m_auxslotdevice) { m_auxslotdevice->write_auxram(offset+0x200, data); return; } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return; } offset += 0x10200; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_auxram0400_w ) { if (m_auxslotdevice) { m_auxslotdevice->write_auxram(offset+0x400, data); return; } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return; } offset += 0x10400; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_auxram0800_w ) { if (m_auxslotdevice) { m_auxslotdevice->write_auxram(offset+0x800, data); return; } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return; } offset += 0x10800; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_auxram2000_w ) { if (m_auxslotdevice) { m_auxslotdevice->write_auxram(offset+0x2000, data); return; } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return; } offset += 0x12000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_auxram4000_w ) { if (m_auxslotdevice) { m_auxslotdevice->write_auxram(offset+0x4000, data); return; } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return; } offset += 0x14000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_auxramc000_w ) { if (m_auxslotdevice) { m_auxslotdevice->write_auxram(offset+0xc000, data); return; } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return; } offset += 0x1c000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_auxramd000_w ) { if (m_auxslotdevice) { m_auxslotdevice->write_auxram(offset+0xd000, data); return; } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return; } offset += 0x1d000; m_rambase[offset] = data; } WRITE8_MEMBER ( apple2_state::apple2_auxrame000_w ) { if (m_auxslotdevice) { m_auxslotdevice->write_auxram(offset+0xe000, data); return; } else if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { return; } offset += 0x1e000; m_rambase[offset] = data; } /*************************************************************************** apple2_c00x_r ***************************************************************************/ READ8_MEMBER ( apple2_state::apple2_c00x_r ) { uint8_t result = 0; if(!machine().side_effects_disabled()) { /* Read the keyboard data and strobe */ g_profiler.start(PROFILER_C00X); result = m_transchar | m_strobe; g_profiler.stop(); } return result; } /*************************************************************************** apple2_c00x_w C000 80STOREOFF C001 80STOREON - use 80-column memory mapping C002 RAMRDOFF C003 RAMRDON - read from aux 48k C004 RAMWRTOFF C005 RAMWRTON - write to aux 48k C006 INTCXROMOFF C007 INTCXROMON C008 ALTZPOFF C009 ALTZPON - use aux ZP, stack and language card area C00A SLOTC3ROMOFF C00B SLOTC3ROMON - use external slot 3 ROM C00C 80COLOFF C00D 80COLON - use 80-column display mode C00E ALTCHARSETOFF C00F ALTCHARSETON - use alt character set ***************************************************************************/ WRITE8_MEMBER ( apple2_state::apple2_c00x_w ) { uint32_t mask; mask = 1 << (offset / 2); apple2_setvar((offset & 1) ? mask : 0, mask); } /*************************************************************************** apple2_c01x_r ***************************************************************************/ READ8_MEMBER( apple2_state::apple2_c01x_r ) { uint8_t result = apple2_getfloatingbusvalue() & 0x7F; if(!machine().side_effects_disabled()) { g_profiler.start(PROFILER_C01X); LOG(("a2 softswitch_r: %04x\n", offset + 0xc010)); switch (offset) { case 0x00: result |= m_transchar | m_strobe; m_strobe = 0; break; case 0x01: result |= (m_flags & VAR_LCRAM2) ? 0x80 : 0x00; break; case 0x02: result |= (m_flags & VAR_LCRAM) ? 0x80 : 0x00; break; case 0x03: result |= (m_flags & VAR_RAMRD) ? 0x80 : 0x00; break; case 0x04: result |= (m_flags & VAR_RAMWRT) ? 0x80 : 0x00; break; case 0x05: result |= (m_flags & VAR_INTCXROM) ? 0x80 : 0x00; break; case 0x06: result |= (m_flags & VAR_ALTZP) ? 0x80 : 0x00; break; case 0x07: result |= (m_flags & VAR_SLOTC3ROM) ? 0x80 : 0x00; break; case 0x08: result |= (m_flags & VAR_80STORE) ? 0x80 : 0x00; break; case 0x09: result |= !m_screen->vblank() ? 0x80 : 0x00; break; case 0x0A: result |= (m_flags & VAR_TEXT) ? 0x80 : 0x00; break; case 0x0B: result |= (m_flags & VAR_MIXED) ? 0x80 : 0x00; break; case 0x0C: result |= (m_flags & VAR_PAGE2) ? 0x80 : 0x00; break; case 0x0D: result |= (m_flags & VAR_HIRES) ? 0x80 : 0x00; break; case 0x0E: result |= (m_flags & VAR_ALTCHARSET) ? 0x80 : 0x00; break; case 0x0F: result |= (m_flags & VAR_80COL) ? 0x80 : 0x00; break; } g_profiler.stop(); } return result; } /*************************************************************************** apple2_c01x_w ***************************************************************************/ WRITE8_MEMBER( apple2_state::apple2_c01x_w ) { /* Clear the keyboard strobe */ g_profiler.start(PROFILER_C01X); m_strobe = 0; g_profiler.stop(); } /*************************************************************************** apple2_c02x_r ***************************************************************************/ READ8_MEMBER( apple2_state::apple2_c02x_r ) { if(!machine().side_effects_disabled()) { apple2_c02x_w(space, offset, 0, 0); } return apple2_getfloatingbusvalue(); } /*************************************************************************** apple2_c02x_w ***************************************************************************/ WRITE8_MEMBER( apple2_state::apple2_c02x_w ) { switch(offset) { case 0x08: apple2_setvar((m_flags & VAR_ROMSWITCH) ^ VAR_ROMSWITCH, VAR_ROMSWITCH); break; } } /*************************************************************************** apple2_c03x_r ***************************************************************************/ READ8_MEMBER ( apple2_state::apple2_c03x_r ) { if(!machine().side_effects_disabled()) { if (!offset) { speaker_sound_device *speaker = machine().device("a2speaker"); m_a2_speaker_state ^= 1; speaker->level_w(m_a2_speaker_state); } } return apple2_getfloatingbusvalue(); } /*************************************************************************** apple2_c03x_w ***************************************************************************/ WRITE8_MEMBER ( apple2_state::apple2_c03x_w ) { apple2_c03x_r(space, offset, 0); } /*************************************************************************** apple2_c05x_r ***************************************************************************/ READ8_MEMBER ( apple2_state::apple2_c05x_r ) { if(!machine().side_effects_disabled()) { uint32_t mask; if (m_machinetype == TK2000) { if (offset == 0xa) // RAM { apple2_setvar(VAR_TK2000RAM, ~0); } else if (offset == 0xb) // ROM { apple2_setvar(0, ~VAR_TK2000RAM); } } /* ANx has reverse SET logic */ if (offset >= 8) { offset ^= 1; } mask = 0x100 << (offset / 2); apple2_setvar((offset & 1) ? mask : 0, mask); } return apple2_getfloatingbusvalue(); } /*************************************************************************** apple2_c05x_w ***************************************************************************/ WRITE8_MEMBER ( apple2_state::apple2_c05x_w ) { apple2_c05x_r(space, offset, 0); } /*************************************************************************** apple2_c06x_r ***************************************************************************/ READ8_MEMBER ( apple2_state::apple2_c06x_r ) { int result = 0; if(!machine().side_effects_disabled()) { switch (offset & 0x0F) { case 0x00: /* Cassette input */ { if (m_cassette) { result = m_cassette->input() > 0.0 ? 0x80 : 0; } else { result = 0; } } break; case 0x01: /* Open-Apple/Joystick button 0 */ result = apple2_pressed_specialkey(0x10); break; case 0x02: /* Closed-Apple/Joystick button 1 */ result = apple2_pressed_specialkey(0x20); break; case 0x03: /* Joystick button 2. Later revision motherboards connected this to SHIFT also */ result = apple2_pressed_specialkey(0x40); break; case 0x04: /* X Joystick 1 axis */ result = machine().time().as_double() < m_joystick_x1_time; break; case 0x05: /* Y Joystick 1 axis */ result = machine().time().as_double() < m_joystick_y1_time; break; case 0x06: /* X Joystick 2 axis */ result = machine().time().as_double() < m_joystick_x2_time; break; case 0x07: /* Y Joystick 2 axis */ result = machine().time().as_double() < m_joystick_y2_time; break; default: /* c060 Empty Cassette head read * and any other non joystick c06 port returns this according to applewin */ return apple2_getfloatingbusvalue(); } } return result ? 0x80 : 0x00; } /*************************************************************************** apple2_c07x_r ***************************************************************************/ READ8_MEMBER ( apple2_state::apple2_c07x_r ) { if(!machine().side_effects_disabled()) { double x_calibration = attotime::from_usec(12).as_double(); double y_calibration = attotime::from_usec(13).as_double(); if (offset == 0) { m_joystick_x1_time = machine().time().as_double() + x_calibration * m_joy1x->read(); m_joystick_y1_time = machine().time().as_double() + y_calibration * m_joy1y->read(); m_joystick_x2_time = machine().time().as_double() + x_calibration * m_joy2x->read(); m_joystick_y2_time = machine().time().as_double() + y_calibration * m_joy2y->read(); } } return 0; } /*************************************************************************** apple2_c07x_w ***************************************************************************/ WRITE8_MEMBER ( apple2_state::apple2_c07x_w ) { // this a machine with an aux slot? if (m_auxslotdevice) { m_auxslotdevice->write_c07x(space, offset&0xf, data); } // AE RamWorks manual indicates that even if the auxslot card sees the c07x write, // so does the motherboard and it will trigger the paddles. So always call this. apple2_c07x_r(space, offset, 0); } /* ----------------------------------------------------------------------- * Floppy disk controller * ----------------------------------------------------------------------- */ int apple2_state::apple2_fdc_has_35() { return (floppy_get_count(machine())); // - apple525_get_count(machine)) > 0; } int apple2_state::apple2_fdc_has_525() { return 1; //apple525_get_count(machine) > 0; } static void apple2_fdc_set_lines(device_t *device, uint8_t lines) { apple2_state *state = device->machine().driver_data(); if (state->m_fdc_diskreg & 0x40) { if (state->apple2_fdc_has_35()) { /* slot 5: 3.5" disks */ sony_set_lines(device,lines); } } else { if (state->apple2_fdc_has_525()) { /* slot 6: 5.25" disks */ apple525_set_lines(device,lines); } } } static void apple2_fdc_set_enable_lines(device_t *device,int enable_mask) { apple2_state *state = device->machine().driver_data(); int slot5_enable_mask = 0; int slot6_enable_mask = 0; if (state->m_fdc_diskreg & 0x40) slot5_enable_mask = enable_mask; else slot6_enable_mask = enable_mask; if (state->apple2_fdc_has_35()) { /* set the 3.5" enable lines */ sony_set_enable_lines(device,slot5_enable_mask); } if (state->apple2_fdc_has_525()) { /* set the 5.25" enable lines */ apple525_set_enable_lines(device,slot6_enable_mask); } } static uint8_t apple2_fdc_read_data(device_t *device) { apple2_state *state = device->machine().driver_data(); uint8_t result = 0x00; if (state->m_fdc_diskreg & 0x40) { if (state->apple2_fdc_has_35()) { /* slot 5: 3.5" disks */ result = sony_read_data(device); } } else { if (state->apple2_fdc_has_525()) { /* slot 6: 5.25" disks */ result = apple525_read_data(device); } } return result; } static void apple2_fdc_write_data(device_t *device, uint8_t data) { apple2_state *state = device->machine().driver_data(); if (state->m_fdc_diskreg & 0x40) { if (state->apple2_fdc_has_35()) { /* slot 5: 3.5" disks */ sony_write_data(device,data); } } else { if (state->apple2_fdc_has_525()) { /* slot 6: 5.25" disks */ apple525_write_data(device,data); } } } static int apple2_fdc_read_status(device_t *device) { apple2_state *state = device->machine().driver_data(); int result = 0; if (state->m_fdc_diskreg & 0x40) { if (state->apple2_fdc_has_35()) { /* slot 5: 3.5" disks */ result = sony_read_status(device); } } else { if (state->apple2_fdc_has_525()) { /* slot 6: 5.25" disks */ result = apple525_read_status(device); } } return result; } void apple2_state::apple2_iwm_setdiskreg(uint8_t data) { m_fdc_diskreg = data & 0xC0; if (apple2_fdc_has_35()) sony_set_sel_line( machine().device("fdc"),m_fdc_diskreg & 0x80); } const applefdc_interface apple2_fdc_interface = { apple2_fdc_set_lines, /* set_lines */ apple2_fdc_set_enable_lines, /* set_enable_lines */ apple2_fdc_read_data, /* read_data */ apple2_fdc_write_data, /* write_data */ apple2_fdc_read_status /* read_status */ }; /* ----------------------------------------------------------------------- * Driver init * ----------------------------------------------------------------------- */ void apple2_state::apple2_init_common() { m_inh_slot = -1; m_flags = 0; m_fdc_diskreg = 0; // do these lookups once at startup m_rom = memregion("maincpu")->base(); m_rom_length = memregion("maincpu")->bytes() & ~0xFFF; m_slot_length = memregion("maincpu")->bytes() - m_rom_length; m_slot_ram = (m_slot_length > 0) ? &m_rom[m_rom_length] : nullptr; m_auxslotdevice = nullptr; if (m_machinetype == APPLE_IIE || m_machinetype == TK3000) { m_auxslotdevice = m_a2eauxslot->get_a2eauxslot_card(); } /* state save registers */ save_item(NAME(m_flags)); machine().save().register_postload(save_prepost_delegate(FUNC(apple2_state::apple2_update_memory_postload), this)); /* --------------------------------------------- * * set up the softswitch mask/set * * --------------------------------------------- */ m_a2_mask = ~0; m_a2_set = 0; /* disable VAR_ROMSWITCH if the ROM is only 16k */ if (memregion("maincpu")->bytes() < 0x8000) m_a2_mask &= ~VAR_ROMSWITCH; if (m_ram->size() <= 64*1024) m_a2_mask &= ~(VAR_RAMRD | VAR_RAMWRT | VAR_80STORE | VAR_ALTZP | VAR_80COL); apple2_refresh_delegates(); } void apple2_state::apple2eplus_init_common(void *apple2cp_ce00_ram) { apple2_memmap_config mem_cfg; m_flags_mask = 0; apple2_init_common(); /* setup memory */ memset(&mem_cfg, 0, sizeof(mem_cfg)); mem_cfg.first_bank = 1; mem_cfg.memmap = apple2_memmap_entries; mem_cfg.auxmem = (uint8_t*)apple2cp_ce00_ram; apple2_setup_memory(&mem_cfg); } MACHINE_START_MEMBER(apple2_state,apple2c) { m_machinetype = APPLE_IIC; apple2eplus_init_common((void *)nullptr); } MACHINE_START_MEMBER(apple2_state,tk3000) { m_machinetype = TK3000; // enhanced IIe clone with Z80 keyboard scanner subcpu apple2eplus_init_common((void *)nullptr); } MACHINE_START_MEMBER(apple2_state,apple2cp) { void *apple2cp_ce00_ram; /* there appears to be some hidden RAM that is swapped in on the Apple * IIc plus; I have not found any official documentation but the BIOS * clearly uses this area as writeable memory */ apple2cp_ce00_ram = auto_alloc_array(machine(), uint8_t, 0x200); memset(apple2cp_ce00_ram, 0, sizeof(uint8_t) * 0x200); m_machinetype = APPLE_IICPLUS; apple2eplus_init_common(apple2cp_ce00_ram); } MACHINE_START_MEMBER(apple2_state,apple2e) { apple2_memmap_config mem_cfg; m_flags_mask = 0; m_machinetype = APPLE_IIE; apple2_init_common(); /* setup memory */ memset(&mem_cfg, 0, sizeof(mem_cfg)); mem_cfg.first_bank = 1; mem_cfg.memmap = apple2_memmap_entries; mem_cfg.auxmem = (uint8_t*)nullptr; apple2_setup_memory(&mem_cfg); } MACHINE_START_MEMBER(apple2_state,laser128) { apple2_memmap_config mem_cfg; m_flags_mask = 0; m_machinetype = LASER128; apple2_init_common(); // 1 MB of expansion RAM in slot 5 m_exp_ram = std::make_unique(1024*1024); memset(m_exp_ram.get(), 0xff, 1024*1024); m_exp_bankhior = 0xf0; m_exp_addrmask = 0xfffff; // save memory expansion vars save_item(NAME(m_exp_regs)); save_item(NAME(m_exp_wptr)); save_item(NAME(m_exp_liveptr)); save_item(NAME(m_exp_bankhior)); save_item(NAME(m_exp_addrmask)); /* setup memory */ memset(&mem_cfg, 0, sizeof(mem_cfg)); mem_cfg.first_bank = 1; mem_cfg.memmap = apple2_memmap_entries; mem_cfg.auxmem = (uint8_t*)nullptr; apple2_setup_memory(&mem_cfg); } MACHINE_START_MEMBER(apple2_state,apple2orig) { apple2_memmap_config mem_cfg; void *apple2cp_ce00_ram = nullptr; // II and II+ have no internal ROM or internal slot 3 h/w, so don't allow these states m_flags_mask = VAR_INTCXROM|VAR_SLOTC3ROM; m_machinetype = APPLE_II; apple2_init_common(); /* setup memory */ memset(&mem_cfg, 0, sizeof(mem_cfg)); mem_cfg.first_bank = 1; mem_cfg.memmap = apple2_memmap_entries; mem_cfg.auxmem = (uint8_t*)apple2cp_ce00_ram; apple2_setup_memory(&mem_cfg); } MACHINE_START_MEMBER(apple2_state,space84) { apple2_memmap_config mem_cfg; void *apple2cp_ce00_ram = nullptr; // II and II+ have no internal ROM or internal slot 3 h/w, so don't allow these states m_flags_mask = VAR_INTCXROM|VAR_SLOTC3ROM; m_machinetype = SPACE84; apple2_init_common(); /* setup memory */ memset(&mem_cfg, 0, sizeof(mem_cfg)); mem_cfg.first_bank = 1; mem_cfg.memmap = apple2_memmap_entries; mem_cfg.auxmem = (uint8_t*)apple2cp_ce00_ram; apple2_setup_memory(&mem_cfg); } MACHINE_START_MEMBER(apple2_state,laba2p) { apple2_memmap_config mem_cfg; void *apple2cp_ce00_ram = nullptr; // II and II+ have no internal ROM or internal slot 3 h/w, so don't allow these states m_flags_mask = VAR_INTCXROM|VAR_SLOTC3ROM; m_machinetype = LABA2P; apple2_init_common(); /* setup memory */ memset(&mem_cfg, 0, sizeof(mem_cfg)); mem_cfg.first_bank = 1; mem_cfg.memmap = apple2_memmap_entries; mem_cfg.auxmem = (uint8_t*)apple2cp_ce00_ram; apple2_setup_memory(&mem_cfg); } MACHINE_START_MEMBER(apple2_state,tk2000) { apple2_memmap_config mem_cfg; // II and II+ have no internal ROM or internal slot 3 h/w, so don't allow these states m_flags_mask = VAR_INTCXROM|VAR_SLOTC3ROM; m_machinetype = TK2000; apple2_init_common(); /* setup memory */ memset(&mem_cfg, 0, sizeof(mem_cfg)); mem_cfg.first_bank = 1; mem_cfg.memmap = tk2000_memmap_entries; mem_cfg.auxmem = (uint8_t*)nullptr; apple2_setup_memory(&mem_cfg); } int apple2_state::apple2_pressed_specialkey(uint8_t key) { return (m_kbspecial.read_safe(0) & key) || (m_joybuttons.read_safe(0) & key); } void apple2_state::apple2_refresh_delegates() { read_delegates_master[0] = read8_delegate(FUNC(apple2_state::read_floatingbus), this); read_delegates_master[1] = read8_delegate(FUNC(apple2_state::apple2_c1xx_r), this); read_delegates_master[2] = read8_delegate(FUNC(apple2_state::apple2_c3xx_r), this); read_delegates_master[3] = read8_delegate(FUNC(apple2_state::apple2_c4xx_r), this); write_delegates_master[0] = write8_delegate(FUNC(apple2_state::apple2_c1xx_w), this); write_delegates_master[1] = write8_delegate(FUNC(apple2_state::apple2_c3xx_w), this); write_delegates_master[2] = write8_delegate(FUNC(apple2_state::apple2_c4xx_w), this); rd_c000 = read8_delegate(FUNC(apple2_state::apple2_c0xx_r), this); wd_c000 = write8_delegate(FUNC(apple2_state::apple2_c0xx_w), this); rd_c080 = read8_delegate(FUNC(apple2_state::apple2_c080_r), this); wd_c080 = write8_delegate(FUNC(apple2_state::apple2_c080_w), this); rd_cfff = read8_delegate(FUNC(apple2_state::apple2_cfff_r), this); wd_cfff = write8_delegate(FUNC(apple2_state::apple2_cfff_w), this); rd_c800 = read8_delegate(FUNC(apple2_state::apple2_c800_r), this); wd_c800 = write8_delegate(FUNC(apple2_state::apple2_c800_w), this); rd_ce00 = read8_delegate(FUNC(apple2_state::apple2_ce00_r), this); wd_ce00 = write8_delegate(FUNC(apple2_state::apple2_ce00_w), this); rd_inh_d000 = read8_delegate(FUNC(apple2_state::apple2_inh_d000_r), this); wd_inh_d000 = write8_delegate(FUNC(apple2_state::apple2_inh_d000_w), this); rd_inh_e000 = read8_delegate(FUNC(apple2_state::apple2_inh_e000_r), this); wd_inh_e000 = write8_delegate(FUNC(apple2_state::apple2_inh_e000_w), this); read_delegates_0000[0] = read8_delegate(FUNC(apple2_state::apple2_auxram0000_r), this); read_delegates_0000[1] = read8_delegate(FUNC(apple2_state::apple2_mainram0000_r), this); read_delegates_0200[0] = read8_delegate(FUNC(apple2_state::apple2_auxram0200_r), this); read_delegates_0200[1] = read8_delegate(FUNC(apple2_state::apple2_mainram0200_r), this); read_delegates_0400[0] = read8_delegate(FUNC(apple2_state::apple2_auxram0400_r), this); read_delegates_0400[1] = read8_delegate(FUNC(apple2_state::apple2_mainram0400_r), this); read_delegates_0800[0] = read8_delegate(FUNC(apple2_state::apple2_auxram0800_r), this); read_delegates_0800[1] = read8_delegate(FUNC(apple2_state::apple2_mainram0800_r), this); read_delegates_2000[0] = read8_delegate(FUNC(apple2_state::apple2_auxram2000_r), this); read_delegates_2000[1] = read8_delegate(FUNC(apple2_state::apple2_mainram2000_r), this); read_delegates_4000[0] = read8_delegate(FUNC(apple2_state::apple2_auxram4000_r), this); read_delegates_4000[1] = read8_delegate(FUNC(apple2_state::apple2_mainram4000_r), this); read_delegates_c000[0] = read8_delegate(FUNC(apple2_state::apple2_auxramc000_r), this); read_delegates_c000[1] = read8_delegate(FUNC(apple2_state::apple2_mainramc000_r), this); read_delegates_d000[0] = read8_delegate(FUNC(apple2_state::apple2_auxramd000_r), this); read_delegates_d000[1] = read8_delegate(FUNC(apple2_state::apple2_mainramd000_r), this); read_delegates_e000[0] = read8_delegate(FUNC(apple2_state::apple2_auxrame000_r), this); read_delegates_e000[1] = read8_delegate(FUNC(apple2_state::apple2_mainrame000_r), this); write_delegates_0000[0] = write8_delegate(FUNC(apple2_state::apple2_auxram0000_w), this); write_delegates_0000[1] = write8_delegate(FUNC(apple2_state::apple2_mainram0000_w), this); write_delegates_0200[0] = write8_delegate(FUNC(apple2_state::apple2_auxram0200_w), this); write_delegates_0200[1] = write8_delegate(FUNC(apple2_state::apple2_mainram0200_w), this); write_delegates_0400[0] = write8_delegate(FUNC(apple2_state::apple2_auxram0400_w), this); write_delegates_0400[1] = write8_delegate(FUNC(apple2_state::apple2_mainram0400_w), this); write_delegates_0800[0] = write8_delegate(FUNC(apple2_state::apple2_auxram0800_w), this); write_delegates_0800[1] = write8_delegate(FUNC(apple2_state::apple2_mainram0800_w), this); write_delegates_2000[0] = write8_delegate(FUNC(apple2_state::apple2_auxram2000_w), this); write_delegates_2000[1] = write8_delegate(FUNC(apple2_state::apple2_mainram2000_w), this); write_delegates_4000[0] = write8_delegate(FUNC(apple2_state::apple2_auxram4000_w), this); write_delegates_4000[1] = write8_delegate(FUNC(apple2_state::apple2_mainram4000_w), this); write_delegates_c000[0] = write8_delegate(FUNC(apple2_state::apple2_auxramc000_w), this); write_delegates_c000[1] = write8_delegate(FUNC(apple2_state::apple2_mainramc000_w), this); write_delegates_d000[0] = write8_delegate(FUNC(apple2_state::apple2_auxramd000_w), this); write_delegates_d000[1] = write8_delegate(FUNC(apple2_state::apple2_mainramd000_w), this); write_delegates_e000[0] = write8_delegate(FUNC(apple2_state::apple2_auxrame000_w), this); write_delegates_e000[1] = write8_delegate(FUNC(apple2_state::apple2_mainrame000_w), this); } READ_LINE_MEMBER(apple2_state::ay3600_shift_r) { // either shift key if (m_kbspecial->read() & 0x06) { return ASSERT_LINE; } return CLEAR_LINE; } READ_LINE_MEMBER(apple2_state::ay3600_control_r) { if (m_kbspecial->read() & 0x08) { return ASSERT_LINE; } return CLEAR_LINE; } static const uint8_t a2_key_remap[0x32][4] = { /* norm shft ctrl both */ { 0x33,0x23,0x33,0x23 }, /* 3 # 00 */ { 0x34,0x24,0x34,0x24 }, /* 4 $ 01 */ { 0x35,0x25,0x35,0x25 }, /* 5 % 02 */ { 0x36,0x5e,0x35,0x53 }, /* 6 ^ 03 */ { 0x37,0x26,0x37,0x26 }, /* 7 & 04 */ { 0x38,0x2a,0x38,0x2a }, /* 8 * 05 */ { 0x39,0x28,0x39,0x28 }, /* 9 ( 06 */ { 0x30,0x29,0x30,0x29 }, /* 0 ) 07 */ { 0x3b,0x3a,0x3b,0x3a }, /* ; : 08 */ { 0x2d,0x5f,0x2d,0x1f }, /* - _ 09 */ { 0x51,0x51,0x11,0x11 }, /* q Q 0a */ { 0x57,0x57,0x17,0x17 }, /* w W 0b */ { 0x45,0x45,0x05,0x05 }, /* e E 0c */ { 0x52,0x52,0x12,0x12 }, /* r R 0d */ { 0x54,0x54,0x14,0x14 }, /* t T 0e */ { 0x59,0x59,0x19,0x19 }, /* y Y 0f */ { 0x55,0x55,0x15,0x15 }, /* u U 10 */ { 0x49,0x49,0x09,0x09 }, /* i I 11 */ { 0x4f,0x4f,0x0f,0x0f }, /* o O 12 */ { 0x50,0x50,0x10,0x10 }, /* p P 13 */ { 0x44,0x44,0x04,0x04 }, /* d D 14 */ { 0x46,0x46,0x06,0x06 }, /* f F 15 */ { 0x47,0x47,0x07,0x07 }, /* g G 16 */ { 0x48,0x48,0x08,0x08 }, /* h H 17 */ { 0x4a,0x4a,0x0a,0x0a }, /* j J 18 */ { 0x4b,0x4b,0x0b,0x0b }, /* k K 19 */ { 0x4c,0x4c,0x0c,0x0c }, /* l L 1a */ { 0x3d,0x2b,0x3d,0x2b }, /* = + 1b */ { 0x08,0x08,0x08,0x08 }, /* Left 1c */ { 0x15,0x15,0x15,0x15 }, /* Right 1d */ { 0x5a,0x5a,0x1a,0x1a }, /* z Z 1e */ { 0x58,0x58,0x18,0x18 }, /* x X 1f */ { 0x43,0x43,0x03,0x03 }, /* c C 20 */ { 0x56,0x56,0x16,0x16 }, /* v V 21 */ { 0x42,0x42,0x02,0x02 }, /* b B 22 */ { 0x4e,0x4e,0x0e,0x0e }, /* n N 23 */ { 0x4d,0x4d,0x0d,0x0d }, /* m M 24 */ { 0x2c,0x3c,0x2c,0x3c }, /* , < 25 */ { 0x2e,0x3e,0x2e,0x3e }, /* . > 26 */ { 0x2f,0x3f,0x2f,0x3f }, /* / ? 27 */ { 0x53,0x53,0x13,0x13 }, /* s S 28 */ { 0x32,0x40,0x32,0x00 }, /* 2 @ 29 */ { 0x31,0x21,0x31,0x31 }, /* 1 ! 2a */ { 0x9b,0x9b,0x9b,0x9b }, /* Escape 2b */ { 0x41,0x41,0x01,0x01 }, /* a A 2c */ { 0x20,0x20,0x20,0x20 }, /* Space 2d */ { 0x00,0x00,0x00,0x00 }, /* 0x2e unused */ { 0x00,0x00,0x00,0x00 }, /* 0x2f unused */ { 0x00,0x00,0x00,0x00 }, /* 0x30 unused */ { 0x0d,0x0d,0x0d,0x0d }, /* Enter 31 */ }; WRITE_LINE_MEMBER(apple2_state::ay3600_data_ready_w) { if (state == ASSERT_LINE) { int mod = 0; m_lastchar = m_ay3600->b_r(); mod = (m_kbspecial->read() & 0x06) ? 0x01 : 0x00; mod |= (m_kbspecial->read() & 0x08) ? 0x02 : 0x00; m_transchar = a2_key_remap[m_lastchar&0x3f][mod]; if (m_transchar != 0) { m_strobe = 0x80; // printf("new char = %04x (%02x)\n", m_lastchar&0x3f, m_transchar); } } } WRITE_LINE_MEMBER(apple2_state::ay3600_iie_data_ready_w) { if (state == ASSERT_LINE) { uint8_t *decode = m_kbdrom->base(); uint16_t trans; m_lastchar = m_ay3600->b_r(); trans = m_lastchar & ~(0x1c0); // clear the 3600's control/shift stuff trans |= (m_lastchar & 0x100)>>2; // bring the 0x100 bit down to the 0x40 place trans <<= 2; // 4 entries per key trans |= (m_kbspecial->read() & 0x06) ? 0x00 : 0x01; // shift is bit 1 (active low) trans |= (m_kbspecial->read() & 0x08) ? 0x00 : 0x02; // control is bit 2 (active low) trans |= (m_kbspecial->read() & 0x01) ? 0x0000 : 0x0200; // caps lock is bit 9 (active low) m_transchar = decode[trans]; m_strobe = 0x80; // printf("new char = %04x (%02x)\n", m_lastchar, m_transchar); } }