New working systems

-------------------
Apple Macintosh Centris 610 [R. Belmont]
Apple Macintosh Centris 650 [R. Belmont]
Apple Macintosh Quadra 610 [R. Belmont]
Apple Macintosh Quadra 650 [R. Belmont]
Apple Macintosh Quadra 800 [R. Belmont]

apple/dafb.cpp: Added a child device to handle the differences in the djMEMC integrated version of DAFB. [R. Belmont]

apple/iosb.cpp: Apple I/O Subsystem Buffer device, which handles I/O for second-generation 68040 machines. [R. Belmont]

apple/djmemc.cpp: Apple memory controller with integrated DAFB video for second-generation 68040 systems. [R. Belmont]
This commit is contained in:
arbee 2023-07-19 20:16:24 -04:00
parent 4b1257e2f0
commit a381012159
8 changed files with 1457 additions and 39 deletions

View File

@ -5,18 +5,20 @@
Emulation by R. Belmont
Some inspiration from mv_sonora by Olivier Galibert and nubus_48gc by Vas Crabb
DAFB (officially Direct Access Frame Buffer, internally Dave's Awesome Frame Buffer) was the on-board video
DAFB (officially Direct Access Frame Buffer, internally Dale's Awesome Frame Buffer) was the on-board video
for the Quadra 700, 900, and 950. Standalone DAFB and DAFB-II include what Apple calls "Turbo SCSI", which
is an interface for up to 2 5394/5396 chips that adds a configurable wait state to each access and can hold
off /DTACK on pseudo-DMA reads and writes.
Shipping configurations:
DAFB - original standalone chip, Quadra 700 and 900 (returns versions 0 and 1)
DAFB II - revised standalone chip with 15 bpp support added (uses AC843 CODEC instead of AC842) (returns version 2)
Used in Quadra 950.
MEMC - DAFB II without the Turbo SCSI logic, in the djMEMC and MEMCjr memory controllers. (returns version 3)
Used in LC 475, LC 575, Quadra 605, Quadra 610, Quadra 650, and Quadra 800.
This version uses a DP8533 timing generator instead of the DP8531.
DAFB - original standalone chip, Quadra 700 and 900 (returns versions 0 and 1)
DAFB II - revised standalone chip with 15 bpp support added (uses AC842a CODEC instead of AC842) (returns version 2)
Used in Quadra 950.
MEMC - DAFB II without the Turbo SCSI logic, in the djMEMC and MEMCjr memory controllers. (returns version 3)
Used in LC 475, LC 575, Quadra 605, Quadra 610, Quadra 650, and Quadra 800.
This version uses a DP8534 timing generator instead of the DP8531 and an AC842a DAC instead of AC842.
DaMFB - DAFB II with a PowerPC bus interface instead of 68040. Used in the HPV card for the PowerMac 6100/7100/8100.
Platinum - DAFB II with 4 MB VRAM support and a blitter bolted on.
The Turbo SCSI block moved into the IOSB and PrimeTime I/O ASICs for the machines where DAFB moved into the
memory controller. It was enhanced slightly to allow longword pseudo-DMA transfers.
@ -45,15 +47,14 @@
#define LOG_SWATCH (1U << 1)
#define LOG_CLOCKGEN (1U << 2)
#define LOG_MONSENSE (1U << 3)
#define LOG_AC842 (1U << 4)
#define LOG_RAMDAC (1U << 4)
#define LOG_TURBOSCSI (1U << 5)
#define VERBOSE (0)
#include "logmacro.h"
static constexpr int VRAM_SIZE = 0x200000 / sizeof(u32);
DEFINE_DEVICE_TYPE(DAFB, dafb_device, "macdafb", "Apple DAFB video")
DEFINE_DEVICE_TYPE(DAFB_MEMC, dafb_memc_device, "macdafb_memc", "Apple DAFB II video (djMEMC integrated)")
//-------------------------------------------------
// ADDRESS_MAP
@ -63,19 +64,22 @@ void dafb_base::map(address_map &map)
{
map(0x00000000, 0x000000ff).rw(FUNC(dafb_base::dafb_r), FUNC(dafb_base::dafb_w));
map(0x00000100, 0x000001ff).rw(FUNC(dafb_base::swatch_r), FUNC(dafb_base::swatch_w));
map(0x00000200, 0x000002ff).rw(FUNC(dafb_base::ac842_r), FUNC(dafb_base::ac842_w));
map(0x00000200, 0x000002ff).rw(FUNC(dafb_base::ramdac_r), FUNC(dafb_base::ramdac_w));
map(0x00000300, 0x000003ff).rw(FUNC(dafb_base::clockgen_r), FUNC(dafb_base::clockgen_w));
}
dafb_base::dafb_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, type, tag, owner, clock),
m_vram_size(0x200000),
m_dafb_version(1),
m_pixel_clock(31334400),
m_pal_address(0), m_pal_idx(0), m_ac842_pbctrl(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_timing_control(0), m_mode(0), m_depth(0), m_monitor_id(0), m_pal_address(0),
m_pal_idx(0), m_ac842_pbctrl(0), m_base(0), m_stride(1024), m_test(0), m_swatch_mode(1),
m_vram_offset(0), m_timing_control(0), m_monitor_id(0),
m_base(0), m_stride(1024), m_test(0), m_swatch_mode(1),
m_cursor_line(0), m_anim_line(0), m_int_status(0), m_hres(0), m_vres(0), m_htotal(0), m_vtotal(0),
m_config(0), m_block_control(0), m_swatch_test(0)
{
@ -95,9 +99,17 @@ dafb_device::dafb_device(const machine_config &mconfig, const char *tag, device_
m_ncr[0] = m_ncr[1] = nullptr;
}
dafb_memc_device::dafb_memc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
dafb_base(mconfig, DAFB_MEMC, tag, owner, clock),
m_pcbr1(0),
m_clock_shift(0),
m_clock_params(0)
{
}
void dafb_base::device_start()
{
m_vram = std::make_unique<u32[]>(VRAM_SIZE);
m_vram = std::make_unique<u32[]>(m_vram_size);
m_vbl_timer = timer_alloc(FUNC(dafb_base::vbl_tick), this);
m_cursor_timer = timer_alloc(FUNC(dafb_base::cursor_tick), this);
@ -108,7 +120,6 @@ void dafb_base::device_start()
save_item(NAME(m_timing_control));
save_item(NAME(m_vram_offset));
save_item(NAME(m_mode));
save_item(NAME(m_depth));
save_item(NAME(m_monitor_id));
save_item(NAME(m_base));
save_item(NAME(m_stride));
@ -130,7 +141,7 @@ void dafb_base::device_start()
save_item(NAME(m_block_control));
save_item(NAME(m_swatch_test));
save_item(NAME(m_int_status));
save_pointer(NAME(m_vram), VRAM_SIZE);
save_pointer(NAME(m_vram), m_vram_size);
machine().save().register_postload(save_prepost_delegate(FUNC(dafb_base::recalc_mode), this));
}
@ -271,6 +282,18 @@ u32 dafb_base::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const
}
}
break;
case 5: // 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;
@ -326,6 +349,7 @@ u32 dafb_base::dafb_r(offs_t offset)
void dafb_base::dafb_w(offs_t offset, u32 data)
{
data &= 0xfff;
switch (offset << 2)
{
case 0: // bits 20-9 of base
@ -508,6 +532,9 @@ u32 dafb_base::swatch_r(offs_t offset)
void dafb_base::swatch_w(offs_t offset, u32 data)
{
// registers are all 12 bits wide
data &= 0xfff;
switch (offset << 2)
{
case 0x0: // Swatch mode
@ -592,7 +619,7 @@ void dafb_base::swatch_w(offs_t offset, u32 data)
}
}
u32 dafb_base::ac842_r(offs_t offset)
u32 dafb_base::ramdac_r(offs_t offset)
{
switch (offset << 2)
{
@ -625,11 +652,12 @@ u32 dafb_base::ac842_r(offs_t offset)
return 0;
}
void dafb_base::ac842_w(offs_t offset, u32 data)
void dafb_base::ramdac_w(offs_t offset, u32 data)
{
switch (offset << 2)
{
case 0:
LOGMASKED(LOG_RAMDAC, "Address to %d\n", data & 0xff);
m_pal_address = data & 0xff;
m_pal_idx = 0;
break;
@ -670,7 +698,7 @@ void dafb_base::ac842_w(offs_t offset, u32 data)
case 0x20:
m_ac842_pbctrl = data;
LOGMASKED(LOG_AC842, "%02x to AC842 pixel bus control, & 0x1c = %02x\n", data, data & 0x1c);
LOGMASKED(LOG_RAMDAC, "%02x to AC842 pixel bus control, & 0x1c = %02x\n", data, data & 0x1c);
switch (data & 0x1c)
{
case 0x00:
@ -752,17 +780,22 @@ void dafb_base::recalc_mode()
}
}
u32 dafb_base::clockgen_r(offs_t offset)
u8 dafb_base::clockgen_r(offs_t offset)
{
return 0;
}
void dafb_base::clockgen_w(offs_t offset, u32 data)
void dafb_base::clockgen_w(offs_t offset, u8 data)
{
m_dp8531_regs[offset>>2] = data & 0xf;
LOGMASKED(LOG_CLOCKGEN, "%s: Write %x to DP8531 at %d\n", tag(), data, offset);
if ((offset & 3) != 3)
{
return;
}
if ((offset >> 2) == 15)
m_dp8531_regs[offset>>4] = data & 0xf;
LOGMASKED(LOG_CLOCKGEN, "%s: Write %x to DP8531 at %d (reg %d)\n", tag(), data, offset, offset>>4);
if ((offset>>4) == 15)
{
int r = m_dp8531_regs[6] << 8 | m_dp8531_regs[5] << 4 | m_dp8531_regs[4];
int p = (1 << m_dp8531_regs[9]);
@ -785,12 +818,12 @@ void dafb_base::clockgen_w(offs_t offset, u32 data)
u32 dafb_base::vram_r(offs_t offset)
{
return m_vram[offset];
return m_vram[offset & (m_vram_size - 1)];
}
void dafb_base::vram_w(offs_t offset, u32 data, u32 mem_mask)
{
COMBINE_DATA(&m_vram[offset]);
COMBINE_DATA(&m_vram[offset & (m_vram_size - 1)]);
}
void dafb_base::recalc_ints()
@ -951,3 +984,128 @@ void dafb_device::turboscsi_drq_w(int state)
template void dafb_device::turboscsi_drq_w<0>(int state);
template void dafb_device::turboscsi_drq_w<1>(int state);
// ************************************************************************
// dafb_memc_device overrides/additions
// ************************************************************************
void dafb_memc_device::device_start()
{
m_vram_size = 0x100000; // all 5 MEMC machines can only have 1 MB VRAM
dafb_base::device_start();
}
// MEMC's DAFB uses the DP8534 clock generator, not the DP8531.
// The interface is quite different, and no datasheet seems to exist.
// This emulation is reverse-engineered from https://sourceforge.net/projects/dt3152/files/
// which brute forces the DP8534 parameters from a given pixel clock (and also shows
// how the parameters become the output clock, as well as how the parameters fit into
// the bitstream clocked into the chip.
u8 dafb_memc_device::clockgen_r(offs_t offset)
{
return 0;
}
void dafb_memc_device::clockgen_w(offs_t offset, u8 data)
{
switch (offset)
{
case 3: // shift parameters into bit 0 one bit at a time
m_clock_shift <<= 1;
m_clock_shift |= (data & 1);
break;
case 19: // commit parameters to memory
m_clock_params = (m_clock_shift << 2);
m_clock_shift = 0;
const u8 param1 = bitswap<8>((m_clock_params >> 32) & 0xff, 0, 1, 2, 3, 4, 5, 6, 7);
const u8 param2 = bitswap<8>((m_clock_params >> 24) & 0xff, 0, 1, 2, 3, 4, 5, 6, 7);
const u8 param3 = bitswap<8>((m_clock_params >> 16) & 0xff, 0, 1, 2, 3, 4, 5, 6, 7);
const u8 param4 = bitswap<8>((m_clock_params >> 8) & 0xff, 0, 1, 2, 3, 4, 5, 6, 7);
const u8 param5 = bitswap<8>(m_clock_params & 0xff, 0, 1, 2, 3, 4, 5, 6, 7);
const u8 p = (param1 >> 7) | (param2 << 1);
const u8 rcnt = (param2 >> 7) | (param3 << 1);
const u8 ncnt = (param4 >> 1) | (param5 << 7);
const float vco_clock = (20.0 * (float)ncnt) / (float)rcnt;
const float pixel_clock = vco_clock / (float)(p+1);
m_pixel_clock = (int)(pixel_clock*1000000+.5);
LOGMASKED(LOG_CLOCKGEN, "DP8534: P %d RCNT %d NCNT %d => VCO=%d Hz, pixel clock %d Hz\n", p, rcnt, ncnt, (int)(vco_clock*1000000+.5), m_pixel_clock);
break;
}
}
// This is an AC842a, which has x555 16bpp mode
u32 dafb_memc_device::ramdac_r(offs_t offset)
{
switch (offset << 2)
{
case 0x20:
if ((m_pal_address == 1) && ((m_ac842_pbctrl & 0x06) == 0x06))
{
return m_pcbr1;
}
else
{
return dafb_base::ramdac_r(offset);
}
default:
return dafb_base::ramdac_r(offset);
}
}
void dafb_memc_device::ramdac_w(offs_t offset, u32 data)
{
switch (offset << 2)
{
case 0x20:
if ((m_pal_address == 1) && ((m_ac842_pbctrl & 0x06) == 0x06))
{
LOGMASKED(LOG_RAMDAC, "%02x to AC842a PCBR1\n", data);
m_pcbr1 = data & 0xf0;
}
else
{
LOGMASKED(LOG_RAMDAC, "%02x to AC842a PCBR0, & 0x1c = %02x\n", data, data & 0x1c);
m_ac842_pbctrl = data;
if ((m_pcbr1 & 0xc0) == 0xc0)
{
m_mode = 5; // 16 bpp (x555)
}
else
{
switch (data & 0x1c)
{
case 0x00:
m_mode = 0; // 1bpp
break;
case 0x08:
m_mode = 1; // 2bpp
break;
case 0x10:
m_mode = 2; // 4bpp
break;
case 0x18:
m_mode = 3; // 8bpp
break;
case 0x1c:
m_mode = 4; // 24bpp
break;
}
}
recalc_mode();
}
break;
default:
dafb_base::ramdac_w(offset, data);
break;
}
}

View File

@ -31,10 +31,25 @@ protected:
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
u32 dafb_r(offs_t offset);
void dafb_w(offs_t offset, u32 data);
u32 swatch_r(offs_t offset);
void swatch_w(offs_t offset, u32 data);
virtual u32 ramdac_r(offs_t offset);
virtual void ramdac_w(offs_t offset, u32 data);
virtual u8 clockgen_r(offs_t offset);
virtual void clockgen_w(offs_t offset, u8 data);
void recalc_ints();
void recalc_mode();
u16 m_scsi_ctrl[2];
int m_drq[2];
int m_scsi_read_cycles[2], m_scsi_write_cycles[2], m_scsi_dma_read_cycles[2], m_scsi_dma_write_cycles[2];
u32 m_vram_size;
int m_dafb_version;
u32 m_pixel_clock;
u8 m_pal_address, m_pal_idx, m_ac842_pbctrl, m_mode;
private:
required_device<screen_device> m_screen;
@ -70,27 +85,15 @@ private:
std::unique_ptr<u32[]> m_vram;
emu_timer *m_vbl_timer, *m_cursor_timer;
u32 m_vram_offset;
u8 m_timing_control, m_mode, m_depth, m_monitor_id;
u8 m_pal_address, m_pal_idx, m_ac842_pbctrl;
u8 m_timing_control, m_monitor_id;
u32 m_base, m_stride, m_test;
u32 m_horizontal_params[10], m_vertical_params[7];
u8 m_swatch_mode;
u16 m_cursor_line, m_anim_line;
s32 m_int_status;
u8 m_dp8531_regs[16];
u32 m_pixel_clock;
u32 m_hres, m_vres, m_htotal, m_vtotal, m_config, m_block_control, m_swatch_test;
u32 dafb_r(offs_t offset);
void dafb_w(offs_t offset, u32 data);
u32 swatch_r(offs_t offset);
void swatch_w(offs_t offset, u32 data);
u32 ac842_r(offs_t offset);
void ac842_w(offs_t offset, u32 data);
u32 clockgen_r(offs_t offset);
void clockgen_w(offs_t offset, u32 data);
void recalc_ints();
void recalc_mode();
u32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
TIMER_CALLBACK_MEMBER(vbl_tick);
@ -123,6 +126,26 @@ private:
ncr53c94_device *m_ncr[2];
};
class dafb_memc_device: public dafb_base
{
public:
dafb_memc_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
protected:
virtual void device_start() override;
virtual u8 clockgen_r(offs_t offset) override;
virtual void clockgen_w(offs_t offset, u8 data) override;
virtual u32 ramdac_r(offs_t offset) override;
virtual void ramdac_w(offs_t offset, u32 data) override;
private:
u8 m_pcbr1;
u64 m_clock_shift;
u64 m_clock_params;
};
DECLARE_DEVICE_TYPE(DAFB, dafb_device)
DECLARE_DEVICE_TYPE(DAFB_MEMC, dafb_memc_device)
#endif /* MAME_APPLE_DAFB_H */

112
src/mame/apple/djmemc.cpp Normal file
View File

@ -0,0 +1,112 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/*
Apple "djMEMC" memory controller
Emulation by R. Belmont
djMEMC contains the following:
- A memory controller for up to 640 MiB of RAM
- The usual Mac ROM/RAM switch so at boot the processor has vectors at 0
- DAFB II video, minus the "Turbo SCSI" feature, which has moved to IOSB
*/
#include "emu.h"
#include "djmemc.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(DJMEMC, djmemc_device, "djmemc", "Apple djMEMC memory controller")
//-------------------------------------------------
// ADDRESS_MAP
//-------------------------------------------------
void djmemc_device::map(address_map &map)
{
map(0x40000000, 0x400fffff).r(FUNC(djmemc_device::rom_switch_r)).mirror(0x0ff00000);
map(0xf9000000, 0xf91fffff).rw(m_video, FUNC(dafb_device::vram_r), FUNC(dafb_device::vram_w));
map(0xf9800000, 0xf98003ff).m(m_video, FUNC(dafb_device::map));
}
//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------
void djmemc_device::device_add_mconfig(machine_config &config)
{
DAFB_MEMC(config, m_video);
m_video->dafb_irq().set(FUNC(djmemc_device::vbl_w));
}
//-------------------------------------------------
// djmemc_device - constructor
//-------------------------------------------------
djmemc_device::djmemc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, DJMEMC, tag, owner, clock),
m_maincpu(*this, finder_base::DUMMY_TAG),
m_video(*this, "video"),
m_rom(*this, finder_base::DUMMY_TAG),
m_irq(*this),
m_overlay(false)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void djmemc_device::device_start()
{
m_rom_ptr = &m_rom[0];
m_rom_size = m_rom.length() << 2;
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void djmemc_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 djmemc_device::rom_switch_r(offs_t offset)
{
// disable the overlay
if (m_overlay)
{
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 djmemc_device::set_ram_info(u32 *ram, u32 size)
{
m_ram_ptr = ram;
m_ram_size = size;
}
void djmemc_device::vbl_w(int state)
{
m_irq(state);
}

58
src/mame/apple/djmemc.h Normal file
View File

@ -0,0 +1,58 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
#ifndef MAME_APPLE_DJMEMC_H
#define MAME_APPLE_DJMEMC_H
#pragma once
#include "dafb.h"
// ======================> djmemc_device
class djmemc_device : public device_t
{
public:
// construction/destruction
djmemc_device(const machine_config &mconfig, const char *tag, device_t *owner)
: djmemc_device(mconfig, tag, owner, (uint32_t)0)
{
}
djmemc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// interface routines
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_rom_tag(T &&... args) { m_rom.set_tag(std::forward<T>(args)...); }
void set_ram_info(u32 *ram, u32 size);
auto write_irq() { return m_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;
private:
required_device<cpu_device> m_maincpu;
required_device<dafb_memc_device> m_video;
required_region_ptr<u32> m_rom;
devcb_write_line m_irq;
std::unique_ptr<u32[]> m_vram;
bool m_overlay;
u32 *m_ram_ptr, *m_rom_ptr;
u32 m_ram_size, m_rom_size;
u32 rom_switch_r(offs_t offset);
void vbl_w(int state);
};
// device type definition
DECLARE_DEVICE_TYPE(DJMEMC, djmemc_device)
#endif // MAME_APPLE_DJMEMC_H

626
src/mame/apple/iosb.cpp Normal file
View File

@ -0,0 +1,626 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/*
Apple "IOSB" I/O ASIC
Emulation by R. Belmont
IOSB stands for "I/O Subsystem Buffer". The chip was originally called "BIOS" ("Buffered I/O Subsystem"),
but they flipped the order around, presumably to avoid the obvious IBM PC reference.
IOSB contains the following:
- A full VIA (VIA1) and a "pseudo-VIA" for VIA2. This is not the standard pseudo-VIA found in
chips like RBV, V8, or Sonora; it acts exactly like a real VIA, just without timers or a shift register.
- A SWIM2 floppy controller
- An ASC-like 4-channel audio controller
- The "Turbo SCSI" logic from the standalone versions of DAFB and DAFB II
- Support logic for various external subsystems (ADB, SCC, SONIC Ethernet)
The "PrimeTime" I/O ASIC is similar, and "PrimeTime II" adds an ATA controller.
*/
#include "emu.h"
#include "iosb.h"
#include "formats/ap_dsk35.h"
#define LOG_TURBOSCSI (1U << 1)
#define LOG_SCSIDRQ (1U << 2)
#define LOG_IOSBREGS (1U << 3)
#define VERBOSE (0)
#include "logmacro.h"
static constexpr u32 C7M = 7833600;
static constexpr u32 C15M = (C7M * 2);
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(IOSB, iosb_device, "iosb", "Apple IOSB system ASIC")
//-------------------------------------------------
// ADDRESS_MAP
//-------------------------------------------------
void iosb_device::map(address_map &map)
{
map(0x00000000, 0x00001fff).rw(FUNC(iosb_device::mac_via_r), FUNC(iosb_device::mac_via_w)).mirror(0x00fc0000);
map(0x00002000, 0x00003fff).rw(FUNC(iosb_device::mac_via2_r), FUNC(iosb_device::mac_via2_w)).mirror(0x00f00000);
map(0x00010000, 0x000100ff).rw(FUNC(iosb_device::turboscsi_r), FUNC(iosb_device::turboscsi_w)).mirror(0x00fc0000);
map(0x00010100, 0x00010103).rw(FUNC(iosb_device::turboscsi_dma_r), FUNC(iosb_device::turboscsi_dma_w)).select(0x00fc0000);
map(0x00014000, 0x00015fff).rw(m_asc, FUNC(asc_device::read), FUNC(asc_device::write)).mirror(0x00f00000);
map(0x00018000, 0x00019fff).rw(FUNC(iosb_device::iosb_regs_r), FUNC(iosb_device::iosb_regs_w)).mirror(0x00f00000);
map(0x0001e000, 0x0001ffff).rw(FUNC(iosb_device::swim_r), FUNC(iosb_device::swim_w)).mirror(0x00f00000);
// IOSB always gives an ID of "0x2BAD", the VIA I/O pins determine the rest
map(0x0fff0000, 0x0fffffff).lr32(NAME([](offs_t offset) { return 0xa55a2bad; }));
}
//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------
void iosb_device::device_add_mconfig(machine_config &config)
{
R65NC22(config, m_via1, C7M / 10);
m_via1->readpa_handler().set(FUNC(iosb_device::via_in_a));
m_via1->readpb_handler().set(FUNC(iosb_device::via_in_b));
m_via1->writepa_handler().set(FUNC(iosb_device::via_out_a));
m_via1->writepb_handler().set(FUNC(iosb_device::via_out_b));
m_via1->cb1_handler().set(FUNC(iosb_device::via_out_cb1));
m_via1->cb2_handler().set(FUNC(iosb_device::via_out_cb2));
m_via1->irq_handler().set(FUNC(iosb_device::via1_irq));
R65NC22(config, m_via2, C7M / 10);
m_via2->readpa_handler().set(FUNC(iosb_device::via2_in_a));
m_via2->irq_handler().set(FUNC(iosb_device::via2_irq));
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
ASC(config, m_asc, C15M, asc_device::asc_type::SONORA);
m_asc->add_route(0, "lspeaker", 1.0);
m_asc->add_route(1, "rspeaker", 1.0);
m_asc->irqf_callback().set(FUNC(iosb_device::asc_irq));
SWIM2(config, m_fdc, C15M);
m_fdc->devsel_cb().set(FUNC(iosb_device::devsel_w));
m_fdc->phases_cb().set(FUNC(iosb_device::phases_w));
applefdintf_device::add_35_hd(config, m_floppy[0]);
applefdintf_device::add_35_nc(config, m_floppy[1]);
RTC3430042(config, m_rtc, XTAL(32'768));
m_rtc->cko_cb().set(m_via1, FUNC(via6522_device::write_ca2));
}
//-------------------------------------------------
// iosb_device - constructor
//-------------------------------------------------
iosb_device::iosb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, IOSB, tag, owner, clock),
m_adb_st(*this),
m_cb1(*this),
m_cb2(*this),
m_pa1(*this, 0),
m_pa2(*this, 0),
m_pa4(*this, 0),
m_pa6(*this, 0),
m_maincpu(*this, finder_base::DUMMY_TAG),
m_ncr(*this, finder_base::DUMMY_TAG),
m_via1(*this, "via1"),
m_via2(*this, "via2"),
m_asc(*this, "asc"),
m_rtc(*this,"rtc"),
m_fdc(*this, "fdc"),
m_floppy(*this, "fdc:%d", 0U),
m_cur_floppy(nullptr),
m_hdsel(0),
m_adb_interrupt(0),
m_drq(0),
m_scsi_irq(0),
m_asc_irq(0),
m_scsi_read_cycles(3),
m_scsi_write_cycles(3),
m_scsi_dma_read_cycles(3),
m_scsi_dma_write_cycles(3),
m_scsi_dma_result(0),
m_scsi_second_half(false)
{
std::fill(std::begin(m_iosb_regs), std::end(m_iosb_regs), 0);
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void iosb_device::device_start()
{
m_maincpu->set_emmu_enable(true);
m_6015_timer = timer_alloc(FUNC(iosb_device::mac_6015_tick), this);
m_6015_timer->adjust(attotime::never);
save_item(NAME(m_via_interrupt));
save_item(NAME(m_via2_interrupt));
save_item(NAME(m_scc_interrupt));
save_item(NAME(m_last_taken_interrupt));
save_item(NAME(m_hdsel));
save_item(NAME(m_via2_ca1_hack));
save_item(NAME(m_nubus_irqs));
save_item(NAME(m_iosb_regs));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void iosb_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;
m_hdsel = 0;
m_nubus_irqs = 0xff;
m_via2_ca1_hack = 1;
m_via2->write_ca1(1);
m_via2->write_cb1(1);
// set defaults that make VIA2 pseudo-ish
m_via2->write(11, 0xc0);
m_via2->write(12, 0x26);
m_via2->write(13, 0x00);
m_via2->write(14, 0x80);
}
TIMER_CALLBACK_MEMBER(iosb_device::mac_6015_tick)
{
m_via1->write_ca1(CLEAR_LINE);
m_via1->write_ca1(ASSERT_LINE);
}
uint8_t iosb_device::via_in_a()
{
u8 result = m_pa1() << 1;
result |= m_pa2() << 2;
result |= m_pa4() << 4;
result |= m_pa6() << 6;
return result;
}
uint8_t iosb_device::via_in_b()
{
return (m_adb_interrupt ? 0 : 8) | m_rtc->data_r();
}
void iosb_device::via_out_cb1(int state)
{
m_cb1(state & 1);
}
void iosb_device::via_out_cb2(int state)
{
m_cb2(state & 1);
}
void iosb_device::via_out_a(uint8_t data)
{
int hdsel = BIT(data, 5);
if (hdsel != m_hdsel)
{
if (m_cur_floppy)
{
m_cur_floppy->ss_w(hdsel);
}
}
m_hdsel = hdsel;
}
void iosb_device::via_out_b(uint8_t data)
{
m_adb_st((data & 0x30) >> 4);
m_rtc->ce_w((data & 0x04)>>2);
m_rtc->data_w(data & 0x01);
m_rtc->clk_w((data >> 1) & 0x01);
}
void iosb_device::via1_irq(int state)
{
m_via_interrupt = state;
field_interrupts();
}
void iosb_device::via2_irq(int state)
{
m_via2_interrupt = state;
field_interrupts();
}
void iosb_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_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 iosb_device::scc_irq_w(int state)
{
m_scc_interrupt = (state == ASSERT_LINE);
field_interrupts();
}
template <u8 mask>
void iosb_device::via2_irq_w(int state)
{
m_nubus_irqs = m_via2->read(1);
if (state)
{
m_nubus_irqs &= ~mask;
}
else
{
m_nubus_irqs |= mask;
}
m_nubus_irqs |= 0x86;
if ((m_nubus_irqs & 0x79) != 0x79)
{
if (m_via2_ca1_hack == 0)
{
m_via2->write_ca1(1);
}
m_via2_ca1_hack = 0;
m_via2->write_ca1(0);
}
else
{
m_via2_ca1_hack = 1;
m_via2->write_ca1(1);
}
}
template void iosb_device::via2_irq_w<0x40>(int state);
template void iosb_device::via2_irq_w<0x20>(int state);
template void iosb_device::via2_irq_w<0x10>(int state);
template void iosb_device::via2_irq_w<0x08>(int state);
template void iosb_device::via2_irq_w<0x01>(int state);
u8 iosb_device::via2_in_a()
{
return m_nubus_irqs;
}
void iosb_device::scsi_irq_w(int state)
{
m_via2->write_cb2(state ^ 1);
m_scsi_irq = state;
}
void iosb_device::asc_irq(int state)
{
m_via2->write_cb1(state);
m_asc_irq = state;
}
void iosb_device::cb1_w(int state)
{
m_via1->write_cb1(state);
}
void iosb_device::cb2_w(int state)
{
m_via1->write_cb2(state);
}
uint16_t iosb_device::mac_via_r(offs_t offset)
{
uint16_t data;
offset >>= 8;
offset &= 0x0f;
if (!machine().side_effects_disabled())
via_sync();
data = m_via1->read(offset);
return (data & 0xff) | (data << 8);
}
void iosb_device::mac_via_w(offs_t offset, uint16_t data, uint16_t mem_mask)
{
offset >>= 8;
offset &= 0x0f;
via_sync();
if (ACCESSING_BITS_0_7)
m_via1->write(offset, data & 0xff);
if (ACCESSING_BITS_8_15)
m_via1->write(offset, (data >> 8) & 0xff);
}
u16 iosb_device::mac_via2_r(offs_t offset)
{
int data;
offset >>= 8;
offset &= 0x0f;
if (!machine().side_effects_disabled())
via_sync();
data = m_via2->read(offset);
// a little more pseudo-ness: bit 0 of the IFR shows the live line states of the IRQs and DRQ
if (offset == 13)
{
data &= ~0x19;
data |= (m_drq) ? 0x01 : 0;
data |= (m_scsi_irq) ? 0x08 : 0;
data |= (m_asc_irq) ? 0x10 : 0;
}
return (data & 0xff) | (data << 8);
}
void iosb_device::mac_via2_w(offs_t offset, u16 data, u16 mem_mask)
{
offset >>= 8;
offset &= 0x0f;
// what makes VIA2 "pseudo" is that regs 4-10 can't be written, and 11 and 12 have canned values
switch (offset)
{
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
return;
case 11:
m_via2->write(11, 0xc0);
return;
case 12:
m_via2->write(12, 0x26);
return;
}
via_sync();
if (ACCESSING_BITS_0_7)
m_via2->write(offset, data & 0xff);
if (ACCESSING_BITS_8_15)
m_via2->write(offset, (data >> 8) & 0xff);
}
void iosb_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));
}
uint16_t iosb_device::swim_r(offs_t offset, u16 mem_mask)
{
if (!machine().side_effects_disabled())
{
m_maincpu->adjust_icount(-5);
}
u16 result = m_fdc->read((offset >> 8) & 0xf);
return result << 8;
}
void iosb_device::swim_w(offs_t offset, u16 data, u16 mem_mask)
{
if (ACCESSING_BITS_0_7)
m_fdc->write((offset >> 8) & 0xf, data & 0xff);
else
m_fdc->write((offset >> 8) & 0xf, data >> 8);
}
void iosb_device::phases_w(uint8_t phases)
{
if (m_cur_floppy)
m_cur_floppy->seek_phase_w(phases);
}
void iosb_device::devsel_w(uint8_t devsel)
{
if (devsel == 1)
m_cur_floppy = m_floppy[0]->get_device();
else if (devsel == 2)
m_cur_floppy = m_floppy[1]->get_device();
else
m_cur_floppy = nullptr;
m_fdc->set_floppy(m_cur_floppy);
if (m_cur_floppy)
m_cur_floppy->ss_w(m_hdsel);
}
u8 iosb_device::turboscsi_r(offs_t offset)
{
if (!machine().side_effects_disabled())
{
m_maincpu->adjust_icount(-m_scsi_read_cycles);
}
return m_ncr->read(offset>>4);
}
void iosb_device::turboscsi_w(offs_t offset, u8 data)
{
LOGMASKED(LOG_TURBOSCSI, "turboscsi_w: %02x @ %x (PC=%x)\n", data, offset>>4, m_maincpu->pc());
m_maincpu->adjust_icount(-m_scsi_write_cycles);
m_ncr->write(offset>>4, data);
}
u32 iosb_device::turboscsi_dma_r(offs_t offset, u32 mem_mask)
{
if (mem_mask != 0xffffffff && mem_mask != 0xffff0000)
{
fatalerror("IOSB: turboscsi_dma_r mem_mask not handled %08x\n", mem_mask);
}
if (!machine().side_effects_disabled() && BIT(offset << 1, 18))
{
m_maincpu->adjust_icount(-m_scsi_dma_read_cycles);
}
if (!m_drq)
{
// The real DAFB simply holds off /DTACK here, we simulate that
// by rewinding and repeating the instruction until DRQ is asserted.
m_maincpu->restart_this_instruction();
m_maincpu->spin_until_time(attotime::from_usec(50));
return 0xffff;
}
if (mem_mask == 0xffffffff)
{
if (!m_scsi_second_half)
{
m_scsi_dma_result = m_ncr->dma16_swap_r()<<16;
m_scsi_second_half = true;
}
if (!m_drq)
{
// The real DAFB simply holds off /DTACK here, we simulate that
// by rewinding and repeating the instruction until DRQ is asserted.
m_maincpu->restart_this_instruction();
m_maincpu->spin_until_time(attotime::from_usec(50));
return 0xffff;
}
m_scsi_second_half = false;
m_scsi_dma_result |= m_ncr->dma16_swap_r();
}
else if (mem_mask == 0xffff0000)
{
m_scsi_dma_result = m_ncr->dma16_swap_r()<<16;
}
return m_scsi_dma_result;
}
void iosb_device::turboscsi_dma_w(offs_t offset, u32 data, u32 mem_mask)
{
if (!machine().side_effects_disabled() && BIT(offset << 1, 18))
{
m_maincpu->adjust_icount(-m_scsi_dma_write_cycles);
}
LOGMASKED(LOG_TURBOSCSI, "dma_w %08x (mask %04x)\n", data & mem_mask, mem_mask);
if (!m_drq)
{
m_maincpu->restart_this_instruction();
m_maincpu->spin_until_time(attotime::from_usec(50));
return;
}
if (mem_mask == 0xffffffff)
{
if (!m_scsi_second_half)
{
m_ncr->dma16_swap_w(data>>16);
}
m_scsi_second_half = true;
if (!m_drq)
{
m_maincpu->restart_this_instruction();
m_maincpu->spin_until_time(attotime::from_usec(50));
return;
}
m_scsi_second_half = false;
m_ncr->dma16_swap_w(data & 0xffff);
}
else if (mem_mask == 0xffff0000)
{
m_ncr->dma16_swap_w(data >> 16);
}
else if (mem_mask == 0xff000000)
{
m_ncr->dma_w(data >> 24);
}
else
{
fatalerror("IOSB: turboscsi_dma_w unhandled mask %08x\n", mem_mask);
}
}
void iosb_device::scsi_drq_w(int state)
{
LOGMASKED(LOG_SCSIDRQ, "SCSI DRQ %d (was %d)\n", state, m_drq);
m_drq = state;
m_via2->write_ca2(state);
}
u16 iosb_device::iosb_regs_r(offs_t offset)
{
LOGMASKED(LOG_IOSBREGS, "iosb_regs_r: @ %x\n", offset>>7);
return m_iosb_regs[offset>>7];
}
void iosb_device::iosb_regs_w(offs_t offset, u16 data, u16 mem_mask)
{
LOGMASKED(LOG_IOSBREGS, "iosb_regs_w: %04x @ %x, mask %04x\n", data, offset>>7, mem_mask);
COMBINE_DATA(&m_iosb_regs[offset>>7]);
if ((offset>>7) == 2)
{
const int times[4] = { 5, 5, 4, 3 };
m_scsi_dma_read_cycles = times[(m_iosb_regs[2]>>8) & 3];
m_scsi_dma_write_cycles = (times[(m_iosb_regs[2]>>11) & 3]);
LOGMASKED(LOG_TURBOSCSI, "SCSI DMA read cycles %d write cycles %d\n", m_scsi_dma_read_cycles, m_scsi_dma_write_cycles);
}
}

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

@ -0,0 +1,128 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
#ifndef MAME_APPLE_IOSB_H
#define MAME_APPLE_IOSB_H
#pragma once
#include "macrtc.h"
#include "cpu/m68000/m68040.h"
#include "machine/6522via.h"
#include "machine/applefdintf.h"
#include "machine/ncr53c90.h"
#include "machine/swim2.h"
#include "sound/asc.h"
#include "speaker.h"
// ======================> iosb_device
class iosb_device : public device_t
{
public:
// construction/destruction
iosb_device(const machine_config &mconfig, const char *tag, device_t *owner)
: iosb_device(mconfig, tag, owner, (uint32_t)0)
{
}
iosb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// interface routines
auto write_adb_st() { return m_adb_st.bind(); } // ADB state
auto write_cb1() { return m_cb1.bind(); } // ADB clock
auto write_cb2() { return m_cb2.bind(); } // ADB data
auto read_pa1() { return m_pa1.bind(); } // ID bits
auto read_pa2() { return m_pa2.bind(); }
auto read_pa4() { return m_pa4.bind(); }
auto read_pa6() { return m_pa6.bind(); }
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)...); }
void pb3_w(int state) { m_adb_interrupt = state; }
void cb1_w(int state); // ADB clock
void cb2_w(int state); // ADB data
void scsi_irq_w(int state);
void scc_irq_w(int state);
template <u8 mask>
void via2_irq_w(int state);
void via_sync();
void scsi_drq_w(int state);
u8 turboscsi_r(offs_t offset);
void turboscsi_w(offs_t offset, u8 data);
u32 turboscsi_dma_r(offs_t offset, u32 mem_mask);
void turboscsi_dma_w(offs_t offset, u32 data, u32 mem_mask);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_add_mconfig(machine_config &config) override;
private:
devcb_write8 m_adb_st;
devcb_write_line m_cb1, m_cb2;
devcb_read_line m_pa1, m_pa2, m_pa4, m_pa6;
required_device<m68000_musashi_device> m_maincpu;
required_device<ncr53c96_device> m_ncr;
required_device<via6522_device> m_via1, m_via2;
required_device<asc_device> m_asc;
required_device<rtc3430042_device> m_rtc;
required_device<applefdintf_device> m_fdc;
required_device_array<floppy_connector, 2> m_floppy;
emu_timer *m_6015_timer;
int m_via_interrupt, m_via2_interrupt, m_scc_interrupt, m_last_taken_interrupt;
floppy_image_device *m_cur_floppy = nullptr;
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;
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);
uint8_t via_in_a();
uint8_t via2_in_a();
uint8_t via_in_b();
void via_out_a(uint8_t data);
void via_out_b(uint8_t data);
void field_interrupts();
void via_out_cb1(int state);
void via_out_cb2(int state);
void via1_irq(int state);
void via2_irq(int state);
void asc_irq(int state);
TIMER_CALLBACK_MEMBER(mac_6015_tick);
void phases_w(uint8_t phases);
void devsel_w(uint8_t devsel);
uint16_t swim_r(offs_t offset, u16 mem_mask);
void swim_w(offs_t offset, u16 data, u16 mem_mask);
};
// device type definition
DECLARE_DEVICE_TYPE(IOSB, iosb_device)
#endif // MAME_APPLE_IOSB_H

View File

@ -0,0 +1,306 @@
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/****************************************************************************
drivers/macquadra800.cpp
Mac Centris 610 ("WLCD")
Mac Centris 630 ("Wombat 25")
Mac Quadra 610 ("Speedbump 610")
Mac Quadra 650 ("Speedbump 650")
Mac Quadra 800 ("Wombat 33")
By R. Belmont
These second-generation 68040 machines shrunk the huge mass of separate
chips found in the Quadra 700 down to a pair of ASICs, djMEMC (memory controller
plus revised DAFB video) and IOSB (I/O bus adaptor with integrated VIAs,
audio, "Turbo SCSI", and SWIM2 floppy).
****************************************************************************/
#include "emu.h"
#include "adbmodem.h"
#include "djmemc.h"
#include "iosb.h"
#include "macadb.h"
#include "mactoolbox.h"
#include "bus/nscsi/devices.h"
#include "bus/nubus/cards.h"
#include "bus/nubus/nubus.h"
#include "bus/rs232/rs232.h"
#include "cpu/m68000/m68040.h"
#include "machine/dp83932c.h"
#include "machine/ncr53c90.h"
#include "machine/nscsi_bus.h"
#include "machine/ram.h"
#include "machine/timer.h"
#include "machine/z80scc.h"
#include "softlist_dev.h"
#define C32M 31.3344_MHz_XTAL
#define C15M (C32M/2)
#define C7M (C32M/4)
namespace {
class quadra800_state : public driver_device
{
public:
quadra800_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_djmemc(*this, "djmemc"),
m_iosb(*this, "iosb"),
m_macadb(*this, "macadb"),
m_adbmodem(*this, "adbmodem"),
m_scc(*this, "scc"),
m_ram(*this, RAM_TAG),
m_scsibus(*this, "scsi"),
m_ncr1(*this, "scsi:7:ncr53c96"),
m_sonic(*this, "sonic")
{
}
void macqd800(machine_config &config);
void macct610(machine_config &config);
void macct650(machine_config &config);
void macqd610(machine_config &config);
void macqd650(machine_config &config);
void quadra800_map(address_map &map);
void init_macqd800();
private:
required_device<m68040_device> m_maincpu;
required_device<djmemc_device> m_djmemc;
required_device<iosb_device> m_iosb;
required_device<macadb_device> m_macadb;
required_device<adbmodem_device> m_adbmodem;
required_device<z80scc_device> m_scc;
required_device<ram_device> m_ram;
required_device<nscsi_bus_device> m_scsibus;
required_device<ncr53c96_device> m_ncr1;
required_device<dp83932c_device> m_sonic;
virtual void machine_start() override;
virtual void machine_reset() override;
u16 mac_scc_r(offs_t offset)
{
m_iosb->via_sync();
u16 result = m_scc->dc_ab_r(offset);
return (result << 8) | result;
}
void mac_scc_2_w(offs_t offset, u16 data) { m_iosb->via_sync(); m_scc->dc_ab_w(offset, data >> 8); }
};
void quadra800_state::machine_start()
{
m_djmemc->set_ram_info((u32 *) m_ram->pointer(), m_ram->size());
}
void quadra800_state::machine_reset()
{
}
void quadra800_state::init_macqd800()
{
}
/***************************************************************************
ADDRESS MAPS
***************************************************************************/
void quadra800_state::quadra800_map(address_map &map)
{
map(0x00000000, 0xffffffff).m(m_djmemc, FUNC(djmemc_device::map));
map(0x50000000, 0x5fffffff).m(m_iosb, FUNC(iosb_device::map));
// 50008000 = Ethernet MAC ID PROM
map(0x5000a000, 0x5000b0ff).m(m_sonic, FUNC(dp83932c_device::map)).umask32(0x0000ffff).mirror(0x00fc0000);
map(0x5000c000, 0x5000dfff).rw(FUNC(quadra800_state::mac_scc_r), FUNC(quadra800_state::mac_scc_2_w)).mirror(0x00fc0000);
}
/***************************************************************************
DEVICE CONFIG
***************************************************************************/
static INPUT_PORTS_START( macadb )
INPUT_PORTS_END
/***************************************************************************
MACHINE DRIVERS
***************************************************************************/
void quadra800_state::macqd800(machine_config &config)
{
M68040(config, m_maincpu, 33_MHz_XTAL);
m_maincpu->set_addrmap(AS_PROGRAM, &quadra800_state::quadra800_map);
m_maincpu->set_dasm_override(std::function(&mac68k_dasm_override), "mac68k_dasm_override");
DJMEMC(config, m_djmemc, 33_MHz_XTAL);
m_djmemc->set_maincpu_tag("maincpu");
m_djmemc->set_rom_tag("bootrom");
m_djmemc->write_irq().set(m_iosb, FUNC(iosb_device::via2_irq_w<0x40>));
IOSB(config, m_iosb, 33_MHz_XTAL);
m_iosb->set_maincpu_tag("maincpu");
m_iosb->set_scsi_tag("scsi:7:ncr53c96");
m_iosb->write_adb_st().set(m_adbmodem, FUNC(adbmodem_device::set_via_state));
// Quadra 800 ID is 0x12
m_iosb->read_pa1().set_constant(1);
m_iosb->read_pa2().set_constant(0);
m_iosb->read_pa4().set_constant(1);
m_iosb->read_pa6().set_constant(0);
SCC85C30(config, m_scc, C7M);
m_scc->configure_channels(3'686'400, 3'686'400, 3'686'400, 3'686'400);
m_scc->out_int_callback().set(m_iosb, FUNC(iosb_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));
// SCSI bus and devices
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, "harddisk");
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_iosb, FUNC(iosb_device::scsi_irq_w));
adapter.drq_handler_cb().set(m_iosb, FUNC(iosb_device::scsi_drq_w));
});
DP83932C(config, m_sonic, 40_MHz_XTAL / 2); // clock is C20M on the schematics
m_sonic->set_bus(m_maincpu, 0);
m_sonic->out_int_cb().set(m_iosb, FUNC(iosb_device::via2_irq_w<0x01>));
nubus_device &nubus(NUBUS(config, "nubus", 40_MHz_XTAL / 4));
nubus.set_space(m_maincpu, AS_PROGRAM);
nubus.out_irqc_callback().set(m_iosb, FUNC(iosb_device::via2_irq_w<0x08>));
nubus.out_irqd_callback().set(m_iosb, FUNC(iosb_device::via2_irq_w<0x10>));
nubus.out_irqe_callback().set(m_iosb, FUNC(iosb_device::via2_irq_w<0x20>));
NUBUS_SLOT(config, "nbc", "nubus", mac_nubus_cards, nullptr);
NUBUS_SLOT(config, "nbd", "nubus", mac_nubus_cards, nullptr);
NUBUS_SLOT(config, "nbe", "nubus", mac_nubus_cards, nullptr);
ADBMODEM(config, m_adbmodem, C7M);
m_adbmodem->via_clock_callback().set(m_iosb, FUNC(iosb_device::cb1_w));
m_adbmodem->via_data_callback().set(m_iosb, FUNC(iosb_device::cb2_w));
m_adbmodem->linechange_callback().set(m_macadb, FUNC(macadb_device::adb_linechange_w));
m_adbmodem->irq_callback().set(m_iosb, FUNC(iosb_device::pb3_w));
m_iosb->write_cb2().set(m_adbmodem, FUNC(adbmodem_device::set_via_data));
config.set_perfect_quantum(m_maincpu);
MACADB(config, m_macadb, C15M);
m_macadb->adb_data_callback().set(m_adbmodem, FUNC(adbmodem_device::set_adb_line));
/* internal ram */
RAM(config, m_ram);
m_ram->set_default_size("8M");
m_ram->set_extra_options("16M,32M,64M,96M,128M,192M,256M,320M,384M,512M,640M");
SOFTWARE_LIST(config, "hdd_list").set_original("mac_hdd");
}
void quadra800_state::macct610(machine_config &config)
{
macqd800(config);
M68040(config.replace(), m_maincpu, 20_MHz_XTAL);
m_maincpu->set_addrmap(AS_PROGRAM, &quadra800_state::quadra800_map);
m_maincpu->set_dasm_override(std::function(&mac68k_dasm_override), "mac68k_dasm_override");
// Centris 610 ID is 0x40
m_iosb->read_pa1().set_constant(0);
m_iosb->read_pa2().set_constant(0);
m_iosb->read_pa4().set_constant(0);
m_iosb->read_pa6().set_constant(1);
}
void quadra800_state::macct650(machine_config &config)
{
macqd800(config);
M68040(config.replace(), m_maincpu, 25_MHz_XTAL);
m_maincpu->set_addrmap(AS_PROGRAM, &quadra800_state::quadra800_map);
m_maincpu->set_dasm_override(std::function(&mac68k_dasm_override), "mac68k_dasm_override");
// Centris 650 ID is 0x46
m_iosb->read_pa1().set_constant(1);
m_iosb->read_pa2().set_constant(1);
m_iosb->read_pa4().set_constant(0);
m_iosb->read_pa6().set_constant(1);
}
void quadra800_state::macqd610(machine_config &config)
{
macqd800(config);
M68040(config.replace(), m_maincpu, 25_MHz_XTAL);
m_maincpu->set_addrmap(AS_PROGRAM, &quadra800_state::quadra800_map);
m_maincpu->set_dasm_override(std::function(&mac68k_dasm_override), "mac68k_dasm_override");
// Quadra 610 ID is 0x44
m_iosb->read_pa1().set_constant(0);
m_iosb->read_pa2().set_constant(1);
m_iosb->read_pa4().set_constant(0);
m_iosb->read_pa6().set_constant(1);
}
void quadra800_state::macqd650(machine_config &config)
{
macqd800(config);
M68040(config.replace(), m_maincpu, 33_MHz_XTAL);
m_maincpu->set_addrmap(AS_PROGRAM, &quadra800_state::quadra800_map);
m_maincpu->set_dasm_override(std::function(&mac68k_dasm_override), "mac68k_dasm_override");
// Quadra 650 ID is 0x52
m_iosb->read_pa1().set_constant(1);
m_iosb->read_pa2().set_constant(0);
m_iosb->read_pa4().set_constant(1);
m_iosb->read_pa6().set_constant(1);
}
ROM_START( macqd800 )
ROM_REGION32_BE(0x100000, "bootrom", 0)
ROM_SYSTEM_BIOS(0, "default", "Version 23F2")
ROMX_LOAD( "f1acad13.rom", 0x000000, 0x100000, CRC(4e70e3c0) SHA1(f2a9ce387019bf272c6e3459d961b30f28942ac5), ROM_BIOS(0) )
ROM_SYSTEM_BIOS(1, "original", "Version 23F1")
ROMX_LOAD( "f1a6f343.rom", 0x000000, 0x100000, CRC(3318a935) SHA1(031f13bfd726a70cfe4c73c5967861bc77297a79), ROM_BIOS(1) )
ROM_END
#define rom_macct610 rom_macqd800
#define rom_macct650 rom_macqd800
#define rom_macqd610 rom_macqd800
#define rom_macqd650 rom_macqd800
} // anonymous namespace
COMP( 1993, macqd800, 0, 0, macqd800, macadb, quadra800_state, init_macqd800, "Apple Computer", "Macintosh Quadra 800", MACHINE_SUPPORTS_SAVE)
COMP( 1993, macct610, macqd800, 0, macct610, macadb, quadra800_state, init_macqd800, "Apple Computer", "Macintosh Centris 610", MACHINE_SUPPORTS_SAVE)
COMP( 1993, macct650, macqd800, 0, macct650, macadb, quadra800_state, init_macqd800, "Apple Computer", "Macintosh Centris 650", MACHINE_SUPPORTS_SAVE)
COMP( 1993, macqd610, macqd800, 0, macqd610, macadb, quadra800_state, init_macqd800, "Apple Computer", "Macintosh Quadra 610", MACHINE_SUPPORTS_SAVE)
COMP( 1993, macqd650, macqd800, 0, macqd650, macadb, quadra800_state, init_macqd800, "Apple Computer", "Macintosh Quadra 650", MACHINE_SUPPORTS_SAVE)

View File

@ -885,6 +885,13 @@ macpd210 // 1992 Apple Macintosh PowerBook Duo 210
@source:apple/macquadra700.cpp
macqd700 // 1991 Apple Macintosh Quadra 700
@source:apple/macquadra800.cpp
macqd800 // 1993 Apple Macintosh Quadra 800
macct610 // 1993 Apple Macintosh Centris 610
macct650 // 1993 Apple Macintosh Centris 650
macqd610 // 1993 Apple Macintosh Quadra 610
macqd650 // 1993 Apple Macintosh Quadra 650
@source:apple/newton.cpp
newtnotp
newtonmp