mirror of
https://github.com/holub/mame
synced 2025-06-05 20:33:45 +03:00
apple/dafb.cpp: New DAFB device for the Quadra 700/900/950, including video and "turbo SCSI". [R. Belmont]
This commit is contained in:
parent
445bf3e6f4
commit
578bef8bae
943
src/mame/apple/dafb.cpp
Normal file
943
src/mame/apple/dafb.cpp
Normal file
@ -0,0 +1,943 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
/*
|
||||
Apple DAFB and DAFB II video (343S0128-01 for DAFB, 343S0128-A for DAFB II)
|
||||
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
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
----------------------------------------------------------------------------------------------------------------
|
||||
|
||||
Apple assigns 3 pins for monitor IDs. These allow 8 possible codes:
|
||||
|
||||
000 - color 2-Page Display (21")
|
||||
001 - monochrome Full Page display (15")
|
||||
010 - color 512x384 (12")
|
||||
011 - monochrome 2 Page display (21")
|
||||
100 - NTSC
|
||||
101 - color Full Page display (15")
|
||||
110 - High-Resolution Color (13" 640x480) or "type 6" extended codes
|
||||
111 - No monitor connected or "type 7" extended codes
|
||||
|
||||
For extended codes, you drive one of the 3 pins at a time and read the 2
|
||||
undriven pins. See http://support.apple.com/kb/TA21618?viewlocale=en_US
|
||||
for details.
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
#include "dafb.h"
|
||||
|
||||
#define LOG_SWATCH (1U << 1)
|
||||
#define LOG_CLOCKGEN (1U << 2)
|
||||
#define LOG_MONSENSE (1U << 3)
|
||||
#define LOG_AC842 (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")
|
||||
|
||||
//-------------------------------------------------
|
||||
// ADDRESS_MAP
|
||||
//-------------------------------------------------
|
||||
|
||||
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(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_dafb_version(1),
|
||||
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_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)
|
||||
{
|
||||
std::fill(std::begin(m_horizontal_params), std::end(m_horizontal_params), 0);
|
||||
std::fill(std::begin(m_vertical_params), std::end(m_vertical_params), 0);
|
||||
m_scsi_read_cycles[0] = m_scsi_read_cycles[1] = 3;
|
||||
m_scsi_write_cycles[0] = m_scsi_write_cycles[1] = 3,
|
||||
m_scsi_dma_read_cycles[0] = m_scsi_dma_read_cycles[1] = 3;
|
||||
m_scsi_dma_write_cycles[0] = m_scsi_dma_write_cycles[1] = 3;
|
||||
}
|
||||
|
||||
dafb_device::dafb_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
dafb_base(mconfig, DAFB, tag, owner, clock),
|
||||
m_maincpu(*this, finder_base::DUMMY_TAG)
|
||||
{
|
||||
m_drq[0] = m_drq[1] = 0;
|
||||
m_ncr[0] = m_ncr[1] = nullptr;
|
||||
}
|
||||
|
||||
void dafb_base::device_start()
|
||||
{
|
||||
m_vram = std::make_unique<u32[]>(VRAM_SIZE);
|
||||
|
||||
m_vbl_timer = timer_alloc(FUNC(dafb_base::vbl_tick), this);
|
||||
m_cursor_timer = timer_alloc(FUNC(dafb_base::cursor_tick), this);
|
||||
|
||||
m_vbl_timer->adjust(attotime::never);
|
||||
m_cursor_timer->adjust(attotime::never);
|
||||
|
||||
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));
|
||||
save_item(NAME(m_swatch_mode));
|
||||
save_item(NAME(m_pal_address));
|
||||
save_item(NAME(m_pal_idx));
|
||||
save_item(NAME(m_ac842_pbctrl));
|
||||
save_item(NAME(m_cursor_line));
|
||||
save_item(NAME(m_hres));
|
||||
save_item(NAME(m_vres));
|
||||
save_item(NAME(m_htotal));
|
||||
save_item(NAME(m_vtotal));
|
||||
save_item(NAME(m_pixel_clock));
|
||||
save_item(NAME(m_horizontal_params));
|
||||
save_item(NAME(m_vertical_params));
|
||||
save_item(NAME(m_dp8531_regs));
|
||||
save_item(NAME(m_test));
|
||||
save_item(NAME(m_config));
|
||||
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);
|
||||
|
||||
machine().save().register_postload(save_prepost_delegate(FUNC(dafb_base::recalc_mode), this));
|
||||
}
|
||||
|
||||
void dafb_base::device_reset()
|
||||
{
|
||||
}
|
||||
|
||||
void dafb_base::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
||||
// dot clock, htotal, hstart, hend, vtotal, vstart, vend
|
||||
m_screen->set_raw(31334400, 896, 0, 640, 525, 0, 480);
|
||||
m_screen->set_screen_update(FUNC(dafb_base::screen_update));
|
||||
|
||||
PALETTE(config, m_palette).set_entries(256);
|
||||
}
|
||||
|
||||
static constexpr u8 ext(u8 bc, u8 ac, u8 ab)
|
||||
{
|
||||
return 0x40 | (bc << 4) | (ac << 2) | ab;
|
||||
}
|
||||
|
||||
static INPUT_PORTS_START(monitor_config)
|
||||
PORT_START("monitor")
|
||||
PORT_CONFNAME(0x7f, 6, "Monitor type")
|
||||
PORT_CONFSETTING(0x00, u8"Mac 21\" Color Display (1152\u00d7870)") // "RGB 2 Page" or "Kong"
|
||||
PORT_CONFSETTING(0x01, u8"Mac Portrait Display (B&W 15\" 640\u00d7870)") // "Full Page" or "Portrait"
|
||||
PORT_CONFSETTING(0x02, u8"Mac RGB Display (12\" 512\u00d7384)") // "Rubik" (modified IIgs AppleColor RGB)
|
||||
PORT_CONFSETTING(0x03, u8"Mac Two-Page Display (B&W 21\" 1152\u00d7870)") // "2 Page"
|
||||
PORT_CONFSETTING(0x06, u8"Mac Hi-Res Display (12-14\" 640\u00d7480)") // "High Res"
|
||||
PORT_CONFSETTING(ext(0, 0, 0), "PAL Encoder (640\u00d7480, 768\u00d7576)")
|
||||
PORT_CONFSETTING(ext(1, 1, 0), "NTSC Encoder (512\u00d7384, 640\u00d7480)")
|
||||
PORT_CONFSETTING(ext(1, 1, 3), "640x480 VGA")
|
||||
PORT_CONFSETTING(ext(2, 3, 1), "832x624 16\" RGB") // "Goldfish" or "16 inch RGB"
|
||||
PORT_CONFSETTING(ext(3, 0, 0), "PAL (640\u00d7480, 768\u00d7576)")
|
||||
INPUT_PORTS_END
|
||||
|
||||
ioport_constructor dafb_base::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME(monitor_config);
|
||||
}
|
||||
|
||||
u32 dafb_base::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
auto const vram8 = util::big_endian_cast<u8 const>(&m_vram[0]) + m_base;
|
||||
const pen_t *pens = m_palette->pens();
|
||||
|
||||
if (m_swatch_mode & 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if convolution is enabled, the stride is fixed at 1024
|
||||
const u32 stride = BIT(m_config, 3) ? 1024 : m_stride;
|
||||
|
||||
switch (m_mode)
|
||||
{
|
||||
case 0: // 1bpp
|
||||
{
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < m_hres/8; x++)
|
||||
{
|
||||
u8 const pixels = vram8[(y * stride) + x];
|
||||
|
||||
*scanline++ = pens[(pixels>>7)&1];
|
||||
*scanline++ = pens[(pixels>>6)&1];
|
||||
*scanline++ = pens[(pixels>>5)&1];
|
||||
*scanline++ = pens[(pixels>>4)&1];
|
||||
*scanline++ = pens[(pixels>>3)&1];
|
||||
*scanline++ = pens[(pixels>>2)&1];
|
||||
*scanline++ = pens[(pixels>>1)&1];
|
||||
*scanline++ = pens[(pixels&1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // 2bpp
|
||||
{
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < m_hres/4; x++)
|
||||
{
|
||||
u8 const pixels = vram8[(y * stride) + x];
|
||||
|
||||
*scanline++ = pens[((pixels>>6)&3)];
|
||||
*scanline++ = pens[((pixels>>4)&3)];
|
||||
*scanline++ = pens[((pixels>>2)&3)];
|
||||
*scanline++ = pens[(pixels&3)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 4bpp
|
||||
{
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < m_hres/2; x++)
|
||||
{
|
||||
u8 const pixels = vram8[(y * stride) + x];
|
||||
|
||||
*scanline++ = pens[(pixels>>4)];
|
||||
*scanline++ = pens[(pixels&0xf)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // 8bpp
|
||||
{
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < m_hres; x++)
|
||||
{
|
||||
u8 const pixels = vram8[(y * stride) + x];
|
||||
*scanline++ = pens[pixels];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // 24 bpp
|
||||
for (int y = 0; y < m_vres; y++)
|
||||
{
|
||||
u32 *scanline = &bitmap.pix(y);
|
||||
u32 const *base = &m_vram[(y * (stride/4)) + (m_base/4)];
|
||||
for (int x = 0; x < m_hres; x++)
|
||||
{
|
||||
*scanline++ = *base++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 dafb_base::dafb_r(offs_t offset)
|
||||
{
|
||||
switch (offset<<2)
|
||||
{
|
||||
case 0x1c: // inverse of monitor sense
|
||||
{
|
||||
u8 mon = m_monitor_config->read();
|
||||
u8 res;
|
||||
LOGMASKED(LOG_MONSENSE, "mon = %02x, m_monitor_id = %02x\n", mon, m_monitor_id);
|
||||
if (mon & 0x40)
|
||||
{
|
||||
res = 7;
|
||||
if (m_monitor_id == 0x4)
|
||||
{
|
||||
res &= 4 | (BIT(mon, 5) << 1) | BIT(mon, 4);
|
||||
}
|
||||
if (m_monitor_id == 0x2)
|
||||
{
|
||||
res &= (BIT(mon, 3) << 2) | 2 | BIT(mon, 2);
|
||||
}
|
||||
if (m_monitor_id == 0x1)
|
||||
{
|
||||
res &= (BIT(mon, 1) << 2) | (BIT(mon, 0) << 1) | 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mon;
|
||||
}
|
||||
|
||||
LOGMASKED(LOG_MONSENSE, "sense result = %x\n", res);
|
||||
return res ^ 7; // return value is the inverse of the sense bits
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x24: // SCSI 539x #1 status
|
||||
return m_scsi_ctrl[0] | (m_drq[0] << 9);
|
||||
|
||||
case 0x28: // SCSI 539x #2 status
|
||||
return m_scsi_ctrl[1] | (m_drq[1] << 9);
|
||||
|
||||
case 0x2c: // test / version (0 = original, 1 = NTSC and PAL fix, 2 = discrete DAFB II, 3 = MEMC/MEMCjr integrated DAFB cell)
|
||||
return (m_test & 0x1ff) | (2<<9);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dafb_base::dafb_w(offs_t offset, u32 data)
|
||||
{
|
||||
switch (offset << 2)
|
||||
{
|
||||
case 0: // bits 20-9 of base
|
||||
m_base &= 0x1e0;
|
||||
m_base |= (data & 0xfff) << 9;
|
||||
LOG("baseA: wrote %08x => %08x\n", data, m_base);
|
||||
break;
|
||||
|
||||
case 4: // bits 8-5 of base
|
||||
m_base &= ~0x1e0;
|
||||
m_base |= (data & 0xf) << 5;
|
||||
LOG("baseB wrote %08x => %08x\n", data, m_base);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
m_stride = data<<2; // stride in DWORDs
|
||||
LOG("Stride = %d\n", m_stride);
|
||||
break;
|
||||
|
||||
case 0xc: // timing control
|
||||
m_timing_control = data;
|
||||
LOG("Timing control = %08x\n", data);
|
||||
break;
|
||||
|
||||
case 0x10: // configuration
|
||||
LOG("DAFB config = %08x\n", data);
|
||||
m_config = data;
|
||||
break;
|
||||
|
||||
|
||||
case 0x14: // block write control
|
||||
LOG("Block write control = %08x\n", data);
|
||||
m_block_control = data;
|
||||
break;
|
||||
|
||||
case 0x1c: // drive monitor sense lines. 0=drive to value in bit 0 of TEST, 1=tri-state
|
||||
m_monitor_id = (data & 0x7) ^ 7;
|
||||
LOGMASKED(LOG_MONSENSE, "%x to sense drive\n", data & 0xf);
|
||||
break;
|
||||
|
||||
/*
|
||||
SCSI bus 1 control:
|
||||
bit 0 = SCSI register read is 6 clocks (if neither bit 0 or 1 are set, 3 clocks?)
|
||||
bit 1 = SCSI register read is 4 clocks
|
||||
bit 2 = SCSI register write is 3 clocks (else what?)
|
||||
bit 3 = SCSI pseudo-DMA read is 3 clocks (else what?)
|
||||
bit 4 = SCSI pseudo-DMA write is 5 clocks
|
||||
bit 5 = SCSI pseudo-DMA write is 3 clocks
|
||||
bit 6 = CS PW Check (?)
|
||||
bit 7 = DRQ Check Read (PDMA reads wait if DRQ isn't set and bus error on timeout)
|
||||
bit 8 = DRQ Check Write
|
||||
bit 9 = DREQ status read
|
||||
*/
|
||||
case 0x24:
|
||||
m_scsi_ctrl[0] = data;
|
||||
if (BIT(data, 0))
|
||||
{
|
||||
m_scsi_read_cycles[0] = 6;
|
||||
}
|
||||
else if (BIT(data, 1))
|
||||
{
|
||||
m_scsi_read_cycles[0] = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scsi_read_cycles[0] = 3;
|
||||
}
|
||||
|
||||
if (BIT(data, 2))
|
||||
{
|
||||
m_scsi_write_cycles[0] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scsi_write_cycles[0] = 4;
|
||||
}
|
||||
|
||||
if (BIT(data, 3))
|
||||
{
|
||||
m_scsi_dma_read_cycles[0] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scsi_dma_read_cycles[0] = 4;
|
||||
}
|
||||
|
||||
if (BIT(data, 4))
|
||||
{
|
||||
m_scsi_dma_write_cycles[0] = 5;
|
||||
}
|
||||
else if (BIT(data, 5))
|
||||
{
|
||||
m_scsi_dma_write_cycles[0] = 3;
|
||||
}
|
||||
LOGMASKED(LOG_TURBOSCSI, "SCSI bus 1 timings: R %d W %d DMAR %d DMAW %d\n", m_scsi_read_cycles[0], m_scsi_write_cycles[0], m_scsi_dma_read_cycles[0], m_scsi_dma_write_cycles[0]);
|
||||
break;
|
||||
|
||||
// SCSI bus 2 control, same definitions as above
|
||||
case 0x28:
|
||||
m_scsi_ctrl[1] = data;
|
||||
if (BIT(data, 0))
|
||||
{
|
||||
m_scsi_read_cycles[1] = 6;
|
||||
}
|
||||
else if (BIT(data, 1))
|
||||
{
|
||||
m_scsi_read_cycles[1] = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scsi_read_cycles[1] = 3;
|
||||
}
|
||||
|
||||
if (BIT(data, 2))
|
||||
{
|
||||
m_scsi_write_cycles[1] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scsi_write_cycles[1] = 4;
|
||||
}
|
||||
|
||||
if (BIT(data, 3))
|
||||
{
|
||||
m_scsi_dma_read_cycles[1] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_scsi_dma_read_cycles[1] = 4;
|
||||
}
|
||||
|
||||
if (BIT(data, 4))
|
||||
{
|
||||
m_scsi_dma_write_cycles[1] = 5;
|
||||
}
|
||||
else if (BIT(data, 5))
|
||||
{
|
||||
m_scsi_dma_write_cycles[1] = 3;
|
||||
}
|
||||
LOGMASKED(LOG_TURBOSCSI, "SCSI bus 2 timings: R %d W %d DMAR %d DMAW %d\n", m_scsi_read_cycles[1], m_scsi_write_cycles[1], m_scsi_dma_read_cycles[1], m_scsi_dma_write_cycles[1]);
|
||||
break;
|
||||
|
||||
// TEST register. Bit 0 is supposedly the value to drive on the monitor sense pins, but that's not what
|
||||
// the code does on the Q700.
|
||||
case 0x2c:
|
||||
LOG("%08x to TEST\n", data);
|
||||
m_test = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 dafb_base::swatch_r(offs_t offset)
|
||||
{
|
||||
switch (offset << 2)
|
||||
{
|
||||
case 0x8: // IRQ/VBL status
|
||||
return m_int_status;
|
||||
|
||||
case 0xc: // clear cursor scanline int
|
||||
m_int_status &= ~4;
|
||||
recalc_ints();
|
||||
break;
|
||||
|
||||
case 0x14: // clear VBL int
|
||||
m_int_status &= ~1;
|
||||
recalc_ints();
|
||||
break;
|
||||
|
||||
case 0x20: // unused register, used by the driver to stash data
|
||||
return m_swatch_test;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dafb_base::swatch_w(offs_t offset, u32 data)
|
||||
{
|
||||
switch (offset << 2)
|
||||
{
|
||||
case 0x0: // Swatch mode
|
||||
m_swatch_mode = data;
|
||||
break;
|
||||
|
||||
case 0x4:
|
||||
if (data & 1) // VBL enable
|
||||
{
|
||||
m_vbl_timer->adjust(m_screen->time_until_pos(480, 0), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vbl_timer->adjust(attotime::never);
|
||||
m_int_status &= ~1;
|
||||
recalc_ints();
|
||||
}
|
||||
|
||||
if (data & 2) // aux scanline interrupt enable
|
||||
{
|
||||
fatalerror("DAFB: Aux scanline interrupt enable not supported!\n");
|
||||
}
|
||||
|
||||
if (data & 4) // cursor scanline interrupt enable
|
||||
{
|
||||
m_cursor_timer->adjust(m_screen->time_until_pos(m_cursor_line, 0), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cursor_timer->adjust(attotime::never);
|
||||
m_int_status &= ~4;
|
||||
recalc_ints();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xc: // clear cursor scanline int
|
||||
m_int_status &= ~4;
|
||||
recalc_ints();
|
||||
break;
|
||||
|
||||
case 0x14: // clear VBL int
|
||||
m_int_status &= ~1;
|
||||
recalc_ints();
|
||||
break;
|
||||
|
||||
case 0x18: // cursor IRQ line
|
||||
m_cursor_line = data;
|
||||
break;
|
||||
|
||||
case 0x1c: // animation IRQ line
|
||||
m_anim_line = data;
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
m_swatch_test = data;
|
||||
break;
|
||||
|
||||
case 0x24: // HSERR - location of horizontal serration pulse
|
||||
case 0x28: // HLFLN - Half-line point where equalizing pulses or serrations fall
|
||||
case 0x2c: // HEQ - Horizontal equalizing pulse
|
||||
case 0x30: // HSP - Horizontal sync pulse
|
||||
case 0x34: // HBWAY - Horizontal breezeway
|
||||
case 0x38: // HBRST - Horizontal burst (where the NTSC colorburst would happen if this wasn't RGB)
|
||||
case 0x3c: // HBP - Horizontal back porch
|
||||
case 0x40: // HAL - Horizontal active line (start of active display area)
|
||||
case 0x44: // HFP - Horizontal front porch (end of active display area)
|
||||
case 0x48: // HPIX - Horizontal pixels - total # of pixel locations in a line minus 2
|
||||
LOGMASKED(LOG_SWATCH, "%d to horiz param offset %02x\n", data, offset);
|
||||
m_horizontal_params[offset - (0x24 / 4)] = data;
|
||||
break;
|
||||
|
||||
case 0x4c: // VHLINE - Vertical half-lines, the total # of half-lines in a field (odd for interlaced, even for NI)
|
||||
case 0x50: // VSYNC - Vertical sync
|
||||
case 0x54: // VBPEQ - Vertical Back Porch Equalization
|
||||
case 0x58: // VBP - Vertical Back Porch (start of active display area)
|
||||
case 0x5c: // VAL - Vertical Active Lines (end of active display area)
|
||||
case 0x60: // VFP - Vertical Front Porch
|
||||
case 0x64: // VFPEQ - Vertical Front Porch Equalization
|
||||
LOGMASKED(LOG_SWATCH, "%d to vertical param offset %02x\n", data, offset);
|
||||
m_vertical_params[offset - (0x4c / 4)] = data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 dafb_base::ac842_r(offs_t offset)
|
||||
{
|
||||
switch (offset << 2)
|
||||
{
|
||||
case 0:
|
||||
m_pal_idx = 0;
|
||||
return m_pal_address;
|
||||
|
||||
case 0x10:
|
||||
{
|
||||
pen_t entry = m_palette->pen(m_pal_address);
|
||||
m_pal_idx++;
|
||||
switch (m_pal_idx - 1)
|
||||
{
|
||||
case 0:
|
||||
return (entry >> 16) & 0xff;
|
||||
case 1:
|
||||
return (entry >> 8) & 0xff;
|
||||
case 2:
|
||||
return entry & 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
return m_ac842_pbctrl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dafb_base::ac842_w(offs_t offset, u32 data)
|
||||
{
|
||||
switch (offset << 2)
|
||||
{
|
||||
case 0:
|
||||
m_pal_address = data & 0xff;
|
||||
m_pal_idx = 0;
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
if ((m_monitor_config->read() == 1) || (m_monitor_config->read() == 3))
|
||||
{
|
||||
// monochrome monitors put info only on the blue channel
|
||||
if (m_pal_idx == 2)
|
||||
{
|
||||
m_palette->set_pen_red_level(m_pal_address, data & 0xff);
|
||||
m_palette->set_pen_green_level(m_pal_address, data & 0xff);
|
||||
m_palette->set_pen_blue_level(m_pal_address, data & 0xff);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (m_pal_idx)
|
||||
{
|
||||
case 0:
|
||||
m_palette->set_pen_red_level(m_pal_address, data & 0xff);
|
||||
break;
|
||||
case 1:
|
||||
m_palette->set_pen_green_level(m_pal_address, data & 0xff);
|
||||
break;
|
||||
case 2:
|
||||
m_palette->set_pen_blue_level(m_pal_address, data & 0xff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_pal_idx++;
|
||||
if (m_pal_idx == 3)
|
||||
{
|
||||
m_pal_idx = 0;
|
||||
m_pal_address++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
m_ac842_pbctrl = data;
|
||||
LOGMASKED(LOG_AC842, "%02x to AC842 pixel bus control, & 0x1c = %02x\n", data, data & 0x1c);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void dafb_base::recalc_mode()
|
||||
{
|
||||
m_htotal = m_horizontal_params[HPIX];
|
||||
m_vtotal = m_vertical_params[VFPEQ] >> 1;
|
||||
|
||||
if ((m_htotal > 0) && (m_vtotal > 0))
|
||||
{
|
||||
m_hres = m_horizontal_params[HFP] - m_horizontal_params[HAL];
|
||||
m_vres = (m_vertical_params[VFP] >> 1) - (m_vertical_params[VAL] >> 1); // these are in half-line units for interlace
|
||||
|
||||
// Quadra 700 programs the wrong base for the 512x384 mode and is off-by-1 on the vertical res.
|
||||
// Maybe that monitor wasn't really intended to be supported?
|
||||
if (m_hres == 512)
|
||||
{
|
||||
m_base = 0x1000;
|
||||
m_vres = 384;
|
||||
}
|
||||
|
||||
const int clockdiv = 1 << ((m_ac842_pbctrl & 0x60) >> 5);
|
||||
LOGMASKED(LOG_SWATCH, "RAW hres %d vres %d htotal %d vtotal %d (clockdiv %d conv %d)\n", m_hres, m_vres, m_htotal, m_vtotal, clockdiv, BIT(m_config, 3));
|
||||
|
||||
// If convolution is active, divide the horiz. res and stride by the clock divider.
|
||||
// If it's not, multiply the horiz. res by the clockdiv.
|
||||
if (BIT(m_config, 3))
|
||||
{
|
||||
m_hres /= clockdiv;
|
||||
m_stride /= clockdiv;
|
||||
|
||||
// All modes with convolution enabled on the Q700 overstate the horizontal resolution by 23 for some reason.
|
||||
// The documentation, including the spreadsheet of mode examples, doesn't show that.
|
||||
// TODO: possibly working around a bug in early chip revisions? Check when DAFB-II machines are suported.
|
||||
m_hres -= 23;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hres *= clockdiv;
|
||||
}
|
||||
|
||||
// if we're interlaced, bump the vertical back to double
|
||||
if (BIT(m_config, 2))
|
||||
{
|
||||
m_vres <<= 1;
|
||||
m_vtotal <<= 1;
|
||||
}
|
||||
|
||||
LOGMASKED(LOG_SWATCH, "hres %d vres %d htotal %d vtotal %d\n", m_hres, m_vres, m_htotal, m_vtotal);
|
||||
if ((m_hres != 0) && (m_vres != 0))
|
||||
{
|
||||
rectangle visarea(0, m_hres - 1, 0, m_vres - 1);
|
||||
m_screen->configure(m_htotal, m_vtotal, visarea, attotime::from_ticks(m_htotal * m_vtotal, m_pixel_clock).as_attoseconds());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u32 dafb_base::clockgen_r(offs_t offset)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dafb_base::clockgen_w(offs_t offset, u32 data)
|
||||
{
|
||||
m_dp8531_regs[offset>>2] = data & 0xf;
|
||||
LOGMASKED(LOG_CLOCKGEN, "%s: Write %x to DP8531 at %d\n", tag(), data, offset);
|
||||
|
||||
if ((offset >> 2) == 15)
|
||||
{
|
||||
int r = m_dp8531_regs[6] << 8 | m_dp8531_regs[5] << 4 | m_dp8531_regs[4];
|
||||
int p = (1 << m_dp8531_regs[9]);
|
||||
|
||||
int n_modulus = m_dp8531_regs[3]<<12 | m_dp8531_regs[2]<<8 | m_dp8531_regs[1]<<4 | m_dp8531_regs[0];
|
||||
int a = (n_modulus & 0x1f) ^ 0x1f; // the inverse of the lowest 5 bits of n_modulus
|
||||
int b = (n_modulus & 0xffe0) >> 5; // the top 11 bits of n_modulus
|
||||
|
||||
a = std::min(a, b);
|
||||
b = std::max(b, 2);
|
||||
|
||||
// N = 32(B - A) + 31(1 + A)
|
||||
int n = (32 * (b - a)) + (31 * (1 + a));
|
||||
int vco = ((20'000'000/r) * n);
|
||||
m_pixel_clock = vco / p;
|
||||
|
||||
LOGMASKED(LOG_CLOCKGEN, "VCO %d, PCLK %d\n", vco, m_pixel_clock);
|
||||
}
|
||||
}
|
||||
|
||||
u32 dafb_base::vram_r(offs_t offset)
|
||||
{
|
||||
return m_vram[offset];
|
||||
}
|
||||
|
||||
void dafb_base::vram_w(offs_t offset, u32 data, u32 mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_vram[offset]);
|
||||
}
|
||||
|
||||
void dafb_base::recalc_ints()
|
||||
{
|
||||
if (m_int_status != 0)
|
||||
{
|
||||
m_irq(ASSERT_LINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_irq(CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(dafb_base::vbl_tick)
|
||||
{
|
||||
m_int_status |= 1;
|
||||
recalc_ints();
|
||||
|
||||
m_vbl_timer->adjust(m_screen->time_until_pos(480, 0), 0);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(dafb_base::cursor_tick)
|
||||
{
|
||||
m_int_status |= 4;
|
||||
recalc_ints();
|
||||
|
||||
m_cursor_timer->adjust(m_screen->time_until_pos(m_cursor_line, 0), 0);
|
||||
}
|
||||
|
||||
// ************************************************************************
|
||||
// dafb_device overrides/additions
|
||||
// ************************************************************************
|
||||
void dafb_device::device_start()
|
||||
{
|
||||
dafb_base::device_start();
|
||||
m_maincpu->set_emmu_enable(true);
|
||||
}
|
||||
|
||||
template <int bus>
|
||||
u8 dafb_device::turboscsi_r(offs_t offset)
|
||||
{
|
||||
if (!machine().side_effects_disabled())
|
||||
{
|
||||
m_maincpu->adjust_icount(-m_scsi_read_cycles[bus]);
|
||||
}
|
||||
return m_ncr[bus]->read(offset>>4);
|
||||
}
|
||||
|
||||
template u8 dafb_device::turboscsi_r<0>(offs_t offset);
|
||||
template u8 dafb_device::turboscsi_r<1>(offs_t offset);
|
||||
|
||||
template <int bus>
|
||||
void dafb_device::turboscsi_w(offs_t offset, u8 data)
|
||||
{
|
||||
m_maincpu->adjust_icount(-m_scsi_write_cycles[bus]);
|
||||
m_ncr[bus]->write(offset>>4, data);
|
||||
}
|
||||
|
||||
template void dafb_device::turboscsi_w<0>(offs_t offset, u8 data);
|
||||
template void dafb_device::turboscsi_w<1>(offs_t offset, u8 data);
|
||||
|
||||
template <int bus>
|
||||
u16 dafb_device::turboscsi_dma_r(offs_t offset, u16 mem_mask)
|
||||
{
|
||||
if (!machine().side_effects_disabled() && BIT(offset << 1, 18))
|
||||
{
|
||||
m_maincpu->adjust_icount(-m_scsi_dma_read_cycles[bus]);
|
||||
}
|
||||
|
||||
if (BIT(m_scsi_ctrl[bus], 7))
|
||||
{
|
||||
if (!m_drq[bus])
|
||||
{
|
||||
// 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 == 0xffff)
|
||||
{
|
||||
return m_ncr[bus]->dma16_swap_r();
|
||||
}
|
||||
else if (ACCESSING_BITS_0_7)
|
||||
{
|
||||
return m_ncr[bus]->dma_r();
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_ncr[bus]->dma_r()<<8;
|
||||
}
|
||||
}
|
||||
|
||||
template u16 dafb_device::turboscsi_dma_r<0>(offs_t offset, u16 mem_mask);
|
||||
template u16 dafb_device::turboscsi_dma_r<1>(offs_t offset, u16 mem_mask);
|
||||
|
||||
template <int bus>
|
||||
void dafb_device::turboscsi_dma_w(offs_t offset, u16 data, u16 mem_mask)
|
||||
{
|
||||
if (!machine().side_effects_disabled() && BIT(offset << 1, 18))
|
||||
{
|
||||
m_maincpu->adjust_icount(-m_scsi_dma_write_cycles[bus]);
|
||||
}
|
||||
|
||||
LOGMASKED(LOG_TURBOSCSI, "dma_w %04x (mask %04x)\n", data & mem_mask, mem_mask);
|
||||
|
||||
if (BIT(m_scsi_ctrl[bus], 8))
|
||||
{
|
||||
if (!m_drq[bus])
|
||||
{
|
||||
m_maincpu->restart_this_instruction();
|
||||
m_maincpu->spin_until_time(attotime::from_usec(50));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mem_mask == 0xffff)
|
||||
{
|
||||
m_ncr[bus]->dma16_swap_w(data);
|
||||
}
|
||||
else if (ACCESSING_BITS_0_7)
|
||||
{
|
||||
m_ncr[bus]->dma_w(data & 0xff);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ncr[bus]->dma_w(data >> 8);
|
||||
}
|
||||
}
|
||||
else // no DRQ safety check, just blindly push to the 53c9x
|
||||
{
|
||||
if (mem_mask == 0xffff)
|
||||
{
|
||||
m_ncr[bus]->dma16_swap_w(data);
|
||||
}
|
||||
else if (ACCESSING_BITS_0_7)
|
||||
{
|
||||
m_ncr[bus]->dma_w(data & 0xff);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ncr[bus]->dma_w(data >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template void dafb_device::turboscsi_dma_w<0>(offs_t offset, u16 data, u16 mem_mask);
|
||||
template void dafb_device::turboscsi_dma_w<1>(offs_t offset, u16 data, u16 mem_mask);
|
||||
|
||||
template <int bus>
|
||||
void dafb_device::turboscsi_drq_w(int state)
|
||||
{
|
||||
LOGMASKED(LOG_TURBOSCSI, "Bus %d DRQ %d (was %d)\n", bus + 1, state, m_drq[bus]);
|
||||
m_drq[bus] = state;
|
||||
}
|
||||
|
||||
template void dafb_device::turboscsi_drq_w<0>(int state);
|
||||
template void dafb_device::turboscsi_drq_w<1>(int state);
|
128
src/mame/apple/dafb.h
Normal file
128
src/mame/apple/dafb.h
Normal file
@ -0,0 +1,128 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
|
||||
#ifndef MAME_APPLE_DAFB_H
|
||||
#define MAME_APPLE_DAFB_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cpu/m68000/m68040.h"
|
||||
#include "machine/ncr53c90.h"
|
||||
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
|
||||
class dafb_base : public device_t
|
||||
{
|
||||
public:
|
||||
dafb_base(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
|
||||
virtual ~dafb_base() = default;
|
||||
|
||||
void map(address_map &map);
|
||||
|
||||
u32 vram_r(offs_t offset);
|
||||
void vram_w(offs_t offset, u32 data, u32 mem_mask);
|
||||
|
||||
auto dafb_irq() { return m_irq.bind(); }
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
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];
|
||||
int m_dafb_version;
|
||||
|
||||
private:
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<palette_device> m_palette;
|
||||
required_ioport m_monitor_config;
|
||||
devcb_write_line m_irq;
|
||||
|
||||
enum
|
||||
{
|
||||
HSERR = 0,
|
||||
HLFLN,
|
||||
HEQ,
|
||||
HSP,
|
||||
HBWAY,
|
||||
HBRST,
|
||||
HBP,
|
||||
HAL,
|
||||
HFP,
|
||||
HPIX
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VHLINE = 0,
|
||||
VSYNC,
|
||||
VBPEQ,
|
||||
VBP,
|
||||
VAL,
|
||||
VFP,
|
||||
VFPEQ
|
||||
};
|
||||
|
||||
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;
|
||||
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);
|
||||
TIMER_CALLBACK_MEMBER(cursor_tick);
|
||||
};
|
||||
|
||||
// Discrete DAFB: Quadra 700 & 900, includes "TurboSCSI"
|
||||
class dafb_device: public dafb_base
|
||||
{
|
||||
public:
|
||||
dafb_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
|
||||
|
||||
template <typename... T> void set_maincpu_tag(T &&... args) { m_maincpu.set_tag(std::forward<T>(args)...); }
|
||||
|
||||
void set_turboscsi1_device(ncr53c94_device *device) { m_ncr[0] = device; }
|
||||
void set_turboscsi2_device(ncr53c94_device *device) { m_ncr[1] = device; }
|
||||
|
||||
template <int bus> void turboscsi_drq_w(int state);
|
||||
|
||||
template <int bus> u8 turboscsi_r(offs_t offset);
|
||||
template <int bus> void turboscsi_w(offs_t offset, u8 data);
|
||||
template <int bus> u16 turboscsi_dma_r(offs_t offset, u16 mem_mask);
|
||||
template <int bus> void turboscsi_dma_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
|
||||
protected:
|
||||
virtual void device_start() override;
|
||||
|
||||
private:
|
||||
required_device<m68000_musashi_device> m_maincpu;
|
||||
ncr53c94_device *m_ncr[2];
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(DAFB, dafb_device)
|
||||
|
||||
#endif /* MAME_APPLE_DAFB_H */
|
@ -9,9 +9,14 @@
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
//#define USE_ADBMODEM
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#ifdef USE_ADBMODEM
|
||||
#include "adbmodem.h"
|
||||
#endif
|
||||
#include "dafb.h"
|
||||
#include "macadb.h"
|
||||
#include "macrtc.h"
|
||||
#include "mactoolbox.h"
|
||||
@ -31,8 +36,6 @@
|
||||
#include "machine/z80scc.h"
|
||||
#include "sound/asc.h"
|
||||
|
||||
#include "emupal.h"
|
||||
#include "screen.h"
|
||||
#include "softlist_dev.h"
|
||||
#include "speaker.h"
|
||||
|
||||
@ -42,7 +45,6 @@
|
||||
#define C15M (C32M/2)
|
||||
#define C7M (C32M/4)
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class macquadra_state : public driver_device
|
||||
@ -54,7 +56,9 @@ public:
|
||||
m_via1(*this, "via1"),
|
||||
m_via2(*this, "via2"),
|
||||
m_macadb(*this, "macadb"),
|
||||
#ifdef USE_ADBMODEM
|
||||
m_adbmodem(*this, "adbmodem"),
|
||||
#endif
|
||||
m_ram(*this, RAM_TAG),
|
||||
m_swim(*this, "fdc"),
|
||||
m_floppy(*this, "fdc:%d", 0U),
|
||||
@ -62,11 +66,9 @@ public:
|
||||
m_scsibus1(*this, "scsi1"),
|
||||
m_ncr1(*this, "scsi1:7:ncr53c96"),
|
||||
m_sonic(*this, "sonic"),
|
||||
m_screen(*this, "screen"),
|
||||
m_palette(*this, "palette"),
|
||||
m_dafb(*this, "dafb"),
|
||||
m_easc(*this, "easc"),
|
||||
m_scc(*this, "scc"),
|
||||
m_vram(*this, "vram"),
|
||||
m_cur_floppy(nullptr),
|
||||
m_hdsel(0)
|
||||
{
|
||||
@ -81,7 +83,9 @@ private:
|
||||
required_device<m68040_device> m_maincpu;
|
||||
required_device<via6522_device> m_via1, m_via2;
|
||||
required_device<macadb_device> m_macadb;
|
||||
#ifdef USE_ADBMODEM
|
||||
required_device<adbmodem_device> m_adbmodem;
|
||||
#endif
|
||||
required_device<ram_device> m_ram;
|
||||
required_device<applefdintf_device> m_swim;
|
||||
required_device_array<floppy_connector, 2> m_floppy;
|
||||
@ -89,39 +93,17 @@ private:
|
||||
required_device<nscsi_bus_device> m_scsibus1;
|
||||
required_device<ncr53c96_device> m_ncr1;
|
||||
required_device<dp83932c_device> m_sonic;
|
||||
required_device<screen_device> m_screen;
|
||||
required_device<palette_device> m_palette;
|
||||
required_device<dafb_device> m_dafb;
|
||||
required_device<asc_device> m_easc;
|
||||
required_device<z80scc_device> m_scc;
|
||||
required_shared_ptr<uint32_t> m_vram;
|
||||
|
||||
virtual void machine_start() override;
|
||||
virtual void machine_reset() override;
|
||||
virtual void video_start() override;
|
||||
virtual void video_reset() override;
|
||||
|
||||
uint32_t screen_update_dafb(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||
uint32_t dafb_r(offs_t offset, uint32_t mem_mask = ~0);
|
||||
void dafb_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
uint32_t dafb_dac_r(offs_t offset, uint32_t mem_mask = ~0);
|
||||
void dafb_dac_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0);
|
||||
void dafb_recalc_ints();
|
||||
|
||||
TIMER_CALLBACK_MEMBER(dafb_vbl_tick);
|
||||
TIMER_CALLBACK_MEMBER(dafb_cursor_tick);
|
||||
|
||||
u32 *m_ram_ptr = nullptr, *m_rom_ptr = nullptr;
|
||||
u32 m_ram_mask = 0, m_ram_size = 0, m_rom_size = 0;
|
||||
|
||||
emu_timer *m_vbl_timer = nullptr, *m_cursor_timer = nullptr, *m_6015_timer = nullptr;
|
||||
|
||||
uint16_t m_cursor_line = 0;
|
||||
uint16_t m_dafb_int_status = 0;
|
||||
int m_dafb_scsi1_drq = 0, m_dafb_scsi2_drq = 0;
|
||||
uint8_t m_dafb_mode = 0;
|
||||
uint32_t m_dafb_base = 0, m_dafb_stride = 0;
|
||||
uint32_t m_dafb_colors[3]{}, m_dafb_count = 0, m_dafb_clutoffs = 0, m_dafb_montype = 0, m_dafb_vbltime = 0;
|
||||
uint32_t m_dafb_palette[256]{};
|
||||
emu_timer *m_6015_timer = nullptr;
|
||||
|
||||
void nubus_irq_9_w(int state);
|
||||
void nubus_irq_a_w(int state);
|
||||
@ -129,32 +111,31 @@ private:
|
||||
void nubus_irq_c_w(int state);
|
||||
void nubus_irq_d_w(int state);
|
||||
void nubus_irq_e_w(int state);
|
||||
void nubus_slot_interrupt(uint8_t slot, uint32_t state);
|
||||
void nubus_slot_interrupt(u8 slot, u32 state);
|
||||
int m_via2_ca1_hack = 0, m_nubus_irq_state = 0;
|
||||
|
||||
void adb_irq_w(int state) { m_adb_irq_pending = state; }
|
||||
int m_adb_irq_pending = 0;
|
||||
|
||||
void dafb_irq_w(int state) { nubus_slot_interrupt(0xf, state);}
|
||||
|
||||
void irq_539x_1_w(int state);
|
||||
[[maybe_unused]] void irq_539x_2_w(int state);
|
||||
void drq_539x_1_w(int state);
|
||||
[[maybe_unused]] void drq_539x_2_w(int state);
|
||||
|
||||
floppy_image_device *m_cur_floppy = nullptr;
|
||||
int m_hdsel = 0;
|
||||
|
||||
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 mac_via_in_a();
|
||||
uint8_t mac_via_in_b();
|
||||
void mac_via_out_a(uint8_t data);
|
||||
void mac_via_out_b(uint8_t data);
|
||||
uint8_t mac_via2_in_a();
|
||||
uint8_t mac_via2_in_b();
|
||||
void mac_via2_out_a(uint8_t data);
|
||||
void mac_via2_out_b(uint8_t data);
|
||||
u16 mac_via_r(offs_t offset);
|
||||
void mac_via_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
u16 mac_via2_r(offs_t offset);
|
||||
void mac_via2_w(offs_t offset, u16 data, u16 mem_mask);
|
||||
u8 mac_via_in_a();
|
||||
u8 mac_via_in_b();
|
||||
void mac_via_out_a(u8 data);
|
||||
void mac_via_out_b(u8 data);
|
||||
u8 mac_via2_in_a();
|
||||
u8 mac_via2_in_b();
|
||||
void mac_via2_out_a(u8 data);
|
||||
void mac_via2_out_b(u8 data);
|
||||
void mac_via_sync();
|
||||
void field_interrupts();
|
||||
void mac_via_irq(int state);
|
||||
@ -162,21 +143,21 @@ private:
|
||||
TIMER_CALLBACK_MEMBER(mac_6015_tick);
|
||||
int m_via_interrupt = 0, m_via2_interrupt = 0, m_scc_interrupt = 0, m_last_taken_interrupt = 0;
|
||||
|
||||
uint32_t rom_switch_r(offs_t offset);
|
||||
u32 rom_switch_r(offs_t offset);
|
||||
bool m_overlay = 0;
|
||||
|
||||
uint16_t mac_scc_r(offs_t offset)
|
||||
u16 mac_scc_r(offs_t offset)
|
||||
{
|
||||
mac_via_sync();
|
||||
uint16_t result = m_scc->dc_ab_r(offset);
|
||||
u16 result = m_scc->dc_ab_r(offset);
|
||||
return (result << 8) | result;
|
||||
}
|
||||
void mac_scc_2_w(offs_t offset, uint16_t data) { mac_via_sync(); m_scc->dc_ab_w(offset, data >> 8); }
|
||||
void mac_scc_2_w(offs_t offset, u16 data) { mac_via_sync(); m_scc->dc_ab_w(offset, data >> 8); }
|
||||
|
||||
void phases_w(uint8_t phases);
|
||||
void devsel_w(uint8_t devsel);
|
||||
void phases_w(u8 phases);
|
||||
void devsel_w(u8 devsel);
|
||||
|
||||
uint16_t swim_r(offs_t offset, u16 mem_mask)
|
||||
u16 swim_r(offs_t offset, u16 mem_mask)
|
||||
{
|
||||
if (!machine().side_effects_disabled())
|
||||
{
|
||||
@ -193,11 +174,6 @@ private:
|
||||
else
|
||||
m_swim->write((offset >> 8) & 0xf, data>>8);
|
||||
}
|
||||
|
||||
uint8_t mac_5396_r(offs_t offset);
|
||||
void mac_5396_w(offs_t offset, uint8_t data);
|
||||
uint16_t mac_5396_dma_r(offs_t offset);
|
||||
void mac_5396_dma_w(offs_t offset, uint16_t data);
|
||||
};
|
||||
|
||||
void macquadra_state::field_interrupts()
|
||||
@ -232,6 +208,9 @@ void macquadra_state::field_interrupts()
|
||||
|
||||
void macquadra_state::machine_start()
|
||||
{
|
||||
m_dafb->set_turboscsi1_device(m_ncr1);
|
||||
m_dafb->set_turboscsi2_device(nullptr);
|
||||
|
||||
m_ram_ptr = (u32*)m_ram->pointer();
|
||||
m_ram_size = m_ram->size()>>1;
|
||||
m_ram_mask = m_ram_size - 1;
|
||||
@ -243,19 +222,6 @@ void macquadra_state::machine_start()
|
||||
m_6015_timer = timer_alloc(FUNC(macquadra_state::mac_6015_tick), this);
|
||||
m_6015_timer->adjust(attotime::never);
|
||||
|
||||
save_item(NAME(m_cursor_line));
|
||||
save_item(NAME(m_dafb_int_status));
|
||||
save_item(NAME(m_dafb_scsi1_drq));
|
||||
save_item(NAME(m_dafb_scsi2_drq));
|
||||
save_item(NAME(m_dafb_mode));
|
||||
save_item(NAME(m_dafb_base));
|
||||
save_item(NAME(m_dafb_stride));
|
||||
save_item(NAME(m_dafb_colors));
|
||||
save_item(NAME(m_dafb_count));
|
||||
save_item(NAME(m_dafb_clutoffs));
|
||||
save_item(NAME(m_dafb_montype));
|
||||
save_item(NAME(m_dafb_vbltime));
|
||||
save_item(NAME(m_dafb_palette));
|
||||
save_item(NAME(m_via2_ca1_hack));
|
||||
save_item(NAME(m_nubus_irq_state));
|
||||
save_item(NAME(m_adb_irq_pending));
|
||||
@ -294,10 +260,10 @@ void macquadra_state::init_macqd700()
|
||||
{
|
||||
}
|
||||
|
||||
void macquadra_state::nubus_slot_interrupt(uint8_t slot, uint32_t state)
|
||||
void macquadra_state::nubus_slot_interrupt(u8 slot, u32 state)
|
||||
{
|
||||
static const uint8_t masks[8] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
|
||||
uint8_t mask = 0xff;
|
||||
static const u8 masks[8] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };
|
||||
u8 mask = 0xff;
|
||||
|
||||
slot -= 9;
|
||||
|
||||
@ -334,312 +300,6 @@ void macquadra_state::nubus_irq_c_w(int state) { nubus_slot_interrupt(0xc, state
|
||||
void macquadra_state::nubus_irq_d_w(int state) { nubus_slot_interrupt(0xd, state); }
|
||||
void macquadra_state::nubus_irq_e_w(int state) { nubus_slot_interrupt(0xe, state); }
|
||||
|
||||
// DAFB: video for Quadra 700/900
|
||||
|
||||
void macquadra_state::dafb_recalc_ints()
|
||||
{
|
||||
if (m_dafb_int_status != 0)
|
||||
{
|
||||
nubus_slot_interrupt(0xf, ASSERT_LINE);
|
||||
}
|
||||
else
|
||||
{
|
||||
nubus_slot_interrupt(0xf, CLEAR_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(macquadra_state::dafb_vbl_tick)
|
||||
{
|
||||
m_dafb_int_status |= 1;
|
||||
dafb_recalc_ints();
|
||||
|
||||
m_vbl_timer->adjust(m_screen->time_until_pos(480, 0), 0);
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(macquadra_state::dafb_cursor_tick)
|
||||
{
|
||||
m_dafb_int_status |= 4;
|
||||
dafb_recalc_ints();
|
||||
|
||||
m_cursor_timer->adjust(m_screen->time_until_pos(m_cursor_line, 0), 0);
|
||||
}
|
||||
|
||||
void macquadra_state::video_start() // DAFB
|
||||
{
|
||||
m_vbl_timer = timer_alloc(FUNC(macquadra_state::dafb_vbl_tick), this);
|
||||
m_cursor_timer = timer_alloc(FUNC(macquadra_state::dafb_cursor_tick), this);
|
||||
|
||||
m_vbl_timer->adjust(attotime::never);
|
||||
m_cursor_timer->adjust(attotime::never);
|
||||
}
|
||||
|
||||
void macquadra_state::video_reset() // DAFB
|
||||
{
|
||||
m_dafb_count = 0;
|
||||
m_dafb_clutoffs = 0;
|
||||
m_dafb_montype = 6;
|
||||
m_dafb_vbltime = 0;
|
||||
m_dafb_int_status = 0;
|
||||
m_dafb_mode = 0;
|
||||
m_dafb_base = 0x1000;
|
||||
m_dafb_stride = 256*4;
|
||||
|
||||
memset(m_dafb_palette, 0, sizeof(m_dafb_palette));
|
||||
}
|
||||
|
||||
uint32_t macquadra_state::dafb_r(offs_t offset, uint32_t mem_mask)
|
||||
{
|
||||
// if (offset != 0x108/4) printf("DAFB: Read @ %x (mask %x PC=%x)\n", offset*4, mem_mask, m_maincpu->pc());
|
||||
|
||||
switch (offset<<2)
|
||||
{
|
||||
case 0x1c: // inverse of monitor sense
|
||||
return 7; // 21" color 2-page
|
||||
|
||||
case 0x24: // SCSI 539x #1 status
|
||||
return m_dafb_scsi1_drq<<9;
|
||||
|
||||
case 0x28: // SCSI 539x #2 status
|
||||
return m_dafb_scsi2_drq<<9;
|
||||
|
||||
case 0x108: // IRQ/VBL status
|
||||
return m_dafb_int_status;
|
||||
|
||||
case 0x10c: // clear cursor scanline int
|
||||
m_dafb_int_status &= ~4;
|
||||
dafb_recalc_ints();
|
||||
break;
|
||||
|
||||
case 0x114: // clear VBL int
|
||||
m_dafb_int_status &= ~1;
|
||||
dafb_recalc_ints();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void macquadra_state::dafb_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
// if (offset != 0x10c/4) printf("DAFB: Write %08x @ %x (mask %x PC=%x)\n", data, offset*4, mem_mask, m_maincpu->pc());
|
||||
|
||||
switch (offset<<2)
|
||||
{
|
||||
case 0: // bits 20-9 of base
|
||||
m_dafb_base &= 0x1ff;
|
||||
m_dafb_base |= (data & 0xffff) << 9;
|
||||
// printf("DAFB baseH: %x\n", m_dafb_base);
|
||||
break;
|
||||
|
||||
case 4: // bits 8-5 of base
|
||||
m_dafb_base &= ~0x1ff;
|
||||
m_dafb_base |= (data & 0xf) << 5;
|
||||
// printf("DAFB baseL: %x\n", m_dafb_base);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
m_dafb_stride = data<<2; // stride in DWORDs
|
||||
// printf("DAFB stride: %x %x\n", m_dafb_stride, data);
|
||||
break;
|
||||
|
||||
case 0x104:
|
||||
if (data & 1) // VBL enable
|
||||
{
|
||||
m_vbl_timer->adjust(m_screen->time_until_pos(480, 0), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_vbl_timer->adjust(attotime::never);
|
||||
m_dafb_int_status &= ~1;
|
||||
dafb_recalc_ints();
|
||||
}
|
||||
|
||||
if (data & 2) // aux scanline interrupt enable
|
||||
{
|
||||
fatalerror("DAFB: Aux scanline interrupt enable not supported!\n");
|
||||
}
|
||||
|
||||
if (data & 4) // cursor scanline interrupt enable
|
||||
{
|
||||
m_cursor_timer->adjust(m_screen->time_until_pos(m_cursor_line, 0), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cursor_timer->adjust(attotime::never);
|
||||
m_dafb_int_status &= ~4;
|
||||
dafb_recalc_ints();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10c: // clear cursor scanline int
|
||||
m_dafb_int_status &= ~4;
|
||||
dafb_recalc_ints();
|
||||
break;
|
||||
|
||||
case 0x114: // clear VBL int
|
||||
m_dafb_int_status &= ~1;
|
||||
dafb_recalc_ints();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t macquadra_state::dafb_dac_r(offs_t offset, uint32_t mem_mask)
|
||||
{
|
||||
// printf("DAFB: Read DAC @ %x (mask %x PC=%x)\n", offset*4, mem_mask, m_maincpu->pc());
|
||||
return 0;
|
||||
}
|
||||
|
||||
void macquadra_state::dafb_dac_w(offs_t offset, uint32_t data, uint32_t mem_mask)
|
||||
{
|
||||
// if ((offset > 0) && (offset != 0x10/4)) printf("DAFB: Write %08x to DAC @ %x (mask %x PC=%x)\n", data, offset*4, mem_mask, m_maincpu->pc());
|
||||
|
||||
switch (offset<<2)
|
||||
{
|
||||
case 0:
|
||||
m_dafb_clutoffs = data & 0xff;
|
||||
m_dafb_count = 0;
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
m_dafb_colors[m_dafb_count++] = data&0xff;
|
||||
|
||||
if (m_dafb_count == 3)
|
||||
{
|
||||
m_palette->set_pen_color(m_dafb_clutoffs, rgb_t(m_dafb_colors[0], m_dafb_colors[1], m_dafb_colors[2]));
|
||||
m_dafb_palette[m_dafb_clutoffs] = rgb_t(m_dafb_colors[0], m_dafb_colors[1], m_dafb_colors[2]);
|
||||
m_dafb_clutoffs++;
|
||||
m_dafb_count = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
switch (data & 0x9f)
|
||||
{
|
||||
case 0x80:
|
||||
m_dafb_mode = 0; // 1bpp
|
||||
break;
|
||||
|
||||
case 0x88:
|
||||
m_dafb_mode = 1; // 2bpp
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
m_dafb_mode = 2; // 4bpp
|
||||
break;
|
||||
|
||||
case 0x98:
|
||||
m_dafb_mode = 3; // 8bpp
|
||||
break;
|
||||
|
||||
case 0x9c:
|
||||
m_dafb_mode = 4; // 24bpp
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t macquadra_state::screen_update_dafb(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
|
||||
{
|
||||
auto const vram8 = util::big_endian_cast<uint8_t const>(m_vram.target()) + m_dafb_base;
|
||||
|
||||
switch (m_dafb_mode)
|
||||
{
|
||||
case 0: // 1bpp
|
||||
{
|
||||
for (int y = 0; y < 870; y++)
|
||||
{
|
||||
uint32_t *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < 1152/8; x++)
|
||||
{
|
||||
uint8_t const pixels = vram8[(y * m_dafb_stride) + x];
|
||||
|
||||
*scanline++ = m_dafb_palette[(pixels>>7)&1];
|
||||
*scanline++ = m_dafb_palette[(pixels>>6)&1];
|
||||
*scanline++ = m_dafb_palette[(pixels>>5)&1];
|
||||
*scanline++ = m_dafb_palette[(pixels>>4)&1];
|
||||
*scanline++ = m_dafb_palette[(pixels>>3)&1];
|
||||
*scanline++ = m_dafb_palette[(pixels>>2)&1];
|
||||
*scanline++ = m_dafb_palette[(pixels>>1)&1];
|
||||
*scanline++ = m_dafb_palette[(pixels&1)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // 2bpp
|
||||
{
|
||||
for (int y = 0; y < 870; y++)
|
||||
{
|
||||
uint32_t *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < 1152/4; x++)
|
||||
{
|
||||
uint8_t const pixels = vram8[(y * m_dafb_stride) + x];
|
||||
|
||||
*scanline++ = m_dafb_palette[((pixels>>6)&3)];
|
||||
*scanline++ = m_dafb_palette[((pixels>>4)&3)];
|
||||
*scanline++ = m_dafb_palette[((pixels>>2)&3)];
|
||||
*scanline++ = m_dafb_palette[(pixels&3)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 4bpp
|
||||
{
|
||||
for (int y = 0; y < 870; y++)
|
||||
{
|
||||
uint32_t *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < 1152/2; x++)
|
||||
{
|
||||
uint8_t const pixels = vram8[(y * m_dafb_stride) + x];
|
||||
|
||||
*scanline++ = m_dafb_palette[(pixels>>4)];
|
||||
*scanline++ = m_dafb_palette[(pixels&0xf)];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // 8bpp
|
||||
{
|
||||
for (int y = 0; y < 870; y++)
|
||||
{
|
||||
uint32_t *scanline = &bitmap.pix(y);
|
||||
for (int x = 0; x < 1152; x++)
|
||||
{
|
||||
uint8_t const pixels = vram8[(y * m_dafb_stride) + x];
|
||||
*scanline++ = m_dafb_palette[pixels];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // 24 bpp
|
||||
for (int y = 0; y < 480; y++)
|
||||
{
|
||||
uint32_t *scanline = &bitmap.pix(y);
|
||||
uint32_t const *base = &m_vram[(y * (m_dafb_stride/4)) + (m_dafb_base/4)];
|
||||
for (int x = 0; x < 640; x++)
|
||||
{
|
||||
*scanline++ = *base++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void macquadra_state::drq_539x_1_w(int state)
|
||||
{
|
||||
m_dafb_scsi1_drq = state;
|
||||
}
|
||||
|
||||
void macquadra_state::drq_539x_2_w(int state)
|
||||
{
|
||||
m_dafb_scsi2_drq = state;
|
||||
}
|
||||
|
||||
void macquadra_state::irq_539x_1_w(int state)
|
||||
{
|
||||
if (state) // make sure a CB1 transition occurs
|
||||
@ -649,13 +309,9 @@ void macquadra_state::irq_539x_1_w(int state)
|
||||
}
|
||||
}
|
||||
|
||||
void macquadra_state::irq_539x_2_w(int state)
|
||||
u16 macquadra_state::mac_via_r(offs_t offset)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t macquadra_state::mac_via_r(offs_t offset)
|
||||
{
|
||||
uint16_t data;
|
||||
u16 data;
|
||||
|
||||
offset >>= 8;
|
||||
offset &= 0x0f;
|
||||
@ -668,7 +324,7 @@ uint16_t macquadra_state::mac_via_r(offs_t offset)
|
||||
return (data & 0xff) | (data << 8);
|
||||
}
|
||||
|
||||
void macquadra_state::mac_via_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
void macquadra_state::mac_via_w(offs_t offset, u16 data, u16 mem_mask)
|
||||
{
|
||||
offset >>= 8;
|
||||
offset &= 0x0f;
|
||||
@ -693,7 +349,7 @@ void macquadra_state::mac_via2_irq(int state)
|
||||
field_interrupts();
|
||||
}
|
||||
|
||||
uint16_t macquadra_state::mac_via2_r(offs_t offset)
|
||||
u16 macquadra_state::mac_via2_r(offs_t offset)
|
||||
{
|
||||
int data;
|
||||
|
||||
@ -707,7 +363,7 @@ uint16_t macquadra_state::mac_via2_r(offs_t offset)
|
||||
return (data & 0xff) | (data << 8);
|
||||
}
|
||||
|
||||
void macquadra_state::mac_via2_w(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
void macquadra_state::mac_via2_w(offs_t offset, u16 data, u16 mem_mask)
|
||||
{
|
||||
offset >>= 8;
|
||||
offset &= 0x0f;
|
||||
@ -743,7 +399,7 @@ void macquadra_state::mac_via_sync()
|
||||
m_maincpu->adjust_icount(-int(main_cycle - cycle));
|
||||
}
|
||||
|
||||
uint32_t macquadra_state::rom_switch_r(offs_t offset)
|
||||
u32 macquadra_state::rom_switch_r(offs_t offset)
|
||||
{
|
||||
// disable the overlay
|
||||
if (m_overlay && !machine().side_effects_disabled())
|
||||
@ -768,36 +424,6 @@ TIMER_CALLBACK_MEMBER(macquadra_state::mac_6015_tick)
|
||||
m_macadb->adb_vblank();
|
||||
}
|
||||
|
||||
uint8_t macquadra_state::mac_5396_r(offs_t offset)
|
||||
{
|
||||
return m_ncr1->read(offset>>4);
|
||||
}
|
||||
|
||||
void macquadra_state::mac_5396_w(offs_t offset, uint8_t data)
|
||||
{
|
||||
m_ncr1->write(offset>>4, data);
|
||||
}
|
||||
|
||||
uint16_t macquadra_state::mac_5396_dma_r(offs_t offset)
|
||||
{
|
||||
// HACK: Extra time is necessary to avoid underrunning the FIFO at 4 MB/sec transfer rates claimed to
|
||||
// be typical for Apple HDDs of the period.
|
||||
// Likely due to inaccurate 68040 bus timings or wait states; DAFB documentation is clear that there is
|
||||
// no "magic latch" like the 5380 machines use.
|
||||
if (!machine().side_effects_disabled() && BIT(offset << 1, 18))
|
||||
m_maincpu->adjust_icount(-4);
|
||||
|
||||
return m_ncr1->dma16_swap_r();
|
||||
}
|
||||
|
||||
void macquadra_state::mac_5396_dma_w(offs_t offset, uint16_t data)
|
||||
{
|
||||
if (!machine().side_effects_disabled() && BIT(offset << 1, 18))
|
||||
m_maincpu->adjust_icount(-4);
|
||||
|
||||
m_ncr1->dma16_swap_w(data);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
ADDRESS MAPS
|
||||
***************************************************************************/
|
||||
@ -807,29 +433,32 @@ void macquadra_state::quadra700_map(address_map &map)
|
||||
|
||||
map(0x50000000, 0x50001fff).rw(FUNC(macquadra_state::mac_via_r), FUNC(macquadra_state::mac_via_w)).mirror(0x00fc0000);
|
||||
map(0x50002000, 0x50003fff).rw(FUNC(macquadra_state::mac_via2_r), FUNC(macquadra_state::mac_via2_w)).mirror(0x00fc0000);
|
||||
// 50008000 = Ethernet MAC ID PROM
|
||||
// 5000a000 = Sonic (DP83932) ethernet
|
||||
// 5000f000 = SCSI cf96, 5000f402 = SCSI #2 cf96
|
||||
map(0x5000f000, 0x5000f0ff).rw(FUNC(macquadra_state::mac_5396_r), FUNC(macquadra_state::mac_5396_w)).mirror(0x00fc0000);
|
||||
map(0x5000f100, 0x5000f101).rw(FUNC(macquadra_state::mac_5396_dma_r), FUNC(macquadra_state::mac_5396_dma_w)).select(0x00fc0000);
|
||||
// 50008000 = Ethernet MAC ID PROM
|
||||
map(0x5000a000, 0x5000b0ff).m(m_sonic, FUNC(dp83932c_device::map)).umask32(0x0000ffff).mirror(0x00fc0000);
|
||||
// 5000e000 = Orwell controls
|
||||
map(0x5000f000, 0x5000f0ff).rw(m_dafb, FUNC(dafb_device::turboscsi_r<0>), FUNC(dafb_device::turboscsi_w<0>)).mirror(0x00fc0000);
|
||||
map(0x5000f100, 0x5000f101).rw(m_dafb, FUNC(dafb_device::turboscsi_dma_r<0>), FUNC(dafb_device::turboscsi_dma_w<0>)).select(0x00fc0000);
|
||||
map(0x5000c000, 0x5000dfff).rw(FUNC(macquadra_state::mac_scc_r), FUNC(macquadra_state::mac_scc_2_w)).mirror(0x00fc0000);
|
||||
map(0x50014000, 0x50015fff).rw(m_easc, FUNC(asc_device::read), FUNC(asc_device::write)).mirror(0x00fc0000);
|
||||
map(0x5001e000, 0x5001ffff).rw(FUNC(macquadra_state::swim_r), FUNC(macquadra_state::swim_w)).mirror(0x00fc0000);
|
||||
|
||||
// f9800000 = VDAC / DAFB
|
||||
map(0xf9000000, 0xf91fffff).ram().share("vram");
|
||||
map(0xf9800000, 0xf98001ff).rw(FUNC(macquadra_state::dafb_r), FUNC(macquadra_state::dafb_w));
|
||||
map(0xf9800200, 0xf980023f).rw(FUNC(macquadra_state::dafb_dac_r), FUNC(macquadra_state::dafb_dac_w));
|
||||
map(0xf9000000, 0xf91fffff).rw(m_dafb, FUNC(dafb_device::vram_r), FUNC(dafb_device::vram_w));
|
||||
map(0xf9800000, 0xf98003ff).m(m_dafb, FUNC(dafb_device::map));
|
||||
}
|
||||
|
||||
uint8_t macquadra_state::mac_via_in_a()
|
||||
u8 macquadra_state::mac_via_in_a()
|
||||
{
|
||||
return 0xc1;
|
||||
}
|
||||
|
||||
uint8_t macquadra_state::mac_via_in_b()
|
||||
u8 macquadra_state::mac_via_in_b()
|
||||
{
|
||||
int val = m_rtc->data_r();
|
||||
#ifdef USE_ADBMODEM
|
||||
u8 val = m_rtc->data_r();
|
||||
#else
|
||||
u8 val = m_macadb->get_adb_state()<<4;
|
||||
val |= m_rtc->data_r();
|
||||
#endif
|
||||
|
||||
if (!m_adb_irq_pending)
|
||||
{
|
||||
@ -841,7 +470,7 @@ uint8_t macquadra_state::mac_via_in_b()
|
||||
return val;
|
||||
}
|
||||
|
||||
void macquadra_state::mac_via_out_a(uint8_t data)
|
||||
void macquadra_state::mac_via_out_a(u8 data)
|
||||
{
|
||||
int hdsel = BIT(data, 5);
|
||||
if (hdsel != m_hdsel)
|
||||
@ -854,43 +483,46 @@ void macquadra_state::mac_via_out_a(uint8_t data)
|
||||
m_hdsel = hdsel;
|
||||
}
|
||||
|
||||
void macquadra_state::mac_via_out_b(uint8_t data)
|
||||
void macquadra_state::mac_via_out_b(u8 data)
|
||||
{
|
||||
// printf("%s VIA1 OUT B: %02x\n", machine().describe_context().c_str(), data);
|
||||
#ifdef USE_ADBMODEM
|
||||
m_adbmodem->set_via_state((data & 0x30) >> 4);
|
||||
|
||||
#else
|
||||
m_macadb->mac_adb_newaction((data & 0x30) >> 4);
|
||||
#endif
|
||||
m_rtc->ce_w((data & 0x04)>>2);
|
||||
m_rtc->data_w(data & 0x01);
|
||||
m_rtc->clk_w((data >> 1) & 0x01);
|
||||
}
|
||||
|
||||
uint8_t macquadra_state::mac_via2_in_a()
|
||||
u8 macquadra_state::mac_via2_in_a()
|
||||
{
|
||||
return 0x80 | m_nubus_irq_state;
|
||||
}
|
||||
|
||||
uint8_t macquadra_state::mac_via2_in_b()
|
||||
u8 macquadra_state::mac_via2_in_b()
|
||||
{
|
||||
return 0xcf; // indicate no NuBus transaction error
|
||||
}
|
||||
|
||||
void macquadra_state::mac_via2_out_a(uint8_t data)
|
||||
void macquadra_state::mac_via2_out_a(u8 data)
|
||||
{
|
||||
}
|
||||
|
||||
void macquadra_state::mac_via2_out_b(uint8_t data)
|
||||
void macquadra_state::mac_via2_out_b(u8 data)
|
||||
{
|
||||
// chain 60.15 Hz to VIA1
|
||||
m_via1->write_ca1(data>>7);
|
||||
}
|
||||
|
||||
void macquadra_state::phases_w(uint8_t phases)
|
||||
void macquadra_state::phases_w(u8 phases)
|
||||
{
|
||||
if (m_cur_floppy)
|
||||
m_cur_floppy->seek_phase_w(phases);
|
||||
}
|
||||
|
||||
void macquadra_state::devsel_w(uint8_t devsel)
|
||||
void macquadra_state::devsel_w(u8 devsel)
|
||||
{
|
||||
if (devsel == 1)
|
||||
m_cur_floppy = m_floppy[0]->get_device();
|
||||
@ -922,14 +554,9 @@ void macquadra_state::macqd700(machine_config &config)
|
||||
m_maincpu->set_addrmap(AS_PROGRAM, &macquadra_state::quadra700_map);
|
||||
m_maincpu->set_dasm_override(std::function(&mac68k_dasm_override), "mac68k_dasm_override");
|
||||
|
||||
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
||||
m_screen->set_refresh_hz(75.08);
|
||||
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(1260));
|
||||
m_screen->set_size(1152, 870);
|
||||
m_screen->set_visarea(0, 1152-1, 0, 870-1);
|
||||
m_screen->set_screen_update(FUNC(macquadra_state::screen_update_dafb));
|
||||
|
||||
PALETTE(config, m_palette).set_entries(256);
|
||||
DAFB(config, m_dafb, 50_MHz_XTAL / 2);
|
||||
m_dafb->set_maincpu_tag("maincpu");
|
||||
m_dafb->dafb_irq().set(FUNC(macquadra_state::dafb_irq_w));
|
||||
|
||||
RTC3430042(config, m_rtc, XTAL(32'768));
|
||||
m_rtc->cko_cb().set(m_via1, FUNC(via6522_device::write_ca2));
|
||||
@ -960,7 +587,7 @@ void macquadra_state::macqd700(machine_config &config)
|
||||
|
||||
adapter.set_busmd(ncr53c96_device::BUSMD_1);
|
||||
adapter.irq_handler_cb().set(*this, FUNC(macquadra_state::irq_539x_1_w));
|
||||
adapter.drq_handler_cb().set(*this, FUNC(macquadra_state::drq_539x_1_w));
|
||||
adapter.drq_handler_cb().set(m_dafb, FUNC(dafb_device::turboscsi_drq_w<0>));
|
||||
});
|
||||
|
||||
DP83932C(config, m_sonic, 40_MHz_XTAL / 2);
|
||||
@ -983,6 +610,9 @@ void macquadra_state::macqd700(machine_config &config)
|
||||
m_via1->writepa_handler().set(FUNC(macquadra_state::mac_via_out_a));
|
||||
m_via1->writepb_handler().set(FUNC(macquadra_state::mac_via_out_b));
|
||||
m_via1->irq_handler().set(FUNC(macquadra_state::mac_via_irq));
|
||||
#ifndef USE_ADBMODEM
|
||||
m_via1->cb2_handler().set(m_macadb, FUNC(macadb_device::adb_data_w));
|
||||
#endif
|
||||
|
||||
R65NC22(config, m_via2, C7M/10);
|
||||
m_via2->readpa_handler().set(FUNC(macquadra_state::mac_via2_in_a));
|
||||
@ -991,16 +621,25 @@ void macquadra_state::macqd700(machine_config &config)
|
||||
m_via2->writepb_handler().set(FUNC(macquadra_state::mac_via2_out_b));
|
||||
m_via2->irq_handler().set(FUNC(macquadra_state::mac_via2_irq));
|
||||
|
||||
ADBMODEM(config, m_adbmodem, C7M);
|
||||
m_adbmodem->via_clock_callback().set(m_via1, FUNC(via6522_device::write_cb1));
|
||||
m_adbmodem->via_data_callback().set(m_via1, FUNC(via6522_device::write_cb2));
|
||||
m_adbmodem->linechange_callback().set(m_macadb, FUNC(macadb_device::adb_linechange_w));
|
||||
m_adbmodem->irq_callback().set(FUNC(macquadra_state::adb_irq_w));
|
||||
m_via1->cb2_handler().set(m_adbmodem, FUNC(adbmodem_device::set_via_data));
|
||||
config.set_maximum_quantum(attotime::from_hz(1000000));
|
||||
#ifdef USE_ADBMODEM
|
||||
ADBMODEM(config, m_adbmodem, C7M);
|
||||
m_adbmodem->via_clock_callback().set(m_via1, FUNC(via6522_device::write_cb1));
|
||||
m_adbmodem->via_data_callback().set(m_via1, FUNC(via6522_device::write_cb2));
|
||||
m_adbmodem->linechange_callback().set(m_macadb, FUNC(macadb_device::adb_linechange_w));
|
||||
m_adbmodem->irq_callback().set(FUNC(macquadra_state::adb_irq_w));
|
||||
m_via1->cb2_handler().set(m_adbmodem, FUNC(adbmodem_device::set_via_data));
|
||||
config.set_maximum_quantum(attotime::from_hz(1000000));
|
||||
#endif
|
||||
|
||||
MACADB(config, m_macadb, C15M);
|
||||
m_macadb->adb_data_callback().set(m_adbmodem, FUNC(adbmodem_device::set_adb_line));
|
||||
#ifdef USE_ADBMODEM
|
||||
m_macadb->adb_data_callback().set(m_adbmodem, FUNC(adbmodem_device::set_adb_line));
|
||||
#else
|
||||
m_macadb->set_mcu_mode(false);
|
||||
m_macadb->via_clock_callback().set(m_via1, FUNC(via6522_device::write_cb1));
|
||||
m_macadb->via_data_callback().set(m_via1, FUNC(via6522_device::write_cb2));
|
||||
m_macadb->adb_irq_callback().set(FUNC(macquadra_state::adb_irq_w));
|
||||
#endif
|
||||
|
||||
SPEAKER(config, "lspeaker").front_left();
|
||||
SPEAKER(config, "rspeaker").front_right();
|
||||
|
Loading…
Reference in New Issue
Block a user