There's too much opportunity for confusion if these are overridden further down the tree.
4011 lines
111 KiB
C++
4011 lines
111 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:R. Belmont
|
|
/***************************************************************************
|
|
|
|
apple2gs.cpp - Apple IIgs
|
|
|
|
Next generation driver written June 2018 by R. Belmont.
|
|
Thanks to the original Apple IIgs driver's authors: Nathan Woods and R. Belmont
|
|
Thanks also to the Apple II Documentation Project/Antoine Vignau, Peter Ferrie, and Olivier Galibert.
|
|
|
|
Unique hardware configurations:
|
|
- ROM 00/01: original motherboard, 256K of RAM (banks 00/01/E0/E1 only), FPI chip manages fast/slow side
|
|
- ROM 03: revised motherboard, 1M of RAM (banks 00/01/->0F/E0/E1), CYA chip replaces FPI
|
|
- Expanded IIe: ROM 00/01 motherboard in a IIe case with a IIe keyboard rather than ADB
|
|
- "Mark Twain" prototype: ROM 3 hardware, SWIM1 instead of IWM, built-in floppy, integrated High-Speed SCSI Card
|
|
and internal SCSI HDD, 2 SIMM slots for RAM expansion instead of the proprietary memory slot of the previous IIgs.
|
|
Only 5 slots: slots 5 and 7 are missing (5 for the SuperDrive, 7 for the SCSI).
|
|
|
|
Timing in terms of the 14M 14.3181818 MHz clock (1/2 of the 28.6363636 master clock):
|
|
- 1 2.8 MHz 65816 cycle is 5 14M clocks.
|
|
- The Mega II 1 MHz side runs for 64 cycles at 14 14M clocks and every 65th is stretched to 16 14M clocks.
|
|
This allows 8-bit Apple II raster demos to work. Each scanline is (64*14) + 16 = 912 14M clocks.
|
|
Due to this stretch, which does not occur on the fast side, the fast and 1 Mhz sides drift from each other
|
|
and sync up every 22800 14M clocks (25 scan lines).
|
|
- Accesses to the 1 MHz side incur a side-sync penalty (waiting for the start of the next 1 MHz cycle).
|
|
- Every 50 14M clocks (10 65816 cycles) DRAM refresh occurs for 5 14M clocks
|
|
* During this time, CPU accesses to ROM, Mega II side I/O, or banks E0/E1 are not penalized (but a side-sync penalty is incurred for the 1 MHz side)
|
|
* Accesses to banks 00-7F are penalized except for I/O in banks 0/1.
|
|
- ROM accesses always run at full speed.
|
|
|
|
One video line is: 6 cycles of right border, 13 cycles of hblank, 6 cycles of left border, and 40 cycles of active video
|
|
|
|
((6*14)*2) + 560 = 728 (total for A2 modes) htotal = 910 (65 * 14)
|
|
((6*16)*2) + 640 = 832 (total for SHR) htotal = 1040 (65 * 16)
|
|
|
|
FF6ACF is speed test in ROM
|
|
Diags:
|
|
A138 = scanline interrupt test (raster is too long to pass this)
|
|
A179 = pass
|
|
A17C = fail 1
|
|
A0F1 = fail 2
|
|
|
|
ZipGS notes:
|
|
$C059 is the GS settings register
|
|
bit 3: CPS Follow
|
|
bit 4: Counter Delay
|
|
bit 5: AppleTalk Delay
|
|
bit 6: Joystick Delay
|
|
bit 7: C/D cache disable
|
|
|
|
$C05D is the speed percentage:
|
|
$F0 = 6%, $E0 = 12%, $D0 = 18%, $C0 = 25%, $B0 = 31%, $A0 = 37%, $90 = 43%, $80 = 50%,
|
|
$70 = 56%, $60 = 62%, $50 = 68%, $40 = 75%, $30 = 81%, $20 = 87%, $10 = 93%, $00 = 100%
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
|
|
#include "apple2video.h"
|
|
|
|
#include "apple2common.h"
|
|
// #include "machine/apple2host.h"
|
|
#include "macadb.h"
|
|
#include "macrtc.h"
|
|
|
|
#include "bus/a2bus/a2bus.h"
|
|
#include "bus/a2bus/cards.h"
|
|
#include "bus/a2gameio/gameio.h"
|
|
#include "bus/rs232/rs232.h"
|
|
#include "cpu/g65816/g65816.h"
|
|
#include "cpu/m6502/m5074x.h"
|
|
#include "machine/bankdev.h"
|
|
#include "machine/ram.h"
|
|
#include "machine/timer.h"
|
|
#include "machine/z80scc.h"
|
|
#include "sound/es5503.h"
|
|
#include "sound/spkrdev.h"
|
|
|
|
#include "machine/applefdintf.h"
|
|
#include "machine/iwm.h"
|
|
#include "machine/swim1.h"
|
|
|
|
#include "screen.h"
|
|
#include "softlist_dev.h"
|
|
#include "speaker.h"
|
|
|
|
#include "utf8.h"
|
|
|
|
|
|
namespace {
|
|
|
|
// various timing standards
|
|
#define A2GS_MASTER_CLOCK (XTAL(28'636'363))
|
|
#define A2GS_14M (A2GS_MASTER_CLOCK/2)
|
|
#define A2GS_7M (A2GS_MASTER_CLOCK/4)
|
|
#define A2GS_2_8M (A2GS_MASTER_CLOCK/10)
|
|
#define A2GS_1M (XTAL(1021800))
|
|
|
|
#define A2GS_UPPERBANK_TAG "inhbank"
|
|
#define A2GS_AUXUPPER_TAG "inhaux"
|
|
#define A2GS_00UPPER_TAG "inh00"
|
|
#define A2GS_01UPPER_TAG "inh01"
|
|
|
|
#define A2GS_C300_TAG "c3bank"
|
|
#define A2GS_LCBANK_TAG "lcbank"
|
|
#define A2GS_LCAUX_TAG "lcaux"
|
|
#define A2GS_LC00_TAG "lc00"
|
|
#define A2GS_LC01_TAG "lc01"
|
|
#define A2GS_B0CXXX_TAG "bnk0atc"
|
|
#define A2GS_B1CXXX_TAG "bnk1atc"
|
|
#define A2GS_B00000_TAG "b0r00bank"
|
|
#define A2GS_B00200_TAG "b0r02bank"
|
|
#define A2GS_B00400_TAG "b0r04bank"
|
|
#define A2GS_B00800_TAG "b0r08bank"
|
|
#define A2GS_B02000_TAG "b0r20bank"
|
|
#define A2GS_B04000_TAG "b0r40bank"
|
|
|
|
#define A2GS_KBD_SPEC_TAG "keyb_special"
|
|
|
|
class apple2gs_state : public driver_device
|
|
{
|
|
public:
|
|
apple2gs_state(const machine_config &mconfig, device_type type, const char *tag)
|
|
: driver_device(mconfig, type, tag),
|
|
m_maincpu(*this, "maincpu"),
|
|
m_screen(*this, "screen"),
|
|
m_scantimer(*this, "scantimer"),
|
|
m_vgctimer(*this, "vgctimer"),
|
|
m_acceltimer(*this, "acceltimer"),
|
|
m_adbmicro(*this, "adbmicro"),
|
|
m_macadb(*this, "macadb"),
|
|
m_ram(*this, "ram"),
|
|
m_rom(*this, "maincpu"),
|
|
m_docram(*this, "docram"),
|
|
m_video(*this, "a2video"),
|
|
m_rtc(*this, "rtc"),
|
|
m_a2bus(*this, "a2bus"),
|
|
m_a2common(*this, "a2common"),
|
|
// m_a2host(*this, "a2host"),
|
|
m_gameio(*this, "gameio"),
|
|
m_speaker(*this, "speaker_sound"),
|
|
m_upperbank(*this, A2GS_UPPERBANK_TAG),
|
|
m_upperaux(*this, A2GS_AUXUPPER_TAG),
|
|
m_upper00(*this, A2GS_00UPPER_TAG),
|
|
m_upper01(*this, A2GS_01UPPER_TAG),
|
|
m_c300bank(*this, A2GS_C300_TAG),
|
|
m_b0_0000bank(*this, A2GS_B00000_TAG),
|
|
m_b0_0200bank(*this, A2GS_B00200_TAG),
|
|
m_b0_0400bank(*this, A2GS_B00400_TAG),
|
|
m_b0_0800bank(*this, A2GS_B00800_TAG),
|
|
m_b0_2000bank(*this, A2GS_B02000_TAG),
|
|
m_b0_4000bank(*this, A2GS_B04000_TAG),
|
|
m_e0_0000bank(*this, "e0_0000_bank"),
|
|
m_e0_0200bank(*this, "e0_0200_bank"),
|
|
m_e0_0400bank(*this, "e0_0400_bank"),
|
|
m_e0_0800bank(*this, "e0_0800_bank"),
|
|
m_e0_2000bank(*this, "e0_2000_bank"),
|
|
m_e0_4000bank(*this, "e0_4000_bank"),
|
|
m_lcbank(*this, A2GS_LCBANK_TAG),
|
|
m_lcaux(*this, A2GS_LCAUX_TAG),
|
|
m_lc00(*this, A2GS_LC00_TAG),
|
|
m_lc01(*this, A2GS_LC01_TAG),
|
|
m_bank0_atc(*this, A2GS_B0CXXX_TAG),
|
|
m_bank1_atc(*this, A2GS_B1CXXX_TAG),
|
|
m_scc(*this, "scc"),
|
|
m_doc(*this, "doc"),
|
|
m_iwm(*this, "fdc"),
|
|
m_floppy(*this, "fdc:%d", 0U),
|
|
m_sysconfig(*this, "a2_config")
|
|
|
|
{
|
|
m_cur_floppy = nullptr;
|
|
m_devsel = 0;
|
|
m_diskreg = 0;
|
|
}
|
|
|
|
void apple2gs(machine_config &config);
|
|
void apple2gsr1(machine_config &config);
|
|
void apple2gsmt(machine_config &config);
|
|
|
|
void rom1_init() { m_is_rom3 = false; }
|
|
void rom3_init() { m_is_rom3 = true; }
|
|
|
|
protected:
|
|
virtual void machine_start() override ATTR_COLD;
|
|
virtual void machine_reset() override ATTR_COLD;
|
|
|
|
private:
|
|
required_device<g65816_device> m_maincpu;
|
|
required_device<screen_device> m_screen;
|
|
required_device<timer_device> m_scantimer, m_vgctimer, m_acceltimer;
|
|
required_device<m5074x_device> m_adbmicro;
|
|
required_device<macadb_device> m_macadb;
|
|
required_device<ram_device> m_ram;
|
|
required_region_ptr<u8> m_rom;
|
|
required_shared_ptr<u8> m_docram;
|
|
required_device<a2_video_device> m_video;
|
|
required_device<rtc3430042_device> m_rtc;
|
|
required_device<a2bus_device> m_a2bus;
|
|
required_device<apple2_common_device> m_a2common;
|
|
// required_device<apple2_host_device> m_a2host;
|
|
required_device<apple2_gameio_device> m_gameio;
|
|
required_device<speaker_sound_device> m_speaker;
|
|
memory_view m_upperbank, m_upperaux, m_upper00, m_upper01;
|
|
required_device<address_map_bank_device> m_c300bank;
|
|
memory_view m_b0_0000bank, m_b0_0200bank, m_b0_0400bank, m_b0_0800bank, m_b0_2000bank, m_b0_4000bank;
|
|
memory_view m_e0_0000bank, m_e0_0200bank, m_e0_0400bank, m_e0_0800bank, m_e0_2000bank, m_e0_4000bank;
|
|
memory_view m_lcbank, m_lcaux, m_lc00, m_lc01, m_bank0_atc, m_bank1_atc;
|
|
required_device<z80scc_device> m_scc;
|
|
required_device<es5503_device> m_doc;
|
|
required_device<applefdintf_device> m_iwm;
|
|
required_device_array<floppy_connector, 4> m_floppy;
|
|
required_ioport m_sysconfig;
|
|
|
|
static constexpr int CNXX_UNCLAIMED = -1;
|
|
static constexpr int CNXX_INTROM = -2;
|
|
|
|
enum glu_reg_names
|
|
{
|
|
// these are the MCU-visible registers
|
|
GLU_KEY_DATA = 0, // MCU W
|
|
GLU_COMMAND, // MCU R
|
|
GLU_MOUSEX, // MCU W
|
|
GLU_MOUSEY, // MCU W
|
|
GLU_KG_STATUS, // MCU R
|
|
GLU_ANY_KEY_DOWN, // MCU W
|
|
GLU_KEYMOD, // MCU W
|
|
GLU_DATA, // MCU W
|
|
|
|
GLU_C000, // 816 R
|
|
GLU_C010, // 816 RW
|
|
GLU_SYSSTAT // 816 R/(limited) W
|
|
};
|
|
|
|
|
|
static constexpr u8 KGS_ANY_KEY_DOWN = 0x01;
|
|
static constexpr u8 KGS_KEYSTROBE = 0x10;
|
|
static constexpr u8 KGS_DATA_FULL = 0x20;
|
|
static constexpr u8 KGS_COMMAND_FULL = 0x40;
|
|
static constexpr u8 KGS_MOUSEX_FULL = 0x80;
|
|
|
|
static constexpr u8 GLU_STATUS_CMDFULL = 0x01;
|
|
static constexpr u8 GLU_STATUS_MOUSEXY = 0x02;
|
|
static constexpr u8 GLU_STATUS_KEYDATIRQEN = 0x04;
|
|
static constexpr u8 GLU_STATUS_KEYDATIRQ = 0x08;
|
|
static constexpr u8 GLU_STATUS_DATAIRQEN = 0x10;
|
|
static constexpr u8 GLU_STATUS_DATAIRQ = 0x20;
|
|
static constexpr u8 GLU_STATUS_MOUSEIRQEN = 0x40;
|
|
static constexpr u8 GLU_STATUS_MOUSEIRQ = 0x080;
|
|
|
|
static constexpr u8 SHAD_IOLC = 0x40; // I/O and language card inhibit for banks 00/01
|
|
static constexpr u8 SHAD_TXTPG2 = 0x20; // inhibits text-page 2 shadowing in both banks (ROM 03 h/w only)
|
|
static constexpr u8 SHAD_AUXHIRES = 0x10; // inhibits bank 01 hi-res region shadowing
|
|
static constexpr u8 SHAD_SUPERHIRES = 0x08; // inhibits bank 01 super-hi-res region shadowing
|
|
static constexpr u8 SHAD_HIRESPG2 = 0x04; // inhibits hi-res page 2 shadowing in both banks
|
|
static constexpr u8 SHAD_HIRESPG1 = 0x02; // inhibits hi-res page 1 shadowing in both banks
|
|
static constexpr u8 SHAD_TXTPG1 = 0x01; // inhibits text-page 1 shadowing in both banks
|
|
|
|
static constexpr u8 SPEED_HIGH = 0x80; // full 2.8 MHz speed when set, Apple II 1 MHz when clear
|
|
[[maybe_unused]] static constexpr u8 SPEED_POWERON = 0x40; // ROM 03 only; indicates machine turned on by power switch (as opposed to ?)
|
|
static constexpr u8 SPEED_ALLBANKS = 0x10; // enables bank 0/1 shadowing in all banks (not supported)
|
|
[[maybe_unused]] static constexpr u8 SPEED_DISKIISL7 = 0x08; // enable Disk II motor on detect for slot 7
|
|
[[maybe_unused]] static constexpr u8 SPEED_DISKIISL6 = 0x04; // enable Disk II motor on detect for slot 6
|
|
[[maybe_unused]] static constexpr u8 SPEED_DISKIISL5 = 0x02; // enable Disk II motor on detect for slot 5
|
|
[[maybe_unused]] static constexpr u8 SPEED_DISKIISL4 = 0x01; // enable Disk II motor on detect for slot 4
|
|
|
|
static constexpr u8 DISKREG_HDSEL = 7; // select signal for 3.5" Sony drives
|
|
static constexpr u8 DISKREG_35SEL = 6; // 1 to enable 3.5" drives, 0 to chain through to 5.25"
|
|
|
|
enum irq_sources
|
|
{
|
|
IRQS_DOC = 0,
|
|
IRQS_SCAN = 1,
|
|
IRQS_ADB = 2,
|
|
IRQS_VBL = 3,
|
|
IRQS_SECOND = 4,
|
|
IRQS_QTRSEC = 5,
|
|
IRQS_SLOT = 6,
|
|
IRQS_SCC = 7
|
|
};
|
|
|
|
static constexpr u8 INTFLAG_IRQASSERTED = 0x01;
|
|
[[maybe_unused]] static constexpr u8 INTFLAG_M2MOUSEMOVE = 0x02;
|
|
[[maybe_unused]] static constexpr u8 INTFLAG_M2MOUSESW = 0x04;
|
|
static constexpr u8 INTFLAG_VBL = 0x08;
|
|
static constexpr u8 INTFLAG_QUARTER = 0x10;
|
|
static constexpr u8 INTFLAG_AN3 = 0x20;
|
|
[[maybe_unused]] static constexpr u8 INTFLAG_MOUSEDOWNLAST = 0x40;
|
|
[[maybe_unused]] static constexpr u8 INTFLAG_MOUSEDOWN = 0x80;
|
|
|
|
[[maybe_unused]] static constexpr u8 VGCINT_EXTERNALEN = 0x01;
|
|
static constexpr u8 VGCINT_SCANLINEEN = 0x02;
|
|
static constexpr u8 VGCINT_SECONDENABLE = 0x04;
|
|
[[maybe_unused]] static constexpr u8 VGCINT_EXTERNAL = 0x10;
|
|
static constexpr u8 VGCINT_SCANLINE = 0x20;
|
|
static constexpr u8 VGCINT_SECOND = 0x40;
|
|
static constexpr u8 VGCINT_ANYVGCINT = 0x80;
|
|
|
|
enum adbstate_t
|
|
{
|
|
ADBSTATE_IDLE,
|
|
ADBSTATE_INCOMMAND,
|
|
ADBSTATE_INRESPONSE
|
|
};
|
|
|
|
bool m_adb_line = false;
|
|
|
|
address_space *m_maincpu_space = nullptr;
|
|
|
|
// align timing to match observed hardware behavior
|
|
static constexpr int ALIGN_VBL = 4;
|
|
static constexpr int ALIGN_CNT = 2;
|
|
static constexpr int ALIGN_RFB = 1;
|
|
static constexpr int HPOS_VBL = BORDER_LEFT + ((40 - ALIGN_VBL) * 16);
|
|
// hardware testing shows SCB IRQs fire 8 video cycles after VBL
|
|
static constexpr int HPOS_VGC = HPOS_VBL + (8 * 16);
|
|
TIMER_DEVICE_CALLBACK_MEMBER(apple2_interrupt);
|
|
TIMER_DEVICE_CALLBACK_MEMBER(apple2_vgc);
|
|
TIMER_DEVICE_CALLBACK_MEMBER(accel_timer);
|
|
|
|
void palette_init(palette_device &palette);
|
|
|
|
void apple2gs_map(address_map &map) ATTR_COLD;
|
|
void vectors_map(address_map &map) ATTR_COLD;
|
|
void a2gs_es5503_map(address_map &map) ATTR_COLD;
|
|
void c300bank_map(address_map &map) ATTR_COLD;
|
|
|
|
void phases_w(uint8_t phases);
|
|
void sel35_w(int sel35);
|
|
void devsel_w(uint8_t devsel);
|
|
void hdsel_w(int hdsel);
|
|
|
|
floppy_image_device *m_cur_floppy = nullptr;
|
|
int m_devsel = 0;
|
|
u8 m_diskreg = 0;
|
|
|
|
u8 auxram0000_r(offs_t offset);
|
|
void auxram0000_w(offs_t offset, u8 data);
|
|
u8 b0ram0000_r(offs_t offset);
|
|
void b0ram0000_w(offs_t offset, u8 data);
|
|
u8 b0ram0200_r(offs_t offset);
|
|
void b0ram0200_w(offs_t offset, u8 data);
|
|
u8 b0ram0400_r(offs_t offset);
|
|
void b0ram0400_w(offs_t offset, u8 data);
|
|
u8 b0ram0800_r(offs_t offset);
|
|
void b0ram0800_w(offs_t offset, u8 data);
|
|
u8 b0ram2000_r(offs_t offset);
|
|
void b0ram2000_w(offs_t offset, u8 data);
|
|
u8 b0ram4000_r(offs_t offset);
|
|
void b0ram4000_w(offs_t offset, u8 data);
|
|
u8 b1ram0000_r(offs_t offset);
|
|
void b1ram0000_w(offs_t offset, u8 data);
|
|
u8 b1ram0200_r(offs_t offset);
|
|
void b1ram0200_w(offs_t offset, u8 data);
|
|
u8 b1ram0400_r(offs_t offset);
|
|
void b1ram0400_w(offs_t offset, u8 data);
|
|
u8 b1ram0800_r(offs_t offset);
|
|
void b1ram0800_w(offs_t offset, u8 data);
|
|
u8 b1ram2000_r(offs_t offset);
|
|
void b1ram2000_w(offs_t offset, u8 data);
|
|
u8 b1ram4000_r(offs_t offset);
|
|
void b1ram4000_w(offs_t offset, u8 data);
|
|
|
|
template <int Addr> u8 e0ram_r(offs_t offset);
|
|
template <int Addr> void e0ram_w(offs_t offset, u8 data);
|
|
template <int Addr> u8 e1ram_r(offs_t offset);
|
|
template <int Addr> void e1ram_w(offs_t offset, u8 data);
|
|
|
|
u8 c000_r(offs_t offset);
|
|
void c000_w(offs_t offset, u8 data);
|
|
u8 c080_r(offs_t offset);
|
|
void c080_w(offs_t offset, u8 data);
|
|
u8 c100_r(offs_t offset);
|
|
void c100_w(offs_t offset, u8 data);
|
|
u8 c300_r(offs_t offset);
|
|
u8 c300_int_r(offs_t offset);
|
|
void c300_w(offs_t offset, u8 data);
|
|
u8 c400_r(offs_t offset);
|
|
void c400_w(offs_t offset, u8 data);
|
|
u8 c800_r(offs_t offset);
|
|
void c800_w(offs_t offset, u8 data);
|
|
u8 inh_r(offs_t offset);
|
|
void inh_w(offs_t offset, u8 data);
|
|
u8 lc_r(offs_t offset);
|
|
void lc_w(offs_t offset, u8 data);
|
|
u8 lc_aux_r(offs_t offset);
|
|
void lc_aux_w(offs_t offset, u8 data);
|
|
u8 lc_00_r(offs_t offset);
|
|
void lc_00_w(offs_t offset, u8 data);
|
|
u8 lc_01_r(offs_t offset);
|
|
void lc_01_w(offs_t offset, u8 data);
|
|
u8 bank0_c000_r(offs_t offset);
|
|
void bank0_c000_w(offs_t offset, u8 data);
|
|
u8 bank1_0000_r(offs_t offset);
|
|
void bank1_0000_sh_w(offs_t offset, u8 data);
|
|
u8 bank1_c000_r(offs_t offset);
|
|
void bank1_c000_w(offs_t offset, u8 data);
|
|
u8 floatingbank_r(offs_t offset);
|
|
u8 ghostram_r(offs_t offset);
|
|
void ghostram_w(offs_t offset, u8 data);
|
|
void a2bus_irq_w(int state);
|
|
void a2bus_nmi_w(int state);
|
|
void a2bus_inh_w(int state);
|
|
void doc_irq_w(int state);
|
|
void scc_irq_w(int state);
|
|
u8 doc_adc_read();
|
|
u8 apple2gs_read_vector(offs_t offset);
|
|
|
|
u8 keyglu_mcu_read(u8 offset);
|
|
void keyglu_mcu_write(u8 offset, u8 data);
|
|
u8 keyglu_816_read(u8 offset);
|
|
void keyglu_816_write(u8 offset, u8 data);
|
|
|
|
u8 m_adb_p2_last, m_adb_p3_last;
|
|
int m_adb_reset_freeze = 0;
|
|
void keyglu_regen_irqs();
|
|
|
|
u8 adbmicro_p0_in();
|
|
u8 adbmicro_p1_in();
|
|
u8 adbmicro_p2_in();
|
|
u8 adbmicro_p3_in();
|
|
void adbmicro_p0_out(u8 data);
|
|
void adbmicro_p1_out(u8 data);
|
|
void adbmicro_p2_out(u8 data);
|
|
void adbmicro_p3_out(u8 data);
|
|
void set_adb_line(int linestate);
|
|
|
|
offs_t dasm_trampoline(std::ostream &stream, offs_t pc, const util::disasm_interface::data_buffer &opcodes, const util::disasm_interface::data_buffer ¶ms);
|
|
void wdm_trampoline(offs_t offset, u8 data) { }; //m_a2host->wdm_w(space, offset, data); }
|
|
|
|
bool m_is_rom3 = false;
|
|
int m_speaker_state = 0;
|
|
|
|
double m_joystick_x1_time = 0, m_joystick_y1_time = 0, m_joystick_x2_time = 0, m_joystick_y2_time = 0;
|
|
|
|
int m_inh_slot = 0, m_cnxx_slot = 0;
|
|
int m_motoroff_time = 0;
|
|
|
|
bool m_romswitch = false;
|
|
|
|
bool m_an0 = false, m_an1 = false, m_an2 = false, m_an3 = false;
|
|
|
|
bool m_vbl = false;
|
|
|
|
int m_irqmask = 0;
|
|
|
|
bool m_intcxrom = false;
|
|
bool m_slotc3rom = false;
|
|
bool m_altzp = false;
|
|
bool m_ramrd = false, m_ramwrt = false;
|
|
bool m_lcram = false, m_lcram2 = false, m_lcprewrite = false, m_lcwriteenable = false;
|
|
bool m_rombank = false;
|
|
|
|
u8 m_shadow = 0, m_speed = 0;
|
|
u8 m_motors_active = 0, m_slotromsel = 0, m_intflag = 0, m_vgcint = 0, m_inten = 0;
|
|
|
|
bool m_last_speed = false;
|
|
|
|
// Sound GLU variables
|
|
u8 m_sndglu_ctrl = 0;
|
|
u16 m_sndglu_addr = 0;
|
|
int m_sndglu_dummy_read = 0;
|
|
|
|
// Key GLU variables
|
|
u8 m_glu_regs[12]{}, m_glu_bus = 0;
|
|
bool m_glu_mcu_read_kgs = false, m_glu_816_read_dstat = false, m_glu_mouse_read_stat = false;
|
|
int m_glu_kbd_y = 0;
|
|
|
|
u8 *m_ram_ptr = nullptr;
|
|
int m_ram_size = 0, m_motherboard_ram = 0, m_ghost_mask = 0;
|
|
u8 m_megaii_ram[0x20000]{}; // 128K of "slow RAM" at $E0/0000
|
|
|
|
int m_inh_bank = 0;
|
|
|
|
bool m_slot_irq = false;
|
|
|
|
double m_x_calibration = 0, m_y_calibration = 0;
|
|
|
|
device_a2bus_card_interface *m_slotdevice[8]{};
|
|
|
|
u32 m_slow_counter = 0;
|
|
|
|
// clock/BRAM
|
|
u8 m_clkdata = 0, m_clock_control = 0;
|
|
void rtc_vgc(int cko);
|
|
|
|
void lcrom_update();
|
|
void do_io(int offset);
|
|
u8 read_floatingbus();
|
|
void update_slotrom_banks();
|
|
void lc_update(int offset, bool writing);
|
|
u8 read_slot_rom(int slotbias, int offset);
|
|
void write_slot_rom(int slotbias, int offset, u8 data);
|
|
u8 read_int_rom(int slotbias, int offset);
|
|
void auxbank_update();
|
|
void raise_irq(int irq);
|
|
void lower_irq(int irq);
|
|
void update_speed();
|
|
int get_vpos();
|
|
void process_clock();
|
|
void clear_vgcint(u8 data);
|
|
|
|
// ZipGS stuff
|
|
bool m_accel_unlocked = false;
|
|
bool m_accel_fast = false;
|
|
bool m_accel_present = false;
|
|
bool m_accel_temp_slowdown = false;
|
|
int m_accel_stage = 0;
|
|
u32 m_accel_speed = 0;
|
|
u8 m_accel_slotspk = 0, m_accel_gsxsettings = 0, m_accel_percent = 0;
|
|
|
|
void accel_full_speed()
|
|
{
|
|
bool isfast = false;
|
|
|
|
if (m_speed & SPEED_HIGH)
|
|
{
|
|
isfast = true;
|
|
}
|
|
|
|
if ((m_motors_active & (m_speed & 0x0f)) != 0)
|
|
{
|
|
isfast = false;
|
|
}
|
|
|
|
if (isfast)
|
|
{
|
|
m_maincpu->set_unscaled_clock(m_accel_speed);
|
|
}
|
|
else
|
|
{
|
|
m_maincpu->set_unscaled_clock(A2GS_1M, true); // re-align with PH0
|
|
}
|
|
}
|
|
|
|
void accel_normal_speed()
|
|
{
|
|
bool isfast = false;
|
|
|
|
if (m_speed & SPEED_HIGH)
|
|
{
|
|
isfast = true;
|
|
}
|
|
|
|
if ((m_motors_active & (m_speed & 0x0f)) != 0)
|
|
{
|
|
isfast = false;
|
|
}
|
|
|
|
if (isfast)
|
|
{
|
|
m_maincpu->set_unscaled_clock(A2GS_2_8M);
|
|
}
|
|
else
|
|
{
|
|
m_maincpu->set_unscaled_clock(A2GS_1M, true); // re-align with PH0
|
|
}
|
|
}
|
|
|
|
void accel_slot(int slot);
|
|
};
|
|
|
|
// FF6ACF is speed test routine in ROM 3
|
|
|
|
// slow_cycle() - take a 1 MHz cycle. Theory: a 2.8 MHz cycle is 14M / 5.
|
|
// 1 MHz is 14M / 14. 14/5 = 2.8 * 65536 (16.16 fixed point) = 0x2cccd.
|
|
#define slow_cycle() \
|
|
{ \
|
|
if (m_last_speed && !machine().side_effects_disabled()) \
|
|
{\
|
|
m_slow_counter += 0x0002cccd; \
|
|
int cycles = (m_slow_counter >> 16) & 0xffff; \
|
|
m_slow_counter &= 0xffff; \
|
|
m_maincpu->adjust_icount(-cycles); \
|
|
} \
|
|
}
|
|
|
|
|
|
offs_t apple2gs_state::dasm_trampoline(std::ostream &stream, offs_t pc, const util::disasm_interface::data_buffer &opcodes, const util::disasm_interface::data_buffer ¶ms)
|
|
{
|
|
return m_a2common->dasm_override_GS(stream, pc, opcodes, params);
|
|
}
|
|
|
|
void apple2gs_state::a2bus_irq_w(int state)
|
|
{
|
|
if (state == ASSERT_LINE)
|
|
{
|
|
raise_irq(IRQS_SLOT);
|
|
m_slot_irq = true;
|
|
}
|
|
else
|
|
{
|
|
lower_irq(IRQS_SLOT);
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::a2bus_nmi_w(int state)
|
|
{
|
|
m_maincpu->set_input_line(INPUT_LINE_NMI, state);
|
|
}
|
|
|
|
// TODO: this assumes /INH only on ROM, needs expansion to support e.g. phantom-slotting cards and etc.
|
|
void apple2gs_state::a2bus_inh_w(int state)
|
|
{
|
|
if (state == ASSERT_LINE)
|
|
{
|
|
// assume no cards are pulling /INH
|
|
m_inh_slot = -1;
|
|
|
|
// scan the slots to figure out which card(s) are INHibiting stuff
|
|
for (int i = 0; i <= 7; i++)
|
|
{
|
|
if (m_slotdevice[i])
|
|
{
|
|
// this driver only can inhibit from 0xd000-0xffff
|
|
if ((m_slotdevice[i]->inh_start() == 0xd000) &&
|
|
(m_slotdevice[i]->inh_end() == 0xffff))
|
|
{
|
|
if ((m_slotdevice[i]->inh_type() & INH_READ) == INH_READ)
|
|
{
|
|
if (m_inh_bank != 1)
|
|
{
|
|
m_upperbank.select(1);
|
|
m_upperaux.select(1);
|
|
m_upper00.select(1);
|
|
m_upper01.select(1);
|
|
m_inh_bank = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_inh_bank != 0)
|
|
{
|
|
m_upperbank.select(0);
|
|
m_upperaux.select(0);
|
|
m_upper00.select(0);
|
|
m_upper01.select(0);
|
|
m_inh_bank = 0;
|
|
}
|
|
}
|
|
|
|
m_inh_slot = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if no slots are inhibiting, make sure ROM is fully switched in
|
|
if ((m_inh_slot == -1) && (m_inh_bank != 0))
|
|
{
|
|
m_upperbank.select(0);
|
|
m_upperaux.select(0);
|
|
m_upper00.select(0);
|
|
m_upper01.select(0);
|
|
m_inh_bank = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// FPI/CYA chip is connected to the VPB output of the 65816.
|
|
// this facilitates the documented behavior from the Firmware Reference.
|
|
u8 apple2gs_state::apple2gs_read_vector(offs_t offset)
|
|
{
|
|
// when IOLC shadowing is enabled, vector fetches always go to ROM,
|
|
// regardless of the language card config.
|
|
if (!(m_shadow & SHAD_IOLC))
|
|
{
|
|
if (m_inh_slot != -1 && (m_slotdevice[m_inh_slot]->inh_type() & INH_READ) == INH_READ)
|
|
return m_slotdevice[m_inh_slot]->read_inh_rom(offset | 0xFFE0);
|
|
else
|
|
return m_maincpu->space(AS_PROGRAM).read_byte(offset | 0xFFFFE0);
|
|
}
|
|
else // else vector fetches from bank 0 RAM
|
|
{
|
|
return m_maincpu->space(AS_PROGRAM).read_byte((offset & 0xffff) | 0xFFE0);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
START/RESET
|
|
***************************************************************************/
|
|
|
|
void apple2gs_state::machine_start()
|
|
{
|
|
m_ram_ptr = m_ram->pointer();
|
|
m_ram_size = m_ram->size();
|
|
m_speaker_state = 0;
|
|
m_speaker->level_w(m_speaker_state);
|
|
m_upperbank.select(0);
|
|
m_upperaux.select(0);
|
|
m_upper00.select(0);
|
|
m_upper01.select(0);
|
|
m_lcbank.select(0);
|
|
m_lcaux.select(0);
|
|
m_lc00.select(0);
|
|
m_lc01.select(0);
|
|
m_b0_0000bank.select(0);
|
|
m_e0_0000bank.select(0);
|
|
m_b0_0200bank.select(0);
|
|
m_e0_0200bank.select(0);
|
|
m_b0_0400bank.select(0);
|
|
m_e0_0400bank.select(0);
|
|
m_b0_0800bank.select(0);
|
|
m_e0_0800bank.select(0);
|
|
m_b0_2000bank.select(0);
|
|
m_e0_2000bank.select(0);
|
|
m_b0_4000bank.select(0);
|
|
m_e0_4000bank.select(0);
|
|
m_inh_bank = 0;
|
|
std::fill(std::begin(m_megaii_ram), std::end(m_megaii_ram), 0);
|
|
|
|
std::fill(std::begin(m_glu_regs), std::end(m_glu_regs), 0);
|
|
|
|
// setup speaker toggle volumes. this should be done mathematically probably,
|
|
// but these ad-hoc values aren't too bad.
|
|
#define LVL(x) (double(x) / 32768.0)
|
|
static const double lvlTable[16] =
|
|
{
|
|
LVL(0x0000), LVL(0x03ff), LVL(0x04ff), LVL(0x05ff), LVL(0x06ff), LVL(0x07ff), LVL(0x08ff), LVL(0x09ff),
|
|
LVL(0x0aff), LVL(0x0bff), LVL(0x0cff), LVL(0x0fff), LVL(0x1fff), LVL(0x3fff), LVL(0x5fff), LVL(0x7fff)
|
|
};
|
|
m_speaker->set_levels(16, lvlTable);
|
|
|
|
// precalculate joystick time constants
|
|
m_x_calibration = attotime::from_nsec(10800).as_double();
|
|
m_y_calibration = attotime::from_nsec(10800).as_double();
|
|
|
|
// cache slot devices
|
|
for (int i = 0; i <= 7; i++)
|
|
{
|
|
m_slotdevice[i] = m_a2bus->get_a2bus_card(i);
|
|
}
|
|
|
|
// setup video pointers
|
|
m_video->set_ram_pointers(m_megaii_ram, &m_megaii_ram[0x10000]);
|
|
m_video->set_char_pointer(memregion("gfx1")->base(), memregion("gfx1")->bytes());
|
|
m_video->setup_GS_graphics();
|
|
|
|
m_video->set_GS_textcol(0xf2);
|
|
|
|
// Mega II events occur near the rightmost edge of active video
|
|
m_scantimer->adjust(m_screen->time_until_pos(0, HPOS_VBL));
|
|
// VGC IRQs occur slightly later during HBL
|
|
m_vgctimer->adjust(m_screen->time_until_pos(0, HPOS_VGC));
|
|
|
|
m_inh_slot = -1;
|
|
m_cnxx_slot = CNXX_UNCLAIMED;
|
|
|
|
// install ROM
|
|
address_space &space = m_maincpu->space(AS_PROGRAM);
|
|
if (m_is_rom3)
|
|
space.install_rom(0xfc0000, 0xffffff, m_rom);
|
|
|
|
// adjust RAM size
|
|
if (!m_is_rom3 && m_ram_size <= 1280 * 1024)
|
|
{
|
|
m_ram_size -= 0x020000; // subtract 128k so requested RAM size matches exactly
|
|
}
|
|
// otherwise, RAM sizes for both classes of machine no longer include the Mega II RAM
|
|
|
|
// install "fast" RAM beyond banks 0, 1
|
|
m_motherboard_ram = m_is_rom3 ? 0x100000 : 0x020000;
|
|
if (m_ram_size > 0x020000)
|
|
{
|
|
space.install_ram(0x020000, m_ram_size - 1, m_ram_ptr + 0x020000);
|
|
|
|
if (m_ram_size > m_motherboard_ram)
|
|
{
|
|
// unmap empty RAM banks in case of non-power-of-two expansion
|
|
if (m_is_rom3 && m_ram_size < 0x800000)
|
|
space.nop_read(m_ram_size, 0x7fffff);
|
|
|
|
// expansion RAM ghosts power-of-two banks up through 7f
|
|
m_ghost_mask = (1 << (32 - count_leading_zeros_32(m_ram_size - m_motherboard_ram - 1))) - 1;
|
|
const int ghost_start = m_motherboard_ram + m_ghost_mask + 1;
|
|
if (ghost_start < 0x800000)
|
|
space.install_readwrite_handler(ghost_start, 0x7fffff,
|
|
read8sm_delegate(*this, FUNC(apple2gs_state::ghostram_r)),
|
|
write8sm_delegate(*this, FUNC(apple2gs_state::ghostram_w)));
|
|
|
|
// unmap empty ROM banks
|
|
if (m_is_rom3) // ROM1 reads floating bus
|
|
space.nop_read(0xf00000, 0xfbffff);
|
|
}
|
|
}
|
|
|
|
// setup save states
|
|
save_item(NAME(m_speaker_state));
|
|
save_item(NAME(m_joystick_x1_time));
|
|
save_item(NAME(m_joystick_y1_time));
|
|
save_item(NAME(m_joystick_x2_time));
|
|
save_item(NAME(m_joystick_y2_time));
|
|
save_item(NAME(m_inh_slot));
|
|
save_item(NAME(m_inh_bank));
|
|
save_item(NAME(m_cnxx_slot));
|
|
save_item(NAME(m_romswitch));
|
|
save_item(NAME(m_an0));
|
|
save_item(NAME(m_an1));
|
|
save_item(NAME(m_an2));
|
|
save_item(NAME(m_an3));
|
|
save_item(NAME(m_intcxrom));
|
|
save_item(NAME(m_rombank));
|
|
save_item(NAME(m_slotc3rom));
|
|
save_item(NAME(m_altzp));
|
|
save_item(NAME(m_ramrd));
|
|
save_item(NAME(m_ramwrt));
|
|
save_item(NAME(m_vbl));
|
|
save_item(NAME(m_irqmask));
|
|
save_item(NAME(m_lcram));
|
|
save_item(NAME(m_lcram2));
|
|
save_item(NAME(m_lcprewrite));
|
|
save_item(NAME(m_lcwriteenable));
|
|
save_item(NAME(m_shadow));
|
|
save_item(NAME(m_speed));
|
|
save_item(NAME(m_clock_control));
|
|
save_item(NAME(m_clkdata));
|
|
save_item(NAME(m_motors_active));
|
|
save_item(NAME(m_slotromsel));
|
|
save_item(NAME(m_diskreg));
|
|
save_item(NAME(m_sndglu_ctrl));
|
|
save_item(NAME(m_sndglu_addr));
|
|
save_item(NAME(m_sndglu_dummy_read));
|
|
save_item(NAME(m_last_speed));
|
|
save_item(NAME(m_glu_regs));
|
|
save_item(NAME(m_glu_bus));
|
|
save_item(NAME(m_glu_mcu_read_kgs));
|
|
save_item(NAME(m_glu_816_read_dstat));
|
|
save_item(NAME(m_glu_mouse_read_stat));
|
|
save_item(NAME(m_glu_kbd_y));
|
|
save_item(NAME(m_intflag));
|
|
save_item(NAME(m_vgcint));
|
|
save_item(NAME(m_inten));
|
|
save_item(NAME(m_slot_irq));
|
|
save_item(NAME(m_slow_counter));
|
|
save_item(NAME(m_megaii_ram));
|
|
save_item(m_clkdata, "CLKDATA");
|
|
save_item(m_clock_control, "CLKCTRL");
|
|
save_item(NAME(m_adb_p2_last));
|
|
save_item(NAME(m_adb_p3_last));
|
|
save_item(NAME(m_adb_reset_freeze));
|
|
save_item(NAME(m_accel_unlocked));
|
|
save_item(NAME(m_accel_stage));
|
|
save_item(NAME(m_accel_fast));
|
|
save_item(NAME(m_accel_present));
|
|
save_item(NAME(m_accel_slotspk));
|
|
save_item(NAME(m_accel_gsxsettings));
|
|
save_item(NAME(m_accel_percent));
|
|
save_item(NAME(m_accel_temp_slowdown));
|
|
save_item(NAME(m_accel_speed));
|
|
save_item(NAME(m_motoroff_time));
|
|
}
|
|
|
|
void apple2gs_state::machine_reset()
|
|
{
|
|
m_adb_p2_last = m_adb_p3_last = 0;
|
|
m_adb_reset_freeze = 0;
|
|
m_romswitch = false;
|
|
m_video->scr_w(0);
|
|
m_video->set_GS_border(0x02);
|
|
m_video->set_GS_textcol(0xf2);
|
|
m_an0 = m_an1 = m_an2 = m_an3 = false;
|
|
m_gameio->an0_w(0);
|
|
m_gameio->an1_w(0);
|
|
m_gameio->an2_w(0);
|
|
m_gameio->an3_w(0);
|
|
m_vbl = false;
|
|
m_slotc3rom = false;
|
|
m_irqmask = 0;
|
|
m_intcxrom = false;
|
|
m_rombank = false;
|
|
m_video->a80store_w(false);
|
|
m_altzp = false;
|
|
m_ramrd = false;
|
|
m_ramwrt = false;
|
|
m_video->set_newvideo(0x01); // verified on ROM03 hardware
|
|
m_slot_irq = false;
|
|
m_clkdata = 0;
|
|
m_clock_control = 0;
|
|
|
|
m_shadow = 0x00;
|
|
m_speed = 0x80;
|
|
m_motors_active = 0;
|
|
m_diskreg = 0;
|
|
m_intflag = 0;
|
|
m_vgcint = 0;
|
|
m_inten = 0;
|
|
|
|
m_motoroff_time = 0;
|
|
|
|
m_slow_counter = 0;
|
|
|
|
// always assert full speed on reset
|
|
m_maincpu->set_unscaled_clock(A2GS_2_8M);
|
|
m_last_speed = true;
|
|
|
|
m_sndglu_ctrl = 0;
|
|
m_sndglu_addr = 0;
|
|
m_sndglu_dummy_read = 0;
|
|
|
|
m_maincpu_space = &m_maincpu->space(AS_PROGRAM);
|
|
|
|
m_b0_0000bank.select(0);
|
|
m_e0_0000bank.select(0);
|
|
m_b0_0200bank.select(0);
|
|
m_e0_0200bank.select(0);
|
|
m_b0_0400bank.select(0);
|
|
m_e0_0400bank.select(0);
|
|
m_b0_0800bank.select(0);
|
|
m_e0_0800bank.select(0);
|
|
m_b0_2000bank.select(0);
|
|
m_e0_2000bank.select(0);
|
|
m_b0_4000bank.select(0);
|
|
m_e0_4000bank.select(0);
|
|
m_bank0_atc.select(1);
|
|
m_bank1_atc.select(1);
|
|
|
|
// LC default state: read ROM, write enabled, Dxxx bank 2
|
|
m_lcram = false;
|
|
m_lcram2 = true;
|
|
m_lcprewrite = false;
|
|
m_lcwriteenable = true;
|
|
|
|
// sync up the banking with the variables.
|
|
// RESEARCH: how does RESET affect LC state and aux banking states?
|
|
auxbank_update();
|
|
update_slotrom_banks();
|
|
|
|
// Apple-specific initial state
|
|
m_scc->ctsa_w(0);
|
|
m_scc->dcda_w(0);
|
|
|
|
// with all the banking reset, now reset the CPU
|
|
m_maincpu->reset();
|
|
|
|
// Setup ZipGS
|
|
m_accel_unlocked = false;
|
|
m_accel_stage = 0;
|
|
m_accel_slotspk = 0x41; // speaker and slot 6 slow
|
|
m_accel_gsxsettings = 0x49; // paddle slow, CPS, GS
|
|
m_accel_percent = 0; // 100% speed
|
|
m_accel_present = false;
|
|
m_accel_temp_slowdown = false;
|
|
m_accel_fast = false;
|
|
|
|
// is Zip enabled?
|
|
if (m_sysconfig->read() & 0x01)
|
|
{
|
|
static const int speeds[4] = { 7000000, 8000000, 12000000, 16000000 };
|
|
m_accel_present = true;
|
|
int idxSpeed = (m_sysconfig->read() >> 1);
|
|
m_accel_speed = speeds[idxSpeed];
|
|
m_accel_fast = true;
|
|
accel_full_speed();
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::raise_irq(int irq)
|
|
{
|
|
if (!(m_irqmask & (1 << irq)))
|
|
{
|
|
m_irqmask |= (1 << irq);
|
|
|
|
if (!(m_intflag & INTFLAG_IRQASSERTED))
|
|
{
|
|
//printf("raise IRQ %d (mask %x)\n", irq, m_irqmask);
|
|
// TODO: Zip AppleTalk slowdown
|
|
|
|
m_intflag |= INTFLAG_IRQASSERTED;
|
|
m_maincpu->set_input_line(G65816_LINE_IRQ, ASSERT_LINE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void apple2gs_state::lower_irq(int irq)
|
|
{
|
|
if (m_irqmask & (1 << irq))
|
|
{
|
|
m_irqmask &= ~(1 << irq);
|
|
|
|
//printf("lower IRQ %d (mask %x)\n", irq, m_irqmask);
|
|
|
|
if (!m_irqmask)
|
|
{
|
|
m_intflag &= ~INTFLAG_IRQASSERTED;
|
|
m_maincpu->set_input_line(G65816_LINE_IRQ, CLEAR_LINE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::update_speed()
|
|
{
|
|
bool isfast = false;
|
|
|
|
if (m_speed & SPEED_HIGH)
|
|
{
|
|
isfast = true;
|
|
}
|
|
|
|
if ((m_motors_active & (m_speed & 0x0f)) != 0)
|
|
{
|
|
isfast = false;
|
|
}
|
|
|
|
// prevent unnecessary reschedules by only setting this if it changed
|
|
if (isfast != m_last_speed)
|
|
{
|
|
if ((m_accel_present) && (isfast))
|
|
{
|
|
accel_full_speed();
|
|
}
|
|
else
|
|
{
|
|
m_maincpu->set_unscaled_clock(isfast ? A2GS_2_8M : A2GS_1M, !isfast);
|
|
}
|
|
m_last_speed = isfast;
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::accel_slot(int slot)
|
|
{
|
|
if ((m_accel_present) && (m_accel_slotspk & (1 << slot)) && !machine().side_effects_disabled())
|
|
{
|
|
m_accel_temp_slowdown = true;
|
|
m_acceltimer->adjust(attotime::from_msec(52));
|
|
accel_normal_speed();
|
|
}
|
|
}
|
|
|
|
TIMER_DEVICE_CALLBACK_MEMBER(apple2gs_state::accel_timer)
|
|
{
|
|
if (m_accel_fast)
|
|
{
|
|
accel_full_speed();
|
|
}
|
|
m_accel_temp_slowdown = false;
|
|
m_acceltimer->adjust(attotime::never);
|
|
}
|
|
|
|
/***************************************************************************
|
|
VIDEO
|
|
***************************************************************************/
|
|
|
|
TIMER_DEVICE_CALLBACK_MEMBER(apple2gs_state::apple2_interrupt)
|
|
{
|
|
// timer fires near the end of active video; handle events for the next line
|
|
int scanline = param + 1;
|
|
|
|
if (scanline == BORDER_TOP)
|
|
{
|
|
m_vbl = false;
|
|
}
|
|
else if (scanline == (192+BORDER_TOP))
|
|
{
|
|
m_vbl = true;
|
|
|
|
// Mega II status flags are set even when the interrupt is disabled
|
|
m_intflag |= INTFLAG_VBL;
|
|
if (m_inten & 0x08)
|
|
{
|
|
raise_irq(IRQS_VBL);
|
|
}
|
|
|
|
m_adbmicro->set_input_line(m5074x_device::M5074X_INT1_LINE, ASSERT_LINE);
|
|
|
|
// 3.5 motor off timeout
|
|
if (m_motoroff_time > 0)
|
|
{
|
|
m_motoroff_time--;
|
|
if (m_motoroff_time == 0)
|
|
{
|
|
if (m_floppy[2]->get_device()) m_floppy[2]->get_device()->tfsel_w(0);
|
|
if (m_floppy[3]->get_device()) m_floppy[3]->get_device()->tfsel_w(0);
|
|
}
|
|
}
|
|
}
|
|
else if (scanline == (192+BORDER_TOP+1))
|
|
{
|
|
m_adbmicro->set_input_line(m5074x_device::M5074X_INT1_LINE, CLEAR_LINE);
|
|
}
|
|
else if (scanline == ((256+BORDER_TOP) % m_screen->height()))
|
|
{
|
|
// LANGSEL is latched when wrapping scanline 256
|
|
const int height = m_video->is_pal_video_mode() ? 312 : 262;
|
|
if (height != m_screen->height())
|
|
{
|
|
// toggle 50/60 Hz, both use 65 1M cycles per scanline
|
|
m_screen->configure(m_screen->width(), height, m_screen->visible_area(), HZ_TO_ATTOSECONDS(A2GS_1M.dvalue() / (65 * height)));
|
|
if (scanline >= height)
|
|
scanline -= height;
|
|
}
|
|
|
|
// "quarter" second IRQ occurs every 16 frames, ~3.75 Hz
|
|
if ((m_screen->frame_number() & 0xf) == 0)
|
|
{
|
|
m_intflag |= INTFLAG_QUARTER;
|
|
if (m_inten & 0x10)
|
|
{
|
|
raise_irq(IRQS_QTRSEC);
|
|
}
|
|
}
|
|
}
|
|
else if (scanline == m_screen->height())
|
|
scanline = 0;
|
|
|
|
m_scantimer->adjust(m_screen->time_until_pos(scanline, HPOS_VBL), scanline);
|
|
}
|
|
|
|
TIMER_DEVICE_CALLBACK_MEMBER(apple2gs_state::apple2_vgc)
|
|
{
|
|
// flush the previous scanline to ensure SCB or palette changes are visible
|
|
m_screen->update_now();
|
|
|
|
// timer fires during HBL past right border; handle events for the next line
|
|
int scanline = param + 1;
|
|
if (scanline >= m_screen->height())
|
|
scanline -= m_screen->height(); // catch 50Hz toggle
|
|
|
|
// scanline interrupts occur during HBL of each super hi-res line
|
|
if ((m_video->get_newvideo() & 0x80) && (scanline >= BORDER_TOP) && (scanline < (BORDER_TOP + 200)))
|
|
{
|
|
u8 scb;
|
|
const int shrline = scanline - BORDER_TOP;
|
|
|
|
if (shrline & 1)
|
|
{
|
|
scb = m_megaii_ram[0x19e80 + (shrline >> 1)];
|
|
}
|
|
else
|
|
{
|
|
scb = m_megaii_ram[0x15e80 + (shrline >> 1)];
|
|
}
|
|
|
|
// latch scb on this cycle for subsequent palette lookups
|
|
m_video->set_SHR_scb(shrline, scb);
|
|
|
|
if (scb & 0x40)
|
|
{
|
|
// VGC status flags are set even when the interrupt is disabled
|
|
m_vgcint |= VGCINT_SCANLINE;
|
|
|
|
// trigger the interrupt if enabled
|
|
if (m_vgcint & VGCINT_SCANLINEEN)
|
|
{
|
|
m_vgcint |= VGCINT_ANYVGCINT;
|
|
raise_irq(IRQS_SCAN);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_vgctimer->adjust(m_screen->time_until_pos(scanline, HPOS_VGC), scanline);
|
|
}
|
|
|
|
void apple2gs_state::rtc_vgc(int cko)
|
|
{
|
|
if (cko) // one second IRQ
|
|
{
|
|
m_vgcint |= VGCINT_SECOND;
|
|
if (m_vgcint & VGCINT_SECONDENABLE)
|
|
{
|
|
m_vgcint |= VGCINT_ANYVGCINT;
|
|
raise_irq(IRQS_SECOND);
|
|
}
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::palette_init(palette_device &palette)
|
|
{
|
|
static const unsigned char apple2gs_palette[] =
|
|
{
|
|
0x0, 0x0, 0x0, /* Black $0 $0000 */
|
|
0xd, 0x0, 0x3, /* Deep Red $1 $0D03 */
|
|
0x0, 0x0, 0x9, /* Dark Blue $2 $0009 */
|
|
0xd, 0x2, 0xd, /* Purple $3 $0D2D */
|
|
0x0, 0x7, 0x2, /* Dark Green $4 $0072 */
|
|
0x5, 0x5, 0x5, /* Dark Gray $5 $0555 */
|
|
0x2, 0x2, 0xf, /* Medium Blue $6 $022F */
|
|
0x6, 0xa, 0xf, /* Light Blue $7 $06AF */
|
|
0x8, 0x5, 0x0, /* Brown $8 $0850 */
|
|
0xf, 0x6, 0x0, /* Orange $9 $0F60 */
|
|
0xa, 0xa, 0xa, /* Light Gray $A $0AAA */
|
|
0xf, 0x9, 0x8, /* Pink $B $0F98 */
|
|
0x1, 0xd, 0x0, /* Light Green $C $01D0 */
|
|
0xf, 0xf, 0x0, /* Yellow $D $0FF0 */
|
|
0x4, 0xf, 0x9, /* Aquamarine $E $04F9 */
|
|
0xf, 0xf, 0xf /* White $F $0FFF */
|
|
};
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
palette.set_pen_color(i,
|
|
apple2gs_palette[(3*i)]*17,
|
|
apple2gs_palette[(3*i)+1]*17,
|
|
apple2gs_palette[(3*i)+2]*17);
|
|
|
|
m_video->set_GS_border_color(i, rgb_t(apple2gs_palette[(3*i)]*17, apple2gs_palette[(3*i)+1]*17, apple2gs_palette[(3*i)+2]*17));
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
I/O
|
|
***************************************************************************/
|
|
void apple2gs_state::auxbank_update()
|
|
{
|
|
int ramwr = (m_ramrd ? 1 : 0) | (m_ramwrt ? 2 : 0);
|
|
|
|
m_b0_0000bank.select(m_altzp ? 1 : 0);
|
|
m_e0_0000bank.select(m_altzp ? 1 : 0);
|
|
m_b0_0200bank.select(ramwr);
|
|
m_e0_0200bank.select(ramwr);
|
|
|
|
if (m_video->get_80store())
|
|
{
|
|
if (m_video->get_page2())
|
|
{
|
|
m_b0_0400bank.select(3);
|
|
m_e0_0400bank.select(3);
|
|
}
|
|
else
|
|
{
|
|
m_b0_0400bank.select(0);
|
|
m_e0_0400bank.select(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_b0_0400bank.select(ramwr);
|
|
m_e0_0400bank.select(ramwr);
|
|
}
|
|
|
|
m_b0_0800bank.select(ramwr);
|
|
m_e0_0800bank.select(ramwr);
|
|
|
|
if ((m_video->get_80store()) && (m_video->get_hires()))
|
|
{
|
|
if (m_video->get_page2())
|
|
{
|
|
m_b0_2000bank.select(3);
|
|
m_e0_2000bank.select(3);
|
|
}
|
|
else
|
|
{
|
|
m_b0_2000bank.select(0);
|
|
m_e0_2000bank.select(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_b0_2000bank.select(ramwr);
|
|
m_e0_2000bank.select(ramwr);
|
|
}
|
|
|
|
m_b0_4000bank.select(ramwr);
|
|
m_e0_4000bank.select(ramwr);
|
|
}
|
|
|
|
void apple2gs_state::update_slotrom_banks()
|
|
{
|
|
//printf("update_slotrom_banks: intcxrom %d cnxx_slot %d SLOT %02x\n", m_intcxrom, m_cnxx_slot, m_slotromsel);
|
|
|
|
// slot 3 ROM is controlled exclusively by SLOTC3ROM
|
|
if (!m_slotc3rom)
|
|
{
|
|
m_c300bank->set_bank(1);
|
|
}
|
|
else
|
|
{
|
|
m_c300bank->set_bank(0);
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::lc_update(int offset, bool writing)
|
|
{
|
|
bool old_lcram = m_lcram;
|
|
|
|
// any even access disables pre-write and writing
|
|
if ((offset & 1) == 0)
|
|
{
|
|
m_lcprewrite = false;
|
|
m_lcwriteenable = false;
|
|
}
|
|
|
|
// any write disables pre-write
|
|
// has no effect on write-enable if writing was enabled already
|
|
if (writing == true)
|
|
{
|
|
m_lcprewrite = false;
|
|
}
|
|
// first odd read enables pre-write, second one enables writing
|
|
else if ((offset & 1) == 1)
|
|
{
|
|
if (m_lcprewrite == false)
|
|
{
|
|
m_lcprewrite = true;
|
|
}
|
|
else
|
|
{
|
|
m_lcwriteenable = true;
|
|
}
|
|
}
|
|
|
|
switch (offset & 3)
|
|
{
|
|
case 0:
|
|
case 3:
|
|
{
|
|
m_lcram = true;
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
case 2:
|
|
{
|
|
m_lcram = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_lcram2 = false;
|
|
|
|
if (!(offset & 8))
|
|
{
|
|
m_lcram2 = true;
|
|
}
|
|
|
|
if (m_lcram != old_lcram)
|
|
{
|
|
lcrom_update();
|
|
}
|
|
|
|
#if 0
|
|
printf("LC: new state %c%c dxxx=%04x altzp=%d\n",
|
|
m_lcram ? 'R' : 'x',
|
|
m_lcwriteenable ? 'W' : 'x',
|
|
m_lcram2 ? 0x1000 : 0x0000,
|
|
m_altzp);
|
|
#endif
|
|
}
|
|
|
|
void apple2gs_state::lcrom_update()
|
|
{
|
|
if (m_lcram)
|
|
{
|
|
m_lcbank.select(1);
|
|
m_lcaux.select(1);
|
|
m_lc00.select(1 + (m_romswitch ? 2 : 0));
|
|
m_lc01.select(1);
|
|
}
|
|
else
|
|
{
|
|
m_lcbank.select(0);
|
|
m_lcaux.select(0);
|
|
m_lc00.select(0 + (m_romswitch ? 2 : 0));
|
|
m_lc01.select(0);
|
|
}
|
|
}
|
|
|
|
// most softswitches don't care about read vs write, so handle them here
|
|
void apple2gs_state::do_io(int offset)
|
|
{
|
|
if(machine().side_effects_disabled()) return;
|
|
|
|
switch (offset)
|
|
{
|
|
case 0x20:
|
|
break;
|
|
|
|
case 0x28: // ROMSWITCH - not used by the IIgs firmware or SSW, but does exist at least on ROM 0/1 (need to test on ROM 3 hw)
|
|
if (!m_is_rom3)
|
|
{
|
|
m_romswitch = !m_romswitch;
|
|
if (m_lcram)
|
|
{
|
|
m_lc00.select(1 + (m_romswitch ? 2 : 0));
|
|
}
|
|
else
|
|
{
|
|
m_lc00.select(0 + (m_romswitch ? 2 : 0));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x2a: // 16-bit access to NEWVIDEO
|
|
break;
|
|
|
|
case 0x30:
|
|
m_speaker_state ^= 1;
|
|
if (m_speaker_state)
|
|
{
|
|
m_speaker->level_w(m_sndglu_ctrl & 0xf);
|
|
}
|
|
else
|
|
{
|
|
m_speaker->level_w(0);
|
|
}
|
|
|
|
if ((m_accel_present) && (m_accel_slotspk & 1))
|
|
{
|
|
m_accel_temp_slowdown = true;
|
|
m_acceltimer->adjust(attotime::from_msec(5));
|
|
accel_normal_speed();
|
|
}
|
|
break;
|
|
|
|
case 0x37: // DMAREG, 16-bit access to CYAREG
|
|
break;
|
|
|
|
case 0x47: // CLRVBLINT
|
|
m_intflag &= ~(INTFLAG_VBL | INTFLAG_QUARTER);
|
|
lower_irq(IRQS_VBL);
|
|
lower_irq(IRQS_QTRSEC);
|
|
break;
|
|
|
|
case 0x50: // graphics mode
|
|
m_video->txt_w(0);
|
|
break;
|
|
|
|
case 0x51: // text mode
|
|
m_video->txt_w(1);
|
|
break;
|
|
|
|
case 0x52: // no mix
|
|
m_video->mix_w(0);
|
|
break;
|
|
|
|
case 0x53: // mixed mode
|
|
m_video->mix_w(1);
|
|
break;
|
|
|
|
case 0x54: // set page 1
|
|
m_video->scr_w(0);
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x55: // set page 2
|
|
m_video->scr_w(1);
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x56: // select lo-res
|
|
m_video->res_w(0);
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x57: // select hi-res
|
|
m_video->res_w(1);
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x58: // AN0 off
|
|
m_an0 = false;
|
|
m_gameio->an0_w(0);
|
|
break;
|
|
|
|
case 0x59: // AN0 on
|
|
m_an0 = true;
|
|
m_gameio->an0_w(1);
|
|
break;
|
|
|
|
case 0x5a: // AN1 off
|
|
m_an1 = false;
|
|
m_gameio->an1_w(0);
|
|
break;
|
|
|
|
case 0x5b: // AN1 on
|
|
m_an1 = true;
|
|
m_gameio->an1_w(1);
|
|
break;
|
|
|
|
case 0x5c: // AN2 off
|
|
m_an2 = false;
|
|
m_gameio->an2_w(0);
|
|
break;
|
|
|
|
case 0x5d: // AN2 on
|
|
m_an2 = true;
|
|
m_gameio->an2_w(1);
|
|
break;
|
|
|
|
case 0x5e: // AN3 off, DHIRESON
|
|
m_an3 = false;
|
|
m_gameio->an3_w(0);
|
|
m_video->an3_w(0);
|
|
break;
|
|
|
|
case 0x5f: // AN3 on, DHIRESOFF
|
|
m_an3 = true;
|
|
m_gameio->an3_w(1);
|
|
m_video->an3_w(1);
|
|
break;
|
|
|
|
case 0x69: // 16-bit access to STATEREG
|
|
break;
|
|
|
|
case 0x70: // PTRIG triggers paddles on read or write
|
|
// Zip paddle slowdown (does ZipGS also use the old Zip flag?)
|
|
if ((m_accel_present) && BIT(m_accel_gsxsettings, 6))
|
|
{
|
|
m_accel_temp_slowdown = true;
|
|
m_acceltimer->adjust(attotime::from_msec(5));
|
|
accel_normal_speed();
|
|
}
|
|
|
|
// 558 monostable one-shot timers; a running timer cannot be restarted
|
|
if (machine().time().as_double() >= m_joystick_x1_time)
|
|
{
|
|
m_joystick_x1_time = machine().time().as_double() + m_x_calibration * m_gameio->pdl0_r();
|
|
}
|
|
if (machine().time().as_double() >= m_joystick_y1_time)
|
|
{
|
|
m_joystick_y1_time = machine().time().as_double() + m_y_calibration * m_gameio->pdl1_r();
|
|
}
|
|
if (machine().time().as_double() >= m_joystick_x2_time)
|
|
{
|
|
m_joystick_x2_time = machine().time().as_double() + m_x_calibration * m_gameio->pdl2_r();
|
|
}
|
|
if (machine().time().as_double() >= m_joystick_y2_time)
|
|
{
|
|
m_joystick_y2_time = machine().time().as_double() + m_y_calibration * m_gameio->pdl3_r();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
logerror("do_io: unknown switch $C0%02X\n", offset);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// return the correct vertical counter per IIgs Tech Note #39
|
|
int apple2gs_state::get_vpos()
|
|
{
|
|
int vpos = m_screen->vpos();
|
|
vpos += (m_screen->hpos() >= (BORDER_LEFT + (40 - ALIGN_CNT) * 16)); // adjust for set_raw
|
|
|
|
if (vpos < BORDER_TOP)
|
|
vpos += m_screen->height(); // remap top border to bottom of VBL
|
|
vpos += 256 - BORDER_TOP;
|
|
if (vpos > 511)
|
|
vpos -= m_screen->height(); // wrap scanline 256 to 250 (60 Hz) or 200 (50 Hz)
|
|
|
|
return vpos;
|
|
}
|
|
|
|
void apple2gs_state::process_clock()
|
|
{
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
m_rtc->clk_w(ASSERT_LINE);
|
|
if (!BIT(m_clock_control, 6))
|
|
{
|
|
m_rtc->data_w(BIT(m_clkdata, 7-i));
|
|
m_rtc->clk_w(CLEAR_LINE);
|
|
}
|
|
else
|
|
{
|
|
m_rtc->clk_w(CLEAR_LINE);
|
|
m_clkdata <<= 1;
|
|
m_clkdata |= m_rtc->data_r() & 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::clear_vgcint(u8 data)
|
|
{
|
|
if (!(data & VGCINT_SECOND))
|
|
{
|
|
m_vgcint &= ~VGCINT_SECOND;
|
|
lower_irq(IRQS_SECOND);
|
|
}
|
|
if (!(data & VGCINT_SCANLINE))
|
|
{
|
|
m_vgcint &= ~VGCINT_SCANLINE;
|
|
lower_irq(IRQS_SCAN);
|
|
}
|
|
if (!(m_vgcint & (VGCINT_SECOND | VGCINT_SCANLINE)))
|
|
{
|
|
m_vgcint &= ~VGCINT_ANYVGCINT;
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::c000_r(offs_t offset)
|
|
{
|
|
u8 ret;
|
|
|
|
if (offset < 0x71)
|
|
{
|
|
switch (offset)
|
|
{
|
|
// C07x ROM and FPI registers are fast
|
|
case 0x2d: case 0x35: case 0x36: case 0x37: case 0x68:
|
|
break;
|
|
default:
|
|
slow_cycle();
|
|
}
|
|
}
|
|
|
|
if (!machine().side_effects_disabled())
|
|
{
|
|
switch (offset)
|
|
{
|
|
case 0x38: // SCCBREG
|
|
return m_scc->cb_r(0);
|
|
|
|
case 0x39: // SCCAREG
|
|
return m_scc->ca_r(0);
|
|
|
|
case 0x3a: // SCCBDATA
|
|
return m_scc->db_r(0);
|
|
|
|
case 0x3b: // SCCADATA
|
|
return m_scc->da_r(0);
|
|
}
|
|
}
|
|
|
|
const u8 uFloatingBus = read_floatingbus(); // video side-effects latch after reading
|
|
const u8 uFloatingBus7 = uFloatingBus & 0x7f;
|
|
const u8 uKeyboard = keyglu_816_read(GLU_C000);
|
|
|
|
switch (offset)
|
|
{
|
|
// keyboard latch
|
|
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06:
|
|
case 0x07: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d:
|
|
case 0x0e: case 0x0f:
|
|
return uKeyboard;
|
|
|
|
case 0x10: // read any key down, reset keyboard strobe
|
|
if (!machine().side_effects_disabled())
|
|
keyglu_816_write(GLU_C010, 0);
|
|
return keyglu_816_read(GLU_C010) | (uKeyboard & 0x7f);
|
|
|
|
case 0x11: // read LCRAM2 (LC Dxxx bank)
|
|
return m_lcram2 ? 0x80 : 0x00;
|
|
|
|
case 0x12: // read LCRAM (is LC readable?)
|
|
return m_lcram ? 0x80 : 0x00;
|
|
|
|
case 0x13: // read RAMRD
|
|
return m_ramrd ? 0x80 : 0x00;
|
|
|
|
case 0x14: // read RAMWRT
|
|
return m_ramwrt ? 0x80 : 0x00;
|
|
|
|
case 0x15: // read INTCXROM
|
|
return m_intcxrom ? 0x80 : 0x00;
|
|
|
|
case 0x16: // read ALTZP
|
|
return m_altzp ? 0x80 : 0x00;
|
|
|
|
case 0x17: // read SLOTC3ROM
|
|
return m_slotc3rom ? 0x80 : 0x00;
|
|
|
|
case 0x18: // read 80STORE
|
|
return m_video->get_80store() ? 0x80 : 0x00;
|
|
|
|
case 0x19: // read VBL (not VBLBAR, see Apple IIGS Technical Note #40)
|
|
return m_vbl ? 0x80 : 0x00;
|
|
|
|
case 0x1a: // read TEXT
|
|
return m_video->get_graphics() ? 0x00 : 0x80;
|
|
|
|
case 0x1b: // read MIXED
|
|
return m_video->get_mix() ? 0x80 : 0x00;
|
|
|
|
case 0x1c: // read PAGE2
|
|
return m_video->get_page2() ? 0x80 : 0x00;
|
|
|
|
case 0x1d: // read HIRES
|
|
return m_video->get_hires() ? 0x80 : 0x00;
|
|
|
|
case 0x1e: // read ALTCHARSET
|
|
return m_video->get_altcharset() ? 0x80 : 0x00;
|
|
|
|
case 0x1f: // read 80COL
|
|
return m_video->get_80col() ? 0x80 : 0x00;
|
|
|
|
case 0x22: // TEXTCOL
|
|
return m_video->get_GS_textcol();
|
|
|
|
case 0x23: // VGCINT
|
|
return m_vgcint;
|
|
|
|
case 0x24: // MOUSEDATA */
|
|
return keyglu_816_read(GLU_MOUSEX);
|
|
|
|
case 0x25: // KEYMODREG
|
|
return keyglu_816_read(GLU_KEYMOD);
|
|
|
|
case 0x26: // DATAREG
|
|
return keyglu_816_read(GLU_DATA);
|
|
|
|
case 0x27: // KMSTATUS
|
|
return keyglu_816_read(GLU_SYSSTAT);
|
|
|
|
case 0x29: // NEWVIDEO
|
|
return m_video->get_newvideo();
|
|
|
|
case 0x2b: // LANGSEL
|
|
return m_video->get_GS_langsel();
|
|
|
|
case 0x2d: // SLOTROMSEL
|
|
return m_slotromsel;
|
|
|
|
case 0x2e: // VERTCNT
|
|
// reading VERTCNT clears SCB status
|
|
if (!machine().side_effects_disabled())
|
|
clear_vgcint(~VGCINT_SCANLINE);
|
|
|
|
return get_vpos() >> 1;
|
|
|
|
case 0x2f: // HORIZCNT
|
|
// reading HORIZCNT clears SCB status
|
|
if (!machine().side_effects_disabled())
|
|
clear_vgcint(~VGCINT_SCANLINE);
|
|
|
|
ret = (m_screen->hpos() - BORDER_LEFT) / 16 + (25 + ALIGN_CNT); // adjust for set_raw
|
|
if (ret >= 65)
|
|
ret -= 65;
|
|
if (ret > 0)
|
|
{
|
|
ret += 0x3f; // HBL [0, 0x40...57] active [0x58...7f]
|
|
}
|
|
|
|
if (get_vpos() & 1)
|
|
{
|
|
ret |= 0x80;
|
|
}
|
|
return ret;
|
|
|
|
case 0x31: // DISKREG
|
|
return m_diskreg;
|
|
|
|
case 0x32: // VGCINTCLEAR
|
|
return uFloatingBus;
|
|
|
|
case 0x33: // CLOCKDATA
|
|
return m_clkdata;
|
|
|
|
case 0x34: // BORDERCOL
|
|
return (m_clock_control & 0xf0) | (m_video->get_GS_border() & 0xf);
|
|
|
|
case 0x35: // SHADOW
|
|
return m_shadow;
|
|
|
|
case 0x36: // SPEED/CYAREG
|
|
return m_speed;
|
|
|
|
case 0x3c: // SOUNDCTL
|
|
return m_sndglu_ctrl;
|
|
|
|
case 0x3d: // SOUNDDATA
|
|
ret = m_sndglu_dummy_read;
|
|
if (!machine().side_effects_disabled())
|
|
{
|
|
if (m_sndglu_ctrl & 0x40) // docram access
|
|
{
|
|
m_sndglu_dummy_read = m_docram[m_sndglu_addr];
|
|
}
|
|
else
|
|
{
|
|
m_sndglu_dummy_read = m_doc->read(m_sndglu_addr);
|
|
}
|
|
|
|
if (m_sndglu_ctrl & 0x20) // auto-increment
|
|
{
|
|
m_sndglu_addr++;
|
|
}
|
|
}
|
|
return ret;
|
|
|
|
case 0x3e: // SOUNDADRL
|
|
return m_sndglu_addr & 0xff;
|
|
|
|
case 0x3f: // SOUNDADRH
|
|
return (m_sndglu_addr >> 8) & 0xff;
|
|
|
|
case 0x41: // INTEN
|
|
return m_inten;
|
|
|
|
case 0x44: // MMDELTAX
|
|
case 0x45: // MMDELTAY
|
|
return 0; // read by AppleTalk to detect SCC activity
|
|
|
|
case 0x46: // INTFLAG
|
|
return (m_an3 ? INTFLAG_AN3 : 0x00) | m_intflag;
|
|
|
|
case 0x60: // button 3 on IIgs, inverted
|
|
return (m_gameio->sw3_r() ? 0 : 0x80) | uFloatingBus7;
|
|
|
|
case 0x61: // button 0 or Open Apple
|
|
// HACK/TODO: the 65816 loses a race to the microcontroller on reset
|
|
if (m_adb_reset_freeze > 0 && !machine().side_effects_disabled())
|
|
m_adb_reset_freeze--;
|
|
return ((m_gameio->sw0_r() || (m_adb_p3_last & 0x20)) ? 0x80 : 0) | uFloatingBus7;
|
|
|
|
case 0x62: // button 1 or Option
|
|
return ((m_gameio->sw1_r() || (m_adb_p3_last & 0x10)) ? 0x80 : 0) | uFloatingBus7;
|
|
|
|
case 0x63: // button 2, inverted (no shift key mod)
|
|
return (m_gameio->sw2_r() ? 0 : 0x80) | uFloatingBus7;
|
|
|
|
case 0x64: // joy 1 X axis
|
|
if (!m_gameio->is_device_connected()) return 0x80 | uFloatingBus7;
|
|
return ((machine().time().as_double() < m_joystick_x1_time) ? 0x80 : 0) | uFloatingBus7;
|
|
|
|
case 0x65: // joy 1 Y axis
|
|
if (!m_gameio->is_device_connected()) return 0x80 | uFloatingBus7;
|
|
return ((machine().time().as_double() < m_joystick_y1_time) ? 0x80 : 0) | uFloatingBus7;
|
|
|
|
case 0x66: // joy 2 X axis
|
|
if (!m_gameio->is_device_connected()) return 0x80 | uFloatingBus7;
|
|
return ((machine().time().as_double() < m_joystick_x2_time) ? 0x80 : 0) | uFloatingBus7;
|
|
|
|
case 0x67: // joy 2 Y axis
|
|
if (!m_gameio->is_device_connected()) return 0x80 | uFloatingBus7;
|
|
return ((machine().time().as_double() < m_joystick_y2_time) ? 0x80 : 0) | uFloatingBus7;
|
|
|
|
case 0x68: // STATEREG, synthesizes all the IIe state regs
|
|
return (m_altzp ? 0x80 : 0x00) |
|
|
(m_video->get_page2() ? 0x40 : 0x00) |
|
|
(m_ramrd ? 0x20 : 0x00) |
|
|
(m_ramwrt ? 0x10 : 0x00) |
|
|
(m_lcram ? 0x00 : 0x08) |
|
|
(m_lcram2 ? 0x04 : 0x00) |
|
|
(m_rombank ? 0x02 : 0x00) |
|
|
(m_intcxrom ? 0x01 : 0x00);
|
|
|
|
// The ROM IRQ vectors point here (0x70 returns floating bus)
|
|
case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
|
|
case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
|
|
return m_rom[offset + 0x3c000];
|
|
|
|
default:
|
|
do_io(offset);
|
|
|
|
if (m_accel_unlocked)
|
|
{
|
|
if (offset == 0x59)
|
|
{
|
|
return m_accel_gsxsettings;
|
|
}
|
|
else if (offset == 0x5a)
|
|
{
|
|
return m_accel_percent | 0x0f;
|
|
}
|
|
else if (offset == 0x5b) // Zip status flags
|
|
{
|
|
// bits 0-1 are cache size: [8, 16, 32, 64]kB
|
|
const u8 b01 = 0x03;
|
|
// bit 3 is set if a temporary delay is active due to slot or softswitch access
|
|
const u8 b3 = m_accel_temp_slowdown ? 0x08 : 0x00;
|
|
// bit 4 is set if the Zip is disabled
|
|
const u8 b4 = m_accel_fast ? 0x00 : 0x10;
|
|
// bit 7 is a 1.0035 millisecond clock; the value changes every 0.50175 milliseconds
|
|
const int time = machine().time().as_ticks(1.0F / 0.00050175F);
|
|
const u8 b7 = (time & 1) ? 0x80 : 0x00;
|
|
return b7 | b4 | b3 | b01;
|
|
}
|
|
else if (offset == 0x5c)
|
|
{
|
|
return m_accel_slotspk;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return uFloatingBus;
|
|
}
|
|
|
|
void apple2gs_state::c000_w(offs_t offset, u8 data)
|
|
{
|
|
if(machine().side_effects_disabled()) return;
|
|
|
|
switch (offset)
|
|
{
|
|
// FPI registers are fast
|
|
case 0x35: case 0x36: case 0x37:
|
|
break;
|
|
default:
|
|
slow_cycle();
|
|
}
|
|
|
|
switch (offset)
|
|
{
|
|
case 0x00: // 80STOREOFF
|
|
m_video->a80store_w(false);
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x01: // 80STOREON
|
|
m_video->a80store_w(true);
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x02: // RAMRDOFF
|
|
m_ramrd = false;
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x03: // RAMRDON
|
|
m_ramrd = true;
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x04: // RAMWRTOFF
|
|
m_ramwrt = false;
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x05: // RAMWRTON
|
|
m_ramwrt = true;
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x06: // INTCXROMOFF
|
|
m_intcxrom = false;
|
|
update_slotrom_banks();
|
|
break;
|
|
|
|
case 0x07: // INTCXROMON
|
|
m_intcxrom = true;
|
|
update_slotrom_banks();
|
|
break;
|
|
|
|
case 0x08: // ALTZPOFF
|
|
m_altzp = false;
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x09: // ALTZPON
|
|
m_altzp = true;
|
|
auxbank_update();
|
|
break;
|
|
|
|
case 0x0a: // SETINTC3ROM
|
|
m_slotc3rom = false;
|
|
update_slotrom_banks();
|
|
break;
|
|
|
|
case 0x0b: // SETSLOTC3ROM
|
|
m_slotc3rom = true;
|
|
update_slotrom_banks();
|
|
break;
|
|
|
|
case 0x0c: // 80COLOFF
|
|
m_video->a80col_w(false);
|
|
break;
|
|
|
|
case 0x0d: // 80COLON
|
|
m_video->a80col_w(true);
|
|
break;
|
|
|
|
case 0x0e: // ALTCHARSETOFF
|
|
m_video->altcharset_w(false);
|
|
break;
|
|
|
|
case 0x0f: // ALTCHARSETON
|
|
m_video->altcharset_w(true);
|
|
break;
|
|
|
|
case 0x10: // clear keyboard latch
|
|
keyglu_816_write(GLU_C010, data);
|
|
break;
|
|
|
|
case 0x20:
|
|
break;
|
|
|
|
case 0x21: // MONOCHROME
|
|
m_video->set_GS_monochrome(data);
|
|
break;
|
|
|
|
case 0x22: // TEXTCOL
|
|
m_video->set_GS_textcol(data);
|
|
break;
|
|
|
|
case 0x23: // VGCINT
|
|
// clearing enable bits may clear VGCINT_ANYVGCINT
|
|
// but it does not clear VGCINT status bits or lower IRQs
|
|
if (!((m_vgcint & (VGCINT_SECOND | VGCINT_SCANLINE))
|
|
& (data & (VGCINT_SECONDENABLE | VGCINT_SCANLINEEN))))
|
|
{
|
|
m_vgcint &= ~(VGCINT_ANYVGCINT);
|
|
}
|
|
|
|
m_vgcint &= 0xf0;
|
|
m_vgcint |= (data & 0x0f);
|
|
//printf("%02x to VGCINT, now %02x\n", data, m_vgcint);
|
|
break;
|
|
|
|
case 0x26: // DATAREG
|
|
// allow ADBuC sync if the Zip is on
|
|
if (m_accel_present)
|
|
{
|
|
m_accel_temp_slowdown = true;
|
|
m_acceltimer->adjust(attotime::from_msec(30));
|
|
accel_normal_speed();
|
|
}
|
|
keyglu_816_write(GLU_COMMAND, data);
|
|
break;
|
|
|
|
case 0x27: // KMSTATUS
|
|
keyglu_816_write(GLU_SYSSTAT, data);
|
|
break;
|
|
|
|
case 0x29: // NEWVIDEO
|
|
m_video->set_newvideo(data);
|
|
break;
|
|
|
|
case 0x2b: // LANGSEL
|
|
m_video->set_GS_langsel(data);
|
|
break;
|
|
|
|
case 0x2d: // SLOTROMSEL
|
|
m_slotromsel = data;
|
|
break;
|
|
|
|
case 0x31: // DISKREG
|
|
if (!BIT(data, DISKREG_35SEL))
|
|
{
|
|
m_motoroff_time = 30;
|
|
}
|
|
|
|
if ((m_cur_floppy) && (BIT(data, DISKREG_35SEL)))
|
|
{
|
|
m_cur_floppy->ss_w(BIT(data, DISKREG_HDSEL));
|
|
}
|
|
m_diskreg = data;
|
|
break;
|
|
|
|
case 0x32: // VGCINTCLEAR
|
|
//printf("%02x to VGCINTCLEAR\n", data);
|
|
clear_vgcint(data);
|
|
break;
|
|
|
|
case 0x33: // CLOCKDATA
|
|
m_clkdata = data;
|
|
break;
|
|
|
|
case 0x34: // CLOCKCTL
|
|
if ((data & 0xf) != (m_video->get_GS_border() & 0xf))
|
|
{
|
|
m_screen->update_now();
|
|
}
|
|
m_clock_control = data & 0x7f;
|
|
m_video->set_GS_border(data & 0xf);
|
|
m_rtc->ce_w(BIT(data, 7) ^ 1);
|
|
if (data & 0x80)
|
|
{
|
|
process_clock();
|
|
}
|
|
break;
|
|
|
|
case 0x35: // SHADOW
|
|
m_shadow = data;
|
|
|
|
// handle I/O and language card inhibit bits here
|
|
if (m_shadow & SHAD_IOLC)
|
|
{
|
|
m_bank0_atc.select(0);
|
|
m_bank1_atc.select(0);
|
|
}
|
|
else
|
|
{
|
|
m_bank0_atc.select(1);
|
|
m_bank1_atc.select(1);
|
|
}
|
|
break;
|
|
|
|
case 0x36: // SPEED
|
|
m_speed = data;
|
|
|
|
if (m_speed & SPEED_ALLBANKS)
|
|
{
|
|
logerror("apple2gs: Driver does not support shadowing in all banks\n");
|
|
}
|
|
update_speed();
|
|
break;
|
|
|
|
case 0x38: // SCCBREG
|
|
m_scc->cb_w(0, data);
|
|
break;
|
|
|
|
case 0x39: // SCCAREG
|
|
m_scc->ca_w(0, data);
|
|
break;
|
|
|
|
case 0x3a: // SCCBDATA
|
|
m_scc->db_w(0, data);
|
|
break;
|
|
|
|
case 0x3b: // SCCADATA
|
|
m_scc->da_w(0, data);
|
|
break;
|
|
|
|
case 0x3c: // SOUNDCTL
|
|
m_sndglu_ctrl = data & 0x7f; // make sure DOC is never busy
|
|
if (!(m_sndglu_ctrl & 0x40)) // clear hi byte of address pointer on DOC access
|
|
{
|
|
m_sndglu_addr &= 0xff;
|
|
}
|
|
break;
|
|
|
|
case 0x3d: // SOUNDDATA
|
|
if (m_sndglu_ctrl & 0x40) // docram access
|
|
{
|
|
m_docram[m_sndglu_addr] = data;
|
|
}
|
|
else
|
|
{
|
|
m_doc->write(m_sndglu_addr, data);
|
|
}
|
|
|
|
if (m_sndglu_ctrl & 0x20) // auto-increment
|
|
{
|
|
m_sndglu_addr++;
|
|
}
|
|
break;
|
|
|
|
case 0x3e: // SOUNDADRL
|
|
m_sndglu_addr &= 0xff00;
|
|
m_sndglu_addr |= data;
|
|
break;
|
|
|
|
case 0x3f: // SOUNDADRH
|
|
m_sndglu_addr &= 0x00ff;
|
|
m_sndglu_addr |= data<<8;
|
|
break;
|
|
|
|
case 0x41: // INTEN
|
|
m_inten = data & 0x1f;
|
|
// clearing enable bits may clear INTFLAG_IRQASSERTED
|
|
// but it does not clear INTFLAG status bits
|
|
if (!(data & 0x10))
|
|
{
|
|
lower_irq(IRQS_QTRSEC);
|
|
}
|
|
if (!(data & 0x08))
|
|
{
|
|
lower_irq(IRQS_VBL);
|
|
}
|
|
//printf("%02x to INTEN, now %02x\n", data, m_vgcint);
|
|
break;
|
|
|
|
case 0x59: // Zip GS-specific settings
|
|
if (m_accel_unlocked)
|
|
{
|
|
m_accel_gsxsettings = data & 0xf8;
|
|
m_accel_gsxsettings |= 0x01; // indicate this is a GS
|
|
}
|
|
do_io(offset);
|
|
break;
|
|
|
|
case 0x5a: // Zip accelerator unlock
|
|
if (m_sysconfig->read() & 0x01)
|
|
{
|
|
if (data == 0x5a)
|
|
{
|
|
m_accel_stage++;
|
|
if (m_accel_stage == 4)
|
|
{
|
|
m_accel_unlocked = true;
|
|
}
|
|
}
|
|
else if (data == 0xa5)
|
|
{
|
|
// lock
|
|
m_accel_unlocked = false;
|
|
m_accel_stage = 0;
|
|
}
|
|
else if (m_accel_unlocked)
|
|
{
|
|
// disable acceleration
|
|
m_accel_fast = false;
|
|
accel_normal_speed();
|
|
}
|
|
}
|
|
do_io(offset);
|
|
break;
|
|
|
|
case 0x5b: // Zip full speed
|
|
if (m_accel_unlocked)
|
|
{
|
|
m_accel_fast = true;
|
|
accel_full_speed();
|
|
}
|
|
do_io(offset);
|
|
break;
|
|
|
|
case 0x5c: // Zip slot/speaker flags
|
|
if (m_accel_unlocked)
|
|
{
|
|
m_accel_slotspk = data;
|
|
}
|
|
do_io(offset);
|
|
break;
|
|
|
|
case 0x5d: // Zip speed percentage
|
|
if (m_accel_unlocked)
|
|
{
|
|
m_accel_percent = data;
|
|
}
|
|
do_io(offset);
|
|
break;
|
|
|
|
case 0x68: // STATEREG
|
|
m_altzp = (data & 0x80);
|
|
m_video->scr_w(data & 0x40);
|
|
m_ramrd = (data & 0x20);
|
|
m_ramwrt = (data & 0x10);
|
|
m_lcram = (data & 0x08) ? false : true;
|
|
m_lcram2 = (data & 0x04);
|
|
m_rombank = (data & 0x02);
|
|
m_intcxrom = (data & 0x01);
|
|
|
|
// update the aux state
|
|
auxbank_update();
|
|
|
|
// update LC state
|
|
if (m_lcram)
|
|
{
|
|
m_lcbank.select(1);
|
|
m_lcaux.select(1);
|
|
m_lc00.select(1);
|
|
m_lc01.select(1);
|
|
}
|
|
else
|
|
{
|
|
m_lcbank.select(0);
|
|
m_lcaux.select(0);
|
|
m_lc00.select(0);
|
|
m_lc01.select(0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
do_io(offset);
|
|
break;
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::c080_r(offs_t offset)
|
|
{
|
|
if (!machine().side_effects_disabled())
|
|
{
|
|
int slot;
|
|
|
|
slow_cycle();
|
|
|
|
offset &= 0x7f;
|
|
slot = offset / 0x10;
|
|
|
|
if (slot == 0)
|
|
{
|
|
lc_update(offset & 0xf, false);
|
|
}
|
|
else
|
|
{
|
|
accel_slot(slot);
|
|
|
|
if (slot >= 4)
|
|
{
|
|
if ((offset & 0xf) == 0x9)
|
|
{
|
|
m_motors_active |= (1 << (slot - 4));
|
|
}
|
|
else if ((offset & 0xf) == 8)
|
|
{
|
|
m_motors_active &= ~(1 << (slot - 4));
|
|
}
|
|
|
|
update_speed();
|
|
}
|
|
|
|
// slot 3 always has I/O go to the external card
|
|
if ((slot != 3) && ((m_slotromsel & (1 << slot)) == 0))
|
|
{
|
|
if (slot == 6)
|
|
{
|
|
return m_iwm->read(offset & 0xf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_slotdevice[slot] != nullptr)
|
|
{
|
|
return m_slotdevice[slot]->read_c0nx(offset % 0x10);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return read_floatingbus();
|
|
}
|
|
|
|
void apple2gs_state::c080_w(offs_t offset, u8 data)
|
|
{
|
|
int slot;
|
|
|
|
slow_cycle();
|
|
|
|
offset &= 0x7f;
|
|
slot = offset / 0x10;
|
|
|
|
if (slot == 0)
|
|
{
|
|
lc_update(offset & 0xf, true);
|
|
}
|
|
else
|
|
{
|
|
if (slot >= 4)
|
|
{
|
|
if ((offset & 0xf) == 0x9)
|
|
{
|
|
m_motors_active |= (1 << (slot - 4));
|
|
}
|
|
else if ((offset & 0xf) == 8)
|
|
{
|
|
m_motors_active &= ~(1 << (slot - 4));
|
|
}
|
|
|
|
update_speed();
|
|
}
|
|
|
|
// slot 3 always has I/O go to the external card
|
|
if ((slot != 3) && ((m_slotromsel & (1 << slot)) == 0))
|
|
{
|
|
if (slot == 6)
|
|
{
|
|
m_iwm->write(offset & 0xf, data);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_slotdevice[slot] != nullptr)
|
|
{
|
|
m_slotdevice[slot]->write_c0nx(offset % 0x10, data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::read_slot_rom(int slotbias, int offset)
|
|
{
|
|
const int slotnum = ((offset>>8) & 0xf) + slotbias;
|
|
|
|
// printf("read_slot_rom: sl %d offs %x, cnxx_slot %d\n", slotnum, offset, m_cnxx_slot);
|
|
|
|
if (m_slotdevice[slotnum] != nullptr)
|
|
{
|
|
// printf("slotdevice is not null\n");
|
|
if ((m_cnxx_slot == CNXX_UNCLAIMED) && (m_slotdevice[slotnum]->take_c800()) && (!machine().side_effects_disabled()))
|
|
{
|
|
m_cnxx_slot = slotnum;
|
|
update_slotrom_banks();
|
|
}
|
|
|
|
return m_slotdevice[slotnum]->read_cnxx(offset&0xff);
|
|
}
|
|
|
|
return read_floatingbus();
|
|
}
|
|
|
|
void apple2gs_state::write_slot_rom(int slotbias, int offset, u8 data)
|
|
{
|
|
const int slotnum = ((offset>>8) & 0xf) + slotbias;
|
|
|
|
slow_cycle();
|
|
|
|
if (m_slotdevice[slotnum] != nullptr)
|
|
{
|
|
if ((m_cnxx_slot == CNXX_UNCLAIMED) && (m_slotdevice[slotnum]->take_c800()) && !machine().side_effects_disabled())
|
|
{
|
|
m_cnxx_slot = slotnum;
|
|
update_slotrom_banks();
|
|
}
|
|
|
|
m_slotdevice[slotnum]->write_cnxx(offset&0xff, data);
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::read_int_rom(int slotbias, int offset)
|
|
{
|
|
if ((m_cnxx_slot == CNXX_UNCLAIMED) && (!machine().side_effects_disabled()))
|
|
{
|
|
m_cnxx_slot = CNXX_INTROM;
|
|
update_slotrom_banks();
|
|
}
|
|
|
|
return m_rom[slotbias + offset];
|
|
}
|
|
|
|
u8 apple2gs_state::c100_r(offs_t offset)
|
|
{
|
|
const int slot = ((offset>>8) & 0xf) + 1;
|
|
|
|
accel_slot(slot);
|
|
slow_cycle();
|
|
|
|
// SETSLOTCXROM is disabled, so the $C02D SLOT register controls what's in each slot
|
|
if (!BIT(m_slotromsel, slot))
|
|
{
|
|
return read_int_rom(0x3c100, offset);
|
|
}
|
|
|
|
return read_slot_rom(1, offset);
|
|
}
|
|
|
|
void apple2gs_state::c100_w(offs_t offset, u8 data)
|
|
{
|
|
const int slot = ((offset>>8) & 0xf) + 1;
|
|
|
|
accel_slot(slot);
|
|
slow_cycle();
|
|
|
|
if (BIT(m_slotromsel, slot))
|
|
{
|
|
write_slot_rom(1, offset, data);
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::c300_int_r(offs_t offset) { accel_slot(3 + ((offset >> 8) & 0x7)); slow_cycle(); return read_int_rom(0x3c300, offset); }
|
|
u8 apple2gs_state::c300_r(offs_t offset) { accel_slot(3 + ((offset >> 8) & 0x7)); slow_cycle(); return read_slot_rom(3, offset); }
|
|
void apple2gs_state::c300_w(offs_t offset, u8 data) { accel_slot(3 + ((offset >> 8) & 0x7)); slow_cycle(); write_slot_rom(3, offset, data); }
|
|
|
|
u8 apple2gs_state::c400_r(offs_t offset)
|
|
{
|
|
const int slot = ((offset>>8) & 0xf) + 4;
|
|
|
|
accel_slot(slot);
|
|
slow_cycle();
|
|
|
|
if (!BIT(m_slotromsel, slot))
|
|
{
|
|
return read_int_rom(0x3c400, offset);
|
|
}
|
|
|
|
return read_slot_rom(4, offset);
|
|
}
|
|
|
|
void apple2gs_state::c400_w(offs_t offset, u8 data)
|
|
{
|
|
const int slot = ((offset>>8) & 0xf) + 4;
|
|
|
|
accel_slot(slot);
|
|
slow_cycle();
|
|
|
|
if (BIT(m_slotromsel, slot))
|
|
{
|
|
write_slot_rom(4, offset, data);
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::c800_r(offs_t offset)
|
|
{
|
|
slow_cycle();
|
|
|
|
if ((offset == 0x7ff) && !machine().side_effects_disabled())
|
|
{
|
|
m_cnxx_slot = CNXX_UNCLAIMED;
|
|
update_slotrom_banks();
|
|
return 0xff;
|
|
}
|
|
|
|
if (m_cnxx_slot == CNXX_INTROM)
|
|
{
|
|
return m_rom[offset + 0x3c800];
|
|
}
|
|
|
|
if ((m_cnxx_slot > 0) && (m_slotdevice[m_cnxx_slot] != nullptr))
|
|
{
|
|
return m_slotdevice[m_cnxx_slot]->read_c800(offset&0xfff);
|
|
}
|
|
|
|
return 0xff;
|
|
}
|
|
|
|
void apple2gs_state::c800_w(offs_t offset, u8 data)
|
|
{
|
|
slow_cycle();
|
|
|
|
if ((m_cnxx_slot > 0) && (m_slotdevice[m_cnxx_slot] != nullptr))
|
|
{
|
|
m_slotdevice[m_cnxx_slot]->write_c800(offset&0xfff, data);
|
|
}
|
|
|
|
if (offset == 0x7ff)
|
|
{
|
|
m_cnxx_slot = CNXX_UNCLAIMED;
|
|
update_slotrom_banks();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 65816 bank register is left on floating bus
|
|
u8 apple2gs_state::floatingbank_r(offs_t offset)
|
|
{
|
|
// When the memory expansion slot is empty, this is the behavior
|
|
// for every bank not populated by motherboard RAM or ROM.
|
|
return offset >> 16;
|
|
}
|
|
|
|
// mirror expansion RAM banks per Hardware Reference, Figure 3-9
|
|
u8 apple2gs_state::ghostram_r(offs_t offset)
|
|
{
|
|
offs_t ghost_offset = (offset & m_ghost_mask) + m_motherboard_ram;
|
|
|
|
if (ghost_offset < m_ram_size)
|
|
return m_ram_ptr[ghost_offset];
|
|
else // unpopulated non-power-of-two bank
|
|
return m_is_rom3 ? 0xff : ((offset + m_motherboard_ram + m_ghost_mask + 1) >> 16);
|
|
}
|
|
|
|
void apple2gs_state::ghostram_w(offs_t offset, u8 data)
|
|
{
|
|
offs_t ghost_offset = (offset & m_ghost_mask) + m_motherboard_ram;
|
|
|
|
if (ghost_offset < m_ram_size)
|
|
m_ram_ptr[ghost_offset] = data;
|
|
}
|
|
|
|
u8 apple2gs_state::inh_r(offs_t offset)
|
|
{
|
|
if (m_inh_slot != -1)
|
|
{
|
|
return m_slotdevice[m_inh_slot]->read_inh_rom(offset + 0xd000);
|
|
}
|
|
|
|
assert(0); // hitting inh_r with invalid m_inh_slot should not be possible
|
|
return read_floatingbus();
|
|
}
|
|
|
|
void apple2gs_state::inh_w(offs_t offset, u8 data)
|
|
{
|
|
if (m_inh_slot != -1)
|
|
{
|
|
m_slotdevice[m_inh_slot]->write_inh_rom(offset + 0xd000, data);
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::lc_r(offs_t offset)
|
|
{
|
|
slow_cycle();
|
|
if (m_altzp)
|
|
{
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
return m_megaii_ram[(offset & 0xfff) + 0x1c000];
|
|
}
|
|
else
|
|
{
|
|
return m_megaii_ram[(offset & 0xfff) + 0x1d000];
|
|
}
|
|
}
|
|
|
|
return m_megaii_ram[(offset & 0x1fff) + 0x1e000];
|
|
}
|
|
else
|
|
{
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
return m_megaii_ram[(offset & 0xfff) + 0xc000];
|
|
}
|
|
else
|
|
{
|
|
return m_megaii_ram[(offset & 0xfff) + 0xd000];
|
|
}
|
|
}
|
|
|
|
return m_megaii_ram[(offset & 0x1fff) + 0xe000];
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::lc_w(offs_t offset, u8 data)
|
|
{
|
|
slow_cycle();
|
|
if (!m_lcwriteenable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_altzp)
|
|
{
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
m_megaii_ram[(offset & 0xfff) + 0x1c000] = data;
|
|
}
|
|
else
|
|
{
|
|
m_megaii_ram[(offset & 0xfff) + 0x1d000] = data;
|
|
}
|
|
return;
|
|
}
|
|
|
|
m_megaii_ram[(offset & 0x1fff) + 0x1e000] = data;
|
|
}
|
|
else
|
|
{
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
m_megaii_ram[(offset & 0xfff) + 0xc000] = data;
|
|
}
|
|
else
|
|
{
|
|
m_megaii_ram[(offset & 0xfff) + 0xd000] = data;
|
|
}
|
|
return;
|
|
}
|
|
|
|
m_megaii_ram[(offset & 0x1fff) + 0xe000] = data;
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::lc_aux_r(offs_t offset)
|
|
{
|
|
slow_cycle();
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
return m_megaii_ram[(offset & 0xfff) + 0x1c000];
|
|
}
|
|
else
|
|
{
|
|
return m_megaii_ram[(offset & 0xfff) + 0x1d000];
|
|
}
|
|
}
|
|
|
|
return m_megaii_ram[(offset & 0x1fff) + 0x1e000];
|
|
}
|
|
|
|
void apple2gs_state::lc_aux_w(offs_t offset, u8 data)
|
|
{
|
|
slow_cycle();
|
|
if (!m_lcwriteenable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
m_megaii_ram[(offset & 0xfff) + 0x1c000] = data;
|
|
}
|
|
else
|
|
{
|
|
m_megaii_ram[(offset & 0xfff) + 0x1d000] = data;
|
|
}
|
|
return;
|
|
}
|
|
|
|
m_megaii_ram[(offset & 0x1fff) + 0x1e000] = data;
|
|
}
|
|
|
|
u8 apple2gs_state::lc_00_r(offs_t offset)
|
|
{
|
|
if (m_altzp)
|
|
{
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
return m_ram_ptr[(offset & 0xfff) + 0x1c000];
|
|
}
|
|
else
|
|
{
|
|
return m_ram_ptr[(offset & 0xfff) + 0x1d000];
|
|
}
|
|
}
|
|
|
|
return m_ram_ptr[(offset & 0x1fff) + 0x1e000];
|
|
}
|
|
else
|
|
{
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
return m_ram_ptr[(offset & 0xfff) + 0xc000];
|
|
}
|
|
else
|
|
{
|
|
return m_ram_ptr[(offset & 0xfff) + 0xd000];
|
|
}
|
|
}
|
|
|
|
return m_ram_ptr[(offset & 0x1fff) + 0xe000];
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::lc_00_w(offs_t offset, u8 data)
|
|
{
|
|
if (!m_lcwriteenable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_altzp)
|
|
{
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
m_ram_ptr[(offset & 0xfff) + 0x1c000] = data;
|
|
}
|
|
else
|
|
{
|
|
m_ram_ptr[(offset & 0xfff) + 0x1d000] = data;
|
|
}
|
|
return;
|
|
}
|
|
|
|
m_ram_ptr[(offset & 0x1fff) + 0x1e000] = data;
|
|
}
|
|
else
|
|
{
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
m_ram_ptr[(offset & 0xfff) + 0xc000] = data;
|
|
}
|
|
else
|
|
{
|
|
m_ram_ptr[(offset & 0xfff) + 0xd000] = data;
|
|
}
|
|
return;
|
|
}
|
|
|
|
m_ram_ptr[(offset & 0x1fff) + 0xe000] = data;
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::lc_01_r(offs_t offset)
|
|
{
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
return m_ram_ptr[(offset & 0xfff) + 0x1c000];
|
|
}
|
|
else
|
|
{
|
|
return m_ram_ptr[(offset & 0xfff) + 0x1d000];
|
|
}
|
|
}
|
|
|
|
return m_ram_ptr[(offset & 0x1fff) + 0x1e000];
|
|
}
|
|
|
|
void apple2gs_state::lc_01_w(offs_t offset, u8 data)
|
|
{
|
|
if (!m_lcwriteenable)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (offset < 0x1000)
|
|
{
|
|
if (m_lcram2)
|
|
{
|
|
m_ram_ptr[(offset & 0xfff) + 0x1c000] = data;
|
|
}
|
|
else
|
|
{
|
|
m_ram_ptr[(offset & 0xfff) + 0x1d000] = data;
|
|
}
|
|
return;
|
|
}
|
|
|
|
m_ram_ptr[(offset & 0x1fff) + 0x1e000] = data;
|
|
}
|
|
|
|
u8 apple2gs_state::read_floatingbus()
|
|
{
|
|
int h_clock = (m_screen->hpos() - BORDER_LEFT) / 16 + (25 + ALIGN_RFB); // adjust for set_raw
|
|
if (h_clock >= 65)
|
|
h_clock -= 65;
|
|
|
|
int v_clock = m_screen->vpos();
|
|
if (v_clock < BORDER_TOP)
|
|
v_clock += m_screen->height(); // remap top border to bottom of VBL
|
|
v_clock -= BORDER_TOP;
|
|
v_clock += (h_clock < (25 - ALIGN_RFB)); // adjust for hpos wrap
|
|
if (v_clock >= m_screen->height())
|
|
v_clock -= m_screen->height();
|
|
|
|
/*
|
|
Unlike 8-bit Apples, the IIgs does not redundantly scan video memory during
|
|
blanking. The first five HBL cycles are used for Mega II "RAM refresh":
|
|
during these PH1 cycles (and everywhere after scanline 199) nothing is put
|
|
onto the data bus. The floating value is instead the last byte fetched
|
|
during PH0, of the instruction which invoked this read. For example:
|
|
LDA C050 returns C0 (typical softswitch)
|
|
LDA C250 returns C2 (ROM of a Your Card slot with no card)
|
|
LDA 50 returns 50 (with direct page C000)
|
|
*/
|
|
static bool recurse = false; // no recursion, single thread
|
|
if (!recurse && ((h_clock < 5) || (v_clock > 199)))
|
|
{
|
|
// approximate (for non-flow control instructions) by peeking at PC
|
|
offs_t pc = m_maincpu->pc();
|
|
// previous byte, wrapping at bank boundary
|
|
pc = (pc & 0xff0000) | ((pc - 1) & 0xffff);
|
|
// prevent recursion via slot firmware or Mega II C07x
|
|
recurse = true;
|
|
u8 res = m_maincpu->space(AS_PROGRAM).read_byte(pc);
|
|
recurse = false;
|
|
return res;
|
|
}
|
|
else
|
|
{
|
|
const u32 address = m_video->scanner_address_GS(h_clock, v_clock);
|
|
return m_megaii_ram[address];
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
ADDRESS MAP
|
|
***************************************************************************/
|
|
|
|
template <int Addr>
|
|
u8 apple2gs_state::e0ram_r(offs_t offset) { slow_cycle(); return m_megaii_ram[offset + Addr]; }
|
|
|
|
template <int Addr>
|
|
void apple2gs_state::e0ram_w(offs_t offset, u8 data) { slow_cycle(); m_megaii_ram[offset + Addr] = data; }
|
|
|
|
template <int Addr>
|
|
u8 apple2gs_state::e1ram_r(offs_t offset) { slow_cycle(); return m_megaii_ram[offset + Addr + 0x10000]; }
|
|
|
|
template <int Addr>
|
|
void apple2gs_state::e1ram_w(offs_t offset, u8 data) { slow_cycle(); m_megaii_ram[offset + Addr + 0x10000] = data; }
|
|
|
|
template u8 apple2gs_state::e0ram_r<0x0000>(offs_t offset);
|
|
template u8 apple2gs_state::e0ram_r<0x0200>(offs_t offset);
|
|
template u8 apple2gs_state::e0ram_r<0x0400>(offs_t offset);
|
|
template u8 apple2gs_state::e0ram_r<0x0800>(offs_t offset);
|
|
template u8 apple2gs_state::e0ram_r<0x2000>(offs_t offset);
|
|
template u8 apple2gs_state::e0ram_r<0x4000>(offs_t offset);
|
|
|
|
template u8 apple2gs_state::e1ram_r<0x0000>(offs_t offset);
|
|
template u8 apple2gs_state::e1ram_r<0x0200>(offs_t offset);
|
|
template u8 apple2gs_state::e1ram_r<0x0400>(offs_t offset);
|
|
template u8 apple2gs_state::e1ram_r<0x0800>(offs_t offset);
|
|
template u8 apple2gs_state::e1ram_r<0x2000>(offs_t offset);
|
|
template u8 apple2gs_state::e1ram_r<0x4000>(offs_t offset);
|
|
|
|
template void apple2gs_state::e0ram_w<0x0000>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e0ram_w<0x0200>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e0ram_w<0x0400>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e0ram_w<0x0800>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e0ram_w<0x2000>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e0ram_w<0x4000>(offs_t offset, u8 data);
|
|
|
|
template void apple2gs_state::e1ram_w<0x0000>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e1ram_w<0x0200>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e1ram_w<0x0400>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e1ram_w<0x0800>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e1ram_w<0x2000>(offs_t offset, u8 data);
|
|
template void apple2gs_state::e1ram_w<0x4000>(offs_t offset, u8 data);
|
|
|
|
u8 apple2gs_state::auxram0000_r(offs_t offset)
|
|
{
|
|
slow_cycle();
|
|
if ((offset >= 0x2000) && (offset < 0xa000) && ((m_video->get_newvideo() & 0xc0) != 0))
|
|
{
|
|
if (offset & 1)
|
|
{
|
|
offset = ((offset - 0x2000) >> 1) + 0x6000;
|
|
}
|
|
else
|
|
{
|
|
offset = ((offset - 0x2000) >> 1) + 0x2000;
|
|
}
|
|
}
|
|
return m_megaii_ram[offset+0x10000];
|
|
}
|
|
|
|
void apple2gs_state::auxram0000_w(offs_t offset, u8 data)
|
|
{
|
|
u16 orig_addr = offset;
|
|
|
|
slow_cycle();
|
|
|
|
if ((offset >= 0x2000) && (offset < 0xa000) && ((m_video->get_newvideo() & 0xc0) != 0))
|
|
{
|
|
if (offset & 1)
|
|
{
|
|
offset = ((offset - 0x2000) >> 1) + 0x6000;
|
|
}
|
|
else
|
|
{
|
|
offset = ((offset - 0x2000) >> 1) + 0x2000;
|
|
}
|
|
}
|
|
|
|
m_megaii_ram[offset+0x10000] = data;
|
|
|
|
if ((orig_addr >= 0x9e00) && (orig_addr <= 0x9fff))
|
|
{
|
|
int color = (orig_addr - 0x9e00) >> 1;
|
|
m_video->set_SHR_color(color, rgb_t(
|
|
((m_megaii_ram[0x19f00 + color] >> 0) & 0x0f) * 17,
|
|
((m_megaii_ram[0x15f00 + color] >> 4) & 0x0f) * 17,
|
|
((m_megaii_ram[0x15f00 + color] >> 0) & 0x0f) * 17));
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::b0ram0000_r(offs_t offset) { return m_ram_ptr[offset]; }
|
|
void apple2gs_state::b0ram0000_w(offs_t offset, u8 data) { m_ram_ptr[offset] = data; }
|
|
u8 apple2gs_state::b0ram0200_r(offs_t offset) { return m_ram_ptr[offset+0x200]; }
|
|
void apple2gs_state::b0ram0200_w(offs_t offset, u8 data) { m_ram_ptr[offset+0x200] = data; }
|
|
u8 apple2gs_state::b0ram0400_r(offs_t offset) { return m_ram_ptr[offset+0x400]; }
|
|
void apple2gs_state::b0ram0400_w(offs_t offset, u8 data)
|
|
{
|
|
m_ram_ptr[offset+0x400] = data;
|
|
if (!(m_shadow & SHAD_TXTPG1))
|
|
{
|
|
slow_cycle();
|
|
m_megaii_ram[offset+0x0400] = data;
|
|
}
|
|
}
|
|
u8 apple2gs_state::b0ram0800_r(offs_t offset) { return m_ram_ptr[offset+0x800]; }
|
|
void apple2gs_state::b0ram0800_w(offs_t offset, u8 data)
|
|
{
|
|
m_ram_ptr[offset+0x800] = data;
|
|
if (offset < 0x400)
|
|
{
|
|
if (!(m_shadow & SHAD_TXTPG2) && m_is_rom3)
|
|
{
|
|
slow_cycle();
|
|
m_megaii_ram[offset+0x800] = data;
|
|
}
|
|
}
|
|
}
|
|
u8 apple2gs_state::b0ram2000_r(offs_t offset) { return m_ram_ptr[offset+0x2000]; }
|
|
void apple2gs_state::b0ram2000_w(offs_t offset, u8 data)
|
|
{
|
|
m_ram_ptr[offset+0x2000] = data;
|
|
if (!(m_shadow & SHAD_HIRESPG1))
|
|
{
|
|
slow_cycle();
|
|
m_megaii_ram[offset+0x2000] = data;
|
|
}
|
|
}
|
|
u8 apple2gs_state::b0ram4000_r(offs_t offset) { return m_ram_ptr[offset+0x4000]; }
|
|
void apple2gs_state::b0ram4000_w(offs_t offset, u8 data)
|
|
{
|
|
m_ram_ptr[offset+0x4000] = data;
|
|
if (offset < 0x2000)
|
|
{
|
|
if (!(m_shadow & SHAD_HIRESPG2))
|
|
{
|
|
slow_cycle();
|
|
m_megaii_ram[offset+0x4000] = data;
|
|
}
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::b1ram0000_r(offs_t offset) { return m_ram_ptr[offset+0x10000]; }
|
|
void apple2gs_state::b1ram0000_w(offs_t offset, u8 data) { m_ram_ptr[offset+0x10000] = data; }
|
|
u8 apple2gs_state::b1ram0200_r(offs_t offset) { return m_ram_ptr[offset+0x10200]; }
|
|
void apple2gs_state::b1ram0200_w(offs_t offset, u8 data) { m_ram_ptr[offset+0x10200] = data; }
|
|
u8 apple2gs_state::b1ram0400_r(offs_t offset) { return m_ram_ptr[offset+0x10400]; }
|
|
void apple2gs_state::b1ram0400_w(offs_t offset, u8 data)
|
|
{
|
|
m_ram_ptr[offset+0x10400] = data;
|
|
if (!(m_shadow & SHAD_TXTPG1))
|
|
{
|
|
slow_cycle();
|
|
m_megaii_ram[offset+0x10400] = data;
|
|
}
|
|
}
|
|
u8 apple2gs_state::b1ram0800_r(offs_t offset) { return m_ram_ptr[offset+0x10800]; }
|
|
void apple2gs_state::b1ram0800_w(offs_t offset, u8 data)
|
|
{
|
|
m_ram_ptr[offset+0x10800] = data;
|
|
if (offset < 0x400)
|
|
{
|
|
if (!(m_shadow & SHAD_TXTPG2) && m_is_rom3)
|
|
{
|
|
slow_cycle();
|
|
m_megaii_ram[offset+0x10800] = data;
|
|
}
|
|
}
|
|
}
|
|
u8 apple2gs_state::b1ram2000_r(offs_t offset) { return m_ram_ptr[offset+0x12000]; }
|
|
void apple2gs_state::b1ram2000_w(offs_t offset, u8 data)
|
|
{
|
|
m_ram_ptr[offset+0x12000] = data;
|
|
if ((!(m_shadow & SHAD_HIRESPG1) && !(m_shadow & SHAD_AUXHIRES)) || !(m_shadow & SHAD_SUPERHIRES))
|
|
{
|
|
auxram0000_w(offset+0x2000, data);
|
|
}
|
|
}
|
|
u8 apple2gs_state::b1ram4000_r(offs_t offset) { return m_ram_ptr[offset+0x14000]; }
|
|
void apple2gs_state::b1ram4000_w(offs_t offset, u8 data)
|
|
{
|
|
m_ram_ptr[offset+0x14000] = data;
|
|
if (offset < 0x2000)
|
|
{
|
|
if ((!(m_shadow & SHAD_HIRESPG2) && !(m_shadow & SHAD_AUXHIRES)) || !(m_shadow & SHAD_SUPERHIRES))
|
|
{
|
|
auxram0000_w(offset+0x4000, data);
|
|
}
|
|
}
|
|
else if ((offset >= 0x2000) && (offset <= 0x5fff))
|
|
{
|
|
if (!(m_shadow & SHAD_SUPERHIRES))
|
|
{
|
|
auxram0000_w(offset+0x4000, data);
|
|
}
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::bank0_c000_r(offs_t offset)
|
|
{
|
|
if (offset & 0x2000)
|
|
{
|
|
offset ^= 0x1000;
|
|
}
|
|
|
|
if (m_ramrd)
|
|
{
|
|
return m_ram_ptr[offset + 0x1c000];
|
|
}
|
|
|
|
return m_ram_ptr[offset + 0xc000];
|
|
}
|
|
|
|
void apple2gs_state::bank0_c000_w(offs_t offset, u8 data)
|
|
{
|
|
if (offset & 0x2000)
|
|
{
|
|
offset ^= 0x1000;
|
|
}
|
|
|
|
if (m_ramwrt)
|
|
{
|
|
m_ram_ptr[offset + 0x1c000] = data;
|
|
return;
|
|
}
|
|
|
|
m_ram_ptr[offset + 0xc000] = data;
|
|
}
|
|
|
|
u8 apple2gs_state::bank1_0000_r(offs_t offset) { return m_ram_ptr[offset + 0x10000]; }
|
|
u8 apple2gs_state::bank1_c000_r(offs_t offset) { if (offset & 0x2000) offset ^= 0x1000; return m_ram_ptr[offset + 0x1c000]; }
|
|
void apple2gs_state::bank1_c000_w(offs_t offset, u8 data) { if (offset & 0x2000) offset ^= 0x1000; m_ram_ptr[offset + 0x1c000] = data; }
|
|
void apple2gs_state::bank1_0000_sh_w(offs_t offset, u8 data)
|
|
{
|
|
m_ram_ptr[offset + 0x10000] = data;
|
|
|
|
switch (offset>>8)
|
|
{
|
|
case 0x04: // text page 1
|
|
case 0x05:
|
|
case 0x06:
|
|
case 0x07:
|
|
if (!(m_shadow & SHAD_TXTPG1))
|
|
{
|
|
slow_cycle();
|
|
m_megaii_ram[offset + 0x10000] = data;
|
|
}
|
|
break;
|
|
|
|
case 0x08: // text page 2 (only shadowable on ROM 03)
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x0b:
|
|
if ((!(m_shadow & SHAD_TXTPG2)) && (m_is_rom3))
|
|
{
|
|
slow_cycle();
|
|
m_megaii_ram[offset + 0x10000] = data;
|
|
}
|
|
break;
|
|
|
|
// hi-res page 1
|
|
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
|
|
case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
|
|
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
|
|
case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
|
|
if ((!(m_shadow & SHAD_HIRESPG1) && !(m_shadow & SHAD_AUXHIRES)) || !(m_shadow & SHAD_SUPERHIRES))
|
|
{
|
|
auxram0000_w(offset, data);
|
|
}
|
|
break;
|
|
|
|
// hi-res page 2
|
|
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
|
|
case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
|
case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
|
|
case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
|
|
if ((!(m_shadow & SHAD_HIRESPG2) && !(m_shadow & SHAD_AUXHIRES)) || !(m_shadow & SHAD_SUPERHIRES))
|
|
{
|
|
auxram0000_w(offset, data);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ((offset >= 0x6000) && (offset <= 0x9fff))
|
|
{
|
|
if (!(m_shadow & SHAD_SUPERHIRES))
|
|
{
|
|
auxram0000_w(offset, data);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::apple2gs_map(address_map &map)
|
|
{
|
|
// default behavior for unpopulated banks (affected by memory expansion slot)
|
|
map(0x000000, 0xffffff).r(FUNC(apple2gs_state::floatingbank_r)).nopw();
|
|
map.unmap_value_high(); // with expansion slot, unpopulated banks return ff on ROM3
|
|
|
|
// "fast side" - runs 2.8 MHz minus RAM refresh, banks 00 and 01 usually have writes shadowed to E0/E1 where I/O lives
|
|
// Banks 00 and 01 also have their own independent language cards which are NOT shadowed.
|
|
map(0x000000, 0x0001ff).view(m_b0_0000bank);
|
|
m_b0_0000bank[0](0x0000, 0x01ff).rw(FUNC(apple2gs_state::b0ram0000_r), FUNC(apple2gs_state::b0ram0000_w));
|
|
m_b0_0000bank[1](0x0000, 0x01ff).rw(FUNC(apple2gs_state::b1ram0000_r), FUNC(apple2gs_state::b1ram0000_w));
|
|
|
|
map(0x000200, 0x0003ff).view(m_b0_0200bank);
|
|
m_b0_0200bank[0](0x0200, 0x03ff).rw(FUNC(apple2gs_state::b0ram0200_r), FUNC(apple2gs_state::b0ram0200_w)); // wr 0 rd 0
|
|
m_b0_0200bank[1](0x0200, 0x03ff).rw(FUNC(apple2gs_state::b1ram0200_r), FUNC(apple2gs_state::b0ram0200_w)); // wr 0 rd 1
|
|
m_b0_0200bank[2](0x0200, 0x03ff).rw(FUNC(apple2gs_state::b0ram0200_r), FUNC(apple2gs_state::b1ram0200_w)); // wr 1 rd 0
|
|
m_b0_0200bank[3](0x0200, 0x03ff).rw(FUNC(apple2gs_state::b1ram0200_r), FUNC(apple2gs_state::b1ram0200_w)); // wr 1 rd 1
|
|
|
|
map(0x000400, 0x0007ff).view(m_b0_0400bank);
|
|
m_b0_0400bank[0](0x0400, 0x07ff).rw(FUNC(apple2gs_state::b0ram0400_r), FUNC(apple2gs_state::b0ram0400_w)); // wr 0 rd 0
|
|
m_b0_0400bank[1](0x0400, 0x07ff).rw(FUNC(apple2gs_state::b1ram0400_r), FUNC(apple2gs_state::b0ram0400_w)); // wr 0 rd 1
|
|
m_b0_0400bank[2](0x0400, 0x07ff).rw(FUNC(apple2gs_state::b0ram0400_r), FUNC(apple2gs_state::b1ram0400_w)); // wr 1 rd 0
|
|
m_b0_0400bank[3](0x0400, 0x07ff).rw(FUNC(apple2gs_state::b1ram0400_r), FUNC(apple2gs_state::b1ram0400_w)); // wr 1 rd 1
|
|
|
|
map(0x000800, 0x001fff).view(m_b0_0800bank);
|
|
m_b0_0800bank[0](0x0800, 0x1fff).rw(FUNC(apple2gs_state::b0ram0800_r), FUNC(apple2gs_state::b0ram0800_w));
|
|
m_b0_0800bank[1](0x0800, 0x1fff).rw(FUNC(apple2gs_state::b1ram0800_r), FUNC(apple2gs_state::b0ram0800_w));
|
|
m_b0_0800bank[2](0x0800, 0x1fff).rw(FUNC(apple2gs_state::b0ram0800_r), FUNC(apple2gs_state::b1ram0800_w));
|
|
m_b0_0800bank[3](0x0800, 0x1fff).rw(FUNC(apple2gs_state::b1ram0800_r), FUNC(apple2gs_state::b1ram0800_w));
|
|
|
|
map(0x002000, 0x003fff).view(m_b0_2000bank);
|
|
m_b0_2000bank[0](0x2000, 0x3fff).rw(FUNC(apple2gs_state::b0ram2000_r), FUNC(apple2gs_state::b0ram2000_w));
|
|
m_b0_2000bank[1](0x2000, 0x3fff).rw(FUNC(apple2gs_state::b1ram2000_r), FUNC(apple2gs_state::b0ram2000_w));
|
|
m_b0_2000bank[2](0x2000, 0x3fff).rw(FUNC(apple2gs_state::b0ram2000_r), FUNC(apple2gs_state::b1ram2000_w));
|
|
m_b0_2000bank[3](0x2000, 0x3fff).rw(FUNC(apple2gs_state::b1ram2000_r), FUNC(apple2gs_state::b1ram2000_w));
|
|
|
|
map(0x004000, 0x00bfff).view(m_b0_4000bank);
|
|
m_b0_4000bank[0](0x4000, 0xbfff).rw(FUNC(apple2gs_state::b0ram4000_r), FUNC(apple2gs_state::b0ram4000_w));
|
|
m_b0_4000bank[1](0x4000, 0xbfff).rw(FUNC(apple2gs_state::b1ram4000_r), FUNC(apple2gs_state::b0ram4000_w));
|
|
m_b0_4000bank[2](0x4000, 0xbfff).rw(FUNC(apple2gs_state::b0ram4000_r), FUNC(apple2gs_state::b1ram4000_w));
|
|
m_b0_4000bank[3](0x4000, 0xbfff).rw(FUNC(apple2gs_state::b1ram4000_r), FUNC(apple2gs_state::b1ram4000_w));
|
|
|
|
map(0x00c000, 0x00ffff).view(m_bank0_atc);
|
|
m_bank0_atc[0](0xc000, 0xffff).rw(FUNC(apple2gs_state::bank0_c000_r), FUNC(apple2gs_state::bank0_c000_w));
|
|
m_bank0_atc[1](0xc000, 0xc07f).rw(FUNC(apple2gs_state::c000_r), FUNC(apple2gs_state::c000_w));
|
|
m_bank0_atc[1](0xc080, 0xc0ff).rw(FUNC(apple2gs_state::c080_r), FUNC(apple2gs_state::c080_w));
|
|
m_bank0_atc[1](0xc100, 0xc2ff).rw(FUNC(apple2gs_state::c100_r), FUNC(apple2gs_state::c100_w));
|
|
m_bank0_atc[1](0xc300, 0xc3ff).m(m_c300bank, FUNC(address_map_bank_device::amap8));
|
|
m_bank0_atc[1](0xc400, 0xc7ff).rw(FUNC(apple2gs_state::c400_r), FUNC(apple2gs_state::c400_w));
|
|
m_bank0_atc[1](0xc800, 0xcfff).rw(FUNC(apple2gs_state::c800_r), FUNC(apple2gs_state::c800_w));
|
|
|
|
m_bank0_atc[1](0xd000, 0xffff).view(m_upper00);
|
|
m_upper00[0](0xd000, 0xffff).view(m_lc00);
|
|
m_upper00[1](0xd000, 0xffff).rw(FUNC(apple2gs_state::inh_r), FUNC(apple2gs_state::inh_w));
|
|
|
|
m_lc00[0](0xd000, 0xffff).rom().region("maincpu", 0x3d000).w(FUNC(apple2gs_state::lc_00_w));
|
|
m_lc00[1](0xd000, 0xffff).rw(FUNC(apple2gs_state::lc_00_r), FUNC(apple2gs_state::lc_00_w));
|
|
m_lc00[2](0xd000, 0xffff).rom().region("maincpu", 0x39000).w(FUNC(apple2gs_state::lc_00_w));
|
|
m_lc00[3](0xd000, 0xffff).rw(FUNC(apple2gs_state::lc_00_r), FUNC(apple2gs_state::lc_00_w));
|
|
|
|
map(0x010000, 0x01bfff).rw(FUNC(apple2gs_state::bank1_0000_r), FUNC(apple2gs_state::bank1_0000_sh_w));
|
|
|
|
map(0x01c000, 0x01ffff).view(m_bank1_atc);
|
|
m_bank1_atc[0](0x1c000, 0x1ffff).rw(FUNC(apple2gs_state::bank1_c000_r), FUNC(apple2gs_state::bank1_c000_w));
|
|
m_bank1_atc[1](0x1c000, 0x1c07f).rw(FUNC(apple2gs_state::c000_r), FUNC(apple2gs_state::c000_w));
|
|
m_bank1_atc[1](0x1c080, 0x1c0ff).rw(FUNC(apple2gs_state::c080_r), FUNC(apple2gs_state::c080_w));
|
|
m_bank1_atc[1](0x1c100, 0x1c2ff).rw(FUNC(apple2gs_state::c100_r), FUNC(apple2gs_state::c100_w));
|
|
m_bank1_atc[1](0x1c300, 0x1c3ff).m(m_c300bank, FUNC(address_map_bank_device::amap8));
|
|
m_bank1_atc[1](0x1c400, 0x1c7ff).rw(FUNC(apple2gs_state::c400_r), FUNC(apple2gs_state::c400_w));
|
|
m_bank1_atc[1](0x1c800, 0x1cfff).rw(FUNC(apple2gs_state::c800_r), FUNC(apple2gs_state::c800_w));
|
|
|
|
m_bank1_atc[1](0x1d000, 0x1ffff).view(m_upper01);
|
|
m_upper01[0](0x1d000, 0x1ffff).view(m_lc01);
|
|
m_upper01[1](0x1d000, 0x1ffff).rw(FUNC(apple2gs_state::inh_r), FUNC(apple2gs_state::inh_w));
|
|
|
|
m_lc01[0](0x1d000, 0x1ffff).rom().region("maincpu", 0x3d000).w(FUNC(apple2gs_state::lc_01_w));
|
|
m_lc01[1](0x1d000, 0x1ffff).rw(FUNC(apple2gs_state::lc_01_r), FUNC(apple2gs_state::lc_01_w));
|
|
|
|
// "Mega II side" - this is basically a 128K IIe on a chip that runs merrily at 1 MHz
|
|
// Unfortunately all I/O happens here, including new IIgs-specific stuff
|
|
map(0xe00000, 0xe001ff).view(m_e0_0000bank);
|
|
m_e0_0000bank[0](0xe00000, 0xe001ff).rw(FUNC(apple2gs_state::e0ram_r<0x0000>), FUNC(apple2gs_state::e0ram_w<0x0000>));
|
|
m_e0_0000bank[1](0xe00000, 0xe001ff).rw(FUNC(apple2gs_state::e1ram_r<0x0000>), FUNC(apple2gs_state::e1ram_w<0x0000>));
|
|
|
|
map(0xe00200, 0xe003ff).view(m_e0_0200bank);
|
|
m_e0_0200bank[0](0xe00200, 0xe003ff).rw(FUNC(apple2gs_state::e0ram_r<0x0200>), FUNC(apple2gs_state::e0ram_w<0x0200>)); // wr 0 rd 0
|
|
m_e0_0200bank[1](0xe00200, 0xe003ff).rw(FUNC(apple2gs_state::e1ram_r<0x0200>), FUNC(apple2gs_state::e0ram_w<0x0200>)); // wr 0 rd 1
|
|
m_e0_0200bank[2](0xe00200, 0xe003ff).rw(FUNC(apple2gs_state::e0ram_r<0x0200>), FUNC(apple2gs_state::e1ram_w<0x0200>)); // wr 1 rd 0
|
|
m_e0_0200bank[3](0xe00200, 0xe003ff).rw(FUNC(apple2gs_state::e1ram_r<0x0200>), FUNC(apple2gs_state::e1ram_w<0x0200>)); // wr 1 rd 1
|
|
|
|
map(0xe00400, 0xe007ff).view(m_e0_0400bank);
|
|
m_e0_0400bank[0](0xe00400, 0xe007ff).rw(FUNC(apple2gs_state::e0ram_r<0x0400>), FUNC(apple2gs_state::e0ram_w<0x0400>)); // wr 0 rd 0
|
|
m_e0_0400bank[1](0xe00400, 0xe007ff).rw(FUNC(apple2gs_state::e1ram_r<0x0400>), FUNC(apple2gs_state::e0ram_w<0x0400>)); // wr 0 rd 1
|
|
m_e0_0400bank[2](0xe00400, 0xe007ff).rw(FUNC(apple2gs_state::e0ram_r<0x0400>), FUNC(apple2gs_state::e1ram_w<0x0400>)); // wr 1 rd 0
|
|
m_e0_0400bank[3](0xe00400, 0xe007ff).rw(FUNC(apple2gs_state::e1ram_r<0x0400>), FUNC(apple2gs_state::e1ram_w<0x0400>)); // wr 1 rd 1
|
|
|
|
map(0xe00800, 0xe01fff).view(m_e0_0800bank);
|
|
m_e0_0800bank[0](0xe00800, 0xe01fff).rw(FUNC(apple2gs_state::e0ram_r<0x0800>), FUNC(apple2gs_state::e0ram_w<0x0800>));
|
|
m_e0_0800bank[1](0xe00800, 0xe01fff).rw(FUNC(apple2gs_state::e1ram_r<0x0800>), FUNC(apple2gs_state::e0ram_w<0x0800>));
|
|
m_e0_0800bank[2](0xe00800, 0xe01fff).rw(FUNC(apple2gs_state::e0ram_r<0x0800>), FUNC(apple2gs_state::e1ram_w<0x0800>));
|
|
m_e0_0800bank[3](0xe00800, 0xe01fff).rw(FUNC(apple2gs_state::e1ram_r<0x0800>), FUNC(apple2gs_state::e1ram_w<0x0800>));
|
|
|
|
map(0xe02000, 0xe03fff).view(m_e0_2000bank);
|
|
m_e0_2000bank[0](0xe02000, 0xe03fff).rw(FUNC(apple2gs_state::e0ram_r<0x2000>), FUNC(apple2gs_state::e0ram_w<0x2000>));
|
|
m_e0_2000bank[1](0xe02000, 0xe03fff).rw(FUNC(apple2gs_state::e1ram_r<0x2000>), FUNC(apple2gs_state::e0ram_w<0x2000>));
|
|
m_e0_2000bank[2](0xe02000, 0xe03fff).rw(FUNC(apple2gs_state::e0ram_r<0x2000>), FUNC(apple2gs_state::e1ram_w<0x2000>));
|
|
m_e0_2000bank[3](0xe02000, 0xe03fff).rw(FUNC(apple2gs_state::e1ram_r<0x2000>), FUNC(apple2gs_state::e1ram_w<0x2000>));
|
|
|
|
map(0xe04000, 0xe0bfff).view(m_e0_4000bank);
|
|
m_e0_4000bank[0](0xe04000, 0xe0bfff).rw(FUNC(apple2gs_state::e0ram_r<0x4000>), FUNC(apple2gs_state::e0ram_w<0x4000>));
|
|
m_e0_4000bank[1](0xe04000, 0xe0bfff).rw(FUNC(apple2gs_state::e1ram_r<0x4000>), FUNC(apple2gs_state::e0ram_w<0x4000>));
|
|
m_e0_4000bank[2](0xe04000, 0xe0bfff).rw(FUNC(apple2gs_state::e0ram_r<0x4000>), FUNC(apple2gs_state::e1ram_w<0x4000>));
|
|
m_e0_4000bank[3](0xe04000, 0xe0bfff).rw(FUNC(apple2gs_state::e1ram_r<0x4000>), FUNC(apple2gs_state::e1ram_w<0x4000>));
|
|
|
|
map(0xe0c000, 0xe0c07f).rw(FUNC(apple2gs_state::c000_r), FUNC(apple2gs_state::c000_w));
|
|
map(0xe0c080, 0xe0c0ff).rw(FUNC(apple2gs_state::c080_r), FUNC(apple2gs_state::c080_w));
|
|
map(0xe0c100, 0xe0c2ff).rw(FUNC(apple2gs_state::c100_r), FUNC(apple2gs_state::c100_w));
|
|
map(0xe0c300, 0xe0c3ff).m(m_c300bank, FUNC(address_map_bank_device::amap8));
|
|
map(0xe0c400, 0xe0c7ff).rw(FUNC(apple2gs_state::c400_r), FUNC(apple2gs_state::c400_w));
|
|
map(0xe0c800, 0xe0cfff).rw(FUNC(apple2gs_state::c800_r), FUNC(apple2gs_state::c800_w));
|
|
|
|
map(0xe0d000, 0xe0ffff).view(m_upperbank);
|
|
m_upperbank[0](0xe0d000, 0xe0ffff).view(m_lcbank);
|
|
m_upperbank[1](0xe0d000, 0xe0ffff).rw(FUNC(apple2gs_state::inh_r), FUNC(apple2gs_state::inh_w));
|
|
|
|
m_lcbank[0](0xe0d000, 0xe0ffff).rom().region("maincpu", 0x3d000).w(FUNC(apple2gs_state::lc_w));
|
|
m_lcbank[1](0xe0d000, 0xe0ffff).rw(FUNC(apple2gs_state::lc_r), FUNC(apple2gs_state::lc_w));
|
|
|
|
map(0xe10000, 0xe1bfff).rw(FUNC(apple2gs_state::auxram0000_r), FUNC(apple2gs_state::auxram0000_w));
|
|
map(0xe1c000, 0xe1c07f).rw(FUNC(apple2gs_state::c000_r), FUNC(apple2gs_state::c000_w));
|
|
map(0xe1c080, 0xe1c0ff).rw(FUNC(apple2gs_state::c080_r), FUNC(apple2gs_state::c080_w));
|
|
map(0xe1c100, 0xe1c2ff).rw(FUNC(apple2gs_state::c100_r), FUNC(apple2gs_state::c100_w));
|
|
map(0xe1c300, 0xe1c3ff).m(m_c300bank, FUNC(address_map_bank_device::amap8));
|
|
map(0xe1c400, 0xe1c7ff).rw(FUNC(apple2gs_state::c400_r), FUNC(apple2gs_state::c400_w));
|
|
map(0xe1c800, 0xe1cfff).rw(FUNC(apple2gs_state::c800_r), FUNC(apple2gs_state::c800_w));
|
|
|
|
map(0xe1d000, 0xe1ffff).view(m_upperaux);
|
|
m_upperaux[0](0xe1d000, 0xe1ffff).view(m_lcaux);
|
|
m_upperaux[1](0xe1d000, 0xe1ffff).rw(FUNC(apple2gs_state::inh_r), FUNC(apple2gs_state::inh_w));
|
|
|
|
m_lcaux[0](0xe1d000, 0xe1ffff).rom().region("maincpu", 0x3d000).w(FUNC(apple2gs_state::lc_aux_w));
|
|
m_lcaux[1](0xe1d000, 0xe1ffff).rw(FUNC(apple2gs_state::lc_aux_r), FUNC(apple2gs_state::lc_aux_w));
|
|
|
|
map(0xfe0000, 0xffffff).rom().region("maincpu", 0x20000);
|
|
}
|
|
|
|
void apple2gs_state::vectors_map(address_map &map)
|
|
{
|
|
map(0x00, 0x1f).r(FUNC(apple2gs_state::apple2gs_read_vector));
|
|
}
|
|
|
|
void apple2gs_state::c300bank_map(address_map &map)
|
|
{
|
|
map(0x0000, 0x00ff).rw(FUNC(apple2gs_state::c300_r), FUNC(apple2gs_state::c300_w));
|
|
map(0x0100, 0x01ff).r(FUNC(apple2gs_state::c300_int_r)).nopw();
|
|
}
|
|
|
|
void apple2gs_state::a2gs_es5503_map(address_map &map)
|
|
{
|
|
map(0x00000, 0x0ffff).mirror(0x10000).readonly().share("docram"); // IIgs only has 64K, top bank mirrors lower bank
|
|
}
|
|
|
|
/***************************************************************************
|
|
ADB microcontroller + KEYGLU emulation
|
|
|
|
Huge thanks to Neil Parker's writeup on the ADB microcontroller!
|
|
http://llx.com/Neil/a2/adb.html
|
|
***************************************************************************/
|
|
|
|
u8 apple2gs_state::adbmicro_p0_in()
|
|
{
|
|
return m_glu_bus;
|
|
}
|
|
|
|
u8 apple2gs_state::adbmicro_p1_in()
|
|
{
|
|
if (!m_is_rom3)
|
|
{
|
|
return 0xff;
|
|
}
|
|
else
|
|
{
|
|
return 0x06;
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::adbmicro_p2_in()
|
|
{
|
|
u8 rv = 0;
|
|
|
|
if (!m_is_rom3)
|
|
{
|
|
rv |= 0x40; // no reset, must be 0 on ROM 3
|
|
}
|
|
rv |= (m_adb_line) ? 0x00 : 0x80;
|
|
|
|
return rv;
|
|
}
|
|
|
|
u8 apple2gs_state::adbmicro_p3_in()
|
|
{
|
|
if (m_is_rom3)
|
|
{
|
|
// Check the jumper to remove the Control Panel from the Control-Open Apple-Esc CDA menu
|
|
if (m_sysconfig->read() & 0x08)
|
|
{
|
|
return 0x40;
|
|
}
|
|
return 0x00;
|
|
}
|
|
else
|
|
{
|
|
return 0x07;
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::adbmicro_p0_out(u8 data)
|
|
{
|
|
m_glu_bus = data;
|
|
}
|
|
|
|
void apple2gs_state::adbmicro_p1_out(u8 data)
|
|
{
|
|
}
|
|
|
|
void apple2gs_state::adbmicro_p2_out(u8 data)
|
|
{
|
|
if (!BIT(data, 5) && BIT(m_adb_p2_last, 5))
|
|
{
|
|
m_adb_reset_freeze = 2;
|
|
m_a2bus->reset_bus();
|
|
m_maincpu->reset();
|
|
m_video->set_newvideo(0x41);
|
|
|
|
m_lcram = false;
|
|
m_lcram2 = true;
|
|
m_lcprewrite = false;
|
|
m_lcwriteenable = true;
|
|
m_intcxrom = false;
|
|
m_slotc3rom = false;
|
|
m_video->a80store_w(false);
|
|
m_altzp = false;
|
|
m_ramrd = false;
|
|
m_ramwrt = false;
|
|
m_altzp = false;
|
|
m_video->scr_w(0);
|
|
m_video->res_w(0);
|
|
m_irqmask = 0;
|
|
|
|
lcrom_update();
|
|
auxbank_update();
|
|
update_slotrom_banks();
|
|
}
|
|
|
|
if (!(data & 0x10))
|
|
{
|
|
if (m_adbmicro->are_port_bits_output(0, 0xff))
|
|
{
|
|
keyglu_mcu_write(data & 7, m_glu_bus);
|
|
}
|
|
else // read GLU
|
|
{
|
|
m_glu_bus = keyglu_mcu_read(data & 7);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_glu_kbd_y = data & 0xf;
|
|
}
|
|
|
|
m_adb_p2_last = data;
|
|
}
|
|
|
|
void apple2gs_state::adbmicro_p3_out(u8 data)
|
|
{
|
|
if (((data & 0x08) == 0x08) != m_adb_line)
|
|
{
|
|
m_adb_line = (data & 0x8) ? true : false;
|
|
m_macadb->adb_linechange_w(!m_adb_line);
|
|
}
|
|
|
|
if (m_adb_reset_freeze == 0)
|
|
{
|
|
m_adb_p3_last = data;
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::set_adb_line(int linestate)
|
|
{
|
|
m_adb_line = (linestate == CLEAR_LINE);
|
|
}
|
|
|
|
u8 apple2gs_state::keyglu_mcu_read(u8 offset)
|
|
{
|
|
u8 rv = m_glu_regs[offset];
|
|
|
|
// printf("MCU reads reg %x\n", offset);
|
|
|
|
// the command full flag is cleared by the MCU reading
|
|
// first the KGS register and then the command register
|
|
if ((offset == GLU_COMMAND) && (m_glu_mcu_read_kgs))
|
|
{
|
|
m_glu_regs[GLU_KG_STATUS] &= ~KGS_COMMAND_FULL;
|
|
m_glu_mcu_read_kgs = false;
|
|
}
|
|
|
|
// prime for the next command register read to clear the command full flag
|
|
if (offset == GLU_KG_STATUS)
|
|
{
|
|
m_glu_mcu_read_kgs = true;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
void apple2gs_state::keyglu_mcu_write(u8 offset, u8 data)
|
|
{
|
|
m_glu_regs[offset] = data;
|
|
|
|
switch (offset)
|
|
{
|
|
case GLU_KEY_DATA:
|
|
// if this is the first key pressed within a certain time frame, don't raise the strobe
|
|
// so that the emulated system doesn't see the keypress used to start the emulation.
|
|
if (m_sysconfig->read() & 0x01)
|
|
{ // bump the cycle count way up for a 16 Mhz ZipGS
|
|
if (m_maincpu->total_cycles() < 700000)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_maincpu->total_cycles() < 25000)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
m_glu_regs[GLU_KG_STATUS] |= KGS_KEYSTROBE;
|
|
m_glu_regs[GLU_SYSSTAT] |= GLU_STATUS_KEYDATIRQ;
|
|
keyglu_regen_irqs();
|
|
break;
|
|
|
|
case GLU_MOUSEX:
|
|
m_glu_regs[GLU_KG_STATUS] |= KGS_MOUSEX_FULL;
|
|
m_glu_regs[GLU_SYSSTAT] |= GLU_STATUS_MOUSEIRQ;
|
|
keyglu_regen_irqs();
|
|
m_glu_mouse_read_stat = false; // signal next read will be mouse X
|
|
break;
|
|
|
|
case GLU_MOUSEY:
|
|
break;
|
|
|
|
case GLU_ANY_KEY_DOWN: // bit 7 is the actual flag here
|
|
if (data & 0x80)
|
|
{
|
|
m_glu_regs[GLU_KG_STATUS] |= KGS_ANY_KEY_DOWN;
|
|
}
|
|
break;
|
|
|
|
case GLU_DATA:
|
|
m_glu_regs[GLU_DATA] = data;
|
|
m_glu_regs[GLU_KG_STATUS] |= KGS_DATA_FULL;
|
|
m_glu_regs[GLU_SYSSTAT] |= GLU_STATUS_DATAIRQ;
|
|
keyglu_regen_irqs();
|
|
m_glu_816_read_dstat = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Keyglu registers map as follows on the 816:
|
|
|
|
C000 = key data + any key down, clears strobe
|
|
C010 = clears keystrobe
|
|
C024 MOUSEDATA = reads GLU mouseX and mouseY
|
|
C025 KEYMODREG = reads GLU keymod register
|
|
C026 DATAREG = writes from the 816 go to COMMAND, reads from DATA
|
|
C027 KMSTATUS = GLU system status register
|
|
*/
|
|
|
|
u8 apple2gs_state::keyglu_816_read(u8 offset)
|
|
{
|
|
switch (offset)
|
|
{
|
|
case GLU_C000:
|
|
if (m_glu_regs[GLU_KG_STATUS] & KGS_KEYSTROBE)
|
|
{
|
|
return m_glu_regs[GLU_KEY_DATA] | 0x80;
|
|
}
|
|
return m_glu_regs[GLU_KEY_DATA];
|
|
|
|
case GLU_C010:
|
|
return (m_glu_regs[GLU_ANY_KEY_DOWN] & 0x80);
|
|
|
|
case GLU_KEYMOD:
|
|
return m_glu_regs[GLU_KEYMOD];
|
|
|
|
case GLU_MOUSEX:
|
|
case GLU_MOUSEY:
|
|
if (!m_glu_mouse_read_stat)
|
|
{
|
|
if (!machine().side_effects_disabled())
|
|
m_glu_mouse_read_stat = true;
|
|
return m_glu_regs[GLU_MOUSEX];
|
|
}
|
|
if (!machine().side_effects_disabled())
|
|
{
|
|
m_glu_mouse_read_stat = false;
|
|
m_glu_regs[GLU_KG_STATUS] &= ~KGS_MOUSEX_FULL;
|
|
m_glu_regs[GLU_SYSSTAT] &= ~GLU_STATUS_MOUSEIRQ;
|
|
keyglu_regen_irqs();
|
|
}
|
|
return m_glu_regs[GLU_MOUSEY];
|
|
|
|
case GLU_SYSSTAT:
|
|
{
|
|
// regenerate sysstat bits
|
|
u8 sysstat = m_glu_regs[GLU_SYSSTAT] & ~0xab;
|
|
if (m_glu_regs[GLU_KG_STATUS] & KGS_COMMAND_FULL)
|
|
{
|
|
sysstat |= GLU_STATUS_CMDFULL;
|
|
}
|
|
if (m_glu_mouse_read_stat)
|
|
{
|
|
sysstat |= GLU_STATUS_MOUSEXY;
|
|
}
|
|
if (m_glu_regs[GLU_KG_STATUS] & KGS_KEYSTROBE)
|
|
{
|
|
sysstat |= GLU_STATUS_KEYDATIRQ;
|
|
}
|
|
if (m_glu_regs[GLU_KG_STATUS] & KGS_DATA_FULL)
|
|
{
|
|
sysstat |= GLU_STATUS_DATAIRQ;
|
|
}
|
|
if (m_glu_regs[GLU_KG_STATUS] & KGS_MOUSEX_FULL)
|
|
{
|
|
sysstat |= GLU_STATUS_MOUSEIRQ;
|
|
}
|
|
if (!machine().side_effects_disabled())
|
|
m_glu_816_read_dstat = true;
|
|
//printf("Read SYSSTAT %02x (PC=%x)\n", sysstat, m_maincpu->pc());
|
|
return sysstat;
|
|
}
|
|
|
|
case GLU_DATA:
|
|
if (m_glu_816_read_dstat && !machine().side_effects_disabled())
|
|
{
|
|
m_glu_816_read_dstat = false;
|
|
m_glu_regs[GLU_KG_STATUS] &= ~KGS_DATA_FULL;
|
|
keyglu_regen_irqs();
|
|
}
|
|
return m_glu_regs[GLU_DATA];
|
|
|
|
default:
|
|
return 0xff;
|
|
break;
|
|
}
|
|
|
|
return 0xff;
|
|
}
|
|
|
|
void apple2gs_state::keyglu_816_write(u8 offset, u8 data)
|
|
{
|
|
if (offset < GLU_C000)
|
|
{
|
|
m_glu_regs[offset&7] = data;
|
|
}
|
|
|
|
switch (offset)
|
|
{
|
|
case GLU_C010:
|
|
m_glu_regs[GLU_SYSSTAT] &= ~GLU_STATUS_KEYDATIRQ;
|
|
m_glu_regs[GLU_KG_STATUS] &= ~KGS_KEYSTROBE;
|
|
keyglu_regen_irqs();
|
|
break;
|
|
|
|
case GLU_COMMAND:
|
|
m_glu_regs[GLU_KG_STATUS] |= KGS_COMMAND_FULL;
|
|
break;
|
|
|
|
case GLU_SYSSTAT:
|
|
m_glu_regs[GLU_SYSSTAT] &= 0xab; // clear the non-read-only fields
|
|
m_glu_regs[GLU_SYSSTAT] |= (data & ~0xab);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::keyglu_regen_irqs()
|
|
{
|
|
bool bIRQ = false;
|
|
|
|
if ((m_glu_regs[GLU_KG_STATUS] & KGS_DATA_FULL) && (m_glu_regs[GLU_SYSSTAT] & GLU_STATUS_DATAIRQEN))
|
|
{
|
|
bIRQ = true;
|
|
}
|
|
|
|
if ((m_glu_regs[GLU_KG_STATUS] & KGS_KEYSTROBE) && (m_glu_regs[GLU_SYSSTAT] & GLU_STATUS_KEYDATIRQEN))
|
|
{
|
|
bIRQ = true;
|
|
}
|
|
|
|
if ((m_glu_regs[GLU_KG_STATUS] & KGS_MOUSEX_FULL) && (m_glu_regs[GLU_SYSSTAT] & GLU_STATUS_MOUSEIRQEN))
|
|
{
|
|
bIRQ = true;
|
|
}
|
|
|
|
if (bIRQ)
|
|
{
|
|
raise_irq(IRQS_ADB);
|
|
}
|
|
else
|
|
{
|
|
lower_irq(IRQS_ADB);
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::scc_irq_w(int state)
|
|
{
|
|
if (state)
|
|
{
|
|
raise_irq(IRQS_SCC);
|
|
}
|
|
else
|
|
{
|
|
lower_irq(IRQS_SCC);
|
|
}
|
|
}
|
|
|
|
/* Sound - DOC */
|
|
void apple2gs_state::doc_irq_w(int state)
|
|
{
|
|
if (state)
|
|
{
|
|
raise_irq(IRQS_DOC);
|
|
}
|
|
else
|
|
{
|
|
lower_irq(IRQS_DOC);
|
|
}
|
|
}
|
|
|
|
u8 apple2gs_state::doc_adc_read()
|
|
{
|
|
return 0x80;
|
|
}
|
|
|
|
void apple2gs_state::phases_w(uint8_t phases)
|
|
{
|
|
if (m_cur_floppy)
|
|
{
|
|
m_cur_floppy->seek_phase_w(phases);
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::devsel_w(uint8_t devsel)
|
|
{
|
|
m_devsel = devsel;
|
|
if (m_devsel == 1)
|
|
{
|
|
if (!BIT(m_diskreg, DISKREG_35SEL))
|
|
{
|
|
m_cur_floppy = m_floppy[0]->get_device();
|
|
}
|
|
else
|
|
{
|
|
m_cur_floppy = m_floppy[2]->get_device();
|
|
m_motoroff_time = 0;
|
|
}
|
|
}
|
|
else if (m_devsel == 2)
|
|
{
|
|
if (!BIT(m_diskreg, DISKREG_35SEL))
|
|
{
|
|
m_cur_floppy = m_floppy[1]->get_device();
|
|
}
|
|
else
|
|
{
|
|
m_cur_floppy = m_floppy[3]->get_device();
|
|
m_motoroff_time = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_cur_floppy = nullptr;
|
|
}
|
|
m_iwm->set_floppy(m_cur_floppy);
|
|
|
|
if ((m_cur_floppy) && (BIT(m_diskreg, DISKREG_35SEL)))
|
|
{
|
|
m_cur_floppy->ss_w(BIT(m_diskreg, DISKREG_HDSEL));
|
|
}
|
|
}
|
|
|
|
void apple2gs_state::sel35_w(int sel35)
|
|
{
|
|
}
|
|
|
|
/***************************************************************************
|
|
INPUT PORTS
|
|
***************************************************************************/
|
|
|
|
INPUT_PORTS_START( apple2gs )
|
|
PORT_START("a2_config")
|
|
PORT_CONFNAME(0x07, 0x00, "CPU type")
|
|
PORT_CONFSETTING(0x00, "Standard")
|
|
PORT_CONFSETTING(0x01, "7 MHz ZipGS")
|
|
PORT_CONFSETTING(0x03, "8 MHz ZipGS")
|
|
PORT_CONFSETTING(0x05, "12 MHz ZipGS")
|
|
PORT_CONFSETTING(0x07, "16 MHz ZipGS")
|
|
INPUT_PORTS_END
|
|
|
|
INPUT_PORTS_START( apple2gsrom3 )
|
|
PORT_INCLUDE( apple2gs )
|
|
|
|
PORT_MODIFY("a2_config")
|
|
PORT_CONFNAME(0x08, 0x00, "Disable CDA Control Panel")
|
|
PORT_CONFSETTING(0x00, DEF_STR(No))
|
|
PORT_CONFSETTING(0x08, DEF_STR(Yes))
|
|
INPUT_PORTS_END
|
|
|
|
void apple2gs_state::apple2gs(machine_config &config)
|
|
{
|
|
/* basic machine hardware */
|
|
G65816(config, m_maincpu, A2GS_2_8M);
|
|
m_maincpu->set_addrmap(AS_PROGRAM, &apple2gs_state::apple2gs_map);
|
|
m_maincpu->set_addrmap(g65816_device::AS_VECTORS, &apple2gs_state::vectors_map);
|
|
m_maincpu->set_dasm_override(FUNC(apple2gs_state::dasm_trampoline));
|
|
m_maincpu->wdm_handler().set(FUNC(apple2gs_state::wdm_trampoline));
|
|
TIMER(config, m_scantimer, 0).configure_generic(FUNC(apple2gs_state::apple2_interrupt));
|
|
TIMER(config, m_vgctimer, 0).configure_generic(FUNC(apple2gs_state::apple2_vgc));
|
|
TIMER(config, m_acceltimer, 0).configure_generic(FUNC(apple2gs_state::accel_timer));
|
|
|
|
config.set_maximum_quantum(attotime::from_hz(60));
|
|
|
|
M50741(config, m_adbmicro, A2GS_MASTER_CLOCK/8);
|
|
m_adbmicro->set_pullups<2>(0x20);
|
|
m_adbmicro->read_p<0>().set(FUNC(apple2gs_state::adbmicro_p0_in));
|
|
m_adbmicro->write_p<0>().set(FUNC(apple2gs_state::adbmicro_p0_out));
|
|
m_adbmicro->read_p<1>().set(FUNC(apple2gs_state::adbmicro_p1_in));
|
|
m_adbmicro->write_p<1>().set(FUNC(apple2gs_state::adbmicro_p1_out));
|
|
m_adbmicro->read_p<2>().set(FUNC(apple2gs_state::adbmicro_p2_in));
|
|
m_adbmicro->write_p<2>().set(FUNC(apple2gs_state::adbmicro_p2_out));
|
|
m_adbmicro->read_p<3>().set(FUNC(apple2gs_state::adbmicro_p3_in));
|
|
m_adbmicro->write_p<3>().set(FUNC(apple2gs_state::adbmicro_p3_out));
|
|
|
|
MACADB(config, m_macadb, A2GS_MASTER_CLOCK/8);
|
|
m_macadb->adb_data_callback().set(FUNC(apple2gs_state::set_adb_line));
|
|
|
|
RTC3430042(config, m_rtc, XTAL(32'768));
|
|
m_rtc->cko_cb().set(FUNC(apple2gs_state::rtc_vgc));
|
|
|
|
APPLE2_VIDEO(config, m_video, A2GS_14M).set_screen(m_screen);
|
|
m_video->set_base_model(a2_video_device::model::IIGS);
|
|
|
|
APPLE2_COMMON(config, m_a2common, A2GS_14M).set_GS_cputag(m_maincpu);
|
|
|
|
// APPLE2_HOST(config, m_a2host, A2GS_14M);
|
|
// m_a2host->set_cputag(m_maincpu);
|
|
// m_a2host->set_space(m_maincpu, AS_PROGRAM);
|
|
|
|
APPLE2_GAMEIO(config, m_gameio, apple2_gameio_device::default_options, nullptr);
|
|
|
|
// HBL is positioned to the right of active video here, but to the left on hardware.
|
|
// the borders are counted as active video here, but as HBL on hardware.
|
|
// these must be compensated for in any use of hpos/vpos/hblank/vblank.
|
|
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
|
m_screen->set_raw(A2GS_1M.value() * 16, 65 * 16, 0, BORDER_LEFT + 40 * 16 + BORDER_RIGHT, 262, 0, 231);
|
|
m_screen->set_screen_update(m_video, NAME((&a2_video_device::screen_update_GS)));
|
|
|
|
PALETTE(config, "palette", FUNC(apple2gs_state::palette_init), 256);
|
|
|
|
/* sound hardware */
|
|
SPEAKER(config, "a2speaker").front_center();
|
|
SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "a2speaker", 1.00);
|
|
|
|
SPEAKER(config, "ensoniq", 4).corners();
|
|
ES5503(config, m_doc, A2GS_7M);
|
|
m_doc->set_channels(4);
|
|
m_doc->set_addrmap(0, &apple2gs_state::a2gs_es5503_map);
|
|
m_doc->irq_func().set(FUNC(apple2gs_state::doc_irq_w));
|
|
m_doc->adc_func().set(FUNC(apple2gs_state::doc_adc_read));
|
|
m_doc->add_route(0, "ensoniq", 1.0, 0);
|
|
m_doc->add_route(1, "ensoniq", 1.0, 1);
|
|
m_doc->add_route(2, "ensoniq", 1.0, 2);
|
|
m_doc->add_route(3, "ensoniq", 1.0, 3);
|
|
|
|
/* RAM */
|
|
RAM(config, m_ram).set_default_size("2M").set_extra_options("1M,3M,4M,5M,6M,7M,8M").set_default_value(0x00);
|
|
|
|
/* C300 banking */
|
|
ADDRESS_MAP_BANK(config, A2GS_C300_TAG).set_map(&apple2gs_state::c300bank_map).set_options(ENDIANNESS_LITTLE, 8, 32, 0x100);
|
|
|
|
/* serial */
|
|
SCC85C30(config, m_scc, A2GS_7M);
|
|
m_scc->configure_channels(3'686'400, 3'686'400, 3'686'400, 3'686'400);
|
|
m_scc->out_int_callback().set(FUNC(apple2gs_state::scc_irq_w));
|
|
m_scc->out_txda_callback().set("printer", FUNC(rs232_port_device::write_txd));
|
|
m_scc->out_txdb_callback().set("modem", FUNC(rs232_port_device::write_txd));
|
|
|
|
rs232_port_device &rs232a(RS232_PORT(config, "printer", default_rs232_devices, nullptr));
|
|
rs232a.rxd_handler().set(m_scc, FUNC(z80scc_device::rxa_w));
|
|
rs232a.dcd_handler().set(m_scc, FUNC(z80scc_device::dcda_w));
|
|
rs232a.cts_handler().set(m_scc, FUNC(z80scc_device::ctsa_w));
|
|
|
|
rs232_port_device &rs232b(RS232_PORT(config, "modem", default_rs232_devices, nullptr));
|
|
rs232b.rxd_handler().set(m_scc, FUNC(z80scc_device::rxb_w));
|
|
rs232b.dcd_handler().set(m_scc, FUNC(z80scc_device::dcdb_w));
|
|
rs232b.cts_handler().set(m_scc, FUNC(z80scc_device::ctsb_w));
|
|
|
|
/* slot devices */
|
|
A2BUS(config, m_a2bus, 0);
|
|
m_a2bus->set_space(m_maincpu, AS_PROGRAM);
|
|
m_a2bus->irq_w().set(FUNC(apple2gs_state::a2bus_irq_w));
|
|
m_a2bus->nmi_w().set(FUNC(apple2gs_state::a2bus_nmi_w));
|
|
m_a2bus->inh_w().set(FUNC(apple2gs_state::a2bus_inh_w));
|
|
m_a2bus->dma_w().set_inputline(m_maincpu, INPUT_LINE_HALT);
|
|
A2BUS_SLOT(config, "sl1", A2GS_7M, m_a2bus, apple2gs_cards, nullptr);
|
|
A2BUS_SLOT(config, "sl2", A2GS_7M, m_a2bus, apple2gs_cards, nullptr);
|
|
A2BUS_SLOT(config, "sl3", A2GS_7M, m_a2bus, apple2gs_cards, nullptr);
|
|
A2BUS_SLOT(config, "sl4", A2GS_7M, m_a2bus, apple2gs_cards, nullptr);
|
|
A2BUS_SLOT(config, "sl5", A2GS_7M, m_a2bus, apple2gs_cards, nullptr);
|
|
A2BUS_SLOT(config, "sl6", A2GS_7M, m_a2bus, apple2gs_cards, nullptr);
|
|
A2BUS_SLOT(config, "sl7", A2GS_7M, m_a2bus, apple2gs_cards, nullptr);
|
|
|
|
IWM(config, m_iwm, A2GS_7M, A2GS_1M*2);
|
|
m_iwm->phases_cb().set(FUNC(apple2gs_state::phases_w));
|
|
m_iwm->sel35_cb().set(FUNC(apple2gs_state::sel35_w));
|
|
m_iwm->devsel_cb().set(FUNC(apple2gs_state::devsel_w));
|
|
|
|
applefdintf_device::add_525(config, m_floppy[0]);
|
|
applefdintf_device::add_525(config, m_floppy[1]);
|
|
applefdintf_device::add_35(config, m_floppy[2]);
|
|
applefdintf_device::add_35(config, m_floppy[3]);
|
|
|
|
SOFTWARE_LIST(config, "flop_gs_clean").set_original("apple2gs_flop_clcracked"); // GS-specific cleanly cracked disks
|
|
SOFTWARE_LIST(config, "flop_gs_orig").set_compatible("apple2gs_flop_orig"); // Original disks for GS
|
|
SOFTWARE_LIST(config, "flop_gs_misc").set_compatible("apple2gs_flop_misc"); // Legacy software list pre-June 2021 and defaced cracks
|
|
SOFTWARE_LIST(config, "flop_a2_clean").set_compatible("apple2_flop_clcracked"); // Apple II series cleanly cracked
|
|
SOFTWARE_LIST(config, "flop_a2_orig").set_compatible("apple2_flop_orig").set_filter("A2GS"); // Filter list to compatible disks for this machine.
|
|
SOFTWARE_LIST(config, "flop_a2_misc").set_compatible("apple2_flop_misc");
|
|
}
|
|
|
|
void apple2gs_state::apple2gsr1(machine_config &config)
|
|
{
|
|
apple2gs(config);
|
|
|
|
// 256K on board + 1M in the expansion slot was common for ROM 01
|
|
m_ram->set_default_size("1280K").set_extra_options("256K,512K,768K,1M,2M,3M,4M,5M,6M,7M,8M").set_default_value(0x00);
|
|
|
|
M50740(config.replace(), m_adbmicro, A2GS_MASTER_CLOCK/8);
|
|
m_adbmicro->set_pullups<2>(0x20);
|
|
m_adbmicro->read_p<0>().set(FUNC(apple2gs_state::adbmicro_p0_in));
|
|
m_adbmicro->write_p<0>().set(FUNC(apple2gs_state::adbmicro_p0_out));
|
|
m_adbmicro->read_p<1>().set(FUNC(apple2gs_state::adbmicro_p1_in));
|
|
m_adbmicro->write_p<1>().set(FUNC(apple2gs_state::adbmicro_p1_out));
|
|
m_adbmicro->read_p<2>().set(FUNC(apple2gs_state::adbmicro_p2_in));
|
|
m_adbmicro->write_p<2>().set(FUNC(apple2gs_state::adbmicro_p2_out));
|
|
m_adbmicro->read_p<3>().set(FUNC(apple2gs_state::adbmicro_p3_in));
|
|
m_adbmicro->write_p<3>().set(FUNC(apple2gs_state::adbmicro_p3_out));
|
|
}
|
|
|
|
void apple2gs_state::apple2gsmt(machine_config &config)
|
|
{
|
|
apple2gs(config);
|
|
|
|
// SWIM1 344S0061 confirmed on two different Mark Twain boards, with 15.6672 MHz oscillator
|
|
SWIM1(config.replace(), m_iwm, 15.6672_MHz_XTAL);
|
|
m_iwm->phases_cb().set(FUNC(apple2gs_state::phases_w));
|
|
m_iwm->sel35_cb().set(FUNC(apple2gs_state::sel35_w));
|
|
m_iwm->devsel_cb().set(FUNC(apple2gs_state::devsel_w));
|
|
|
|
applefdintf_device::add_525(config, m_floppy[0]);
|
|
applefdintf_device::add_525(config, m_floppy[1]);
|
|
applefdintf_device::add_35_hd(config, m_floppy[2]);
|
|
applefdintf_device::add_35_hd(config, m_floppy[3]);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
Game driver(s)
|
|
|
|
***************************************************************************/
|
|
ROM_START(apple2gs)
|
|
// M50740/50741 ADB MCU inside the IIgs system unit
|
|
ROM_REGION(0x1000, "adbmicro", 0)
|
|
ROM_LOAD( "341s0632-2.bin", 0x000000, 0x001000, CRC(e1c11fb0) SHA1(141d18c36a617ab9dce668445440d34354be0672) )
|
|
|
|
ROM_REGION(0x4000,"gfx1",0)
|
|
ROM_LOAD("344s0047.bin", 0x000000, 0x004000, CRC(2d541944) SHA1(5a5a77c8ec45632aea1a57cd9c9257f7f6e44668)) /* Mega II: 344S0047. Dumped from the test registers, verified identical on both ROM 1 and 3 */
|
|
|
|
ROM_REGION(0x80000,"maincpu",0)
|
|
// 341-0728 is the MASK rom version while 341-0737 is the EPROM version - SAME data.
|
|
ROM_LOAD("341-0728", 0x00000, 0x20000, CRC(8d410067) SHA1(c0f4704233ead14cb8e1e8a68fbd7063c56afd27) ) /* 341-0728: IIgs ROM03 FC-FD */
|
|
// 341-0748 is the MASK rom version while 341-0749 is the EPROM version - SAME data.
|
|
ROM_LOAD("341-0748", 0x30000, 0x10000, CRC(18190283) SHA1(c70576869deec92ca82c78438b1d5c686eac7480) ) /* 341-0748: IIgs ROM03 FE-FF */
|
|
ROM_CONTINUE ( 0x20000, 0x10000) /* high address line is inverted on PCB? */
|
|
ROM_END
|
|
|
|
ROM_START(apple2gsr3p)
|
|
ROM_REGION(0x1000, "adbmicro", 0)
|
|
ROM_LOAD( "341s0632-2.bin", 0x000000, 0x001000, CRC(e1c11fb0) SHA1(141d18c36a617ab9dce668445440d34354be0672) )
|
|
|
|
ROM_REGION(0x4000,"gfx1",0)
|
|
ROM_LOAD("344s0047.bin", 0x000000, 0x004000, CRC(2d541944) SHA1(5a5a77c8ec45632aea1a57cd9c9257f7f6e44668)) /* Mega II: 344S0047. Dumped from the test registers, verified identical on both ROM 1 and 3 */
|
|
|
|
ROM_REGION(0x80000,"maincpu",0)
|
|
ROM_LOAD("341-0728", 0x00000, 0x20000, CRC(8d410067) SHA1(c0f4704233ead14cb8e1e8a68fbd7063c56afd27) ) /* 341-0728: IIgs ROM03 prototype FC-FD - 28 pin MASK rom */
|
|
ROM_LOAD("341-0729", 0x20000, 0x20000, NO_DUMP) /* 341-0729: IIgs ROM03 prototype FE-FF */
|
|
ROM_END
|
|
|
|
ROM_START(apple2gsr1)
|
|
ROM_REGION(0xc00, "adbmicro", 0)
|
|
ROM_LOAD( "341s0345.bin", 0x000000, 0x000c00, CRC(48cd5779) SHA1(97e421f5247c00a0ca34cd08b6209df573101480) )
|
|
|
|
ROM_REGION(0x4000,"gfx1",0)
|
|
ROM_LOAD("344s0047.bin", 0x000000, 0x004000, CRC(2d541944) SHA1(5a5a77c8ec45632aea1a57cd9c9257f7f6e44668)) /* Mega II: 344S0047. Dumped from the test registers, verified identical on both ROM 1 and 3 */
|
|
|
|
ROM_REGION(0x80000,"maincpu",0)
|
|
ROM_LOAD("342-0077-b", 0x20000, 0x20000, CRC(42f124b0) SHA1(e4fc7560b69d062cb2da5b1ffbe11cd1ca03cc37)) /* 342-0077-B: IIgs ROM01 */
|
|
ROM_END
|
|
|
|
ROM_START(apple2gsr0)
|
|
ROM_REGION(0xc00, "adbmicro", 0)
|
|
ROM_LOAD( "341s0345.bin", 0x000000, 0x000c00, CRC(48cd5779) SHA1(97e421f5247c00a0ca34cd08b6209df573101480) )
|
|
|
|
ROM_REGION(0x4000,"gfx1",0)
|
|
ROM_LOAD("344s0047.bin", 0x000000, 0x004000, CRC(2d541944) SHA1(5a5a77c8ec45632aea1a57cd9c9257f7f6e44668)) /* Mega II: 344S0047. Dumped from the test registers, verified identical on both ROM 1 and 3 */
|
|
|
|
ROM_REGION(0x80000,"maincpu",0)
|
|
ROM_LOAD("342-0077-a", 0x20000, 0x20000, CRC(dfbdd97b) SHA1(ff0c245dd0732ec4413a934fd80efc2defd8a8e3) ) /* 342-0077-A: IIgs ROM00 */
|
|
ROM_END
|
|
|
|
ROM_START(apple2gsr0p) // 6/19/1986 Cortland prototype
|
|
ROM_REGION(0xc00, "adbmicro", 0)
|
|
ROM_LOAD( "341s0345.bin", 0x000000, 0x000c00, CRC(48cd5779) SHA1(97e421f5247c00a0ca34cd08b6209df573101480) )
|
|
|
|
ROM_REGION(0x4000,"gfx1",0)
|
|
ROM_LOAD("344s0047.bin", 0x000000, 0x004000, CRC(2d541944) SHA1(5a5a77c8ec45632aea1a57cd9c9257f7f6e44668)) /* Mega II: 344S0047. Dumped from the test registers, verified identical on both ROM 1 and 3 */
|
|
|
|
ROM_REGION(0x80000,"maincpu",0)
|
|
ROM_LOAD( "rombf.bin", 0x020000, 0x020000, CRC(ab04fedf) SHA1(977589a17553956d583a21020080a39dd396df5c) )
|
|
ROM_END
|
|
|
|
ROM_START(apple2gsr0p2) // 3/10/1986 Cortland prototype, boots as "Apple //'ing - Alpha 2.0"
|
|
ROM_REGION(0xc00, "adbmicro", 0)
|
|
ROM_LOAD( "341s0345.bin", 0x000000, 0x000c00, CRC(48cd5779) SHA1(97e421f5247c00a0ca34cd08b6209df573101480) )
|
|
|
|
ROM_REGION(0x4000,"gfx1",0)
|
|
ROM_LOAD("344s0047.bin", 0x000000, 0x004000, CRC(2d541944) SHA1(5a5a77c8ec45632aea1a57cd9c9257f7f6e44668)) /* Mega II: 344S0047. Dumped from the test registers, verified identical on both ROM 1 and 3 */
|
|
|
|
ROM_REGION(0x80000,"maincpu",0)
|
|
ROM_LOAD( "apple iigs alpha rom 2.0 19860310.bin", 0x020000, 0x020000, CRC(a47d275f) SHA1(c5836adcfc8be69c7351b84afa94c814e8d92b81) )
|
|
ROM_END
|
|
|
|
ROM_START(apple2gsmt)
|
|
// 50741 ADB MCU inside the IIgs system unit
|
|
ROM_REGION(0x1000, "adbmicro", 0)
|
|
ROM_LOAD( "341s0632-2.bin", 0x000000, 0x001000, CRC(e1c11fb0) SHA1(141d18c36a617ab9dce668445440d34354be0672) )
|
|
|
|
ROM_REGION(0x4000, "gfx1", 0)
|
|
ROM_LOAD("344s0047.bin", 0x000000, 0x004000, CRC(2d541944) SHA1(5a5a77c8ec45632aea1a57cd9c9257f7f6e44668)) /* Mega II: 344S0047. Dumped from the test registers, verified identical on both ROM 1 and 3 */
|
|
|
|
ROM_REGION(0x80000, "maincpu", 0)
|
|
// The Mark Twain ROM is 512K, with address bit 16 inverted (same as ROM 3).
|
|
// The first 256K is filled with 64K of 0xF0, then 0xF1, 0xF2, and 0xF3. I'm guessing this was meant to be
|
|
// a small ROM disk at $F00000, like the Mac Classic has. The second 256K is the firmware we all know from
|
|
// the "System 6.0.1" source leak.
|
|
ROM_LOAD( "mtrom.bin", 0x040000, 0x040000, CRC(d75414c5) SHA1(7054915f5e5f9f3bb2cbecf6830d4f80793694a6) )
|
|
ROM_CONTINUE(0x10000, 0x10000)
|
|
ROM_CONTINUE(0x00000, 0x10000)
|
|
ROM_CONTINUE(0x30000, 0x10000)
|
|
ROM_CONTINUE(0x20000, 0x10000)
|
|
|
|
// The firmware for the built-in High-Speed SCSI Card
|
|
ROM_REGION(0x8000, "hsscsi", 0)
|
|
ROM_LOAD( "mtscsi.bin", 0x000000, 0x008000, CRC(7426c880) SHA1(1c16310e5c180701a05089d69c6e72e9dc7434f6) )
|
|
ROM_END
|
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */
|
|
COMP( 1989, apple2gs, 0, apple2, apple2gs, apple2gsrom3, apple2gs_state, rom3_init, "Apple Computer", "Apple IIgs (ROM03)", MACHINE_SUPPORTS_SAVE )
|
|
COMP( 198?, apple2gsr3p, apple2gs, 0, apple2gs, apple2gsrom3, apple2gs_state, rom3_init, "Apple Computer", "Apple IIgs (ROM03 prototype)", MACHINE_NOT_WORKING )
|
|
COMP( 1987, apple2gsr1, apple2gs, 0, apple2gsr1, apple2gs, apple2gs_state, rom1_init, "Apple Computer", "Apple IIgs (ROM01)", MACHINE_SUPPORTS_SAVE )
|
|
COMP( 1986, apple2gsr0, apple2gs, 0, apple2gsr1, apple2gs, apple2gs_state, rom1_init, "Apple Computer", "Apple IIgs (ROM00)", MACHINE_SUPPORTS_SAVE )
|
|
COMP( 1986, apple2gsr0p, apple2gs, 0, apple2gsr1, apple2gs, apple2gs_state, rom1_init, "Apple Computer", "Apple IIgs (ROM00 prototype 6/19/1986)", MACHINE_SUPPORTS_SAVE )
|
|
COMP( 1986, apple2gsr0p2, apple2gs, 0, apple2gsr1, apple2gs, apple2gs_state, rom1_init, "Apple Computer", "Apple IIgs (ROM00 prototype 3/10/1986)", MACHINE_SUPPORTS_SAVE )
|
|
COMP( 1991, apple2gsmt, apple2gs, 0, apple2gsmt, apple2gsrom3, apple2gs_state, rom3_init, "Apple Computer", "Apple IIgs (1991 Mark Twain prototype)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE )
|