mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
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:
parent
4b1257e2f0
commit
a381012159
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
112
src/mame/apple/djmemc.cpp
Normal 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
58
src/mame/apple/djmemc.h
Normal 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
626
src/mame/apple/iosb.cpp
Normal 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
128
src/mame/apple/iosb.h
Normal 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
|
306
src/mame/apple/macquadra800.cpp
Normal file
306
src/mame/apple/macquadra800.cpp
Normal 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)
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user