// 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 Timing in terms of the 14M 14.3181818 MHz clock (1/2 of the 28.6363636 master clock): - 1 65816 cycle is 5 14M clocks - 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) * Accesses to banks 00-7F are penalized except for I/O in banks 0/1. - 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). One video line is: 6 cycles of right border, 13 cycles of hblank, 6 cycles of left border, and 40 cycles of active video 640 + 96 + 96 = 832 (make borders each 38 pixels wider in A2 modes) 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 (reverse logic: 0 = delay is ON) 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 "video/apple2.h" #define RUN_ADB_MICRO (0) // use the ADB microcontroller for keyboard/mouse input #define ADB_HLE (0) // connect the ADB microcontroller to the macadb.cpp ADB bit-serial keyboard+mouse #define LOG_ADB (0) // log ADB activity in the old-style HLE simulation of the microcontroller and GLU #include "machine/apple2common.h" //#include "machine/apple2host.h" #include "machine/macadb.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/kb3600.h" #include "machine/nvram.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 "screen.h" #include "softlist_dev.h" #include "speaker.h" #include "formats/ap_dsk35.h" #include "formats/ap2_dsk.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_1M (A2GS_MASTER_CLOCK/28) #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_acceltimer(*this, "acceltimer"), m_adbmicro(*this, "adbmicro"), #if ADB_HLE m_macadb(*this, "macadb"), #endif m_ram(*this, "ram"), m_rom(*this, "maincpu"), m_docram(*this, "docram"), m_nvram(*this, "nvram"), m_video(*this, "a2video"), m_a2bus(*this, "a2bus"), m_a2common(*this, "a2common"), // m_a2host(*this, "a2host"), m_gameio(*this, "gameio"), m_speaker(*this, "speaker"), 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_0400bank(*this, "e0_0400_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_kbd(*this, "Y%d", 0), m_kbspecial(*this, A2GS_KBD_SPEC_TAG), m_sysconfig(*this, "a2_config"), m_ay3600(*this, "ay3600"), m_kbdrom(*this, "keyboard"), m_adb_mousex(*this, "adb_mouse_x"), m_adb_mousey(*this, "adb_mouse_y") { m_cur_floppy = nullptr; m_devsel = 0; m_diskreg = 0; } void apple2gs(machine_config &config); void apple2gsr1(machine_config &config); void rom1_init() { m_is_rom3 = false; } void rom3_init() { m_is_rom3 = true; } protected: virtual void machine_start() override; virtual void machine_reset() override; private: required_device m_maincpu; required_device m_screen; required_device m_scantimer, m_acceltimer; required_device m_adbmicro; #if ADB_HLE required_device m_macadb; #endif required_device m_ram; required_region_ptr m_rom; required_shared_ptr m_docram; required_device m_nvram; required_device m_video; required_device m_a2bus; required_device m_a2common; // required_device m_a2host; required_device m_gameio; required_device m_speaker; memory_view m_upperbank, m_upperaux, m_upper00, m_upper01; required_device m_c300bank; memory_view m_b0_0000bank, m_b0_0200bank, m_b0_0400bank, m_b0_0800bank, m_b0_2000bank, m_b0_4000bank, m_e0_0400bank; memory_view m_lcbank, m_lcaux, m_lc00, m_lc01, m_bank0_atc, m_bank1_atc; required_device m_scc; required_device m_doc; required_device m_iwm; required_device_array m_floppy; optional_ioport_array<10> m_kbd; optional_ioport m_kbspecial; required_ioport m_sysconfig; optional_device m_ay3600; required_memory_region m_kbdrom; optional_ioport m_adb_mousex, m_adb_mousey; 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 apple2gs_clock_mode { CLOCKMODE_IDLE, CLOCKMODE_TIME, CLOCKMODE_INTERNALREGS, CLOCKMODE_BRAM1, CLOCKMODE_BRAM2 }; enum adbstate_t { ADBSTATE_IDLE, ADBSTATE_INCOMMAND, ADBSTATE_INRESPONSE }; bool m_adb_line = false; address_space *m_maincpu_space = nullptr; TIMER_DEVICE_CALLBACK_MEMBER(apple2_interrupt); TIMER_DEVICE_CALLBACK_MEMBER(accel_timer); void palette_init(palette_device &palette); u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); void apple2gs_map(address_map &map); void vectors_map(address_map &map); void a2gs_es5503_map(address_map &map); void c300bank_map(address_map &map); 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 ram0000_r(offs_t offset); void ram0000_w(offs_t offset, u8 data); u8 ram0800_r(offs_t offset); void ram0800_w(offs_t offset, u8 data); 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); u8 e0ram0400_r(offs_t offset); void e0ram0400_w(offs_t offset, u8 data); u8 e1ram0400_r(offs_t offset); void e1ram0400_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); DECLARE_WRITE_LINE_MEMBER(a2bus_irq_w); DECLARE_WRITE_LINE_MEMBER(a2bus_nmi_w); DECLARE_WRITE_LINE_MEMBER(a2bus_inh_w); DECLARE_WRITE_LINE_MEMBER(doc_irq_w); DECLARE_WRITE_LINE_MEMBER(scc_irq_w); u8 doc_adc_read(); u8 apple2gs_read_vector(offs_t offset); #if !RUN_ADB_MICRO DECLARE_READ_LINE_MEMBER(ay3600_shift_r); DECLARE_READ_LINE_MEMBER(ay3600_control_r); DECLARE_WRITE_LINE_MEMBER(ay3600_data_ready_w); DECLARE_WRITE_LINE_MEMBER(ay3600_ako_w); TIMER_DEVICE_CALLBACK_MEMBER(ay3600_repeat); #endif u8 keyglu_mcu_read(u8 offset); void keyglu_mcu_write(u8 offset, u8 data); #if RUN_ADB_MICRO u8 keyglu_816_read(u8 offset); void keyglu_816_write(u8 offset, u8 data); #endif 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); #if ADB_HLE void set_adb_line(int linestate); #endif 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_page2 = 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_80store = 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_ioudis = false; bool m_rombank = false; u8 m_shadow = 0, m_speed = 0, m_textcol = 0; u8 m_motors_active = 0, m_slotromsel = 0, m_intflag = 0, m_vgcint = 0, m_inten = 0, m_newvideo = 0; bool m_last_speed = false; // Sound GLU variables u8 m_sndglu_ctrl = 0; int 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; 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, m_clock_read = 0, m_clock_reg1 = 0; apple2gs_clock_mode m_clock_mode; u32 m_clock_curtime; seconds_t m_clock_curtime_interval; u8 m_clock_bram[256]{}; int m_clock_frame = 0; // ADB simulation #if !RUN_ADB_MICRO adbstate_t m_adb_state; u8 m_adb_command = 0; u8 m_adb_mode = 0; u8 m_adb_kmstatus = 0; u8 m_adb_pending_status = 0; u8 m_adb_latent_result = 0; s32 m_adb_command_length = 0; s32 m_adb_command_pos = 0; u8 m_adb_response_length = 0; s32 m_adb_response_pos = 0; u8 m_adb_command_bytes[8]{}; u8 m_adb_response_bytes[8]{}; u8 m_adb_memory[0x100]{}; int m_adb_address_keyboard = 0; int m_adb_address_mouse = 0; u16 m_lastchar = 0, m_strobe = 0; u8 m_transchar = 0; bool m_anykeydown = false; int m_repeatdelay = 0; u8 adb_read_datareg(); u8 adb_read_kmstatus(); u8 adb_read_memory(u32 address); void adb_write_memory(u32 address, u8 data); void adb_set_mode(u8 mode); void adb_set_config(u8 b1, u8 b2, u8 b3); void adb_post_response(const u8 *bytes, size_t length); void adb_post_response_1(u8 b); void adb_post_response_2(u8 b1, u8 b2); void adb_post_response_3(u8 b1, u8 b2, u8 b3); void adb_do_command(); void adb_write_datareg(u8 data); void adb_write_kmstatus(u8 data); u8 adb_read_mousedata(); s8 seven_bit_diff(u8 v1, u8 v2); void adb_check_mouse(); #endif u8 m_mouse_x; u8 m_mouse_y; s8 m_mouse_dx; s8 m_mouse_dy; 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(); // 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(1021800); } } 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_14M/5); } else { m_maincpu->set_unscaled_clock(1021800); } } 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 (!machine().side_effects_disabled() && m_last_speed) \ {\ 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); } WRITE_LINE_MEMBER(apple2gs_state::a2bus_irq_w) { if (state == ASSERT_LINE) { raise_irq(IRQS_SLOT); m_slot_irq = true; } else { lower_irq(IRQS_SLOT); } } WRITE_LINE_MEMBER(apple2gs_state::a2bus_nmi_w) { 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. WRITE_LINE_MEMBER(apple2gs_state::a2bus_inh_w) { 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)) { 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); } } /*************************************************************************** ADB MCU simulation ***************************************************************************/ #if !RUN_ADB_MICRO READ_LINE_MEMBER(apple2gs_state::ay3600_shift_r) { // either shift key if (m_kbspecial->read() & 0x06) { return ASSERT_LINE; } return CLEAR_LINE; } READ_LINE_MEMBER(apple2gs_state::ay3600_control_r) { if (m_kbspecial->read() & 0x08) { return ASSERT_LINE; } return CLEAR_LINE; } WRITE_LINE_MEMBER(apple2gs_state::ay3600_data_ready_w) { if (state == ASSERT_LINE) { u8 *decode = m_kbdrom->base(); u16 trans; // if the user presses a valid key to start the driver from the info screen, // we will see that key. ignore keys in the first 25,000 cycles (in my tests, // the unwanted key shows up at 17030 cycles) 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_lastchar = m_ay3600->b_r(); u8 special = m_kbspecial->read(); trans = m_lastchar & ~(0x1c0); // clear the 3600's control/shift stuff trans |= (m_lastchar & 0x100)>>2; // bring the 0x100 bit down to the 0x40 place trans <<= 2; // 4 entries per key trans |= (special & 0x06) ? 0x00 : 0x01; // shift is bit 1 (active low) trans |= (special & 0x08) ? 0x00 : 0x02; // control is bit 2 (active low) trans |= (special & 0x01) ? 0x0000 : 0x0200; // caps lock is bit 9 (active low) // hack in keypad equals because we can't find it in the IIe keymap (Sather doesn't show it in the matrix, but it's clearly on real platinum IIes) if (m_lastchar == 0x106) { m_transchar = '='; } else { m_transchar = decode[trans]; } m_strobe = 0x80; // printf("new char = %04x (%02x)\n", m_lastchar, m_transchar); /* check for command-control-esc and command-control delete */ if ((special & 0x18) == 0x18) { if (m_transchar == 0x1b) { m_adb_pending_status |= 0x20; } else if (m_transchar == 0x7f) { m_adb_pending_status |= 0x10; } if (m_adb_pending_status && m_adb_state == ADBSTATE_IDLE) { adb_post_response_1(m_adb_pending_status); m_adb_pending_status = 0; } } } } WRITE_LINE_MEMBER(apple2gs_state::ay3600_ako_w) { m_anykeydown = (state == ASSERT_LINE) ? true : false; if (m_anykeydown) { m_repeatdelay = 10; } } TIMER_DEVICE_CALLBACK_MEMBER(apple2gs_state::ay3600_repeat) { // is the key still down? if (m_anykeydown) { if (m_repeatdelay) { m_repeatdelay--; } else { m_strobe = 0x80; } } } #endif #if !RUN_ADB_MICRO u8 apple2gs_state::adb_read_memory(u32 address) { if (address < std::size(m_adb_memory)) return m_adb_memory[address]; else return 0x00; } void apple2gs_state::adb_write_memory(u32 address, u8 data) { if (address < std::size(m_adb_memory)) m_adb_memory[address] = data; } void apple2gs_state::adb_set_mode(u8 mode) { m_adb_mode = mode; } void apple2gs_state::adb_set_config(u8 b1, u8 b2, u8 b3) { /* ignore for now */ } void apple2gs_state::adb_post_response(const u8 *bytes, size_t length) { assert(length < std::size(m_adb_response_bytes)); memcpy(m_adb_response_bytes, bytes, length); m_adb_state = ADBSTATE_INRESPONSE; m_adb_response_length = length; m_adb_response_pos = 0; m_adb_kmstatus |= 0x20; if (m_adb_kmstatus & 0x10) raise_irq(IRQS_ADB); } void apple2gs_state::adb_post_response_1(u8 b) { adb_post_response(&b, 1); } void apple2gs_state::adb_post_response_2(u8 b1, u8 b2) { u8 b[2]; b[0] = b1; b[1] = b2; adb_post_response(b, 2); } void apple2gs_state::adb_post_response_3(u8 b1, u8 b2, u8 b3) { u8 b[3]; b[0] = b1; b[1] = b2; b[2] = b3; adb_post_response(b, 3); } void apple2gs_state::adb_do_command() { int device; u32 address; u8 val; m_adb_state = ADBSTATE_IDLE; if (LOG_ADB) logerror("adb_do_command(): adb_command=0x%02x\n", m_adb_command); switch(m_adb_command) { case 0x00: /* ??? */ break; case 0x01: /* abort */ break; case 0x02: /* reset keyboard uC */ break; case 0x03: /* flush keyboard buffer */ break; case 0x04: /* set modes */ adb_set_mode(m_adb_mode | m_adb_command_bytes[0]); break; case 0x05: /* clear modes */ adb_set_mode(m_adb_mode & ~m_adb_command_bytes[0]); break; case 0x06: /* set config */ adb_set_config(m_adb_command_bytes[0], m_adb_command_bytes[1], m_adb_command_bytes[2]); break; case 0x07: /* synchronize */ adb_set_mode(m_adb_command_bytes[0]); adb_set_config(m_adb_command_bytes[1], m_adb_command_bytes[2], m_adb_command_bytes[3]); break; case 0x08: /* write memory */ address = m_adb_command_bytes[0]; val = m_adb_command_bytes[1]; adb_write_memory(address, val); break; case 0x09: /* read memory */ address = (m_adb_command_bytes[1] << 8) | m_adb_command_bytes[0]; adb_post_response_1(adb_read_memory(address)); break; case 0x0a: /* read modes */ adb_post_response_1(m_adb_mode); break; case 0x0b: /* read config */ adb_post_response_3(0, 0, 0); /* ignored for now */ break; case 0x0c: /* read adb error */ adb_post_response_1(0); break; case 0x0d: /* get version */ adb_post_response_1(m_is_rom3 ? 0x06 : 0x05); /* rom0 0x04 */ break; case 0x0e: /* read available charsets */ adb_post_response_2(0x01, 0x00); break; case 0x0f: /* read available layouts */ adb_post_response_2(0x01, 0x00); break; case 0x10: /* reset system */ break; case 0x11: /* send adb keycode */ break; case 0x12: /* mystery command 0x12 - mouse key parameters */ case 0x13: /* mystery command 0x13 - disk key parameters */ break; case 0x40: /* reset adb */ break; case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: /* transmit adb bytes. first byte is adb device command */ break; case 0x84: // ACS demo disk #2 has a bug and writes this accidentally to $C026 break; case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: /* send data to device */ device = m_adb_command & 0x0f; if (device == m_adb_address_keyboard) { } else if (device == m_adb_address_mouse) { } break; case 0xf2: break; default: fatalerror("ADB command 0x%02x unimplemented\n", m_adb_command); } } u8 apple2gs_state::adb_read_datareg() { u8 result; switch(m_adb_state) { case ADBSTATE_INRESPONSE: result = m_adb_response_bytes[m_adb_response_pos++]; if (m_adb_response_pos >= m_adb_response_length) { m_adb_state = ADBSTATE_IDLE; m_adb_latent_result = result; m_adb_kmstatus &= ~0x20; if (((m_adb_kmstatus & (m_adb_kmstatus >> 1)) & 0x54) == 0) lower_irq(IRQS_ADB); } break; default: result = 0; //m_adb_latent_result & 0x7f; break; } if (LOG_ADB) logerror("adb_read_datareg(): result=0x%02x\n", result); return result; } void apple2gs_state::adb_write_datareg(u8 data) { if (LOG_ADB) logerror("adb_write_datareg(): data=0x%02x\n", data); switch(m_adb_state) { case ADBSTATE_IDLE: m_adb_command = data; m_adb_command_length = 0; m_adb_command_pos = 0; // printf("ADB command %02x\n", data); switch(data) { case 0x00: /* ??? */ case 0x01: /* abort */ case 0x02: /* reset keyboard uC */ /* do nothing for now */ break; case 0x03: /* flush keyboard buffer */ m_adb_command_length = 0; break; case 0x04: /* set modes */ case 0x05: /* clear modes */ m_adb_command_length = 1; break; case 0x06: /* set config */ m_adb_command_length = 3; break; case 0x07: /* synchronize */ if (m_is_rom3) m_adb_command_length = 8; // ROM 3 has 8 bytes: mode byte, 3 config bytes, kbd/mouse params, disk eject options else m_adb_command_length = 4; // ROM 0/1 has 4 bytes sync break; case 0x08: /* write memory */ case 0x09: /* read memory */ m_adb_command_length = 2; break; case 0x0a: /* read modes */ case 0x0b: /* read config */ case 0x0c: /* read adb error */ case 0x0d: /* get version */ case 0x0e: /* read available charsets */ case 0x0f: /* read available layouts */ m_adb_command_length = 0; m_adb_state = ADBSTATE_INCOMMAND; /* HACK */ break; case 0x10: /* reset system */ /* do nothing for now */ break; case 0x11: /* send adb keycode */ m_adb_command_length = 1; break; case 0x12: /* mystery command 0x12 - mouse key parameters? */ case 0x13: /* mystery command 0x13 - disk eject parameters? */ m_adb_command_length = 2; break; case 0x40: /* reset ADB */ break; /* 0x49 - 0x4f - transmit ADB bytes where length = command & 0xf - 6*/ case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: m_adb_command_length = (m_adb_command & 0x0f) - 6; break; case 0x50: /* enable SRQ device 0 */ case 0x51: /* enable SRQ device 1 */ case 0x52: /* enable SRQ device 2 */ case 0x53: /* enable SRQ device 3 */ /* ignore for now */ break; case 0x60: /* flush adb buffer device 0 */ case 0x61: /* flush adb buffer device 1 */ case 0x62: /* flush adb buffer device 2 */ case 0x63: /* flush adb buffer device 3 */ /* ignore for now */ break; case 0x70: /* disable SRQ device 0 */ case 0x71: /* disable SRQ device 1 */ case 0x72: /* disable SRQ device 2 */ case 0x73: /* disable SRQ device 3 */ /* ignore for now */ break; case 0x84: // ACS demo disk #2 has a bug and writes this accidentally to $C026 break; case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: /* send data to device */ m_adb_command_length = 2; break; case 0xe2: // Jam Session sends this when starting a song break; case 0xf2: adb_post_response_1(0x80); break; default: fatalerror("ADB command 0x%02x unimplemented\n", data); } if (m_adb_command_length > 0) { m_adb_state = ADBSTATE_INCOMMAND; if (LOG_ADB) logerror("adb_write_datareg(): in command length %u\n", (unsigned) m_adb_command_length); } break; case ADBSTATE_INCOMMAND: assert(m_adb_command_pos < std::size(m_adb_command_bytes)); // printf("ADB param %02x\n", data); m_adb_command_bytes[m_adb_command_pos++] = data; break; case ADBSTATE_INRESPONSE: m_adb_state = ADBSTATE_IDLE; break; } /* do command if necessary */ if ((m_adb_state == ADBSTATE_INCOMMAND) && (m_adb_command_pos >= m_adb_command_length)) adb_do_command(); } // real rom 3 h/w reads 0x90 when idle, 0x98 when key pressed // current MAME reads back 0xb0 when idle u8 apple2gs_state::adb_read_kmstatus() { return m_adb_kmstatus; } void apple2gs_state::adb_write_kmstatus(u8 data) { m_adb_kmstatus &= ~0x54; m_adb_kmstatus |= data & 0x54; if (((m_adb_kmstatus & (m_adb_kmstatus >> 1)) & 0x54)) raise_irq(IRQS_ADB); else lower_irq(IRQS_ADB); } u8 apple2gs_state::adb_read_mousedata() { u8 result = 0x00; u8 absolute; s8 delta; if (m_adb_kmstatus & 0x80) // mouse register full { if (m_adb_kmstatus & 0x02) // H/V mouse data select { absolute = m_mouse_y; delta = m_mouse_dy; m_adb_kmstatus &= ~0x82; if (((m_adb_kmstatus & (m_adb_kmstatus >> 1)) & 0x54) == 0) lower_irq(IRQS_ADB); } else { absolute = m_mouse_x; delta = m_mouse_dx; m_adb_kmstatus |= 0x02; } if (delta > 63) delta = 63; else if (delta < -64) delta = -64; result = (absolute & 0x80) | (delta & 0x7F); } else { // no mouse axis data, so just return the button status. used by some 3200 viewers. result = m_adb_mousey->read() & 0x80; } return result; } s8 apple2gs_state::seven_bit_diff(u8 v1, u8 v2) { v1 -= v2; if (v1 & 0x40) v1 |= 0x80; else v1 &= ~0x80; return v1; } void apple2gs_state::adb_check_mouse() { u8 new_mouse_x, new_mouse_y; /* read mouse values */ if ((m_adb_kmstatus & 0x80) == 0x00) { new_mouse_x = m_adb_mousex->read(); new_mouse_y = m_adb_mousey->read(); if ((m_mouse_x != new_mouse_x) || (m_mouse_y != new_mouse_y)) { m_mouse_dx = seven_bit_diff(new_mouse_x, m_mouse_x); m_mouse_dy = seven_bit_diff(new_mouse_y, m_mouse_y); m_mouse_x = new_mouse_x; m_mouse_y = new_mouse_y; m_adb_kmstatus |= 0x80; m_adb_kmstatus &= ~0x02; if (m_adb_kmstatus & 0x40) { raise_irq(IRQS_ADB); } } } } #endif /*************************************************************************** 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_b0_0200bank.select(0); m_b0_0400bank.select(0); m_e0_0400bank.select(0); m_b0_0800bank.select(0); m_b0_2000bank.select(0); m_b0_4000bank.select(0); m_inh_bank = 0; #if !RUN_ADB_MICRO m_transchar = 0; m_anykeydown = false; #endif std::fill(std::begin(m_megaii_ram), std::end(m_megaii_ram), 0); m_nvram->set_base(m_clock_bram, sizeof(m_clock_bram)); // 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->m_ram_ptr = m_megaii_ram; m_video->m_aux_ptr = &m_megaii_ram[0x10000]; m_video->m_char_ptr = memregion("gfx1")->base(); m_video->m_char_size = memregion("gfx1")->bytes(); m_video->m_8bit_graphics = std::make_unique(560, 192); m_textcol = 0xf2; m_video->m_GSfg = (m_textcol >> 4) & 0xf; m_video->m_GSbg = m_textcol & 0xf; m_inh_slot = -1; m_cnxx_slot = CNXX_UNCLAIMED; // install memory beyond 256K/1M address_space& space = m_maincpu->space(AS_PROGRAM); int ramsize = m_ram_size - 0x20000; // subtract 128K for banks 0 and 1, which are handled specially // RAM sizes for both classes of machine no longer include the Mega II RAM space.install_ram(0x020000, ramsize - 1 + 0x20000, m_ram_ptr + 0x020000); // 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_page2)); 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_80store)); save_item(NAME(m_slotc3rom)); save_item(NAME(m_altzp)); save_item(NAME(m_ramrd)); save_item(NAME(m_ramwrt)); save_item(NAME(m_ioudis)); 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_textcol)); 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(m_clock_read, "CLKRD"); save_item(m_clock_reg1, "CLKREG1"); save_item(m_clock_curtime, "CLKCURTIME"); save_item(m_clock_curtime_interval, "CLKCURTIMEINT"); // save_item(m_clock_mode, "CLKMODE"); save_item(NAME(m_clock_bram)); save_item(NAME(m_clock_frame)); #if !RUN_ADB_MICRO save_item(NAME(m_adb_memory)); save_item(NAME(m_adb_command_bytes)); save_item(NAME(m_adb_response_bytes)); // save_item(m_adb_state, "ADB/m_adb_state"); save_item(m_adb_command, "ADB/m_adb_command"); save_item(m_adb_mode, "ADB/m_adb_mode"); save_item(m_adb_kmstatus, "ADB/m_adb_kmstatus"); save_item(m_adb_pending_status, "ADB/m_adb_pending_status"); save_item(m_adb_latent_result, "ADB/m_adb_latent_result"); save_item(m_adb_command_length, "ADB/m_adb_command_length"); save_item(m_adb_command_pos, "ADB/m_adb_command_pos"); save_item(m_adb_response_length, "ADB/m_adb_response_length"); save_item(m_adb_response_pos, "ADB/m_adb_response_pos"); save_item(m_adb_address_keyboard, "ADB/m_adb_address_keyboard"); save_item(m_adb_address_mouse, "ADB/m_adb_address_mouse"); save_item(NAME(m_lastchar)); save_item(NAME(m_strobe)); save_item(NAME(m_transchar)); save_item(NAME(m_anykeydown)); save_item(NAME(m_repeatdelay)); #endif save_item(m_mouse_x, "MX"); save_item(m_mouse_y, "MY"); save_item(m_mouse_dx, "MDX"); save_item(m_mouse_dy, "MDY"); 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)); save_item(NAME(m_newvideo)); } void apple2gs_state::machine_reset() { m_page2 = false; m_romswitch = false; m_video->m_page2 = false; m_video->m_GSborder = 0x02; m_video->m_GSbg = 0x02; m_video->m_GSfg = 0x0f; 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_80store = false; m_video->m_80store = false; m_altzp = false; m_ramrd = false; m_ramwrt = false; m_ioudis = true; m_newvideo = 0x01; // verified on ROM03 hardware m_clock_frame = 0; m_mouse_x = 0x00; m_mouse_y = 0x00; m_mouse_dx = 0x00; m_mouse_dy = 0x00; m_slot_irq = false; #if !RUN_ADB_MICRO m_adb_state = ADBSTATE_IDLE; m_adb_kmstatus = 0x00; m_adb_command = 0; m_adb_mode = 0; m_adb_latent_result = 0; m_adb_command_length = 0; m_adb_command_pos = 0; m_adb_response_length = 0; m_adb_response_pos = 0; memset(m_adb_command_bytes, 0, sizeof(m_adb_command_bytes)); memset(m_adb_response_bytes, 0, sizeof(m_adb_response_bytes)); memset(m_adb_memory, 0, sizeof(m_adb_memory)); m_adb_address_keyboard = 2; m_adb_address_mouse = 3; #endif /* init time */ m_clkdata = 0; m_clock_control =0; m_clock_read = 0; m_clock_reg1 = 0; m_clock_mode = CLOCKMODE_IDLE; m_clock_curtime_interval = 0; // seed the clock with real time struct tm cur_time, mac_reference; system_time curtime; machine().current_datetime(curtime); cur_time.tm_sec = curtime.local_time.second; cur_time.tm_min = curtime.local_time.minute; cur_time.tm_hour = curtime.local_time.hour; cur_time.tm_mday = curtime.local_time.mday; cur_time.tm_mon = curtime.local_time.month; cur_time.tm_year = curtime.local_time.year-1900; cur_time.tm_isdst = 0; /* The count starts on 1st January 1904 */ mac_reference.tm_sec = 0; mac_reference.tm_min = 0; mac_reference.tm_hour = 0; mac_reference.tm_mday = 1; mac_reference.tm_mon = 0; mac_reference.tm_year = 4; mac_reference.tm_isdst = 0; m_clock_curtime = difftime(mktime(&cur_time), mktime(&mac_reference)); 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_14M/5); 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_b0_0200bank.select(0); m_b0_0400bank.select(0); m_e0_0400bank.select(0); m_b0_0800bank.select(0); m_b0_2000bank.select(0); m_b0_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(); // 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 = 0; 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); //printf("raise IRQ %d (mask %x)\n", irq, m_irqmask); if (m_irqmask) { 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); } else { m_maincpu->set_input_line(G65816_LINE_IRQ, ASSERT_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_14M / 5 : A2GS_1M); } m_last_speed = isfast; } } void apple2gs_state::accel_slot(int slot) { if ((m_accel_present) && (m_accel_slotspk & (1 << slot))) { 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) { int scanline = m_screen->vpos(); m_screen->update_partial(scanline); if ((scanline % 8) == 0) { #if !RUN_ADB_MICRO adb_check_mouse(); if (m_adb_state == ADBSTATE_IDLE && m_adb_pending_status) { adb_post_response_1(m_adb_pending_status); m_adb_pending_status = 0; } #endif } /* check scanline interrupt bits if we're in super hi-res and the current scanline is within the active display area */ if ((m_video->m_newvideo & 0x80) && (scanline >= (BORDER_TOP-1)) && (scanline < (200+BORDER_TOP-1))) { u8 scb; const int shrline = scanline - BORDER_TOP + 1; if (shrline & 1) { scb = m_megaii_ram[0x19e80 + (shrline >> 1)]; } else { scb = m_megaii_ram[0x15e80 + (shrline >> 1)]; } if (scb & 0x40) { // scanline int flag is set even when the actual interrupt is disabled m_vgcint |= VGCINT_SCANLINE; // see if the interrupt is also enabled and trigger it if so if (m_vgcint & VGCINT_SCANLINEEN) { m_vgcint |= VGCINT_ANYVGCINT; raise_irq(IRQS_SCAN); } } } if (scanline == (192+BORDER_TOP)) { #if ADB_HLE m_macadb->adb_vblank(); #endif m_vbl = true; // check for ctrl-reset #if !RUN_ADB_MICRO if ((m_kbspecial->read() & 0x88) == 0x88) { m_maincpu->reset(); } #endif // VBL interrupt if ((m_inten & 0x08) && !(m_intflag & INTFLAG_VBL)) { m_intflag |= INTFLAG_VBL; raise_irq(IRQS_VBL); } m_adbmicro->set_input_line(0, ASSERT_LINE); m_video->m_sysconfig = 0; m_clock_frame++; // quarter second? if ((m_clock_frame % 15) == 0) { if ((m_inten & 0x10) && !(m_intflag & INTFLAG_QUARTER)) { m_intflag |= INTFLAG_QUARTER; raise_irq(IRQS_QTRSEC); } } // 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); } } // one second if (m_clock_frame >= 60) { //printf("one sec, vgcint = %02x\n", m_vgcint); m_clock_frame = 0; m_clock_curtime++; if ((m_vgcint & VGCINT_SECONDENABLE) && !(m_vgcint & VGCINT_SECOND)) { m_vgcint |= (VGCINT_SECOND|VGCINT_ANYVGCINT); raise_irq(IRQS_SECOND); } } } else if (scanline == (192+BORDER_TOP+1)) { m_adbmicro->set_input_line(1, ASSERT_LINE); } } 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->m_GSborder_colors[i] = rgb_t(apple2gs_palette[(3*i)]*17, apple2gs_palette[(3*i)+1]*17, apple2gs_palette[(3*i)+2]*17); } } u32 apple2gs_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { return m_video->screen_update_GS(screen, bitmap, cliprect); } /*************************************************************************** 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_b0_0200bank.select(ramwr); if (m_80store) { if (m_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); if ((m_80store) && (m_video->m_hires)) { if (m_page2) { m_b0_2000bank.select(3); } else { m_b0_2000bank.select(0); } } else { m_b0_2000bank.select(ramwr); } m_b0_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) { 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); } } #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 } // 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; if (m_ioudis) { switch (offset) { case 0x5e: // SETDHIRES m_video->dhires_w(0); return; case 0x5f: // CLRDHIRES m_video->dhires_w(1); 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 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 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_page2 = false; m_video->scr_w(0); auxbank_update(); break; case 0x55: // set page 2 m_page2 = true; 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 m_an3 = false; m_gameio->an3_w(0); break; case 0x5f: // AN3 on m_an3 = true; m_gameio->an3_w(1); break; case 0x68: // STATE break; // trigger joypad read case 0x70: 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: // 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; } } // apple2gs_get_vpos - return the correct vertical counter value for the current scanline. int apple2gs_state::get_vpos() { // as per IIgs Tech Note #39, this is simply scanline + 250 on NTSC (262 lines), // or scanline + 200 on PAL (312 lines) int vpos = m_screen->vpos() + (511 - BORDER_TOP + 6); if (vpos > 511) { vpos -= (511 - 250); } return vpos; } void apple2gs_state::process_clock() { u8 operation; switch(m_clock_mode) { case CLOCKMODE_IDLE: m_clock_read = (m_clkdata >> 7); m_clock_reg1 = (m_clkdata >> 2) & 0x03; operation = (m_clkdata >> 4) & 0x07; if ((m_clkdata & 0x40) == 0x00) { switch(operation) { case 0x00: /* read/write seconds register */ m_clock_mode = CLOCKMODE_TIME; break; case 0x03: /* internal registers */ if (m_clock_reg1 & 0x02) { m_clock_mode = CLOCKMODE_BRAM2; m_clock_reg1 = (m_clkdata & 0x07) << 5; } else { m_clock_mode = CLOCKMODE_INTERNALREGS; } break; default: //fatalerror("NYI\n"); break; } } break; case CLOCKMODE_BRAM1: if (m_clock_read) { m_clkdata = m_clock_bram[m_clock_reg1]; //printf("Read BRAM %02x = %02x\n", m_clock_reg1, m_clkdata); } else { //printf("Write BRAM %02x = %02x\n", m_clock_reg1, m_clkdata); m_clock_bram[m_clock_reg1] = m_clkdata; } m_clock_mode = CLOCKMODE_IDLE; break; case CLOCKMODE_BRAM2: m_clock_reg1 |= (m_clkdata >> 2) & 0x1F; m_clock_mode = CLOCKMODE_BRAM1; break; case CLOCKMODE_INTERNALREGS: //printf("internalregs, reg %d, read %x\n", m_clock_reg1, m_clock_read); switch (m_clock_reg1) { case 0x00: /* test register */ break; case 0x01: /* write protect register */ break; } m_clock_mode = CLOCKMODE_IDLE; break; case CLOCKMODE_TIME: if (m_clock_control & 0x40) { m_clkdata = m_clock_curtime >> (m_clock_reg1 * 8); //printf("Read time reg %x = %x\n", m_clock_reg1, m_clkdata); } else { m_clock_curtime &= ~(0xFF << (m_clock_reg1 * 8)); m_clock_curtime |= m_clkdata << (m_clock_reg1 * 8); //printf("Write time reg %x = %x\n", m_clock_reg1, m_clkdata); } m_clock_mode = CLOCKMODE_IDLE; break; default: //fatalerror("NYI\n"); break; } } u8 apple2gs_state::c000_r(offs_t offset) { u8 ret; // allow ROM window at C07x to be debugger-visible if ((offset < 0x70) || (offset > 0x7f)) { if(machine().side_effects_disabled()) return read_floatingbus(); } slow_cycle(); u8 uFloatingBus7 = read_floatingbus() & 0x7f; #if RUN_ADB_MICRO u8 uKeyboard = keyglu_816_read(GLU_C000); u8 uKeyboardC010 = keyglu_816_read(GLU_C010); #else u8 uKeyboard = m_transchar | m_strobe; u8 uKeyboardC010 = m_transchar; #endif switch (offset) { case 0x00: // keyboard latch return uKeyboard; 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 0x10: // read any key down, reset keyboard strobe #if !RUN_ADB_MICRO m_strobe = 0; return uKeyboardC010 | (m_anykeydown ? 0x80 : 0x00); #else keyglu_816_write(GLU_C010, 0); return uKeyboardC010; #endif case 0x11: // read LCRAM2 (LC Dxxx bank) return uKeyboardC010 | (m_lcram2 ? 0x80 : 0x00); case 0x12: // read LCRAM (is LC readable?) return uKeyboardC010 | (m_lcram ? 0x80 : 0x00); case 0x13: // read RAMRD return uKeyboardC010 | (m_ramrd ? 0x80 : 0x00); case 0x14: // read RAMWRT return uKeyboardC010 | (m_ramwrt ? 0x80 : 0x00); case 0x15: // read INTCXROM return uKeyboardC010 | (m_intcxrom ? 0x80 : 0x00); case 0x16: // read ALTZP return uKeyboardC010 | (m_altzp ? 0x80 : 0x00); case 0x17: // read SLOTC3ROM return uKeyboardC010 | (m_slotc3rom ? 0x80 : 0x00); case 0x18: // read 80STORE return uKeyboardC010 | (m_80store ? 0x80 : 0x00); case 0x19: // read VBLBAR return uKeyboardC010 | (m_screen->vblank() ? 0x00 : 0x80); case 0x1a: // read TEXT return uKeyboardC010 | (m_video->m_graphics ? 0x00 : 0x80); case 0x1b: // read MIXED return uKeyboardC010 | (m_video->m_mix ? 0x80 : 0x00); case 0x1c: // read PAGE2 return uKeyboardC010 | (m_page2 ? 0x80 : 0x00); case 0x1d: // read HIRES return uKeyboardC010 | (m_video->m_hires ? 0x80 : 0x00); case 0x1e: // read ALTCHARSET return uKeyboardC010 | (m_video->m_altcharset ? 0x80 : 0x00); case 0x1f: // read 80COL return uKeyboardC010 | (m_video->m_80col ? 0x80 : 0x00); case 0x22: // TEXTCOL return m_textcol; case 0x23: // VGCINT return m_vgcint; #if RUN_ADB_MICRO 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); #else case 0x24: // MOUSEDATA */ return adb_read_mousedata(); case 0x25: // KEYMODREG ret = 0; { u8 temp = m_kbspecial->read(); if (temp & 1) // capslock { ret |= 4; } if (temp & 6) // shift { ret |= 1; } if (temp & 8) // control { ret |= 2; } if (temp & 0x10) // open apple/command { ret |= 0x80; } if (temp & 0x20) // option { ret |= 0x40; } // keypad is a little rough right now if (m_lastchar >= 0x28 && m_lastchar <= 0x2d) { ret |= 0x10; } else if (m_lastchar >= 0x32 && m_lastchar <= 0x37) { ret |= 0x10; } else if (m_lastchar >= 0x3c && m_lastchar <= 0x3f) { ret |= 0x10; } else if (m_lastchar >= 0x100 && m_lastchar <= 0x101) { ret |= 0x10; } else if ((m_lastchar >= 0x109 && m_lastchar <= 0x10a) || (m_lastchar == 0x106)) { ret |= 0x10; } } return ret; case 0x26: // DATAREG return adb_read_datareg(); case 0x27: // KMSTATUS // hack to let one-second IRQs get through in Nucleus if (m_vgcint & VGCINT_SECOND) return 0; // secondary hack for slot IRQs if (m_slot_irq) { m_slot_irq = false; return 0; } return adb_read_kmstatus(); #endif case 0x29: // NEWVIDEO return m_newvideo; case 0x2d: // SLOTROMSEL return m_slotromsel; case 0x2e: // VERTCNT return get_vpos() >> 1; case 0x2f: // HORIZCNT ret = m_screen->hpos() / 11; if (ret > 0) { ret += 0x40; } if (get_vpos() & 1) { ret |= 0x80; } return ret; case 0x31: // DISKREG return m_diskreg; case 0x32: // VGCINTCLEAR return 0; case 0x33: // CLOCKDATA return m_clkdata; case 0x34: // BORDERCOL return (m_clock_control & 0xf0) | (m_video->m_GSborder & 0xf); case 0x35: // SHADOW return m_shadow; case 0x36: // SPEED/CYAREG return m_speed; 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); case 0x3c: // SOUNDCTL return m_sndglu_ctrl; case 0x3d: // SOUNDDATA ret = m_sndglu_dummy_read; 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 0x46: // INTFLAG return (m_an3 ? INTFLAG_AN3 : 0x00) | m_intflag; case 0x47: // CLRVBLINT m_intflag &= ~(INTFLAG_VBL|INTFLAG_QUARTER); lower_irq(IRQS_VBL); lower_irq(IRQS_QTRSEC); return read_floatingbus(); case 0x60: // button 3 on IIgs return m_gameio->sw3_r() | uFloatingBus7; #if RUN_ADB_MICRO case 0x61: // button 0 or Open Apple return m_gameio->sw0_r() | uFloatingBus7; case 0x62: // button 1 or Option return m_gameio->sw1_r() | uFloatingBus7; case 0x63: // button 2 or SHIFT key return m_gameio->sw2_r() | uFloatingBus7; #else case 0x61: // button 0 or Open Apple return ((m_gameio->sw0_r() || (m_kbspecial->read() & 0x10)) ? 0x80 : 0) | uFloatingBus7; case 0x62: // button 1 or Option return ((m_gameio->sw1_r() || (m_kbspecial->read() & 0x20)) ? 0x80 : 0) | uFloatingBus7; case 0x63: // button 2 or SHIFT key return ((m_gameio->sw2_r() || (m_kbspecial->read() & 0x06)) ? 0x80 : 0) | uFloatingBus7; #endif 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_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); case 0x70: // PTRIG - triggers paddles on read or write if (!machine().side_effects_disabled()) { // 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(); } } return m_rom[offset + 0x3c000]; // The ROM IRQ vectors point here 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) { // 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); if (time & 1) { return 0x03; } else { return 0x83; } } else if (offset == 0x5c) { return m_accel_slotspk; } } break; } // assume all $C00X returns the keyboard, like on the IIe if ((offset & 0xf0) == 0x00) { return uKeyboard; } return read_floatingbus(); } void apple2gs_state::c000_w(offs_t offset, u8 data) { if(machine().side_effects_disabled()) return; slow_cycle(); switch (offset) { case 0x00: // 80STOREOFF m_80store = false; m_video->m_80store = false; auxbank_update(); break; case 0x01: // 80STOREON m_80store = true; m_video->m_80store = 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->m_80col = false; break; case 0x0d: // 80COLON m_video->m_80col = true; break; case 0x0e: // ALTCHARSETOFF m_video->m_altcharset = false; break; case 0x0f: // ALTCHARSETON m_video->m_altcharset = true; break; case 0x10: // clear keyboard latch #if RUN_ADB_MICRO keyglu_816_write(GLU_C010, data); break; #else m_strobe = 0; break; #endif case 0x20: break; case 0x21: // MONOCHROME m_video->m_monochrome = data; break; case 0x22: // TEXTCOL if (m_textcol != data) { m_screen->update_now(); } m_textcol = data; m_video->m_GSfg = (data >> 4) & 0xf; m_video->m_GSbg = data & 0xf; break; case 0x23: // VGCINT if ((m_vgcint & VGCINT_SECOND) && !(data & VGCINT_SECONDENABLE)) { lower_irq(IRQS_SECOND); m_vgcint &= ~(VGCINT_SECOND); } if ((m_vgcint & VGCINT_SCANLINE) && !(data & VGCINT_SCANLINEEN)) { lower_irq(IRQS_SCAN); m_vgcint &= ~(VGCINT_SCANLINE); } if (!(m_vgcint & (VGCINT_SECOND|VGCINT_SCANLINE))) { m_vgcint &= ~(VGCINT_ANYVGCINT); } m_vgcint &= 0xf0; m_vgcint |= (data & 0x0f); //printf("%02x to VGCINT, now %02x\n", data, m_vgcint); break; #if RUN_ADB_MICRO case 0x26: // DATAREG keyglu_816_write(GLU_COMMAND, data); break; case 0x27: // KMSTATUS keyglu_816_write(GLU_SYSSTAT, data); break; #else case 0x26: // DATAREG adb_write_datareg(data); break; case 0x27: // KMSTATUS adb_write_kmstatus(data); break; #endif case 0x29: // NEWVIDEO m_video->m_newvideo = m_newvideo = data; break; case 0x2d: // SLOTROMSEL m_slotromsel = data; break; case 0x31: // 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); // one second if (m_vgcint & VGCINT_SECOND) { lower_irq(IRQS_SECOND); m_vgcint &= ~(VGCINT_SECOND|VGCINT_ANYVGCINT); } // scanline if (m_vgcint & VGCINT_SCANLINE) { lower_irq(IRQS_SCAN); m_vgcint &= ~(VGCINT_SCANLINE|VGCINT_ANYVGCINT); } if (m_irqmask & ((1<m_GSborder & 0xf)) { m_screen->update_now(); } m_clock_control = data & 0x7f; m_video->m_GSborder = data & 0xf; 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; 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 0x47: // CLRVBLINT m_intflag &= ~(INTFLAG_VBL|INTFLAG_QUARTER); lower_irq(IRQS_VBL); lower_irq(IRQS_QTRSEC); 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 } 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 accel_normal_speed(); m_accel_unlocked = false; m_accel_stage = 0; } } do_io(offset); break; case 0x5b: // Zip full speed if (m_accel_unlocked) { 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; } break; case 0x68: // STATEREG m_altzp = (data & 0x80); m_page2 = (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; case 0x70: 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: do_io(offset); // make sure it also side-effect resets the paddles as documented break; case 0x7e: // SETIOUDIS m_ioudis = true; break; case 0x7f: // CLRIOUDIS m_ioudis = false; 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 { if (m_accel_present) { 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; slow_cycle(); accel_slot(slot); // SETSLOTCXROM is disabled, so the $C02D SLOT register controls what's in each slot if (!(m_slotromsel & (1 << 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 ((m_slotromsel & (1 << 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 (!(m_slotromsel & (1 << 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 ((m_slotromsel & (1 << 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; } } 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 (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 (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; } // floating bus code from old machine/apple2: needs to be reworked based on real beam position to enable e.g. Bob Bishop's screen splitter u8 apple2gs_state::read_floatingbus() { enum { // scanner types kScannerNone = 0, kScannerApple2, kScannerApple2e, // scanner constants kHBurstClock = 53, // clock when Color Burst starts kHBurstClocks = 4, // clocks per Color Burst duration kHClock0State = 0x18, // H[543210] = 011000 kHClocks = 65, // clocks per horizontal scan (including HBL) kHPEClock = 40, // clock when HPE (horizontal preset enable) goes low kHPresetClock = 41, // clock when H state presets kHSyncClock = 49, // clock when HSync starts kHSyncClocks = 4, // clocks per HSync duration kNTSCScanLines = 262, // total scan lines including VBL (NTSC) kNTSCVSyncLine = 224, // line when VSync starts (NTSC) kPALScanLines = 312, // total scan lines including VBL (PAL) kPALVSyncLine = 264, // line when VSync starts (PAL) kVLine0State = 0x100, // V[543210CBA] = 100000000 kVPresetLine = 256, // line when V state presets kVSyncLines = 4, // lines per VSync duration kClocksPerVSync = kHClocks * kNTSCScanLines // FIX: NTSC only? }; // vars // int i, Hires, Mixed, Page2, _80Store, ScanLines, /* VSyncLine, ScanCycles,*/ h_clock, h_state, h_0, h_1, h_2, h_3, h_4, h_5, v_line, v_state, v_A, v_B, v_C, v_0, v_1, v_2, v_3, v_4, /* v_5, */ _hires, addend0, addend1, addend2, sum, address; // video scanner data // i = m_maincpu->total_cycles() % kClocksPerVSync; // cycles into this VSync // machine state switches // Hires = (m_video->m_hires && m_video->m_graphics) ? 1 : 0; Mixed = m_video->m_mix ? 1 : 0; Page2 = m_page2 ? 1 : 0; _80Store = m_80store ? 1 : 0; // calculate video parameters according to display standard // ScanLines = 1 ? kNTSCScanLines : kPALScanLines; // FIX: NTSC only? // VSyncLine = 1 ? kNTSCVSyncLine : kPALVSyncLine; // FIX: NTSC only? // ScanCycles = ScanLines * kHClocks; // calculate horizontal scanning state // h_clock = (i + kHPEClock) % kHClocks; // which horizontal scanning clock h_state = kHClock0State + h_clock; // H state bits if (h_clock >= kHPresetClock) // check for horizontal preset { h_state -= 1; // correct for state preset (two 0 states) } h_0 = (h_state >> 0) & 1; // get horizontal state bits h_1 = (h_state >> 1) & 1; h_2 = (h_state >> 2) & 1; h_3 = (h_state >> 3) & 1; h_4 = (h_state >> 4) & 1; h_5 = (h_state >> 5) & 1; // calculate vertical scanning state // v_line = i / kHClocks; // which vertical scanning line v_state = kVLine0State + v_line; // V state bits if ((v_line >= kVPresetLine)) // check for previous vertical state preset { v_state -= ScanLines; // compensate for preset } v_A = (v_state >> 0) & 1; // get vertical state bits v_B = (v_state >> 1) & 1; v_C = (v_state >> 2) & 1; v_0 = (v_state >> 3) & 1; v_1 = (v_state >> 4) & 1; v_2 = (v_state >> 5) & 1; v_3 = (v_state >> 6) & 1; v_4 = (v_state >> 7) & 1; //v_5 = (v_state >> 8) & 1; // calculate scanning memory address // _hires = Hires; if (Hires && Mixed && (v_4 & v_2)) { _hires = 0; // (address is in text memory) } addend0 = 0x68; // 1 1 0 1 addend1 = (h_5 << 5) | (h_4 << 4) | (h_3 << 3); addend2 = (v_4 << 6) | (v_3 << 5) | (v_4 << 4) | (v_3 << 3); sum = (addend0 + addend1 + addend2) & (0x0F << 3); address = 0; address |= h_0 << 0; // a0 address |= h_1 << 1; // a1 address |= h_2 << 2; // a2 address |= sum; // a3 - aa6 address |= v_0 << 7; // a7 address |= v_1 << 8; // a8 address |= v_2 << 9; // a9 address |= ((_hires) ? v_A : (1 ^ (Page2 & (1 ^ _80Store)))) << 10; // a10 address |= ((_hires) ? v_B : (Page2 & (1 ^ _80Store))) << 11; // a11 if (_hires) // hires? { // Y: insert hires only address bits // address |= v_C << 12; // a12 address |= (1 ^ (Page2 & (1 ^ _80Store))) << 13; // a13 address |= (Page2 & (1 ^ _80Store)) << 14; // a14 } else { // N: text, so no higher address bits unless Apple ][, not Apple //e // if ((1) && // Apple ][? // FIX: check for Apple ][? (FB is most useful in old games) (kHPEClock <= h_clock) && // Y: HBL? (h_clock <= (kHClocks - 1))) { address |= 1 << 12; // Y: a12 (add $1000 to address!) } } return m_megaii_ram[address % m_ram_size]; // FIX: this seems to work, but is it right!? } /*************************************************************************** ADDRESS MAP ***************************************************************************/ u8 apple2gs_state::e0ram0400_r(offs_t offset) { slow_cycle(); return m_megaii_ram[offset + 0x0400]; } void apple2gs_state::e0ram0400_w(offs_t offset, u8 data) { slow_cycle(); m_megaii_ram[offset + 0x0400] = data; } u8 apple2gs_state::e1ram0400_r(offs_t offset) { slow_cycle(); return m_megaii_ram[offset + 0x10400]; } void apple2gs_state::e1ram0400_w(offs_t offset, u8 data) { slow_cycle(); m_megaii_ram[offset + 0x10400] = data; } u8 apple2gs_state::ram0000_r(offs_t offset) { slow_cycle(); return m_megaii_ram[offset]; } void apple2gs_state::ram0000_w(offs_t offset, u8 data) { slow_cycle(); m_megaii_ram[offset] = data; } u8 apple2gs_state::ram0800_r(offs_t offset) { slow_cycle(); return m_megaii_ram[offset + 0x800]; } void apple2gs_state::ram0800_w(offs_t offset, u8 data) { slow_cycle(); m_megaii_ram[offset + 0x800] = data; } u8 apple2gs_state::auxram0000_r(offs_t offset) { slow_cycle(); if ((offset >= 0x2000) && (offset < 0xa000) && ((m_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_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->m_shr_palette[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) { 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) { /* "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, 0xffff).rw(FUNC(apple2gs_state::c000_r), FUNC(apple2gs_state::c000_w)); m_bank0_atc[1](0xc080, 0xffff).rw(FUNC(apple2gs_state::c080_r), FUNC(apple2gs_state::c080_w)); m_bank0_atc[1](0xc100, 0xffff).rw(FUNC(apple2gs_state::c100_r), FUNC(apple2gs_state::c100_w)); m_bank0_atc[1](0xc300, 0xffff).m(m_c300bank, FUNC(address_map_bank_device::amap8)); m_bank0_atc[1](0xc400, 0xffff).rw(FUNC(apple2gs_state::c400_r), FUNC(apple2gs_state::c400_w)); m_bank0_atc[1](0xc800, 0xffff).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, 0xe003ff).rw(FUNC(apple2gs_state::ram0000_r), FUNC(apple2gs_state::ram0000_w)); map(0xe00400, 0xe007ff).view(m_e0_0400bank); m_e0_0400bank[0](0x0400, 0x07ff).rw(FUNC(apple2gs_state::e0ram0400_r), FUNC(apple2gs_state::e0ram0400_w)); // wr 0 rd 0 m_e0_0400bank[1](0x0400, 0x07ff).rw(FUNC(apple2gs_state::e1ram0400_r), FUNC(apple2gs_state::e0ram0400_w)); // wr 0 rd 1 m_e0_0400bank[2](0x0400, 0x07ff).rw(FUNC(apple2gs_state::e0ram0400_r), FUNC(apple2gs_state::e1ram0400_w)); // wr 1 rd 0 m_e0_0400bank[3](0x0400, 0x07ff).rw(FUNC(apple2gs_state::e1ram0400_r), FUNC(apple2gs_state::e1ram0400_w)); // wr 1 rd 1 map(0xe00800, 0xe0bfff).rw(FUNC(apple2gs_state::ram0800_r), FUNC(apple2gs_state::ram0800_w)); 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(0xfc0000, 0xffffff).rom().region("maincpu", 0x00000); } 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://www.llx.com/~nparker/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() { return 0xc7; } 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 (!(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; } } void apple2gs_state::adbmicro_p3_out(u8 data) { if (((data & 0x08) == 0x08) != m_adb_line) { m_adb_line = (data & 0x8) ? true : false; #if ADB_HLE m_macadb->adb_linechange_w(!m_adb_line); #endif } } #if ADB_HLE void apple2gs_state::set_adb_line(int linestate) { m_adb_line = (linestate == CLEAR_LINE); } #endif 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; // printf("MCU reads COMMAND = %02x (drop command full)\n", rv); } // 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) { // eat ADB SRQ notices - this shouldn't be necessary and breaks ROM 0/1 :( //if ((offset == GLU_DATA) && (data == 0x08)) //{ // return; //} // if (m_glu_regs[offset] != data) // { // printf("MCU writes %02x to GLU reg %x (PC=%x)\n", data, offset, m_adbmicro->pc()); // } 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: case GLU_MOUSEY: m_glu_regs[GLU_KG_STATUS] |= KGS_MOUSEX_FULL; m_glu_regs[GLU_SYSSTAT] |= GLU_STATUS_MOUSEIRQ; if (offset == GLU_MOUSEX) { keyglu_regen_irqs(); } m_glu_mouse_read_stat = false; // signal next read will be mouse X 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; // printf("MCU writes %02x to DATA\n", data); 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 */ #if RUN_ADB_MICRO 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) { m_glu_mouse_read_stat = 1; m_glu_regs[GLU_KG_STATUS] &= ~KGS_MOUSEX_FULL; keyglu_regen_irqs(); return m_glu_regs[GLU_MOUSEX]; } 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_regs[GLU_KG_STATUS] & 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; } 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) { 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; } } #endif void apple2gs_state::keyglu_regen_irqs() { #if RUN_ADB_MICRO 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 (bIRQ) { raise_irq(IRQS_ADB); } else { lower_irq(IRQS_ADB); } #endif } WRITE_LINE_MEMBER(apple2gs_state::scc_irq_w) { if (state) { raise_irq(IRQS_SCC); } else { lower_irq(IRQS_SCC); } } /* Sound - DOC */ WRITE_LINE_MEMBER(apple2gs_state::doc_irq_w) { 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 ***************************************************************************/ /* Apple IIe platinum and IIgs upgrade key matrix | Y0 | Y1 | Y2 | Y3 | Y4 | Y5 | Y6 | Y7 | Y8 | Y9 | | | | | | | | | | | | ----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----| X0 | ESC | 1 | 2 | 3 | 4 | 6 | 5 | 7 | 8 | 9 | ----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----| X1 | TAB | Q | W | E | R | Y | T | U | I | O | ----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----| X2 | A | D | S | H | F | G | J | K | ;: | L | ----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----| X3 | Z | X | C | V | B | M | N | ,< | .> | /? | ----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----| X4 | KP/ | | KP0 | KP1 | KP2 | KP3 | \| | += | 0 | -_ | ----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----| X5 | |KPEsc| KP4 | KP5 | KP6 | KP7 | `~ | P | [{ | ]} | ----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----| X6 | KP* | | KP8 | KP9 | KP. | KP+ |RETRN| UP | SPC | '" | ----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----| X7 | | | | KP- |KPENT| | DEL |DOWN |LEFT |RIGHT| ----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----| */ INPUT_PORTS_START( apple2gs ) #if !RUN_ADB_MICRO PORT_START("X0") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27) PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!') PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@') PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#') PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$') PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^') PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%') PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&') PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*') PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(') PORT_START("X1") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q') PORT_CHAR('q') PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('W') PORT_CHAR('w') PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('E') PORT_CHAR('e') PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('R') PORT_CHAR('r') PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y') PORT_CHAR('y') PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('T') PORT_CHAR('t') PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('U') PORT_CHAR('u') PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('I') PORT_CHAR('i') PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('O') PORT_CHAR('o') PORT_START("X2") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CHAR('a') PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('D') PORT_CHAR('d') PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('S') PORT_CHAR('s') PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('H') PORT_CHAR('h') PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('F') PORT_CHAR('f') PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('G') PORT_CHAR('g') PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('J') PORT_CHAR('j') PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('K') PORT_CHAR('k') PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':') PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('L') PORT_CHAR('l') PORT_START("X3") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z') PORT_CHAR('z') PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('X') PORT_CHAR('x') PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('C') PORT_CHAR('c') PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('V') PORT_CHAR('v') PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('B') PORT_CHAR('b') PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('N') PORT_CHAR('n') PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('M') PORT_CHAR('m') PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<') PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>') PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?') PORT_START("X4") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH_PAD) PORT_CHAR(UCHAR_MAMEKEY(SLASH_PAD)) PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0_PAD) PORT_CHAR(UCHAR_MAMEKEY(0_PAD)) PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_1_PAD) PORT_CHAR(UCHAR_MAMEKEY(1_PAD)) PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_2_PAD) PORT_CHAR(UCHAR_MAMEKEY(2_PAD)) PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_3_PAD) PORT_CHAR(UCHAR_MAMEKEY(3_PAD)) PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('\\') PORT_CHAR('|') PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+') PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')') PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_') PORT_START("X5") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Keypad Esc") PORT_CODE(KEYCODE_NUMLOCK) PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_4_PAD) PORT_CHAR(UCHAR_MAMEKEY(4_PAD)) PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_5_PAD) PORT_CHAR(UCHAR_MAMEKEY(5_PAD)) PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_6_PAD) PORT_CHAR(UCHAR_MAMEKEY(6_PAD)) PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_7_PAD) PORT_CHAR(UCHAR_MAMEKEY(7_PAD)) PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~') PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('P') PORT_CHAR('p') PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{') PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}') PORT_START("X6") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ASTERISK) PORT_CHAR(UCHAR_MAMEKEY(ASTERISK)) PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_8_PAD) PORT_CHAR(UCHAR_MAMEKEY(8_PAD)) PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_9_PAD) PORT_CHAR(UCHAR_MAMEKEY(9_PAD)) PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_DEL_PAD) PORT_CHAR(UCHAR_MAMEKEY(DEL_PAD)) PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_PLUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(PLUS_PAD)) PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP)) PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ') PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('\"') PORT_START("X7") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS_PAD) PORT_CHAR(UCHAR_MAMEKEY(EQUALS_PAD)) PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS_PAD) PORT_CHAR(UCHAR_MAMEKEY(MINUS_PAD)) PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD)) PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Delete") PORT_CODE(KEYCODE_BACKSPACE)PORT_CHAR(8) PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN)) PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT)) PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT)) PORT_START("X8") PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x100, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_BIT(0x200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_START(A2GS_KBD_SPEC_TAG) PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Left Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Right Shift") PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Control") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2) PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Open Apple") PORT_CODE(KEYCODE_LALT) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Option") PORT_CODE(KEYCODE_RALT) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RESET") PORT_CODE(KEYCODE_F12) PORT_START("adb_mouse_x") PORT_BIT( 0x7f, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_CODE(MOUSECODE_BUTTON2) PORT_NAME("Mouse Button 1") PORT_START("adb_mouse_y") PORT_BIT( 0x7f, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_CODE(MOUSECODE_BUTTON1) PORT_NAME("Mouse Button 0") #endif 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 void apple2gs_state::apple2gs(machine_config &config) { /* basic machine hardware */ G65816(config, m_maincpu, A2GS_MASTER_CLOCK/10); 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); m_scantimer->configure_scanline(FUNC(apple2gs_state::apple2_interrupt), "screen", 0, 1); 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->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)); #if ADB_HLE MACADB(config, m_macadb, A2GS_MASTER_CLOCK/8); m_macadb->set_mcu_mode(true); m_macadb->adb_data_callback().set(FUNC(apple2gs_state::set_adb_line)); #endif #if !RUN_ADB_MICRO /* keyboard controller */ AY3600(config, m_ay3600, 0); m_ay3600->x0().set_ioport("X0"); m_ay3600->x1().set_ioport("X1"); m_ay3600->x2().set_ioport("X2"); m_ay3600->x3().set_ioport("X3"); m_ay3600->x4().set_ioport("X4"); m_ay3600->x5().set_ioport("X5"); m_ay3600->x6().set_ioport("X6"); m_ay3600->x7().set_ioport("X7"); m_ay3600->x8().set_ioport("X8"); m_ay3600->shift().set(FUNC(apple2gs_state::ay3600_shift_r)); m_ay3600->control().set(FUNC(apple2gs_state::ay3600_control_r)); m_ay3600->data_ready().set(FUNC(apple2gs_state::ay3600_data_ready_w)); m_ay3600->ako().set(FUNC(apple2gs_state::ay3600_ako_w)); /* repeat timer. 15 Hz from page 7-15 of "Understanding the Apple IIe" */ TIMER(config, "repttmr").configure_periodic(FUNC(apple2gs_state::ay3600_repeat), attotime::from_hz(15)); #endif NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_0); APPLE2_VIDEO(config, m_video, A2GS_14M).set_screen(m_screen); 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); SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_refresh_hz(60); m_screen->set_size(704, 262); // 640+32+32 for the borders m_screen->set_visarea(0,703,0,230); m_screen->set_screen_update(FUNC(apple2gs_state::screen_update)); PALETTE(config, "palette", FUNC(apple2gs_state::palette_init), 256); /* sound hardware */ SPEAKER(config, "mono").front_center(); SPEAKER_SOUND(config, m_speaker).add_route(ALL_OUTPUTS, "mono", 1.00); SPEAKER(config, "lspeaker").front_left(); SPEAKER(config, "rspeaker").front_right(); ES5503(config, m_doc, A2GS_7M); m_doc->set_channels(2); 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)); // IIgs Tech Node #19 says even channels are right, odd are left, and 80s/90s stereo cards followed that. m_doc->add_route(0, "rspeaker", 1.0); m_doc->add_route(1, "lspeaker", 1.0); /* 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_14M / 2); 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", m_a2bus, apple2gs_cards, nullptr); A2BUS_SLOT(config, "sl2", m_a2bus, apple2gs_cards, nullptr); A2BUS_SLOT(config, "sl3", m_a2bus, apple2gs_cards, nullptr); A2BUS_SLOT(config, "sl4", m_a2bus, apple2gs_cards, nullptr); A2BUS_SLOT(config, "sl5", m_a2bus, apple2gs_cards, nullptr); A2BUS_SLOT(config, "sl6", m_a2bus, apple2gs_cards, nullptr); A2BUS_SLOT(config, "sl7", m_a2bus, apple2gs_cards, nullptr); IWM(config, m_iwm, A2GS_7M, A2GS_MASTER_CLOCK/14); 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->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)); } /*************************************************************************** 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(0x1000,"gfx1",0) ROM_LOAD ( "apple2gs.chr", 0x0000, 0x1000, CRC(91e53cd8) SHA1(34e2443e2ef960a36c047a09ed5a93f471797f89)) /* need label/part number */ ROM_REGION(0x40000,"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? */ // temporary: use IIe enhanced keyboard decode ROM ROM_REGION( 0x800, "keyboard", 0 ) ROM_LOAD( "341-0132-d.e12", 0x000, 0x800, CRC(c506efb9) SHA1(8e14e85c645187504ec9d162b3ea614a0c421d32) ) ROM_END ROM_START(apple2gsr3p) ROM_REGION(0x1000, "adbmicro", 0) ROM_LOAD( "341s0632-2.bin", 0x000000, 0x001000, CRC(e1c11fb0) SHA1(141d18c36a617ab9dce668445440d34354be0672) ) ROM_REGION(0x1000,"gfx1",0) ROM_LOAD ( "apple2gs.chr", 0x0000, 0x1000, CRC(91e53cd8) SHA1(34e2443e2ef960a36c047a09ed5a93f471797f89)) /* need label/part number */ ROM_REGION(0x40000,"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 */ // temporary: use IIe enhanced keyboard decode ROM ROM_REGION( 0x800, "keyboard", 0 ) ROM_LOAD( "341-0132-d.e12", 0x000, 0x800, CRC(c506efb9) SHA1(8e14e85c645187504ec9d162b3ea614a0c421d32) ) ROM_END ROM_START(apple2gsr1) ROM_REGION(0xc00, "adbmicro", 0) ROM_LOAD( "341s0345.bin", 0x000000, 0x000c00, CRC(48cd5779) SHA1(97e421f5247c00a0ca34cd08b6209df573101480) ) ROM_REGION(0x1000,"gfx1",0) ROM_LOAD ( "apple2gs.chr", 0x0000, 0x1000, CRC(91e53cd8) SHA1(34e2443e2ef960a36c047a09ed5a93f471797f89)) /* need label/part number */ ROM_REGION(0x40000,"maincpu",0) ROM_LOAD("342-0077-b", 0x20000, 0x20000, CRC(42f124b0) SHA1(e4fc7560b69d062cb2da5b1ffbe11cd1ca03cc37)) /* 342-0077-B: IIgs ROM01 */ // temporary: use IIe enhanced keyboard decode ROM ROM_REGION( 0x800, "keyboard", 0 ) ROM_LOAD( "341-0132-d.e12", 0x000, 0x800, CRC(c506efb9) SHA1(8e14e85c645187504ec9d162b3ea614a0c421d32) ) ROM_END ROM_START(apple2gsr0) ROM_REGION(0xc00, "adbmicro", 0) ROM_LOAD( "341s0345.bin", 0x000000, 0x000c00, CRC(48cd5779) SHA1(97e421f5247c00a0ca34cd08b6209df573101480) ) ROM_REGION(0x1000,"gfx1",0) ROM_LOAD ( "apple2gs.chr", 0x0000, 0x1000, CRC(91e53cd8) SHA1(34e2443e2ef960a36c047a09ed5a93f471797f89)) ROM_REGION(0x40000,"maincpu",0) ROM_LOAD("342-0077-a", 0x20000, 0x20000, CRC(dfbdd97b) SHA1(ff0c245dd0732ec4413a934fd80efc2defd8a8e3) ) /* 342-0077-A: IIgs ROM00 */ // temporary: use IIe enhanced keyboard decode ROM ROM_REGION( 0x800, "keyboard", 0 ) ROM_LOAD( "341-0132-d.e12", 0x000, 0x800, CRC(c506efb9) SHA1(8e14e85c645187504ec9d162b3ea614a0c421d32) ) 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(0x1000,"gfx1",0) ROM_LOAD ( "apple2gs.chr", 0x0000, 0x1000, CRC(91e53cd8) SHA1(34e2443e2ef960a36c047a09ed5a93f471797f89)) ROM_REGION(0x40000,"maincpu",0) ROM_LOAD( "rombf.bin", 0x020000, 0x020000, CRC(ab04fedf) SHA1(977589a17553956d583a21020080a39dd396df5c) ) // temporary: use IIe enhanced keyboard decode ROM ROM_REGION( 0x800, "keyboard", 0 ) ROM_LOAD( "341-0132-d.e12", 0x000, 0x800, CRC(c506efb9) SHA1(8e14e85c645187504ec9d162b3ea614a0c421d32) ) 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(0x1000,"gfx1",0) ROM_LOAD ( "apple2gs.chr", 0x0000, 0x1000, CRC(91e53cd8) SHA1(34e2443e2ef960a36c047a09ed5a93f471797f89)) ROM_REGION(0x40000,"maincpu",0) ROM_LOAD( "apple iigs alpha rom 2.0 19860310.bin", 0x020000, 0x020000, CRC(a47d275f) SHA1(c5836adcfc8be69c7351b84afa94c814e8d92b81) ) // temporary: use IIe enhanced keyboard decode ROM ROM_REGION( 0x800, "keyboard", 0 ) ROM_LOAD( "341-0132-d.e12", 0x000, 0x800, CRC(c506efb9) SHA1(8e14e85c645187504ec9d162b3ea614a0c421d32) ) ROM_END } // Anonymous namespace /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME */ COMP( 1989, apple2gs, 0, apple2, apple2gs, apple2gs, apple2gs_state, rom3_init, "Apple Computer", "Apple IIgs (ROM03)", MACHINE_SUPPORTS_SAVE ) COMP( 198?, apple2gsr3p, apple2gs, 0, apple2gs, apple2gs, 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 )