// license:BSD-3-Clause // copyright-holders:Nathan Woods, Raphael Nabet, R. Belmont /*************************************************************************** video/mac.c Macintosh video hardware Emulates the video hardware for compact Macintosh series (original Macintosh (128k, 512k, 512ke), Macintosh Plus, Macintosh SE, Macintosh Classic) Also emulates on-board video for systems with the RBV, V8, Eagle, Sonora, and DAFB chips. ---------------------------------------------------------------------- Monitor sense codes 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 use "type 6" extended codes 111 - No monitor connected or use "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. Extended codes: Sense 2 Low Sense 1 Low Sense 0 Low 1 & 0 2 & 0 2 & 1 Multiple Scan 14" 00 00 11 Multiple Scan 16" 00 10 11 Multiple Scan 21" 10 00 11 PAL Encoder 00 00 00 NTSC Encoder 01 01 00 VGA/Super VGA 01 01 11 RGB 16" 10 11 01 PAL Monitor 11 00 00 RGB 19" 11 10 10 Radius color TPD 11 00 01 (TPD = Two Page Display) Radius mono TPD 11 01 00 Apple TPD 11 01 01 Apple color FPD 01 11 10 (FPD = Full Page Display) ***************************************************************************/ #include "emu.h" #include "sound/asc.h" #include "includes/mac.h" #include "machine/ram.h" PALETTE_INIT_MEMBER(mac_state,mac) { palette.set_pen_color(0, 0xff, 0xff, 0xff); palette.set_pen_color(1, 0x00, 0x00, 0x00); } // 4-level grayscale PALETTE_INIT_MEMBER(mac_state,macgsc) { palette.set_pen_color(0, 0xff, 0xff, 0xff); palette.set_pen_color(1, 0x7f, 0x7f, 0x7f); palette.set_pen_color(2, 0x3f, 0x3f, 0x3f); palette.set_pen_color(3, 0x00, 0x00, 0x00); } VIDEO_START_MEMBER(mac_state,mac) { } #define MAC_MAIN_SCREEN_BUF_OFFSET 0x5900 #define MAC_ALT_SCREEN_BUF_OFFSET 0xD900 UINT32 mac_state::screen_update_mac(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { UINT32 video_base; const UINT16 *video_ram; UINT16 word; UINT16 *line; int y, x, b; video_base = m_ram->size() - (m_screen_buffer ? MAC_MAIN_SCREEN_BUF_OFFSET : MAC_ALT_SCREEN_BUF_OFFSET); video_ram = (const UINT16 *) (m_ram->pointer() + video_base); for (y = 0; y < MAC_V_VIS; y++) { line = &bitmap.pix16(y); for (x = 0; x < MAC_H_VIS; x += 16) { word = *(video_ram++); for (b = 0; b < 16; b++) { line[x + b] = (word >> (15 - b)) & 0x0001; } } } return 0; } UINT32 mac_state::screen_update_macse30(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { UINT32 video_base; const UINT16 *video_ram; UINT16 word; UINT16 *line; int y, x, b; video_base = m_screen_buffer ? 0x8000 : 0; video_base += (MAC_H_VIS/8); video_ram = (const UINT16 *) &m_vram[video_base/4]; for (y = 0; y < MAC_V_VIS; y++) { line = &bitmap.pix16(y); for (x = 0; x < MAC_H_VIS; x += 16) { word = video_ram[((y * MAC_H_VIS)/16) + ((x/16)^1)]; for (b = 0; b < 16; b++) { line[x + b] = (word >> (15 - b)) & 0x0001; } } } return 0; } UINT32 mac_state::screen_update_macprtb(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { const UINT16 *video_ram; UINT16 word; UINT16 *line; int y, x, b; video_ram = (const UINT16 *) m_vram16.target(); for (y = 0; y < 400; y++) { line = &bitmap.pix16(y); for (x = 0; x < 640; x += 16) { word = video_ram[((y * 640)/16) + ((x/16))]; for (b = 0; b < 16; b++) { line[x + b] = (word >> (15 - b)) & 0x0001; } } } return 0; } UINT32 mac_state::screen_update_macpb140(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { const UINT16 *video_ram; UINT16 word; UINT16 *line; int y, x, b; video_ram = (const UINT16 *) m_vram.target(); for (y = 0; y < 400; y++) { line = &bitmap.pix16(y); for (x = 0; x < 640; x += 16) { word = video_ram[((y * 640)/16) + ((x/16)^1)]; for (b = 0; b < 16; b++) { line[x + b] = (word >> (15 - b)) & 0x0001; } } } return 0; } UINT32 mac_state::screen_update_macpb160(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { UINT16 *line; int y, x; UINT8 pixels; UINT8 *vram8 = (UINT8 *)m_vram.target(); for (y = 0; y < 400; y++) { line = &bitmap.pix16(y); for (x = 0; x < 640/4; x++) { pixels = vram8[(y * 160) + (BYTE4_XOR_BE(x))]; *line++ = ((pixels>>6)&3); *line++ = ((pixels>>4)&3); *line++ = ((pixels>>2)&3); *line++ = (pixels&3); } } return 0; } // IIci/IIsi RAM-Based Video (RBV) and children: V8, Eagle, Spice, VASP, Sonora VIDEO_START_MEMBER(mac_state,macrbv) { } VIDEO_RESET_MEMBER(mac_state,maceagle) { m_rbv_montype = 32; m_rbv_palette[0xfe] = 0xffffff; m_rbv_palette[0xff] = 0; } VIDEO_RESET_MEMBER(mac_state,macrbv) { rectangle visarea; int htotal, vtotal; double framerate; int view; memset(m_rbv_regs, 0, sizeof(m_rbv_regs)); m_rbv_count = 0; m_rbv_clutoffs = 0; m_rbv_immed10wr = 0; m_rbv_regs[2] = 0x7f; m_rbv_regs[3] = 0; m_rbv_type = RBV_TYPE_RBV; visarea.min_x = 0; visarea.min_y = 0; view = 0; if (m_montype) { m_rbv_montype = m_montype->read_safe(2); } else { m_rbv_montype = 2; } switch (m_rbv_montype) { case 1: // 15" portrait display visarea.max_x = 640-1; visarea.max_y = 870-1; htotal = 832; vtotal = 918; framerate = 75.0; view = 1; break; case 2: // 12" RGB visarea.max_x = 512-1; visarea.max_y = 384-1; htotal = 640; vtotal = 407; framerate = 60.15; break; case 6: // 13" RGB default: visarea.max_x = 640-1; visarea.max_y = 480-1; htotal = 800; vtotal = 525; framerate = 59.94; break; } // printf("RBV reset: monitor is %dx%d @ %f Hz\n", visarea.max_x+1, visarea.max_y+1, framerate); machine().first_screen()->configure(htotal, vtotal, visarea, HZ_TO_ATTOSECONDS(framerate)); render_target *target = machine().render().first_target(); target->set_view(view); } VIDEO_RESET_MEMBER(mac_state,macsonora) { rectangle visarea; int htotal, vtotal; double framerate; int view = 0; memset(m_rbv_regs, 0, sizeof(m_rbv_regs)); m_rbv_count = 0; m_rbv_clutoffs = 0; m_rbv_immed10wr = 0; m_rbv_regs[2] = 0x7f; m_rbv_regs[3] = 0; m_rbv_type = RBV_TYPE_SONORA; visarea.min_x = 0; visarea.min_y = 0; m_rbv_montype = m_montype->read_safe(2); switch (m_rbv_montype) { case 1: // 15" portrait display visarea.max_x = 640-1; visarea.max_y = 870-1; htotal = 832; vtotal = 918; framerate = 75.0; view = 1; break; case 2: // 12" RGB visarea.max_x = 512-1; visarea.max_y = 384-1; htotal = 640; vtotal = 407; framerate = 60.15; break; case 6: // 13" RGB default: visarea.max_x = 640-1; visarea.max_y = 480-1; htotal = 800; vtotal = 525; framerate = 59.94; break; } // printf("Sonora reset: monitor is %dx%d @ %f Hz\n", visarea.max_x+1, visarea.max_y+1, framerate); machine().first_screen()->configure(htotal, vtotal, visarea, HZ_TO_ATTOSECONDS(framerate)); render_target *target = machine().render().first_target(); target->set_view(view); } VIDEO_START_MEMBER(mac_state,macsonora) { memset(m_rbv_regs, 0, sizeof(m_rbv_regs)); m_rbv_count = 0; m_rbv_clutoffs = 0; m_rbv_immed10wr = 0; m_rbv_regs[2] = 0x7f; m_rbv_regs[3] = 0; m_rbv_regs[4] = 0x6; m_rbv_regs[5] = 0x3; m_sonora_vctl[0] = 0x9f; m_sonora_vctl[1] = 0; m_sonora_vctl[2] = 0; m_rbv_type = RBV_TYPE_SONORA; } VIDEO_START_MEMBER(mac_state,macv8) { memset(m_rbv_regs, 0, sizeof(m_rbv_regs)); m_rbv_count = 0; m_rbv_clutoffs = 0; m_rbv_immed10wr = 0; m_rbv_regs[0] = 0x4f; m_rbv_regs[1] = 0x06; m_rbv_regs[2] = 0x7f; m_rbv_type = RBV_TYPE_V8; } UINT32 mac_state::screen_update_macrbv(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { UINT32 *scanline; int x, y, hres, vres; UINT8 *vram8 = (UINT8 *)m_ram->pointer(); switch (m_rbv_montype) { case 32: // classic II built-in display hres = MAC_H_VIS; vres = MAC_V_VIS; vram8 += 0x1f9a80; // Classic II apparently doesn't use VRAM? break; case 1: // 15" portrait display hres = 640; vres = 870; break; case 2: // 12" RGB hres = 512; vres = 384; break; case 6: // 13" RGB default: hres = 640; vres = 480; break; } switch (m_rbv_regs[0x10] & 7) { case 0: // 1bpp { UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres; x+=8) { pixels = vram8[(y * (hres/8)) + ((x/8)^3)]; *scanline++ = m_rbv_palette[0xfe|(pixels>>7)]; *scanline++ = m_rbv_palette[0xfe|((pixels>>6)&1)]; *scanline++ = m_rbv_palette[0xfe|((pixels>>5)&1)]; *scanline++ = m_rbv_palette[0xfe|((pixels>>4)&1)]; *scanline++ = m_rbv_palette[0xfe|((pixels>>3)&1)]; *scanline++ = m_rbv_palette[0xfe|((pixels>>2)&1)]; *scanline++ = m_rbv_palette[0xfe|((pixels>>1)&1)]; *scanline++ = m_rbv_palette[0xfe|(pixels&1)]; } } } break; case 1: // 2bpp { UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres/4; x++) { pixels = vram8[(y * (hres/4)) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[0xfc|((pixels>>6)&3)]; *scanline++ = m_rbv_palette[0xfc|((pixels>>4)&3)]; *scanline++ = m_rbv_palette[0xfc|((pixels>>2)&3)]; *scanline++ = m_rbv_palette[0xfc|(pixels&3)]; } } } break; case 2: // 4bpp { UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres/2; x++) { pixels = vram8[(y * (hres/2)) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[0xf0|(pixels>>4)]; *scanline++ = m_rbv_palette[0xf0|(pixels&0xf)]; } } } break; case 3: // 8bpp { UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres; x++) { pixels = vram8[(y * hres) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[pixels]; } } } } return 0; } UINT32 mac_state::screen_update_macrbvvram(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { UINT32 *scanline; int x, y, hres, vres; switch (m_rbv_montype) { case 1: // 15" portrait display hres = 640; vres = 870; break; case 2: // 12" RGB hres = 512; vres = 384; break; case 6: // 13" RGB default: hres = 640; vres = 480; break; } switch (m_rbv_regs[0x10] & 7) { case 0: // 1bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres; x+=8) { pixels = vram8[(y * 0x400) + ((x/8)^3)]; *scanline++ = m_rbv_palette[0x7f|(pixels&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<1)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<2)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<3)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<4)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<5)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<6)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<7)&0x80)]; } } } break; case 1: // 2bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres/4; x++) { pixels = vram8[(y * (hres/4)) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[0xfc|((pixels>>6)&3)]; *scanline++ = m_rbv_palette[0xfc|((pixels>>4)&3)]; *scanline++ = m_rbv_palette[0xfc|((pixels>>2)&3)]; *scanline++ = m_rbv_palette[0xfc|(pixels&3)]; } } } break; case 2: // 4bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres/2; x++) { pixels = vram8[(y * (hres/2)) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[0xf0|(pixels>>4)]; *scanline++ = m_rbv_palette[0xf0|(pixels&0xf)]; } } } break; case 3: // 8bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres; x++) { pixels = vram8[(y * 2048) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[pixels]; } } } } return 0; } UINT32 mac_state::screen_update_macv8(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { UINT32 *scanline; int x, y, hres, vres; switch (m_rbv_montype) { case 1: // 15" portrait display hres = 640; vres = 870; break; case 2: // 12" RGB hres = 512; vres = 384; break; case 6: // 13" RGB default: hres = 640; vres = 480; break; } switch (m_rbv_regs[0x10] & 7) { case 0: // 1bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres; x+=8) { pixels = vram8[(y * 1024) + ((x/8)^3)]; *scanline++ = m_rbv_palette[0x7f|(pixels&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<1)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<2)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<3)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<4)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<5)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<6)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<7)&0x80)]; } } } break; case 1: // 2bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres/4; x++) { pixels = vram8[(y * 1024) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[0x3f|(pixels&0xc0)]; *scanline++ = m_rbv_palette[0x3f|((pixels<<2)&0xc0)]; *scanline++ = m_rbv_palette[0x3f|((pixels<<4)&0xc0)]; *scanline++ = m_rbv_palette[0x3f|((pixels<<6)&0xc0)]; } } } break; case 2: // 4bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres/2; x++) { pixels = vram8[(y * 1024) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[(pixels&0xf0) | 0xf]; *scanline++ = m_rbv_palette[((pixels&0x0f)<<4) | 0xf]; } } } break; case 3: // 8bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres; x++) { pixels = vram8[(y * 1024) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[pixels]; } } } break; } return 0; } UINT32 mac_state::screen_update_macsonora(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { UINT32 *scanline; int x, y, hres, vres, stride; switch (m_rbv_montype) { case 1: // 15" portrait display stride = hres = 640; vres = 870; break; case 2: // 12" RGB stride = hres = 512; vres = 384; break; case 6: // 13" RGB default: stride = hres = 640; vres = 480; break; } // forced blank? if (m_sonora_vctl[0] & 0x80) { return 0; } switch (m_sonora_vctl[1] & 7) { case 0: // 1bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres; x+=8) { pixels = vram8[(y * (stride/8)) + ((x/8)^3)]; *scanline++ = m_rbv_palette[0x7f|(pixels&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<1)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<2)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<3)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<4)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<5)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<6)&0x80)]; *scanline++ = m_rbv_palette[0x7f|((pixels<<7)&0x80)]; } } } break; case 1: // 2bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres/4; x++) { pixels = vram8[(y * (stride/4)) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[0x3f|(pixels&0xc0)]; *scanline++ = m_rbv_palette[0x3f|((pixels<<2)&0xc0)]; *scanline++ = m_rbv_palette[0x3f|((pixels<<4)&0xc0)]; *scanline++ = m_rbv_palette[0x3f|((pixels<<6)&0xc0)]; } } } break; case 2: // 4bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres/2; x++) { pixels = vram8[(y * (stride/2)) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[(pixels&0xf0) | 0xf]; *scanline++ = m_rbv_palette[((pixels&0x0f)<<4) | 0xf]; } } } break; case 3: // 8bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres; x++) { pixels = vram8[(y * stride) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[pixels]; } } } break; case 4: // 16bpp { UINT16 *vram16 = (UINT16 *)m_vram.target(); UINT16 pixels; for (y = 0; y < vres; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < hres; x++) { pixels = vram16[(y * stride) + (x^1)]; *scanline++ = rgb_t(((pixels>>10) & 0x1f)<<3, ((pixels>>5) & 0x1f)<<3, (pixels & 0x1f)<<3); } } } break; } return 0; } // DAFB: video for Quadra 700/900 void mac_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(mac_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(mac_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); } VIDEO_START_MEMBER(mac_state,macdafb) { m_vbl_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mac_state::dafb_vbl_tick),this)); m_cursor_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mac_state::dafb_cursor_tick),this)); m_vbl_timer->adjust(attotime::never); m_cursor_timer->adjust(attotime::never); } VIDEO_RESET_MEMBER(mac_state,macdafb) { m_rbv_count = 0; m_rbv_clutoffs = 0; m_rbv_montype = 6; m_rbv_vbltime = 0; m_dafb_int_status = 0; m_rbv_type = RBV_TYPE_DAFB; m_dafb_mode = 0; m_dafb_base = 0x1000; m_dafb_stride = 256*4; memset(m_rbv_palette, 0, sizeof(m_rbv_palette)); } READ32_MEMBER(mac_state::dafb_r) { // 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; } WRITE32_MEMBER(mac_state::dafb_w) { // 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; } } READ32_MEMBER(mac_state::dafb_dac_r) { // printf("DAFB: Read DAC @ %x (mask %x PC=%x)\n", offset*4, mem_mask, m_maincpu->pc()); return 0; } WRITE32_MEMBER(mac_state::dafb_dac_w) { // 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_rbv_clutoffs = data & 0xff; m_rbv_count = 0; break; case 0x10: m_rbv_colors[m_rbv_count++] = data&0xff; if (m_rbv_count == 3) { m_palette->set_pen_color(m_rbv_clutoffs, rgb_t(m_rbv_colors[0], m_rbv_colors[1], m_rbv_colors[2])); m_rbv_palette[m_rbv_clutoffs] = rgb_t(m_rbv_colors[0], m_rbv_colors[1], m_rbv_colors[2]); m_rbv_clutoffs++; m_rbv_count = 0; } break; case 0x20: printf("%x to DAFB mode\n", data); 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 mac_state::screen_update_macdafb(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { UINT32 *scanline; int x, y; switch (m_dafb_mode) { case 0: // 1bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; vram8 += m_dafb_base; for (y = 0; y < 870; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < 1152; x+=8) { pixels = vram8[(y * m_dafb_stride) + ((x/8)^3)]; *scanline++ = m_rbv_palette[(pixels>>7)&1]; *scanline++ = m_rbv_palette[(pixels>>6)&1]; *scanline++ = m_rbv_palette[(pixels>>5)&1]; *scanline++ = m_rbv_palette[(pixels>>4)&1]; *scanline++ = m_rbv_palette[(pixels>>3)&1]; *scanline++ = m_rbv_palette[(pixels>>2)&1]; *scanline++ = m_rbv_palette[(pixels>>1)&1]; *scanline++ = m_rbv_palette[(pixels&1)]; } } } break; case 1: // 2bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; vram8 += m_dafb_base; for (y = 0; y < 870; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < 1152/4; x++) { pixels = vram8[(y * m_dafb_stride) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[((pixels>>6)&3)]; *scanline++ = m_rbv_palette[((pixels>>4)&3)]; *scanline++ = m_rbv_palette[((pixels>>2)&3)]; *scanline++ = m_rbv_palette[(pixels&3)]; } } } break; case 2: // 4bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; vram8 += m_dafb_base; for (y = 0; y < 870; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < 1152/2; x++) { pixels = vram8[(y * m_dafb_stride) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[(pixels>>4)]; *scanline++ = m_rbv_palette[(pixels&0xf)]; } } } break; case 3: // 8bpp { UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; vram8 += m_dafb_base; for (y = 0; y < 870; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < 1152; x++) { pixels = vram8[(y * m_dafb_stride) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[pixels]; } } } break; case 4: // 24 bpp for (y = 0; y < 480; y++) { UINT32 *base; scanline = &bitmap.pix32(y); base = (UINT32 *)&m_vram[(y * (m_dafb_stride/4)) + (m_dafb_base/4)]; for (x = 0; x < 640; x++) { *scanline++ = *base++; } } break; } return 0; } UINT32 mac_state::screen_update_macpbwd(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)/* Color PowerBooks using an off-the-shelf WD video chipset */ { UINT32 *scanline; int x, y; UINT8 *vram8 = (UINT8 *)m_vram.target(); UINT8 pixels; // vram8 += 0x40000; for (y = 0; y < 480; y++) { scanline = &bitmap.pix32(y); for (x = 0; x < 640; x++) { pixels = vram8[(y * 640) + (BYTE4_XOR_BE(x))]; *scanline++ = m_rbv_palette[pixels]; } } return 0; } READ32_MEMBER(mac_state::macwd_r) { switch (offset) { case 0xf6: if (m_screen->vblank()) { return 0xffffffff; } else { return 0; } default: // printf("macwd_r: @ %x, mask %08x (PC=%x)\n", offset, mem_mask, m_maincpu->pc()); break; } return 0; } WRITE32_MEMBER(mac_state::macwd_w) { switch (offset) { case 0xf2: if (mem_mask == 0xff000000) // DAC control { m_rbv_clutoffs = data>>24; m_rbv_count = 0; } else if (mem_mask == 0x00ff0000) // DAC data { m_rbv_colors[m_rbv_count++] = (data>>16)&0xff; if (m_rbv_count == 3) { // printf("RAMDAC: color %d = %02x %02x %02x\n", m_rbv_clutoffs, m_rbv_colors[0], m_rbv_colors[1], m_rbv_colors[2]); m_rbv_palette[m_rbv_clutoffs] = rgb_t(m_rbv_colors[0], m_rbv_colors[1], m_rbv_colors[2]); m_rbv_clutoffs++; m_rbv_count = 0; } } else { printf("macwd: Unknown DAC write, data %08x, mask %08x\n", data, mem_mask); } break; default: // printf("macwd_w: %x @ %x, mask %08x (PC=%x)\n", data, offset, mem_mask, m_maincpu->pc()); break; } }