mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
apple/f108.cpp: New device for the Apple F108 memory controller / northbridge. [R. Belmont]
apple/valkyrie.cpp: New device for Apple Valkyrie framebuffer ASIC. [R. Belmont] apple/iosb.cpp: Added support for the PrimeTime II I/O ASIC. [R. Belmont] New machines added as working ----------------------------- Apple Computer Macintosh Quadra 630 [R. Belmont] New working clones added ------------------------ Apple Computer Macintosh LC/Performa 580 [R. Belmont]
This commit is contained in:
parent
7bb90aa659
commit
972e35e451
211
src/mame/apple/f108.cpp
Normal file
211
src/mame/apple/f108.cpp
Normal file
@ -0,0 +1,211 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/*
|
||||
Apple "F108" memory controller
|
||||
Emulation by R. Belmont
|
||||
|
||||
F108 contains:
|
||||
- A memory controller
|
||||
- The usual Mac ROM/RAM switch so at boot the processor has vectors at 0
|
||||
- An ATA bus interface
|
||||
- An SCC interface
|
||||
- A SCSI controller which is claimed to be "just like a 53C96". A real 53C96 seems to work fine.
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#include "f108.h"
|
||||
|
||||
#include "softlist_dev.h"
|
||||
|
||||
#include "bus/nscsi/devices.h"
|
||||
#include "bus/rs232/rs232.h"
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
DEFINE_DEVICE_TYPE(F108, f108_device, "macf108", "Apple F108 memory controller")
|
||||
|
||||
//-------------------------------------------------
|
||||
// ADDRESS_MAP
|
||||
//-------------------------------------------------
|
||||
|
||||
void f108_device::map(address_map &map)
|
||||
{
|
||||
map(0x40000000, 0x400fffff).r(FUNC(f108_device::rom_switch_r)).mirror(0x0ff00000).nopw();
|
||||
map(0x5000c000, 0x5000dfff).rw(FUNC(f108_device::scc_r), FUNC(f108_device::scc_w)).mirror(0x00fc0000);
|
||||
map(0x5001a000, 0x5001a01f).rw(m_ata, FUNC(ata_interface_device::cs0_swap_r), FUNC(ata_interface_device::cs0_swap_w)).umask32(0xffff0000).mirror(0x00fc0000);
|
||||
map(0x5001a000, 0x5001a003).rw(FUNC(f108_device::ata_data_r), FUNC(f108_device::ata_data_w)).mirror(0x00fc0000);
|
||||
map(0x5001a020, 0x5001a03f).rw(m_ata, FUNC(ata_interface_device::cs1_swap_r), FUNC(ata_interface_device::cs1_swap_w)).umask32(0xffff0000).mirror(0x00fc0000);
|
||||
// a040 is probably a configuration register based on later Apple ATA implementations, but the values written don't make sense
|
||||
map(0xf9000000, 0xf90fffff).ram(); // VRAM
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_add_mconfig - add device configuration
|
||||
//-------------------------------------------------
|
||||
|
||||
void f108_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
ATA_INTERFACE(config, m_ata).options(ata_devices, "hdd", nullptr, false);
|
||||
m_ata->irq_handler().set(FUNC(f108_device::ata_irq_w));
|
||||
|
||||
NSCSI_BUS(config, m_scsibus);
|
||||
NSCSI_CONNECTOR(config, "scsi:0", mac_scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:1", mac_scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:2", mac_scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:3", mac_scsi_devices, nullptr);
|
||||
NSCSI_CONNECTOR(config, "scsi:4", mac_scsi_devices, "cdrom");
|
||||
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("ncr53c96", NCR53C96).clock(40_MHz_XTAL).machine_config(
|
||||
[this] (device_t *device)
|
||||
{
|
||||
ncr53c96_device &adapter = downcast<ncr53c96_device &>(*device);
|
||||
|
||||
adapter.set_busmd(ncr53c96_device::BUSMD_1);
|
||||
adapter.irq_handler_cb().set(m_primetimeii, FUNC(primetime_device::scsi_irq_w));
|
||||
adapter.drq_handler_cb().set(m_primetimeii, FUNC(primetime_device::scsi_drq_w));
|
||||
});
|
||||
|
||||
SOFTWARE_LIST(config, "hdd_list").set_original("mac_hdd");
|
||||
|
||||
SCC85C30(config, m_scc, 31.3344_MHz_XTAL/4);
|
||||
m_scc->configure_channels(3'686'400, 3'686'400, 3'686'400, 3'686'400);
|
||||
m_scc->out_int_callback().set(FUNC(f108_device::scc_irq_w));
|
||||
m_scc->out_txda_callback().set("printer", FUNC(rs232_port_device::write_txd));
|
||||
m_scc->out_txdb_callback().set("modem", FUNC(rs232_port_device::write_txd));
|
||||
|
||||
rs232_port_device &rs232a(RS232_PORT(config, "printer", default_rs232_devices, nullptr));
|
||||
rs232a.rxd_handler().set(m_scc, FUNC(z80scc_device::rxa_w));
|
||||
rs232a.dcd_handler().set(m_scc, FUNC(z80scc_device::dcda_w));
|
||||
rs232a.cts_handler().set(m_scc, FUNC(z80scc_device::ctsa_w));
|
||||
|
||||
rs232_port_device &rs232b(RS232_PORT(config, "modem", default_rs232_devices, nullptr));
|
||||
rs232b.rxd_handler().set(m_scc, FUNC(z80scc_device::rxb_w));
|
||||
rs232b.dcd_handler().set(m_scc, FUNC(z80scc_device::dcdb_w));
|
||||
rs232b.cts_handler().set(m_scc, FUNC(z80scc_device::ctsb_w));
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// f108_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
f108_device::f108_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
device_t(mconfig, F108, tag, owner, clock),
|
||||
m_maincpu(*this, finder_base::DUMMY_TAG),
|
||||
m_primetimeii(*this, finder_base::DUMMY_TAG),
|
||||
m_ata(*this, "ata"),
|
||||
m_scsibus(*this, "scsi"),
|
||||
m_ncr1(*this, "scsi:7:ncr53c96"),
|
||||
m_scc(*this, "scc"),
|
||||
m_rom(*this, finder_base::DUMMY_TAG),
|
||||
m_ata_irq(*this),
|
||||
m_overlay(false)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void f108_device::device_start()
|
||||
{
|
||||
m_rom_ptr = &m_rom[0];
|
||||
m_rom_size = m_rom.length() << 2;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void f108_device::device_reset()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
u32 f108_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 f108_device::set_ram_info(u32 *ram, u32 size)
|
||||
{
|
||||
m_ram_ptr = ram;
|
||||
m_ram_size = size;
|
||||
}
|
||||
|
||||
void f108_device::ata_irq_w(int state)
|
||||
{
|
||||
m_ata_irq(state);
|
||||
}
|
||||
|
||||
u32 f108_device::ata_data_r(offs_t offset, u32 mem_mask)
|
||||
{
|
||||
u32 retval = 0;
|
||||
|
||||
if (mem_mask == 0xffffffff)
|
||||
{
|
||||
retval = m_ata->cs0_swap_r(0, 0xffff) << 16;
|
||||
retval |= m_ata->cs0_swap_r(0, 0xffff);
|
||||
}
|
||||
else if ((mem_mask & 0xffff0000) != 0)
|
||||
{
|
||||
retval = m_ata->cs0_swap_r(0, mem_mask >> 16) << 16;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void f108_device::ata_data_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
if (mem_mask == 0xffffffff)
|
||||
{
|
||||
m_ata->cs0_swap_w(0, data >> 16, 0xffff);
|
||||
m_ata->cs0_swap_w(0, data & 0xffff, 0xffff);
|
||||
}
|
||||
else if ((mem_mask & 0xffff0000) != 0)
|
||||
{
|
||||
m_ata->cs0_swap_w(0, data >> 16, mem_mask >> 16);
|
||||
}
|
||||
}
|
||||
|
||||
u16 f108_device::scc_r(offs_t offset)
|
||||
{
|
||||
m_primetimeii->via_sync();
|
||||
u16 result = m_scc->dc_ab_r(offset);
|
||||
return (result << 8) | result;
|
||||
}
|
||||
|
||||
void f108_device::scc_w(offs_t offset, u16 data)
|
||||
{
|
||||
m_primetimeii->via_sync();
|
||||
m_scc->dc_ab_w(offset, data >> 8);
|
||||
}
|
||||
|
||||
void f108_device::scc_irq_w(int state)
|
||||
{
|
||||
m_primetimeii->scc_irq_w(state);
|
||||
}
|
72
src/mame/apple/f108.h
Normal file
72
src/mame/apple/f108.h
Normal file
@ -0,0 +1,72 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
|
||||
#ifndef MAME_APPLE_F108_H
|
||||
#define MAME_APPLE_F108_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "iosb.h"
|
||||
|
||||
#include "bus/ata/ataintf.h"
|
||||
#include "machine/ncr53c90.h"
|
||||
#include "machine/nscsi_bus.h"
|
||||
#include "machine/z80scc.h"
|
||||
|
||||
// ======================> f108_device
|
||||
|
||||
/// \brief Device class for Apple F108 system controller ASIC.
|
||||
///
|
||||
/// F108 includes a memory controller, NCR 53C96 compatible SCSI,
|
||||
/// and a single-drive ATA-1 interface.
|
||||
class f108_device : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
f108_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// interface routines
|
||||
virtual void map(address_map &map);
|
||||
|
||||
template <typename... T> void set_maincpu_tag(T &&... args) { m_maincpu.set_tag(std::forward<T>(args)...); }
|
||||
template <typename... T> void set_primetimeii_tag(T &&... args) { m_primetimeii.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);
|
||||
|
||||
auto write_ata_irq() { return m_ata_irq.bind(); }
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
u32 rom_switch_r(offs_t offset);
|
||||
|
||||
private:
|
||||
void ata_irq_w(int state);
|
||||
u32 ata_data_r(offs_t offset, u32 mem_mask);
|
||||
void ata_data_w(offs_t offset, u32 data, u32 mem_mask);
|
||||
u16 scc_r(offs_t offset);
|
||||
void scc_w(offs_t offset, u16 data);
|
||||
void scc_irq_w(int state);
|
||||
|
||||
required_device<cpu_device> m_maincpu;
|
||||
required_device<primetimeii_device> m_primetimeii;
|
||||
required_device<ata_interface_device> m_ata;
|
||||
required_device<nscsi_bus_device> m_scsibus;
|
||||
required_device<ncr53c96_device> m_ncr1;
|
||||
required_device<z80scc_device> m_scc;
|
||||
required_region_ptr<u32> m_rom;
|
||||
|
||||
devcb_write_line m_ata_irq;
|
||||
|
||||
bool m_overlay;
|
||||
u32 *m_ram_ptr, *m_rom_ptr;
|
||||
u32 m_ram_size, m_rom_size;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(F108, f108_device)
|
||||
|
||||
#endif // MAME_APPLE_F108_H
|
@ -15,12 +15,12 @@
|
||||
- The "Turbo SCSI" logic from the standalone versions of DAFB and DAFB II
|
||||
- Support logic for various external subsystems (ADB, SCC, SONIC Ethernet)
|
||||
|
||||
IOSB and PrimeTime are similar to Sonora, but replace the RBV/V8/VASP/Sonora pseudo-VIA with a
|
||||
real VIA core that has the timers disabled and some IER and PCR bits hard-wired to specific values.
|
||||
The pseudo-VIA returns in AMIC on the PDM-class PowerMacs and goes away forever in the TNT-class.
|
||||
IOSB and PrimeTime are similar to Sonora, but replace the RBV/V8/VASP/Sonora pseudo-VIA with a
|
||||
real VIA core that has the timers disabled and some IER and PCR bits hard-wired to specific values.
|
||||
The pseudo-VIA returns in AMIC on the PDM-class PowerMacs and goes away forever in the TNT-class.
|
||||
|
||||
PrimeTime swaps the GI/Microchip ADB modem interface for the standard Cuda hookup found in Sonora,
|
||||
and doesn't bring out the 4 VIA ID pins. PrimeTime II is similar.
|
||||
PrimeTime swaps the GI/Microchip ADB modem interface for the standard Cuda hookup found in Sonora,
|
||||
and doesn't bring out the 4 VIA ID pins. PrimeTime II is similar.
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
@ -44,6 +44,7 @@ static constexpr u32 C15M = (C7M * 2);
|
||||
|
||||
DEFINE_DEVICE_TYPE(IOSB, iosb_device, "iosb", "Apple IOSB I/O ASIC")
|
||||
DEFINE_DEVICE_TYPE(PRIMETIME, primetime_device, "primetime", "Apple PrimeTime I/O ASIC")
|
||||
DEFINE_DEVICE_TYPE(PRIMETIMEII, primetimeii_device, "primetime2", "Apple PrimeTime II I/O ASIC")
|
||||
|
||||
//-------------------------------------------------
|
||||
// ADDRESS_MAP
|
||||
@ -125,6 +126,11 @@ iosb_base::iosb_base(const machine_config &mconfig, device_type type, const char
|
||||
m_asc(*this, "asc"),
|
||||
m_fdc(*this, "fdc"),
|
||||
m_floppy(*this, "fdc:%d", 0U),
|
||||
m_nubus_irqs(0xff),
|
||||
m_via_interrupt(0),
|
||||
m_via2_interrupt(0),
|
||||
m_scc_interrupt(0),
|
||||
m_last_taken_interrupt(-1),
|
||||
m_cur_floppy(nullptr),
|
||||
m_hdsel(0),
|
||||
m_adb_interrupt(0),
|
||||
@ -147,14 +153,26 @@ iosb_device::iosb_device(const machine_config &mconfig, const char *tag, device_
|
||||
{
|
||||
}
|
||||
|
||||
primetime_device::primetime_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
iosb_base(mconfig, PRIMETIME, tag, owner, clock),
|
||||
primetime_device::primetime_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
|
||||
iosb_base(mconfig, type, tag, owner, clock),
|
||||
write_pb4(*this),
|
||||
write_pb5(*this),
|
||||
read_pb3(*this, 0)
|
||||
{
|
||||
}
|
||||
|
||||
primetime_device::primetime_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
primetime_device(mconfig, PRIMETIME, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
primetimeii_device::primetimeii_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||
primetime_device(mconfig, PRIMETIMEII, tag, owner, clock),
|
||||
m_ata_irq(0)
|
||||
{
|
||||
std::fill(std::begin(m_primetimeii_regs), std::end(m_primetimeii_regs), 0);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
@ -185,11 +203,6 @@ void iosb_base::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;
|
||||
m_hdsel = 0;
|
||||
m_nubus_irqs = 0xff;
|
||||
|
||||
m_via2_ca1_hack = 1;
|
||||
m_via2->write_ca1(1);
|
||||
m_via2->write_cb1(1);
|
||||
@ -293,7 +306,7 @@ void iosb_base::field_interrupts()
|
||||
|
||||
void iosb_base::scc_irq_w(int state)
|
||||
{
|
||||
m_scc_interrupt = (state == ASSERT_LINE);
|
||||
m_scc_interrupt = (state == ASSERT_LINE) ? 1 : 0;
|
||||
field_interrupts();
|
||||
}
|
||||
|
||||
@ -545,6 +558,8 @@ u32 iosb_base::turboscsi_dma_r(offs_t offset, u32 mem_mask)
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
LOGMASKED(LOG_TURBOSCSI, "dma_r mask %08x (%s)\n", mem_mask, machine().describe_context());
|
||||
|
||||
if (mem_mask == 0xffffffff)
|
||||
{
|
||||
if (!m_scsi_second_half)
|
||||
@ -627,7 +642,6 @@ void iosb_base::scsi_drq_w(int state)
|
||||
|
||||
u16 iosb_base::iosb_regs_r(offs_t offset)
|
||||
{
|
||||
LOGMASKED(LOG_IOSBREGS, "iosb_regs_r: @ %x\n", offset>>7);
|
||||
return m_iosb_regs[offset>>7];
|
||||
}
|
||||
|
||||
@ -671,3 +685,39 @@ void primetime_device::via_out_b(uint8_t data)
|
||||
write_pb4(BIT(data, 4));
|
||||
write_pb5(BIT(data, 5));
|
||||
}
|
||||
|
||||
// ------------------------------------------- PrimeTime II device
|
||||
void primetimeii_device::device_start()
|
||||
{
|
||||
primetime_device::device_start();
|
||||
save_item(NAME(m_ata_irq));
|
||||
save_item(NAME(m_primetimeii_regs));
|
||||
}
|
||||
|
||||
void primetimeii_device::map(address_map &map)
|
||||
{
|
||||
iosb_base::map(map);
|
||||
map(0x0001a100, 0x0001a10f).r(FUNC(primetimeii_device::ata_regs_r)).mirror(0x00f00000);
|
||||
}
|
||||
|
||||
// This may actually be in F108, the boundaries between the two chips aren't completely clear
|
||||
u16 primetimeii_device::ata_regs_r(offs_t offset)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0: // special interrupt status: bit 6 = VBL IRQ, bit 5 = ATA IRQ
|
||||
return ((m_nubus_irqs ^ 0xff) & 0x40) | (m_ata_irq << 5);
|
||||
|
||||
default:
|
||||
LOGMASKED(LOG_IOSBREGS, "%s: Unhandled ata_regs_r @ %x\n", tag(), offset);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void primetimeii_device::ata_irq_w(int state)
|
||||
{
|
||||
via2_irq_w<0x10>(state);
|
||||
m_ata_irq = state;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ class iosb_base : public device_t
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
iosb_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
iosb_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
// interface routines
|
||||
auto write_adb_st() { return m_adb_st.bind(); } // ADB state
|
||||
@ -34,7 +34,7 @@ public:
|
||||
auto read_pa4() { return m_pa4.bind(); }
|
||||
auto read_pa6() { return m_pa6.bind(); }
|
||||
|
||||
void map(address_map &map);
|
||||
virtual void map(address_map &map);
|
||||
|
||||
template <typename... T> void set_maincpu_tag(T &&... args) { m_maincpu.set_tag(std::forward<T>(args)...); }
|
||||
template <typename... T> void set_scsi_tag(T &&... args) { m_ncr.set_tag(std::forward<T>(args)...); }
|
||||
@ -65,6 +65,9 @@ protected:
|
||||
virtual uint8_t via_in_b();
|
||||
virtual void via_out_b(uint8_t data);
|
||||
|
||||
virtual u16 iosb_regs_r(offs_t offset);
|
||||
virtual void iosb_regs_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
|
||||
devcb_write8 m_adb_st;
|
||||
devcb_write_line m_cb1, m_cb2;
|
||||
devcb_read_line m_pa1, m_pa2, m_pa4, m_pa6;
|
||||
@ -76,6 +79,10 @@ protected:
|
||||
required_device<applefdintf_device> m_fdc;
|
||||
required_device_array<floppy_connector, 2> m_floppy;
|
||||
|
||||
u16 m_iosb_regs[0x20];
|
||||
|
||||
u8 m_nubus_irqs;
|
||||
|
||||
private:
|
||||
emu_timer *m_6015_timer;
|
||||
int m_via_interrupt, m_via2_interrupt, m_scc_interrupt, m_last_taken_interrupt;
|
||||
@ -83,22 +90,16 @@ private:
|
||||
int m_hdsel;
|
||||
int m_adb_interrupt;
|
||||
int m_via2_ca1_hack;
|
||||
u8 m_nubus_irqs;
|
||||
|
||||
int m_drq, m_scsi_irq, m_asc_irq;
|
||||
int m_scsi_read_cycles, m_scsi_write_cycles, m_scsi_dma_read_cycles, m_scsi_dma_write_cycles;
|
||||
s32 m_drq, m_scsi_irq, m_asc_irq;
|
||||
u32 m_scsi_read_cycles, m_scsi_write_cycles, m_scsi_dma_read_cycles, m_scsi_dma_write_cycles;
|
||||
u32 m_scsi_dma_result;
|
||||
bool m_scsi_second_half;
|
||||
|
||||
u16 m_iosb_regs[0x20];
|
||||
|
||||
u16 iosb_regs_r(offs_t offset);
|
||||
void iosb_regs_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
|
||||
uint16_t mac_via_r(offs_t offset);
|
||||
void mac_via_w(offs_t offset, uint16_t data, uint16_t mem_mask);
|
||||
uint16_t mac_via2_r(offs_t offset);
|
||||
void mac_via2_w(offs_t offset, uint16_t data, uint16_t mem_mask);
|
||||
u16 mac_via_r(offs_t offset);
|
||||
void mac_via_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
u16 mac_via2_r(offs_t offset);
|
||||
void mac_via2_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
|
||||
uint8_t via_in_a();
|
||||
uint8_t via2_in_a();
|
||||
@ -113,15 +114,19 @@ private:
|
||||
|
||||
void phases_w(uint8_t phases);
|
||||
void devsel_w(uint8_t devsel);
|
||||
uint16_t swim_r(offs_t offset, u16 mem_mask);
|
||||
u16 swim_r(offs_t offset, u16 mem_mask);
|
||||
void swim_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
};
|
||||
|
||||
/// \brief Device class for Apple IOSB I/O controller ASIC.
|
||||
///
|
||||
/// IOSB includes 2 VIAs, TurboSCSI logic, a SWIM 2 floppy controller,
|
||||
/// and more.
|
||||
class iosb_device : public iosb_base
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
iosb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
iosb_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
@ -138,7 +143,8 @@ class primetime_device : public iosb_base
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
primetime_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
primetime_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
|
||||
primetime_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
auto pb4_callback() { return write_pb4.bind(); }
|
||||
auto pb5_callback() { return write_pb5.bind(); }
|
||||
@ -154,8 +160,29 @@ protected:
|
||||
private:
|
||||
};
|
||||
|
||||
class primetimeii_device : public primetime_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
primetimeii_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
virtual void map(address_map &map) override;
|
||||
|
||||
void ata_irq_w(int state);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
|
||||
private:
|
||||
u16 ata_regs_r(offs_t offset);
|
||||
|
||||
s32 m_ata_irq;
|
||||
u16 m_primetimeii_regs[0x20];
|
||||
};
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(IOSB, iosb_device)
|
||||
DECLARE_DEVICE_TYPE(PRIMETIME, primetime_device)
|
||||
DECLARE_DEVICE_TYPE(PRIMETIMEII, primetimeii_device)
|
||||
|
||||
#endif // MAME_APPLE_IOSB_H
|
||||
|
209
src/mame/apple/macquadra630.cpp
Executable file
209
src/mame/apple/macquadra630.cpp
Executable file
@ -0,0 +1,209 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/****************************************************************************
|
||||
|
||||
drivers/macquadra630.cpp
|
||||
Mac Quadra 630 ("Show and Tell")
|
||||
Mac LC 580 ("Dragonkid")
|
||||
|
||||
By R. Belmont
|
||||
|
||||
These machines took the cost-reduced but still decent Quadra 605/LC 575
|
||||
and made them even cheaper by replacing the full-featured DAFB video chip
|
||||
with "Valkyrie". Which appears to offer only a few pre-programmed video
|
||||
mode timings.
|
||||
|
||||
Further cost reduction occured by replacing the hard disk with an ATA/IDE
|
||||
model instead of the by-then traditional Mac SCSI drive. The ATA interface
|
||||
was wedged into the chipset in a somewhat odd manner that impacts VIA2
|
||||
interrupt handling (including video VBL IRQs).
|
||||
|
||||
Known problems:
|
||||
- If you don't boot an OS, the mouse pointer will stop updating when the
|
||||
question-mark disk appears. If you do boot an OS, everything's fine.
|
||||
|
||||
- The later version boot ROM for the LC 580 can't boot a SCSI CD-ROM. It
|
||||
reads 512 bytes of a 2048 byte sector and expects CyclePhase_96 to read
|
||||
and discard the rest of the sector from the drive. But it sees a (pseudo)
|
||||
DMA command was active and waits for DRQ, which doesn't happen because
|
||||
the 53C96's transfer count is zero. The earlier ROM has the same logic as
|
||||
previous (and later!) 53C96 machines and works fine.
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "softlist_dev.h"
|
||||
|
||||
#include "cuda.h"
|
||||
#include "f108.h"
|
||||
#include "iosb.h"
|
||||
#include "macadb.h"
|
||||
#include "mactoolbox.h"
|
||||
#include "valkyrie.h"
|
||||
|
||||
#include "cpu/m68000/m68040.h"
|
||||
#include "machine/ram.h"
|
||||
#include "machine/timer.h"
|
||||
|
||||
#define C32M 31.3344_MHz_XTAL
|
||||
#define C15M (C32M/2)
|
||||
#define C7M (C32M/4)
|
||||
|
||||
namespace {
|
||||
|
||||
class quadra630_state : public driver_device
|
||||
{
|
||||
public:
|
||||
quadra630_state(const machine_config &mconfig, device_type type, const char *tag) :
|
||||
driver_device(mconfig, type, tag),
|
||||
m_maincpu(*this, "maincpu"),
|
||||
m_f108(*this, "f108"),
|
||||
m_primetimeii(*this, "primetimeii"),
|
||||
m_video(*this, "valkyrie"),
|
||||
m_macadb(*this, "macadb"),
|
||||
m_cuda(*this, "cuda"),
|
||||
m_ram(*this, RAM_TAG)
|
||||
{
|
||||
}
|
||||
|
||||
void macqd630(machine_config &config);
|
||||
void maclc580(machine_config &config);
|
||||
|
||||
void quadra630_map(address_map &map);
|
||||
void lc580_map(address_map &map);
|
||||
|
||||
void init_macqd630();
|
||||
|
||||
private:
|
||||
required_device<m68040_device> m_maincpu;
|
||||
required_device<f108_device> m_f108;
|
||||
required_device<primetimeii_device> m_primetimeii;
|
||||
required_device<valkyrie_device> m_video;
|
||||
required_device<macadb_device> m_macadb;
|
||||
required_device<cuda_device> m_cuda;
|
||||
required_device<ram_device> m_ram;
|
||||
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
|
||||
void cuda_reset_w(int state)
|
||||
{
|
||||
m_maincpu->set_input_line(INPUT_LINE_HALT, state);
|
||||
m_maincpu->set_input_line(INPUT_LINE_RESET, state);
|
||||
}
|
||||
};
|
||||
|
||||
void quadra630_state::machine_start()
|
||||
{
|
||||
m_f108->set_ram_info((u32 *) m_ram->pointer(), m_ram->size());
|
||||
}
|
||||
|
||||
void quadra630_state::machine_reset()
|
||||
{
|
||||
m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
|
||||
}
|
||||
|
||||
void quadra630_state::init_macqd630()
|
||||
{
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
ADDRESS MAPS
|
||||
***************************************************************************/
|
||||
void quadra630_state::quadra630_map(address_map &map)
|
||||
{
|
||||
map(0x00000000, 0xffffffff).m(m_f108, FUNC(f108_device::map));
|
||||
map(0x00000000, 0xffffffff).m(m_video, FUNC(valkyrie_device::map));
|
||||
map(0x50000000, 0x5fffffff).m(m_primetimeii, FUNC(primetime_device::map));
|
||||
|
||||
// 5000a000 = SONIC if comm slot card is installed
|
||||
map(0x5000a000, 0x5000bfff).noprw().mirror(0x00fc0000);
|
||||
|
||||
// 2252 = Q630, 225a = LC580
|
||||
map(0x5ffffffc, 0x5fffffff).lr32(NAME([](offs_t offset) { return 0xa55a2252; }));
|
||||
}
|
||||
|
||||
void quadra630_state::lc580_map(address_map &map)
|
||||
{
|
||||
quadra630_map(map);
|
||||
|
||||
map(0x5ffffffc, 0x5fffffff).lr32(NAME([](offs_t offset) { return 0xa55a225a; }));
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
DEVICE CONFIG
|
||||
***************************************************************************/
|
||||
|
||||
static INPUT_PORTS_START( macadb )
|
||||
INPUT_PORTS_END
|
||||
|
||||
/***************************************************************************
|
||||
MACHINE DRIVERS
|
||||
***************************************************************************/
|
||||
|
||||
void quadra630_state::macqd630(machine_config &config)
|
||||
{
|
||||
M68040(config, m_maincpu, 33_MHz_XTAL);
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &quadra630_state::quadra630_map);
|
||||
m_maincpu->set_dasm_override(std::function(&mac68k_dasm_override), "mac68k_dasm_override");
|
||||
|
||||
F108(config, m_f108, 33_MHz_XTAL);
|
||||
m_f108->set_maincpu_tag("maincpu");
|
||||
m_f108->set_primetimeii_tag("primetimeii");
|
||||
m_f108->set_rom_tag("bootrom");
|
||||
m_f108->write_ata_irq().set(m_primetimeii, FUNC(primetimeii_device::ata_irq_w));
|
||||
|
||||
PRIMETIMEII(config, m_primetimeii, 33_MHz_XTAL);
|
||||
m_primetimeii->set_maincpu_tag("maincpu");
|
||||
m_primetimeii->set_scsi_tag("f108:scsi:7:ncr53c96");
|
||||
|
||||
VALKYRIE(config, m_video, C32M);
|
||||
m_video->write_irq().set(m_primetimeii, FUNC(primetime_device::via2_irq_w<0x40>));
|
||||
|
||||
MACADB(config, m_macadb, C15M);
|
||||
|
||||
// TODO: recapamac.com.au's logic board photos show Cuda 2.40 for both Q630 and LC580,
|
||||
// but both ROM versions have issues syncing with 2.38 and 2.40 while 2.37 works.
|
||||
CUDA_V237(config, m_cuda, XTAL(32'768));
|
||||
m_cuda->reset_callback().set(FUNC(quadra630_state::cuda_reset_w));
|
||||
m_cuda->linechange_callback().set(m_macadb, FUNC(macadb_device::adb_linechange_w));
|
||||
m_cuda->via_clock_callback().set(m_primetimeii, FUNC(primetime_device::cb1_w));
|
||||
m_cuda->via_data_callback().set(m_primetimeii, FUNC(primetime_device::cb2_w));
|
||||
m_macadb->adb_data_callback().set(m_cuda, FUNC(cuda_device::set_adb_line));
|
||||
config.set_perfect_quantum(m_maincpu);
|
||||
|
||||
m_primetimeii->pb3_callback().set(m_cuda, FUNC(cuda_device::get_treq));
|
||||
m_primetimeii->pb4_callback().set(m_cuda, FUNC(cuda_device::set_byteack));
|
||||
m_primetimeii->pb5_callback().set(m_cuda, FUNC(cuda_device::set_tip));
|
||||
m_primetimeii->write_cb2().set(m_cuda, FUNC(cuda_device::set_via_data));
|
||||
|
||||
/* internal ram */
|
||||
RAM(config, m_ram);
|
||||
m_ram->set_default_size("4M");
|
||||
m_ram->set_extra_options("8M,16M,32M");
|
||||
}
|
||||
|
||||
void quadra630_state::maclc580(machine_config &config)
|
||||
{
|
||||
macqd630(config);
|
||||
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &quadra630_state::lc580_map);
|
||||
}
|
||||
|
||||
ROM_START( macqd630 )
|
||||
ROM_REGION32_BE(0x100000, "bootrom", 0)
|
||||
ROM_LOAD( "06684214.bin", 0x000000, 0x100000, CRC(1735e7a5) SHA1(47cd505b6a7c46e5c0ffa29f0d5037c83e94a02f) )
|
||||
ROM_END
|
||||
|
||||
ROM_START( maclc580 )
|
||||
ROM_REGION32_BE(0x100000, "bootrom", 0)
|
||||
ROM_SYSTEM_BIOS(0, "older", "Version 32F1")
|
||||
ROMX_LOAD("06684214.bin", 0x000000, 0x100000, CRC(1735e7a5) SHA1(47cd505b6a7c46e5c0ffa29f0d5037c83e94a02f), ROM_BIOS(0))
|
||||
ROM_SYSTEM_BIOS(1, "later", "Version 32F2 (bug: can't boot CD-ROM)")
|
||||
ROMX_LOAD( "064dc91d.bin", 0x000000, 0x100000, CRC(59e6960f) SHA1(f48a8adf06bce50beee033d0d814da0e5e916d08), ROM_BIOS(1))
|
||||
ROM_END
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
COMP( 1994, macqd630, 0, 0, macqd630, macadb, quadra630_state, init_macqd630, "Apple Computer", "Macintosh Quadra 630", MACHINE_SUPPORTS_SAVE)
|
||||
COMP( 1995, maclc580, macqd630, 0, maclc580, macadb, quadra630_state, init_macqd630, "Apple Computer", "Macintosh LC/Performa 580", MACHINE_SUPPORTS_SAVE)
|
473
src/mame/apple/valkyrie.cpp
Normal file
473
src/mame/apple/valkyrie.cpp
Normal file
@ -0,0 +1,473 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/*
|
||||
Apple "Valkyrie" - very low-cost video framebuffer
|
||||
Emulation by R. Belmont
|
||||
|
||||
This was the bonus awfulness in the infamous Quadra 630/LC 580 machines. Only
|
||||
a few monitor types are supported and the video mode timings appear to be hardcoded
|
||||
into the chip.
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "valkyrie.h"
|
||||
|
||||
#define LOG_MODE (1U << 1)
|
||||
#define LOG_MONSENSE (1U << 2)
|
||||
#define LOG_RAMDAC (1U << 3)
|
||||
|
||||
#define VERBOSE (0)
|
||||
#include "logmacro.h"
|
||||
|
||||
DEFINE_DEVICE_TYPE(VALKYRIE, valkyrie_device, "valkyrie", "Apple Valkyrie video")
|
||||
|
||||
//-------------------------------------------------
|
||||
// ADDRESS_MAP
|
||||
//-------------------------------------------------
|
||||
|
||||
void valkyrie_device::map(address_map &map)
|
||||
{
|
||||
map(0x50f2a000, 0x50f2bfff).rw(FUNC(valkyrie_device::regs_r), FUNC(valkyrie_device::regs_w));
|
||||
map(0x50f24000, 0x50f25fff).rw(FUNC(valkyrie_device::ramdac_r), FUNC(valkyrie_device::ramdac_w));
|
||||
|
||||
map(0xf9000000, 0xf90fffff).rw(FUNC(valkyrie_device::vram_r), FUNC(valkyrie_device::vram_w));
|
||||
}
|
||||
|
||||
valkyrie_device::valkyrie_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
device_t(mconfig, VALKYRIE, tag, owner, clock),
|
||||
m_vram_size(0x100000),
|
||||
m_pixel_clock(31334400),
|
||||
m_pal_address(0), m_pal_idx(0), m_mode(0),
|
||||
m_screen(*this, "screen"),
|
||||
m_palette(*this, "palette"),
|
||||
m_monitor_config(*this, "monitor"),
|
||||
m_irq(*this),
|
||||
m_vram_offset(0), m_monitor_id(0),
|
||||
m_base(0), m_stride(1024), m_int_status(0), m_hres(0), m_vres(0), m_htotal(0), m_vtotal(0),
|
||||
m_config(0)
|
||||
{
|
||||
}
|
||||
|
||||
void valkyrie_device::device_start()
|
||||
{
|
||||
m_vram = std::make_unique<u32[]>(m_vram_size);
|
||||
|
||||
m_vbl_timer = timer_alloc(FUNC(valkyrie_device::vbl_tick), this);
|
||||
m_vbl_timer->adjust(attotime::never);
|
||||
|
||||
save_item(NAME(m_vram_offset));
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_monitor_id));
|
||||
save_item(NAME(m_base));
|
||||
save_item(NAME(m_stride));
|
||||
save_item(NAME(m_pal_address));
|
||||
save_item(NAME(m_pal_idx));
|
||||
save_item(NAME(m_hres));
|
||||
save_item(NAME(m_vres));
|
||||
save_item(NAME(m_htotal));
|
||||
save_item(NAME(m_vtotal));
|
||||
save_item(NAME(m_pixel_clock));
|
||||
save_item(NAME(m_config));
|
||||
save_item(NAME(m_int_status));
|
||||
save_pointer(NAME(m_vram), m_vram_size);
|
||||
|
||||
machine().save().register_postload(save_prepost_delegate(FUNC(valkyrie_device::recalc_mode), this));
|
||||
}
|
||||
|
||||
void valkyrie_device::device_reset()
|
||||
{
|
||||
// zero out the palette on start, I'm not sure where the video enable is, or if there is one
|
||||
/* for (int i = 0; i < 256; i++)
|
||||
{
|
||||
m_palette->set_pen_red_level(i, 0);
|
||||
m_palette->set_pen_green_level(i, 0);
|
||||
m_palette->set_pen_blue_level(i, 0);
|
||||
}*/
|
||||
m_enable = false;
|
||||
}
|
||||
|
||||
void valkyrie_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
||||
// dot clock, htotal, hstart, hend, vtotal, vstart, vend
|
||||
m_screen->set_raw(31334400, 896, 0, 640, 525, 0, 480);
|
||||
m_screen->set_screen_update(FUNC(valkyrie_device::screen_update));
|
||||
|
||||
PALETTE(config, m_palette).set_entries(256);
|
||||
}
|
||||
|
||||
static constexpr u8 ext(u8 bc, u8 ac, u8 ab)
|
||||
{
|
||||
return 0x40 | (bc << 4) | (ac << 2) | ab;
|
||||
}
|
||||
|
||||
static INPUT_PORTS_START(monitor_config)
|
||||
PORT_START("monitor")
|
||||
PORT_CONFNAME(0x7f, 6, "Monitor type")
|
||||
PORT_CONFSETTING(0x02, u8"Mac RGB Display (12\" 512\u00d7384)") // "Rubik" (modified IIgs AppleColor RGB)
|
||||
PORT_CONFSETTING(0x06, u8"Mac Hi-Res Display (12-14\" 640\u00d7480)") // "High Res"
|
||||
PORT_CONFSETTING(ext(1, 1, 3), "640x480 VGA")
|
||||
PORT_CONFSETTING(ext(2, 3, 1), "832x624 16\" RGB") // "Goldfish" or "16 inch RGB"
|
||||
INPUT_PORTS_END
|
||||
|
||||
ioport_constructor valkyrie_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME(monitor_config);
|
||||
}
|
||||
|
||||
u32 valkyrie_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
auto const vram8 = util::big_endian_cast<u8 const>(&m_vram[0]) + 0x1000;
|
||||
const pen_t *pens = m_palette->pens();
|
||||
|
||||
if (!m_enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u32 stride = (m_stride << m_mode);
|
||||
switch (m_mode)
|
||||
{
|
||||
case 0: // 1bpp
|
||||
{
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < m_hres/8; x++)
|
||||
{
|
||||
u8 const pixels = vram8[(y * stride) + x];
|
||||
|
||||
*scanline++ = pens[(pixels>>7)&1];
|
||||
*scanline++ = pens[(pixels>>6)&1];
|
||||
*scanline++ = pens[(pixels>>5)&1];
|
||||
*scanline++ = pens[(pixels>>4)&1];
|
||||
*scanline++ = pens[(pixels>>3)&1];
|
||||
*scanline++ = pens[(pixels>>2)&1];
|
||||
*scanline++ = pens[(pixels>>1)&1];
|
||||
*scanline++ = pens[(pixels&1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // 2bpp
|
||||
{
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < m_hres/4; x++)
|
||||
{
|
||||
u8 const pixels = vram8[(y * stride) + x];
|
||||
|
||||
*scanline++ = pens[((pixels>>6)&3)];
|
||||
*scanline++ = pens[((pixels>>4)&3)];
|
||||
*scanline++ = pens[((pixels>>2)&3)];
|
||||
*scanline++ = pens[(pixels&3)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 4bpp
|
||||
{
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < m_hres/2; x++)
|
||||
{
|
||||
u8 const pixels = vram8[(y * stride) + x];
|
||||
|
||||
*scanline++ = pens[(pixels>>4)];
|
||||
*scanline++ = pens[(pixels&0xf)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // 8bpp
|
||||
{
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < m_hres; x++)
|
||||
{
|
||||
u8 const pixels = vram8[(y * stride) + x];
|
||||
*scanline++ = pens[pixels];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // 16bpp x555
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < m_hres; x++)
|
||||
{
|
||||
u16 const pixels = (vram8[(y * stride) + (x<<1)] << 8) | vram8[(y * stride) + (x<<1) + 1];
|
||||
*scanline++ = rgb_t(((pixels >> 10) & 0x1f) << 3, ((pixels >> 5) & 0x1f) << 3, (pixels & 0x1f) << 3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 valkyrie_device::regs_r(offs_t offset)
|
||||
{
|
||||
// printf("Read regs @ %x\n", offset<<2);
|
||||
switch (offset<<2)
|
||||
{
|
||||
case 0:
|
||||
return m_video_timing;
|
||||
|
||||
case 4:
|
||||
return m_mode;
|
||||
|
||||
case 0x10: // config
|
||||
return m_config;
|
||||
|
||||
case 0x14:
|
||||
return (m_screen->vblank() << 24);
|
||||
|
||||
case 0x1c: // monitor sense in upper nibble, write monitor sense in lower nibble
|
||||
{
|
||||
u8 mon = m_monitor_config->read();
|
||||
u8 res;
|
||||
LOGMASKED(LOG_MONSENSE, "mon = %02x, m_monitor_id = %02x\n", mon, m_monitor_id);
|
||||
if (mon & 0x40)
|
||||
{
|
||||
res = 7;
|
||||
if (m_monitor_id == 0x4)
|
||||
{
|
||||
res &= 4 | (BIT(mon, 5) << 1) | BIT(mon, 4);
|
||||
}
|
||||
if (m_monitor_id == 0x2)
|
||||
{
|
||||
res &= (BIT(mon, 3) << 2) | 2 | BIT(mon, 2);
|
||||
}
|
||||
if (m_monitor_id == 0x1)
|
||||
{
|
||||
res &= (BIT(mon, 1) << 2) | (BIT(mon, 0) << 1) | 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mon;
|
||||
}
|
||||
|
||||
LOGMASKED(LOG_MONSENSE, "sense result = %x\n", res);
|
||||
return res<<28;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void valkyrie_device::regs_w(offs_t offset, u32 data)
|
||||
{
|
||||
data &= 0xfff;
|
||||
switch (offset << 2)
|
||||
{
|
||||
case 0: // video timing select (apparently from hardcoded values!)
|
||||
m_video_timing = data;
|
||||
break;
|
||||
|
||||
case 4: // video depth: 0=1bpp, 1=2bpp, 2=4bpp, 3=8bpp, 4=16bpp
|
||||
LOG("Mode set to %d\n", data & 7);
|
||||
m_mode = data & 7;
|
||||
break;
|
||||
|
||||
case 0xc: // written to lock in the video timing from register 0
|
||||
if (data == 0x101)
|
||||
{
|
||||
recalc_mode();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
m_config = data;
|
||||
|
||||
m_int_status &= ~1;
|
||||
recalc_ints();
|
||||
|
||||
if (data & 1) // VBL enable
|
||||
{
|
||||
m_vbl_timer->adjust(m_screen->time_until_pos(m_vres, 0), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vbl_timer->adjust(attotime::never);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x18: // screen enable
|
||||
m_enable = (data & 0x80) ? true : false;
|
||||
break;
|
||||
|
||||
case 0x1c: // drive monitor sense lines. 1 = drive, 0 = tri-state
|
||||
m_monitor_id = (data & 0x7);
|
||||
LOGMASKED(LOG_MONSENSE, "%x to sense drive\n", data & 0xf);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG("Valkyrie: Unk write %08x @ %x\n", data, offset<<2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 valkyrie_device::ramdac_r(offs_t offset)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0:
|
||||
if (!machine().side_effects_disabled())
|
||||
{
|
||||
m_pal_idx = 0;
|
||||
}
|
||||
return m_pal_address<<24;
|
||||
|
||||
case 1:
|
||||
{
|
||||
pen_t const entry = m_palette->pen(m_pal_address);
|
||||
u8 const idx = m_pal_idx;
|
||||
if (!machine().side_effects_disabled())
|
||||
{
|
||||
m_pal_idx++;
|
||||
}
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return ((entry >> 16) & 0xff) << 24;
|
||||
case 1:
|
||||
return ((entry >> 8) & 0xff) << 24;
|
||||
case 2:
|
||||
return (entry & 0xff) << 24;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void valkyrie_device::ramdac_w(offs_t offset, u32 data)
|
||||
{
|
||||
data >>= 24;
|
||||
switch (offset)
|
||||
{
|
||||
case 0:
|
||||
m_pal_address = data & 0xff;
|
||||
m_pal_idx = 0;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
switch (m_pal_idx)
|
||||
{
|
||||
case 0:
|
||||
m_palette->set_pen_red_level(m_pal_address, data & 0xff);
|
||||
break;
|
||||
case 1:
|
||||
m_palette->set_pen_green_level(m_pal_address, data & 0xff);
|
||||
break;
|
||||
case 2:
|
||||
m_palette->set_pen_blue_level(m_pal_address, data & 0xff);
|
||||
break;
|
||||
}
|
||||
|
||||
m_pal_idx++;
|
||||
if (m_pal_idx == 3)
|
||||
{
|
||||
m_pal_idx = 0;
|
||||
m_pal_address++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
LOGMASKED(LOG_RAMDAC, "%02x to DAC @ %x\n", data, offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void valkyrie_device::recalc_mode()
|
||||
{
|
||||
// mode parameters taken from the Quadra 630 Developer Note
|
||||
switch (m_video_timing)
|
||||
{
|
||||
case 0x101: // default
|
||||
case 0x686: // 13" 640x480
|
||||
m_hres = 640;
|
||||
m_vres = 480;
|
||||
m_htotal = 864;
|
||||
m_vtotal = 525;
|
||||
m_pixel_clock = 30240000;
|
||||
m_stride = 80;
|
||||
break;
|
||||
|
||||
case 0x282: // Rubik 512x384
|
||||
m_hres = 512;
|
||||
m_vres = 384;
|
||||
m_htotal = 640;
|
||||
m_vtotal = 407;
|
||||
m_pixel_clock = 15670000;
|
||||
m_stride = 64;
|
||||
break;
|
||||
|
||||
case 0xb8b: // VGA 640x480
|
||||
m_hres = 640;
|
||||
m_vres = 480;
|
||||
m_htotal = 800;
|
||||
m_vtotal = 525;
|
||||
m_pixel_clock = 25180000;
|
||||
m_stride = 80;
|
||||
break;
|
||||
|
||||
case 0x989: // 16" RGB 832x624?
|
||||
m_hres = 832;
|
||||
m_vres = 624;
|
||||
m_htotal = 1072;
|
||||
m_vtotal = 690;
|
||||
m_pixel_clock = 50000000;
|
||||
m_stride = 104;
|
||||
break;
|
||||
}
|
||||
|
||||
const double refresh = (double)m_pixel_clock / (double)(m_htotal * m_vtotal);
|
||||
LOGMASKED(LOG_MODE, "hres %d vres %d htotal %d vtotal %d refresh %f stride %d mode %d\n", m_hres, m_vres, m_htotal, m_vtotal, refresh, m_stride, m_mode);
|
||||
if ((m_hres != 0) && (m_vres != 0))
|
||||
{
|
||||
rectangle visarea(0, m_hres - 1, 0, m_vres - 1);
|
||||
m_screen->configure(m_htotal, m_vtotal, visarea, attotime::from_ticks(m_htotal * m_vtotal, m_pixel_clock).as_attoseconds());
|
||||
}
|
||||
}
|
||||
|
||||
u32 valkyrie_device::vram_r(offs_t offset)
|
||||
{
|
||||
return m_vram[offset & (m_vram_size - 1)];
|
||||
}
|
||||
|
||||
void valkyrie_device::vram_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_vram[offset & (m_vram_size - 1)]);
|
||||
}
|
||||
|
||||
void valkyrie_device::recalc_ints()
|
||||
{
|
||||
if (m_int_status != 0)
|
||||
{
|
||||
m_irq(ASSERT_LINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_irq(CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(valkyrie_device::vbl_tick)
|
||||
{
|
||||
m_int_status |= 1;
|
||||
recalc_ints();
|
||||
|
||||
m_vbl_timer->adjust(m_screen->time_until_pos(480, 0), 0);
|
||||
}
|
67
src/mame/apple/valkyrie.h
Normal file
67
src/mame/apple/valkyrie.h
Normal file
@ -0,0 +1,67 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
|
||||
#ifndef MAME_APPLE_VALKYRIE_H
|
||||
#define MAME_APPLE_VALKYRIE_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu/m68000/m68040.h"
|
||||
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
|
||||
class valkyrie_device : public device_t
|
||||
{
|
||||
public:
|
||||
valkyrie_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
virtual ~valkyrie_device() = default;
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
auto write_irq() { return m_irq.bind(); }
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
void recalc_ints();
|
||||
void recalc_mode();
|
||||
|
||||
u32 m_vram_size;
|
||||
u32 m_pixel_clock;
|
||||
|
||||
u8 m_pal_address, m_pal_idx, m_mode;
|
||||
|
||||
private:
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<palette_device> m_palette;
|
||||
required_ioport m_monitor_config;
|
||||
devcb_write_line m_irq;
|
||||
|
||||
std::unique_ptr<u32[]> m_vram;
|
||||
emu_timer *m_vbl_timer;
|
||||
u32 m_vram_offset;
|
||||
u8 m_monitor_id;
|
||||
u32 m_base, m_stride, m_video_timing;
|
||||
s32 m_int_status;
|
||||
u32 m_hres, m_vres, m_htotal, m_vtotal, m_config;
|
||||
bool m_enable;
|
||||
|
||||
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
|
||||
u32 regs_r(offs_t offset);
|
||||
void regs_w(offs_t offset, u32 data);
|
||||
u32 ramdac_r(offs_t offset);
|
||||
void ramdac_w(offs_t offset, u32 data);
|
||||
u32 vram_r(offs_t offset);
|
||||
void vram_w(offs_t offset, u32 data, u32 mem_mask);
|
||||
|
||||
TIMER_CALLBACK_MEMBER(vbl_tick);
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(VALKYRIE, valkyrie_device)
|
||||
|
||||
#endif /* MAME_APPLE_VALKYRIE_H */
|
4
src/mame/mame.lst
Normal file → Executable file
4
src/mame/mame.lst
Normal file → Executable file
@ -904,6 +904,10 @@ macqd605 // 1993 Apple Macintosh Quadra 605
|
||||
maclc475 // 1993 Apple Macintosh LC/Performa 475
|
||||
maclc575 // 1994 Apple Macintosh LC/Performa 575
|
||||
|
||||
@source:apple/macquadra630.cpp
|
||||
macqd630 // July 18, 1994 Apple Macintosh Quadra 630
|
||||
maclc580 // April 3, 1995 Apple Macintosh LC/Performa 580
|
||||
|
||||
@source:apple/macquadra700.cpp
|
||||
macqd700 // 1991 Apple Macintosh Quadra 700
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user