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]
This commit is contained in:
arbee 2025-02-10 22:46:29 -05:00
parent 21e5da0532
commit f2ba762e0a
15 changed files with 3320 additions and 170 deletions

View File

@ -2012,6 +2012,8 @@ if CPUS["M6805"] then
MAME_DIR .. "src/devices/cpu/m6805/m68hc05.h",
MAME_DIR .. "src/devices/cpu/m6805/m68hc05e1.cpp",
MAME_DIR .. "src/devices/cpu/m6805/m68hc05e1.h",
MAME_DIR .. "src/devices/cpu/m6805/m68hc05pge.cpp",
MAME_DIR .. "src/devices/cpu/m6805/m68hc05pge.h",
}
end

View File

@ -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;
}

View File

@ -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

View File

@ -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);

340
src/mame/apple/csc.cpp Normal file
View File

@ -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]);
}

55
src/mame/apple/csc.h Normal file
View File

@ -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 */

176
src/mame/apple/gsc.cpp Normal file
View File

@ -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]);
}

51
src/mame/apple/gsc.h Normal file
View File

@ -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 */

View File

@ -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)

View File

@ -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)

508
src/mame/apple/msc.cpp Normal file
View File

@ -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));
}

128
src/mame/apple/msc.h Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -958,7 +958,14 @@ macpb165c
macpb170
macpb180
macpb180c
@source:apple/macpwrbkmsc.cpp
macpd210
macpd230
macpd250
macpd270c
macpd280
macpd280c
@source:apple/macquadra605.cpp
macqd605