From 578bef8bae3a1848a61c88c8b033cd8bf67254ce Mon Sep 17 00:00:00 2001 From: arbee Date: Wed, 5 Jul 2023 11:04:58 -0400 Subject: apple/dafb.cpp: New DAFB device for the Quadra 700/900/950, including video and "turbo SCSI". [R. Belmont] --- src/mame/apple/dafb.cpp | 943 ++++++++++++++++++++++++++++++++++++++++ src/mame/apple/dafb.h | 128 ++++++ src/mame/apple/macquadra700.cpp | 555 +++++------------------ 3 files changed, 1168 insertions(+), 458 deletions(-) create mode 100644 src/mame/apple/dafb.cpp create mode 100644 src/mame/apple/dafb.h diff --git a/src/mame/apple/dafb.cpp b/src/mame/apple/dafb.cpp new file mode 100644 index 00000000000..9f28c9c1166 --- /dev/null +++ b/src/mame/apple/dafb.cpp @@ -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(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(&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 +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 +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 +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 +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 +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); diff --git a/src/mame/apple/dafb.h b/src/mame/apple/dafb.h new file mode 100644 index 00000000000..e47ef203768 --- /dev/null +++ b/src/mame/apple/dafb.h @@ -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 m_screen; + required_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 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 void set_maincpu_tag(T &&... args) { m_maincpu.set_tag(std::forward(args)...); } + + void set_turboscsi1_device(ncr53c94_device *device) { m_ncr[0] = device; } + void set_turboscsi2_device(ncr53c94_device *device) { m_ncr[1] = device; } + + template void turboscsi_drq_w(int state); + + template u8 turboscsi_r(offs_t offset); + template void turboscsi_w(offs_t offset, u8 data); + template u16 turboscsi_dma_r(offs_t offset, u16 mem_mask); + template void turboscsi_dma_w(offs_t offset, u16 data, u16 mem_mask); + +protected: + virtual void device_start() override; + +private: + required_device m_maincpu; + ncr53c94_device *m_ncr[2]; +}; + +DECLARE_DEVICE_TYPE(DAFB, dafb_device) + +#endif /* MAME_APPLE_DAFB_H */ diff --git a/src/mame/apple/macquadra700.cpp b/src/mame/apple/macquadra700.cpp index 6fd84580286..194cd99e9f2 100644 --- a/src/mame/apple/macquadra700.cpp +++ b/src/mame/apple/macquadra700.cpp @@ -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 m_maincpu; required_device m_via1, m_via2; required_device m_macadb; +#ifdef USE_ADBMODEM required_device m_adbmodem; +#endif required_device m_ram; required_device m_swim; required_device_array m_floppy; @@ -89,39 +93,17 @@ private: required_device m_scsibus1; required_device m_ncr1; required_device m_sonic; - required_device m_screen; - required_device m_palette; + required_device m_dafb; required_device m_easc; required_device m_scc; - required_shared_ptr 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(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(); -- cgit v1.2.3