// 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<apple2_meminfo[]>(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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<speaker_sound_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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<apple2_state>();
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<uint8_t[]>(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);
}
}