summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author arbee <rb6502@users.noreply.github.com>2025-02-10 22:46:29 -0500
committer arbee <rb6502@users.noreply.github.com>2025-02-10 22:46:29 -0500
commitf2ba762e0a39c294ff60912fc30ec1c50925d15c (patch)
tree3c9bd71e47352b1d471eb4ad1c5ad5602fba9379 /src
parent21e5da0532ded429b30d02a8fe60ae40ae6dd37b (diff)
apple/macpwrbk030.cpp: Moved macpd210 out to new driver for MSC-based portables. [R. Belmont]
apple/gsc.cpp: Split Apple Gray Scale Controller (remarked C&T 65210) to its own device. [R. Belmont] apple/csc.cpp: Initial Apple Color Screen Controller (remarked C&T 65220) support. [R. Belmont] apple/msc.cpp: Initial Apple Main System Controller and MSC II support. [R. Belmont] m6805/m68hc05pge.cpp: Initial support for the Apple/Motorola "PG&E" microcontroller. [R. Belmont] apple/macpwrbkmsc.cpp: New driver for MSC and MSC II-based Mac PowerBooks and PowerBook Duos. [R. Belmont] Systems promoted to working --------------------------- Apple Macintosh PowerBook Duo 210 [R. Belmont] New working systems ------------------- Apple Macintosh PowerBook Duo 270c [R. Belmont] Apple Macintosh PowerBook Duo 280 [R. Belmont] New working clones ------------------ Apple Macintosh PowerBook Duo 230 [R. Belmont] Apple Macintosh PowerBook Duo 250 [R. Belmont] Apple Macintosh PowerBook Duo 280c [R. Belmont]
Diffstat (limited to 'src')
-rw-r--r--src/devices/cpu/m6805/m68hc05pge.cpp926
-rw-r--r--src/devices/cpu/m6805/m68hc05pge.h150
-rw-r--r--src/devices/machine/6522via.h5
-rw-r--r--src/mame/apple/csc.cpp340
-rw-r--r--src/mame/apple/csc.h55
-rw-r--r--src/mame/apple/gsc.cpp176
-rw-r--r--src/mame/apple/gsc.h51
-rw-r--r--src/mame/apple/macpwrbk030.cpp188
-rw-r--r--src/mame/apple/macpwrbkmsc.cpp937
-rw-r--r--src/mame/apple/msc.cpp508
-rw-r--r--src/mame/apple/msc.h128
-rw-r--r--src/mame/apple/pseudovia.cpp11
-rw-r--r--src/mame/apple/pseudovia.h6
-rw-r--r--src/mame/mame.lst7
14 files changed, 3318 insertions, 170 deletions
diff --git a/src/devices/cpu/m6805/m68hc05pge.cpp b/src/devices/cpu/m6805/m68hc05pge.cpp
new file mode 100644
index 00000000000..880540ffd03
--- /dev/null
+++ b/src/devices/cpu/m6805/m68hc05pge.cpp
@@ -0,0 +1,926 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*
+ Motorola M68HC05PGE semi-custom "PG&E" 68HC05 Power Management Unit for Apple
+ Emulation by R. Belmont
+
+ Named for the electric utility in Cupertino, Pacific Gas & Electric.
+ Early versions of this chip had screened artwork of a power station with
+ lightning bolts, see the PCB photo at:
+ https://www.dobreprogramy.pl/@macminik/powerbook-duo-best-of-both-worlds,blog,39291
+
+ This is a 160-pin part with a lot of feature blocks. Most of the components appear
+ in other 68HC05 variants so I have included references to HC05 parts with similar
+ or identical versions of that functionality.
+
+ - 512 bytes of internal ROM, which can be banked out
+ - Eleven 8-bit GPIO ports A, B, C, D, E, F, G, H, J, K, and L
+ - Four PWM (pulse width modulation) analog outputs (68HC05F32)
+ - One PLM (pulse length modulation) analog output (68HC05B4)
+ - Four ADC inputs (68HC05B4)
+ - An SPI interface (68HC05F32)
+ - A hardware 10x8 keyboard matrix scanner
+ - A 2-axis hardware quadrature decoder for a mouse or trackball
+ - Fixed-interval one second and 5.86 millisecond timers
+ - A custom RTC that counts a uint32 number of seconds in the classic Mac/IIgs format
+ - A custom Apple Desktop Bus modem
+*/
+
+#include "emu.h"
+#include "m68hc05pge.h"
+#include "m6805defs.h"
+#include "6805dasm.h"
+
+#define LOG_ADB (1U << 1)
+#define LOG_IRQ (1U << 2)
+#define LOG_PWM (1U << 3)
+#define LOG_PLM (1U << 4)
+#define LOG_SPI (1U << 5)
+#define LOG_SPI_VERBOSE (1U << 6)
+#define LOG_ADC (1U << 7)
+
+#define VERBOSE (0)
+
+#include "logmacro.h"
+
+DEFINE_DEVICE_TYPE(M68HC05PGE, m68hc05pge_device, "m68hc05pge", "Motorola M68HC05PGE")
+
+static constexpr int M68HC05PGE_INT_IRQ = M6805_IRQ_LINE; // external IRQ line
+static constexpr int M68HC05PGE_INT_ADB = M68HC05PGE_INT_IRQ + 1; // ADB interrupt
+static constexpr int M68HC05PGE_INT_RTI = M68HC05PGE_INT_IRQ + 2; // real-time (5.86 ms) interrupt
+static constexpr int M68HC05PGE_INT_CPI = M68HC05PGE_INT_IRQ + 3; // one second interrupt
+static constexpr int M68HC05PGE_INT_SPI = M68HC05PGE_INT_IRQ + 4; // SPI interrupt
+static constexpr int M68HC05PGE_INT_KEY = M68HC05PGE_INT_IRQ + 5; // keyboard scanner interrupt
+
+static constexpr u8 CSCR_SRAM_CS = 5; // chip select for $8000-$FFFF SRAM
+static constexpr u8 CSCR_RESET = 0;
+
+static constexpr u8 OPTION_INTROM = 7; // internal ROM at fe00, else external address bus
+static constexpr u8 OPTION_EXTBUS = 6; // tri-state external address bus, else ext. bus enabled
+static constexpr u8 OPTION_IRQSENSE = 1; // IRQ is edge-triggered, else level triggered
+static constexpr u8 OPTION_RESET = (1<<OPTION_INTROM);
+
+static constexpr u8 SPCR_IRQ_ENABLE = 7; // IRQ enabled
+static constexpr u8 SPCR_ENABLE = 6; // SPI mode enabled
+static constexpr u8 SPCR_MASTER = 4; // SPI master mode if set, slave otherwise
+static constexpr u8 SPCR_POLARITY = 3; // SPI clock polarity: 0 = clock starts low, 1 = clock starts high
+static constexpr u8 SPCR_PHASE = 2; // SPI phase: 0 = sampled on the rising edge, 1 = sampled on the falling edge
+
+static constexpr u8 SPSR_IRQ_FLAG = 7; // SPI interrupt flag: 1 = interrupt would occur if IRQ_ENABLE in SPCR is set
+
+static constexpr u8 CPICSR_586_IRQ_FLAG = 7; // 5.86ms interrupt flag
+static constexpr u8 CPICSR_ONESEC_IRQ_FLAG = 6; // 1 second interrupt flag
+static constexpr u8 CPICSR_586_IRQ_ENABLE = 5; // 5.86ms interrupt enable
+static constexpr u8 CPICSR_ONESEC_IRQ_ENABLE = 4; // 1 second interrupt enable
+
+static constexpr u8 ADCSR_CONV_COMPLETE = 7; // ADC conversion complete
+static constexpr u8 ADCSR_START_CONV = 5; // ADC start conversion
+static constexpr u8 ADCSR_CHANNEL_MASK = 0x0f; // ADC channel mask for ADCSR
+
+static constexpr u8 ADBXR_TDRE = 7; // ADB transmitter empty
+static constexpr u8 ADBXR_TC = 6; // ADB transmit complete
+static constexpr u8 ADBXR_SRQ = 5; // ADB got a Service ReQuest
+static constexpr u8 ADBXR_RDRF = 3; // ADB receiver full
+static constexpr u8 ADBXR_BRST = 0; // ADB send reset
+static constexpr u8 ADBXR_IRQS ((1 << ADBXR_TDRE) | (1 << ADBXR_TC) | (1 << ADBXR_SRQ) | (1 << ADBXR_RDRF));
+
+static constexpr int s_spi_divisors[4] = {2, 4, 16, 32};
+
+ROM_START( m68hc05pge )
+ ROM_REGION(0x200, "pge", 0)
+ ROM_LOAD( "pge_boot.bin", 0x000000, 0x000200, CRC(62d4dfed) SHA1(79dc721651bf47aec53f57885779c84c4781761d) )
+ROM_END
+
+m68hc05pge_device::m68hc05pge_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int addrbits, address_map_constructor internal_map) :
+ m6805_base_device(mconfig, tag, owner, clock, type, {s_hc_b_ops, s_hc_cycles, 16, 0x00ff, 0x0040, 0xfffc}),
+ device_nvram_interface(mconfig, *this),
+ m_program_config("program", ENDIANNESS_BIG, 8, addrbits, 0, internal_map),
+ m_internal_ram(*this, "internal_ram"),
+ m_introm(*this, "bankfe00"),
+ m_read_tbX(*this, 0),
+ m_read_tbY(*this, 0),
+ m_read_tbB(*this, 0),
+ m_read_p(*this, 0),
+ m_write_p(*this),
+ m_ad_in(*this, 0),
+ m_pwm_out(*this),
+ write_spi_mosi(*this),
+ write_spi_clock(*this),
+ m_pll_ctrl(0), m_timer_ctrl(0), m_onesec(0),
+ m_option(OPTION_RESET),
+ m_cscr(CSCR_RESET),
+ m_spi_in(0), m_spi_out(0),
+ m_spi_bit(0), m_spi_clock(0), m_spi_miso(0),
+ m_spcr(0), m_spsr(0),
+ m_cpicsr(0),
+ m_adcsr(0),
+ m_adbcr(0), m_adbsr(1 << ADBXR_TDRE), m_adbdr(0),
+ m_tbcs(0),
+ m_pwmacr(0), m_pwma0(0), m_pwma1(0),
+ m_pwmbcr(0), m_pwmb0(0), m_pwmb1(0),
+ m_plmcr(0), m_plmt1(0), m_plmt2(0)
+{
+ std::fill(std::begin(m_pullups), std::end(m_pullups), 0);
+}
+
+m68hc05pge_device::m68hc05pge_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ m68hc05pge_device(mconfig, M68HC05PGE, tag, owner, clock, 16, address_map_constructor(FUNC(m68hc05pge_device::m68hc05pge_map), this))
+{
+}
+
+void m68hc05pge_device::device_start()
+{
+ m6805_base_device::device_start();
+
+ save_item(NAME(m_ports));
+ save_item(NAME(m_ddrs));
+ save_item(NAME(m_pll_ctrl));
+ save_item(NAME(m_timer_ctrl));
+ save_item(NAME(m_onesec));
+ save_item(NAME(m_option));
+ save_item(NAME(m_cscr));
+ save_item(NAME(m_spi_in));
+ save_item(NAME(m_spi_out));
+ save_item(NAME(m_spi_bit));
+ save_item(NAME(m_spi_clock));
+ save_item(NAME(m_spi_miso));
+ save_item(NAME(m_spcr));
+ save_item(NAME(m_spsr));
+ save_item(NAME(m_cpicsr));
+ save_item(NAME(m_adcsr));
+ save_item(NAME(m_adbcr));
+ save_item(NAME(m_adbsr));
+ save_item(NAME(m_adbdr));
+ save_item(NAME(m_tbcs));
+ save_item(NAME(m_pwmacr));
+ save_item(NAME(m_pwma0));
+ save_item(NAME(m_pwma1));
+ save_item(NAME(m_pwmbcr));
+ save_item(NAME(m_pwmb0));
+ save_item(NAME(m_pwmb1));
+ save_item(NAME(m_plmcr));
+ save_item(NAME(m_plmt1));
+ save_item(NAME(m_plmt2));
+
+ m_seconds_timer = timer_alloc(FUNC(m68hc05pge_device::seconds_tick), this);
+ m_cpi_timer = timer_alloc(FUNC(m68hc05pge_device::cpi_tick), this);
+ m_spi_timer = timer_alloc(FUNC(m68hc05pge_device::spi_tick), this);
+ m_adb_timer = timer_alloc(FUNC(m68hc05pge_device::adb_tick), this);
+
+ system_time systime;
+ struct tm cur_time, macref;
+ machine().current_datetime(systime);
+
+ cur_time.tm_sec = systime.local_time.second;
+ cur_time.tm_min = systime.local_time.minute;
+ cur_time.tm_hour = systime.local_time.hour;
+ cur_time.tm_mday = systime.local_time.mday;
+ cur_time.tm_mon = systime.local_time.month;
+ cur_time.tm_year = systime.local_time.year - 1900;
+ cur_time.tm_isdst = 0;
+
+ macref.tm_sec = 0;
+ macref.tm_min = 0;
+ macref.tm_hour = 0;
+ macref.tm_mday = 1;
+ macref.tm_mon = 0;
+ macref.tm_year = 4;
+ macref.tm_isdst = 0;
+ const u32 ref = (u32)mktime(&macref);
+ m_rtc = (u32)((u32)mktime(&cur_time) - ref);
+}
+
+void m68hc05pge_device::device_reset()
+{
+ option_w(OPTION_RESET);
+ cscr_w(CSCR_RESET);
+
+ m6805_base_device::device_reset();
+
+ // all ports reset to input on startup
+ memset(m_ports, 0, sizeof(m_ports));
+ memset(m_ddrs, 0, sizeof(m_ddrs));
+
+ // on reset the transmitter is empty
+ m_adbsr = (1 << ADBXR_TDRE);
+
+ // start the 1 second timer
+ m_seconds_timer->adjust(attotime::from_hz(1), 0, attotime::from_hz(1));
+ // and the 5.86ms timer (5.86ms = 5860 uSec)
+ m_cpi_timer->adjust(attotime::from_usec(5860), 0, attotime::from_usec(5860));
+}
+
+device_memory_interface::space_config_vector m68hc05pge_device::memory_space_config() const
+{
+ return space_config_vector {
+ std::make_pair(AS_PROGRAM, &m_program_config)
+ };
+}
+
+void m68hc05pge_device::interrupt_vector()
+{
+ for (int irq = M68HC05PGE_INT_IRQ; irq <= M68HC05PGE_INT_KEY; irq++)
+ {
+ if (BIT(m_pending_interrupts, irq))
+ {
+ LOGMASKED(LOG_IRQ, "Taking IRQ %d vector %04x\n", irq, 0xfffa - (irq << 1));
+ m_pending_interrupts &= ~(1 << irq);
+ rm16<true>(0xfffa - (irq << 1), m_pc);
+ return;
+ }
+ }
+}
+
+u64 m68hc05pge_device::execute_clocks_to_cycles(u64 clocks) const noexcept
+{
+ return (clocks + 1) / 2;
+}
+
+u64 m68hc05pge_device::execute_cycles_to_clocks(u64 cycles) const noexcept
+{
+ return cycles * 2;
+}
+
+std::unique_ptr<util::disasm_interface> m68hc05pge_device::create_disassembler()
+{
+ return std::make_unique<m68hc05_disassembler>();
+}
+
+void m68hc05pge_device::send_port(u8 offset, u8 data)
+{
+ m_write_p[offset](data);
+}
+
+u8 m68hc05pge_device::ports_r(offs_t offset)
+{
+ u8 incoming = m_read_p[offset]();
+
+ // apply data direction registers
+ incoming &= (m_ddrs[offset] ^ 0xff);
+ // OR in ddr-masked version of port writes
+ incoming |= (m_ports[offset] & m_ddrs[offset]);
+
+ return incoming;
+}
+
+void m68hc05pge_device::ports_w(offs_t offset, u8 data)
+{
+ send_port(offset, (data & m_ddrs[offset]) | (m_pullups[offset] & ~m_ddrs[offset]));
+ m_ports[offset] = data;
+}
+
+u8 m68hc05pge_device::ddrs_r(offs_t offset)
+{
+ return m_ddrs[offset];
+}
+
+void m68hc05pge_device::ddrs_w(offs_t offset, u8 data)
+{
+ send_port(offset, (m_ports[offset] & data) | (m_pullups[offset] & ~data));
+ m_ddrs[offset] = data;
+}
+
+u8 m68hc05pge_device::pll_r()
+{
+ return m_pll_ctrl;
+}
+
+void m68hc05pge_device::pll_w(u8 data)
+{
+ if (m_pll_ctrl != data)
+ {
+ static const int clocks[4] = {524288, 1048576, 2097152, 4194304};
+ LOG("PLL ctrl: clock %d TCS:%d BCS:%d AUTO:%d BWC:%d PLLON:%d (PC=%x)\n", clocks[data & 3],
+ (data & 0x80) ? 1 : 0,
+ (data & 0x40) ? 1 : 0,
+ (data & 0x20) ? 1 : 0,
+ (data & 0x10) ? 1 : 0,
+ (data & 0x08) ? 1 : 0, pc());
+ }
+
+ m_pll_ctrl = data;
+}
+
+void m68hc05pge_device::execute_set_input(int inputnum, int state)
+{
+ if (state == CLEAR_LINE)
+ {
+ m_pending_interrupts &= ~(1 << inputnum);
+ }
+ else
+ {
+ m_pending_interrupts |= (1 << inputnum);
+ }
+}
+
+// fires every 1 second
+TIMER_CALLBACK_MEMBER(m68hc05pge_device::seconds_tick)
+{
+ m_rtc++;
+ m_cpicsr |= (1 << CPICSR_ONESEC_IRQ_FLAG);
+ if (BIT(m_cpicsr, CPICSR_ONESEC_IRQ_ENABLE))
+ {
+ set_input_line(M68HC05PGE_INT_CPI, ASSERT_LINE);
+ }
+}
+
+// fires every 5.86ms
+TIMER_CALLBACK_MEMBER(m68hc05pge_device::cpi_tick)
+{
+ m_cpicsr |= (1 << CPICSR_586_IRQ_FLAG);
+ if (BIT(m_cpicsr, CPICSR_586_IRQ_ENABLE))
+ {
+ set_input_line(M68HC05PGE_INT_RTI, ASSERT_LINE);
+ }
+}
+
+const tiny_rom_entry *m68hc05pge_device::device_rom_region() const
+{
+ return ROM_NAME(m68hc05pge);
+}
+
+void m68hc05pge_device::m68hc05pge_map(address_map &map)
+{
+ map(0x0000, 0x0003).rw(FUNC(m68hc05pge_device::ports_r), FUNC(m68hc05pge_device::ports_w));
+ map(0x0004, 0x0006).rw(FUNC(m68hc05pge_device::ddrs_r), FUNC(m68hc05pge_device::ddrs_w));
+ map(0x0007, 0x0007).rw(FUNC(m68hc05pge_device::pll_r), FUNC(m68hc05pge_device::pll_w));
+ map(0x000a, 0x000c).rw(FUNC(m68hc05pge_device::spi_r), FUNC(m68hc05pge_device::spi_w));
+ map(0x000d, 0x000d).rw(FUNC(m68hc05pge_device::cpicsr_r), FUNC(m68hc05pge_device::cpicsr_w));
+ map(0x000e, 0x000e).rw(FUNC(m68hc05pge_device::cscr_r), FUNC(m68hc05pge_device::cscr_w));
+ map(0x000f, 0x000f).rw(FUNC(m68hc05pge_device::kcsr_r), FUNC(m68hc05pge_device::kcsr_w));
+ map(0x0014, 0x0016).rw(FUNC(m68hc05pge_device::trackball_r), FUNC(m68hc05pge_device::trackball_w));
+ map(0x0018, 0x001a).rw(FUNC(m68hc05pge_device::adb_r), FUNC(m68hc05pge_device::adb_w));
+ map(0x001c, 0x001c).rw(FUNC(m68hc05pge_device::option_r), FUNC(m68hc05pge_device::option_w));
+ map(0x001d, 0x001e).rw(FUNC(m68hc05pge_device::adc_r), FUNC(m68hc05pge_device::adc_w));
+ map(0x0020, 0x002c).rw(FUNC(m68hc05pge_device::ports_high_r), FUNC(m68hc05pge_device::ports_high_w));
+ map(0x002d, 0x0032).rw(FUNC(m68hc05pge_device::pwm_r), FUNC(m68hc05pge_device::pwm_w));
+ map(0x0034, 0x0036).rw(FUNC(m68hc05pge_device::plm_r), FUNC(m68hc05pge_device::plm_w));
+ map(0x0038, 0x003b).rw(FUNC(m68hc05pge_device::rtc_r), FUNC(m68hc05pge_device::rtc_w));
+ map(0x0040, 0x03ff).ram().share(m_internal_ram); // internal RAM
+ map(0x0ff0, 0x0ff0).nopw(); // watchdog reset (period not known)
+
+ map(0x8000, 0xffff).view(m_introm);
+ m_introm[0](0x8000, 0xffff).rw(FUNC(m68hc05pge_device::sram_r), FUNC(m68hc05pge_device::sram_w));
+ m_introm[1](0x8000, 0xffff).rw(FUNC(m68hc05pge_device::sram_r), FUNC(m68hc05pge_device::sram_w));
+ m_introm[1](0xfe00, 0xffff).rom().region("pge", 0);
+}
+
+u8 m68hc05pge_device::sram_r(offs_t offset)
+{
+ if (BIT(m_cscr, CSCR_SRAM_CS) && !BIT(m_option, OPTION_EXTBUS))
+ {
+ return m_sram[offset];
+ }
+
+ return 0xff;
+}
+
+void m68hc05pge_device::sram_w(offs_t offset, u8 data)
+{
+ if (BIT(m_cscr, CSCR_SRAM_CS) && !BIT(m_option, OPTION_EXTBUS))
+ {
+ m_sram[offset] = data;
+ }
+}
+
+u8 m68hc05pge_device::spi_r(offs_t offset)
+{
+ switch (offset)
+ {
+ case 0:
+ return m_spcr;
+
+ case 1:
+ return m_spsr;
+
+ case 2:
+ if (!machine().side_effects_disabled())
+ {
+ LOGMASKED(LOG_SPI, "SPI got %02x\n", m_spi_in);
+ if (BIT(m_spsr, SPSR_IRQ_FLAG))
+ {
+ set_input_line(M68HC05PGE_INT_SPI, CLEAR_LINE);
+ }
+ }
+ return m_spi_in;
+ }
+
+ return 0;
+}
+
+void m68hc05pge_device::spi_w(offs_t offset, u8 data)
+{
+ switch (offset)
+ {
+ case 0:
+ m_spcr = data;
+ m_spi_clock = BIT(m_spcr, SPCR_POLARITY);
+ write_spi_clock(m_spi_clock);
+ break;
+
+ case 2:
+ if (!BIT(m_spcr, SPCR_MASTER))
+ {
+ logerror("68HC05PGE: SPI slave mode not implemented\n");
+ }
+
+ if (BIT(m_spsr, SPSR_IRQ_FLAG))
+ {
+ set_input_line(M68HC05PGE_INT_SPI, CLEAR_LINE);
+ }
+ m_spsr &= ~(1 << SPSR_IRQ_FLAG);
+
+ m_spi_clock = BIT(m_spcr, SPCR_POLARITY);
+ write_spi_clock(m_spi_clock);
+
+ m_spi_out = data;
+ m_spi_in = 0;
+ LOGMASKED(LOG_SPI, "SPI: sending %02x, clock rate %d\n", data, clock() / s_spi_divisors[m_spcr & 3]);
+ m_spi_bit = 16;
+ m_spi_timer->adjust(attotime::from_hz(clock() / s_spi_divisors[m_spcr & 3]));
+ break;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(m68hc05pge_device::spi_tick)
+{
+ LOGMASKED(LOG_SPI_VERBOSE, "spi_tick: bit %d\n", m_spi_bit);
+
+ // first clock edge of a bit
+ if (!(m_spi_bit & 1))
+ {
+ // phase = 0, set up the output data before sending the first clock edge of the bit
+ if (!BIT(m_spcr, SPCR_PHASE))
+ {
+ write_spi_mosi(BIT(m_spi_out, 7));
+ m_spi_out <<= 1;
+ }
+
+ write_spi_clock(m_spi_clock ^ 1);
+
+ // phase = 0, input bit became valid on that first edge
+ if (!BIT(m_spcr, SPCR_PHASE))
+ {
+ m_spi_in <<= 1;
+ m_spi_in |= m_spi_miso;
+ LOGMASKED(LOG_SPI_VERBOSE, "PGE: MISO %d, shift %02x (PH0 POL%d)\n", m_spi_miso, m_spi_in, BIT(m_spcr, SPCR_POLARITY));
+ }
+ }
+ else // second clock edge of the bit
+ {
+ // phase = 1, the output bit must be valid before this clock edge
+ if (BIT(m_spcr, SPCR_PHASE))
+ {
+ write_spi_mosi(BIT(m_spi_out, 7));
+ m_spi_out <<= 1;
+ }
+
+ write_spi_clock(m_spi_clock);
+
+ // phase = 1, input bit became valid on this second edge
+ if (BIT(m_spcr, SPCR_PHASE))
+ {
+ m_spi_in <<= 1;
+ m_spi_in |= m_spi_miso;
+ LOGMASKED(LOG_SPI_VERBOSE, "PGE: MISO %d, shift %02x (PH1 POL%d)\n", m_spi_miso, m_spi_in, BIT(m_spcr, SPCR_POLARITY));
+ }
+ }
+
+ m_spi_bit--;
+ if (m_spi_bit > 0)
+ {
+ m_spi_timer->adjust(attotime::from_hz(clock() / s_spi_divisors[m_spcr & 3]));
+ }
+ else
+ {
+ m_spsr |= (1 << SPSR_IRQ_FLAG);
+ if (BIT(m_spcr, SPCR_IRQ_ENABLE))
+ {
+ set_input_line(M68HC05PGE_INT_SPI, ASSERT_LINE);
+ }
+ }
+}
+
+u8 m68hc05pge_device::cpicsr_r()
+{
+ return m_cpicsr;
+}
+
+void m68hc05pge_device::cpicsr_w(u8 data)
+{
+ m_cpicsr = data;
+ if (!BIT(data, CPICSR_ONESEC_IRQ_FLAG))
+ {
+ set_input_line(M68HC05PGE_INT_CPI, CLEAR_LINE);
+ }
+ if (!BIT(data, CPICSR_586_IRQ_FLAG))
+ {
+ set_input_line(M68HC05PGE_INT_RTI, CLEAR_LINE);
+ }
+}
+
+u8 m68hc05pge_device::cscr_r()
+{
+ return m_cscr;
+}
+
+void m68hc05pge_device::cscr_w(u8 data)
+{
+ m_cscr = data;
+}
+
+u8 m68hc05pge_device::kcsr_r()
+{
+ return 0;
+}
+
+void m68hc05pge_device::kcsr_w(u8 data)
+{
+// printf("%02x to KCSR\n", data);
+}
+
+u8 m68hc05pge_device::trackball_r(offs_t offset)
+{
+ switch (offset)
+ {
+ case 0: // TBCS
+ return (m_read_tbB() << 7) | m_tbcs; // button not pressed
+ break;
+
+ case 1: // signed X delta
+ return m_read_tbX();
+
+ case 2: // signed Y delta
+ return m_read_tbY();
+ }
+
+ return 0;
+}
+
+void m68hc05pge_device::trackball_w(offs_t offset, u8 data)
+{
+ if (offset == 0)
+ {
+ m_tbcs = data & 0x7f;
+ }
+}
+
+u8 m68hc05pge_device::adb_r(offs_t offset)
+{
+ switch (offset)
+ {
+ case 0:
+ return m_adbcr;
+
+ case 1:
+ return m_adbsr;
+
+ case 2:
+ return m_adbdr;
+ }
+
+ return 0;
+}
+
+void m68hc05pge_device::adb_w(offs_t offset, u8 data)
+{
+ //printf("%02x to ADB @ %d\n", data, offset);
+ switch (offset)
+ {
+ case 0:
+ //printf("%02x to ADBCR, previous %02x\n", data, m_adbcr);
+ // if we're clearing transmit complete, set transmitter empty
+ if (BIT(m_adbcr, ADBXR_TC) && !BIT(data, ADBXR_TC))
+ {
+ //printf("ADB enabling transmitter empty\n");
+ m_adbsr |= (1 << ADBXR_TDRE);
+ }
+
+ // if we're clearing transmitter empty, kick the timer for transmitter complete
+ if (BIT(m_adbcr, ADBXR_TDRE) && !BIT(data, ADBXR_TDRE))
+ {
+ //printf("ADB setting completion timer\n");
+ m_adb_timer->adjust(attotime::from_usec(50), 1);
+ }
+
+ m_adbcr = data;
+ if (m_adbsr & m_adbcr & ADBXR_IRQS)
+ {
+ set_input_line(M68HC05PGE_INT_ADB, ASSERT_LINE);
+ }
+ else
+ {
+ set_input_line(M68HC05PGE_INT_ADB, CLEAR_LINE);
+ }
+ break;
+
+ case 1:
+ m_adbsr = data;
+ if (m_adbsr & m_adbcr & ADBXR_IRQS)
+ {
+ set_input_line(M68HC05PGE_INT_ADB, ASSERT_LINE);
+ }
+ else
+ {
+ set_input_line(M68HC05PGE_INT_ADB, CLEAR_LINE);
+ }
+ break;
+
+ case 2:
+ m_adbdr = data;
+ LOGMASKED(LOG_ADB, "ADB sending %02x\n", data);
+ m_adbsr &= ~((1 << ADBXR_TDRE) | (1 << ADBXR_TC));
+ m_adb_timer->adjust(attotime::from_usec(1200), 0);
+ break;
+ }
+}
+
+TIMER_CALLBACK_MEMBER(m68hc05pge_device::adb_tick)
+{
+ switch (param)
+ {
+ case 0: // byte transmitted, trigger transmitter empty
+ m_adbsr |= (1 << ADBXR_TDRE);
+ break;
+
+ case 1:
+ m_adbsr |= (1 << ADBXR_TC);
+ break;
+ }
+
+ if (m_adbsr & m_adbcr & ADBXR_IRQS)
+ {
+ set_input_line(M68HC05PGE_INT_ADB, ASSERT_LINE);
+ }
+}
+
+u8 m68hc05pge_device::option_r()
+{
+ return m_option;
+}
+
+void m68hc05pge_device::option_w(u8 data)
+{
+ LOGMASKED(LOG_GENERAL, "%02x to OPTION\n", data);
+ m_option = data;
+
+ m_introm.select(BIT(data, OPTION_INTROM));
+}
+
+u8 m68hc05pge_device::adc_r(offs_t offset)
+{
+ if (!offset)
+ {
+ LOGMASKED(LOG_ADC, "ADC read ch %d\n", m_adcsr & ADCSR_CHANNEL_MASK);
+ return m_ad_in[m_adcsr & ADCSR_CHANNEL_MASK]();
+ }
+
+ return m_adcsr;
+}
+
+void m68hc05pge_device::adc_w(offs_t offset, u8 data)
+{
+ LOGMASKED(LOG_ADC, "%02x to ADC @ %d\n", data, offset);
+ if (offset)
+ {
+ m_adcsr = data;
+
+ if (BIT(m_adcsr, ADCSR_START_CONV))
+ {
+ m_adcsr |= (1 << ADCSR_CONV_COMPLETE);
+ }
+ }
+}
+
+u8 m68hc05pge_device::ports_high_r(offs_t offset)
+{
+ switch (offset)
+ {
+ case 0: // PORTE
+ case 2: // PORTF
+ case 4: // PORTG
+ case 6: // PORTH
+ case 8: // PORTJ
+ return ports_r((offset >> 1) + PGE_PORTE);
+
+ case 0xa: // PORTL
+ return ports_r(PGE_PORTL);
+
+ case 0xc: // PORTK
+ return ports_r(PGE_PORTK);
+
+ case 1: // DDRE
+ case 3: // DDRF
+ case 5: // DDRG
+ case 7: // DDRH
+ case 9: // DDRJ
+ return m_ddrs[(offset >> 1) + PGE_PORTE];
+
+ case 0xb: // DDRL
+ return m_ddrs[PGE_PORTL];
+ }
+
+ return 0;
+}
+
+void m68hc05pge_device::ports_high_w(offs_t offset, u8 data)
+{
+ switch (offset)
+ {
+ case 0: // PORTE
+ case 2: // PORTF
+ case 4: // PORTG
+ case 6: // PORTH
+ case 8: // PORTJ
+ ports_w((offset >> 1) + PGE_PORTE, data);
+ break;
+
+ case 0xa: // PORTL
+ ports_w(PGE_PORTL, data);
+ break;
+
+ case 0xc: // PORTK
+ ports_w(PGE_PORTK, data);
+ break;
+
+ case 1: // DDRE
+ case 3: // DDRF
+ case 5: // DDRG
+ case 7: // DDRH
+ case 9: // DDRJ
+ ddrs_w((offset >> 1) + PGE_PORTE, data);
+ break;
+
+ case 0xb: // DDRL
+ ddrs_w(PGE_PORTL, data);
+ break;
+ }
+}
+
+u8 m68hc05pge_device::pwm_r(offs_t offset)
+{
+ switch (offset)
+ {
+ case 0:
+ return m_pwmacr;
+
+ case 1:
+ return m_pwma0;
+
+ case 2:
+ return m_pwma1;
+
+ case 3:
+ return m_pwmbcr;
+
+ case 4:
+ return m_pwmb0;
+
+ case 5:
+ return m_pwmb1;
+ }
+
+ return 0;
+}
+
+void m68hc05pge_device::pwm_w(offs_t offset, u8 data)
+{
+ LOGMASKED(LOG_PWM, "%02x to PWM @ %d\n", data, offset);
+ switch (offset)
+ {
+ case 0: // PWMACR
+ m_pwmacr = data;
+ break;
+
+ case 1: // PWMA0
+ LOGMASKED(LOG_PWM, "%02x to PWMA0\n", data);
+ m_pwma0 = data;
+ m_pwm_out[PGE_PWMA0](data);
+ break;
+
+ case 2: // PWMA1
+ LOGMASKED(LOG_PWM, "%02x to PWMA1\n", data);
+ m_pwma1 = data;
+ m_pwm_out[PGE_PWMA1](data);
+ break;
+
+ case 3: // PWMBCR
+ m_pwmbcr = data;
+ break;
+
+ case 4: // PWMB0
+ LOGMASKED(LOG_PWM, "%02x to PWMB0\n", data);
+ m_pwmb0 = data;
+ m_pwm_out[PGE_PWMB0](data);
+ break;
+
+ case 5: // PWMB1
+ LOGMASKED(LOG_PWM, "%02x to PWMB1\n", data);
+ m_pwmb1 = data;
+ m_pwm_out[PGE_PWMB1](data);
+ break;
+ }
+}
+
+u8 m68hc05pge_device::plm_r(offs_t offset)
+{
+ switch (offset)
+ {
+ case 0:
+ return m_plmcr;
+
+ case 1:
+ return m_plmt1;
+
+ case 2:
+ return m_plmt2;
+ }
+
+ return 0;
+}
+
+void m68hc05pge_device::plm_w(offs_t offset, u8 data)
+{
+ LOGMASKED(LOG_PLM, "%02x to PLM @ %d\n", data, offset);
+ switch (offset)
+ {
+ case 0: // PLMCR
+ m_plmcr = data;
+ break;
+
+ case 1: // PLM timer 1
+ m_plmt1 = data;
+ break;
+
+ case 2: // PLM timer 2
+ m_plmt2 = data;
+ break;
+ }
+}
+
+u8 m68hc05pge_device::rtc_r(offs_t offset)
+{
+ switch (offset)
+ {
+ case 0:
+ return m_rtc >> 24;
+
+ case 1:
+ return (m_rtc >> 16) & 0xff;
+
+ case 2:
+ return (m_rtc >> 8) & 0xff;
+
+ case 3:
+ return m_rtc & 0xff;
+ }
+
+ return 0;
+}
+
+void m68hc05pge_device::rtc_w(offs_t offset, u8 data)
+{
+ switch (offset)
+ {
+ case 0:
+ m_rtc &= ~0xff000000;
+ m_rtc |= data << 24;
+ break;
+
+ case 1:
+ m_rtc &= ~0x00ff0000;
+ m_rtc |= data << 16;
+ break;
+
+ case 2:
+ m_rtc &= ~0x0000ff00;
+ m_rtc |= data << 8;
+ break;
+
+ case 3:
+ m_rtc &= ~0x000000ff;
+ m_rtc |= data;
+ break;
+ }
+}
+
+void m68hc05pge_device::nvram_default()
+{
+}
+
+bool m68hc05pge_device::nvram_read(util::read_stream &file)
+{
+ auto const [err, actual] = read(file, m_internal_ram, 0x3c0);
+ auto const [err2, actual2] = read(file, m_sram, 0x8000);
+
+ m_internal_ram[0x91 - 0x40] = 0; // clear power flag so the boot ROM does a cold boot
+
+ return !err && !err2;
+}
+
+bool m68hc05pge_device::nvram_write(util::write_stream &file)
+{
+ auto const [err, actual] = write(file, m_internal_ram, 0x3c0);
+ auto const [err2, actual2] = write(file, m_sram, 0x8000);
+ return !err && !err2;
+}
diff --git a/src/devices/cpu/m6805/m68hc05pge.h b/src/devices/cpu/m6805/m68hc05pge.h
new file mode 100644
index 00000000000..bd29b19057b
--- /dev/null
+++ b/src/devices/cpu/m6805/m68hc05pge.h
@@ -0,0 +1,150 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+#ifndef MAME_CPU_M6805_M68HC05PGE_H
+#define MAME_CPU_M6805_M68HC05PGE_H
+
+#pragma once
+
+#include "emu.h"
+#include "m6805.h"
+
+class m68hc05pge_device : public m6805_base_device, public device_nvram_interface
+{
+public:
+ const address_space_config m_program_config;
+
+ static constexpr int PGE_PORTA = 0;
+ static constexpr int PGE_PORTB = 1;
+ static constexpr int PGE_PORTC = 2;
+ static constexpr int PGE_PORTD = 3;
+ static constexpr int PGE_PORTE = 4;
+ static constexpr int PGE_PORTF = 5;
+ static constexpr int PGE_PORTG = 6;
+ static constexpr int PGE_PORTH = 7;
+ static constexpr int PGE_PORTJ = 8;
+ static constexpr int PGE_PORTK = 9;
+ static constexpr int PGE_PORTL = 10;
+
+ static constexpr int PGE_PWMA0 = 0;
+ static constexpr int PGE_PWMA1 = 1;
+ static constexpr int PGE_PWMB0 = 2;
+ static constexpr int PGE_PWMB1 = 3;
+
+ m68hc05pge_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+
+ auto read_tbX() { return m_read_tbX.bind(); } // trackball X
+ auto read_tbY() { return m_read_tbY.bind(); } // trackball Y
+ auto read_tbB() { return m_read_tbB.bind(); } // trackball button
+ template <std::size_t Bit> auto read_p() { return m_read_p[Bit].bind(); }
+ template <std::size_t Bit> auto write_p() { return m_write_p[Bit].bind(); }
+ template <std::size_t Bit> void set_pullups(u8 mask) { m_pullups[Bit] = mask; }
+
+ template <std::size_t ad_port> auto ad_in() { return m_ad_in[ad_port].bind(); }
+
+ template <std::size_t pwm> auto pwm_out() { return m_pwm_out[pwm].bind(); }
+
+ auto spi_mosi_callback() { return write_spi_mosi.bind(); }
+ auto spi_clock_callback() { return write_spi_clock.bind(); }
+ void spi_miso_w(int state) { m_spi_miso = state; }
+
+protected:
+ // construction/destruction
+ m68hc05pge_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int addrbits, address_map_constructor internal_map);
+
+ // device-level overrides
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual space_config_vector memory_space_config() const override;
+ virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD;
+
+ virtual void nvram_default() override;
+ virtual bool nvram_read(util::read_stream &file) override;
+ virtual bool nvram_write(util::write_stream &file) override;
+
+ virtual void interrupt_vector() override;
+
+ virtual uint64_t execute_clocks_to_cycles(uint64_t clocks) const noexcept override;
+ virtual uint64_t execute_cycles_to_clocks(uint64_t cycles) const noexcept override;
+ virtual void execute_set_input(int inputnum, int state) override;
+ virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+
+ void m68hc05pge_map(address_map &map) ATTR_COLD;
+
+ u8 ports_r(offs_t offset);
+ void ports_w(offs_t offset, u8 data);
+ u8 ddrs_r(offs_t offset);
+ void ddrs_w(offs_t offset, u8 data);
+ u8 read_port(u8 offset);
+ void send_port(u8 offset, u8 data);
+ u8 pll_r();
+ void pll_w(u8 data);
+ u8 spi_r(offs_t offset);
+ void spi_w(offs_t offset, u8 data);
+ u8 cpicsr_r();
+ void cpicsr_w(u8 data);
+ u8 cscr_r();
+ void cscr_w(u8 data);
+ u8 kcsr_r();
+ void kcsr_w(u8 data);
+ u8 trackball_r(offs_t offset);
+ void trackball_w(offs_t offset, u8 data);
+ u8 adb_r(offs_t offset);
+ void adb_w(offs_t offset, u8 data);
+ u8 option_r();
+ void option_w(u8 data);
+ u8 adc_r(offs_t offset);
+ void adc_w(offs_t offset, u8 data);
+ u8 ports_high_r(offs_t offset);
+ void ports_high_w(offs_t offset, u8 data);
+ u8 pwm_r(offs_t offset);
+ void pwm_w(offs_t offset, u8 data);
+ u8 plm_r(offs_t offset);
+ void plm_w(offs_t offset, u8 data);
+ u8 rtc_r(offs_t offset);
+ void rtc_w(offs_t offset, u8 data);
+ u8 sram_r(offs_t offset);
+ void sram_w(offs_t offset, u8 data);
+
+ TIMER_CALLBACK_MEMBER(seconds_tick);
+ TIMER_CALLBACK_MEMBER(cpi_tick);
+ TIMER_CALLBACK_MEMBER(spi_tick);
+ TIMER_CALLBACK_MEMBER(adb_tick);
+
+ required_shared_ptr<u8> m_internal_ram;
+
+ memory_view m_introm;
+
+ devcb_read8 m_read_tbX, m_read_tbY;
+ devcb_read_line m_read_tbB;
+ devcb_read8::array<11> m_read_p;
+ devcb_write8::array<11> m_write_p;
+
+ devcb_read8::array<16> m_ad_in;
+
+ devcb_write8::array<4> m_pwm_out;
+
+ devcb_write_line write_spi_mosi, write_spi_clock;
+
+ u8 m_ports[11], m_ddrs[11], m_pullups[11];
+ u8 m_pll_ctrl;
+ u8 m_timer_ctrl;
+ u8 m_onesec;
+ u8 m_option, m_cscr;
+ u8 m_spi_in, m_spi_out;
+ int m_spi_bit, m_spi_clock, m_spi_miso;
+ u8 m_spcr, m_spsr;
+ u8 m_cpicsr;
+ u8 m_adcsr;
+ u8 m_adbcr, m_adbsr, m_adbdr;
+ u8 m_tbcs;
+ u8 m_pwmacr, m_pwma0, m_pwma1;
+ u8 m_pwmbcr, m_pwmb0, m_pwmb1;
+ u8 m_plmcr, m_plmt1, m_plmt2;
+ emu_timer *m_seconds_timer, *m_cpi_timer, *m_spi_timer, *m_adb_timer;
+ u32 m_rtc;
+ u8 m_sram[0x8000];
+};
+
+DECLARE_DEVICE_TYPE(M68HC05PGE, m68hc05pge_device)
+
+#endif // MAME_CPU_M6805_M58HC05PGE_H
diff --git a/src/devices/machine/6522via.h b/src/devices/machine/6522via.h
index 7895ee45d39..12210ffc7a1 100644
--- a/src/devices/machine/6522via.h
+++ b/src/devices/machine/6522via.h
@@ -130,12 +130,13 @@ protected:
TIMER_CALLBACK_MEMBER(t2_tick);
TIMER_CALLBACK_MEMBER(ca2_tick);
+ void set_int(int data);
+ void clear_int(int data);
+
private:
uint16_t get_counter1_value();
void counter2_decrement();
- void set_int(int data);
- void clear_int(int data);
void shift_out();
void shift_in();
void set_pa_line(int line, int state);
diff --git a/src/mame/apple/csc.cpp b/src/mame/apple/csc.cpp
new file mode 100644
index 00000000000..c58c3db194e
--- /dev/null
+++ b/src/mame/apple/csc.cpp
@@ -0,0 +1,340 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*
+ Apple Color Screen Controller (CSC) video, aka Chips & Technologies 65220
+ Emulation by R. Belmont
+
+ References:
+ https://github.com/elliotnunn/supermario/blob/master/base/SuperMarioProj.1994-02-09/Internal/Asm/HardwarePrivateEqu.a#L1220
+ https://github.com/elliotnunn/supermario/tree/master/base/SuperMarioProj.1994-02-09/DeclData/DeclVideo/CSC
+
+ For Escher (PowerBook Duo 270C), panel 0 is the only option.
+ For Yeager (PowerBook Duo280/280C), panel 0 is color 640x480, panel 4 is TFT grayscale, and panel 6 is STN grayscale
+ For Blackbird (Powerbook 5xx), panel 0 is Sharp color TFT, 1 is color STN, 2 is NEC color TFT, 3 is Hosiden color TFT,
+ 4 is Toshiba color TFT, 5 is Sharp grayscale STN, and 6 is Hosiden grayscale TFT
+*/
+
+#include "emu.h"
+#include "csc.h"
+
+DEFINE_DEVICE_TYPE(CSC, csc_device, "applecsc", "Apple Color Screen Controller video")
+
+static constexpr u8 CSC_PANEL_ID = 0x02;
+static constexpr u8 CSC_PANEL_SETUP = 0x08;
+static constexpr u8 CSC_DISPLAY_FORMAT = 0x12;
+static constexpr u8 CSC_DISPLAY_STATUS = 0x14;
+static constexpr u8 CSC_ADDR_REG_W = 0x40;
+static constexpr u8 CSC_DATA_REG = 0x42;
+static constexpr u8 CSC_ADDR_REG_R = 0x46;
+
+static constexpr u8 CSC_DISPSTAT_IRQ_ENABLE = 0;
+static constexpr u8 CSC_DISPSTAT_IRQ = 1;
+
+static constexpr u8 CSC_PANELSETUP_480 = 1;
+static constexpr u8 CSC_PANELSETUP_COLOR = 2;
+static constexpr u8 CSC_PANELSETUP_ENABLED = 3;
+
+// mask to determine a color 480-tall panel in 400-tall mode to fit 15bpp in 512K
+static constexpr u8 CSC_PANELSETUP_COLOR400_MASK = (1 << CSC_PANELSETUP_480) | (1 << CSC_PANELSETUP_COLOR);
+
+void csc_device::map(address_map & map)
+{
+ map(0x00f20000, 0x00f2007f).rw(FUNC(csc_device::csc_r), FUNC(csc_device::csc_w));
+ map(0x10000000, 0x10ffffff).rw(FUNC(csc_device::vram_r), FUNC(csc_device::vram_w));
+}
+
+csc_device::csc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, CSC, tag, owner, clock),
+ m_screen(*this, "screen"),
+ m_palette(*this, "palette"),
+ m_irq(*this),
+ m_csc_panel_id(0),
+ m_pal_idx(0),
+ m_pmu_blank_display(true)
+{
+ std::fill(std::begin(m_csc_regs), std::end(m_csc_regs), 0);
+}
+
+void csc_device::device_start()
+{
+ m_vram = std::make_unique<u32[]>(0x80000);
+
+ save_item(NAME(m_csc_regs));
+ save_item(NAME(m_pal_idx));
+ save_item(NAME(m_pmu_blank_display));
+ save_pointer(NAME(m_vram), 0x80000);
+}
+
+void csc_device::device_reset()
+{
+ if (m_csc_panel_id >= 4)
+ {
+ m_screen->set_raw(21604953, 800, 0, 640, 449, 0, 400);
+ }
+}
+
+void csc_device::device_add_mconfig(machine_config &config)
+{
+ PALETTE(config, m_palette).set_entries(256);
+
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ m_screen->set_raw(25175000, 800, 0, 640, 525, 0, 480);
+ m_screen->set_screen_update(FUNC(csc_device::screen_update_csc));
+ m_screen->screen_vblank().set(FUNC(csc_device::csc_irq_w));
+}
+
+void csc_device::set_panel_id(int panel_id)
+{
+ m_csc_panel_id = panel_id;
+}
+
+u8 csc_device::csc_r(offs_t offset)
+{
+ if (offset == CSC_PANEL_ID)
+ {
+ return m_csc_panel_id;
+ }
+ else if (offset == CSC_DATA_REG)
+ {
+ u8 component = 0;
+ switch (m_pal_idx)
+ {
+ case 0:
+ component = m_palette->pen_color(m_csc_regs[CSC_ADDR_REG_R]).r();
+ break;
+ case 1:
+ component = m_palette->pen_color(m_csc_regs[CSC_ADDR_REG_R]).g();
+ break;
+ case 2:
+ component = m_palette->pen_color(m_csc_regs[CSC_ADDR_REG_R]).b();
+ break;
+ }
+ m_pal_idx++;
+ if (m_pal_idx == 3)
+ {
+ m_pal_idx = 0;
+ m_csc_regs[CSC_ADDR_REG_R]++;
+ }
+
+ return component;
+ }
+
+ return m_csc_regs[offset];
+}
+
+void csc_device::csc_w(offs_t offset, u8 data)
+{
+ switch (offset)
+ {
+ case CSC_DISPLAY_STATUS:
+ if (BIT(data, CSC_DISPSTAT_IRQ))
+ {
+ m_irq(CLEAR_LINE);
+ data = m_csc_regs[offset] & ~(1 << CSC_DISPSTAT_IRQ);
+ }
+ break;
+
+ case CSC_DISPLAY_FORMAT:
+ // if this is a monochrome panel, setup the palette correctly for the mode
+ if (!BIT(m_csc_regs[CSC_PANEL_SETUP], CSC_PANELSETUP_COLOR))
+ {
+ switch (data)
+ {
+ case 0:
+ m_palette->set_pen_color(0, rgb_t(255, 255, 255));
+ m_palette->set_pen_color(0x80, rgb_t(0, 0, 0));
+ break;
+
+ case 1:
+ m_palette->set_pen_color(0, rgb_t(255, 255, 255));
+ m_palette->set_pen_color(0x40, rgb_t(192, 192, 192));
+ m_palette->set_pen_color(0x80, rgb_t(64, 64, 64));
+ m_palette->set_pen_color(0xc0, rgb_t(0, 0, 0));
+ break;
+
+ case 2:
+ for (int i = 15; i >= 0; i--)
+ {
+ m_palette->set_pen_red_level(i<<4, (15 - i) << 4);
+ m_palette->set_pen_green_level(i<<4, (15 - i) << 4);
+ m_palette->set_pen_blue_level(i<<4, (15 - i) << 4);
+ }
+ break;
+
+ case 3:
+ for (int i = 255; i >= 0; i--)
+ {
+ m_palette->set_pen_red_level(i, 255 - i);
+ m_palette->set_pen_green_level(i, 255 - i);
+ m_palette->set_pen_blue_level(i, 255 - i);
+ }
+ break;
+ }
+ }
+ break;
+
+ case CSC_ADDR_REG_W: // write CLUT index
+ m_pal_idx = 0;
+ break;
+
+ case CSC_DATA_REG:
+ switch (m_pal_idx)
+ {
+ case 0:
+ m_palette->set_pen_red_level(m_csc_regs[CSC_ADDR_REG_W], data);
+ break;
+ case 1:
+ m_palette->set_pen_green_level(m_csc_regs[CSC_ADDR_REG_W], data);
+ break;
+ case 2:
+ m_palette->set_pen_blue_level(m_csc_regs[CSC_ADDR_REG_W], data);
+ break;
+ }
+ m_pal_idx++;
+ if (m_pal_idx == 3)
+ {
+ m_pal_idx = 0;
+ m_csc_regs[CSC_ADDR_REG_W]++;
+ }
+ break;
+
+ case CSC_ADDR_REG_R: // read CLUT index
+ m_pal_idx = 0;
+ break;
+ }
+
+ m_csc_regs[offset] = data;
+}
+
+void csc_device::csc_irq_w(int state)
+{
+ if (state == ASSERT_LINE)
+ {
+ m_csc_regs[CSC_DISPLAY_STATUS] |= (1 << CSC_DISPSTAT_IRQ);
+ if (BIT(m_csc_regs[CSC_DISPLAY_STATUS], 0))
+ {
+ m_irq(ASSERT_LINE);
+ }
+ }
+}
+
+u32 csc_device::screen_update_csc(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ // is the display enabled?
+ if (!BIT(m_csc_regs[CSC_PANEL_SETUP], CSC_PANELSETUP_ENABLED))
+ {
+ bitmap.fill(0xf, cliprect);
+ return 0;
+ }
+
+ const auto vram8 = util::big_endian_cast<u8 const>(&m_vram[0]);
+ const auto vram16 = util::big_endian_cast<u16 const>(&m_vram[0]);
+ const pen_t *pens = m_palette->pens();
+ const int vres = BIT(m_csc_regs[CSC_PANEL_SETUP], CSC_PANELSETUP_480) ? 480 : 400;
+ const int dispoffs = ((m_csc_regs[CSC_PANEL_SETUP] & CSC_PANELSETUP_COLOR400_MASK) == (1 << CSC_PANELSETUP_COLOR)) ? 40 : 0;
+
+ if (dispoffs)
+ {
+ bitmap.fill(0xf, cliprect);
+ }
+
+ switch (m_csc_regs[CSC_DISPLAY_FORMAT])
+ {
+ case 0:
+ {
+ for (int y = 0; y < vres; y++)
+ {
+ u32 *scanline = &bitmap.pix(y + dispoffs);
+ for (int x = 0; x < 640; x += 8)
+ {
+ u8 const pixels = vram8[(y * 80) + (x / 8)];
+
+ *scanline++ = pens[pixels & 0x80];
+ *scanline++ = pens[(pixels << 1) & 0x80];
+ *scanline++ = pens[(pixels << 2) & 0x80];
+ *scanline++ = pens[(pixels << 3) & 0x80];
+ *scanline++ = pens[(pixels << 4) & 0x80];
+ *scanline++ = pens[(pixels << 5) & 0x80];
+ *scanline++ = pens[(pixels << 6) & 0x80];
+ *scanline++ = pens[(pixels << 7) & 0x80];
+ }
+ }
+ }
+ break;
+
+ case 1: // 2bpp
+ {
+ for (int y = 0; y < vres; y++)
+ {
+ u32 *scanline = &bitmap.pix(y + dispoffs);
+ for (int x = 0; x < 640 / 4; x++)
+ {
+ u8 const pixels = vram8[(y * 160) + x];
+
+ *scanline++ = pens[(pixels & 0xc0)];
+ *scanline++ = pens[((pixels << 2) & 0xc0)];
+ *scanline++ = pens[((pixels << 4) & 0xc0)];
+ *scanline++ = pens[((pixels << 6) & 0xc0)];
+ }
+ }
+ }
+ break;
+
+ case 2: // 4bpp
+ {
+ for (int y = 0; y < vres; y++)
+ {
+ u32 *scanline = &bitmap.pix(y + dispoffs);
+
+ for (int x = 0; x < 640 / 2; x++)
+ {
+ u8 const pixels = vram8[(y * 320) + x];
+ *scanline++ = pens[(pixels & 0xf0)];
+ *scanline++ = pens[((pixels << 4) & 0xf0)];
+ }
+ }
+ }
+ break;
+
+ case 3: // 8bpp
+ {
+ for (int y = 0; y < vres; y++)
+ {
+ u32 *scanline = &bitmap.pix(y + dispoffs);
+
+ for (int x = 0; x < 640; x++)
+ {
+ u8 const pixels = vram8[(y * 640) + x];
+ *scanline++ = pens[pixels];
+ }
+ }
+ }
+ break;
+
+ case 4: // 16bpp
+ {
+ for (int y = 0; y < vres; y++)
+ {
+ u32 *scanline = &bitmap.pix(y + dispoffs);
+ for (int x = 0; x < 640; x++)
+ {
+ u16 const pixels = vram16[(y * 640) + x];
+ *scanline++ = rgb_t(((pixels >> 10) & 0x1f) << 3, ((pixels >> 5) & 0x1f) << 3, (pixels & 0x1f) << 3);
+ }
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+u32 csc_device::vram_r(offs_t offset)
+{
+ return m_vram[offset & 0x7ffff];
+}
+
+void csc_device::vram_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_vram[offset & 0x7ffff]);
+}
diff --git a/src/mame/apple/csc.h b/src/mame/apple/csc.h
new file mode 100644
index 00000000000..cefc305fdf2
--- /dev/null
+++ b/src/mame/apple/csc.h
@@ -0,0 +1,55 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+
+#ifndef MAME_APPLE_CSC_H
+#define MAME_APPLE_CSC_H
+
+#pragma once
+
+#include "emupal.h"
+#include "screen.h"
+
+class csc_device : public device_t
+{
+public:
+ csc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ virtual ~csc_device() = default;
+
+ auto write_irq() { return m_irq.bind(); }
+
+ void map(address_map &map) ATTR_COLD;
+
+ void set_panel_id(int panel_id);
+ void set_pmu_blank(bool blank) { m_pmu_blank_display = blank; }
+
+protected:
+ // device_t overrides
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
+
+private:
+ required_device<screen_device> m_screen;
+ required_device<palette_device> m_palette;
+ devcb_write_line m_irq;
+
+ std::unique_ptr<u32[]> m_vram;
+
+ u8 m_csc_regs[0x50];
+ u8 m_csc_panel_id;
+ int m_pal_idx;
+ bool m_pmu_blank_display;
+
+ u32 screen_update_csc(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+ u8 csc_r(offs_t offset);
+ void csc_w(offs_t offset, u8 data);
+ void csc_irq_w(int state);
+
+ u32 vram_r(offs_t offset);
+ void vram_w(offs_t offset, u32 data, u32 mem_mask);
+};
+
+DECLARE_DEVICE_TYPE(CSC, csc_device)
+
+#endif /* MAME_APPLE_CSC_H */
diff --git a/src/mame/apple/gsc.cpp b/src/mame/apple/gsc.cpp
new file mode 100644
index 00000000000..06ecf7a9bd5
--- /dev/null
+++ b/src/mame/apple/gsc.cpp
@@ -0,0 +1,176 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*
+ Apple Gray Scale Controller (GSC) video, aka Chips & Technologies 65210
+ Emulation by R. Belmont
+
+ Reference:
+ https://github.com/elliotnunn/supermario/blob/master/base/SuperMarioProj.1994-02-09/Internal/Asm/HardwarePrivateEqu.a#L1201
+ https://github.com/elliotnunn/supermario/tree/master/base/SuperMarioProj.1994-02-09/DeclData/DeclVideo/DBLite
+
+ panel 4 = 640x480 JeDI (PowerBook 150)
+ panel 5 = 640x400 Dartanian (PowerBook 160/180)
+ panel 6 = 640x400 DBLite (PowerBook Duo 210/230/250)
+*/
+
+#include "emu.h"
+#include "gsc.h"
+
+DEFINE_DEVICE_TYPE(GSC, gsc_device, "applegsc", "Apple Gray Scale Controller video")
+
+static constexpr u8 GSC_GRAYSCALE = 0x04;
+
+static constexpr u8 GSC_GS_DISPLAY_ENABLED = 5;
+static constexpr u8 GSC_GS_MODE_MASK = 0x03;
+
+//-------------------------------------------------
+// ADDRESS_MAP
+//-------------------------------------------------
+
+void gsc_device::map(address_map &map)
+{
+ map(0x00f20000, 0x00f21fff).rw(FUNC(gsc_device::gsc_r), FUNC(gsc_device::gsc_w));
+ map(0x10000000, 0x1001ffff).rw(FUNC(gsc_device::vram_r), FUNC(gsc_device::vram_w)).mirror(0x0ffe0000);
+}
+
+gsc_device::gsc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
+ device_t(mconfig, GSC, tag, owner, clock),
+ m_screen(*this, "screen"),
+ m_palette(*this, "palette")
+{
+ std::fill(std::begin(m_gsc_regs), std::end(m_gsc_regs), 0);
+}
+
+void gsc_device::device_start()
+{
+ m_vram = std::make_unique<u32[]>(0x20000);
+
+ save_item(NAME(m_gsc_regs));
+ save_item(NAME(m_pmu_blank_display));
+ save_pointer(NAME(m_vram), 0x20000);
+}
+
+void gsc_device::device_reset()
+{
+ if (m_gsc_panel_id == 4)
+ {
+ m_screen->set_raw(25175000, 800, 0, 640, 525, 0, 480);
+ }
+}
+
+void gsc_device::device_add_mconfig(machine_config &config)
+{
+ SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
+ // these parameters are not real; we know the refresh rate is ~60.15 Hz and that's it
+ m_screen->set_raw(21604953, 800, 0, 640, 449, 0, 400);
+
+ m_screen->set_palette(m_palette);
+ m_screen->set_screen_update(FUNC(gsc_device::screen_update_gsc));
+
+ PALETTE(config, m_palette, FUNC(gsc_device::macgsc_palette), 16);
+}
+
+void gsc_device::macgsc_palette(palette_device &palette) const
+{
+ for (u8 i = 0; i < 16; i++)
+ {
+ palette.set_pen_color(i, ((15 - i) << 4) | 0xf, ((15 - i) << 4) | 0xf, ((15 - i) << 4) | 0xf);
+ }
+}
+
+u32 gsc_device::screen_update_gsc(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ auto const vram8 = util::big_endian_cast<u8 const>(&m_vram[0]);
+ int height = (m_gsc_panel_id == 4) ? 480 : 400;
+
+ // is the display enabled?
+ if (!BIT(m_gsc_regs[GSC_GRAYSCALE], GSC_GS_DISPLAY_ENABLED) && !m_pmu_blank_display)
+ {
+ bitmap.fill(0xf, cliprect);
+ return 0;
+ }
+
+ switch (m_gsc_regs[4] & GSC_GS_MODE_MASK)
+ {
+ case 0:
+ for (int y = 0; y < height; y++)
+ {
+ u16 *line = &bitmap.pix(y);
+
+ for (int x = 0; x < 640; x += 8)
+ {
+ u8 const pixels = vram8[(y * 640 / 8) + (x / 8)];
+ *line++ = ((pixels >> 7) & 1) ? 0xf : 0;
+ *line++ = ((pixels >> 6) & 1) ? 0xf : 0;
+ *line++ = ((pixels >> 5) & 1) ? 0xf : 0;
+ *line++ = ((pixels >> 4) & 1) ? 0xf : 0;
+ *line++ = ((pixels >> 3) & 1) ? 0xf : 0;
+ *line++ = ((pixels >> 2) & 1) ? 0xf : 0;
+ *line++ = ((pixels >> 1) & 1) ? 0xf : 0;
+ *line++ = (pixels & 1) ? 0xf : 0;
+ }
+ }
+ break;
+
+ case 1:
+ for (int y = 0; y < height; y++)
+ {
+ u16 *line = &bitmap.pix(y);
+
+ for (int x = 0; x < 640; x += 4)
+ {
+ u8 const pixels = vram8[(y * 640 / 4) + (x / 4)];
+ *line++ = ((pixels >> 4) & 0xc);
+ *line++ = ((pixels >> 2) & 0xc);
+ *line++ = (pixels & 0xc);
+ *line++ = ((pixels << 2) & 0xc);
+ }
+ }
+ break;
+
+ case 2:
+ for (int y = 0; y < height; y++)
+ {
+ u16 *line = &bitmap.pix(y);
+
+ for (int x = 0; x < 640; x += 2)
+ {
+ u8 const pixels = vram8[(y * 640 / 2) + (x / 2)];
+ *line++ = pixels >> 4;
+ *line++ = pixels & 0xf;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+void gsc_device::set_panel_id(int panel_id)
+{
+ m_gsc_panel_id = panel_id;
+}
+
+u8 gsc_device::gsc_r(offs_t offset)
+{
+ if (offset == 1)
+ {
+ return m_gsc_panel_id;
+ }
+
+ return m_gsc_regs[offset & 0x1f];
+}
+
+void gsc_device::gsc_w(offs_t offset, u8 data)
+{
+ m_gsc_regs[offset & 0x1f] = data;
+}
+
+u32 gsc_device::vram_r(offs_t offset)
+{
+ return m_vram[offset & 0x1ffff];
+}
+
+void gsc_device::vram_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ COMBINE_DATA(&m_vram[offset & 0x1ffff]);
+}
diff --git a/src/mame/apple/gsc.h b/src/mame/apple/gsc.h
new file mode 100644
index 00000000000..c9ca1c1fa5e
--- /dev/null
+++ b/src/mame/apple/gsc.h
@@ -0,0 +1,51 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+
+#ifndef MAME_APPLE_GSC_H
+#define MAME_APPLE_GSC_H
+
+#pragma once
+
+#include "emupal.h"
+#include "screen.h"
+
+class gsc_device : public device_t
+{
+public:
+ gsc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
+ virtual ~gsc_device() = default;
+
+ void map(address_map &map) ATTR_COLD;
+
+ void set_panel_id(int panel_id);
+ void set_pmu_blank(bool blank) { m_pmu_blank_display = blank; }
+
+protected:
+ // device_t overrides
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
+
+private:
+ required_device<screen_device> m_screen;
+ required_device<palette_device> m_palette;
+
+ std::unique_ptr<u32[]> m_vram;
+
+ u8 m_gsc_regs[0x20];
+ u8 m_gsc_panel_id;
+ bool m_pmu_blank_display;
+
+ u32 screen_update_gsc(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+ u8 gsc_r(offs_t offset);
+ void gsc_w(offs_t offset, u8 data);
+ u32 vram_r(offs_t offset);
+ void vram_w(offs_t offset, u32 data, u32 mem_mask);
+
+ void macgsc_palette(palette_device &palette) const;
+};
+
+DECLARE_DEVICE_TYPE(GSC, gsc_device)
+
+#endif /* MAME_APPLE_GSC_H */
diff --git a/src/mame/apple/macpwrbk030.cpp b/src/mame/apple/macpwrbk030.cpp
index 64d3edf97df..258261ee79c 100644
--- a/src/mame/apple/macpwrbk030.cpp
+++ b/src/mame/apple/macpwrbk030.cpp
@@ -121,19 +121,12 @@
INT1: 60 Hz clock
INT2: INT2 PULLUP (pulled up and otherwise N/C)
- PG&E (68HC05 PMU) version spotting:
- (find the text "BORG" in the system ROM, the next 32768 bytes are the PG&E image.
- offset +4 in the image is the version byte).
- 01 - PowerBook Duo 210/230/250
- 02 - PowerBook 540c, PBDuo 270C, PBDuo 280/280C
- 03 - PowerBook 150
- 08 - PB190cs, PowerBook 540c PPC update, all PowerPC PowerBooks through WallStreet G3s
-
****************************************************************************/
#include "emu.h"
#include "dfac.h"
+#include "gsc.h"
#include "macadb.h"
#include "macrtc.h"
#include "macscsi.h"
@@ -180,6 +173,7 @@ public:
m_swim(*this, "fdc"),
m_floppy(*this, "fdc:%d", 0U),
m_rtc(*this, "rtc"),
+ m_gsc(*this, "gsc"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_asc(*this, "asc"),
@@ -212,7 +206,6 @@ public:
m_ponti_SPI_SR(0),
m_ponti_backlight_ctl(0)
{
- std::fill(std::begin(m_gsc_regs), std::end(m_gsc_regs), 0);
}
void macpb140(machine_config &config);
@@ -224,11 +217,9 @@ public:
void macpb170(machine_config &config);
void macpb180(machine_config &config);
void macpb180c(machine_config &config);
- void macpd210(machine_config &config);
void macpb140_map(address_map &map) ATTR_COLD;
void macpb160_map(address_map &map) ATTR_COLD;
void macpb165c_map(address_map &map) ATTR_COLD;
- void macpd210_map(address_map &map) ATTR_COLD;
private:
required_device<m68030_device> m_maincpu;
@@ -242,8 +233,9 @@ private:
required_device<applefdintf_device> m_swim;
required_device_array<floppy_connector, 2> m_floppy;
required_device<rtc3430042_device> m_rtc;
- required_device<screen_device> m_screen;
- required_device<palette_device> m_palette;
+ optional_device<gsc_device> m_gsc;
+ optional_device<screen_device> m_screen;
+ optional_device<palette_device> m_palette;
required_device<asc_device> m_asc;
required_device<z80scc_device> m_scc;
optional_shared_ptr<u32> m_vram, m_ext_vram;
@@ -263,7 +255,6 @@ private:
floppy_image_device *m_cur_floppy;
int m_hdsel;
- u8 m_gsc_regs[0x20];
bool m_pmu_blank_display;
u8 m_pmu_from_via, m_pmu_to_via, m_pmu_ack, m_pmu_req;
@@ -275,7 +266,6 @@ private:
virtual void machine_reset() override ATTR_COLD;
u32 screen_update_ddc(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
- u32 screen_update_gsc(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
u32 screen_update_vga(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
u16 via_r(offs_t offset);
@@ -311,10 +301,6 @@ private:
void swim_w(offs_t offset, u16 data, u16 mem_mask);
u32 buserror_r();
- u8 gsc_r(offs_t offset);
- void gsc_w(offs_t offset, u8 data);
- void macgsc_palette(palette_device &palette) const;
-
u32 jaws_r(offs_t offset, u32 mem_mask);
void jaws_w(offs_t offset, u32 data, u32 mem_mask);
u32 niagra_r(offs_t offset, u32 mem_mask);
@@ -342,9 +328,6 @@ private:
u8 battery2_r();
u8 battery3_r();
u8 brightness_r();
-
- // ID for PowerBook Duo 210
- u32 pd210_id_r() { return 0xa55a1004; }
};
void macpb030_state::machine_start()
@@ -590,12 +573,12 @@ void macpb030_state::niagra_w(offs_t offset, u32 data, u32 mem_mask)
u16 macpb030_state::pangola_r()
{
return m_pangola_data;
+ // TODO: trace pins, 0x13 -> 0x17 -> 0x16 sequence written before waking up VGA core
}
void macpb030_state::pangola_w(u16 data)
{
m_pangola_data = data;
- // TODO: trace pins, 0x13 -> 0x17 -> 0x16 sequence written before waking up VGA core
}
u8 macpb030_state::pangola_vram_r(offs_t offset)
@@ -753,7 +736,6 @@ u8 macpb030_state::pmu_comms_r()
return (m_pmu_req << 7);
}
-u8 last_comms = 0xff;
void macpb030_state::pmu_comms_w(u8 data)
{
if (!BIT(data, 1))
@@ -767,10 +749,7 @@ void macpb030_state::pmu_comms_w(u8 data)
space.install_rom(0x00000000, memory_end & ~memory_mirror, memory_mirror, m_rom_ptr);
m_overlay = true;
}
- if ((data & 3) != (last_comms & 3))
- {
- last_comms = data;
- }
+
m_maincpu->set_input_line(INPUT_LINE_HALT, BIT(data, 0) ? CLEAR_LINE : ASSERT_LINE);
m_maincpu->set_input_line(INPUT_LINE_RESET, BIT(data, 1) ? CLEAR_LINE : ASSERT_LINE);
@@ -791,14 +770,9 @@ void macpb030_state::pmu_p4_w(u8 data)
{
m_macadb->adb_linechange_w((data & 1) ^ 1);
m_pmu_blank_display = BIT(data, 2) ^ 1;
-}
-
-// 16-level grayscale
-void macpb030_state::macgsc_palette(palette_device &palette) const
-{
- for (u8 i = 0; i < 16; i++)
+ if (m_gsc)
{
- palette.set_pen_color(i, ((15 - i) << 4) | 0xf, ((15 - i) << 4) | 0xf, ((15 - i) << 4) | 0xf);
+ m_gsc->set_pmu_blank(m_pmu_blank_display);
}
}
@@ -947,72 +921,6 @@ u32 macpb030_state::screen_update_ddc(screen_device &screen, bitmap_ind16 &bitma
return 0;
}
-u32 macpb030_state::screen_update_gsc(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-{
- u8 const *const vram8 = (u8 *)m_vram.target();
-
- // is the display enabled?
- if (!(m_gsc_regs[4] & 0x20) || m_pmu_blank_display)
- {
- bitmap.fill(0xf, cliprect);
- return 0;
- }
-
- switch (m_gsc_regs[4] & 3)
- {
- case 0:
- for (int y = 0; y < 400; y++)
- {
- u16 *line = &bitmap.pix(y);
-
- for (int x = 0; x < 640; x += 8)
- {
- u8 const pixels = vram8[(y * 640 / 8) + (BYTE4_XOR_BE(x / 8))];
- *line++ = ((pixels >> 7) & 1) ? 0xf : 0;
- *line++ = ((pixels >> 6) & 1) ? 0xf : 0;
- *line++ = ((pixels >> 5) & 1) ? 0xf : 0;
- *line++ = ((pixels >> 4) & 1) ? 0xf : 0;
- *line++ = ((pixels >> 3) & 1) ? 0xf : 0;
- *line++ = ((pixels >> 2) & 1) ? 0xf : 0;
- *line++ = ((pixels >> 1) & 1) ? 0xf : 0;
- *line++ = (pixels & 1) ? 0xf : 0;
- }
- }
- break;
-
- case 1:
- for (int y = 0; y < 400; y++)
- {
- u16 *line = &bitmap.pix(y);
-
- for (int x = 0; x < 640; x += 4)
- {
- u8 const pixels = vram8[(y * 640 / 4) + (BYTE4_XOR_BE(x / 4))];
- *line++ = ((pixels >> 4) & 0xc);
- *line++ = ((pixels >> 2) & 0xc);
- *line++ = (pixels & 0xc);
- *line++ = ((pixels << 2) & 0xc);
- }
- }
- break;
-
- case 2:
- for (int y = 0; y < 400; y++)
- {
- u16 *line = &bitmap.pix(y);
-
- for (int x = 0; x < 640; x += 2)
- {
- u8 const pixels = vram8[(y * 640 / 2) + (BYTE4_XOR_BE(x / 2))];
- *line++ = pixels >> 4;
- *line++ = pixels & 0xf;
- }
- }
- break;
- }
- return 0;
-}
-
u32 macpb030_state::screen_update_vga(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
if (m_pmu_blank_display)
@@ -1179,21 +1087,6 @@ void macpb030_state::scsi_berr_w(u8 data)
m_maincpu->pulse_input_line(M68K_LINE_BUSERROR, attotime::zero);
}
-u8 macpb030_state::gsc_r(offs_t offset)
-{
- if (offset == 1)
- {
- return 5;
- }
-
- return m_gsc_regs[offset & 0x1f];
-}
-
-void macpb030_state::gsc_w(offs_t offset, u8 data)
-{
- m_gsc_regs[offset & 0x1f] = data;
-}
-
/***************************************************************************
ADDRESS MAPS
****************************************************************************/
@@ -1223,6 +1116,8 @@ void macpb030_state::macpb160_map(address_map &map)
{
map(0x40000000, 0x400fffff).r(FUNC(macpb030_state::rom_switch_r)).mirror(0x0ff00000);
+ map(0x50000000, 0x6fffffff).m(m_gsc, FUNC(gsc_device::map));
+
map(0x50f00000, 0x50f01fff).rw(FUNC(macpb030_state::via_r), FUNC(macpb030_state::via_w));
map(0x50f02000, 0x50f03fff).rw(FUNC(macpb030_state::via2_r), FUNC(macpb030_state::via2_w));
map(0x50f04000, 0x50f05fff).rw(FUNC(macpb030_state::scc_r), FUNC(macpb030_state::scc_w));
@@ -1231,12 +1126,9 @@ void macpb030_state::macpb160_map(address_map &map)
map(0x50f12060, 0x50f12063).r(FUNC(macpb030_state::scsi_drq_r));
map(0x50f14000, 0x50f15fff).rw(m_asc, FUNC(asc_device::read), FUNC(asc_device::write));
map(0x50f16000, 0x50f17fff).rw(FUNC(macpb030_state::swim_r), FUNC(macpb030_state::swim_w));
- map(0x50f20000, 0x50f21fff).rw(FUNC(macpb030_state::gsc_r), FUNC(macpb030_state::gsc_w));
map(0x50f24000, 0x50f27fff).r(FUNC(macpb030_state::buserror_r)); // bus error here to make sure we aren't mistaken for another decoder
map(0x50f80000, 0x50fbffff).rw(FUNC(macpb030_state::niagra_r), FUNC(macpb030_state::niagra_w));
- map(0x60000000, 0x6001ffff).ram().share("vram").mirror(0x0ffe0000);
-
// external video on 160/180
map(0xfe0fe000, 0xfe0fe0ff).rw(FUNC(macpb030_state::ext_video_r), FUNC(macpb030_state::ext_video_w));
map(0xfe100000, 0xfe17ffff).ram().share("ext_vram");
@@ -1260,7 +1152,7 @@ void macpb030_state::macpb165c_map(address_map &map)
// on-board color video on 165c/180c, presumably under ISA bus
map(0xfc000000, 0xfc07ffff).rw(FUNC(macpb030_state::pangola_vram_r), FUNC(macpb030_state::pangola_vram_w)).mirror(0x00380000);
-// map(0xfc400102, 0xfc400102).w(wd90c26_vga_device::wakeup_w));
+ //map(0xfc400102, 0xfc400102).w(wd90c26_vga_device::wakeup_w));
map(0xfc4003b0, 0xfc4003df).m(m_vga, FUNC(wd90c26_vga_device::io_map));
// TODO: trace $3d0 writes (doesn't belong to WD90C26 core, RAMDAC overlay?)
map(0xfc4046e8, 0xfc4046e8).mirror(0x3000).w(m_vga, FUNC(wd90c26_vga_device::mode_setup_w));
@@ -1273,26 +1165,6 @@ void macpb030_state::macpb165c_map(address_map &map)
map(0xfe100000, 0xfe17ffff).ram().share("ext_vram");
}
-void macpb030_state::macpd210_map(address_map &map)
-{
- map(0x40000000, 0x400fffff).r(FUNC(macpb030_state::rom_switch_r)).mirror(0x0ff00000);
-
- map(0x50f00000, 0x50f01fff).rw(FUNC(macpb030_state::via_r), FUNC(macpb030_state::via_w));
- map(0x50f02000, 0x50f03fff).rw(FUNC(macpb030_state::via2_r), FUNC(macpb030_state::via2_w));
- map(0x50f04000, 0x50f05fff).rw(FUNC(macpb030_state::scc_r), FUNC(macpb030_state::scc_w));
- map(0x50f06000, 0x50f07fff).rw(FUNC(macpb030_state::scsi_drq_r), FUNC(macpb030_state::scsi_drq_w));
- map(0x50f10000, 0x50f11fff).rw(FUNC(macpb030_state::scsi_r), FUNC(macpb030_state::scsi_w));
- map(0x50f12060, 0x50f12063).r(FUNC(macpb030_state::scsi_drq_r));
- map(0x50f14000, 0x50f15fff).rw(m_asc, FUNC(asc_device::read), FUNC(asc_device::write));
- map(0x50f16000, 0x50f17fff).rw(FUNC(macpb030_state::swim_r), FUNC(macpb030_state::swim_w));
- map(0x50f20000, 0x50f21fff).rw(FUNC(macpb030_state::gsc_r), FUNC(macpb030_state::gsc_w));
- map(0x50f24000, 0x50f27fff).r(FUNC(macpb030_state::buserror_r)); // bus error here to make sure we aren't mistaken for another decoder
-
- map(0x5ffffffc, 0x5fffffff).r(FUNC(macpb030_state::pd210_id_r));
-
- map(0x60000000, 0x6001ffff).ram().share("vram").mirror(0x0ffe0000);
-}
-
u8 macpb030_state::via_in_a()
{
return 0x81 | 0x12; // ID for 140/160
@@ -1404,7 +1276,7 @@ void macpb030_state::macpb140(machine_config &config)
applefdintf_device::add_35_nc(config, m_floppy[1]);
NSCSI_BUS(config, "scsi");
- NSCSI_CONNECTOR(config, "scsi:0", mac_scsi_devices, nullptr);
+ NSCSI_CONNECTOR(config, "scsi:0", mac_scsi_devices, "harddisk");
NSCSI_CONNECTOR(config, "scsi:1", mac_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:2", mac_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:3").option_set("cdrom", NSCSI_CDROM_APPLE).machine_config(
@@ -1415,7 +1287,7 @@ void macpb030_state::macpb140(machine_config &config)
});
NSCSI_CONNECTOR(config, "scsi:4", mac_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:5", mac_scsi_devices, nullptr);
- NSCSI_CONNECTOR(config, "scsi:6", mac_scsi_devices, "harddisk");
+ NSCSI_CONNECTOR(config, "scsi:6", mac_scsi_devices, nullptr);
NSCSI_CONNECTOR(config, "scsi:7").option_set("ncr5380", NCR53C80).machine_config([this](device_t *device) {
ncr53c80_device &adapter = downcast<ncr53c80_device &>(*device);
adapter.irq_handler().set(m_pseudovia, FUNC(pseudovia_device::scsi_irq_w));
@@ -1499,8 +1371,11 @@ void macpb030_state::macpb160(machine_config &config)
m_maincpu->set_addrmap(AS_PROGRAM, &macpb030_state::macpb160_map);
m_maincpu->set_fpu_enable(false);
- PALETTE(config.replace(), m_palette, FUNC(macpb030_state::macgsc_palette), 16);
- m_screen->set_screen_update(FUNC(macpb030_state::screen_update_gsc));
+ config.device_remove("screen");
+ config.device_remove("palette");
+
+ GSC(config, m_gsc, 31.3344_MHz_XTAL);
+ m_gsc->set_panel_id(5);
m_ram->set_extra_options("4M,6M,8M,12M,14M");
}
@@ -1520,13 +1395,14 @@ void macpb030_state::macpb180(machine_config &config)
void macpb030_state::macpb165c(machine_config &config)
{
- macpb180(config);
+ macpb140(config);
+ m_maincpu->set_clock(33_MHz_XTAL);
+ m_maincpu->set_fpu_enable(true);
m_maincpu->set_addrmap(AS_PROGRAM, &macpb030_state::macpb165c_map);
m_screen->set_raw(25.175_MHz_XTAL, 800, 0, 640, 524, 0, 480);
m_screen->set_screen_update(FUNC(macpb030_state::screen_update_vga));
m_screen->set_no_palette();
- m_screen->set_type(SCREEN_TYPE_LCD);
WD90C26(config, m_vga, 0);
m_vga->set_screen(m_screen);
@@ -1542,16 +1418,6 @@ void macpb030_state::macpb180c(machine_config &config)
m_vga->read_cnf15_callback().set_constant(0);
}
-void macpb030_state::macpd210(machine_config &config)
-{
- macpb160(config);
- m_maincpu->set_addrmap(AS_PROGRAM, &macpb030_state::macpd210_map);
-
- M50753(config.replace(), m_pmu, 3.93216_MHz_XTAL).set_disable();
-
- m_ram->set_extra_options("8M,12M,16M,20M,24M");
-}
-
ROM_START(macpb140)
ROM_REGION32_BE(0x100000, "bootrom", 0)
ROM_LOAD("420dbff3.rom", 0x000000, 0x100000, CRC(88ea2081) SHA1(7a8ee468d16e64f2ad10cb8d1a45e6f07cc9e212))
@@ -1588,13 +1454,6 @@ ROM_END
#define rom_macpb165c rom_macpb180c
-ROM_START(macpd210)
- ROM_REGION32_BE(0x100000, "bootrom", 0)
- ROM_LOAD("ecfa989b.rom", 0x000000, 0x100000, CRC(b86ed854) SHA1(ed1371c97117a5884da4a6605ecfc5abed48ae5a))
-
- ROM_REGION(0x1800, "pmu", ROMREGION_ERASE00)
-ROM_END
-
} // anonymous namespace
@@ -1607,6 +1466,3 @@ COMP(1993, macpb165, macpb160, 0, macpb165, macadb, macpb030_state, empty_init,
COMP(1993, macpb165c, macpb180c, 0, macpb165c, macadb, macpb030_state, empty_init, "Apple Computer", "Macintosh PowerBook 165c", MACHINE_SUPPORTS_SAVE)
COMP(1992, macpb180, macpb160, 0, macpb180, macadb, macpb030_state, empty_init, "Apple Computer", "Macintosh PowerBook 180", MACHINE_SUPPORTS_SAVE)
COMP(1993, macpb180c, 0, 0, macpb180c, macadb, macpb030_state, empty_init, "Apple Computer", "Macintosh PowerBook 180c", MACHINE_SUPPORTS_SAVE)
-
-// PowerBook Duos (probably will not belong in this driver ultimately)
-COMP(1992, macpd210, 0, 0, macpd210, macadb, macpb030_state, empty_init, "Apple Computer", "Macintosh PowerBook Duo 210", MACHINE_NOT_WORKING)
diff --git a/src/mame/apple/macpwrbkmsc.cpp b/src/mame/apple/macpwrbkmsc.cpp
new file mode 100644
index 00000000000..dfc23ab452e
--- /dev/null
+++ b/src/mame/apple/macpwrbkmsc.cpp
@@ -0,0 +1,937 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/****************************************************************************
+
+ macpwrbkmsc.cpp
+ 68K Mac PowerBooks based on the MSC/MSC II system ASICs and the PG&E power manager
+ By R. Belmont
+
+ Supported machines:
+ PowerBook Duo 210: 68030 @ 25 MHz, 640x400 passive-matrix 4bpp grayscale screen, 4 MiB RAM (24 max)
+ PowerBook Duo 230: 68030 @ 33 MHz, 640x400 passive-matrix 4bpp grayscale screen, 4 MiB RAM (24 max)
+ PowerBook Duo 250: 68030 @ 33 MHz, 640x400 active-matrix 4bpp grayscale screen, 4 MiB RAM (24 max)
+ PowerBook Duo 270c: 68030 @ 33 MHz, FPU, 640x480 active-matrix 16bpp color screen, 4 MiB RAM (32 max)
+ PowerBook Duo 280: 68040 @ 33 MHz, 640x480 active-matrix 4bpp grayscale screen, 4 MiB RAM (40 max)
+ PowerBook Duo 280c: 68040 @ 33 MHz, 640x480 active-matrix 16bpp color screen, 4 MiB RAM (40 max)
+
+ Future:
+ PowerBook 150: '030 @ 33 MHz, 640x480 grayscale screen, 4 MiB RAM (40 max), IDE HDD, ADB trackpad, PG&E matrix keyboard
+
+ ============================================================================
+ Technical info
+
+ Pseudo-VIA2 Port B bits 1 and 2 are /PMU_ACK and /PMU_REQ, respectively.
+ Main PMU comms are through the VIA shifter, but using a hardware SPI block
+ on the PG&E end instead of the 68HC05 losing cycles doing bit-banging.
+
+ Brightness: PLM 1 7F (all the way down) to 26 (all the way up)
+ PLM 2 01 " " " " to 5A
+ Total of the 2 PLM timers is always 0x80. Timer 1 is off period, timer 2 is on period.
+
+ PWM A0 - charging current control
+ PWM B0 - screen contrast, 0x33 to 0xc5 range
+
+ Temperature sensors read on a non-linear scale, probably a commercial part.
+ Here are selected points from the lookup table the 68HC05 uses to convert it.
+
+ Sensor val Temperature (Celsius)
+ ---------------------------------
+ 0 - 9: invalid (high)
+ 10 115
+ 20 92
+ 30 78
+ 40 68
+ 50 60
+ 60 54
+ 70 49
+ 80 44
+ 90 39
+ 100 35
+ 110 31
+ 120 28
+ 130 24
+ 140 21
+ 150 17
+ 160 14
+ 170 10
+ 180 6
+ 190 2
+ 195 & 196 0
+ 200 -2
+ 210 -7
+ 220 -12
+ 230 -19
+ 240 -28
+ 250 -48
+ 252 -55
+ 253+ invalid (low)
+****************************************************************************/
+
+#include "emu.h"
+
+#include "csc.h"
+#include "dfac.h"
+#include "gsc.h"
+#include "macscsi.h"
+#include "mactoolbox.h"
+#include "msc.h"
+
+#include "bus/nscsi/cd.h"
+#include "bus/nscsi/devices.h"
+#include "cpu/m6805/m68hc05pge.h"
+#include "cpu/m68000/m68030.h"
+#include "cpu/m68000/m68040.h"
+#include "machine/ds2401.h"
+#include "machine/ram.h"
+#include "machine/timer.h"
+#include "machine/z80scc.h"
+#include "machine/ncr5380.h"
+#include "machine/nscsi_bus.h"
+#include "bus/nscsi/devices.h"
+
+#include "softlist_dev.h"
+#include "speaker.h"
+#include "utf8.h"
+
+namespace {
+class macpbmsc_state : public driver_device
+{
+public:
+ macpbmsc_state(const machine_config &mconfig, device_type type, const char *tag) :
+ driver_device(mconfig, type, tag),
+ m_maincpu(*this, "maincpu"),
+ m_pmu(*this, "pge"),
+ m_msc(*this, "msc"),
+ m_dfac(*this, "dfac"),
+ m_ncr5380(*this, "scsi:7:ncr5380"),
+ m_scsihelp(*this, "scsihelp"),
+ m_ram(*this, RAM_TAG),
+ m_gsc(*this, "gsc"),
+ m_csc(*this, "csc"),
+ m_scc(*this, "scc"),
+ m_battserial(*this, "ds2400"),
+ m_mouse0(*this, "MOUSE0"),
+ m_mouse1(*this, "MOUSE1"),
+ m_mouse2(*this, "MOUSE2"),
+ m_keys(*this, "Y%u", 0),
+ m_kbspecial(*this, "keyb_special"),
+ m_ca1_data(0),
+ m_cb1_data(0),
+ m_pmu_blank_display(true),
+ m_portc(0),
+ m_last_porte(0xff),
+ m_last_portf(0xff),
+ m_last_portg(0xff),
+ m_last_porth(0x00), // bit 0 must start as 0 for the PG&E bootrom to configure the DFAC
+ m_last_portl(0xff),
+ m_lastmousex(0), m_lastmousey(0), m_lastbutton(0),
+ m_mouseX(0), m_mouseY(0),
+ m_matrix_row(0)
+ {
+ }
+
+ void macpd2xx_base_map(address_map &map) ATTR_COLD;
+ void macpd210(machine_config &config);
+ void macpd210_map(address_map &map) ATTR_COLD;
+ void macpd230(machine_config &config);
+ void macpd230_map(address_map &map) ATTR_COLD;
+ void macpd250(machine_config &config);
+ void macpd250_map(address_map &map) ATTR_COLD;
+ void macpd270c(machine_config &config);
+ void macpd270c_map(address_map &map) ATTR_COLD;
+ void macpd280(machine_config &config);
+ void macpd280c(machine_config &config);
+ void macpd280_map(address_map &map) ATTR_COLD;
+
+private:
+ required_device<m68000_musashi_device> m_maincpu;
+ required_device<m68hc05pge_device> m_pmu;
+ required_device<msc_device> m_msc;
+ required_device<dfac_device> m_dfac;
+ required_device<ncr53c80_device> m_ncr5380;
+ required_device<mac_scsi_helper_device> m_scsihelp;
+ required_device<ram_device> m_ram;
+ optional_device<gsc_device> m_gsc;
+ optional_device<csc_device> m_csc;
+ required_device<z80scc_device> m_scc;
+ required_device<ds2401_device> m_battserial;
+ required_ioport m_mouse0, m_mouse1, m_mouse2;
+ required_ioport_array<8> m_keys;
+ required_ioport m_kbspecial;
+ int m_ca1_data;
+ int m_cb1_data;
+
+ bool m_pmu_blank_display;
+
+ u8 m_portc, m_last_porte, m_last_portf, m_last_portg, m_last_porth, m_last_portl;
+
+ s32 m_lastmousex, m_lastmousey, m_lastbutton;
+ u8 m_mouseX, m_mouseY;
+ u8 m_matrix_row;
+
+ virtual void machine_start() override ATTR_COLD;
+ virtual void machine_reset() override ATTR_COLD;
+
+ void scc_irq_w(int state);
+ void via_irq_w(int state);
+
+ u16 scsi_r(offs_t offset, u16 mem_mask);
+ void scsi_w(offs_t offset, u16 data, u16 mem_mask);
+ u32 scsi_drq_r(offs_t offset, u32 mem_mask = ~0);
+ void scsi_drq_w(offs_t offset, u32 data, u32 mem_mask = ~0);
+ void scsi_berr_w(u8 data);
+ u16 scc_r(offs_t offset);
+ void scc_w(offs_t offset, u16 data);
+ void vbl_w(int state);
+
+ u8 pmu_porta_r();
+ u8 pmu_portb_r();
+ u8 pmu_portc_r();
+ void pmu_portc_w(u8 data);
+ u8 pmu_portd_r();
+ u8 pmu_porte_r();
+ void pmu_porte_w(u8 data);
+ u8 pmu_portf_r();
+ void pmu_portf_w(u8 data);
+ u8 pmu_portg_r();
+ void pmu_portg_w(u8 data);
+ u8 pmu_porth_r();
+ void pmu_porth_w(u8 data);
+ void pmu_portj_w(u8 data);
+ void pmu_portl_w(u8 data);
+ u8 pmu_read_mouseX();
+ u8 pmu_read_mouseY();
+ int pmu_read_mouseButton();
+ u8 pmu_bat_low();
+ u8 pmu_bat_high();
+ u8 pmu_bat_current();
+ u8 pmu_bat_temp();
+ u8 pmu_ambient_temp();
+};
+
+void macpbmsc_state::machine_start()
+{
+ m_msc->set_ram_info((u32 *)m_ram->pointer(), m_ram->size());
+
+ m_ca1_data = 0;
+
+ save_item(NAME(m_ca1_data));
+ save_item(NAME(m_cb1_data));
+ save_item(NAME(m_pmu_blank_display));
+ save_item(NAME(m_portc));
+ save_item(NAME(m_last_porte));
+ save_item(NAME(m_last_portf));
+ save_item(NAME(m_last_portg));
+ save_item(NAME(m_last_porth));
+ save_item(NAME(m_last_portl));
+ save_item(NAME(m_lastmousex));
+ save_item(NAME(m_lastmousey));
+ save_item(NAME(m_lastbutton));
+ save_item(NAME(m_mouseX));
+ save_item(NAME(m_mouseY));
+ save_item(NAME(m_matrix_row));
+}
+
+void macpbmsc_state::machine_reset()
+{
+ m_ca1_data = 0;
+ m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
+}
+
+u16 macpbmsc_state::scc_r(offs_t offset)
+{
+ m_msc->via_sync();
+ const u16 result = m_scc->dc_ab_r(offset);
+ return (result << 8) | result;
+}
+
+void macpbmsc_state::scc_w(offs_t offset, u16 data)
+{
+ m_scc->dc_ab_w(offset, data >> 8);
+}
+
+void macpbmsc_state::vbl_w(int state)
+{
+ int MouseCountX = 0, MouseCountY = 0;
+ int NewX, NewY;
+
+ NewX = m_mouse1->read();
+ NewY = m_mouse2->read();
+
+ // printf("pollmouse: X %d Y %d\n", NewX, NewY);
+
+ /* see if it moved in the x coord */
+ if (NewX != m_lastmousex)
+ {
+ int diff = (NewX - m_lastmousex);
+
+ /* check for wrap */
+ if (diff > 0x80)
+ diff = 0x100 - diff;
+ if (diff < -0x80)
+ diff = -0x100 - diff;
+
+ MouseCountX += diff;
+ m_lastmousex = NewX;
+ }
+
+ /* see if it moved in the y coord */
+ if (NewY != m_lastmousey)
+ {
+ int diff = (NewY - m_lastmousey);
+
+ /* check for wrap */
+ if (diff > 0x80)
+ diff = 0x100 - diff;
+ if (diff < -0x80)
+ diff = -0x100 - diff;
+
+ MouseCountY += diff;
+ m_lastmousey = NewY;
+ }
+
+ m_lastbutton = m_mouse0->read() & 0x01;
+ m_mouseX = MouseCountX;
+ m_mouseY = MouseCountY;
+// printf("X %02x Y %02x\n", m_mouseX, m_mouseY);
+}
+
+u16 macpbmsc_state::scsi_r(offs_t offset, u16 mem_mask)
+{
+ const int reg = (offset >> 3) & 0xf;
+ const bool pseudo_dma = (reg == 6) && (offset >= 0x130);
+
+ return m_scsihelp->read_wrapper(pseudo_dma, reg) << 8;
+}
+
+void macpbmsc_state::scsi_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ const int reg = (offset >> 3) & 0xf;
+ const bool pseudo_dma = (reg == 0) && (offset >= 0x100);
+
+ m_scsihelp->write_wrapper(pseudo_dma, reg, data>>8);
+}
+
+u32 macpbmsc_state::scsi_drq_r(offs_t offset, u32 mem_mask)
+{
+ switch (mem_mask)
+ {
+ case 0xff000000:
+ return m_scsihelp->read_wrapper(true, 6)<<24;
+
+ case 0xffff0000:
+ return (m_scsihelp->read_wrapper(true, 6)<<24) | (m_scsihelp->read_wrapper(true, 6)<<16);
+
+ case 0xffffffff:
+ return (m_scsihelp->read_wrapper(true, 6)<<24) | (m_scsihelp->read_wrapper(true, 6)<<16) | (m_scsihelp->read_wrapper(true, 6)<<8) | m_scsihelp->read_wrapper(true, 6);
+
+ default:
+ logerror("scsi_drq_r: unknown mem_mask %08x\n", mem_mask);
+ }
+
+ return 0;
+}
+
+void macpbmsc_state::scsi_drq_w(offs_t offset, u32 data, u32 mem_mask)
+{
+ switch (mem_mask)
+ {
+ case 0xff000000:
+ m_scsihelp->write_wrapper(true, 0, data>>24);
+ break;
+
+ case 0xffff0000:
+ m_scsihelp->write_wrapper(true, 0, data>>24);
+ m_scsihelp->write_wrapper(true, 0, data>>16);
+ break;
+
+ case 0xffffffff:
+ m_scsihelp->write_wrapper(true, 0, data>>24);
+ m_scsihelp->write_wrapper(true, 0, data>>16);
+ m_scsihelp->write_wrapper(true, 0, data>>8);
+ m_scsihelp->write_wrapper(true, 0, data&0xff);
+ break;
+
+ default:
+ logerror("scsi_drq_w: unknown mem_mask %08x\n", mem_mask);
+ break;
+ }
+}
+
+void macpbmsc_state::scsi_berr_w(u8 data)
+{
+ m_maincpu->pulse_input_line(M68K_LINE_BUSERROR, attotime::zero);
+}
+
+u8 macpbmsc_state::pmu_porta_r()
+{
+ if (m_portc == 0) // power key
+ {
+ return 0xdf | ((m_kbspecial->read() & 1) << 5);
+ }
+
+ // matrix X0-X7 (bits 0-7)
+ return m_keys[m_matrix_row]->read() & 0xff;
+}
+
+u8 macpbmsc_state::pmu_portb_r()
+{
+ // matrix X8-X10 (bits 0-2), modifiers (bits 3-7)
+ return (m_kbspecial->read() & 0xf8) | ((m_keys[m_matrix_row]->read() >> 8) & 7);
+}
+
+u8 macpbmsc_state::pmu_portc_r()
+{
+ return m_portc ^ 0xff;
+}
+
+void macpbmsc_state::pmu_portc_w(u8 data)
+{
+ m_portc = data ^ 0xff;
+
+ // matrix row select
+ m_matrix_row = 0;
+ for (u8 i = 0; i < 8; i++)
+ {
+ if (BIT(m_portc, i))
+ {
+ m_matrix_row = i;
+ return;
+ }
+ }
+}
+
+// bit 4 = 1 for US keyboard, 0 for ISO
+// bit 5 = 1 for sound power off
+// bit 6 = 1 for docking station NOT present
+// bit 7 = 1 for second mouse button NOT pressed
+u8 macpbmsc_state::pmu_portd_r()
+{
+ return (1 << 7) | (1 << 6) | (1 << 4); // no docking station, US keyboard
+}
+
+// bit 1 = screen power on/off
+// bit 2 = MSC /reset
+// bit 7 = data line for 1-wire Dallas comms with the battery
+u8 macpbmsc_state::pmu_porte_r()
+{
+ if (!machine().side_effects_disabled())
+ {
+ return (m_last_porte & 0x7f) | (m_battserial->read() << 7);
+ }
+
+ return m_last_porte;
+}
+
+void macpbmsc_state::pmu_porte_w(u8 data)
+{
+ if (BIT(data, 2) != BIT(m_last_porte, 2))
+ {
+ if (BIT(data, 2))
+ {
+ m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
+ }
+ m_msc->pmu_reset_w(BIT(data, 2) ^ 1);
+ }
+ m_maincpu->set_input_line(INPUT_LINE_RESET, BIT(data, 2) ? CLEAR_LINE : ASSERT_LINE);
+ if (BIT(data, 1) != BIT(m_last_porte, 1))
+ {
+ m_pmu_blank_display = BIT(data, 1);
+ if (m_gsc)
+ {
+ m_gsc->set_pmu_blank(m_pmu_blank_display);
+ }
+ else if (m_gsc)
+ {
+ m_csc->set_pmu_blank(m_pmu_blank_display);
+ }
+ }
+ if (BIT(data, 7) != BIT(m_last_porte, 7))
+ {
+ m_battserial->write(BIT(data, 7));
+ }
+ m_last_porte = data;
+}
+
+// bit 0 = Power (1 = off, 0 = on)
+// bit 2 = 1 for +5V present when input, cause level 1 interrupt when output (VIA CB2?)
+// bit 3 = clamshell open (1) or closed (0)
+// bit 6 = /PMREQ
+u8 macpbmsc_state::pmu_portf_r()
+{
+ u8 retval = (1 << 2); // indicate +5V present
+ retval |= (1 << 3); // indicate clamshell open
+ retval |= (m_msc->get_pmu_req() << 6);
+ return retval;
+}
+
+u8 macpbmsc_state::pmu_bat_low()
+{
+ return 0xff;
+}
+
+u8 macpbmsc_state::pmu_bat_high()
+{
+ return 0x7f;
+}
+
+u8 macpbmsc_state::pmu_bat_current()
+{
+ return 0x40;
+}
+
+u8 macpbmsc_state::pmu_bat_temp()
+{
+ return 131; // ~24 degrees C
+}
+
+u8 macpbmsc_state::pmu_ambient_temp()
+{
+ return 131; // ~24 degrees C
+}
+
+void macpbmsc_state::pmu_portf_w(u8 data)
+{
+ if (!BIT(data, 2) && BIT(m_last_portf, 2))
+ {
+ m_msc->cb1_int_hack(ASSERT_LINE);
+ }
+ else if (BIT(data, 2) && !BIT(m_last_portf, 2))
+ {
+ m_msc->cb1_int_hack(CLEAR_LINE);
+ }
+
+ m_last_portf = data;
+}
+
+// bit 3 = 1 for docking station powered up
+// bit 4 = caps lock LED
+// bit 5 = sleep LED
+// bit 6 = charger present (1 = present)
+u8 macpbmsc_state::pmu_portg_r()
+{
+ return (1 << 6); // indicate we're on a charger
+}
+
+// bit 1 set turns on the main battery power
+// bit 5 is sleep: 0 = normal operation, 1 = turn off 31.whatever MHz master clock
+void macpbmsc_state::pmu_portg_w(u8 data)
+{
+ if (BIT(data, 5) != BIT(m_last_portg, 5))
+ {
+ if (!BIT(data, 5))
+ {
+ m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
+ m_msc->pmu_reset_w(ASSERT_LINE);
+ m_msc->pmu_reset_w(CLEAR_LINE);
+ }
+ }
+
+ m_last_portg = data;
+}
+
+// bit 0 = DFAC reset
+// bit 1 = sleep LED (270c, maybe 280/280c also?)
+// bit 2 = NMI
+// bit 5 = DFAC latch
+// bit 6 = /PMACK
+u8 macpbmsc_state::pmu_porth_r()
+{
+ return m_last_porth;
+}
+
+void macpbmsc_state::pmu_porth_w(u8 data)
+{
+ m_dfac->latch_write(BIT(data, 5));
+ m_msc->pmu_ack_w(BIT(data, 6));
+ m_last_porth = data;
+}
+
+// bit 6 = DFAC clock
+// bit 7 = DFAC data
+void macpbmsc_state::pmu_portj_w(u8 data)
+{
+ m_dfac->clock_write(BIT(data, 6));
+ m_dfac->data_write(BIT(data, 7));
+}
+
+// bit 1 = main power to the CPU (1 = off, 0 = on)
+void macpbmsc_state::pmu_portl_w(u8 data)
+{
+ m_last_portl = data;
+}
+
+u8 macpbmsc_state::pmu_read_mouseX()
+{
+ return m_mouseX;
+}
+
+u8 macpbmsc_state::pmu_read_mouseY()
+{
+ return m_mouseY;
+}
+
+int macpbmsc_state::pmu_read_mouseButton()
+{
+ return m_lastbutton;
+}
+
+/***************************************************************************
+ ADDRESS MAPS
+****************************************************************************/
+
+void macpbmsc_state::macpd2xx_base_map(address_map &map)
+{
+ map(0x40000000, 0x600fffff).m(m_msc, FUNC(msc_device::map));
+
+ map(0x50f04000, 0x50f05fff).rw(FUNC(macpbmsc_state::scc_r), FUNC(macpbmsc_state::scc_w));
+ map(0x50f06000, 0x50f07fff).rw(FUNC(macpbmsc_state::scsi_drq_r), FUNC(macpbmsc_state::scsi_drq_w));
+ map(0x50f10000, 0x50f11fff).rw(FUNC(macpbmsc_state::scsi_r), FUNC(macpbmsc_state::scsi_w));
+ map(0x50f12060, 0x50f12063).r(FUNC(macpbmsc_state::scsi_drq_r));
+}
+
+void macpbmsc_state::macpd210_map(address_map &map)
+{
+ macpd2xx_base_map(map);
+
+ map(0x50000000, 0x6fffffff).m(m_gsc, FUNC(gsc_device::map));
+
+ map(0x5ffffffc, 0x5fffffff).lr32(NAME([](offs_t offset) { return 0xa55a1004; }));
+}
+
+void macpbmsc_state::macpd230_map(address_map &map)
+{
+ macpd210_map(map);
+
+ map(0x5ffffffc, 0x5fffffff).lr32(NAME([](offs_t offset) { return 0xa55a1005; }));
+}
+
+void macpbmsc_state::macpd250_map(address_map &map)
+{
+ macpd210_map(map);
+
+ map(0x5ffffffc, 0x5fffffff).lr32(NAME([](offs_t offset) { return 0xa55a1006; }));
+}
+
+void macpbmsc_state::macpd270c_map(address_map &map)
+{
+ macpd2xx_base_map(map);
+
+ map(0x50000000, 0x6fffffff).m(m_csc, FUNC(csc_device::map));
+
+ map(0x5ffffffc, 0x5fffffff).lr32(NAME([](offs_t offset) { return 0xa55a1002; }));
+}
+
+void macpbmsc_state::macpd280_map(address_map &map)
+{
+ macpd270c_map(map);
+
+ map(0x5ffffffc, 0x5fffffff).lr32(NAME([](offs_t offset) { return 0xa55a1000; }));
+}
+
+static INPUT_PORTS_START( dblite )
+ PORT_START("MOUSE0") /* Mouse - button */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Mouse Button") PORT_CODE(MOUSECODE_BUTTON1)
+
+ PORT_START("MOUSE1") /* Mouse - X AXIS */
+ PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
+
+ PORT_START("MOUSE2") /* Mouse - Y AXIS */
+ PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
+
+ PORT_START("Y0")
+ PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Tab") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9)
+ PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
+ PORT_BIT(0x004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
+ PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
+ PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
+ PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
+ PORT_BIT(0x080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(']') PORT_CHAR('}')
+ PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))
+ PORT_BIT(0x400, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("Y1")
+ PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')
+ PORT_BIT(0x004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
+ PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
+ PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_J) PORT_CHAR('j') PORT_CHAR('J')
+ PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
+ PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('\'') PORT_CHAR('\"')
+ PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(10)
+ PORT_BIT(0x400, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("Y2")
+ PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Esc") PORT_CODE(KEYCODE_ESC) PORT_CHAR(27)
+ PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Brightness Up") PORT_CODE(KEYCODE_F4) PORT_CHAR(UCHAR_MAMEKEY(F4))
+ PORT_BIT(0x004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Brightness Down") PORT_CODE(KEYCODE_F5) PORT_CHAR(UCHAR_MAMEKEY(F5))
+ PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')
+ PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')
+ PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_ENTER_PAD) PORT_CHAR(UCHAR_MAMEKEY(ENTER_PAD))
+ PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
+ PORT_BIT(0x400, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("Y3")
+ PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Contrast Down") PORT_CODE(KEYCODE_F6) PORT_CHAR(UCHAR_MAMEKEY(F6))
+ PORT_BIT(0x004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')
+ PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Contrast Up") PORT_CODE(KEYCODE_F7) PORT_CHAR(UCHAR_MAMEKEY(F7))
+ PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')
+ PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')
+ PORT_BIT(0x080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
+ PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT)
+ PORT_BIT(0x400, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("Y4")
+ PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_A) PORT_CHAR('A') PORT_CHAR('a')
+ PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
+ PORT_BIT(0x004, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
+ PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
+ PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')
+ PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
+ PORT_BIT(0x080, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
+ PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
+ PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT)
+ PORT_BIT(0x400, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("Y5")
+ PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
+ PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('@')
+ PORT_BIT(0x004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
+ PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('^')
+ PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('*')
+ PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR(')')
+ PORT_BIT(0x080, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('+')
+ PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x400, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("Y6")
+ PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')
+ PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_TILDE) PORT_CHAR('`') PORT_CHAR('~')
+ PORT_BIT(0x004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
+ PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
+ PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
+ PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
+ PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('[') PORT_CHAR('{')
+ PORT_BIT(0x080, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_BACKSLASH) PORT_CHAR('#') PORT_CHAR(U'^') // (actually to the left of the return key on the ASDF row)
+ PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Return") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13)
+ PORT_BIT(0x400, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("Y7")
+ PORT_BIT(0x001, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x002, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
+ PORT_BIT(0x004, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
+ PORT_BIT(0x008, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
+ PORT_BIT(0x010, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('&')
+ PORT_BIT(0x020, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR('(')
+ PORT_BIT(0x040, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('_')
+ PORT_BIT(0x080, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x100, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Delete") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
+ PORT_BIT(0x200, IP_ACTIVE_LOW, IPT_UNUSED)
+ PORT_BIT(0x400, IP_ACTIVE_LOW, IPT_UNUSED)
+
+ PORT_START("keyb_special")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Power") PORT_CODE(KEYCODE_F12)
+
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Command") PORT_CODE(KEYCODE_LALT)
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Control") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_SHIFT_2)
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Shift") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1)
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Option") PORT_CODE(KEYCODE_RALT)
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_KEYBOARD) PORT_NAME("Caps Lock") PORT_CODE(KEYCODE_CAPSLOCK) PORT_TOGGLE
+INPUT_PORTS_END
+
+/***************************************************************************
+ MACHINE DRIVERS
+***************************************************************************/
+
+void macpbmsc_state::macpd210(machine_config &config)
+{
+ M68030(config, m_maincpu, 25_MHz_XTAL);
+ m_maincpu->set_addrmap(AS_PROGRAM, &macpbmsc_state::macpd210_map);
+ m_maincpu->set_dasm_override(std::function(&mac68k_dasm_override), "mac68k_dasm_override");
+ m_maincpu->set_fpu_enable(false);
+
+ M68HC05PGE(config, m_pmu, 4.194304_MHz_XTAL);
+ m_pmu->read_p<m68hc05pge_device::PGE_PORTA>().set(FUNC(macpbmsc_state::pmu_porta_r));
+ m_pmu->read_p<m68hc05pge_device::PGE_PORTB>().set(FUNC(macpbmsc_state::pmu_portb_r));
+ m_pmu->read_p<m68hc05pge_device::PGE_PORTC>().set(FUNC(macpbmsc_state::pmu_portc_r));
+ m_pmu->write_p<m68hc05pge_device::PGE_PORTC>().set(FUNC(macpbmsc_state::pmu_portc_w));
+ m_pmu->read_p<m68hc05pge_device::PGE_PORTD>().set(FUNC(macpbmsc_state::pmu_portd_r));
+ m_pmu->read_p<m68hc05pge_device::PGE_PORTE>().set(FUNC(macpbmsc_state::pmu_porte_r));
+ m_pmu->write_p<m68hc05pge_device::PGE_PORTE>().set(FUNC(macpbmsc_state::pmu_porte_w));
+ m_pmu->read_p<m68hc05pge_device::PGE_PORTF>().set(FUNC(macpbmsc_state::pmu_portf_r));
+ m_pmu->write_p<m68hc05pge_device::PGE_PORTF>().set(FUNC(macpbmsc_state::pmu_portf_w));
+ m_pmu->read_p<m68hc05pge_device::PGE_PORTG>().set(FUNC(macpbmsc_state::pmu_portg_r));
+ m_pmu->write_p<m68hc05pge_device::PGE_PORTG>().set(FUNC(macpbmsc_state::pmu_portg_w));
+ m_pmu->read_p<m68hc05pge_device::PGE_PORTH>().set(FUNC(macpbmsc_state::pmu_porth_r));
+ m_pmu->write_p<m68hc05pge_device::PGE_PORTH>().set(FUNC(macpbmsc_state::pmu_porth_w));
+ m_pmu->write_p<m68hc05pge_device::PGE_PORTJ>().set(FUNC(macpbmsc_state::pmu_portj_w));
+ m_pmu->write_p<m68hc05pge_device::PGE_PORTL>().set(FUNC(macpbmsc_state::pmu_portl_w));
+ m_pmu->set_pullups<m68hc05pge_device::PGE_PORTC>(0xff);
+ m_pmu->set_pullups<m68hc05pge_device::PGE_PORTE>(0x80); // bit 7 of port E is the 1-Wire bus
+ m_pmu->ad_in<0>().set(FUNC(macpbmsc_state::pmu_bat_low));
+ m_pmu->ad_in<1>().set(FUNC(macpbmsc_state::pmu_bat_high));
+ m_pmu->ad_in<2>().set(FUNC(macpbmsc_state::pmu_bat_current));
+ m_pmu->ad_in<3>().set(FUNC(macpbmsc_state::pmu_bat_temp));
+ m_pmu->ad_in<4>().set(FUNC(macpbmsc_state::pmu_ambient_temp));
+ m_pmu->spi_clock_callback().set(m_msc, FUNC(msc_device::cb1_w));
+ m_pmu->spi_mosi_callback().set(m_msc, FUNC(msc_device::cb2_w));
+ m_pmu->read_tbB().set(FUNC(macpbmsc_state::pmu_read_mouseButton));
+ m_pmu->read_tbX().set(FUNC(macpbmsc_state::pmu_read_mouseX));
+ m_pmu->read_tbY().set(FUNC(macpbmsc_state::pmu_read_mouseY));
+
+ MSC(config, m_msc, 31.3344_MHz_XTAL);
+ m_msc->set_maincpu_tag("maincpu");
+ m_msc->set_pmu_tag("pge");
+ m_msc->set_rom_tag("bootrom");
+ m_msc->set_cpu_clock(25_MHz_XTAL);
+ m_msc->add_route(0, m_dfac, 1.0);
+ m_msc->add_route(1, m_dfac, 1.0);
+ m_msc->cb2_callback().set(m_pmu, FUNC(m68hc05pge_device::spi_miso_w));
+ m_msc->vbl_callback().set(FUNC(macpbmsc_state::vbl_w));
+
+ APPLE_DFAC(config, m_dfac, 22257);
+ m_dfac->add_route(0, "lspeaker", 1.0);
+ m_dfac->add_route(1, "rspeaker", 1.0);
+
+ GSC(config, m_gsc, 31.3344_MHz_XTAL);
+ m_gsc->set_panel_id(6);
+
+ NSCSI_BUS(config, "scsi");
+ NSCSI_CONNECTOR(config, "scsi:0", mac_scsi_devices, "harddisk");
+ NSCSI_CONNECTOR(config, "scsi:1", mac_scsi_devices, nullptr);
+ NSCSI_CONNECTOR(config, "scsi:2", mac_scsi_devices, nullptr);
+ NSCSI_CONNECTOR(config, "scsi:3").option_set("cdrom", NSCSI_CDROM_APPLE).machine_config(
+ [](device_t *device)
+ {
+ device->subdevice<cdda_device>("cdda")->add_route(0, "^^lspeaker", 1.0);
+ device->subdevice<cdda_device>("cdda")->add_route(1, "^^rspeaker", 1.0);
+ });
+ NSCSI_CONNECTOR(config, "scsi:4", mac_scsi_devices, nullptr);
+ NSCSI_CONNECTOR(config, "scsi:5", mac_scsi_devices, nullptr);
+ NSCSI_CONNECTOR(config, "scsi:6", mac_scsi_devices, nullptr);
+ NSCSI_CONNECTOR(config, "scsi:7").option_set("ncr5380", NCR53C80).machine_config([this](device_t *device) {
+ ncr53c80_device &adapter = downcast<ncr53c80_device &>(*device);
+ adapter.irq_handler().set(m_msc, FUNC(msc_device::scsi_irq_w));
+ adapter.drq_handler().set(m_scsihelp, FUNC(mac_scsi_helper_device::drq_w));
+ });
+
+ MAC_SCSI_HELPER(config, m_scsihelp);
+ m_scsihelp->scsi_read_callback().set(m_ncr5380, FUNC(ncr53c80_device::read));
+ m_scsihelp->scsi_write_callback().set(m_ncr5380, FUNC(ncr53c80_device::write));
+ m_scsihelp->scsi_dma_read_callback().set(m_ncr5380, FUNC(ncr53c80_device::dma_r));
+ m_scsihelp->scsi_dma_write_callback().set(m_ncr5380, FUNC(ncr53c80_device::dma_w));
+ m_scsihelp->cpu_halt_callback().set_inputline(m_maincpu, INPUT_LINE_HALT);
+ m_scsihelp->timeout_error_callback().set(FUNC(macpbmsc_state::scsi_berr_w));
+
+ SCC85C30(config, m_scc, 31.3344_MHz_XTAL / 4);
+ m_scc->out_int_callback().set(m_msc, FUNC(msc_device::scc_irq_w));
+
+ DS2401(config, m_battserial, 0); // actually DS2400, but 2400/2401 are compatible
+
+ SPEAKER(config, "lspeaker").front_left();
+ SPEAKER(config, "rspeaker").front_right();
+
+ RAM(config, m_ram);
+ m_ram->set_default_size("4M");
+ m_ram->set_extra_options("8M,12M,16M,24M");
+
+ SOFTWARE_LIST(config, "hdd_list").set_original("mac_hdd");
+ SOFTWARE_LIST(config, "cd_list").set_original("mac_cdrom").set_filter("MC68030,MC68030_32");
+}
+
+void macpbmsc_state::macpd230(machine_config &config)
+{
+ macpd210(config);
+ m_maincpu->set_clock(33_MHz_XTAL);
+ m_maincpu->set_addrmap(AS_PROGRAM, &macpbmsc_state::macpd230_map);
+ m_msc->set_cpu_clock(33_MHz_XTAL);
+}
+
+void macpbmsc_state::macpd250(machine_config &config)
+{
+ macpd230(config);
+ m_maincpu->set_fpu_enable(true);
+ m_maincpu->set_addrmap(AS_PROGRAM, &macpbmsc_state::macpd250_map);
+}
+
+void macpbmsc_state::macpd270c(machine_config &config)
+{
+ macpd230(config);
+ config.device_remove("gsc");
+
+ CSC(config, m_csc, 31.3344_MHz_XTAL);
+ m_csc->write_irq().set(m_msc, FUNC(msc_device::lcd_irq_w));
+ m_csc->set_panel_id(0);
+
+ m_maincpu->set_fpu_enable(true);
+ m_maincpu->set_addrmap(AS_PROGRAM, &macpbmsc_state::macpd270c_map);
+}
+
+void macpbmsc_state::macpd280(machine_config &config)
+{
+ macpd270c(config);
+
+ m_csc->set_panel_id(4);
+
+ M68040(config.replace(), m_maincpu, 33_MHz_XTAL/2);
+ m_maincpu->set_addrmap(AS_PROGRAM, &macpbmsc_state::macpd280_map);
+}
+
+void macpbmsc_state::macpd280c(machine_config &config)
+{
+ macpd280(config);
+
+ m_csc->set_panel_id(0);
+}
+
+ROM_START(macpd210)
+ ROM_REGION32_BE(0x100000, "bootrom", 0)
+ ROM_LOAD("ecfa989b.rom", 0x000000, 0x100000, CRC(b86ed854) SHA1(ed1371c97117a5884da4a6605ecfc5abed48ae5a))
+
+ // battery serial number, read from an embedded Dallas DS2400
+ ROM_REGION(0x8, "ds2400", ROMREGION_ERASE00)
+ ROM_LOAD( "duobatid.bin", 0x000000, 0x000008, CRC(7545c341) SHA1(61b094ee5b398077f70eaa1887921c8366f7abfe) )
+ROM_END
+
+ROM_START(macpd270c)
+ ROM_REGION32_BE(0x100000, "bootrom", 0)
+ ROM_LOAD( "0024d346.rom", 0x000000, 0x100000, CRC(94c4d04a) SHA1(be7bd9637203e4513b896146ddfc85c37817d131) )
+
+ ROM_REGION(0x8, "ds2400", ROMREGION_ERASE00)
+ ROM_LOAD( "duobatid.bin", 0x000000, 0x000008, CRC(7545c341) SHA1(61b094ee5b398077f70eaa1887921c8366f7abfe) )
+ROM_END
+
+ROM_START(macpd280)
+ ROM_REGION32_BE(0x100000, "bootrom", 0)
+ ROM_LOAD("015621d7.rom", 0x000000, 0x100000, CRC(568d28eb) SHA1(d49dd69cf038784b8849793ad3c0e62c2d11f653))
+
+ ROM_REGION(0x8, "ds2400", ROMREGION_ERASE00)
+ ROM_LOAD( "duobatid.bin", 0x000000, 0x000008, CRC(7545c341) SHA1(61b094ee5b398077f70eaa1887921c8366f7abfe) )
+ROM_END
+
+#define rom_macpd230 rom_macpd210
+#define rom_macpd250 rom_macpd210
+#define rom_macpd280c rom_macpd280
+
+} // anonymous namespace
+
+COMP(1992, macpd210, 0, 0, macpd210, dblite, macpbmsc_state, empty_init, "Apple Computer", "Macintosh PowerBook Duo 210", MACHINE_SUPPORTS_SAVE)
+COMP(1992, macpd230, macpd210, 0, macpd230, dblite, macpbmsc_state, empty_init, "Apple Computer", "Macintosh PowerBook Duo 230", MACHINE_SUPPORTS_SAVE)
+COMP(1993, macpd250, macpd210, 0, macpd250, dblite, macpbmsc_state, empty_init, "Apple Computer", "Macintosh PowerBook Duo 250", MACHINE_SUPPORTS_SAVE)
+COMP(1993, macpd270c, 0, 0, macpd270c, dblite, macpbmsc_state, empty_init, "Apple Computer", "Macintosh PowerBook Duo 270c", MACHINE_SUPPORTS_SAVE)
+COMP(1994, macpd280, 0, 0, macpd280, dblite, macpbmsc_state, empty_init, "Apple Computer", "Macintosh PowerBook Duo 280", MACHINE_SUPPORTS_SAVE)
+COMP(1994, macpd280c, macpd280, 0, macpd280c, dblite, macpbmsc_state, empty_init, "Apple Computer", "Macintosh PowerBook Duo 280c", MACHINE_SUPPORTS_SAVE)
diff --git a/src/mame/apple/msc.cpp b/src/mame/apple/msc.cpp
new file mode 100644
index 00000000000..b5c9aeff0d3
--- /dev/null
+++ b/src/mame/apple/msc.cpp
@@ -0,0 +1,508 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+/*
+ Apple "MSC" (Main System Controller) system ASIC
+ Emulation by R. Belmont
+
+ MSC contains the following:
+ - A memory controller for up to 36MB (up to 4MB soldered and 32MB of SIMMs)
+ - A modified VIA (VIA1) and a "pseudo-VIA", which is basically a combination GPIO and
+ interrupt controller that looks somewhat like a VIA with no timers and no shift register.
+ - An EASC-like 4-channel audio controller
+ - Power management support functions
+
+ MSC II is identical, but with a 68040 bus interface instead of 68030.
+*/
+
+#include "emu.h"
+#include "msc.h"
+
+static constexpr u32 C7M = 7833600;
+static constexpr u32 C15M = (C7M * 2);
+
+[[maybe_unused]] static constexpr u8 SOUND_POWER = 0; // 0 = DFAC power off, 1 = DFAC power on
+static constexpr u8 SOUND_BUSY = 6; // 1 = ASC FIFO accessed since last read of this register
+[[maybe_unused]] static constexpr u8 SOUND_LATCH = 7; // 1 = DFAC is powered up
+
+DEFINE_DEVICE_TYPE(MSC, msc_device, "msc", "Apple MSC system ASIC")
+DEFINE_DEVICE_TYPE(MSC_VIA, mscvia_device, "mscvia", "Apple MSC integrated VIA")
+
+void msc_device::map(address_map &map)
+{
+ map(0x00000000, 0x000fffff).r(FUNC(msc_device::rom_switch_r)).mirror(0x0ff00000);
+
+ map(0x10f00000, 0x10f01fff).rw(FUNC(msc_device::via_r), FUNC(msc_device::via_w));
+ map(0x10f14000, 0x10f15fff).rw(m_asc, FUNC(asc_device::read), FUNC(asc_device::write));
+ map(0x10f26000, 0x10f27fff).rw(FUNC(msc_device::via2_r), FUNC(msc_device::via2_w));
+ map(0x10fa0000, 0x10fa0003).w(FUNC(msc_device::power_cycle_w));
+}
+
+//-------------------------------------------------
+// device_add_mconfig - add device configuration
+//-------------------------------------------------
+
+void msc_device::device_add_mconfig(machine_config &config)
+{
+ MSC_VIA(config, m_via1, C7M / 10);
+ m_via1->readpa_handler().set(FUNC(msc_device::via_in_a));
+ m_via1->readpb_handler().set(FUNC(msc_device::via_in_b));
+ m_via1->writepa_handler().set(FUNC(msc_device::via_out_a));
+ m_via1->writepb_handler().set(FUNC(msc_device::via_out_b));
+ m_via1->cb2_handler().set(FUNC(msc_device::via_out_cb2));
+ m_via1->irq_handler().set(FUNC(msc_device::via1_irq));
+
+ APPLE_PSEUDOVIA(config, m_pseudovia, C15M);
+ m_pseudovia->irq_callback().set(FUNC(msc_device::via2_irq));
+ m_pseudovia->readpa_handler().set(FUNC(msc_device::via2_in_a));
+ m_pseudovia->readpb_handler().set(FUNC(msc_device::via2_in_b));
+ m_pseudovia->writepa_handler().set(FUNC(msc_device::via2_out_a));
+ m_pseudovia->writepb_handler().set(FUNC(msc_device::via2_out_b));
+ m_pseudovia->readmsc_handler().set(FUNC(msc_device::msc_pseudovia_r));
+ m_pseudovia->writemsc_handler().set(FUNC(msc_device::msc_pseudovia_w));
+ m_pseudovia->readvideo_handler().set(FUNC(msc_device::msc_config_r));
+ m_pseudovia->writevideo_handler().set(FUNC(msc_device::msc_config_w));
+
+ ASC(config, m_asc, C15M, asc_device::asc_type::EASC);
+ m_asc->add_route(0, tag(), 1.0);
+ m_asc->add_route(1, tag(), 1.0);
+ m_asc->irqf_callback().set(m_pseudovia, FUNC(pseudovia_device::asc_irq_w));
+}
+
+mscvia_device::mscvia_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : via6522_device(mconfig, MSC_VIA, tag, owner, clock)
+{
+}
+
+msc_device::msc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, MSC, tag, owner, clock),
+ device_sound_interface(mconfig, *this),
+ write_pb4(*this),
+ write_pb5(*this),
+ write_cb2(*this),
+ write_vbl(*this),
+ read_pb3(*this, 0),
+ m_maincpu(*this, finder_base::DUMMY_TAG),
+ m_pmu(*this, finder_base::DUMMY_TAG),
+ m_via1(*this, "via1"),
+ m_pseudovia(*this, "pseudovia"),
+ m_asc(*this, "asc"),
+ m_rom(*this, finder_base::DUMMY_TAG),
+ m_via_interrupt(0),
+ m_pmu_interrupt(0),
+ m_via2_interrupt(0),
+ m_scc_interrupt(0),
+ m_overlay(false),
+ m_pmu_req(1),
+ m_pmu_ack(1),
+ m_msc_config(0),
+ m_msc_clock_ctrl(0),
+ m_msc_sound_ctrl(0)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void msc_device::device_start()
+{
+ m_stream = stream_alloc(8, 2, m_asc->clock(), STREAM_SYNCHRONOUS);
+
+ m_6015_timer = timer_alloc(FUNC(msc_device::msc_6015_tick), this);
+ m_6015_timer->adjust(attotime::never);
+
+ save_item(NAME(m_via_interrupt));
+ save_item(NAME(m_pmu_interrupt));
+ save_item(NAME(m_via2_interrupt));
+ save_item(NAME(m_scc_interrupt));
+ save_item(NAME(m_overlay));
+ save_item(NAME(m_last_taken_interrupt));
+ save_item(NAME(m_pmu_ack));
+ save_item(NAME(m_pmu_req));
+ save_item(NAME(m_msc_config));
+ save_item(NAME(m_msc_clock_ctrl));
+ save_item(NAME(m_msc_sound_ctrl));
+
+ m_rom_ptr = &m_rom[0];
+ m_rom_size = m_rom.length() << 2;
+
+ // power management needs to know if the user is idle but sound is playing, so as not to put the machine to sleep
+ m_maincpu->space(AS_PROGRAM).install_write_tap(0x50f14000, 0x50f15fff, "snd_latch_mon", [this](offs_t offset, u32 &data, u32 mem_mask)
+ {
+ this->m_msc_sound_ctrl |= (1 << SOUND_BUSY);
+ });
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void msc_device::device_reset()
+{
+ // start 60.15 Hz timer
+ m_6015_timer->adjust(attotime::from_hz(60.15), 0, attotime::from_hz(60.15));
+
+ m_via_interrupt = m_via2_interrupt = m_scc_interrupt = 0;
+ m_last_taken_interrupt = -1;
+
+ // main cpu shouldn't start until PMU wakes it up
+ m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
+
+ m_overlay = true;
+
+ // put ROM mirror at 0
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ const u32 memory_size = std::min((u32)0x3fffff, m_rom_size);
+ const u32 memory_end = memory_size - 1;
+ offs_t memory_mirror = memory_end & ~(memory_size - 1);
+
+ space.unmap_write(0x00000000, memory_end);
+ space.install_rom(0x00000000, memory_end & ~memory_mirror, memory_mirror, m_rom_ptr);
+}
+
+void msc_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
+{
+ for (int i = 0; i < inputs[0].samples(); i++)
+ {
+ outputs[0].put(i, inputs[0].get(i));
+ outputs[1].put(i, inputs[1].get(i));
+ }
+}
+
+u32 msc_device::rom_switch_r(offs_t offset)
+{
+ // disable the overlay
+ if (m_overlay && !machine().side_effects_disabled())
+ {
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ const u32 memory_end = m_ram_size - 1;
+ void *memory_data = m_ram_ptr;
+ offs_t memory_mirror = memory_end & ~memory_end;
+
+ space.install_ram(0x00000000, memory_end & ~memory_mirror, memory_mirror, memory_data);
+ m_overlay = false;
+ }
+
+ return m_rom_ptr[offset & ((m_rom_size - 1) >> 2)];
+}
+
+void msc_device::set_cpu_clock(XTAL clock)
+{
+ m_cpu_clock = clock.value();
+}
+
+void msc_device::power_cycle_w(u32 data)
+{
+ // CPU power down control. Expects the CPU to reset after a short delay and resume.
+ // We make that no delay, since we don't care about saving power.
+ // Called with 0 for normal delay and resume, 0xffffffff for actual full system sleep on 210/230,
+ // ff000000 for full system sleep on later machines, and 5a000000 for power cycle.
+ if ((data == 0) || (data == 0x5a000000))
+ {
+ m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
+ m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
+ }
+ else
+ {
+ m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
+ }
+}
+
+u8 msc_device::msc_config_r()
+{
+ return m_msc_config;
+}
+
+void msc_device::msc_config_w(u8 data)
+{
+ if (BIT(data, 1) != BIT(m_msc_clock_ctrl, 1))
+ {
+ m_maincpu->set_clock(BIT(data, 1) ? clock() / 2 : m_cpu_clock);
+ }
+
+ m_msc_config = data;
+}
+
+u8 msc_device::msc_pseudovia_r(offs_t offset)
+{
+ switch (offset)
+ {
+ case 1:
+ return m_msc_clock_ctrl;
+
+ case 2:
+ {
+ const u8 retval = m_msc_sound_ctrl;
+ m_msc_sound_ctrl &= ~(1 << SOUND_BUSY);
+ return retval;
+ }
+ }
+
+ return 0;
+}
+
+void msc_device::msc_pseudovia_w(offs_t offset, u8 data)
+{
+ switch (offset)
+ {
+ case 1:
+ m_msc_clock_ctrl = data;
+ break;
+
+ case 2:
+ m_msc_sound_ctrl = data;
+ break;
+ }
+}
+
+void msc_device::set_ram_info(u32 *ram, u32 size)
+{
+ m_ram_ptr = ram;
+ m_ram_size = size;
+}
+
+TIMER_CALLBACK_MEMBER(msc_device::msc_6015_tick)
+{
+ m_via1->write_ca1(CLEAR_LINE);
+ m_via1->write_ca1(ASSERT_LINE);
+
+ write_vbl(ASSERT_LINE);
+}
+
+u8 msc_device::via_in_a()
+{
+ return 0x07;
+}
+
+u8 msc_device::via_in_b()
+{
+ return 0;
+}
+
+void msc_device::via_out_cb2(int state)
+{
+ write_cb2(state & 1);
+}
+
+void msc_device::via_out_a(u8 data)
+{
+}
+
+void msc_device::via_out_b(u8 data)
+{
+}
+
+void msc_device::via1_irq(int state)
+{
+ m_via_interrupt = state;
+ field_interrupts();
+}
+
+u8 msc_device::via2_r(offs_t offset)
+{
+ if (!machine().side_effects_disabled())
+ {
+ via_sync();
+ via_sync();
+ via_sync();
+ via_sync();
+ }
+
+ return m_pseudovia->read(offset);
+}
+
+void msc_device::via2_w(offs_t offset, u8 data)
+{
+ via_sync();
+ via_sync();
+ via_sync();
+ via_sync();
+ m_pseudovia->write(offset, data);
+}
+
+u8 msc_device::via2_in_a()
+{
+ return 0;
+}
+
+u8 msc_device::via2_in_b()
+{
+ return ((m_pmu_ack & 1) << 1) | (m_pmu_req << 2);
+}
+
+void msc_device::via2_out_a(u8 data)
+{
+}
+
+void msc_device::via2_out_b(u8 data)
+{
+ if (m_pmu_req != BIT(data, 2))
+ {
+ m_pmu_req = BIT(data, 2);
+ m_maincpu->spin_until_time(attotime::from_usec(80));
+ }
+}
+
+void msc_device::via2_irq(int state)
+{
+ m_via2_interrupt = state;
+ field_interrupts();
+}
+
+int msc_device::get_pmu_req()
+{
+ return m_pmu_req;
+}
+
+void msc_device::pmu_ack_w(int state)
+{
+ if (m_pmu_ack != state)
+ {
+ m_pmu_ack = state;
+ m_pmu->spin_until_time(attotime::from_usec(20));
+ }
+}
+
+void msc_device::pmu_reset_w(int state)
+{
+ if (!state)
+ {
+ // put ROM mirror at 0 for reset
+ address_space &space = m_maincpu->space(AS_PROGRAM);
+ const u32 memory_size = std::min((u32)0x3fffff, m_rom_size);
+ const u32 memory_end = memory_size - 1;
+ offs_t memory_mirror = memory_end & ~(memory_size - 1);
+
+ space.unmap_write(0x00000000, memory_end);
+ space.install_rom(0x00000000, memory_end & ~memory_mirror, memory_mirror, m_rom_ptr);
+ m_overlay = true;
+ }
+ m_maincpu->set_input_line(INPUT_LINE_RESET, state);
+}
+
+void msc_device::cb1_int_hack(int state)
+{
+ if (state)
+ {
+ m_via1->cb1_int_hack(ASSERT_LINE);
+ }
+}
+
+void msc_device::field_interrupts()
+{
+ int take_interrupt = -1;
+
+ if (m_scc_interrupt)
+ {
+ take_interrupt = 4;
+ }
+ else if (m_via2_interrupt)
+ {
+ take_interrupt = 2;
+ }
+ else if (m_pmu_interrupt && ((m_via1->read(via6522_device::VIA_IER) & 0x90) == 0x90))
+ {
+ take_interrupt = 1;
+ }
+ else if (m_via_interrupt)
+ {
+ take_interrupt = 1;
+ }
+
+ if (m_last_taken_interrupt > -1)
+ {
+ m_maincpu->set_input_line(m_last_taken_interrupt, CLEAR_LINE);
+ m_last_taken_interrupt = -1;
+ }
+
+ if (take_interrupt > -1)
+ {
+ m_maincpu->set_input_line(take_interrupt, ASSERT_LINE);
+ m_last_taken_interrupt = take_interrupt;
+ }
+}
+
+void msc_device::scc_irq_w(int state)
+{
+ m_scc_interrupt = (state == ASSERT_LINE);
+ field_interrupts();
+}
+
+void msc_device::scsi_irq_w(int state)
+{
+ m_pseudovia->scsi_irq_w(state);
+}
+
+void msc_device::slot0_irq_w(int state)
+{
+ m_pseudovia->slot_irq_w<0x08>(state);
+}
+
+void msc_device::slot1_irq_w(int state)
+{
+ m_pseudovia->slot_irq_w<0x10>(state);
+}
+
+void msc_device::slot2_irq_w(int state)
+{
+ m_pseudovia->slot_irq_w<0x20>(state);
+}
+
+void msc_device::lcd_irq_w(int state)
+{
+ m_pseudovia->slot_irq_w<0x40>(state);
+}
+
+void msc_device::cb1_w(int state)
+{
+ m_via1->write_cb1(state);
+}
+
+void msc_device::cb2_w(int state)
+{
+ m_via1->write_cb2(state);
+}
+
+u16 msc_device::via_r(offs_t offset)
+{
+ offset >>= 8;
+ offset &= 0x0f;
+
+ if (!machine().side_effects_disabled())
+ via_sync();
+
+ return m_via1->read(offset) << 8;
+}
+
+void msc_device::via_w(offs_t offset, u16 data, u16 mem_mask)
+{
+ offset >>= 8;
+ offset &= 0x0f;
+ data >>= 8;
+
+ via_sync();
+ m_via1->write(offset, data & 0xff);
+}
+
+void msc_device::via_sync()
+{
+ // The via runs at 783.36KHz while the main cpu runs at 15MHz or
+ // more, so we need to sync the access with the via clock. Plus
+ // the whole access takes half a (via) cycle and ends when synced
+ // with the main cpu again.
+
+ // Get the main cpu time
+ u64 cycle = m_maincpu->total_cycles();
+
+ // Get the number of the cycle the via is in at that time
+ u64 via_cycle = cycle * m_via1->clock() / m_maincpu->clock();
+
+ // The access is going to start at via_cycle+1 and end at
+ // via_cycle+1.5, compute what that means in maincpu cycles (the
+ // +1 rounds up, since the clocks are too different to ever be
+ // synced).
+ u64 main_cycle = (via_cycle * 2 + 3) * m_maincpu->clock() / (2 * m_via1->clock()) + 1;
+
+ // Finally adjust the main cpu icount as needed.
+ m_maincpu->adjust_icount(-int(main_cycle - cycle));
+}
diff --git a/src/mame/apple/msc.h b/src/mame/apple/msc.h
new file mode 100644
index 00000000000..1b51a4cc11a
--- /dev/null
+++ b/src/mame/apple/msc.h
@@ -0,0 +1,128 @@
+// license:BSD-3-Clause
+// copyright-holders:R. Belmont
+
+#ifndef MAME_APPLE_MSC_H
+#define MAME_APPLE_MSC_H
+
+#pragma once
+
+#include "pseudovia.h"
+
+#include "machine/6522via.h"
+#include "sound/asc.h"
+#include "speaker.h"
+
+class mscvia_device : public via6522_device
+{
+public:
+ mscvia_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ // Something is definitely customized with how PB1 interrupts work in the MSC's internal VIA1.
+ // This makes CPU/PMU comms work properly and fits with what we see in the leaked System 7.1
+ // source tree, but I'm not sure it's the exact behavior of the real MSC.
+ void cb1_int_hack(int state)
+ {
+ if (state == ASSERT_LINE)
+ {
+ set_int(0x10); // INT_CB1
+ }
+ }
+};
+
+class msc_device : public device_t, public device_sound_interface
+{
+public:
+ msc_device(const machine_config &mconfig, const char *tag, device_t *owner)
+ : msc_device(mconfig, tag, owner, (uint32_t)0)
+ {
+ }
+
+ msc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ auto pb4_callback() { return write_pb4.bind(); }
+ auto pb5_callback() { return write_pb5.bind(); }
+ auto cb2_callback() { return write_cb2.bind(); }
+ auto vbl_callback() { return write_vbl.bind(); }
+ auto pb3_callback() { return read_pb3.bind(); }
+
+ void map(address_map &map) ATTR_COLD;
+
+ template <typename... T> void set_maincpu_tag(T &&... args) { m_maincpu.set_tag(std::forward<T>(args)...); }
+ template <typename... T> void set_pmu_tag(T &&... args) { m_pmu.set_tag(std::forward<T>(args)...); }
+ template <typename... T> void set_rom_tag(T &&... args) { m_rom.set_tag(std::forward<T>(args)...); }
+ void set_ram_info(u32 *ram, u32 size);
+ void set_cpu_clock(XTAL clock);
+
+ void cb1_w(int state);
+ void cb2_w(int state);
+ void scc_irq_w(int state);
+ void scsi_irq_w(int state);
+ void slot0_irq_w(int state);
+ void slot1_irq_w(int state);
+ void slot2_irq_w(int state);
+ void lcd_irq_w(int state);
+ void pmu_reset_w(int state);
+
+ void via_sync();
+
+ int get_pmu_req();
+ void pmu_ack_w(int state);
+ void cb1_int_hack(int state);
+
+protected:
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
+
+ virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
+
+private:
+ devcb_write_line write_pb4, write_pb5, write_cb2, write_vbl;
+ devcb_read_line read_pb3;
+
+ required_device<cpu_device> m_maincpu, m_pmu;
+ required_device<mscvia_device> m_via1;
+ required_device<pseudovia_device> m_pseudovia;
+ required_device<asc_device> m_asc;
+ required_region_ptr<u32> m_rom;
+
+ sound_stream *m_stream;
+ emu_timer *m_6015_timer;
+ u32 m_cpu_clock;
+ int m_via_interrupt, m_pmu_interrupt, m_via2_interrupt, m_scc_interrupt, m_last_taken_interrupt;
+ bool m_overlay;
+ u32 *m_ram_ptr, *m_rom_ptr;
+ u32 m_ram_size, m_rom_size;
+ u8 m_pmu_req, m_pmu_ack;
+ u8 m_msc_config, m_msc_clock_ctrl, m_msc_sound_ctrl;
+
+ u32 rom_switch_r(offs_t offset);
+ void power_cycle_w(u32 data);
+ u8 msc_config_r();
+ void msc_config_w(u8 data);
+ u8 msc_pseudovia_r(offs_t offset);
+ void msc_pseudovia_w(offs_t offset, u8 data);
+
+ u16 via_r(offs_t offset);
+ void via_w(offs_t offset, u16 data, u16 mem_mask);
+ u8 via2_r(offs_t offset);
+ void via2_w(offs_t offset, u8 data);
+
+ u8 via_in_a();
+ u8 via_in_b();
+ void via_out_a(u8 data);
+ void via_out_b(u8 data);
+ u8 via2_in_a();
+ u8 via2_in_b();
+ void via2_out_a(u8 data);
+ void via2_out_b(u8 data);
+ void field_interrupts();
+ void via_out_cb2(int state);
+ void via1_irq(int state);
+ void via2_irq(int state);
+ TIMER_CALLBACK_MEMBER(msc_6015_tick);
+};
+
+DECLARE_DEVICE_TYPE(MSC, msc_device)
+
+#endif // MAME_APPLE_MSC_H
diff --git a/src/mame/apple/pseudovia.cpp b/src/mame/apple/pseudovia.cpp
index 92743e229f8..4474efb01ff 100644
--- a/src/mame/apple/pseudovia.cpp
+++ b/src/mame/apple/pseudovia.cpp
@@ -33,10 +33,12 @@ pseudovia_device::pseudovia_device(const machine_config &mconfig, const char *ta
m_in_b_handler(*this, 0),
m_in_config_handler(*this, 0),
m_in_video_handler(*this, 0),
+ m_in_msc_handler(*this, 0),
m_out_a_handler(*this),
m_out_b_handler(*this),
m_out_config_handler(*this),
m_out_video_handler(*this),
+ m_out_msc_handler(*this),
m_pseudovia_ier(0),
m_pseudovia_ifr(0)
{
@@ -181,6 +183,11 @@ uint8_t pseudovia_device::read(offs_t offset)
{
data &= ~0x80;
}
+
+ if ((offset >= 0x20) && (offset <= 0x2f))
+ {
+ data = m_in_msc_handler(offset & 0xf);
+ }
}
else
{
@@ -272,6 +279,10 @@ void pseudovia_device::write(offs_t offset, uint8_t data)
break;
default:
+ if ((offset >= 0x20) && (offset <= 0x2f))
+ {
+ m_out_msc_handler(offset & 0xf, data);
+ }
m_pseudovia_regs[offset] = data;
break;
}
diff --git a/src/mame/apple/pseudovia.h b/src/mame/apple/pseudovia.h
index 5887162736e..31154def859 100644
--- a/src/mame/apple/pseudovia.h
+++ b/src/mame/apple/pseudovia.h
@@ -16,10 +16,12 @@ public:
auto readpb_handler() { return m_in_b_handler.bind(); }
auto readconfig_handler() { return m_in_config_handler.bind(); }
auto readvideo_handler() { return m_in_video_handler.bind(); }
+ auto readmsc_handler() { return m_in_msc_handler.bind(); }
auto writepa_handler() { return m_out_a_handler.bind(); }
auto writepb_handler() { return m_out_b_handler.bind(); }
auto writeconfig_handler() { return m_out_config_handler.bind(); }
auto writevideo_handler() { return m_out_video_handler.bind(); }
+ auto writemsc_handler() { return m_out_msc_handler.bind(); }
auto irq_callback() { return m_write_irq.bind(); }
uint8_t read(offs_t offset);
@@ -38,8 +40,8 @@ protected:
private:
devcb_write_line m_write_irq;
- devcb_read8 m_in_a_handler, m_in_b_handler, m_in_config_handler, m_in_video_handler;
- devcb_write8 m_out_a_handler, m_out_b_handler, m_out_config_handler, m_out_video_handler;
+ devcb_read8 m_in_a_handler, m_in_b_handler, m_in_config_handler, m_in_video_handler, m_in_msc_handler;
+ devcb_write8 m_out_a_handler, m_out_b_handler, m_out_config_handler, m_out_video_handler, m_out_msc_handler;
uint8_t m_pseudovia_regs[256], m_pseudovia_ier, m_pseudovia_ifr;
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index 33d888c5f38..e8ea80c11c4 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -958,7 +958,14 @@ macpb165c
macpb170
macpb180
macpb180c
+
+@source:apple/macpwrbkmsc.cpp
macpd210
+macpd230
+macpd250
+macpd270c
+macpd280
+macpd280c
@source:apple/macquadra605.cpp
macqd605