mirror of
https://github.com/holub/mame
synced 2025-04-17 22:13:04 +03:00
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:
parent
21e5da0532
commit
f2ba762e0a
@ -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
|
||||
|
||||
|
926
src/devices/cpu/m6805/m68hc05pge.cpp
Normal file
926
src/devices/cpu/m6805/m68hc05pge.cpp
Normal 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(¯ef);
|
||||
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;
|
||||
}
|
150
src/devices/cpu/m6805/m68hc05pge.h
Normal file
150
src/devices/cpu/m6805/m68hc05pge.h
Normal 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
|
@ -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
340
src/mame/apple/csc.cpp
Normal 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
55
src/mame/apple/csc.h
Normal 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
176
src/mame/apple/gsc.cpp
Normal 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
51
src/mame/apple/gsc.h
Normal 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 */
|
@ -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)
|
||||
|
937
src/mame/apple/macpwrbkmsc.cpp
Normal file
937
src/mame/apple/macpwrbkmsc.cpp
Normal 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
508
src/mame/apple/msc.cpp
Normal 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
128
src/mame/apple/msc.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -958,7 +958,14 @@ macpb165c
|
||||
macpb170
|
||||
macpb180
|
||||
macpb180c
|
||||
|
||||
@source:apple/macpwrbkmsc.cpp
|
||||
macpd210
|
||||
macpd230
|
||||
macpd250
|
||||
macpd270c
|
||||
macpd280
|
||||
macpd280c
|
||||
|
||||
@source:apple/macquadra605.cpp
|
||||
macqd605
|
||||
|
Loading…
Reference in New Issue
Block a user