From 0a6538f9d9ceea756d8a403f97ba38c49ef86a1f Mon Sep 17 00:00:00 2001 From: AJR Date: Fri, 13 Jul 2018 01:06:14 -0400 Subject: x68000: Separate VINAS/VICON CRTC device - Fix the dot clock divider calculation yet again (nw) --- scripts/target/mame/mess.lua | 2 + src/mame/drivers/x68k.cpp | 98 +++---- src/mame/includes/x68k.h | 77 +---- src/mame/video/x68k.cpp | 663 +++++-------------------------------------- src/mame/video/x68k_crtc.cpp | 642 +++++++++++++++++++++++++++++++++++++++++ src/mame/video/x68k_crtc.h | 124 ++++++++ 6 files changed, 895 insertions(+), 711 deletions(-) create mode 100644 src/mame/video/x68k_crtc.cpp create mode 100644 src/mame/video/x68k_crtc.h diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 2768bede7ef..a3760cb5455 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -2972,6 +2972,8 @@ files { MAME_DIR .. "src/mame/machine/x68k_hdc.h", MAME_DIR .. "src/mame/machine/x68k_kbd.cpp", MAME_DIR .. "src/mame/machine/x68k_kbd.h", + MAME_DIR .. "src/mame/video/x68k_crtc.cpp", + MAME_DIR .. "src/mame/video/x68k_crtc.h", MAME_DIR .. "src/mame/drivers/mz80.cpp", MAME_DIR .. "src/mame/includes/mz80.h", MAME_DIR .. "src/mame/video/mz80.cpp", diff --git a/src/mame/drivers/x68k.cpp b/src/mame/drivers/x68k.cpp index df555a22ea7..d8971ad5746 100644 --- a/src/mame/drivers/x68k.cpp +++ b/src/mame/drivers/x68k.cpp @@ -170,21 +170,6 @@ void x68k_state::device_timer(emu_timer &timer, device_timer_id id, int param, v case TIMER_X68K_NET_IRQ: x68k_net_irq(ptr, param); break; - case TIMER_X68K_CRTC_OPERATION_END: - x68k_crtc_operation_end(ptr, param); - break; - case TIMER_X68K_HSYNC: - x68k_hsync(ptr, param); - break; - case TIMER_X68K_CRTC_RASTER_END: - x68k_crtc_raster_end(ptr, param); - break; - case TIMER_X68K_CRTC_RASTER_IRQ: - x68k_crtc_raster_irq(ptr, param); - break; - case TIMER_X68K_CRTC_VBLANK_IRQ: - x68k_crtc_vblank_irq(ptr, param); - break; case TIMER_X68K_FDC_TC: m_upd72065->tc_w(ASSERT_LINE); m_upd72065->tc_w(CLEAR_LINE); @@ -1129,9 +1114,9 @@ void x68k_state::x68k_map(address_map &map) { map(0x000000, 0xbffffb).rw(FUNC(x68k_state::x68k_emptyram_r), FUNC(x68k_state::x68k_emptyram_w)); map(0xbffffc, 0xbfffff).rw(FUNC(x68k_state::x68k_rom0_r), FUNC(x68k_state::x68k_rom0_w)); - map(0xc00000, 0xdfffff).rw(FUNC(x68k_state::x68k_gvram_r), FUNC(x68k_state::x68k_gvram_w)); - map(0xe00000, 0xe7ffff).rw(FUNC(x68k_state::x68k_tvram_r), FUNC(x68k_state::x68k_tvram_w)); - map(0xe80000, 0xe81fff).rw(FUNC(x68k_state::x68k_crtc_r), FUNC(x68k_state::x68k_crtc_w)); + map(0xc00000, 0xdfffff).rw(m_crtc, FUNC(x68k_crtc_device::gvram_r), FUNC(x68k_crtc_device::gvram_w)); + map(0xe00000, 0xe7ffff).rw(m_crtc, FUNC(x68k_crtc_device::tvram_r), FUNC(x68k_crtc_device::tvram_w)); + map(0xe80000, 0xe81fff).rw(m_crtc, FUNC(x68k_crtc_device::crtc_r), FUNC(x68k_crtc_device::crtc_w)); map(0xe82000, 0xe821ff).rw(m_gfxpalette, FUNC(palette_device::read16), FUNC(palette_device::write16)).share("gfxpalette"); map(0xe82200, 0xe823ff).rw(m_pcgpalette, FUNC(palette_device::read16), FUNC(palette_device::write16)).share("pcgpalette"); map(0xe82400, 0xe83fff).rw(FUNC(x68k_state::x68k_vid_r), FUNC(x68k_state::x68k_vid_w)); @@ -1168,9 +1153,9 @@ void x68k_state::x68kxvi_map(address_map &map) { map(0x000000, 0xbffffb).rw(FUNC(x68k_state::x68k_emptyram_r), FUNC(x68k_state::x68k_emptyram_w)); map(0xbffffc, 0xbfffff).rw(FUNC(x68k_state::x68k_rom0_r), FUNC(x68k_state::x68k_rom0_w)); - map(0xc00000, 0xdfffff).rw(FUNC(x68k_state::x68k_gvram_r), FUNC(x68k_state::x68k_gvram_w)); - map(0xe00000, 0xe7ffff).rw(FUNC(x68k_state::x68k_tvram_r), FUNC(x68k_state::x68k_tvram_w)); - map(0xe80000, 0xe81fff).rw(FUNC(x68k_state::x68k_crtc_r), FUNC(x68k_state::x68k_crtc_w)); + map(0xc00000, 0xdfffff).rw(m_crtc, FUNC(x68k_crtc_device::gvram_r), FUNC(x68k_crtc_device::gvram_w)); + map(0xe00000, 0xe7ffff).rw(m_crtc, FUNC(x68k_crtc_device::tvram_r), FUNC(x68k_crtc_device::tvram_w)); + map(0xe80000, 0xe81fff).rw(m_crtc, FUNC(x68k_crtc_device::crtc_r), FUNC(x68k_crtc_device::crtc_w)); map(0xe82000, 0xe821ff).rw(m_gfxpalette, FUNC(palette_device::read16), FUNC(palette_device::write16)).share("gfxpalette"); map(0xe82200, 0xe823ff).rw(m_pcgpalette, FUNC(palette_device::read16), FUNC(palette_device::write16)).share("pcgpalette"); map(0xe82400, 0xe83fff).rw(FUNC(x68k_state::x68k_vid_r), FUNC(x68k_state::x68k_vid_w)); @@ -1209,9 +1194,9 @@ void x68k_state::x68030_map(address_map &map) map.global_mask(0x00ffffff); // Still only has 24-bit address space map(0x000000, 0xbffffb).rw(FUNC(x68k_state::x68k_emptyram_r), FUNC(x68k_state::x68k_emptyram_w)); map(0xbffffc, 0xbfffff).rw(FUNC(x68k_state::x68k_rom0_r), FUNC(x68k_state::x68k_rom0_w)); - map(0xc00000, 0xdfffff).rw(FUNC(x68k_state::x68k_gvram_r), FUNC(x68k_state::x68k_gvram_w)); - map(0xe00000, 0xe7ffff).rw(FUNC(x68k_state::x68k_tvram_r), FUNC(x68k_state::x68k_tvram_w)); - map(0xe80000, 0xe81fff).rw(FUNC(x68k_state::x68k_crtc_r), FUNC(x68k_state::x68k_crtc_w)); + map(0xc00000, 0xdfffff).rw(m_crtc, FUNC(x68k_crtc_device::gvram_r), FUNC(x68k_crtc_device::gvram_w)); + map(0xe00000, 0xe7ffff).rw(m_crtc, FUNC(x68k_crtc_device::tvram_r), FUNC(x68k_crtc_device::tvram_w)); + map(0xe80000, 0xe81fff).rw(m_crtc, FUNC(x68k_crtc_device::crtc_r), FUNC(x68k_crtc_device::crtc_w)); map(0xe82000, 0xe821ff).rw(m_gfxpalette, FUNC(palette_device::read32), FUNC(palette_device::write32)).share("gfxpalette"); map(0xe82200, 0xe823ff).rw(m_pcgpalette, FUNC(palette_device::read32), FUNC(palette_device::write32)).share("pcgpalette"); map(0xe82400, 0xe83fff).rw(FUNC(x68k_state::x68k_vid_r), FUNC(x68k_state::x68k_vid_w)); @@ -1282,9 +1267,6 @@ static INPUT_PORTS_START( x68000 ) PORT_CONFNAME( 0x02, 0x02, "Enable fake bus errors") PORT_CONFSETTING( 0x00, DEF_STR( Off )) PORT_CONFSETTING( 0x02, DEF_STR( On )) - PORT_CONFNAME( 0x04, 0x04, "Enable partial updates on each HSync") - PORT_CONFSETTING( 0x00, DEF_STR( Off )) - PORT_CONFSETTING( 0x04, DEF_STR( On )) PORT_START("mouse1") // mouse buttons PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_BUTTON9) PORT_NAME("Left mouse button") PORT_CODE(MOUSECODE_BUTTON1) @@ -1492,36 +1474,15 @@ void x68k_state::machine_reset() memset(m_ram->pointer(),0,m_ram->size()); memcpy(m_ram->pointer(),romdata,8); - // initialise CRTC, set registers to defaults for the standard text mode (768x512) - m_crtc.reg[0] = 137; // Horizontal total (in characters) - m_crtc.reg[1] = 14; // Horizontal sync end - m_crtc.reg[2] = 28; // Horizontal start - m_crtc.reg[3] = 124; // Horizontal end - m_crtc.reg[4] = 567; // Vertical total - m_crtc.reg[5] = 5; // Vertical sync end - m_crtc.reg[6] = 40; // Vertical start - m_crtc.reg[7] = 552; // Vertical end - m_crtc.reg[8] = 27; // Horizontal adjust - - m_scanline = m_screen->vpos();// = m_crtc.reg[6]; // Vertical start - - // start VBlank timer - m_crtc.vblank = 1; - attotime const irq_time = m_screen->time_until_pos(m_crtc.reg[6],2); - m_vblank_irq->adjust(irq_time); - - // start HBlank timer - m_scanline_timer->adjust(m_screen->scan_period(), 1); - /// TODO: get callbacks to trigger these m_mfpdev->i0_w(1); // alarm m_mfpdev->i1_w(1); // expon m_mfpdev->i2_w(0); // pow sw m_mfpdev->i3_w(1); // fmirq - m_mfpdev->i4_w(1); // v-disp + //m_mfpdev->i4_w(1); // v-disp m_mfpdev->i5_w(1); // unused (always set) - m_mfpdev->i6_w(1); // cirq - m_mfpdev->i7_w(1); // h-sync + //m_mfpdev->i6_w(1); // cirq + //m_mfpdev->i7_w(1); // h-sync // reset output values output().set_value("key_led_kana",1); @@ -1591,9 +1552,6 @@ void x68k_state::init_x68000() // copy last half of BIOS to a user region, to use for initial startup memcpy(user2,(rom+0xff0000),0x10000); - m_scanline_timer = timer_alloc(TIMER_X68K_HSYNC); - m_raster_irq = timer_alloc(TIMER_X68K_CRTC_RASTER_IRQ); - m_vblank_irq = timer_alloc(TIMER_X68K_CRTC_VBLANK_IRQ); m_mouse_timer = timer_alloc(TIMER_X68K_SCC_ACK); m_led_timer = timer_alloc(TIMER_X68K_LED); m_net_timer = timer_alloc(TIMER_X68K_NET_IRQ); @@ -1650,16 +1608,16 @@ MACHINE_CONFIG_START(x68k_state::x68000) MCFG_QUANTUM_TIME(attotime::from_hz(60)) /* device hardware */ - MCFG_DEVICE_ADD(MC68901_TAG, MC68901, 16_MHz_XTAL / 4) + MCFG_DEVICE_ADD("mc68901", MC68901, 16_MHz_XTAL / 4) MCFG_MC68901_TIMER_CLOCK(16_MHz_XTAL / 4) MCFG_MC68901_RX_CLOCK(0) MCFG_MC68901_TX_CLOCK(0) MCFG_MC68901_OUT_IRQ_CB(WRITELINE(*this, x68k_state, mfp_irq_callback)) - MCFG_MC68901_OUT_TBO_CB(WRITELINE(MC68901_TAG, mc68901_device, clock_w)) + MCFG_MC68901_OUT_TBO_CB(WRITELINE("mc68901", mc68901_device, clock_w)) MCFG_MC68901_OUT_SO_CB(WRITELINE("keyboard", rs232_port_device, write_txd)) MCFG_DEVICE_ADD("keyboard", RS232_PORT, keyboard, "x68k") - MCFG_RS232_RXD_HANDLER(WRITELINE(MC68901_TAG, mc68901_device, write_rx)) + MCFG_RS232_RXD_HANDLER(WRITELINE("mc68901", mc68901_device, write_rx)) MCFG_DEVICE_ADD("ppi8255", I8255A, 0) MCFG_I8255_IN_PORTA_CB(READ8(*this, x68k_state, ppi_port_a_r)) @@ -1678,14 +1636,25 @@ MACHINE_CONFIG_START(x68k_state::x68000) MCFG_DEVICE_ADD("scc", SCC8530, 40_MHz_XTAL / 8) - MCFG_DEVICE_ADD(RP5C15_TAG, RP5C15, 32.768_kHz_XTAL) - MCFG_RP5C15_OUT_ALARM_CB(WRITELINE(MC68901_TAG, mc68901_device, i0_w)) + MCFG_DEVICE_ADD("rp5c15", RP5C15, 32.768_kHz_XTAL) + MCFG_RP5C15_OUT_ALARM_CB(WRITELINE("mc68901", mc68901_device, i0_w)) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) MCFG_SCREEN_RAW_PARAMS(69.55199_MHz_XTAL / 2, 1096, 0, 768, 568, 0, 512) // initial setting MCFG_SCREEN_UPDATE_DRIVER(x68k_state, screen_update_x68000) + VINAS(config, m_crtc, 38.86363_MHz_XTAL); + m_crtc->set_screen("screen"); + m_crtc->vdisp_cb().set("mc68901", FUNC(mc68901_device::i4_w)); + m_crtc->vdisp_cb().append("mc68901", FUNC(mc68901_device::tai_w)); + m_crtc->rint_cb().set("mc68901", FUNC(mc68901_device::i6_w)); + m_crtc->hsync_cb().set("mc68901", FUNC(mc68901_device::i7_w)); + m_crtc->tvram_read_cb().set(FUNC(x68k_state::tvram_read)); + m_crtc->tvram_write_cb().set(FUNC(x68k_state::tvram_write)); + m_crtc->gvram_read_cb().set(FUNC(x68k_state::gvram_read)); + m_crtc->gvram_write_cb().set(FUNC(x68k_state::gvram_write)); + MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "pcgpalette", gfxdecode_device::empty) MCFG_PALETTE_ADD("gfxpalette", 256) @@ -1762,6 +1731,17 @@ MACHINE_CONFIG_START(x68k_state::x68ksupr) MCFG_LEGACY_SCSI_PORT("scsi") MCFG_MB89352A_IRQ_CB(WRITELINE(*this, x68k_state, x68k_scsi_irq)) MCFG_MB89352A_DRQ_CB(WRITELINE(*this, x68k_state, x68k_scsi_drq)) + + VICON(config.replace(), m_crtc, 38.86363_MHz_XTAL); + m_crtc->set_screen("screen"); + m_crtc->vdisp_cb().set("mc68901", FUNC(mc68901_device::i4_w)); + m_crtc->vdisp_cb().append("mc68901", FUNC(mc68901_device::tai_w)); + m_crtc->rint_cb().set("mc68901", FUNC(mc68901_device::i6_w)); + m_crtc->hsync_cb().set("mc68901", FUNC(mc68901_device::i7_w)); + m_crtc->tvram_read_cb().set(FUNC(x68k_state::tvram_read)); + m_crtc->tvram_write_cb().set(FUNC(x68k_state::tvram_write)); + m_crtc->gvram_read_cb().set(FUNC(x68k_state::gvram_read)); + m_crtc->gvram_write_cb().set(FUNC(x68k_state::gvram_write)); MACHINE_CONFIG_END MACHINE_CONFIG_START(x68k_state::x68kxvi) diff --git a/src/mame/includes/x68k.h b/src/mame/includes/x68k.h index cbd8efbbaf7..9c59c5e9c0b 100644 --- a/src/mame/includes/x68k.h +++ b/src/mame/includes/x68k.h @@ -22,14 +22,12 @@ #include "sound/flt_vol.h" #include "sound/okim6258.h" #include "sound/ym2151.h" +#include "video/x68k_crtc.h" #include "bus/x68k/x68kexp.h" #include "emupal.h" #include "screen.h" -#define MC68901_TAG "mc68901" -#define RP5C15_TAG "rp5c15" - #define GFX16 0 #define GFX256 1 #define GFX65536 2 @@ -43,11 +41,12 @@ public: , m_okim6258(*this, "okim6258") , m_hd63450(*this, "hd63450") , m_ram(*this, RAM_TAG) + , m_crtc(*this, "crtc") , m_gfxdecode(*this, "gfxdecode") , m_gfxpalette(*this, "gfxpalette") , m_pcgpalette(*this, "pcgpalette") - , m_mfpdev(*this, MC68901_TAG) - , m_rtc(*this, RP5C15_TAG) + , m_mfpdev(*this, "mc68901") + , m_rtc(*this, "rp5c15") , m_scc(*this, "scc") , m_ym2151(*this, "ym2151") , m_ppi(*this, "ppi8255") @@ -93,11 +92,6 @@ private: TIMER_MD_6BUTTON_PORT2_TIMEOUT, TIMER_X68K_BUS_ERROR, TIMER_X68K_NET_IRQ, - TIMER_X68K_CRTC_OPERATION_END, - TIMER_X68K_HSYNC, - TIMER_X68K_CRTC_RASTER_END, - TIMER_X68K_CRTC_RASTER_IRQ, - TIMER_X68K_CRTC_VBLANK_IRQ, TIMER_X68K_FDC_TC, TIMER_X68K_ADPCM }; @@ -106,6 +100,7 @@ private: required_device m_okim6258; required_device m_hd63450; required_device m_ram; + required_device m_crtc; required_device m_gfxdecode; required_device m_gfxpalette; required_device m_pcgpalette; @@ -182,39 +177,6 @@ private: int clock; // ADPCM clock speed } m_adpcm; struct - { - unsigned short reg[24]; // registers - int operation; // operation port (0xe80481) - int vblank; // 1 if in VBlank - int hblank; // 1 if in HBlank - int htotal; // Horizontal Total (in characters) - int vtotal; // Vertical Total - int hbegin; // Horizontal Begin - int vbegin; // Vertical Begin - int hend; // Horizontal End - int vend; // Vertical End - int hsync_end; // Horizontal Sync End - int vsync_end; // Vertical Sync End - int hsyncadjust; // Horizontal Sync Adjustment - float hmultiple; // Horizontal pixel multiplier - float vmultiple; // Vertical scanline multiplier (x2 for doublescan modes) - int height; - int width; - int visible_height; - int visible_width; - int hshift; - int vshift; - int video_width; // horizontal total (in pixels) - int video_height; // vertical total - int bg_visible_height; - int bg_visible_width; - int bg_hshift; - int bg_vshift; - int bg_hvres; // bits 0,1 = H-Res, bits 2,3 = V-Res, bit 4 = L/H Freq (0=15.98kHz, 1=31.5kHz) - int bg_double; // 1 if PCG is to be doubled. - int interlace; // 1024 vertical resolution is interlaced - } m_crtc; // CRTC - struct { // video controller at 0xe82000 unsigned short reg[3]; int text_pri; @@ -223,6 +185,12 @@ private: int gfxlayer_pri[4]; // block displayed for each priority level int tile8_dirty[1024]; int tile16_dirty[256]; + int bg_visible_height; + int bg_visible_width; + int bg_hshift; + int bg_vshift; + int bg_hvres; // bits 0,1 = H-Res, bits 2,3 = V-Res, bit 4 = L/H Freq (0=15.98kHz, 1=31.5kHz) + int bg_double; // 1 if PCG is to be doubled. } m_video; struct { @@ -254,7 +222,6 @@ private: uint8_t m_ppi_port[3]; int m_current_vector[8]; uint8_t m_current_irq_line; - unsigned int m_scanline; int m_led_state; emu_timer* m_mouse_timer; emu_timer* m_led_timer; @@ -262,9 +229,6 @@ private: unsigned char m_scc_prev; uint16_t m_ppi_prev; int m_mfp_prev; - emu_timer* m_scanline_timer; - emu_timer* m_raster_irq; - emu_timer* m_vblank_irq; emu_timer* m_fdc_tc; emu_timer* m_adpcm_timer; emu_timer* m_bus_error_timer; @@ -274,7 +238,6 @@ private: tilemap_t* m_bg0_16; tilemap_t* m_bg1_16; int m_sprite_shift; - int m_oddscanline; bool m_is_32bit; TILE_GET_INFO_MEMBER(x68k_get_bg0_tile); @@ -290,11 +253,6 @@ private: TIMER_CALLBACK_MEMBER(md_6button_port2_timeout); TIMER_CALLBACK_MEMBER(x68k_bus_error); TIMER_CALLBACK_MEMBER(x68k_net_irq); - TIMER_CALLBACK_MEMBER(x68k_crtc_operation_end); - TIMER_CALLBACK_MEMBER(x68k_hsync); - TIMER_CALLBACK_MEMBER(x68k_crtc_raster_end); - TIMER_CALLBACK_MEMBER(x68k_crtc_raster_irq); - TIMER_CALLBACK_MEMBER(x68k_crtc_vblank_irq); DECLARE_READ8_MEMBER(ppi_port_a_r); DECLARE_READ8_MEMBER(ppi_port_b_r); DECLARE_READ8_MEMBER(ppi_port_c_r); @@ -350,22 +308,17 @@ private: DECLARE_WRITE16_MEMBER(x68k_spritereg_w); DECLARE_READ16_MEMBER(x68k_spriteram_r); DECLARE_WRITE16_MEMBER(x68k_spriteram_w); - DECLARE_WRITE16_MEMBER(x68k_crtc_w); - DECLARE_READ16_MEMBER(x68k_crtc_r); - DECLARE_WRITE16_MEMBER(x68k_gvram_w); - DECLARE_READ16_MEMBER(x68k_gvram_r); - DECLARE_WRITE16_MEMBER(x68k_tvram_w); - DECLARE_READ16_MEMBER(x68k_tvram_r); + DECLARE_READ16_MEMBER(tvram_read); + DECLARE_WRITE16_MEMBER(tvram_write); + DECLARE_READ16_MEMBER(gvram_read); + DECLARE_WRITE16_MEMBER(gvram_write); IRQ_CALLBACK_MEMBER(x68k_int_ack); void x68030_map(address_map &map); void x68k_map(address_map &map); void x68kxvi_map(address_map &map); -private: inline void x68k_plot_pixel(bitmap_rgb32 &bitmap, int x, int y, uint32_t color); - void x68k_crtc_text_copy(int src, int dest, uint8_t planes); - void x68k_crtc_refresh_mode(); void x68k_draw_text(bitmap_rgb32 &bitmap, int xscr, int yscr, rectangle rect); bool x68k_draw_gfx_scanline(bitmap_ind16 &bitmap, rectangle cliprect, uint8_t priority); void x68k_draw_gfx(bitmap_rgb32 &bitmap,rectangle cliprect); diff --git a/src/mame/video/x68k.cpp b/src/mame/video/x68k.cpp index 17fa4658543..17972c5203a 100644 --- a/src/mame/video/x68k.cpp +++ b/src/mame/video/x68k.cpp @@ -92,542 +92,25 @@ bitmap_rgb32* ::x68k_get_gfx_page(int pri,int type) return nullptr; // should never reach here either. } */ -void x68k_state::x68k_crtc_text_copy(int src, int dest, uint8_t planes) -{ - // copys one raster in T-VRAM to another raster - int src_ram = src * 256; // 128 bytes per scanline - int dest_ram = dest * 256; - - // update RAM in each plane - if(planes & 1) - memcpy(&m_tvram[dest_ram],&m_tvram[src_ram],512); - if(planes & 2) - memcpy(&m_tvram[dest_ram+0x10000],&m_tvram[src_ram+0x10000],512); - if(planes & 4) - memcpy(&m_tvram[dest_ram+0x20000],&m_tvram[src_ram+0x20000],512); - if(planes & 8) - memcpy(&m_tvram[dest_ram+0x30000],&m_tvram[src_ram+0x30000],512); -} - -TIMER_CALLBACK_MEMBER(x68k_state::x68k_crtc_operation_end) -{ - int bit = param; - m_crtc.operation &= ~bit; -} - -void x68k_state::x68k_crtc_refresh_mode() -{ -// rectangle rect; -// double scantime; - rectangle scr,visiblescr; - int length; - - // Calculate data from register values - m_crtc.vmultiple = 1; - if((m_crtc.reg[20] & 0x10) != 0 && (m_crtc.reg[20] & 0x0c) == 0) - m_crtc.vmultiple = 2; // 31.5kHz + 256 lines = doublescan - if(m_crtc.interlace != 0) - m_crtc.vmultiple = 0.5f; // 31.5kHz + 1024 lines or 15kHz + 512 lines = interlaced - m_crtc.htotal = (m_crtc.reg[0] + 1) * 8; - m_crtc.vtotal = (m_crtc.reg[4] + 1) / m_crtc.vmultiple; // default is 567 (568 scanlines) - m_crtc.hbegin = (m_crtc.reg[2] * 8) + 1; - m_crtc.hend = (m_crtc.reg[3] * 8); - m_crtc.vbegin = (m_crtc.reg[6]) / m_crtc.vmultiple; - m_crtc.vend = (m_crtc.reg[7] - 1) / m_crtc.vmultiple; - if((m_crtc.vmultiple == 2) && !(m_crtc.reg[7] & 1)) // otherwise if the raster irq line == vblank line, the raster irq fires too late - m_crtc.vend++; - m_crtc.hsync_end = (m_crtc.reg[1]) * 8; - m_crtc.vsync_end = (m_crtc.reg[5]) / m_crtc.vmultiple; - m_crtc.hsyncadjust = m_crtc.reg[8]; - scr.set(0, m_crtc.htotal - 8, 0, m_crtc.vtotal); - if(scr.max_y <= m_crtc.vend) - scr.max_y = m_crtc.vend + 2; - if(scr.max_x <= m_crtc.hend) - scr.max_x = m_crtc.hend + 2; - visiblescr.set(m_crtc.hbegin, m_crtc.hend, m_crtc.vbegin, m_crtc.vend); - - // expand visible area to the size indicated by CRTC reg 20 - length = m_crtc.hend - m_crtc.hbegin; - if (length < m_crtc.width) - { - visiblescr.min_x = m_crtc.hbegin - ((m_crtc.width - length)/2); - visiblescr.max_x = m_crtc.hend + ((m_crtc.width - length)/2); - } - length = m_crtc.vend - m_crtc.vbegin; - if (length < m_crtc.height) - { - visiblescr.min_y = m_crtc.vbegin - ((m_crtc.height - length)/2); - visiblescr.max_y = m_crtc.vend + ((m_crtc.height - length)/2); - } - // bounds check - if(visiblescr.min_x < 0) - visiblescr.min_x = 0; - if(visiblescr.min_y < 0) - visiblescr.min_y = 0; - if(visiblescr.max_x >= scr.max_x) - visiblescr.max_x = scr.max_x - 2; - if(visiblescr.max_y >= scr.max_y - 1) - visiblescr.max_y = scr.max_y - 2; - -// LOG("CRTC regs - %i %i %i %i - %i %i %i %i - %i - %i\n",m_crtc.reg[0],m_crtc.reg[1],m_crtc.reg[2],m_crtc.reg[3], -// m_crtc.reg[4],m_crtc.reg[5],m_crtc.reg[6],m_crtc.reg[7],m_crtc.reg[8],m_crtc.reg[9]); - unsigned div = (m_crtc.reg[20] & 0x03) == 0 ? 4 : 2; - if ((m_crtc.reg[20] & 0x0c) == 0) - div *= BIT(m_crtc.reg[20], 4) ? 3 : 2; - attotime refresh = attotime::from_ticks(scr.max_x * scr.max_y, (BIT(m_crtc.reg[20], 4) ? 69.55199_MHz_XTAL : 38.86363_MHz_XTAL) / div); - LOG("m_screen->configure(%i,%i,[%i,%i,%i,%i],%f)\n", scr.max_x, scr.max_y, visiblescr.min_x, visiblescr.min_y, visiblescr.max_x, visiblescr.max_y, ATTOSECONDS_TO_HZ(refresh.as_attoseconds())); - m_screen->configure(scr.max_x, scr.max_y, visiblescr, refresh.as_attoseconds()); -} - -TIMER_CALLBACK_MEMBER(x68k_state::x68k_hsync) -{ - int hstate = param; - attotime hsync_time; - - m_crtc.hblank = hstate; - m_mfpdev->i7_w(!m_crtc.hblank); - - if(m_crtc.operation & 8) - x68k_crtc_text_copy((m_crtc.reg[22] & 0xff00) >> 8,(m_crtc.reg[22] & 0x00ff),(m_crtc.reg[21] & 0xf)); - - if(m_crtc.vmultiple == 2) // 256-line (doublescan) - { - if(hstate == 1) - { - if(m_oddscanline == 1) - { - int scan = m_screen->vpos(); - if(scan > m_crtc.vend) - scan = m_crtc.vbegin; - hsync_time = m_screen->time_until_pos(scan,(m_crtc.htotal + m_crtc.hend) / 2); - m_scanline_timer->adjust(hsync_time); - if(scan != 0) - { - if((ioport("options")->read() & 0x04)) - { - m_screen->update_partial(scan); - } - } - } - else - { - int scan = m_screen->vpos(); - if(scan > m_crtc.vend) - scan = m_crtc.vbegin; - hsync_time = m_screen->time_until_pos(scan,m_crtc.hend / 2); - m_scanline_timer->adjust(hsync_time); - if(scan != 0) - { - if((ioport("options")->read() & 0x04)) - { - m_screen->update_partial(scan); - } - } - } - } - if(hstate == 0) - { - if(m_oddscanline == 1) - { - int scan = m_screen->vpos(); - if(scan > m_crtc.vend) - scan = m_crtc.vbegin; - else - scan++; - hsync_time = m_screen->time_until_pos(scan,m_crtc.hbegin / 2); - m_scanline_timer->adjust(hsync_time, 1); - m_oddscanline = 0; - } - else - { - hsync_time = m_screen->time_until_pos(m_screen->vpos(),(m_crtc.htotal + m_crtc.hbegin) / 2); - m_scanline_timer->adjust(hsync_time, 1); - m_oddscanline = 1; - } - } - } - else // 512-line - { - if(hstate == 1) - { - int scan = m_screen->vpos(); - if(scan > m_crtc.vend) - scan = 0; - hsync_time = m_screen->time_until_pos(scan,m_crtc.hend); - m_scanline_timer->adjust(hsync_time); - if(scan != 0) - { - if((ioport("options")->read() & 0x04)) - { - m_screen->update_partial(scan); - } - } - } - if(hstate == 0) - { - hsync_time = m_screen->time_until_pos(m_screen->vpos()+1,m_crtc.hbegin); - m_scanline_timer->adjust(hsync_time, 1); - } - } -} -TIMER_CALLBACK_MEMBER(x68k_state::x68k_crtc_raster_end) +READ16_MEMBER(x68k_state::tvram_read) { - m_mfpdev->i6_w(1); -} - -TIMER_CALLBACK_MEMBER(x68k_state::x68k_crtc_raster_irq) -{ - int scan = param; - attotime irq_time; - attotime end_time; - - if(scan <= m_crtc.vtotal) - { - m_mfpdev->i6_w(0); - m_screen->update_partial(scan); - irq_time = m_screen->time_until_pos(scan,m_crtc.hbegin); - // end of HBlank period clears GPIP6 also? - end_time = m_screen->time_until_pos(scan,m_crtc.hend); - m_raster_irq->adjust(irq_time, scan); - timer_set(end_time, TIMER_X68K_CRTC_RASTER_END); - LOG("GPIP6: Raster triggered at line %i (%i)\n",scan,m_screen->vpos()); - } -} - -TIMER_CALLBACK_MEMBER(x68k_state::x68k_crtc_vblank_irq) -{ - int val = param; - attotime irq_time; - int vblank_line; - - if(val == 1) // V-DISP on - { - m_crtc.vblank = 1; - vblank_line = m_crtc.vbegin; - irq_time = m_screen->time_until_pos(vblank_line,2); - m_vblank_irq->adjust(irq_time); - LOG("CRTC: VBlank on\n"); - } - if(val == 0) // V-DISP off - { - m_crtc.vblank = 0; - vblank_line = m_crtc.vend; - if(vblank_line > m_crtc.vtotal) - vblank_line = m_crtc.vtotal; - irq_time = m_screen->time_until_pos(vblank_line,2); - m_vblank_irq->adjust(irq_time, 1); - LOG("CRTC: VBlank off\n"); - } - - m_mfpdev->tai_w(!m_crtc.vblank); - m_mfpdev->i4_w(!m_crtc.vblank); -} - - -// CRTC "VINAS 1+2 / VICON" at 0xe80000 -/* 0xe80000 - Registers (all are 16-bit): - * 0 - Horizontal Total (in characters) - * 1 - Horizontal Sync End - * 2 - Horizontal Display Begin - * 3 - Horizontal Display End - * 4 - Vertical Total (in scanlines) - * 5 - Vertical Sync End - * 6 - Vertical Display Begin - * 7 - Vertical Display End - * 8 - Fine Horizontal Sync Adjustment - * 9 - Raster Line (for Raster IRQ mapped to MFP GPIP6) - * 10/11 - Text Layer X and Y Scroll - * 12/13 - Graphic Layer 0 X and Y Scroll - * 14/15 - Graphic Layer 1 X and Y Scroll - * 16/17 - Graphic Layer 2 X and Y Scroll - * 18/19 - Graphic Layer 3 X and Y Scroll - * 20 - bit 12 - Text VRAM mode : 0 = display, 1 = buffer - * bit 11 - Graphic VRAM mode : 0 = display, 1 = buffer - * bit 10 - "Real" screen size : 0 = 512x512, 1 = 1024x1024 - * bits 8,9 - Colour mode : - * 00 = 16 colour 01 = 256 colour - * 10 = Undefined 11 = 65,536 colour - * bit 4 - Horizontal Frequency : 0 = 15.98kHz, 1 = 31.50kHz - * bits 2,3 - Vertical dots : - * 00 = 256 01 = 512 - * 10 or 11 = 1024 (interlaced) - * bits 0,1 - Horizontal dots : - * 00 = 256 01 = 512 - * 10 = 768 11 = 50MHz clock mode (Compact XVI or later) - * 21 - bit 9 - Text Screen Access Mask Enable - * bit 8 - Text Screen Simultaneous Plane Access Enable - * bits 4-7 - Text Screen Simultaneous Plane Access Select - * bits 0-3 - Text Screen Line Copy Plane Select - * Graphic Screen High-speed Clear Page Select - * 22 - Text Screen Line Copy - * bits 15-8 - Source Line - * bits 7-0 - Destination Line - * 23 - Text Screen Mask Pattern - * - * 0xe80481 - Operation Port (8-bit): - * bit 3 - Text Screen Line Copy Begin - * bit 1 - Graphic Screen High-speed Clear Begin - * bit 0 - Image Taking Begin (?) - * Operation Port bits are cleared automatically when the requested - * operation is completed. - */ -WRITE16_MEMBER(x68k_state::x68k_crtc_w ) -{ - if (offset < 0x24) - COMBINE_DATA(m_crtc.reg+offset); - switch(offset) - { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - x68k_crtc_refresh_mode(); - break; - case 9: // CRTC raster IRQ (GPIP6) - { - attotime irq_time; - data = m_crtc.reg[9]; - irq_time = m_screen->time_until_pos((data) / m_crtc.vmultiple,2); - - if(data != m_screen->vpos()) - m_mfpdev->i6_w(1); - if(irq_time.as_double() > 0) - m_raster_irq->adjust(irq_time, (data) / m_crtc.vmultiple); - } - LOG("CRTC: Write to raster IRQ register - %i\n",data); - break; - case 20: - if(ACCESSING_BITS_0_7) - { - m_crtc.interlace = 0; - switch(data & 0x0c) - { - case 0x00: - m_crtc.height = 256; - break; - case 0x08: - case 0x0c: // TODO: 1024 vertical, if horizontal freq = 31kHz - m_crtc.height = 512; - m_crtc.interlace = 1; // if 31kHz, 1024 lines = interlaced - break; - case 0x04: - m_crtc.height = 512; - if(!(m_crtc.reg[20] & 0x0010)) // if 15kHz, 512 lines = interlaced - m_crtc.interlace = 1; - break; - } - switch(data & 0x03) - { - case 0x00: - m_crtc.width = 256; - break; - case 0x01: - m_crtc.width = 512; - break; - case 0x02: - case 0x03: // 0x03 = 50MHz clock mode (XVI only) - m_crtc.width = 768; - break; - } - } -/* if(ACCESSING_BITS_8_15) - { - m_crtc.interlace = 0; - if(data & 0x0400) - m_crtc.interlace = 1; - }*/ - logerror("CRTC: Register 20 = %04x\n", m_crtc.reg[20]); - x68k_crtc_refresh_mode(); - break; - case 576: // operation register - m_crtc.operation = data; - if(data & 0x02) // high-speed graphic screen clear - { - memset(&m_gvram[0],0,0x40000); - timer_set(attotime::from_msec(10), TIMER_X68K_CRTC_OPERATION_END, 0x02); // time taken to do operation is a complete guess. - } - break; - } -// LOG("%s CRTC: Wrote %04x to CRTC register %i\n",machine().describe_context(),data,offset); -} - -READ16_MEMBER(x68k_state::x68k_crtc_r ) -{ - if(offset < 24) - { -// LOG("%s CRTC: Read %04x from CRTC register %i\n",machine().describe_context(),m_crtc.reg[offset],offset); - switch(offset) - { - case 9: - return 0; - case 10: // Text X/Y scroll - case 11: - case 12: // Graphic layer 0 scroll - case 13: - return m_crtc.reg[offset] & 0x3ff; - case 14: // Graphic layer 1 scroll - case 15: - case 16: // Graphic layer 2 scroll - case 17: - case 18: // Graphic layer 3 scroll - case 19: - return m_crtc.reg[offset] & 0x1ff; - default: - return m_crtc.reg[offset]; - } - } - if(offset == 576) // operation port, operation bits are set to 0 when operation is complete - return m_crtc.operation; -// LOG("CRTC: [%08x] Read from unknown CRTC register %i\n",activecpu_get_pc(),offset); - return 0xffff; -} - -WRITE16_MEMBER(x68k_state::x68k_gvram_w ) -{ -// int xloc,yloc,pageoffset; - /* - G-VRAM usage is determined by colour depth and "real" screen size. - - For screen size of 1024x1024, all G-VRAM space is used, in one big page. - At 1024x1024 real screen size, colour depth is always 4bpp, and ranges from - 0xc00000-0xdfffff. - - For screen size of 512x512, the colour depth determines the page usage. - 16 colours = 4 pages - 256 colours = 2 pages - 65,536 colours = 1 page - Page 1 - 0xc00000-0xc7ffff Page 2 - 0xc80000-0xcfffff - Page 3 - 0xd00000-0xd7ffff Page 4 - 0xd80000-0xdfffff - */ - - // handle different G-VRAM page setups - if(m_crtc.reg[20] & 0x0800) // G-VRAM set to buffer - { - if(offset < 0x40000) - COMBINE_DATA(&m_gvram[offset]); - } - else - { - switch(m_crtc.reg[20] & 0x0300) - { - case 0x0300: - if(offset < 0x40000) - COMBINE_DATA(&m_gvram[offset]); - break; - case 0x0100: - if(offset < 0x40000) - { - m_gvram[offset] = (m_gvram[offset] & 0xff00) | (data & 0x00ff); - } - if(offset >= 0x40000 && offset < 0x80000) - { - m_gvram[offset-0x40000] = (m_gvram[offset-0x40000] & 0x00ff) | ((data & 0x00ff) << 8); - } - break; - case 0x0000: - if(offset < 0x40000) - { - m_gvram[offset] = (m_gvram[offset] & 0xfff0) | (data & 0x000f); - } - if(offset >= 0x40000 && offset < 0x80000) - { - m_gvram[offset-0x40000] = (m_gvram[offset-0x40000] & 0xff0f) | ((data & 0x000f) << 4); - } - if(offset >= 0x80000 && offset < 0xc0000) - { - m_gvram[offset-0x80000] = (m_gvram[offset-0x80000] & 0xf0ff) | ((data & 0x000f) << 8); - } - if(offset >= 0xc0000 && offset < 0x100000) - { - m_gvram[offset-0xc0000] = (m_gvram[offset-0xc0000] & 0x0fff) | ((data & 0x000f) << 12); - } - break; - default: - logerror("G-VRAM written while layer setup is undefined.\n"); - } - } + return m_tvram[offset]; } -WRITE16_MEMBER(x68k_state::x68k_tvram_w ) +WRITE16_MEMBER(x68k_state::tvram_write) { - uint16_t text_mask; - - text_mask = ~(m_crtc.reg[23]) & mem_mask; - - if(!(m_crtc.reg[21] & 0x0200)) // text access mask enable - text_mask = 0xffff & mem_mask; - - mem_mask = text_mask; - - if(m_crtc.reg[21] & 0x0100) - { // simultaneous T-VRAM plane access (I think ;)) - int plane,wr; - offset = offset & 0x00ffff; - wr = (m_crtc.reg[21] & 0x00f0) >> 4; - for(plane=0;plane<4;plane++) - { - if(wr & (1 << plane)) - { - COMBINE_DATA(&m_tvram[offset+0x10000*plane]); - } - } - } - else - { - COMBINE_DATA(&m_tvram[offset]); - } + COMBINE_DATA(&m_tvram[offset]); } -READ16_MEMBER(x68k_state::x68k_gvram_r ) +READ16_MEMBER(x68k_state::gvram_read) { - uint16_t ret = 0; - - if(m_crtc.reg[20] & 0x0800) // G-VRAM set to buffer - return m_gvram[offset]; - - switch(m_crtc.reg[20] & 0x0300) // colour setup determines G-VRAM use - { - case 0x0300: // 65,536 colour (RGB) - 16-bits per word - if(offset < 0x40000) - ret = m_gvram[offset]; - else - ret = 0xffff; - break; - case 0x0100: // 256 colour (paletted) - 8 bits per word - if(offset < 0x40000) - ret = m_gvram[offset] & 0x00ff; - if(offset >= 0x40000 && offset < 0x80000) - ret = (m_gvram[offset-0x40000] & 0xff00) >> 8; - if(offset >= 0x80000) - ret = 0xffff; - break; - case 0x0000: // 16 colour (paletted) - 4 bits per word - if(offset < 0x40000) - ret = m_gvram[offset] & 0x000f; - if(offset >= 0x40000 && offset < 0x80000) - ret = (m_gvram[offset-0x40000] & 0x00f0) >> 4; - if(offset >= 0x80000 && offset < 0xc0000) - ret = (m_gvram[offset-0x80000] & 0x0f00) >> 8; - if(offset >= 0xc0000 && offset < 0x100000) - ret = (m_gvram[offset-0xc0000] & 0xf000) >> 12; - break; - default: - logerror("G-VRAM read while layer setup is undefined.\n"); - ret = 0xffff; - } - - return ret; + return m_gvram[offset]; } -READ16_MEMBER(x68k_state::x68k_tvram_r ) +WRITE16_MEMBER(x68k_state::gvram_write) { - return m_tvram[offset]; + COMBINE_DATA(&m_gvram[offset]); } WRITE16_MEMBER(x68k_state::x68k_spritereg_w ) @@ -636,44 +119,44 @@ WRITE16_MEMBER(x68k_state::x68k_spritereg_w ) switch(offset) { case 0x400: - m_bg0_8->set_scrollx(0,(data - m_crtc.hbegin - m_crtc.bg_hshift) & 0x3ff); - m_bg0_16->set_scrollx(0,(data - m_crtc.hbegin - m_crtc.bg_hshift) & 0x3ff); + m_bg0_8->set_scrollx(0,(data - m_crtc->hbegin() - m_video.bg_hshift) & 0x3ff); + m_bg0_16->set_scrollx(0,(data - m_crtc->hbegin() - m_video.bg_hshift) & 0x3ff); break; case 0x401: - m_bg0_8->set_scrolly(0,(data - m_crtc.vbegin) & 0x3ff); - m_bg0_16->set_scrolly(0,(data - m_crtc.vbegin) & 0x3ff); + m_bg0_8->set_scrolly(0,(data - m_crtc->vbegin()) & 0x3ff); + m_bg0_16->set_scrolly(0,(data - m_crtc->vbegin()) & 0x3ff); break; case 0x402: - m_bg1_8->set_scrollx(0,(data - m_crtc.hbegin - m_crtc.bg_hshift) & 0x3ff); - m_bg1_16->set_scrollx(0,(data - m_crtc.hbegin - m_crtc.bg_hshift) & 0x3ff); + m_bg1_8->set_scrollx(0,(data - m_crtc->hbegin() - m_video.bg_hshift) & 0x3ff); + m_bg1_16->set_scrollx(0,(data - m_crtc->hbegin() - m_video.bg_hshift) & 0x3ff); break; case 0x403: - m_bg1_8->set_scrolly(0,(data - m_crtc.vbegin) & 0x3ff); - m_bg1_16->set_scrolly(0,(data - m_crtc.vbegin) & 0x3ff); + m_bg1_8->set_scrolly(0,(data - m_crtc->vbegin()) & 0x3ff); + m_bg1_16->set_scrolly(0,(data - m_crtc->vbegin()) & 0x3ff); break; case 0x406: // BG H-DISP (normally equals CRTC reg 2 value + 4) if(data != 0x00ff) { - m_crtc.bg_visible_width = (m_crtc.reg[3] - ((data & 0x003f) - 4)) * 8; - m_crtc.bg_hshift = ((data - (m_crtc.reg[2]+4)) * 8); - if(m_crtc.bg_hshift > 0) - m_crtc.bg_hshift = 0; + m_video.bg_visible_width = m_crtc->hend() - ((data & 0x003f) - 4) * 8; + m_video.bg_hshift = ((data - 4) * 8) - (m_crtc->hbegin() - 1); + if(m_video.bg_hshift > 0) + m_video.bg_hshift = 0; } break; case 0x407: // BG V-DISP (like CRTC reg 6) - m_crtc.bg_vshift = m_crtc.vshift; + m_video.bg_vshift = m_crtc->vshift(); break; case 0x408: // BG H/V-Res - m_crtc.bg_hvres = data & 0x1f; + m_video.bg_hvres = data & 0x1f; if(data != 0xff) { // Handle when the PCG is using 256 and the CRTC is using 512 - if((m_crtc.bg_hvres & 0x0c) == 0x00 && (m_crtc.reg[20] & 0x0c) == 0x04) - m_crtc.bg_double = 2; + if((m_video.bg_hvres & 0x0c) == 0x00 && m_crtc->vfactor() == 1) + m_video.bg_double = 2; else - m_crtc.bg_double = 1; + m_video.bg_double = 1; } else - m_crtc.bg_double = 1; + m_video.bg_double = 1; break; } } @@ -724,7 +207,7 @@ void x68k_state::x68k_draw_text(bitmap_rgb32 &bitmap, int xscr, int yscr, rectan for(line=rect.min_y;line<=rect.max_y;line++) // per scanline { // adjust for scroll registers - loc = (((line - m_crtc.vbegin) + yscr) & 0x3ff) * 64; + loc = (((line - m_crtc->vbegin()) + yscr) & 0x3ff) * 64; loc += (xscr / 16) & 0x7f; loc &= 0xffff; bit = 15 - (xscr & 0x0f); @@ -763,16 +246,16 @@ bool x68k_state::x68k_draw_gfx_scanline( bitmap_ind16 &bitmap, rectangle cliprec for(scanline=cliprect.min_y;scanline<=cliprect.max_y;scanline++) // per scanline { - if(m_crtc.reg[20] & 0x0400) // 1024x1024 "real" screen size - use 1024x1024 16-colour gfx layer + if(m_crtc->is_1024x1024()) // 1024x1024 "real" screen size - use 1024x1024 16-colour gfx layer { // adjust for scroll registers if(m_video.reg[2] & 0x0010 && priority == m_video.gfxlayer_pri[0]) { - xscr = (m_crtc.reg[12] & 0x3ff); - yscr = (m_crtc.reg[13] & 0x3ff); - lineoffset = (((scanline - m_crtc.vbegin) + yscr) & 0x3ff) * 1024; + xscr = (m_crtc->xscr_gfx(0) & 0x3ff); + yscr = (m_crtc->yscr_gfx(0) & 0x3ff); + lineoffset = (((scanline - m_crtc->vbegin()) + yscr) & 0x3ff) * 1024; loc = xscr & 0x3ff; - for(pixel=m_crtc.hbegin;pixel<=m_crtc.hend;pixel++) + for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++) { switch(lineoffset & 0xc0000) { @@ -810,14 +293,14 @@ bool x68k_state::x68k_draw_gfx_scanline( bitmap_ind16 &bitmap, rectangle cliprec switch(m_video.reg[0] & 0x03) { case 0x00: // 16 colours - xscr = ((m_crtc.reg[12+(page*2)])) & 0x1ff; - yscr = ((m_crtc.reg[13+(page*2)])) & 0x1ff; - lineoffset = (((scanline - m_crtc.vbegin) + yscr) & 0x1ff) * 512; + xscr = m_crtc->xscr_gfx(page) & 0x1ff; + yscr = m_crtc->yscr_gfx(page) & 0x1ff; + lineoffset = (((scanline - m_crtc->vbegin()) + yscr) & 0x1ff) * 512; loc = xscr & 0x1ff; shift = 4; if((m_video.reg[2] & 0x1a00) == 0x1a00) ret = true; - for(pixel=m_crtc.hbegin;pixel<=m_crtc.hend;pixel++) + for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++) { colour = ((m_gvram[lineoffset + loc] >> page*shift) & 0x000f); if(ret && (colour & 1)) @@ -848,14 +331,14 @@ bool x68k_state::x68k_draw_gfx_scanline( bitmap_ind16 &bitmap, rectangle cliprec case 0x01: // 256 colours if(page == 0 || page == 2) { - xscr = ((m_crtc.reg[12+(page*2)])) & 0x1ff; - yscr = ((m_crtc.reg[13+(page*2)])) & 0x1ff; - lineoffset = (((scanline - m_crtc.vbegin) + yscr) & 0x1ff) * 512; + xscr = m_crtc->xscr_gfx(page) & 0x1ff; + yscr = m_crtc->yscr_gfx(page) & 0x1ff; + lineoffset = (((scanline - m_crtc->vbegin()) + yscr) & 0x1ff) * 512; loc = xscr & 0x1ff; shift = 4; if((m_video.reg[2] & 0x1a00) == 0x1a00) ret = true; - for(pixel=m_crtc.hbegin;pixel<=m_crtc.hend;pixel++) + for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++) { colour = ((m_gvram[lineoffset + loc] >> page*shift) & 0x00ff); if(ret && (colour & 1)) @@ -885,11 +368,11 @@ bool x68k_state::x68k_draw_gfx_scanline( bitmap_ind16 &bitmap, rectangle cliprec } break; case 0x03: // 65536 colours - xscr = ((m_crtc.reg[12])) & 0x1ff; - yscr = ((m_crtc.reg[13])) & 0x1ff; - lineoffset = (((scanline - m_crtc.vbegin) + yscr) & 0x1ff) * 512; + xscr = m_crtc->xscr_gfx(0) & 0x1ff; + yscr = m_crtc->yscr_gfx(0) & 0x1ff; + lineoffset = (((scanline - m_crtc->vbegin()) + yscr) & 0x1ff) * 512; loc = xscr & 0x1ff; - for(pixel=m_crtc.hbegin;pixel<=m_crtc.hend;pixel++) + for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++) { colour = m_gvram[lineoffset + loc]; if(colour || (priority == 3)) @@ -913,7 +396,7 @@ void x68k_state::x68k_draw_gfx(bitmap_rgb32 &bitmap,rectangle cliprect) //int xscr,yscr; //int gpage; - if(m_crtc.reg[20] & 0x0800) // if graphic layers are set to buffer, then they aren't visible + if(m_crtc->gfx_layer_buffer()) // if graphic layers are set to buffer, then they aren't visible return; m_gfxbitmap.fill(0, cliprect); @@ -929,7 +412,7 @@ void x68k_state::x68k_draw_gfx(bitmap_rgb32 &bitmap,rectangle cliprect) { uint16_t colour; bool blend = false; - for(pixel=m_crtc.hbegin;pixel<=m_crtc.hend;pixel++) + for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++) { if((m_video.reg[0] & 0x03) == 3) { @@ -1024,15 +507,15 @@ void x68k_state::x68k_draw_sprites(bitmap_ind16 &bitmap, int priority, rectangle int sx = (m_spritereg[ptr+0] & 0x3ff) - 16; int sy = (m_spritereg[ptr+1] & 0x3ff) - 16; - rect.min_x=m_crtc.hshift; - rect.min_y=m_crtc.vshift; - rect.max_x=rect.min_x + m_crtc.visible_width-1; - rect.max_y=rect.min_y + m_crtc.visible_height-1; + rect.min_x=m_crtc->hshift(); + rect.min_y=m_crtc->vshift(); + rect.max_x=rect.min_x + m_crtc->visible_width()-1; + rect.max_y=rect.min_y + m_crtc->visible_height()-1; - sx += m_crtc.bg_hshift; + sx += m_video.bg_hshift; sx += m_sprite_shift; - m_gfxdecode->gfx(1)->zoom_transpen(bitmap,cliprect,code,colour,xflip,yflip,m_crtc.hbegin+sx,m_crtc.vbegin+(sy*m_crtc.bg_double),0x10000,0x10000*m_crtc.bg_double,0x00); + m_gfxdecode->gfx(1)->zoom_transpen(bitmap,cliprect,code,colour,xflip,yflip,m_crtc->hbegin()+sx,m_crtc->vbegin()+(sy*m_video.bg_double),0x10000,0x10000*m_video.bg_double,0x00); } } } @@ -1147,19 +630,19 @@ uint32_t x68k_state::screen_update_x68000(screen_device &screen, bitmap_rgb32 &b x68k_bg0 = m_bg0_16; x68k_bg1 = m_bg1_16; } -// rect.max_x=m_crtc.width; -// rect.max_y=m_crtc.height; +// rect.max_x=m_crtc->width(); +// rect.max_y=m_crtc->height(); bitmap.fill(0, cliprect); if(m_sysport.contrast == 0) // if monitor contrast is 0, then don't bother displaying anything return 0; - rect.min_x=m_crtc.hbegin; - rect.min_y=m_crtc.vbegin; -// rect.max_x=rect.min_x + m_crtc.visible_width-1; -// rect.max_y=rect.min_y + m_crtc.visible_height-1; - rect.max_x=m_crtc.hend; - rect.max_y=m_crtc.vend; + rect.min_x=m_crtc->hbegin(); + rect.min_y=m_crtc->vbegin(); +// rect.max_x=rect.min_x + m_crtc->visible_width()-1; +// rect.max_y=rect.min_y + m_crtc->visible_height()-1; + rect.max_x=m_crtc->hend(); + rect.max_y=m_crtc->vend(); if(rect.min_y < cliprect.min_y) rect.min_y = cliprect.min_y; @@ -1198,14 +681,14 @@ uint32_t x68k_state::screen_update_x68000(screen_device &screen, bitmap_rgb32 &b { if((m_spritereg[0x404] & 0x0030) == 0x10) // BG1 TXSEL { - x68k_bg0->set_scrollx(0,(m_spritereg[0x402] - m_crtc.hbegin - m_crtc.bg_hshift) & 0x3ff); - x68k_bg0->set_scrolly(0,(m_spritereg[0x403] - m_crtc.vbegin) & 0x3ff); + x68k_bg0->set_scrollx(0,(m_spritereg[0x402] - m_crtc->hbegin() - m_video.bg_hshift) & 0x3ff); + x68k_bg0->set_scrolly(0,(m_spritereg[0x403] - m_crtc->vbegin()) & 0x3ff); x68k_bg0->draw(screen, m_pcgbitmap,rect,0,0); } else { - x68k_bg1->set_scrollx(0,(m_spritereg[0x402] - m_crtc.hbegin - m_crtc.bg_hshift) & 0x3ff); - x68k_bg1->set_scrolly(0,(m_spritereg[0x403] - m_crtc.vbegin) & 0x3ff); + x68k_bg1->set_scrollx(0,(m_spritereg[0x402] - m_crtc->hbegin() - m_video.bg_hshift) & 0x3ff); + x68k_bg1->set_scrolly(0,(m_spritereg[0x403] - m_crtc->vbegin()) & 0x3ff); x68k_bg1->draw(screen, m_pcgbitmap,rect,0,0); } } @@ -1214,14 +697,14 @@ uint32_t x68k_state::screen_update_x68000(screen_device &screen, bitmap_rgb32 &b { if((m_spritereg[0x404] & 0x0006) == 0x02) // BG0 TXSEL { - x68k_bg0->set_scrollx(0,(m_spritereg[0x400] - m_crtc.hbegin - m_crtc.bg_hshift) & 0x3ff); - x68k_bg0->set_scrolly(0,(m_spritereg[0x401] - m_crtc.vbegin) & 0x3ff); + x68k_bg0->set_scrollx(0,(m_spritereg[0x400] - m_crtc->hbegin() - m_video.bg_hshift) & 0x3ff); + x68k_bg0->set_scrolly(0,(m_spritereg[0x401] - m_crtc->vbegin()) & 0x3ff); x68k_bg0->draw(screen, m_pcgbitmap,rect,0,0); } else { - x68k_bg1->set_scrollx(0,(m_spritereg[0x400] - m_crtc.hbegin - m_crtc.bg_hshift) & 0x3ff); - x68k_bg1->set_scrolly(0,(m_spritereg[0x401] - m_crtc.vbegin) & 0x3ff); + x68k_bg1->set_scrollx(0,(m_spritereg[0x400] - m_crtc->hbegin() - m_video.bg_hshift) & 0x3ff); + x68k_bg1->set_scrolly(0,(m_spritereg[0x401] - m_crtc->vbegin()) & 0x3ff); x68k_bg1->draw(screen, m_pcgbitmap,rect,0,0); } } @@ -1229,7 +712,7 @@ uint32_t x68k_state::screen_update_x68000(screen_device &screen, bitmap_rgb32 &b for(scanline=rect.min_y;scanline<=rect.max_y;scanline++) { - for(pixel=m_crtc.hbegin;pixel<=m_crtc.hend;pixel++) + for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++) { uint8_t colour = m_pcgbitmap.pix16(scanline, pixel) & 0xff; if((colour && (m_pcgpalette->pen(colour) & 0xffffff)) || ((m_video.reg[1] & 0x3000) == 0x2000)) @@ -1241,9 +724,9 @@ uint32_t x68k_state::screen_update_x68000(screen_device &screen, bitmap_rgb32 &b // Text screen if(m_video.reg[2] & 0x0020 && priority == m_video.text_pri) { - xscr = (m_crtc.reg[10] & 0x3ff); - yscr = (m_crtc.reg[11] & 0x3ff); - if(!(m_crtc.reg[20] & 0x1000)) // if text layer is set to buffer, then it's not visible + xscr = (m_crtc->xscr_text() & 0x3ff); + yscr = (m_crtc->yscr_text() & 0x3ff); + if(!m_crtc->text_layer_buffer()) // if text layer is set to buffer, then it's not visible x68k_draw_text(bitmap,xscr,yscr,rect); } } @@ -1253,7 +736,7 @@ uint32_t x68k_state::screen_update_x68000(screen_device &screen, bitmap_rgb32 &b uint16_t colour; for(scanline=rect.min_y;scanline<=rect.max_y;scanline++) { - for(pixel=m_crtc.hbegin;pixel<=m_crtc.hend;pixel++) + for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++) { colour = m_special.pix16(scanline, pixel) & 0xff; if(colour) diff --git a/src/mame/video/x68k_crtc.cpp b/src/mame/video/x68k_crtc.cpp new file mode 100644 index 00000000000..d997b7aefe0 --- /dev/null +++ b/src/mame/video/x68k_crtc.cpp @@ -0,0 +1,642 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald,Carl + +#include "emu.h" +#include "video/x68k_crtc.h" +#include "screen.h" + +//#define VERBOSE 0 +#include "logmacro.h" + +// device type definitions +DEFINE_DEVICE_TYPE(VINAS, vinas_device, "vinas", "IX0902/IX0903 VINAS CRTC") +DEFINE_DEVICE_TYPE(VICON, vicon_device, "vicon", "IX1093 VICON CRTC") + +x68k_crtc_device::x68k_crtc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , device_video_interface(mconfig, *this) + , m_vdisp_callback(*this) + , m_rint_callback(*this) + , m_hsync_callback(*this) + , m_tvram_read_callback(*this) + , m_gvram_read_callback(*this) + , m_tvram_write_callback(*this) + , m_gvram_write_callback(*this) + , m_operation(0) + , m_vblank(false) + , m_hblank(false) + , m_htotal(0) + , m_vtotal(0) + , m_hend(0) + , m_vend(0) + , m_hsync_end(0) + , m_vsync_end(0) + , m_hsyncadjust(0) + , m_vmultiple(1) + , m_height(0) + , m_width(0) + , m_visible_height(0) + , m_visible_width(0) + , m_hshift(0) + , m_vshift(0) + , m_interlace(false) + , m_oddscanline(false) +{ + std::fill(std::begin(m_reg), std::end(m_reg), 0); +} + +vinas_device::vinas_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : x68k_crtc_device(mconfig, VINAS, tag, owner, clock) +{ +} + +vicon_device::vicon_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : x68k_crtc_device(mconfig, VICON, tag, owner, clock) +{ +} + +void x68k_crtc_device::device_resolve_objects() +{ + m_vdisp_callback.resolve_safe(); + m_rint_callback.resolve_safe(); + m_hsync_callback.resolve_safe(); + m_tvram_read_callback.resolve_safe(0); + m_gvram_read_callback.resolve_safe(0); + m_tvram_write_callback.resolve_safe(); + m_gvram_write_callback.resolve_safe(); +} + +void x68k_crtc_device::device_start() +{ + m_scanline_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(x68k_crtc_device::hsync), this)); + m_operation_end_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(x68k_crtc_device::operation_end), this)); + m_raster_end_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(x68k_crtc_device::raster_end), this)); + m_raster_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(x68k_crtc_device::raster_irq), this)); + m_vblank_irq_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(x68k_crtc_device::vblank_irq), this)); + + // save state + save_item(NAME(m_reg)); + save_item(NAME(m_operation)); + save_item(NAME(m_vblank)); + save_item(NAME(m_hblank)); + save_item(NAME(m_htotal)); + save_item(NAME(m_vtotal)); + save_item(NAME(m_hend)); + save_item(NAME(m_vend)); + save_item(NAME(m_hsync_end)); + save_item(NAME(m_vsync_end)); + save_item(NAME(m_hsyncadjust)); + save_item(NAME(m_vmultiple)); + save_item(NAME(m_height)); + save_item(NAME(m_width)); + save_item(NAME(m_visible_height)); + save_item(NAME(m_visible_width)); + save_item(NAME(m_hshift)); + save_item(NAME(m_vshift)); + save_item(NAME(m_interlace)); + save_item(NAME(m_oddscanline)); +} + +void x68k_crtc_device::device_reset() +{ + // initialise CRTC, set registers to defaults for the standard text mode (768x512) + m_reg[0] = 137; // Horizontal total (in characters) + m_reg[1] = 14; // Horizontal sync end + m_reg[2] = 28; // Horizontal start + m_reg[3] = 124; // Horizontal end + m_reg[4] = 567; // Vertical total + m_reg[5] = 5; // Vertical sync end + m_reg[6] = 40; // Vertical start + m_reg[7] = 552; // Vertical end + m_reg[8] = 27; // Horizontal adjust + + //m_scanline = screen().vpos();// = m_reg[6]; // Vertical start + + // start VBlank timer + m_vblank = true; + attotime const irq_time = screen().time_until_pos(m_reg[6],2); + m_vblank_irq_timer->adjust(irq_time); + + // start HBlank timer + m_scanline_timer->adjust(screen().scan_period(), 1); + + m_vdisp_callback(1); + m_rint_callback(1); + m_hsync_callback(1); +} + +void x68k_crtc_device::text_copy(unsigned src, unsigned dest, u8 planes) +{ + // copys one raster in T-VRAM to another raster + offs_t src_ram = src * 256; // 128 bytes per scanline + offs_t dest_ram = dest * 256; + + // update RAM in each plane + for (int words = 256; words > 0; words--, src_ram++, dest_ram++) + { + for (u8 plane = 0; plane < 3; plane++) + if (BIT(planes, plane)) + m_tvram_write_callback(dest_ram + 0x10000 * plane, m_tvram_read_callback(src_ram + 0x10000 * plane, 0xffff), 0xffff); + } +} + +TIMER_CALLBACK_MEMBER(x68k_crtc_device::operation_end) +{ + int bit = param; + m_operation &= ~bit; +} + +void x68k_crtc_device::refresh_mode() +{ + // Calculate data from register values + m_vmultiple = 1; + if ((m_reg[20] & 0x10) != 0 && (m_reg[20] & 0x0c) == 0) + m_vmultiple = 2; // 31.5kHz + 256 lines = doublescan + if (m_interlace) + m_vmultiple = 0.5f; // 31.5kHz + 1024 lines or 15kHz + 512 lines = interlaced + m_htotal = (m_reg[0] + 1) * 8; + m_vtotal = (m_reg[4] + 1) / m_vmultiple; // default is 567 (568 scanlines) + m_hbegin = (m_reg[2] * 8) + 1; + m_hend = (m_reg[3] * 8); + m_vbegin = (m_reg[6]) / m_vmultiple; + m_vend = (m_reg[7] - 1) / m_vmultiple; + if ((m_vmultiple == 2) && !(m_reg[7] & 1)) // otherwise if the raster irq line == vblank line, the raster irq fires too late + m_vend++; + m_hsync_end = (m_reg[1]) * 8; + m_vsync_end = (m_reg[5]) / m_vmultiple; + m_hsyncadjust = m_reg[8]; + + rectangle scr(0, m_htotal - 8, 0, m_vtotal); + if (scr.max_y <= m_vend) + scr.max_y = m_vend + 2; + if (scr.max_x <= m_hend) + scr.max_x = m_hend + 2; + rectangle visiblescr(m_hbegin, m_hend, m_vbegin, m_vend); + + // expand visible area to the size indicated by CRTC reg 20 + int length = m_hend - m_hbegin; + if (length < m_width) + { + visiblescr.min_x = m_hbegin - ((m_width - length)/2); + visiblescr.max_x = m_hend + ((m_width - length)/2); + } + length = m_vend - m_vbegin; + if (length < m_height) + { + visiblescr.min_y = m_vbegin - ((m_height - length)/2); + visiblescr.max_y = m_vend + ((m_height - length)/2); + } + // bounds check + if (visiblescr.min_x < 0) + visiblescr.min_x = 0; + if (visiblescr.min_y < 0) + visiblescr.min_y = 0; + if (visiblescr.max_x >= scr.max_x) + visiblescr.max_x = scr.max_x - 2; + if (visiblescr.max_y >= scr.max_y - 1) + visiblescr.max_y = scr.max_y - 2; + +// LOG("CRTC regs - %i %i %i %i - %i %i %i %i - %i - %i\n", m_reg[0], m_reg[1], m_reg[2], m_reg[3], +// m_reg[4], m_reg[5], m_reg[6], m_reg[7], m_reg[8], m_reg[9]); + unsigned div = (m_reg[20] & 0x03) == 0 ? 4 : 2; + if (BIT(m_reg[20], 4) && !BIT(m_reg[20], 1)) + div = BIT(m_reg[20], 0) ? 3 : 6; + if ((m_reg[20] & 0x0c) == 0) + div *= 2; + attotime refresh = attotime::from_ticks(scr.max_x * scr.max_y, (BIT(m_reg[20], 4) ? 69.55199_MHz_XTAL : 38.86363_MHz_XTAL) / div); + LOG("screen().configure(%i,%i,[%i,%i,%i,%i],%f)\n", scr.max_x, scr.max_y, visiblescr.min_x, visiblescr.min_y, visiblescr.max_x, visiblescr.max_y, ATTOSECONDS_TO_HZ(refresh.as_attoseconds())); + screen().configure(scr.max_x, scr.max_y, visiblescr, refresh.as_attoseconds()); +} + +TIMER_CALLBACK_MEMBER(x68k_crtc_device::hsync) +{ + int hstate = param; + attotime hsync_time; + + m_hblank = hstate; + m_hsync_callback(!m_hblank); + + if (m_operation & 8) + text_copy((m_reg[22] & 0xff00) >> 8, (m_reg[22] & 0x00ff), (m_reg[21] & 0xf)); + + if (m_vmultiple == 2) // 256-line (doublescan) + { + if (hstate == 1) + { + if (m_oddscanline) + { + int scan = screen().vpos(); + if (scan > m_vend) + scan = m_vbegin; + hsync_time = screen().time_until_pos(scan, (m_htotal + m_hend) / 2); + m_scanline_timer->adjust(hsync_time); + if (scan != 0) + screen().update_partial(scan); + } + else + { + int scan = screen().vpos(); + if (scan > m_vend) + scan = m_vbegin; + hsync_time = screen().time_until_pos(scan, m_hend / 2); + m_scanline_timer->adjust(hsync_time); + if (scan != 0) + screen().update_partial(scan); + } + } + if (hstate == 0) + { + if (m_oddscanline) + { + int scan = screen().vpos(); + if (scan > m_vend) + scan = m_vbegin; + else + scan++; + hsync_time = screen().time_until_pos(scan, m_hbegin / 2); + m_scanline_timer->adjust(hsync_time, 1); + m_oddscanline = false; + } + else + { + hsync_time = screen().time_until_pos(screen().vpos(), (m_htotal + m_hbegin) / 2); + m_scanline_timer->adjust(hsync_time, 1); + m_oddscanline = true; + } + } + } + else // 512-line + { + if (hstate == 1) + { + int scan = screen().vpos(); + if (scan > m_vend) + scan = 0; + hsync_time = screen().time_until_pos(scan, m_hend); + m_scanline_timer->adjust(hsync_time); + if (scan != 0) + screen().update_partial(scan); + } + if (hstate == 0) + { + hsync_time = screen().time_until_pos(screen().vpos() + 1, m_hbegin); + m_scanline_timer->adjust(hsync_time, 1); + } + } +} + +TIMER_CALLBACK_MEMBER(x68k_crtc_device::raster_end) +{ + m_rint_callback(1); +} + +TIMER_CALLBACK_MEMBER(x68k_crtc_device::raster_irq) +{ + int scan = param; + attotime irq_time; + attotime end_time; + + if (scan <= m_vtotal) + { + m_rint_callback(0); + screen().update_partial(scan); + irq_time = screen().time_until_pos(scan, m_hbegin); + // end of HBlank period clears GPIP6 also? + end_time = screen().time_until_pos(scan, m_hend); + m_raster_irq_timer->adjust(irq_time, scan); + m_raster_end_timer->adjust(end_time); + LOG("GPIP6: Raster triggered at line %i (%i)\n", scan,screen().vpos()); + } +} + +TIMER_CALLBACK_MEMBER(x68k_crtc_device::vblank_irq) +{ + int val = param; + attotime irq_time; + int vblank_line; + + if (val == 1) // V-DISP on + { + m_vblank = 1; + vblank_line = m_vbegin; + irq_time = screen().time_until_pos(vblank_line, 2); + m_vblank_irq_timer->adjust(irq_time); + LOG("CRTC: VBlank on\n"); + } + if (val == 0) // V-DISP off + { + m_vblank = 0; + vblank_line = m_vend; + if (vblank_line > m_vtotal) + vblank_line = m_vtotal; + irq_time = screen().time_until_pos(vblank_line, 2); + m_vblank_irq_timer->adjust(irq_time, 1); + LOG("CRTC: VBlank off\n"); + } + + m_vdisp_callback(!m_vblank); +} + + +// CRTC "VINAS 1+2 / VICON" at 0xe80000 +/* 0xe80000 - Registers (all are 16-bit): + * 0 - Horizontal Total (in characters) + * 1 - Horizontal Sync End + * 2 - Horizontal Display Begin + * 3 - Horizontal Display End + * 4 - Vertical Total (in scanlines) + * 5 - Vertical Sync End + * 6 - Vertical Display Begin + * 7 - Vertical Display End + * 8 - Fine Horizontal Sync Adjustment + * 9 - Raster Line (for Raster IRQ mapped to MFP GPIP6) + * 10/11 - Text Layer X and Y Scroll + * 12/13 - Graphic Layer 0 X and Y Scroll + * 14/15 - Graphic Layer 1 X and Y Scroll + * 16/17 - Graphic Layer 2 X and Y Scroll + * 18/19 - Graphic Layer 3 X and Y Scroll + * 20 - bit 12 - Text VRAM mode : 0 = display, 1 = buffer + * bit 11 - Graphic VRAM mode : 0 = display, 1 = buffer + * bit 10 - "Real" screen size : 0 = 512x512, 1 = 1024x1024 + * bits 8,9 - Colour mode : + * 00 = 16 colour 01 = 256 colour + * 10 = Undefined 11 = 65,536 colour + * bit 4 - Horizontal Frequency : 0 = 15.98kHz, 1 = 31.50kHz + * bits 2,3 - Vertical dots : + * 00 = 256 01 = 512 + * 10 or 11 = 1024 (interlaced) + * bits 0,1 - Horizontal dots : + * 00 = 256 01 = 512 + * 10 = 768 11 = 50MHz clock mode (Compact XVI or later) + * 21 - bit 9 - Text Screen Access Mask Enable + * bit 8 - Text Screen Simultaneous Plane Access Enable + * bits 4-7 - Text Screen Simultaneous Plane Access Select + * bits 0-3 - Text Screen Line Copy Plane Select + * Graphic Screen High-speed Clear Page Select + * 22 - Text Screen Line Copy + * bits 15-8 - Source Line + * bits 7-0 - Destination Line + * 23 - Text Screen Mask Pattern + * + * 0xe80481 - Operation Port (8-bit): + * bit 3 - Text Screen Line Copy Begin + * bit 1 - Graphic Screen High-speed Clear Begin + * bit 0 - Image Taking Begin (?) + * Operation Port bits are cleared automatically when the requested + * operation is completed. + */ +WRITE16_MEMBER(x68k_crtc_device::crtc_w) +{ + if (offset < 0x24) + COMBINE_DATA(&m_reg[offset]); + switch (offset) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + refresh_mode(); + break; + case 9: // CRTC raster IRQ (GPIP6) + { + data = m_reg[9]; + attotime irq_time = screen().time_until_pos((data) / m_vmultiple,2); + + if (data != screen().vpos()) + m_rint_callback(1); + if (irq_time.as_double() > 0) + m_raster_irq_timer->adjust(irq_time, (data) / m_vmultiple); + } + LOG("CRTC: Write to raster IRQ register - %i\n",data); + break; + case 20: + if (ACCESSING_BITS_0_7) + { + m_interlace = false; + switch (data & 0x0c) + { + case 0x00: + m_height = 256; + break; + case 0x08: + case 0x0c: // TODO: 1024 vertical, if horizontal freq = 31kHz + m_height = 512; + m_interlace = true; // if 31kHz, 1024 lines = interlaced + break; + case 0x04: + m_height = 512; + if (!(m_reg[20] & 0x0010)) // if 15kHz, 512 lines = interlaced + m_interlace = true; + break; + } + switch (data & 0x03) + { + case 0x00: + m_width = 256; + break; + case 0x01: + m_width = 512; + break; + case 0x02: + case 0x03: // 0x03 = 50MHz clock mode (XVI only) + m_width = 768; + break; + } + } +/* if (ACCESSING_BITS_8_15) + { + m_interlace = false; + if (data & 0x0400) + m_interlace = true; + }*/ + logerror("CRTC: Register 20 = %04x\n", m_reg[20]); + refresh_mode(); + break; + case 576: // operation register + m_operation = data; + if (data & 0x02) // high-speed graphic screen clear + { + for (offs_t addr = 0; addr < 0x40000; addr++) + m_gvram_write_callback(addr, 0, 0xffff); + m_operation_end_timer->adjust(attotime::from_msec(10), 0x02); // time taken to do operation is a complete guess. + } + break; + } +// LOG("%s CRTC: Wrote %04x to CRTC register %i\n",machine().describe_context(), data, offset); +} + +READ16_MEMBER(x68k_crtc_device::crtc_r) +{ + if (offset < 24) + { +// LOG("%s CRTC: Read %04x from CRTC register %i\n",machine().describe_context(), m_reg[offset], offset); + switch (offset) + { + case 9: + return 0; + case 10: // Text X/Y scroll + case 11: + case 12: // Graphic layer 0 scroll + case 13: + return m_reg[offset] & 0x3ff; + case 14: // Graphic layer 1 scroll + case 15: + case 16: // Graphic layer 2 scroll + case 17: + case 18: // Graphic layer 3 scroll + case 19: + return m_reg[offset] & 0x1ff; + default: + return m_reg[offset]; + } + } + if (offset == 576) // operation port, operation bits are set to 0 when operation is complete + return m_operation; +// LOG("CRTC: [%08x] Read from unknown CRTC register %i\n",activecpu_get_pc(),offset); + return 0xffff; +} + +WRITE16_MEMBER(x68k_crtc_device::gvram_w) +{ +// int xloc,yloc,pageoffset; + /* + G-VRAM usage is determined by colour depth and "real" screen size. + + For screen size of 1024x1024, all G-VRAM space is used, in one big page. + At 1024x1024 real screen size, colour depth is always 4bpp, and ranges from + 0xc00000-0xdfffff. + + For screen size of 512x512, the colour depth determines the page usage. + 16 colours = 4 pages + 256 colours = 2 pages + 65,536 colours = 1 page + Page 1 - 0xc00000-0xc7ffff Page 2 - 0xc80000-0xcfffff + Page 3 - 0xd00000-0xd7ffff Page 4 - 0xd80000-0xdfffff + */ + + // handle different G-VRAM page setups + if (m_reg[20] & 0x0800) // G-VRAM set to buffer + { + if (offset < 0x40000) + m_gvram_write_callback(offset, data, mem_mask); + } + else + { + switch (m_reg[20] & 0x0300) + { + case 0x0300: + if (offset < 0x40000) + m_gvram_write_callback(offset, data, mem_mask); + break; + case 0x0100: + if (offset < 0x40000) + { + m_gvram_write_callback(offset, data & 0x00ff, 0x00ff); + } + else if (offset >= 0x40000 && offset < 0x80000) + { + m_gvram_write_callback(offset - 0x40000, (data & 0x00ff) << 8, 0xff00); + } + break; + case 0x0000: + if (offset < 0x40000) + { + m_gvram_write_callback(offset, data & 0x000f, 0x000f); + } + else if (offset >= 0x40000 && offset < 0x80000) + { + m_gvram_write_callback(offset - 0x40000, (data & 0x000f) << 4, 0x00f0); + } + else if (offset >= 0x80000 && offset < 0xc0000) + { + m_gvram_write_callback(offset - 0x80000, (data & 0x000f) << 8, 0x0f00); + } + else if (offset >= 0xc0000 && offset < 0x100000) + { + m_gvram_write_callback(offset - 0xc0000, (data & 0x000f) << 12, 0xf000); + } + break; + default: + logerror("G-VRAM written while layer setup is undefined.\n"); + } + } +} + +WRITE16_MEMBER(x68k_crtc_device::tvram_w) +{ + u16 text_mask = ~(m_reg[23]) & mem_mask; + + if (!(m_reg[21] & 0x0200)) // text access mask enable + text_mask = 0xffff & mem_mask; + + mem_mask = text_mask; + + if (m_reg[21] & 0x0100) + { + // simultaneous T-VRAM plane access (I think ;)) + offset &= 0x00ffff; + u8 wr = (m_reg[21] & 0x00f0) >> 4; + for (int plane = 0; plane < 4; plane++) + { + if (BIT(wr, plane)) + { + m_tvram_write_callback(offset + 0x10000 * plane, data, mem_mask); + } + } + } + else + { + m_tvram_write_callback(offset, data, mem_mask); + } +} + +READ16_MEMBER(x68k_crtc_device::gvram_r) +{ + u16 ret = 0; + + if (m_reg[20] & 0x0800) // G-VRAM set to buffer + return m_gvram_read_callback(offset); + + switch (m_reg[20] & 0x0300) // colour setup determines G-VRAM use + { + case 0x0300: // 65,536 colour (RGB) - 16-bits per word + if (offset < 0x40000) + ret = m_gvram_read_callback(offset); + else + ret = 0xffff; + break; + case 0x0100: // 256 colour (paletted) - 8 bits per word + if (offset < 0x40000) + ret = m_gvram_read_callback(offset) & 0x00ff; + else if (offset >= 0x40000 && offset < 0x80000) + ret = (m_gvram_read_callback(offset - 0x40000) & 0xff00) >> 8; + else if (offset >= 0x80000) + ret = 0xffff; + break; + case 0x0000: // 16 colour (paletted) - 4 bits per word + if (offset < 0x40000) + ret = m_gvram_read_callback(offset) & 0x000f; + else if (offset >= 0x40000 && offset < 0x80000) + ret = (m_gvram_read_callback(offset - 0x40000) & 0x00f0) >> 4; + else if (offset >= 0x80000 && offset < 0xc0000) + ret = (m_gvram_read_callback(offset - 0x80000) & 0x0f00) >> 8; + else if (offset >= 0xc0000 && offset < 0x100000) + ret = (m_gvram_read_callback(offset - 0xc0000) & 0xf000) >> 12; + break; + default: + logerror("G-VRAM read while layer setup is undefined.\n"); + ret = 0xffff; + } + + return ret; +} + +READ16_MEMBER(x68k_crtc_device::tvram_r) +{ + return m_tvram_read_callback(offset, mem_mask); +} diff --git a/src/mame/video/x68k_crtc.h b/src/mame/video/x68k_crtc.h new file mode 100644 index 00000000000..a532dbe72f5 --- /dev/null +++ b/src/mame/video/x68k_crtc.h @@ -0,0 +1,124 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald,Carl + +#ifndef MAME_VIDEO_X68K_CRTC_H +#define MAME_VIDEO_X68K_CRTC_H + +class x68k_crtc_device : public device_t, public device_video_interface +{ +public: + // device configuration + auto vdisp_cb() { return m_vdisp_callback.bind(); } + auto rint_cb() { return m_rint_callback.bind(); } + auto hsync_cb() { return m_hsync_callback.bind(); } + auto tvram_read_cb() { return m_tvram_read_callback.bind(); } + auto tvram_write_cb() { return m_tvram_write_callback.bind(); } + auto gvram_read_cb() { return m_gvram_read_callback.bind(); } + auto gvram_write_cb() { return m_gvram_write_callback.bind(); } + // TODO: XTAL clocks + + DECLARE_WRITE16_MEMBER(crtc_w); + DECLARE_READ16_MEMBER(crtc_r); + DECLARE_WRITE16_MEMBER(gvram_w); + DECLARE_READ16_MEMBER(gvram_r); + DECLARE_WRITE16_MEMBER(tvram_w); + DECLARE_READ16_MEMBER(tvram_r); + + // getters + u16 xscr_text() const { return m_reg[10]; } + u16 yscr_text() const { return m_reg[11]; } + u16 xscr_gfx(int page) const { return m_reg[12 + page * 2]; } + u16 yscr_gfx(int page) const { return m_reg[13 + page * 2]; } + u8 vfactor() const { return (m_reg[20] & 0x0c) >> 2; } + bool is_1024x1024() const { return BIT(m_reg[20], 10); } + bool gfx_layer_buffer() const { return BIT(m_reg[20], 11); } + bool text_layer_buffer() const { return BIT(m_reg[20], 12); } + u16 hbegin() const { return m_hbegin; } + u16 vbegin() const { return m_vbegin; } + u16 hend() const { return m_hend; } + u16 vend() const { return m_vend; } + u16 visible_height() const { return m_visible_height; } + u16 visible_width() const { return m_visible_width; } + u16 hshift() const { return m_hshift; } + u16 vshift() const { return m_vshift; } + +protected: + // base constructor + x68k_crtc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); + + // device-specific overrides + virtual void device_resolve_objects() override; + virtual void device_start() override; + virtual void device_reset() override; + +private: + // internal helpers + void text_copy(unsigned src, unsigned dest, u8 planes); + TIMER_CALLBACK_MEMBER(operation_end); + void refresh_mode(); + TIMER_CALLBACK_MEMBER(hsync); + TIMER_CALLBACK_MEMBER(raster_end); + TIMER_CALLBACK_MEMBER(raster_irq); + TIMER_CALLBACK_MEMBER(vblank_irq); + + // device callbacks + devcb_write_line m_vdisp_callback; + devcb_write_line m_rint_callback; + devcb_write_line m_hsync_callback; + devcb_read16 m_tvram_read_callback; + devcb_read16 m_gvram_read_callback; + devcb_write16 m_tvram_write_callback; + devcb_write16 m_gvram_write_callback; + + // internal state + u16 m_reg[24]; // registers + u8 m_operation; // operation port (0xe80481) + bool m_vblank; // true if in VBlank + bool m_hblank; // true if in HBlank + u16 m_htotal; // Horizontal Total (in characters) + u16 m_vtotal; // Vertical Total + u16 m_hbegin; // Horizontal Begin + u16 m_vbegin; // Vertical Begin + u16 m_hend; // Horizontal End + u16 m_vend; // Vertical End + u16 m_hsync_end; // Horizontal Sync End + u16 m_vsync_end; // Vertical Sync End + u16 m_hsyncadjust; // Horizontal Sync Adjustment + //float m_hmultiple; // Horizontal pixel multiplier + float m_vmultiple; // Vertical scanline multiplier (x2 for doublescan modes) + u16 m_height; + u16 m_width; + u16 m_visible_height; + u16 m_visible_width; + u16 m_hshift; + u16 m_vshift; + //u16 m_video_width; // horizontal total (in pixels) + //u16 m_video_height; // vertical total + bool m_interlace; // 1024 vertical resolution is interlaced + //u16 m_scanline; + bool m_oddscanline; + + emu_timer *m_scanline_timer; + emu_timer *m_raster_irq_timer; + emu_timer *m_vblank_irq_timer; + emu_timer *m_raster_end_timer; + emu_timer *m_operation_end_timer; +}; + +class vinas_device : public x68k_crtc_device +{ +public: + vinas_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +class vicon_device : public x68k_crtc_device +{ +public: + vicon_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); +}; + +// device type definitions +DECLARE_DEVICE_TYPE(VINAS, vinas_device) +DECLARE_DEVICE_TYPE(VICON, vicon_device) + +#endif // MAME_VIDEO_X68K_CRTC_H -- cgit v1.2.3