From 498b7a0a7ddf138e83b79acbc159597587db3804 Mon Sep 17 00:00:00 2001 From: Angelo Salese Date: Tue, 4 Jul 2023 19:10:46 +0200 Subject: video/pc_vga.cpp: part 2 of interface modernization (#11315) * video/pc_vga.cpp: update QA, move SVGA related function to bottom of file * chore: rename clgd542x.cpp -> pc_vga_cirrus.cpp * chore: move SiS630 SVGA portion to pc_vga_sis.cpp * chore: intermediate step to convert crtc/seq/attribute/gc_reg_read/write to maps from violating parties * video/pc_vga_cirrus.cpp: preliminary implementation of hidden DAC mode * misc/gambl186.cpp: fix compile * pc_vga_cirrus.cpp: fix gambl186 regression * chore: convert pc_vga sequencer regs to space memory * chore: make sure that address_space_config is preserved when inheriting * trs/vis.cpp: convert VGA to sequencer_map * chore: move s3virge out of bus/isa * pc_vga.cpp: convert ATC to attribute_map * pc_vga.cpp: convert GC to gc_map * pc_vga.cpp: convert CRTC to crtc_map * fixes trs/vis.cpp refresh rate by chain reaction (40 Hz -> 61 Hz) * video/s3virge.cpp: fix regression * video/pc_vga.cpp: reorder functions * chore: modernize VGA main I/O interfaces * video/clgd546x_laguna.cpp: update to latest * konami/konmedal020.cpp: fix -validate * video/pc_vga.cpp: use yet another custom address_map_constructor in place of the non-working memory_view pattern * video/ibm8514a.cpp: address self review [skip ci] --- scripts/src/bus.lua | 2 - scripts/src/video.lua | 30 +- src/devices/bus/isa/s3virge.cpp | 1700 ------------------- src/devices/bus/isa/s3virge.h | 255 --- src/devices/bus/isa/svga_cirrus.cpp | 21 +- src/devices/bus/isa/svga_cirrus.h | 6 +- src/devices/bus/isa/svga_s3.cpp | 49 +- src/devices/bus/isa/svga_s3.h | 11 +- src/devices/bus/isa/svga_trident.cpp | 20 +- src/devices/bus/isa/svga_trident.h | 4 + src/devices/bus/isa/svga_tseng.cpp | 9 +- src/devices/bus/isa/svga_tseng.h | 2 + src/devices/bus/isa/vga.cpp | 9 +- src/devices/bus/isa/vga.h | 2 + src/devices/bus/isa/vga_ati.cpp | 33 +- src/devices/bus/isa/vga_ati.h | 5 + src/devices/machine/sis630_gui.cpp | 390 +---- src/devices/machine/sis630_gui.h | 46 +- src/devices/video/clgd542x.cpp | 1496 ----------------- src/devices/video/clgd542x.h | 132 -- src/devices/video/clgd546x_laguna.cpp | 87 +- src/devices/video/clgd546x_laguna.h | 9 +- src/devices/video/ibm8514a.cpp | 16 +- src/devices/video/pc_vga.cpp | 2874 ++++++++++++++++++--------------- src/devices/video/pc_vga.h | 86 +- src/devices/video/pc_vga_ati.cpp | 17 - src/devices/video/pc_vga_ati.h | 1 - src/devices/video/pc_vga_cirrus.cpp | 1485 +++++++++++++++++ src/devices/video/pc_vga_cirrus.h | 132 ++ src/devices/video/pc_vga_nvidia.cpp | 376 ++--- src/devices/video/pc_vga_nvidia.h | 12 +- src/devices/video/pc_vga_s3.cpp | 867 +++++----- src/devices/video/pc_vga_s3.h | 18 +- src/devices/video/pc_vga_sis.cpp | 301 ++++ src/devices/video/pc_vga_sis.h | 44 + src/devices/video/pc_vga_trident.cpp | 1137 +++++++------ src/devices/video/pc_vga_trident.h | 36 +- src/devices/video/pc_vga_tseng.cpp | 445 ++--- src/devices/video/pc_vga_tseng.h | 25 +- src/devices/video/pc_xga.cpp | 97 +- src/devices/video/pc_xga.h | 9 +- src/devices/video/riva128.cpp | 87 +- src/devices/video/riva128.h | 6 - src/devices/video/s3virge.cpp | 1238 ++++++++++++++ src/devices/video/s3virge.h | 248 +++ src/devices/video/virge_pci.cpp | 143 +- src/devices/video/virge_pci.h | 14 +- src/mame/be/bebox.cpp | 11 +- src/mame/funworld/photoply.cpp | 14 +- src/mame/konami/konmedal020.cpp | 7 +- src/mame/misc/gambl186.cpp | 6 +- src/mame/misc/gammagic.cpp | 4 +- src/mame/misc/gamtor.cpp | 115 +- src/mame/misc/magtouch.cpp | 4 +- src/mame/misc/pntnpuzl.cpp | 5 +- src/mame/misc/savquest.cpp | 4 +- src/mame/misc/su2000.cpp | 4 +- src/mame/pc/fruitpc.cpp | 4 +- src/mame/pc/pangofun.cpp | 4 +- src/mame/pc/paokaipc.cpp | 4 +- src/mame/pc/pcat_dyn.cpp | 4 +- src/mame/pc/pcat_nit.cpp | 10 +- src/mame/pc/queen.cpp | 4 +- src/mame/trs/vis.cpp | 550 ++++--- 64 files changed, 6922 insertions(+), 7864 deletions(-) delete mode 100644 src/devices/bus/isa/s3virge.cpp delete mode 100644 src/devices/bus/isa/s3virge.h delete mode 100644 src/devices/video/clgd542x.cpp delete mode 100644 src/devices/video/clgd542x.h create mode 100644 src/devices/video/pc_vga_cirrus.cpp create mode 100644 src/devices/video/pc_vga_cirrus.h create mode 100644 src/devices/video/pc_vga_sis.cpp create mode 100644 src/devices/video/pc_vga_sis.h create mode 100644 src/devices/video/s3virge.cpp create mode 100644 src/devices/video/s3virge.h diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 32805592c97..532e6904e15 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -1763,8 +1763,6 @@ if (BUSES["ISA"]~=null) then MAME_DIR .. "src/devices/bus/isa/pds.h", MAME_DIR .. "src/devices/bus/isa/pgc.cpp", MAME_DIR .. "src/devices/bus/isa/pgc.h", - MAME_DIR .. "src/devices/bus/isa/s3virge.cpp", - MAME_DIR .. "src/devices/bus/isa/s3virge.h", MAME_DIR .. "src/devices/bus/isa/sb16.cpp", MAME_DIR .. "src/devices/bus/isa/sb16.h", MAME_DIR .. "src/devices/bus/isa/sblaster.cpp", diff --git a/scripts/src/video.lua b/scripts/src/video.lua index 0d93d333934..07ed008f8a4 100644 --- a/scripts/src/video.lua +++ b/scripts/src/video.lua @@ -907,13 +907,13 @@ end -------------------------------------------------- -- ---@src/devices/video/clgd542x.h,VIDEOS["PC_VGA_CIRRUS"] = true +--@src/devices/video/pc_vga_cirrus.h,VIDEOS["PC_VGA_CIRRUS"] = true -------------------------------------------------- if (VIDEOS["PC_VGA_CIRRUS"]~=null) then files { - MAME_DIR .. "src/devices/video/clgd542x.cpp", - MAME_DIR .. "src/devices/video/clgd542x.h", + MAME_DIR .. "src/devices/video/pc_vga_cirrus.cpp", + MAME_DIR .. "src/devices/video/pc_vga_cirrus.h", } end @@ -941,6 +941,30 @@ if (VIDEOS["PC_VGA_S3"]~=null) then } end +-------------------------------------------------- +-- +--@src/devices/video/s3virge.h,VIDEOS["S3VIRGE"] = true +-------------------------------------------------- + +if (VIDEOS["S3VIRGE"]~=null) then + files { + MAME_DIR .. "src/devices/video/s3virge.cpp", + MAME_DIR .. "src/devices/video/s3virge.h", + } +end + +-------------------------------------------------- +-- +--@src/devices/video/pc_vga_sis.h,VIDEOS["PC_VGA_SIS"] = true +-------------------------------------------------- + +if (VIDEOS["PC_VGA_SIS"]~=null) then + files { + MAME_DIR .. "src/devices/video/pc_vga_sis.cpp", + MAME_DIR .. "src/devices/video/pc_vga_sis.h", + } +end + -------------------------------------------------- -- --@src/devices/video/pc_vga_trident.h,VIDEOS["PC_VGA_TRIDENT"] = true diff --git a/src/devices/bus/isa/s3virge.cpp b/src/devices/bus/isa/s3virge.cpp deleted file mode 100644 index a621c3ed22c..00000000000 --- a/src/devices/bus/isa/s3virge.cpp +++ /dev/null @@ -1,1700 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Barry Rodewald -/* - * s3virge.cpp - * - * Implementation of the S3 Virge series of video card - * - * Current status: - * - Working on getting VESA video modes working better - 800x600 and higher skip every other line at - * 8-bit depth, but are fine at 15/16-bit depth. - * - S3D is not implemented at all, so no 2D/3D acceleration yet. - * - * TODO: - * - Proper FIFOs; - * - Implement 3d commands; - * - Implement remaining ROP commands; - * - Secondary stream mixing; - * - S3 Scenic Highway i/f (SAA7110 + S3 Scenic/MX2 MPEG-1); - * - DMAs; - * - interrupts; - * - big endian support for non-x86 machines; - * - DDC/I2C i/f, cfr. serial port on MMFF20 - * - win98se: doesn't show transparent layer on shut down screen; - * - */ - -#include "emu.h" -#include "s3virge.h" - -#include "screen.h" - -//#include - -#define VERBOSE (LOG_REG | LOG_CMD | LOG_MMIO) -//#define LOG_OUTPUT_STREAM std::cout - -#include "logmacro.h" - -#define LOG_REG (1U << 1) -#define LOG_CMD (1U << 2) -#define LOG_MMIO (1U << 3) - -#define LOGREG(...) LOGMASKED(LOG_REG, __VA_ARGS__) -#define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__) -#define LOGMMIO(...) LOGMASKED(LOG_MMIO, __VA_ARGS__) - - -#define CRTC_PORT_ADDR ((vga.miscellaneous_output & 1) ? 0x3d0 : 0x3b0) - -DEFINE_DEVICE_TYPE(S3VIRGE, s3virge_vga_device, "virge_vga", "S3 86C325") -DEFINE_DEVICE_TYPE(S3VIRGEDX, s3virgedx_vga_device, "virgedx_vga", "S3 86C375") -DEFINE_DEVICE_TYPE(S3VIRGEDX1, s3virgedx_rev1_vga_device, "virgedx_vga_r1", "S3 86C375 (rev 1)") - -s3virge_vga_device::s3virge_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : s3virge_vga_device(mconfig, S3VIRGE, tag, owner, clock) -{ -} - -s3virge_vga_device::s3virge_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) - : s3_vga_device(mconfig, type, tag, owner, clock) - , m_linear_config_changed_cb(*this) -{ -} - -s3virgedx_vga_device::s3virgedx_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : s3virgedx_vga_device(mconfig, S3VIRGEDX, tag, owner, clock) -{ -} - -s3virgedx_vga_device::s3virgedx_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) - : s3virge_vga_device(mconfig, type, tag, owner, clock) -{ -} - -s3virgedx_rev1_vga_device::s3virgedx_rev1_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : s3virgedx_vga_device(mconfig, S3VIRGEDX1, tag, owner, clock) -{ -} - -void s3virge_vga_device::device_start() -{ - zero(); - - for (int i = 0; i < 0x100; i++) - set_pen_color(i, 0, 0, 0); - - // Avoid an infinite loop when displaying. 0 is not possible anyway. - vga.crtc.maximum_scan_line = 1; - - // copy over interfaces - vga.svga_intf.seq_regcount = 0x1c; - vga.svga_intf.crtc_regcount = 0x19; - vga.memory = std::make_unique(vga.svga_intf.vram_size); - memset(&vga.memory[0], 0, vga.svga_intf.vram_size); - - save_pointer(vga.memory, "Video RAM", vga.svga_intf.vram_size); - save_item(vga.crtc.data,"CRTC Registers"); - save_item(vga.sequencer.data,"Sequencer Registers"); - save_item(vga.attribute.data,"Attribute Registers"); - - m_vblank_timer = timer_alloc(FUNC(vga_device::vblank_timer_cb), this); - m_draw_timer = timer_alloc(FUNC(s3virge_vga_device::draw_step_tick), this); - - memset(&s3, 0, sizeof(s3)); - memset(&s3virge, 0, sizeof(s3virge)); - s3virge.linear_address = 0x70000000; - s3virge.linear_address_size_full = 0x10000; - s3virge.s3d.cmd_fifo_slots_free = 16; - save_item(s3virge.s3d.pattern,"S3D Pattern Data"); - save_item(s3virge.s3d.reg[0],"S3D Registers: BitBLT"); - save_item(s3virge.s3d.reg[1],"S3D Registers: 2D Line"); - save_item(s3virge.s3d.reg[2],"S3D Registers: 2D Polygon"); - save_item(s3virge.s3d.reg[3],"S3D Registers: 3D Line"); - save_item(s3virge.s3d.reg[4],"S3D Registers: 3D Triangle"); - - // Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason - for (int x = 0; x < 4; x++) - { - s3.cursor_fg[x] = 0xff; - s3.cursor_bg[x] = 0x00; - } - // set device ID - s3.id_high = 0x56; // CR2D - s3.id_low = 0x31; // CR2E - s3.revision = 0x00; // CR2F (value unknown) - s3.id_cr30 = 0xe1; // CR30 -} - -void s3virgedx_vga_device::device_start() -{ - s3virge_vga_device::device_start(); - - // set device ID - s3.id_high = 0x8a; // CR2D - s3.id_low = 0x01; // CR2E - s3.revision = 0x00; // CR2F (value unknown) - s3.id_cr30 = 0xe1; // CR30 -} - -void s3virgedx_rev1_vga_device::device_start() -{ - s3virge_vga_device::device_start(); - - // set device ID - s3.id_high = 0x8a; // CR2D - s3.id_low = 0x01; // CR2E - s3.revision = 0x01; // CR2F - s3.id_cr30 = 0xe1; // CR30 -} - -void s3virge_vga_device::device_reset() -{ - s3_vga_device::device_reset(); - // Power-on strapping bits. Sampled at reset, but can be modified later. - // These are just assumed defaults. - s3.strapping = 0x000f0912; - - // TODO: fix soft reset state - // On Windows 98 shutdown message sometimes leads to an hang the next boot around - s3virge.s3d.state = S3D_STATE_IDLE; - s3virge.s3d.cmd_fifo_current_ptr = 0; - s3virge.s3d.cmd_fifo_slots_free = 16; - s3virge.s3d.busy = false; - //m_draw_timer->adjust(attotime::never); -} - -void s3virgedx_vga_device::device_reset() -{ - s3virge_vga_device::device_reset(); - // Power-on strapping bits. Sampled at reset, but can be modified later. - // These are just assumed defaults. - s3.strapping = 0x000f0912; -} - -void s3virgedx_rev1_vga_device::device_reset() -{ - s3virgedx_vga_device::device_reset(); - // Power-on strapping bits. Sampled at reset, but can be modified later. - // These are based on results from a Diamond Stealth 3D 2000 Pro (Virge/DX based) - // bits 8-15 are still unknown, S3ID doesn't show config register 2 (CR37) - s3.strapping = 0x0aff0912; -} - -uint16_t s3virge_vga_device::offset() -{ - if(svga.rgb24_en) - return vga.crtc.offset * 6; // special handling for 24bpp packed mode - return s3_vga_device::offset(); -} - -uint8_t s3virge_vga_device::s3_crtc_reg_read(uint8_t index) -{ - uint8_t res; - - if(index <= 0x18) - res = crtc_reg_read(index); - else - { - switch(index) - { - case 0x2d: - res = s3.id_high; - break; - case 0x2e: - res = s3.id_low; - break; - case 0x2f: - res = s3.revision; - break; - case 0x30: // CR30 Chip ID/REV register - res = s3.id_cr30; - break; - case 0x31: - res = s3.memory_config; - break; - case 0x35: - res = s3.crt_reg_lock; - break; - case 0x36: // Configuration register 1 - res = s3.strapping & 0x000000ff; - break; - case 0x37: // Configuration register 2 - res = (s3.strapping & 0x0000ff00) >> 8; - break; - case 0x38: - res = s3.reg_lock1; - break; - case 0x39: - res = s3.reg_lock2; - break; - case 0x42: // CR42 Mode Control - res = s3.cr42 & 0x0f; // bit 5 set if interlaced, leave it unset for now. - break; - case 0x43: - res = s3.cr43; - break; - case 0x45: - res = s3.cursor_mode; - break; - case 0x46: - res = (s3.cursor_x & 0xff00) >> 8; - break; - case 0x47: - res = s3.cursor_x & 0x00ff; - break; - case 0x48: - res = (s3.cursor_y & 0xff00) >> 8; - break; - case 0x49: - res = s3.cursor_y & 0x00ff; - break; - case 0x4a: - res = s3.cursor_fg[s3.cursor_fg_ptr]; - s3.cursor_fg_ptr = 0; - break; - case 0x4b: - res = s3.cursor_bg[s3.cursor_bg_ptr]; - s3.cursor_bg_ptr = 0; - break; - case 0x4c: - res = (s3.cursor_start_addr & 0xff00) >> 8; - break; - case 0x4d: - res = s3.cursor_start_addr & 0x00ff; - break; - case 0x4e: - res = s3.cursor_pattern_x; - break; - case 0x4f: - res = s3.cursor_pattern_y; - break; - case 0x51: - res = (vga.crtc.start_addr_latch & 0x0c0000) >> 18; - res |= ((svga.bank_w & 0x30) >> 2); - break; - case 0x55: - res = s3.extended_dac_ctrl; - break; - case 0x58: - res = s3virge.linear_address_size & 0x03; - res |= s3virge.linear_address_enable ? 0x10 : 0x00; - break; - case 0x59: - res = (s3virge.linear_address & 0xff000000) >> 24; - break; - case 0x5a: - switch(s3virge.linear_address_size & 0x03) - { - case 0: // 64kB - default: - res = (s3virge.linear_address & 0x00ff0000) >> 16; - break; - case 1: // 1MB - res = (s3virge.linear_address & 0x00f00000) >> 16; - break; - case 2: // 2MB - res = (s3virge.linear_address & 0x00e00000) >> 16; - break; - case 3: // 4MB - res = (s3virge.linear_address & 0x00c00000) >> 16; - break; - } - break; - case 0x5c: - // if VGA dot clock is set to 3 (misc reg bits 2-3), then selected dot clock is read, otherwise read VGA clock select - if((vga.miscellaneous_output & 0xc) == 0x0c) - res = s3.cr42 & 0x0f; - else - res = (vga.miscellaneous_output & 0xc) >> 2; - break; - case 0x67: - res = s3.ext_misc_ctrl_2; - break; - case 0x68: // Configuration register 3 - res = (s3.strapping & 0x00ff0000) >> 16; - break; - case 0x69: - res = vga.crtc.start_addr_latch >> 16; - break; - case 0x6a: - res = svga.bank_r & 0x7f; - break; - case 0x6f: // Configuration register 4 - res = (s3.strapping & 0xff000000) >> 24; - break; - default: - res = vga.crtc.data[index]; - //machine.debug_break(); - //printf("%02x\n",index); - break; - } - } - - return res; -} - -void s3virge_vga_device::s3_define_video_mode() -{ - int divisor = 1; - const XTAL base_xtal = XTAL(14'318'181); - XTAL xtal = (vga.miscellaneous_output & 0xc) ? base_xtal*2 : base_xtal*1.75; - - if((vga.miscellaneous_output & 0xc) == 0x0c) - { - // Dot clock is set via SR12 and SR13 - // DCLK calculation - double ratio = (double)(s3.clk_pll_m+2) / (double)((s3.clk_pll_n+2)*(pow(2.0,s3.clk_pll_r))); // clock between XIN and XOUT - xtal = base_xtal * ratio; - //printf("DCLK set to %dHz M=%i N=%i R=%i\n",xtal,s3.clk_pll_m,s3.clk_pll_n,s3.clk_pll_r); - } - - if((s3.ext_misc_ctrl_2) >> 4) - { - svga.rgb8_en = 0; - svga.rgb15_en = 0; - svga.rgb16_en = 0; - svga.rgb24_en = 0; - switch((s3.ext_misc_ctrl_2) >> 4) - { - case 0x01: svga.rgb8_en = 1; break; - case 0x03: svga.rgb15_en = 1; divisor = 2; break; - case 0x05: svga.rgb16_en = 1; divisor = 2; break; - case 0x0d: svga.rgb24_en = 1; divisor = 1; break; - default: fatalerror("TODO: s3 video mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4)); - } - } - else - { - svga.rgb8_en = (s3.cr3a & 0x10) >> 4; - svga.rgb15_en = 0; - svga.rgb16_en = 0; - svga.rgb24_en = 0; - } - if(s3.cr43 & 0x80) // Horizontal clock doubling (technically, doubles horizontal CRT parameters) - divisor *= 2; - recompute_params_clock(divisor, xtal.value()); -} - -void s3virge_vga_device::s3_crtc_reg_write(uint8_t index, uint8_t data) -{ - if(index <= 0x18) - { - crtc_reg_write(index,data); - s3_define_video_mode(); - } - else - { - switch(index) - { - case 0x31: // CR31 Memory Configuration Register - s3.memory_config = data; - vga.crtc.start_addr_latch &= ~0x30000; - vga.crtc.start_addr_latch |= ((data & 0x30) << 12); - s3_define_video_mode(); - break; - case 0x35: - if((s3.reg_lock1 & 0xc) != 8 || ((s3.reg_lock1 & 0xc0) == 0)) // lock register - return; - s3.crt_reg_lock = data; - svga.bank_w = data & 0xf; - svga.bank_r = svga.bank_w; - break; - case 0x36: - if(s3.reg_lock2 == 0xa5) - { - s3.strapping = (s3.strapping & 0xffffff00) | data; - LOGREG("CR36: Strapping data = %08x\n",s3.strapping); - } - break; - case 0x37: - if(s3.reg_lock2 == 0xa5) - { - s3.strapping = (s3.strapping & 0xffff00ff) | (data << 8); - LOGREG("CR37: Strapping data = %08x\n",s3.strapping); - } - break; - case 0x38: - s3.reg_lock1 = data; - break; - case 0x39: - /* TODO: reg lock mechanism */ - s3.reg_lock2 = data; - break; - case 0x3a: - s3.cr3a = data; - break; - case 0x40: - s3.enable_s3d = data & 0x01; // enable S3D registers - break; - case 0x42: - s3.cr42 = data; // bit 5 = interlace, bits 0-3 = dot clock (seems to be undocumented) - break; - case 0x43: - s3.cr43 = data; // bit 2 = bit 8 of offset register, but only if bits 4-5 of CR51 are 00h. - if((s3.cr51 & 0x30) == 0) - vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x04) << 6); - else - vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr51 & 0x30) << 4); - s3_define_video_mode(); - break; -/* -3d4h index 45h (R/W): CR45 Hardware Graphics Cursor Mode -bit 0 HWGC ENB. Hardware Graphics Cursor Enable. Set to enable the - HardWare Cursor in VGA and enhanced modes. - 1 (911/24) Delay Timing for Pattern Data Fetch - 2 (801/5,928) Hardware Cursor Horizontal Stretch 2. If set the cursor - pixels are stretched horizontally to two bytes and items 0 and 1 of - the fore/background stacks in 3d4h index 4Ah/4Bh are used. - 3 (801/5,928) Hardware Cursor Horizontal Stretch 3. If set the cursor - pixels are stretched horizontally to three bytes and items 0,1 and - 2 of the fore/background stacks in 3d4h index 4Ah/4Bh are used. - 2-3 (805i,864/964) HWC-CSEL. Hardware Cursor Color Select. - 0: 4/8bit, 1: 15/16bt, 2: 24bit, 3: 32bit - Note: So far I've had better luck with: 0: 8/15/16bit, 1: 32bit?? - 4 (80x +) Hardware Cursor Right Storage. If set the cursor data is - stored in the last 256 bytes of 4 1Kyte lines (4bits/pixel) or the - last 512 bytes of 2 2Kbyte lines (8bits/pixel). Intended for - 1280x1024 modes where there are no free lines at the bottom. - 5 (928) Cursor Control Enable for Brooktree Bt485 DAC. If set and 3d4h - index 55h bit 5 is set the HC1 output becomes the ODF and the HC0 - output becomes the CDE - (964) BT485 ODF Selection for Bt485A RAMDAC. If set pin 185 (RS3 - /ODF) is the ODF output to a Bt485A compatible RamDAC (low for even - fields and high for odd fields), if clear pin185 is the RS3 output. - */ - case 0x45: - s3.cursor_mode = data; - break; -/* -3d4h index 46h M(R/W): CR46/7 Hardware Graphics Cursor Origin-X -bit 0-10 The HardWare Cursor X position. For 64k modes this value should be - twice the actual X co-ordinate. - */ - case 0x46: - s3.cursor_x = (s3.cursor_x & 0x00ff) | (data << 8); - break; - case 0x47: - s3.cursor_x = (s3.cursor_x & 0xff00) | data; - break; -/* -3d4h index 48h M(R/W): CR48/9 Hardware Graphics Cursor Origin-Y -bit 0-9 (911/24) The HardWare Cursor Y position. - 0-10 (80x +) The HardWare Cursor Y position. -Note: The position is activated when the high byte of the Y coordinate (index - 48h) is written, so this byte should be written last (not 911/924 ?) - */ - case 0x48: - s3.cursor_y = (s3.cursor_y & 0x00ff) | (data << 8); - break; - case 0x49: - s3.cursor_y = (s3.cursor_y & 0xff00) | data; - break; - -/* -3d4h index 4Ah (R/W): Hardware Graphics Cursor Foreground Stack (80x +) -bit 0-7 The Foreground Cursor color. Three bytes (4 for the 864/964) are - stacked here. When the Cursor Mode register (3d4h index 45h) is read - the stackpointer is reset. When a byte is written the byte is - written into the current top of stack and the stackpointer is - increased. The first byte written (item 0) is allways used, the - other two(3) only when Hardware Cursor Horizontal Stretch (3d4h - index 45h bit 2-3) is enabled. - */ - case 0x4a: - s3.cursor_fg[s3.cursor_fg_ptr++] = data; - s3.cursor_fg_ptr %= 4; - break; -/* -3d4h index 4Bh (R/W): Hardware Graphics Cursor Background Stack (80x +) -bit 0-7 The Background Cursor color. Three bytes (4 for the 864/964) are - stacked here. When the Cursor Mode register (3d4h index 45h) is read - the stackpointer is reset. When a byte is written the byte is - written into the current top of stack and the stackpointer is - increased. The first byte written (item 0) is allways used, the - other two(3) only when Hardware Cursor Horizontal Stretch (3d4h - index 45h bit 2-3) is enabled. - */ - case 0x4b: - s3.cursor_bg[s3.cursor_bg_ptr++] = data; - s3.cursor_bg_ptr %= 4; - break; -/* -3d4h index 4Ch M(R/W): CR4C/D Hardware Graphics Cursor Storage Start Address -bit 0-9 (911,924) HCS_STADR. Hardware Graphics Cursor Storage Start Address - 0-11 (80x,928) HWGC_STA. Hardware Graphics Cursor Storage Start Address - 0-12 (864,964) HWGC_STA. Hardware Graphics Cursor Storage Start Address - Address of the HardWare Cursor Map in units of 1024 bytes (256 bytes - for planar modes). The cursor map is a 64x64 bitmap with 2 bits (A - and B) per pixel. The map is stored as one word (16 bits) of bit A, - followed by one word with the corresponding 16 B bits. - The bits are interpreted as: - A B MS-Windows: X-11: - 0 0 Background Screen data - 0 1 Foreground Screen data - 1 0 Screen data Background - 1 1 Inverted screen Foreground - The Windows/X11 switch is only available for the 80x +. - (911/24) For 64k color modes the cursor is stored as one byte (8 - bits) of A bits, followed by the 8 B-bits, and each bit in the - cursor should be doubled to provide a consistent cursor image. - (801/5,928) For Hi/True color modes use the Horizontal Stretch bits - (3d4h index 45h bits 2 and 3). - */ - case 0x4c: - s3.cursor_start_addr = (s3.cursor_start_addr & 0x00ff) | (data << 8); - LOGREG("HW Cursor Address: %08x\n",s3.cursor_start_addr); - break; - case 0x4d: - s3.cursor_start_addr = (s3.cursor_start_addr & 0xff00) | data; - LOGREG("HW Cursor Address: %08x\n",s3.cursor_start_addr); - break; -/* -3d4h index 4Eh (R/W): CR4E HGC Pattern Disp Start X-Pixel Position -bit 0-5 Pattern Display Start X-Pixel Position. - */ - case 0x4e: - s3.cursor_pattern_x = data; - break; -/* -3d4h index 4Fh (R/W): CR4F HGC Pattern Disp Start Y-Pixel Position -bit 0-5 Pattern Display Start Y-Pixel Position. - */ - case 0x4f: - s3.cursor_pattern_y = data; - break; - case 0x51: - s3.cr51 = data; - vga.crtc.start_addr_latch &= ~0xc0000; - vga.crtc.start_addr_latch |= ((data & 0x3) << 18); - svga.bank_w = (svga.bank_w & 0xcf) | ((data & 0x0c) << 2); - svga.bank_r = svga.bank_w; - if((data & 0x30) != 0x00) - vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x30) << 4); - else - vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr43 & 0x04) << 6); - s3_define_video_mode(); - break; - case 0x53: - s3.cr53 = data; - break; -/* -3d4h index 55h (R/W): Extended Video DAC Control Register (80x +) -bit 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the - RAMDAC, allowing access to all 8 or 16 registers on advanced RAMDACs. - If this field is 0, 3d4h index 43h bit 1 is active. - 2 Enable General Input Port Read. If set DAC reads are disabled and the - STRD strobe for reading the General Input Port is enabled for reading - while DACRD is active, if clear DAC reads are enabled. - 3 (928) Enable External SID Operation if set. If set video data is - passed directly from the VRAMs to the DAC rather than through the - VGA chip - 4 Hardware Cursor MS/X11 Mode. If set the Hardware Cursor is in X11 - mode, if clear in MS-Windows mode - 5 (80x,928) Hardware Cursor External Operation Mode. If set the two - bits of cursor data ,is output on the HC[0-1] pins for the video DAC - The SENS pin becomes HC1 and the MID2 pin becomes HC0. - 6 ?? - 7 (80x,928) Disable PA Output. If set PA[0-7] and VCLK are tristated. - (864/964) TOFF VCLK. Tri-State Off VCLK Output. VCLK output tri - -stated if set - */ - case 0x55: - s3.extended_dac_ctrl = data; - break; - - case 0x58: - { - const uint8_t old_size = s3virge.linear_address_size; - const bool old_enable = s3virge.linear_address_enable; - const bool size_changed = old_size != s3virge.linear_address_size; - - s3virge.linear_address_size = data & 0x03; - s3virge.linear_address_enable = data & 0x10; - - switch(data & 0x03) - { - case LAW_64K: - s3virge.linear_address_size_full = 0x10000; - break; - case LAW_1MB: - s3virge.linear_address_size_full = 0x100000; - break; - case LAW_2MB: - s3virge.linear_address_size_full = 0x200000; - break; - case LAW_4MB: - s3virge.linear_address_size_full = 0x400000; - break; - } - - if ((s3virge.linear_address_enable != old_enable) || size_changed) - { - m_linear_config_changed_cb(s3virge.linear_address_enable); - } - - LOGREG("CR58: write %02x\n", data); - break; - } - case 0x59: - { - const uint32_t old_address = s3virge.linear_address; - s3virge.linear_address = (s3virge.linear_address & 0x00ff0000) | (data << 24); - LOGREG("Linear framebuffer address = %08x\n",s3virge.linear_address); - - if (old_address != s3virge.linear_address && s3virge.linear_address_enable) - { - m_linear_config_changed_cb(1); - } - break; - } - case 0x5a: - { - const uint32_t old_address = s3virge.linear_address; - s3virge.linear_address = (s3virge.linear_address & 0xff000000) | (data << 16); - LOGREG("Linear framebuffer address = %08x\n",s3virge.linear_address); - - if (old_address != s3virge.linear_address && s3virge.linear_address_enable) - { - m_linear_config_changed_cb(1); - } - break; - } - -/* -3d4h index 5Dh (R/W): Extended Horizontal Overflow Register (80x +) -bit 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h - index 0) - 1 Horizontal Display End bit 8. Bit 8 of the Horizontal Display End - register (3d4h index 1) - 2 Start Horizontal Blank bit 8. Bit 8 of the Horizontal Start Blanking - register (3d4h index 2). - 3 (864,964) EHB+64. End Horizontal Blank +64. If set the /BLANK pulse - is extended by 64 DCLKs. Note: Is this bit 6 of 3d4h index 3 or - does it really extend by 64 ? - 4 Start Horizontal Sync Position bit 8. Bit 8 of the Horizontal Start - Retrace register (3d4h index 4). - 5 (864,964) EHS+32. End Horizontal Sync +32. If set the HSYNC pulse - is extended by 32 DCLKs. Note: Is this bit 5 of 3d4h index 5 or - does it really extend by 32 ? - 6 (928,964) Data Transfer Position bit 8. Bit 8 of the Data Transfer - Position register (3d4h index 3Bh) - 7 (928,964) Bus-Grant Terminate Position bit 8. Bit 8 of the Bus Grant - Termination register (3d4h index 5Fh). -*/ - case 0x5d: - vga.crtc.horz_total = (vga.crtc.horz_total & 0xfeff) | ((data & 0x01) << 8); - vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0xfeff) | ((data & 0x02) << 7); - vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0xfeff) | ((data & 0x04) << 6); - vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xffbf) | ((data & 0x08) << 3); - vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0xfeff) | ((data & 0x10) << 4); - vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0xffdf) | (data & 0x20); - s3_define_video_mode(); - break; -/* -3d4h index 5Eh (R/W): Extended Vertical Overflow Register (80x +) -bit 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h - index 6). Bits 8 and 9 are in 3d4h index 7 bit 0 and 5. - 1 Vertical Display End bit 10. Bit 10 of the Vertical Display End - register (3d4h index 12h). Bits 8 and 9 are in 3d4h index 7 bit 1 - and 6 - 2 Start Vertical Blank bit 10. Bit 10 of the Vertical Start Blanking - register (3d4h index 15h). Bit 8 is in 3d4h index 7 bit 3 and bit 9 - in 3d4h index 9 bit 5 - 4 Vertical Retrace Start bit 10. Bit 10 of the Vertical Start Retrace - register (3d4h index 10h). Bits 8 and 9 are in 3d4h index 7 bit 2 - and 7. - 6 Line Compare Position bit 10. Bit 10 of the Line Compare register - (3d4h index 18h). Bit 8 is in 3d4h index 7 bit 4 and bit 9 in 3d4h - index 9 bit 6. - */ - case 0x5e: - vga.crtc.vert_total = (vga.crtc.vert_total & 0xfbff) | ((data & 0x01) << 10); - vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0xfbff) | ((data & 0x02) << 9); - vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0xfbff) | ((data & 0x04) << 8); - vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0xfbff) | ((data & 0x10) << 6); - vga.crtc.line_compare = (vga.crtc.line_compare & 0xfbff) | ((data & 0x40) << 4); - s3_define_video_mode(); - break; - case 0x67: - s3.ext_misc_ctrl_2 = data; - s3_define_video_mode(); - //printf("%02x X\n",data); - break; - case 0x68: - if(s3.reg_lock2 == 0xa5) - { - s3.strapping = (s3.strapping & 0xff00ffff) | (data << 16); - LOGREG("CR68: Strapping data = %08x\n",s3.strapping); - } - break; - case 0x69: - vga.crtc.start_addr_latch &= ~0x1f0000; - vga.crtc.start_addr_latch |= ((data & 0x1f) << 16); - s3_define_video_mode(); - break; - case 0x6a: - svga.bank_w = data & 0x3f; - svga.bank_r = svga.bank_w; - break; - case 0x6f: - if(s3.reg_lock2 == 0xa5) - { - s3.strapping = (s3.strapping & 0x00ffffff) | (data << 24); - LOGREG("CR6F: Strapping data = %08x\n",s3.strapping); - } - break; - default: - LOGREG("S3: CR%02X write %02x\n",index,data); - break; - } - } -} - - -uint8_t s3virge_vga_device::port_03b0_r(offs_t offset) -{ - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 5: - res = s3_crtc_reg_read(vga.crtc.index); - break; - default: - res = vga_device::port_03b0_r(offset); - break; - } - } - - return res; -} - -void s3virge_vga_device::port_03b0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 5: - vga.crtc.data[vga.crtc.index] = data; - s3_crtc_reg_write(vga.crtc.index,data); - break; - default: - vga_device::port_03b0_w(offset,data); - break; - } - } -} - -uint8_t s3virge_vga_device::port_03c0_r(offs_t offset) -{ - uint8_t res; - - switch(offset) - { - default: - res = s3_vga_device::port_03c0_r(offset); - break; - } - - return res; -} - -void s3virge_vga_device::port_03c0_w(offs_t offset, uint8_t data) -{ - switch(offset) - { - default: - s3_vga_device::port_03c0_w(offset,data); - break; - } -} - -uint8_t s3virge_vga_device::port_03d0_r(offs_t offset) -{ - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - res = s3_crtc_reg_read(vga.crtc.index); - break; - default: - res = vga_device::port_03d0_r(offset); - break; - } - } - - return res; -} - -void s3virge_vga_device::port_03d0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - vga.crtc.data[vga.crtc.index] = data; - s3_crtc_reg_write(vga.crtc.index,data); - break; - default: - vga_device::port_03d0_w(offset,data); - break; - } - } -} - -uint8_t s3virge_vga_device::mem_r(offs_t offset) -{ - if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) - { - uint8_t data; - if(offset & 0x10000) - return 0; - data = 0xff; - if(vga.sequencer.data[4] & 0x8) - { - if(offset + (svga.bank_r*0x10000) < vga.svga_intf.vram_size) - data = vga.memory[offset + (svga.bank_r*0x10000)]; - } - else - { - int i; - - for(i=0;i<4;i++) - { - if(vga.sequencer.map_mask & 1 << i) - { - if(offset*4+i+(svga.bank_r*0x10000) < vga.svga_intf.vram_size) - data |= vga.memory[offset*4+i+(svga.bank_r*0x10000)]; - } - } - } - return data; - } - if((offset + (svga.bank_r*0x10000)) < vga.svga_intf.vram_size) - return vga_device::mem_r(offset); - else - return 0xff; -} - -void s3virge_vga_device::mem_w(offs_t offset, uint8_t data) -{ - // bit 4 of CR53 enables memory-mapped I/O - if(s3.cr53 & 0x10) - { - // TODO - } - - if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) - { - // printf("%08x %02x (%02x %02x) %02X\n",offset,data,vga.sequencer.map_mask,svga.bank_w,(vga.sequencer.data[4] & 0x08)); - if(offset & 0x10000) - return; - if(vga.sequencer.data[4] & 0x8) - { - if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size) - vga.memory[(offset + (svga.bank_w*0x10000))] = data; - } - else - { - int i; - for(i=0;i<4;i++) - { - if(vga.sequencer.map_mask & 1 << i) - { - if((offset*4+i+(svga.bank_w*0x10000)) < vga.svga_intf.vram_size) - vga.memory[(offset*4+i+(svga.bank_w*0x10000))] = data; - } - } - } - return; - } - - if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size) - vga_device::mem_w(offset,data); -} - -uint8_t s3virge_vga_device::fb_r(offs_t offset) -{ - if(offset < s3virge.linear_address_size_full) - return vga.memory[offset % vga.svga_intf.vram_size]; - return 0xff; -} - -void s3virge_vga_device::fb_w(offs_t offset, uint8_t data) -{ - if(offset < s3virge.linear_address_size_full) - vga.memory[offset % vga.svga_intf.vram_size] = data; -} - -void s3virge_vga_device::add_command(int cmd_type) -{ - // add command to S3D FIFO - if(s3virge.s3d.cmd_fifo_slots_free == 0) - { - LOGCMD("Attempt to add command when all command slots are full\n"); - return; - } - memcpy(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].reg,s3virge.s3d.reg[cmd_type],256*4); - s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type; - LOGCMD("Added command type %i cmd %08x ptr %u\n",s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type,s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].reg[S3D_REG_COMMAND],s3virge.s3d.cmd_fifo_next_ptr); - s3virge.s3d.cmd_fifo_next_ptr++; - if(s3virge.s3d.cmd_fifo_next_ptr >= 16) - s3virge.s3d.cmd_fifo_next_ptr = 0; - if(s3virge.s3d.cmd_fifo_slots_free == 16) // if all slots are free, start command now - command_start(); - s3virge.s3d.cmd_fifo_slots_free--; - // TODO: handle full FIFO -} - -void s3virge_vga_device::command_start() -{ - // start next command in FIFO - int cmd_type = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type; - - switch(cmd_type) - { - case OP_2DLINE: - LOGCMD("2D Line command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); - break; - case OP_2DPOLY: - LOGCMD("2D Poly command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); - break; - case OP_3DLINE: - LOGCMD("3D Line command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); - break; - case OP_3DTRI: - LOGCMD("3D Tri command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); - break; - case OP_BITBLT: - s3virge.s3d.state = S3D_STATE_BITBLT; - s3virge.s3d.busy = true; - s3virge.s3d.bitblt_x_src = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RSRC_XY] & 0x07ff0000) >> 16; - s3virge.s3d.bitblt_y_src = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RSRC_XY] & 0x000007ff); - s3virge.s3d.bitblt_x_dst = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RDEST_XY] & 0x07ff0000) >> 16; - s3virge.s3d.bitblt_y_dst = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RDEST_XY] & 0x000007ff); - s3virge.s3d.bitblt_width = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RWIDTH_HEIGHT] & 0xffff0000) >> 16; - s3virge.s3d.bitblt_height = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RWIDTH_HEIGHT] & 0x0000ffff); - s3virge.s3d.bitblt_x_current = s3virge.s3d.bitblt_x_dst; - s3virge.s3d.bitblt_x_src_current = s3virge.s3d.bitblt_x_src; - s3virge.s3d.bitblt_y_current = s3virge.s3d.bitblt_y_dst; - s3virge.s3d.bitblt_y_src_current = s3virge.s3d.bitblt_y_src; - s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8; - s3virge.s3d.bitblt_pat_y = s3virge.s3d.bitblt_y_current % 8; - s3virge.s3d.clip_r = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_L_R] & 0x000007ff; - s3virge.s3d.clip_l = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_L_R] & 0x07ff0000) >> 16; - s3virge.s3d.clip_b = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_T_B] & 0x000007ff; - s3virge.s3d.clip_t = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_T_B] & 0x07ff0000) >> 16; - if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000080)) - m_draw_timer->adjust(attotime::from_nsec(250),0,attotime::from_nsec(250)); - s3virge.s3d.bitblt_step_count = 0; - s3virge.s3d.bitblt_mono_pattern = - s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_MONO_PAT_0] | (uint64_t)(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_MONO_PAT_1]) << 32; - s3virge.s3d.bitblt_current_pixel = 0; - s3virge.s3d.bitblt_pixel_pos = 0; - s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR] = 0xffffffff; // win31 never sets this? - LOGCMD("Started BitBLT command [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); - //if(((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x01fe0000) >> 17) == 0xf0) machine().debug_break(); - break; - } -} - -void s3virge_vga_device::command_finish() -{ - s3virge.s3d.state = S3D_STATE_IDLE; - s3virge.s3d.cmd_fifo_current_ptr++; - if(s3virge.s3d.cmd_fifo_current_ptr >= 16) - s3virge.s3d.cmd_fifo_current_ptr = 0; - s3virge.s3d.cmd_fifo_slots_free++; - if(s3virge.s3d.cmd_fifo_slots_free > 16) - s3virge.s3d.cmd_fifo_slots_free = 16; - m_draw_timer->adjust(attotime::never); - - // check if there is another command in the FIFO - if(s3virge.s3d.cmd_fifo_slots_free < 16) - command_start(); - else - s3virge.s3d.busy = false; - - LOGMMIO("Command finished [%u] (%u slots free)\n",s3virge.s3d.cmd_fifo_current_ptr,s3virge.s3d.cmd_fifo_slots_free); -} - -void s3virge_vga_device::line2d_step() -{ - command_finish(); -} - -void s3virge_vga_device::poly2d_step() -{ - command_finish(); -} - -void s3virge_vga_device::line3d_step() -{ - command_finish(); -} - -void s3virge_vga_device::poly3d_step() -{ - command_finish(); -} - - -uint32_t s3virge_vga_device::GetROP(uint8_t rop, uint32_t src, uint32_t dst, uint32_t pat) -{ - uint32_t ret = 0; - - switch(rop) - { - case 0x00: // 0 - ret = 0; - break; - case 0x0a: // DPna - ret = (dst & (~pat)); - break; - case 0x22: // DSna - ret = (dst & (~src)); - break; - case 0x33: // Sn - ret = ~src; - break; - case 0x55: // Dn - ret = ~dst; - break; - case 0x5a: // DPx - ret = dst ^ pat; - break; - case 0x66: // DSx - ret = dst ^ src; - break; - case 0x88: // DSa - ret = dst & src; - break; - case 0xb8: // PSDPxax - ret = ((dst ^ pat) & src) ^ pat; - break; - case 0xbb: // DSno - ret = (dst | (~src)); - break; - case 0xcc: - ret = src; - break; - case 0xe2: // DSPDxax - ret = ((pat ^ dst) & src) ^ dst; - break; - case 0xee: // DSo - ret = (dst | src); - break; - case 0xf0: - ret = pat; - break; - case 0xff: // 1 - ret = 0xffffffff; - break; - default: - popmessage("bus/isa/s3virge.cpp: Unimplemented ROP 0x%02x",rop); - } - - return ret; -} - -bool s3virge_vga_device::advance_pixel() -{ - bool xpos, ypos; - int16_t top, left, right, bottom; - // advance src/dst and pattern location - xpos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x02000000; // X Positive - ypos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x04000000; // Y Positive - if(xpos) - { - left = s3virge.s3d.bitblt_x_dst; - right = s3virge.s3d.bitblt_x_dst + s3virge.s3d.bitblt_width + 1; - s3virge.s3d.bitblt_x_current++; - s3virge.s3d.bitblt_x_src_current++; - s3virge.s3d.bitblt_pat_x++; - } - else - { - left = s3virge.s3d.bitblt_x_dst - s3virge.s3d.bitblt_width - 1; - right = s3virge.s3d.bitblt_x_dst; - s3virge.s3d.bitblt_x_current--; - s3virge.s3d.bitblt_x_src_current--; - s3virge.s3d.bitblt_pat_x--; -// machine().debug_break(); - } - if(ypos) - { - top = s3virge.s3d.bitblt_y_dst; - bottom = s3virge.s3d.bitblt_y_dst + s3virge.s3d.bitblt_height; - } - else - { - top = s3virge.s3d.bitblt_y_dst - s3virge.s3d.bitblt_height; - bottom = s3virge.s3d.bitblt_y_dst; - } - if(s3virge.s3d.bitblt_pat_x < 0 || s3virge.s3d.bitblt_pat_x >= 8) - s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8; - if((s3virge.s3d.bitblt_x_current >= right) || (s3virge.s3d.bitblt_x_current <= left)) - { - s3virge.s3d.bitblt_x_current = s3virge.s3d.bitblt_x_dst; - s3virge.s3d.bitblt_x_src_current = s3virge.s3d.bitblt_x_src; - if(ypos) - { - s3virge.s3d.bitblt_y_current++; - s3virge.s3d.bitblt_y_src_current++; - s3virge.s3d.bitblt_pat_y++; - } - else - { - s3virge.s3d.bitblt_y_current--; - s3virge.s3d.bitblt_y_src_current--; - s3virge.s3d.bitblt_pat_y--; - } - s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8; - if(s3virge.s3d.bitblt_pat_y >= 8 || s3virge.s3d.bitblt_pat_y < 0) - s3virge.s3d.bitblt_pat_y = s3virge.s3d.bitblt_y_current % 8; - logerror("SRC: %i,%i DST: %i,%i PAT: %i,%i Bounds: %i,%i,%i,%i\n", - s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, - s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, - s3virge.s3d.bitblt_pat_x,s3virge.s3d.bitblt_pat_y, - left,right,top,bottom); - if((s3virge.s3d.bitblt_y_current >= bottom) || (s3virge.s3d.bitblt_y_current <= top)) - return true; - } - return false; -} - -void s3virge_vga_device::bitblt_step() -{ - if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x40)) - bitblt_monosrc_step(); - else - bitblt_colour_step(); -} - -void s3virge_vga_device::bitblt_colour_step() -{ - // progress current BitBLT operation - // get source and destination addresses - uint32_t src_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BASE] & 0x003ffff8; - uint32_t dst_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_BASE] & 0x003ffff8; - - const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND]; - const uint8_t pixel_size = (current_command & 0x0000001c) >> 2; - const uint8_t rop = (current_command & 0x01fe0000) >> 17; - const int align = (current_command & 0x000000c00) >> 10; - //const bool tp = bool(BIT(current_command, 9)); - const bool de = bool(BIT(current_command, 5)); - - uint32_t src = 0; - uint32_t dst = 0; - uint32_t pat = 0; - int x; - bool done = false; - - switch(pixel_size) - { - case 0: // 8bpp - for(x=0;x<4;x++) - { - if(current_command & 0x80) - src = s3virge.s3d.image_xfer >> (x*8); - else - src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - if(current_command & 0x100) - { - pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); - } - else - { - pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y * 8) + s3virge.s3d.bitblt_pat_x]; - } - dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - - if (de) - write_pixel8(dst_base, s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, GetROP(rop, src, dst, pat) & 0xff); - - done = advance_pixel(); - if(done) - { - command_finish(); - break; - } - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) - { - if(align == 2) // doubleword aligned, end here - break; - if(align == 1) // word aligned, move to next word - { - if(x < 2) - x = 2; - else - break; - } - } - } - break; - case 1: // 16bpp - if(current_command & 0x80) - src = s3virge.s3d.image_xfer; - else - src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - if(current_command & 0x100) - { - pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); - } - else - pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2) + 1]) << 8; - - if (de) - write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff); - done = advance_pixel(); - if(done) - { - command_finish(); - break; - } - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst && align == 2) - break; // if a new line of an image transfer, and is dword aligned, stop here - if(current_command & 0x80) - src = s3virge.s3d.image_xfer >> 16; - else - src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - if(current_command & 0x100) - { - pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); - } - else - pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2) + 1]) << 8; - if (de) - write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff); - if(advance_pixel()) - command_finish(); - break; - case 2: // 24bpp - if(current_command & 0x80) - { - src = s3virge.s3d.image_xfer; - for(x=0;x<4;x++) - { - s3virge.s3d.bitblt_current_pixel |= ((s3virge.s3d.image_xfer >> (x*8)) & 0xff) << s3virge.s3d.bitblt_pixel_pos*8; - s3virge.s3d.bitblt_pixel_pos++; - if(s3virge.s3d.bitblt_pixel_pos > 2) - { - s3virge.s3d.bitblt_pixel_pos = 0; - dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - if(current_command & 0x100) - { - pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); - } - else - pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 1]) << 8 - | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 2]) << 16; - if (de) - write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.bitblt_current_pixel, dst, pat)); - s3virge.s3d.bitblt_current_pixel = 0; - done = advance_pixel(); - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) - { - if(align == 2) // doubleword aligned, end here - x = 4; - if(align == 1) // word aligned, move to next word - { - if(x < 2) - x = 2; - else - x = 4; - } - } - if(done) - command_finish(); - } - } - break; - } - else - { - src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - if(current_command & 0x100) - { - pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) - ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); - } - else - pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 1]) << 8 - | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 2]) << 16; - } - if (de) - write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat)); - if(advance_pixel()) - command_finish(); - break; - } - - s3virge.s3d.bitblt_step_count++; -} - -void s3virge_vga_device::bitblt_monosrc_step() -{ - // progress current monochrome source BitBLT operation - uint32_t src_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BASE] & 0x003ffff8; - uint32_t dst_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_BASE] & 0x003ffff8; - - const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND]; - const uint8_t pixel_size = (current_command & 0x0000001c) >> 2; - const uint8_t rop = (current_command & 0x01fe0000) >> 17; - //const bool tp = bool(BIT(current_command, 9)); - const bool de = bool(BIT(current_command, 5)); - const int align = (current_command & 0x000000c00) >> 10; - - uint32_t src = 0; - uint32_t dst = 0; - // Windows 98 cares about this being initialized to non-zero for - // greyed back/forward icons in Explorer, system icons and right click disabled Paste command. - uint32_t pat = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR]; - int x; - bool done = false; - - switch(pixel_size) - { - case 0: // 8bpp - for(x=31;x>=0;x--) - { - if(current_command & 0x80) - src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); - else - src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - - if (de) - { - if(src & (1 << x)) - write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xff); - else if(!(current_command & 0x200)) // only draw background colour if transparency is not set - write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xff); - } - //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop); - done = advance_pixel(); - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) - { - switch(align) - { - case 0: - x &= ~7; - break; - case 1: - x &= ~15; - break; - case 2: - x = -1; - break; - } - if(done) - { - command_finish(); - break; - } - } - } - break; - case 1: // 16bpp - for(x=31;x>=0;x--) - { - if(current_command & 0x80) - src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); - else - src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - - if (de) - { - if(src & (1 << x)) - write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xffff); - else if(!(current_command & 0x200)) // only draw background colour if transparency is not set - write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xffff); - } - //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop); - done = advance_pixel(); - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) - { - switch(align) - { - case 0: - x &= ~7; - break; - case 1: - x &= ~15; - break; - case 2: - x = -1; - break; - } - if(done) - { - command_finish(); - break; - } - } - } - break; - case 2: // 24bpp - for(x=31;x>=0;x--) - { - if(current_command & 0x80) - src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); - else - src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); - dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); - - if (de) - { - if(src & (1 << x)) - write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat)); - else if(!(current_command & 0x200)) // only draw background colour if transparency is not set - write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat)); - } - //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop); - done = advance_pixel(); - if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) - { - switch(align) - { - case 0: - x &= ~7; - break; - case 1: - x &= ~15; - break; - case 2: - x = -1; - break; - } - if(done) - { - command_finish(); - break; - } - } - } - break; - } - - s3virge.s3d.bitblt_step_count++; -} - -TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) -{ - // TODO: S3D state timing - switch(s3virge.s3d.state) - { - case S3D_STATE_IDLE: - m_draw_timer->adjust(attotime::zero); - break; - case S3D_STATE_2DLINE: - line2d_step(); - break; - case S3D_STATE_2DPOLY: - poly2d_step(); - break; - case S3D_STATE_3DLINE: - line3d_step(); - break; - case S3D_STATE_3DPOLY: - poly3d_step(); - break; - case S3D_STATE_BITBLT: - bitblt_step(); - break; - } -} - -inline void s3virge_vga_device::write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val) -{ - if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002) - if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b) - return; - vga.memory[(base + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = val & 0xff; - vga.memory[(base + 1 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 8) & 0xff; - vga.memory[(base + 2 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 16) & 0xff; - vga.memory[(base + 3 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 24) & 0xff; -} - -inline void s3virge_vga_device::write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val) -{ - if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002) - if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b) - return; - vga.memory[(base + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] = val & 0xff; - vga.memory[(base + 1 + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 8) & 0xff; - vga.memory[(base + 2 + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 16) & 0xff; -} - -inline void s3virge_vga_device::write_pixel16(uint32_t base, uint16_t x, uint16_t y, uint16_t val) -{ - if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002) - if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b) - return; - vga.memory[(base + (x*2) + (y*dest_stride())) % vga.svga_intf.vram_size] = val & 0xff; - vga.memory[(base + 1 + (x*2) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 8) & 0xff; -} - -inline void s3virge_vga_device::write_pixel8(uint32_t base, uint16_t x, uint16_t y, uint8_t val) -{ - if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002) - if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b) - return; - vga.memory[(base + x + (y*dest_stride())) % vga.svga_intf.vram_size] = val; -} - -inline uint32_t s3virge_vga_device::read_pixel32(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) -{ - return (vga.memory[(base + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 24) | - (vga.memory[(base + 1 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 16) | - (vga.memory[(base + 2 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 8) | - vga.memory[(base + 3 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size]; -} - -inline uint32_t s3virge_vga_device::read_pixel24(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) -{ - return (vga.memory[(base + (x * 3) + (y * stride_select)) % vga.svga_intf.vram_size]) | - (vga.memory[(base + 1 + (x * 3) + (y * stride_select)) % vga.svga_intf.vram_size] << 8) | - (vga.memory[(base + 2 + (x * 3) + (y * stride_select)) % vga.svga_intf.vram_size] << 16); -} - -inline uint16_t s3virge_vga_device::read_pixel16(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) -{ - return (vga.memory[(base + (x * 2) + (y * stride_select) % vga.svga_intf.vram_size)]) | - (vga.memory[(base + 1 + (x * 2) + (y * stride_select)) % vga.svga_intf.vram_size] << 8); -} - -inline uint8_t s3virge_vga_device::read_pixel8(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) -{ - return vga.memory[(base + x + (y * stride_select)) % vga.svga_intf.vram_size]; -} - -// 2D command register format - A500 (BitBLT), A900 (2D line), AD00 (2D Polygon) -// bit 0 - Autoexecute, if set command is executed when the highest relevant register is written to (A50C / A97C / AD7C) -// bit 1 - Enable hardware clipping -// bits 2-4 - Destination colour format - (0 = 8bpp palettised, 1 = 16bpp RGB1555 or RGB565, 2 = 24bpp RGB888 -// bit 5 - Draw enable - if reset, doesn't draw anything, but is still executed -// bit 6 - Image source Mono transfer, if set source is mono, otherwise source is the same pixel depth as the destination -// bit 7 - Image data source - 0 = source is in video memory, 1 = source is from the image transfer port (CPU / system memory) -// bit 8 - Mono pattern - if set, pattern data is mono, otherwise pattern data is the same pixel depth as the destination -// Cleared to 0 if using an ROP with a colour source Must be set to 1 if doing a rectangle fill operation -// bit 9 - Transparency - if set, does not update if a background colour is selected. Effectively only if bit 7 is set, Typically used for text display. -// bits 10-11 - Image transfer alignment - Data for an image transfer is byte (0), word (1), or doubleword (2) aligned. All image transfers are doubleword in size. -// bits 12-13 - First doubleword offset - (Image transfers) - start with the given byte (+1) in a doubleword for an image transfer -// bits 17-24 - MS Windows Raster Operation -// bit 25 - X Positive - if set, BitBLT is performed from left to right, otherwise, from right to left -// bit 26 - Y Positive - if set, BitBLT is performed from top to bottom, otherwise from bottom to top -// bits 27-30 - 2D Command - 0000 = BitBLT, 0010 = Rectangle Fill, 0011 = Line Draw, 0101 = Polygon Fill, 1111 = NOP (Turns off autoexecute without executing a command) -// bit 31 - 2D / 3D Select - - -uint32_t s3virge_vga_device::s3d_sub_status_r() -{ - uint32_t res = 0x00000000; - - if(!s3virge.s3d.busy) - res |= 0x00002000; // S3d engine is idle - - //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); - if(s3virge.s3d.cmd_fifo_slots_free == 16) - res |= 0x1f00; - - return res; -} - -void s3virge_vga_device::s3d_sub_control_w(uint32_t data) -{ - s3virge.interrupt_enable = data & 0x00003f80; - // TODO: bits 14-15==10 - reset engine - LOGMMIO("Sub control = %08x\n", data); -} - -/* - * Advanced Function Control Register (MM850C) - * ---- --xx xx-- ---- command fifo status - * ---- ---- ---x ---- LA ENB Linear Addressing Enable (mirror of CR58 bit 4) - * ---- ---- ---- --x- RST DM Reset read DMA - * ---- ---- ---- ---x ENB EHFC Enable enhanced functions (mirror of CR66 bit 0) - */ -uint32_t s3virge_vga_device::s3d_func_ctrl_r() -{ - uint32_t ret = 0; - - ret |= (s3virge.s3d.cmd_fifo_slots_free << 6); - return ret; -} - -uint32_t s3virge_vga_device::s3d_register_r(offs_t offset) -{ - uint32_t res = 0; - int op_type = (((offset*4) & 0x1c00) >> 10) - 1; - - // unused registers - if(offset < 0x100/4) - return 0; - if(offset >= 0x1c0/4 && offset < 0x400/4) - return 0; - - // handle BitBLT pattern registers - if((offset >= 0x100/4) && (offset < 0x1c0/4)) - return s3virge.s3d.pattern[offset - (0x100/4)]; - - res = s3virge.s3d.reg[op_type][((offset*4) & 0x03ff) / 4]; - LOGMMIO("MM%04X returning %08x\n", (offset*4)+0xa000, res); - - return res; -} - -void s3virge_vga_device::s3d_register_w(offs_t offset, uint32_t data) -{ - int op_type = (((offset*4) & 0x1c00) >> 10) - 1; - - // unused registers - if(offset < 0x100/4) - return; - if(offset >= 0x1c0/4 && offset < 0x400/4) - return; - - // handle BitBLT pattern registers - if((offset >= 0x100/4) && (offset < 0x1c0/4)) - { - //COMBINE_DATA(&s3virge.s3d.pattern[(offset*4) - (0x100/4)]); - s3virge.s3d.pattern[((offset - 0x100/4)*4)+3] = (data & 0xff000000) >> 24; - s3virge.s3d.pattern[((offset - 0x100/4)*4)+2] = (data & 0x00ff0000) >> 16; - s3virge.s3d.pattern[((offset - 0x100/4)*4)+1] = (data & 0x0000ff00) >> 8; - s3virge.s3d.pattern[((offset - 0x100/4)*4)] = (data & 0x000000ff); - return; - } - - s3virge.s3d.reg[op_type][((offset*4) & 0x03ff) / 4] = data; - LOGMMIO("MM%04X = %08x\n", (offset*4)+0xa000, data); - switch(offset) - { - case 0x500/4: - if(!(data & 0x00000001)) - add_command(op_type); - break; - case 0x50c/4: - if(s3virge.s3d.reg[op_type][S3D_REG_COMMAND] & 0x00000001) // autoexecute enabled - add_command(op_type); - break; - } -} - diff --git a/src/devices/bus/isa/s3virge.h b/src/devices/bus/isa/s3virge.h deleted file mode 100644 index ba2abd8cfd9..00000000000 --- a/src/devices/bus/isa/s3virge.h +++ /dev/null @@ -1,255 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Barry Rodewald -/* - * s3virge.h - * - * S3 ViRGE 2D/3D video card - * - */ - -#ifndef MAME_BUS_ISA_S3VIRGE_H -#define MAME_BUS_ISA_S3VIRGE_H - -#pragma once - -#include "video/pc_vga_s3.h" - -// ======================> s3virge_vga_device - -class s3virge_vga_device : public s3_vga_device -{ -public: - // construction/destruction - s3virge_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - auto linear_config_changed() { return m_linear_config_changed_cb.bind(); } - - virtual uint8_t port_03b0_r(offs_t offset) override; - virtual void port_03b0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03c0_r(offs_t offset) override; - virtual void port_03c0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03d0_r(offs_t offset) override; - virtual void port_03d0_w(offs_t offset, uint8_t data) override; - virtual uint8_t mem_r(offs_t offset) override; - virtual void mem_w(offs_t offset, uint8_t data) override; - - uint8_t fb_r(offs_t offset); - void fb_w(offs_t offset, uint8_t data); - uint32_t s3d_sub_status_r(); - void s3d_sub_control_w(uint32_t data); - uint32_t s3d_func_ctrl_r(); - - uint32_t s3d_register_r(offs_t offset); - void s3d_register_w(offs_t offset, uint32_t data); - - void image_xfer(uint32_t data) - { -// if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000080) - { -// logerror("IMG Xfer:(%u):%08x X:%u(%u) Y:%u(%u)\n",s3virge.s3d.bitblt_step_count,data,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_width,s3virge.s3d.bitblt_y_current,s3virge.s3d.bitblt_height); - s3virge.s3d.image_xfer = data; - bitblt_step(); - } - } - - uint32_t get_linear_address() { return s3virge.linear_address; } - void set_linear_address(uint32_t addr) { s3virge.linear_address = addr; } - uint8_t get_linear_address_size() { return s3virge.linear_address_size; } - uint32_t get_linear_address_size_full() { return s3virge.linear_address_size_full; } - bool is_linear_address_active() { return s3virge.linear_address_enable; } - bool is_new_mmio_active() { return s3.cr53 & 0x08; } - uint16_t src_stride() - { - return (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 0) & 0xfff8; - } - uint16_t dest_stride() - { -// if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x0000001c) == 0x08) -// { -// popmessage("Stride=%08x",(((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8) / 3) -// + ((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8)); -// return (((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8) / 3) -// + ((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8); -// } -// else - return (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8; - } - - ibm8514a_device* get_8514() { fatalerror("s3virge requested non-existent 8514/A device\n"); return nullptr; } - -protected: - s3virge_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); - - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - virtual uint16_t offset() override; - - enum - { - LAW_64K = 0, - LAW_1MB, - LAW_2MB, - LAW_4MB - }; - - // register groups - enum - { - OP_BITBLT = 0, - OP_2DLINE, - OP_2DPOLY, - OP_3DLINE, - OP_3DTRI - }; - - enum - { - S3D_STATE_IDLE = 0, - S3D_STATE_BITBLT, - S3D_STATE_2DLINE, - S3D_STATE_2DPOLY, - S3D_STATE_3DLINE, - S3D_STATE_3DPOLY - }; - - enum - { - S3D_REG_SRC_BASE = 0xd4/4, - S3D_REG_DEST_BASE = 0xd8/4, - S3D_REG_CLIP_L_R = 0xdc/4, - S3D_REG_CLIP_T_B = 0xe0/4, - S3D_REG_DEST_SRC_STR = 0xe4/4, - S3D_REG_MONO_PAT_0 = 0xe8/4, - S3D_REG_MONO_PAT_1 = 0xec/4, - S3D_REG_PAT_BG_CLR = 0xf0/4, - S3D_REG_PAT_FG_CLR = 0xf4/4, - S3D_REG_SRC_BG_CLR = 0xf8/4, - S3D_REG_SRC_FG_CLR = 0xfc/4, - S3D_REG_COMMAND = 0x100/4, - S3D_REG_RWIDTH_HEIGHT = 0x104/4, - S3D_REG_RSRC_XY = 0x108/4, - S3D_REG_RDEST_XY = 0x10c/4 - }; - - struct - { - uint32_t linear_address; - uint8_t linear_address_size; - uint32_t linear_address_size_full; - bool linear_address_enable; - uint32_t interrupt_enable; - - struct - { - int state; - bool busy; - struct - { - uint32_t reg[256]; - int op_type; - } cmd_fifo[16]; - int cmd_fifo_next_ptr; // command added here in FIFO - int cmd_fifo_current_ptr; // command currently being processed in FIFO - int cmd_fifo_slots_free; - - uint8_t pattern[0xc0]; - uint32_t reg[5][256]; - - // BitBLT command state - uint16_t bitblt_x_src; - uint16_t bitblt_y_src; - uint16_t bitblt_x_dst; - uint16_t bitblt_y_dst; - int16_t bitblt_x_current; - int16_t bitblt_y_current; - int16_t bitblt_x_src_current; - int16_t bitblt_y_src_current; - int8_t bitblt_pat_x; - int8_t bitblt_pat_y; - uint16_t bitblt_height; - uint16_t bitblt_width; - uint32_t bitblt_step_count; - uint64_t bitblt_mono_pattern; - uint32_t bitblt_current_pixel; - uint32_t bitblt_pixel_pos; // current position in a pixel (for packed 24bpp colour image transfers) - uint32_t image_xfer; // source data via image transfer ports - uint16_t clip_l; - uint16_t clip_r; - uint16_t clip_t; - uint16_t clip_b; - } s3d; - } s3virge; - - TIMER_CALLBACK_MEMBER(draw_step_tick); - - inline void write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val); - inline void write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val); - inline void write_pixel16(uint32_t base, uint16_t x, uint16_t y, uint16_t val); - inline void write_pixel8(uint32_t base, uint16_t x, uint16_t y, uint8_t val); - inline uint32_t read_pixel32(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); - inline uint32_t read_pixel24(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); - inline uint16_t read_pixel16(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); - inline uint8_t read_pixel8(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); - - uint32_t GetROP(uint8_t rop, uint32_t src, uint32_t dst, uint32_t pat); - bool advance_pixel(); - - devcb_write_line m_linear_config_changed_cb; - -private: - emu_timer* m_draw_timer; - void bitblt_step(); - void bitblt_colour_step(); - void bitblt_monosrc_step(); - void line2d_step(); - void poly2d_step(); - void line3d_step(); - void poly3d_step(); - void add_command(int cmd_type); - void command_start(); - void command_finish(); - - virtual uint8_t s3_crtc_reg_read(uint8_t index); - virtual void s3_define_video_mode(void); - virtual void s3_crtc_reg_write(uint8_t index, uint8_t data); - // has no 8514/A device -}; - - -// ======================> s3virgedx_vga_device - -class s3virgedx_vga_device : public s3virge_vga_device -{ -public: - // construction/destruction - s3virgedx_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - -protected: - s3virgedx_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); - - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; -}; - -// ======================> s3virgedx_vga_device - -class s3virgedx_rev1_vga_device : public s3virgedx_vga_device -{ -public: - // construction/destruction - s3virgedx_rev1_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - -protected: - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; -}; - -// device type definition -DECLARE_DEVICE_TYPE(S3VIRGE, s3virge_vga_device) -DECLARE_DEVICE_TYPE(S3VIRGEDX, s3virgedx_vga_device) -DECLARE_DEVICE_TYPE(S3VIRGEDX1, s3virgedx_rev1_vga_device) - -#endif // MAME_BUS_ISA_S3VIRGE_H diff --git a/src/devices/bus/isa/svga_cirrus.cpp b/src/devices/bus/isa/svga_cirrus.cpp index 750d0f41142..25275181781 100644 --- a/src/devices/bus/isa/svga_cirrus.cpp +++ b/src/devices/bus/isa/svga_cirrus.cpp @@ -65,6 +65,11 @@ isa16_svga_cirrus_device::isa16_svga_cirrus_device(const machine_config &mconfig { } +void isa16_svga_cirrus_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(cirrus_gd5430_device::io_map)); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -76,11 +81,8 @@ void isa16_svga_cirrus_device::device_start() m_isa->install_rom(this, 0xc0000, 0xc7fff, "dm_clgd5430"); - m_isa->install_device(0x03b0, 0x03bf, read8sm_delegate(*m_vga, FUNC(cirrus_gd5430_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(cirrus_gd5430_device::port_03b0_w))); - m_isa->install_device(0x03c0, 0x03cf, read8sm_delegate(*m_vga, FUNC(cirrus_gd5430_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(cirrus_gd5430_device::port_03c0_w))); - m_isa->install_device(0x03d0, 0x03df, read8sm_delegate(*m_vga, FUNC(cirrus_gd5430_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(cirrus_gd5430_device::port_03d0_w))); - m_isa->install_memory(0xa0000, 0xbffff, read8sm_delegate(*m_vga, FUNC(cirrus_gd5430_device::mem_r)), write8sm_delegate(*m_vga, FUNC(cirrus_gd5430_device::mem_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_svga_cirrus_device::io_isa_map); } //------------------------------------------------- @@ -145,6 +147,11 @@ isa16_svga_cirrus_gd542x_device::isa16_svga_cirrus_gd542x_device(const machine_c { } +void isa16_svga_cirrus_gd542x_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(cirrus_gd5428_device::io_map)); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -156,11 +163,9 @@ void isa16_svga_cirrus_gd542x_device::device_start() m_isa->install_rom(this, 0xc0000, 0xc7fff, "clgd542x"); - m_isa->install_device(0x03b0, 0x03bf, read8sm_delegate(*m_vga, FUNC(cirrus_gd5428_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(cirrus_gd5428_device::port_03b0_w))); - m_isa->install_device(0x03c0, 0x03cf, read8sm_delegate(*m_vga, FUNC(cirrus_gd5428_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(cirrus_gd5428_device::port_03c0_w))); - m_isa->install_device(0x03d0, 0x03df, read8sm_delegate(*m_vga, FUNC(cirrus_gd5428_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(cirrus_gd5428_device::port_03d0_w))); - m_isa->install_memory(0xa0000, 0xbffff, read8sm_delegate(*m_vga, FUNC(cirrus_gd5428_device::mem_r)), write8sm_delegate(*m_vga, FUNC(cirrus_gd5428_device::mem_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_svga_cirrus_gd542x_device::io_isa_map); + } //------------------------------------------------- diff --git a/src/devices/bus/isa/svga_cirrus.h b/src/devices/bus/isa/svga_cirrus.h index d2e7d75595c..0286d3d8510 100644 --- a/src/devices/bus/isa/svga_cirrus.h +++ b/src/devices/bus/isa/svga_cirrus.h @@ -6,7 +6,7 @@ #pragma once #include "isa.h" -#include "video/clgd542x.h" +#include "video/pc_vga_cirrus.h" //************************************************************************** // TYPE DEFINITIONS @@ -31,6 +31,8 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); + private: required_device m_vga; }; @@ -54,6 +56,8 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); + private: required_device m_vga; }; diff --git a/src/devices/bus/isa/svga_s3.cpp b/src/devices/bus/isa/svga_s3.cpp index 1315c471679..57ad259fd99 100644 --- a/src/devices/bus/isa/svga_s3.cpp +++ b/src/devices/bus/isa/svga_s3.cpp @@ -1,10 +1,13 @@ // license:BSD-3-Clause // copyright-holders:Barry Rodewald -/*************************************************************************** +/************************************************************************************************** ISA SVGA S3 wrapper -***************************************************************************/ + TODO: + - All these cards are really PCI and needs to be moved to video/virge_pci.cpp. + +**************************************************************************************************/ #include "emu.h" #include "svga_s3.h" @@ -86,6 +89,11 @@ isa16_svga_s3_device::isa16_svga_s3_device(const machine_config &mconfig, const { } +void isa16_svga_s3_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(s3_vga_device::io_map)); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -97,9 +105,8 @@ void isa16_svga_s3_device::device_start() m_isa->install_rom(this, 0xc0000, 0xc7fff, "s3_764"); - m_isa->install_device(0x03b0, 0x03bf, read8sm_delegate(*m_vga, FUNC(s3_vga_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(s3_vga_device::port_03b0_w))); - m_isa->install_device(0x03c0, 0x03cf, read8sm_delegate(*m_vga, FUNC(s3_vga_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(s3_vga_device::port_03c0_w))); - m_isa->install_device(0x03d0, 0x03df, read8sm_delegate(*m_vga, FUNC(s3_vga_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(s3_vga_device::port_03d0_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_svga_s3_device::io_isa_map); + m_isa->install16_device(0x82e8, 0x82eb, read16smo_delegate(*m_8514, FUNC(ibm8514a_device::ibm8514_currenty_r)), write16smo_delegate(*m_8514, FUNC(ibm8514a_device::ibm8514_currenty_w))); m_isa->install16_device(0x86e8, 0x86eb, read16smo_delegate(*m_8514, FUNC(ibm8514a_device::ibm8514_currentx_r)), write16smo_delegate(*m_8514, FUNC(ibm8514a_device::ibm8514_currentx_w))); m_isa->install16_device(0x8ae8, 0x8aeb, read16smo_delegate(*m_8514, FUNC(ibm8514a_device::ibm8514_desty_r)), write16smo_delegate(*m_8514, FUNC(ibm8514a_device::ibm8514_desty_w))); @@ -202,6 +209,11 @@ isa16_s3virge_device::isa16_s3virge_device(const machine_config &mconfig, const { } +void isa16_s3virge_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(s3virge_vga_device::io_map)); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -213,9 +225,7 @@ void isa16_s3virge_device::device_start() m_isa->install_rom(this, 0xc0000, 0xc7fff, "s3virge"); - m_isa->install_device(0x03b0, 0x03bf, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03b0_w))); - m_isa->install_device(0x03c0, 0x03cf, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03c0_w))); - m_isa->install_device(0x03d0, 0x03df, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03d0_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_s3virge_device::io_isa_map); m_isa->install_memory(0xa0000, 0xbffff, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::mem_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::mem_w))); } @@ -310,6 +320,12 @@ isa16_s3virgedx_device::isa16_s3virgedx_device(const machine_config &mconfig, co { } +void isa16_s3virgedx_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(s3virgedx_vga_device::io_map)); +} + + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -321,11 +337,9 @@ void isa16_s3virgedx_device::device_start() m_isa->install_rom(this, 0xc0000, 0xc7fff, "s3virgedx"); - m_isa->install_device(0x03b0, 0x03bf, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03b0_w))); - m_isa->install_device(0x03c0, 0x03cf, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03c0_w))); - m_isa->install_device(0x03d0, 0x03df, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03d0_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_s3virgedx_device::io_isa_map); - m_isa->install_memory(0xa0000, 0xbffff, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::mem_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::mem_w))); + m_isa->install_memory(0xa0000, 0xbffff, read8sm_delegate(*m_vga, FUNC(s3virgedx_vga_device::mem_r)), write8sm_delegate(*m_vga, FUNC(s3virgedx_vga_device::mem_w))); save_item(NAME(m_lfb_enable)); save_item(NAME(m_lfb_start)); @@ -410,6 +424,11 @@ isa16_stealth3d2kpro_device::isa16_stealth3d2kpro_device(const machine_config &m { } +void isa16_stealth3d2kpro_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(s3virgedx_vga_device::io_map)); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -421,11 +440,9 @@ void isa16_stealth3d2kpro_device::device_start() m_isa->install_rom(this, 0xc0000, 0xc7fff, "stealth3d"); - m_isa->install_device(0x03b0, 0x03bf, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03b0_w))); - m_isa->install_device(0x03c0, 0x03cf, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03c0_w))); - m_isa->install_device(0x03d0, 0x03df, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::port_03d0_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_stealth3d2kpro_device::io_isa_map); - m_isa->install_memory(0xa0000, 0xbffff, read8sm_delegate(*m_vga, FUNC(s3virge_vga_device::mem_r)), write8sm_delegate(*m_vga, FUNC(s3virge_vga_device::mem_w))); + m_isa->install_memory(0xa0000, 0xbffff, read8sm_delegate(*m_vga, FUNC(s3virgedx_vga_device::mem_r)), write8sm_delegate(*m_vga, FUNC(s3virgedx_vga_device::mem_w))); } //------------------------------------------------- diff --git a/src/devices/bus/isa/svga_s3.h b/src/devices/bus/isa/svga_s3.h index 7009ce28167..c414c7ee6f6 100644 --- a/src/devices/bus/isa/svga_s3.h +++ b/src/devices/bus/isa/svga_s3.h @@ -6,9 +6,8 @@ #pragma once #include "isa.h" -#include "s3virge.h" - #include "video/pc_vga_s3.h" +#include "video/s3virge.h" //************************************************************************** @@ -36,6 +35,8 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); + private: required_device m_vga; required_device m_8514; @@ -62,6 +63,8 @@ protected: void linear_config_changed_w(int state); + void io_isa_map(address_map &map); + private: required_device m_vga; }; @@ -87,6 +90,8 @@ protected: void linear_config_changed_w(int state); + void io_isa_map(address_map &map); + private: required_device m_vga; bool m_lfb_enable; @@ -115,6 +120,8 @@ protected: void linear_config_changed_w(int state); + void io_isa_map(address_map &map); + private: required_device m_vga; }; diff --git a/src/devices/bus/isa/svga_trident.cpp b/src/devices/bus/isa/svga_trident.cpp index 0c5024d08ba..790a405770e 100644 --- a/src/devices/bus/isa/svga_trident.cpp +++ b/src/devices/bus/isa/svga_trident.cpp @@ -52,6 +52,11 @@ isa16_svga_tvga9000_device::isa16_svga_tvga9000_device(const machine_config &mco { } +void isa16_svga_tvga9000_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(tvga9000_device::io_map)); +} + uint8_t isa16_svga_tvga9000_device::input_port_0_r() { return 0xff; } //return machine().root_device().ioport("IN0")->read(); } void isa16_svga_tvga9000_device::device_start() @@ -60,9 +65,8 @@ void isa16_svga_tvga9000_device::device_start() m_isa->install_rom(this, 0xc0000, 0xc7fff, "tvga9000"); - m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*m_vga, FUNC(tvga9000_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(tvga9000_device::port_03b0_w))); - m_isa->install_device(0x3c0, 0x3cf, read8sm_delegate(*m_vga, FUNC(tvga9000_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(tvga9000_device::port_03c0_w))); - m_isa->install_device(0x3d0, 0x3df, read8sm_delegate(*m_vga, FUNC(tvga9000_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(tvga9000_device::port_03d0_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_svga_tvga9000_device::io_isa_map); + m_isa->install_device(0x43c4, 0x43cb, read8sm_delegate(*m_vga, FUNC(tvga9000_device::port_43c6_r)), write8sm_delegate(*m_vga, FUNC(tvga9000_device::port_43c6_w))); m_isa->install_device(0x83c4, 0x83cb, read8sm_delegate(*m_vga, FUNC(tvga9000_device::port_83c6_r)), write8sm_delegate(*m_vga, FUNC(tvga9000_device::port_83c6_w))); @@ -122,6 +126,11 @@ isa16_svga_tgui9680_device::isa16_svga_tgui9680_device(const machine_config &mco { } +void isa16_svga_tgui9680_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(trident_vga_device::io_map)); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -133,9 +142,8 @@ void isa16_svga_tgui9680_device::device_start() m_isa->install_rom(this, 0xc0000, 0xc7fff, "tgui9680"); - m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*m_vga, FUNC(trident_vga_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(trident_vga_device::port_03b0_w))); - m_isa->install_device(0x3c0, 0x3cf, read8sm_delegate(*m_vga, FUNC(trident_vga_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(trident_vga_device::port_03c0_w))); - m_isa->install_device(0x3d0, 0x3df, read8sm_delegate(*m_vga, FUNC(trident_vga_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(trident_vga_device::port_03d0_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_svga_tgui9680_device::io_isa_map); + m_isa->install_device(0x43c4, 0x43cb, read8sm_delegate(*m_vga, FUNC(trident_vga_device::port_43c6_r)), write8sm_delegate(*m_vga, FUNC(trident_vga_device::port_43c6_w))); m_isa->install_device(0x83c4, 0x83cb, read8sm_delegate(*m_vga, FUNC(trident_vga_device::port_83c6_r)), write8sm_delegate(*m_vga, FUNC(trident_vga_device::port_83c6_w))); diff --git a/src/devices/bus/isa/svga_trident.h b/src/devices/bus/isa/svga_trident.h index 39afd40be96..1ca7b622009 100644 --- a/src/devices/bus/isa/svga_trident.h +++ b/src/devices/bus/isa/svga_trident.h @@ -34,6 +34,8 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); + private: required_device m_vga; }; @@ -56,6 +58,8 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); + private: required_device m_vga; }; diff --git a/src/devices/bus/isa/svga_tseng.cpp b/src/devices/bus/isa/svga_tseng.cpp index be93e3188fe..39a6533f3c7 100644 --- a/src/devices/bus/isa/svga_tseng.cpp +++ b/src/devices/bus/isa/svga_tseng.cpp @@ -118,11 +118,14 @@ void isa8_svga_et4k_device::remap(int space_id, offs_t start, offs_t end) map_io(); } +void isa8_svga_et4k_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(tseng_vga_device::io_map)); +} + void isa8_svga_et4k_device::map_io() { - m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*m_vga, FUNC(tseng_vga_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(tseng_vga_device::port_03b0_w))); - m_isa->install_device(0x3c0, 0x3cf, read8sm_delegate(*m_vga, FUNC(tseng_vga_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(tseng_vga_device::port_03c0_w))); - m_isa->install_device(0x3d0, 0x3df, read8sm_delegate(*m_vga, FUNC(tseng_vga_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(tseng_vga_device::port_03d0_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa8_svga_et4k_device::io_isa_map); } void isa8_svga_et4k_device::map_ram() diff --git a/src/devices/bus/isa/svga_tseng.h b/src/devices/bus/isa/svga_tseng.h index f1b56423ef0..f842889e027 100644 --- a/src/devices/bus/isa/svga_tseng.h +++ b/src/devices/bus/isa/svga_tseng.h @@ -41,6 +41,8 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); + private: void map_io(); void map_ram(); diff --git a/src/devices/bus/isa/vga.cpp b/src/devices/bus/isa/vga.cpp index b573f4c5701..3fa8752ae91 100644 --- a/src/devices/bus/isa/vga.cpp +++ b/src/devices/bus/isa/vga.cpp @@ -62,6 +62,11 @@ isa8_vga_device::isa8_vga_device(const machine_config &mconfig, const char *tag, { } +void isa8_vga_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(vga_device::io_map)); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -73,9 +78,7 @@ void isa8_vga_device::device_start() m_isa->install_rom(this, 0xc0000, 0xc7fff, "ibm_vga"); - m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*m_vga, FUNC(vga_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(vga_device::port_03b0_w))); - m_isa->install_device(0x3c0, 0x3cf, read8sm_delegate(*m_vga, FUNC(vga_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(vga_device::port_03c0_w))); - m_isa->install_device(0x3d0, 0x3df, read8sm_delegate(*m_vga, FUNC(vga_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(vga_device::port_03d0_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &isa8_vga_device::io_isa_map); m_isa->install_memory(0xa0000, 0xbffff, read8sm_delegate(*m_vga, FUNC(vga_device::mem_r)), write8sm_delegate(*m_vga, FUNC(vga_device::mem_w))); } diff --git a/src/devices/bus/isa/vga.h b/src/devices/bus/isa/vga.h index c1b4d7226aa..1a3a530160d 100644 --- a/src/devices/bus/isa/vga.h +++ b/src/devices/bus/isa/vga.h @@ -33,6 +33,8 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); + private: required_device m_vga; }; diff --git a/src/devices/bus/isa/vga_ati.cpp b/src/devices/bus/isa/vga_ati.cpp index b3a7c1414bc..bee1f847c18 100644 --- a/src/devices/bus/isa/vga_ati.cpp +++ b/src/devices/bus/isa/vga_ati.cpp @@ -159,6 +159,21 @@ isa16_vga_mach64_device::isa16_vga_mach64_device(const machine_config &mconfig, { } +void isa16_vga_gfxultra_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(ati_vga_device::io_map)); +} + +void isa16_vga_gfxultrapro_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(mach32_device::io_map)); +} + +void isa16_vga_mach64_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(mach64_device::io_map)); +} + //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- @@ -174,9 +189,9 @@ void isa16_vga_gfxultra_device::device_start() m_isa->install_device(0x1ce, 0x1cf, read8sm_delegate(*m_vga, FUNC(ati_vga_device::ati_port_ext_r)), write8sm_delegate(*m_vga, FUNC(ati_vga_device::ati_port_ext_w))); m_isa->install_device(0x2e8, 0x2ef, read8sm_delegate(*m_8514, FUNC(mach8_device::ibm8514_status_r)), write8sm_delegate(*m_8514, FUNC(mach8_device::ibm8514_htotal_w))); - m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*m_vga, FUNC(ati_vga_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(vga_device::port_03b0_w))); - m_isa->install_device(0x3c0, 0x3cf, read8sm_delegate(*m_vga, FUNC(ati_vga_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(vga_device::port_03c0_w))); - m_isa->install_device(0x3d0, 0x3df, read8sm_delegate(*m_vga, FUNC(ati_vga_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(vga_device::port_03d0_w))); + + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_vga_gfxultra_device::io_isa_map); + m_isa->install16_device(0x12e8, 0x12eb, read16smo_delegate(*m_8514, FUNC(mach8_device::ibm8514_vtotal_r)), write16smo_delegate(*m_8514, FUNC(mach8_device::ibm8514_vtotal_w))); m_isa->install16_device(0x12ec, 0x12ef, read16smo_delegate(*m_8514, FUNC(mach8_device::mach8_config1_r)), write16smo_delegate(*this)); m_isa->install16_device(0x16e8, 0x16eb, read16smo_delegate(*m_8514, FUNC(mach8_device::ibm8514_vdisp_r)), write16smo_delegate(*m_8514, FUNC(mach8_device::ibm8514_vdisp_w))); @@ -235,9 +250,9 @@ void isa16_vga_gfxultrapro_device::device_start() m_isa->install_device(0x1ce, 0x1cf, read8sm_delegate(*m_vga, FUNC(mach32_device::ati_port_ext_r)), write8sm_delegate(*m_vga, FUNC(mach32_device::ati_port_ext_w))); m_isa->install_device(0x2e8, 0x2ef, read8sm_delegate(*m_vga, FUNC(mach32_device::mach32_status_r)), write8sm_delegate(*m_vga, FUNC(mach32_device::ibm8514_htotal_w))); - m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*m_vga, FUNC(mach32_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(mach32_device::port_03b0_w))); - m_isa->install_device(0x3c0, 0x3cf, read8sm_delegate(*m_vga, FUNC(mach32_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(mach32_device::port_03c0_w))); - m_isa->install_device(0x3d0, 0x3df, read8sm_delegate(*m_vga, FUNC(mach32_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(mach32_device::port_03d0_w))); + + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_vga_gfxultrapro_device::io_isa_map); + m_isa->install16_device(0xaec, 0xaef, read16sm_delegate(*m_vga, FUNC(mach32_device::mach32_readonly_sm_r)), write16sm_delegate(*m_vga, FUNC(mach32_device::mach32_cursor_l_w))); m_isa->install16_device(0xeec, 0xeef, read16sm_delegate(*m_vga, FUNC(mach32_device::mach32_readonly_sm_r)), write16sm_delegate(*m_vga, FUNC(mach32_device::mach32_cursor_h_w))); m_isa->install16_device(0x12e8, 0x12eb, read16smo_delegate(*m_vga, FUNC(mach32_device::ibm8514_vtotal_r)), write16smo_delegate(*m_vga, FUNC(mach32_device::ibm8514_vtotal_w))); @@ -304,9 +319,9 @@ void isa16_vga_mach64_device::device_start() m_isa->install_device(0x1ce, 0x1cf, read8sm_delegate(*m_vga, FUNC(mach64_device::ati_port_ext_r)), write8sm_delegate(*m_vga, FUNC(mach64_device::ati_port_ext_w))); m_isa->install_device(0x2e8, 0x2ef, read8sm_delegate(*m_vga, FUNC(mach64_device::mach32_status_r)), write8sm_delegate(*m_vga, FUNC(mach64_device::ibm8514_htotal_w))); - m_isa->install_device(0x3b0, 0x3bf, read8sm_delegate(*m_vga, FUNC(mach64_device::port_03b0_r)), write8sm_delegate(*m_vga, FUNC(mach64_device::port_03b0_w))); - m_isa->install_device(0x3c0, 0x3cf, read8sm_delegate(*m_vga, FUNC(mach64_device::port_03c0_r)), write8sm_delegate(*m_vga, FUNC(mach64_device::port_03c0_w))); - m_isa->install_device(0x3d0, 0x3df, read8sm_delegate(*m_vga, FUNC(mach64_device::port_03d0_r)), write8sm_delegate(*m_vga, FUNC(mach64_device::port_03d0_w))); + + m_isa->install_device(0x03b0, 0x03df, *this, &isa16_vga_mach64_device::io_isa_map); + m_isa->install16_device(0x12e8, 0x12eb, read16smo_delegate(*m_vga, FUNC(mach64_device::ibm8514_vtotal_r)), write16smo_delegate(*m_vga, FUNC(mach64_device::ibm8514_vtotal_w))); m_isa->install16_device(0x12ec, 0x12ef, read16smo_delegate(*m_vga, FUNC(mach64_device::mach32_config1_smo_r)), write16smo_delegate(*m_vga, FUNC(mach64_device::mach64_config1_w))); m_isa->install16_device(0x16e8, 0x16eb, read16smo_delegate(*m_vga, FUNC(mach64_device::ibm8514_vdisp_r)), write16smo_delegate(*m_vga, FUNC(mach64_device::ibm8514_vdisp_w))); diff --git a/src/devices/bus/isa/vga_ati.h b/src/devices/bus/isa/vga_ati.h index 5ca355f590c..3b7c064bbaa 100644 --- a/src/devices/bus/isa/vga_ati.h +++ b/src/devices/bus/isa/vga_ati.h @@ -42,6 +42,8 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); + private: required_device m_vga; required_device m_8514; @@ -66,6 +68,8 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); + private: required_device m_vga; }; @@ -89,6 +93,7 @@ protected: virtual void device_add_mconfig(machine_config &config) override; virtual const tiny_rom_entry *device_rom_region() const override; + void io_isa_map(address_map &map); private: required_device m_vga; }; diff --git a/src/devices/machine/sis630_gui.cpp b/src/devices/machine/sis630_gui.cpp index cdbd4fe9db9..8cc245cbed0 100644 --- a/src/devices/machine/sis630_gui.cpp +++ b/src/devices/machine/sis630_gui.cpp @@ -29,7 +29,6 @@ - 2d acceleration; - Turbo queue stuff; - AGP; - - interlace (cfr. xubuntu 6.10 splash screen on 1024x768x32); - xubuntu 6.10 splash screen is decentered (zooming?) - xubuntu 6.10 splash screen text is unreadable or not visible depending on res selected; - Interface with '301 bridge (a lovely can of worms); @@ -43,10 +42,9 @@ #define LOG_TODO (1U << 2) // log unimplemented registers #define LOG_MAP (1U << 3) // log full remaps #define LOG_AGP (1U << 4) // log AGP -#define LOG_SVGA (1U << 5) // log SVGA -#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP | LOG_AGP | LOG_SVGA) -//#define LOG_OUTPUT_FUNC osd_printf_warning +#define VERBOSE (LOG_GENERAL | LOG_IO | LOG_TODO | LOG_MAP | LOG_AGP) +//#define LOG_OUTPUT_FUNC osd_printf_info #include "logmacro.h" @@ -54,303 +52,6 @@ #define LOGMAP(...) LOGMASKED(LOG_MAP, __VA_ARGS__) #define LOGTODO(...) LOGMASKED(LOG_TODO, __VA_ARGS__) #define LOGAGP(...) LOGMASKED(LOG_AGP, __VA_ARGS__) -#define LOGSVGA(...) LOGMASKED(LOG_SVGA, __VA_ARGS__) - -/************************** - * - * SVGA implementation - * - *************************/ - -// TODO: later variant of 5598 -// (definitely doesn't have dual segment mode for instance) -DEFINE_DEVICE_TYPE(SIS630_SVGA, sis630_svga_device, "sis630_svga", "SiS 630 SVGA") - -sis630_svga_device::sis630_svga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : svga_device(mconfig, SIS630_SVGA, tag, owner, clock) -{ - -} - -void sis630_svga_device::device_start() -{ - svga_device::device_start(); - zero(); - - // Avoid an infinite loop when displaying. 0 is not possible anyway. - vga.crtc.maximum_scan_line = 1; - - // copy over interfaces - vga.svga_intf.seq_regcount = 0x05; - vga.svga_intf.crtc_regcount = 0x27; - vga.svga_intf.vram_size = 64*1024*1024; - //vga.memory = std::make_unique(vga.svga_intf.vram_size); -} - -void sis630_svga_device::device_reset() -{ - svga_device::device_reset(); - - m_svga_bank_reg_w = m_svga_bank_reg_r = 0; - m_unlock_reg = false; - //m_dual_seg_mode = false; -} - -// Page 144 -uint8_t sis630_svga_device::crtc_reg_read(uint8_t index) -{ - if (index < 0x19) - return svga_device::crtc_reg_read(index); - - // make sure '301 CRT2 is not enabled - if (index == 0x30) - return 0; - - if (index == 0x31) - return 0x60; - - if (index == 0x32) - return 0x20; - - // TODO: if one of these is 0xff then it enables a single port transfer to $b8000 - return m_crtc_ext_regs[index]; -} - -void sis630_svga_device::crtc_reg_write(uint8_t index, uint8_t data) -{ - if (index < 0x19) - svga_device::crtc_reg_write(index, data); - else - { - m_crtc_ext_regs[index] = data; - } -} - -uint8_t sis630_svga_device::seq_reg_read(uint8_t index) -{ - switch (index) - { - // extended id register - case 0x05: - return m_unlock_reg ? 0xa1 : 0x21; - case 0x06: - return m_ramdac_mode; - case 0x07: - return m_ext_misc_ctrl_0; - case 0x0a: - return m_ext_vert_overflow; - case 0x0b: - case 0x0c: - return m_ext_horz_overflow[index - 0xb]; - case 0x0d: - return vga.crtc.start_addr_latch >> 16; - case 0x14: - // sis_main.c calculates VRAM size in two ways: - // 1. the legacy way ('300), by probing this register - // 2. by reading '630 PCI host register $63 (as shared DRAM?) - // Method 1 seems enough to enforce "64MB" message at POST, - // 2 is probably more correct but unsure about how to change the shared area in BIOS - // (shutms11 will always write a "0x41" on fresh CMOS then a "0x47" - // on successive boots no matter what) - const u8 bus_width = m_seq_ext_regs[index] & 0xc0; - return (bus_width) | ((vga.svga_intf.vram_size / (1024 * 1024) - 1) & 0x3f); - } - - //LOGSVGA("Unemulated index R [%02x]\n", index); - return m_seq_ext_regs[index]; -} - -std::tuple sis630_svga_device::flush_true_color_mode() -{ - // punt if extended or true color is off - if ((m_ramdac_mode & 0x12) != 0x12) - return std::make_tuple(0, 0); - - const u8 res = (m_ext_misc_ctrl_0 & 4) >> 2; - - return std::make_tuple(res, res ^ 1); -} - -void sis630_svga_device::recompute_params() -{ - // TODO: ext clock - recompute_params_clock(1, XTAL(25'174'800).value()); -} - - -void sis630_svga_device::seq_reg_write(uint8_t index, uint8_t data) -{ - if (index < vga.svga_intf.seq_regcount) - svga_device::seq_reg_write(index, data); - else - { - if (index == 0x05) - { - m_unlock_reg = (data == 0x86); - LOGSVGA("Unlock register write %02x (%s)\n", data, m_unlock_reg ? "unlocked" : "locked"); - } - else - { - if (!m_unlock_reg) - { - LOGSVGA("Attempt to write to extended SVGA while locked [$%02x] -> %02x\n", index, data); - return; - } - - m_seq_ext_regs[index] = data; - - switch(index) - { - /* - * x--- ---- GFX mode linear addressing enable - * -x-- ---- GFX hardware cursor display - * --x- ---- GFX mode interlace - * ---x ---- True Color enable (ties with index 0x07 bit 2) - * ---- x--- RGB16 enable - * ---- -x-- RGB15 enable - * ---- --x- enhanced GFX mode enable - * ---- ---x enhanced text mode enable - */ - case 0x06: - m_ramdac_mode = data; - LOGSVGA("RAMDAC mode %02x\n", data); - - if (!BIT(data, 1)) - { - svga.rgb8_en = svga.rgb15_en = svga.rgb16_en = svga.rgb24_en = svga.rgb32_en = 0; - } - else - { - if (BIT(data, 2)) - svga.rgb15_en = 1; - if (BIT(data, 3)) - svga.rgb16_en = 1; - std::tie(svga.rgb24_en, svga.rgb32_en) = flush_true_color_mode(); - } - break; - case 0x07: - LOGSVGA("Extended Misc. Control register 0 (%02x) %02x\n", index, data); - m_ext_misc_ctrl_0 = data; - std::tie(svga.rgb24_en, svga.rgb32_en) = flush_true_color_mode(); - break; - case 0x0a: - LOGSVGA("Extended vertical Overflow register (%02x) %02x\n", index, data); - m_ext_vert_overflow = data; - vga.crtc.vert_retrace_end = (vga.crtc.vert_retrace_end & 0xf) | ((data & 0x20) >> 1); - vga.crtc.vert_blank_end = (vga.crtc.vert_blank_end & 0x00ff) | ((data & 0x10) << 4); - vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0x03ff) | ((data & 0x08) << 7); - vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0x03ff) | ((data & 0x04) << 8); - vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0x03ff) | ((data & 0x02) << 9); - vga.crtc.vert_total = (vga.crtc.vert_total & 0x03ff) | ((data & 0x01) << 10); - recompute_params(); - break; - case 0x0b: - //m_dual_seg_mode = bool(BIT(data, 3)); - LOGSVGA("Extended horizontal Overflow 1 (%02x) %02x\n", index, data); - m_ext_horz_overflow[0] = data; - - vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0x00ff) | ((data & 0xc0) << 2); - vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0x00ff) | ((data & 0x30) << 4); - vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0x00ff) | ((data & 0x0c) << 6); - vga.crtc.horz_total = (vga.crtc.horz_total & 0x00ff) | ((data & 0x03) << 8); - - recompute_params(); - break; - case 0x0c: - LOGSVGA("Extended horizontal Overflow 2 (%02x) %02x\n", index, data); - m_ext_horz_overflow[1] = data; - - vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0x001f) | ((data & 0x04) << 3); - vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0x003f) | ((data & 0x03) << 6); - recompute_params(); - break; - case 0x0d: - LOGSVGA("Extended starting address register (%02x) %02x\n", index, data); - vga.crtc.start_addr_latch &= ~0xff0000; - vga.crtc.start_addr_latch |= data << 16; - break; - case 0x0e: - LOGSVGA("Extended pitch register (%02x) %02x\n", index, data); - // sis_main.c implicitly sets this with bits 0-3 granularity, assume being right - vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x0f) << 8); - break; - case 0x1e: - if (data & 0x40) - popmessage("Warning: enable 2d engine"); - break; - case 0x20: - if (data & 0x81) - popmessage("Warning: %s %s", BIT(data, 7) ? "PCI address enabled" : "", BIT(data, 0) ? "memory map I/O enable" : ""); - break; - default: - LOGSVGA("Extended write %02x %02x\n", index, data); - break; - } - } - } -} - -uint16_t sis630_svga_device::offset() -{ - if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) - return vga.crtc.offset << 3; - return svga_device::offset(); -} - -// read by gamecstl Kontron BIOS -u8 sis630_svga_device::port_03c0_r(offs_t offset) -{ - if (offset == 0xd) - return m_svga_bank_reg_w; - if (offset == 0xb) - return m_svga_bank_reg_r; - - return svga_device::port_03c0_r(offset); -} - -void sis630_svga_device::port_03c0_w(offs_t offset, uint8_t data) -{ - // TODO: for '630 it's always with dual segment enabled? - - if (offset == 0xd) - { - //if (m_dual_seg_mode) - m_svga_bank_reg_w = (data & 0x3f) * 0x10000; - //else - { - // m_svga_bank_reg_w = (data >> 4) * 0x10000; - // m_svga_bank_reg_r = (data & 0xf) * 0x10000; - } - return; - } - - if (offset == 0xb) - { - //if (m_dual_seg_mode) - m_svga_bank_reg_r = (data & 0x3f) * 0x10000; - // otherwise ignored if dual segment mode disabled - return; - } - - svga_device::port_03c0_w(offset, data); -} - -uint8_t sis630_svga_device::mem_r(offs_t offset) -{ - if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) - return svga_device::mem_linear_r(offset + m_svga_bank_reg_r); - return svga_device::mem_r(offset); -} - -void sis630_svga_device::mem_w(offs_t offset, uint8_t data) -{ - if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) - { - svga_device::mem_linear_w(offset + m_svga_bank_reg_w, data); - return; - } - svga_device::mem_w(offset, data); -} /***************************** * @@ -515,9 +216,7 @@ void sis630_gui_device::space_io_map(address_map &map) // RIO + 0x16: 301 RAMDAC // RIO + 0x30/+0x40/+0x50: omitted, legacy '300/'630 VGA regs? // (gamecstl definitely tries to access 0x44 index 5 for readback extension ID) - map(0x30, 0x3f).rw(FUNC(sis630_gui_device::vga_3b0_r), FUNC(sis630_gui_device::vga_3b0_w)); - map(0x40, 0x4f).rw(FUNC(sis630_gui_device::vga_3c0_r), FUNC(sis630_gui_device::vga_3c0_w)); - map(0x50, 0x5f).rw(FUNC(sis630_gui_device::vga_3d0_r), FUNC(sis630_gui_device::vga_3d0_w)); + map(0x30, 0x5f).m(m_svga, FUNC(sis630_svga_device::io_map)); } void sis630_gui_device::legacy_memory_map(address_map &map) @@ -527,9 +226,7 @@ void sis630_gui_device::legacy_memory_map(address_map &map) void sis630_gui_device::legacy_io_map(address_map &map) { - map(0x03b0, 0x03bf).rw(FUNC(sis630_gui_device::vga_3b0_r), FUNC(sis630_gui_device::vga_3b0_w)); - map(0x03c0, 0x03cf).rw(FUNC(sis630_gui_device::vga_3c0_r), FUNC(sis630_gui_device::vga_3c0_w)); - map(0x03d0, 0x03df).rw(FUNC(sis630_gui_device::vga_3d0_r), FUNC(sis630_gui_device::vga_3d0_w)); + map(0x03b0, 0x03df).m(m_svga, FUNC(sis630_svga_device::io_map)); } void sis630_gui_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, @@ -575,85 +272,6 @@ void sis630_gui_device::vram_w(offs_t offset, uint8_t data) downcast(m_svga.target())->mem_w(offset, data); } -u32 sis630_gui_device::vga_3b0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 3) << 24; - return result; -} - -void sis630_gui_device::vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 3, data >> 24); -} - - -u32 sis630_gui_device::vga_3c0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 3) << 24; - return result; -} - -void sis630_gui_device::vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 3, data >> 24); -} - -u32 sis630_gui_device::vga_3d0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 3) << 24; - return result; -} - -void sis630_gui_device::vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 3, data >> 24); -} - /***************************** * * 630 bridge PCI implementation diff --git a/src/devices/machine/sis630_gui.h b/src/devices/machine/sis630_gui.h index 460ba080eb7..600cd84d24e 100644 --- a/src/devices/machine/sis630_gui.h +++ b/src/devices/machine/sis630_gui.h @@ -7,45 +7,7 @@ #pragma once #include "pci.h" -#include "video/pc_vga.h" - -class sis630_svga_device : public svga_device -{ -public: - sis630_svga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - virtual uint8_t mem_r(offs_t offset) override; - virtual void mem_w(offs_t offset, uint8_t data) override; - - virtual u8 port_03c0_r(offs_t offset) override; - virtual void port_03c0_w(offs_t offset, uint8_t data) override; - -protected: - virtual void device_start() override; - virtual void device_reset() override; - virtual uint8_t crtc_reg_read(uint8_t index) override; - virtual void crtc_reg_write(uint8_t index, uint8_t data) override; - virtual uint8_t seq_reg_read(uint8_t index) override; - virtual void seq_reg_write(uint8_t index, uint8_t data) override; - virtual uint16_t offset() override; - virtual void recompute_params() override; - - u8 m_crtc_ext_regs[0x100]{}; - u8 m_seq_ext_regs[0x100]{}; - u8 m_ramdac_mode = 0; - u8 m_ext_misc_ctrl_0 = 0; - u8 m_ext_vert_overflow = 0; - u8 m_ext_horz_overflow[2]{}; - u32 m_svga_bank_reg_w = 0; - u32 m_svga_bank_reg_r = 0; - bool m_unlock_reg = false; - - std::tuple flush_true_color_mode(); -// bool m_dual_seg_mode = false; -}; - -DECLARE_DEVICE_TYPE(SIS630_SVGA, sis630_svga_device) - +#include "video/pc_vga_sis.h" class sis630_gui_device : public pci_device { @@ -79,12 +41,6 @@ private: u8 vram_r(offs_t offset); void vram_w(offs_t offset, uint8_t data); - u32 vga_3b0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - u32 vga_3c0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - u32 vga_3d0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); void subvendor_w(offs_t offset, u32 data, u32 mem_mask = ~0); diff --git a/src/devices/video/clgd542x.cpp b/src/devices/video/clgd542x.cpp deleted file mode 100644 index e3429d03e2b..00000000000 --- a/src/devices/video/clgd542x.cpp +++ /dev/null @@ -1,1496 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Barry Rodewald -/* - - Cirrus Logic GD542x/3x video chipsets - -*/ - -#include "emu.h" -#include "clgd542x.h" - -#include "screen.h" - - -#define LOG_REG (1U << 1) -#define LOG_BLIT (1U << 2) -#define VERBOSE (0) -#include "logmacro.h" - -//#define TEXT_LINES (LINES_HELPER) -#define LINES (vga.crtc.vert_disp_end+1) -#define TEXT_LINES (vga.crtc.vert_disp_end+1) - -#define GRAPHIC_MODE (vga.gc.alpha_dis) /* else text mode */ - -#define EGA_COLUMNS (vga.crtc.horz_disp_end+1) -#define EGA_START_ADDRESS (vga.crtc.start_addr) -#define EGA_LINE_LENGTH (vga.crtc.offset<<1) - -#define VGA_COLUMNS (vga.crtc.horz_disp_end+1) -#define VGA_START_ADDRESS (vga.crtc.start_addr) -#define VGA_LINE_LENGTH (vga.crtc.offset<<3) - -#define IBM8514_LINE_LENGTH (m_vga->offset()) - -#define VGA_CH_WIDTH ((vga.sequencer.data[1]&1)?8:9) - -#define TEXT_COLUMNS (vga.crtc.horz_disp_end+1) -#define TEXT_START_ADDRESS (vga.crtc.start_addr<<3) -#define TEXT_LINE_LENGTH (vga.crtc.offset<<1) - -#define TEXT_COPY_9COLUMN(ch) (((ch & 0xe0) == 0xc0)&&(vga.attribute.data[0x10]&4)) - -DEFINE_DEVICE_TYPE(CIRRUS_GD5428, cirrus_gd5428_device, "clgd5428", "Cirrus Logic GD5428") -DEFINE_DEVICE_TYPE(CIRRUS_GD5430, cirrus_gd5430_device, "clgd5430", "Cirrus Logic GD5430") -DEFINE_DEVICE_TYPE(CIRRUS_GD5446, cirrus_gd5446_device, "clgd5446", "Cirrus Logic GD5446") - - -cirrus_gd5428_device::cirrus_gd5428_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : cirrus_gd5428_device(mconfig, CIRRUS_GD5428, tag, owner, clock) -{ -} - -cirrus_gd5428_device::cirrus_gd5428_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) - : svga_device(mconfig, type, tag, owner, clock) -{ -} - -cirrus_gd5430_device::cirrus_gd5430_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : cirrus_gd5428_device(mconfig, CIRRUS_GD5430, tag, owner, clock) -{ -} - -cirrus_gd5446_device::cirrus_gd5446_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : cirrus_gd5428_device(mconfig, CIRRUS_GD5446, tag, owner, clock) -{ -} - -void cirrus_gd5428_device::device_start() -{ - zero(); - - for (int i = 0; i < 0x100; i++) - set_pen_color(i, 0, 0, 0); - - // Avoid an infinite loop when displaying. 0 is not possible anyway. - vga.crtc.maximum_scan_line = 1; - - // copy over interfaces - vga.svga_intf.seq_regcount = 0x1f; - vga.svga_intf.crtc_regcount = 0x2d; - vga.memory = std::make_unique(vga.svga_intf.vram_size); - memset(&vga.memory[0], 0, vga.svga_intf.vram_size); - - save_pointer(NAME(vga.memory), vga.svga_intf.vram_size); - save_pointer(vga.crtc.data,"CRTC Registers",0x100); - save_pointer(vga.sequencer.data,"Sequencer Registers",0x100); - save_pointer(vga.attribute.data,"Attribute Registers", 0x15); - save_item(NAME(m_chip_id)); - - m_vblank_timer = timer_alloc(FUNC(vga_device::vblank_timer_cb), this); - - m_chip_id = 0x98; // GD5428 - Rev 0 -} - -void cirrus_gd5430_device::device_start() -{ - cirrus_gd5428_device::device_start(); - m_chip_id = 0xa0; // GD5430 - Rev 0 -} - -void cirrus_gd5446_device::device_start() -{ - cirrus_gd5428_device::device_start(); - m_chip_id = 0x80 | 0x39; // GD5446 -} - - -void cirrus_gd5428_device::device_reset() -{ - vga_device::device_reset(); - gc_locked = true; - gc_mode_ext = 0; - gc_bank_0 = gc_bank_1 = 0; - m_lock_reg = 0; - m_blt_status = 0; - m_cursor_attr = 0x00; // disable hardware cursor and extra palette - m_cursor_x = m_cursor_y = 0; - m_cursor_addr = 0; - m_scratchpad1 = m_scratchpad2 = m_scratchpad3 = 0; - m_cr19 = m_cr1a = m_cr1b = 0; - m_vclk_num[0] = 0x4a; - m_vclk_denom[0] = 0x2b; - m_vclk_num[1] = 0x5b; - m_vclk_denom[1] = 0x2f; - m_blt_source = m_blt_dest = m_blt_source_current = m_blt_dest_current = 0; - memset(m_ext_palette, 0, sizeof(m_ext_palette)); - m_ext_palette_enabled = false; - m_blt_system_transfer = false; -} - -uint32_t cirrus_gd5428_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - uint32_t ptr = (vga.svga_intf.vram_size - 0x4000); // cursor patterns are stored in the last 16kB of VRAM - svga_device::screen_update(screen, bitmap, cliprect); - - /*uint8_t cur_mode =*/ pc_vga_choosevideomode(); - if(m_cursor_attr & 0x01) // hardware cursor enabled - { - // draw hardware graphics cursor - if(m_cursor_attr & 0x04) // 64x64 - { - ptr += ((m_cursor_addr & 0x3c) * 256); - for(int y=0;y<64;y++) - { - for(int x=0;x<64;x+=8) - { - for(int bit=0;bit<8;bit++) - { - uint8_t pixel1 = vga.memory[ptr % vga.svga_intf.vram_size] >> (7-bit); - uint8_t pixel2 = vga.memory[(ptr+512) % vga.svga_intf.vram_size] >> (7-bit); - uint8_t output = ((pixel1 & 0x01) << 1) | (pixel2 & 0x01); - switch(output) - { - case 0: // transparent - do nothing - break; - case 1: // background - bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 16) | (m_ext_palette[0].green << 8) | (m_ext_palette[0].blue); - break; - case 2: // XOR - bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit); - break; - case 3: // foreground - bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 16) | (m_ext_palette[15].green << 8) | (m_ext_palette[15].blue); - break; - } - } - } - } - } - else - { - ptr += ((m_cursor_addr & 0x3f) * 256); - for(int y=0;y<32;y++) - { - for(int x=0;x<32;x+=8) - { - for(int bit=0;bit<8;bit++) - { - uint8_t pixel1 = vga.memory[ptr % vga.svga_intf.vram_size] >> (7-bit); - uint8_t pixel2 = vga.memory[(ptr+128) % vga.svga_intf.vram_size] >> (7-bit); - uint8_t output = ((pixel1 & 0x01) << 1) | (pixel2 & 0x01); - switch(output) - { - case 0: // transparent - do nothing - break; - case 1: // background - bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 18) | (m_ext_palette[0].green << 10) | (m_ext_palette[0].blue << 2); - break; - case 2: // XOR - bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit); - break; - case 3: // foreground - bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 18) | (m_ext_palette[15].green << 10) | (m_ext_palette[15].blue << 2); - break; - } - } - ptr++; - } - } - } - } - return 0; -} - -void cirrus_gd5428_device::cirrus_define_video_mode() -{ - uint8_t divisor = 1; - float clock; - const XTAL xtal = XTAL(14'318'181); - uint8_t clocksel = (vga.miscellaneous_output & 0xc) >> 2; - - svga.rgb8_en = 0; - svga.rgb15_en = 0; - svga.rgb16_en = 0; - svga.rgb24_en = 0; - svga.rgb32_en = 0; - - if(gc_locked || m_vclk_num[clocksel] == 0 || m_vclk_denom[clocksel] == 0) - clock = ((vga.miscellaneous_output & 0xc) ? xtal*2: xtal*1.75).dvalue(); - else - { - int numerator = m_vclk_num[clocksel] & 0x7f; - int denominator = (m_vclk_denom[clocksel] & 0x3e) >> 1; - int mul = m_vclk_denom[clocksel] & 0x01 ? 2 : 1; - clock = (xtal * numerator / denominator / mul).dvalue(); - } - - if (!gc_locked && (vga.sequencer.data[0x07] & 0x01)) - { - switch(vga.sequencer.data[0x07] & 0x06) // bit 3 is reserved on GD542x - { - case 0x00: svga.rgb8_en = 1; break; - case 0x02: svga.rgb16_en = 1; clock /= 2; break; // Clock / 2 for 16-bit data - case 0x04: svga.rgb24_en = 1; clock /= 3; break; // Clock / 3 for 24-bit data - case 0x06: svga.rgb16_en = 1; divisor = 2; break; // Clock rate for 16-bit data - } - } - recompute_params_clock(divisor, (int)clock); -} - -uint16_t cirrus_gd5428_device::offset() -{ - uint16_t off = vga_device::offset(); - - if (svga.rgb8_en == 1) // guess - off <<= 2; - if (svga.rgb16_en == 1) - off <<= 2; - if (svga.rgb24_en == 1) - off <<= 2; - if (svga.rgb32_en == 1) - off <<= 2; -// popmessage("Offset: %04x %s %s ** -- actual: %04x",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD",off); - return off; -} - -void cirrus_gd5428_device::start_bitblt() -{ - uint32_t x,y; - - if(m_blt_mode & 0x01) - { - start_reverse_bitblt(); - return; - } - - LOGMASKED(LOG_BLIT, "CL: BitBLT started: Src: %06x Dst: %06x Width: %i Height %i ROP: %02x Mode: %02x\n",m_blt_source,m_blt_dest,m_blt_width,m_blt_height,m_blt_rop,m_blt_mode); - - m_blt_source_current = m_blt_source; - m_blt_dest_current = m_blt_dest; - - for(y=0;y<=m_blt_height;y++) - { - for(x=0;x<=m_blt_width;x++) - { - if(m_blt_mode & 0x80) // colour expand - { - if(m_blt_mode & 0x10) // 16-bit colour expansion / transparency width - { - // use GR0/1/10/11 background/foreground regs - uint16_t pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-((x/2) % 8)) & 0x01) ? ((m_gr11 << 8) | vga.gc.enable_set_reset) : ((m_gr10 << 8) | vga.gc.set_reset); - - if(m_blt_dest_current & 1) - copy_pixel(pixel >> 8, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - else - copy_pixel(pixel & 0xff, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't increment if a pattern (it's only 8 bits) - m_blt_source_current++; - } - else - { - uint8_t pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-(x % 8)) & 0x01) ? vga.gc.enable_set_reset : vga.gc.set_reset; // use GR0/1/10/11 background/foreground regs - - copy_pixel(pixel, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't increment if a pattern (it's only 8 bits) - m_blt_source_current++; - } - } - else - { - copy_pixel(vga.memory[m_blt_source_current % vga.svga_intf.vram_size], vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - m_blt_source_current++; - } - - m_blt_dest_current++; - if(m_blt_mode & 0x40 && (x % 8) == 7) // 8x8 pattern - reset pattern source location - { - if(m_blt_mode & 0x80) // colour expand - m_blt_source_current = m_blt_source + (1*(y % 8)); // patterns are linear data - else if(svga.rgb15_en || svga.rgb16_en) - { - if(m_blt_mode & 0x40 && (x % 16) == 15) - m_blt_source_current = m_blt_source + (16*(y % 8)); - } - else - m_blt_source_current = m_blt_source + (8*(y % 8)); - } - } - if(m_blt_mode & 0x40) // 8x8 pattern - { - if(m_blt_mode & 0x80) // colour expand - m_blt_source_current = m_blt_source + (1*(y % 8)); // patterns are linear data - else if(svga.rgb15_en || svga.rgb16_en) - { - if(m_blt_mode & 0x40 && (x % 16) == 15) - m_blt_source_current = m_blt_source + (16*(y % 8)); - } - else - m_blt_source_current = m_blt_source + (8*(y % 8)); - } - else - m_blt_source_current = m_blt_source + (m_blt_source_pitch*(y+1)); - m_blt_dest_current = m_blt_dest + (m_blt_dest_pitch*(y+1)); - } - m_blt_status &= ~0x02; -} - -void cirrus_gd5428_device::start_reverse_bitblt() -{ - uint32_t x,y; - - LOGMASKED(LOG_BLIT, "CL: Reverse BitBLT started: Src: %06x Dst: %06x Width: %i Height %i ROP: %02x Mode: %02x\n",m_blt_source,m_blt_dest,m_blt_width,m_blt_height,m_blt_rop,m_blt_mode); - - // Start at end of blit - m_blt_source_current = m_blt_source; - m_blt_dest_current = m_blt_dest; - - for(y=0;y<=m_blt_height;y++) - { - for(x=0;x<=m_blt_width;x++) - { - if(m_blt_mode & 0x80) // colour expand - { - if(m_blt_mode & 0x10) // 16-bit colour expansion / transparency width - { - // use GR0/1/10/11 background/foreground regs - uint16_t pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-((x/2) % 8)) & 0x01) ? ((m_gr11 << 8) | vga.gc.enable_set_reset) : ((m_gr10 << 8) | vga.gc.set_reset); - - if(m_blt_dest_current & 1) - copy_pixel(pixel >> 8, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - else - copy_pixel(pixel & 0xff, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't increment if a pattern (it's only 8 bits) - m_blt_source_current--; - } - else - { - uint8_t pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-(x % 8)) & 0x01) ? vga.gc.enable_set_reset : vga.gc.set_reset; // use GR0/1/10/11 background/foreground regs - - copy_pixel(pixel, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't decrement if a pattern (it's only 8 bits) - m_blt_source_current--; - } - } - else - { - copy_pixel(vga.memory[m_blt_source_current % vga.svga_intf.vram_size], vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - m_blt_source_current--; - } - m_blt_dest_current--; - if(m_blt_mode & 0x40 && (x % 8) == 7) // 8x8 pattern - reset pattern source location - { - if(m_blt_mode & 0x80) // colour expand - m_blt_source_current = m_blt_source - (1*(y % 8)); // patterns are linear data - else if(svga.rgb15_en || svga.rgb16_en) - { - if(m_blt_mode & 0x40 && (x % 16) == 15) - m_blt_source_current = m_blt_source - (16*(y % 8)); - } - else - m_blt_source_current = m_blt_source - (8*(y % 8)); - } - } - if(m_blt_mode & 0x40) // 8x8 pattern - { - if(m_blt_mode & 0x80) // colour expand - m_blt_source_current = m_blt_source - (1*(y % 8)); // patterns are linear data - else if(svga.rgb15_en || svga.rgb16_en) - { - if(m_blt_mode & 0x40 && (x % 16) == 15) - m_blt_source_current = m_blt_source - (16*(y % 8)); - } - else - m_blt_source_current = m_blt_source - (8*(y % 8)); - } - else - m_blt_source_current = m_blt_source - (m_blt_source_pitch*(y+1)); - m_blt_dest_current = m_blt_dest - (m_blt_dest_pitch*(y+1)); - } - m_blt_status &= ~0x02; -} - -void cirrus_gd5428_device::start_system_bitblt() -{ - LOGMASKED(LOG_BLIT, "CL: BitBLT from system memory started: Src: %06x Dst: %06x Width: %i Height %i ROP: %02x Mode: %02x\n",m_blt_source,m_blt_dest,m_blt_width,m_blt_height,m_blt_rop,m_blt_mode); - m_blt_system_transfer = true; - m_blt_system_count = 0; - m_blt_system_buffer = 0; - m_blt_pixel_count = m_blt_scan_count = 0; - m_blt_source_current = m_blt_source; - m_blt_dest_current = m_blt_dest; - m_blt_status |= 0x09; -} - -// non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored -void cirrus_gd5428_device::blit_dword() -{ - // TODO: add support for reverse direction - uint8_t x,pixel; - - for(x=0;x<32;x+=8) - { - pixel = ((m_blt_system_buffer & (0x000000ff << x)) >> x); - if(m_blt_pixel_count <= m_blt_width) - copy_pixel(pixel,vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - m_blt_dest_current++; - m_blt_pixel_count++; - } - if(m_blt_pixel_count > m_blt_width) - { - m_blt_pixel_count = 0; - m_blt_scan_count++; - m_blt_dest_current = m_blt_dest + (m_blt_dest_pitch*m_blt_scan_count); - } - if(m_blt_scan_count > m_blt_height) - { - m_blt_system_transfer = false; // BitBLT complete - m_blt_status &= ~0x0b; - } -} - -// colour-expanded BitBLTs from system memory are on a byte boundary, unused bits are ignored -void cirrus_gd5428_device::blit_byte() -{ - // TODO: add support for reverse direction - uint8_t x,pixel; - - for(x=0;x<8;x++) - { - // use GR0/1/10/11 background/foreground regs - if(m_blt_dest_current & 1) - pixel = ((m_blt_system_buffer & (0x00000001 << (7-x))) >> (7-x)) ? m_gr11 : m_gr10; - else - pixel = ((m_blt_system_buffer & (0x00000001 << (7-x))) >> (7-x)) ? vga.gc.enable_set_reset : vga.gc.set_reset; - if(m_blt_pixel_count <= m_blt_width - 1) - copy_pixel(pixel,vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); - m_blt_dest_current++; - m_blt_pixel_count++; - } - if(m_blt_pixel_count > m_blt_width) - { - m_blt_pixel_count = 0; - m_blt_scan_count++; - m_blt_dest_current = m_blt_dest + (m_blt_dest_pitch*m_blt_scan_count); - } - if(m_blt_scan_count > m_blt_height) - { - m_blt_system_transfer = false; // BitBLT complete - m_blt_status &= ~0x0b; - } -} - -void cirrus_gd5428_device::copy_pixel(uint8_t src, uint8_t dst) -{ - uint8_t res = src; - - switch(m_blt_rop) - { - case 0x00: // BLACK - res = 0x00; - break; - case 0x0b: // DSTINVERT - res = ~dst; - break; - case 0x0d: // SRC - res = src; - break; - case 0x0e: // WHITE - res = 0xff; - break; - case 0x59: // SRCINVERT - res = src ^ dst; - break; - default: - popmessage("CL: Unsupported BitBLT ROP mode %02x",m_blt_rop); - } - - // handle transparency compare - if(m_blt_mode & 0x08) // TODO: 16-bit compare - { - // if ROP result matches the transparency colour, don't change the pixel - if((res & (~m_blt_trans_colour_mask & 0xff)) == ((m_blt_trans_colour & 0xff) & (~m_blt_trans_colour_mask & 0xff))) - return; - } - - vga.memory[m_blt_dest_current % vga.svga_intf.vram_size] = res; -} - -uint8_t cirrus_gd5428_device::cirrus_seq_reg_read(uint8_t index) -{ - uint8_t res; - - res = 0xff; - - switch(index) - { - case 0x02: - if(gc_mode_ext & 0x08) - res = vga.sequencer.map_mask & 0xff; - else - res = vga.sequencer.map_mask & 0x0f; - break; - case 0x06: - if(gc_locked) - return 0x0f; - else - return m_lock_reg; - break; - case 0x09: - //printf("%02x\n",index); - res = vga.sequencer.data[index]; - break; - case 0x0a: - res = m_scratchpad1; - break; - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - res = m_vclk_num[index-0x0b]; - break; - case 0x0f: - res = vga.sequencer.data[index] & 0xe7; - res |= 0x18; // 32-bit DRAM data bus width (1MB-2MB) - break; - case 0x12: - res = m_cursor_attr; - break; - case 0x14: - res = m_scratchpad2; - break; - case 0x15: - res = m_scratchpad3; - break; - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - res = m_vclk_denom[index-0x1b]; - break; - default: - res = vga.sequencer.data[index]; - } - - return res; -} - -void cirrus_gd5428_device::cirrus_seq_reg_write(uint8_t index, uint8_t data) -{ - LOGMASKED(LOG_REG, "CL: SEQ write %02x to SR%02x\n",data,index); - switch(index) - { - case 0x02: - if(gc_mode_ext & 0x08) - vga.sequencer.map_mask = data & 0xff; - else - vga.sequencer.map_mask = data & 0x0f; - break; - case 0x06: - // Note: extensions are always enabled on the GD5429 - if((data & 0x17) == 0x12) // bits 3,5,6,7 ignored - { - gc_locked = false; - logerror("Cirrus register extensions unlocked\n"); - } - else - { - gc_locked = true; - logerror("Cirrus register extensions locked\n"); - } - m_lock_reg = data & 0x17; - break; - case 0x07: - if((data & 0xf0) != 0) - popmessage("1MB framebuffer window enabled at %iMB (%02x)",data >> 4,data); - vga.sequencer.data[vga.sequencer.index] = data; - break; - case 0x09: - //printf("%02x %02x\n",index,data); - vga.sequencer.data[vga.sequencer.index] = data; - break; - case 0x0a: - m_scratchpad1 = data; // GD5402/GD542x BIOS writes VRAM size here. - break; - case 0x0b: - case 0x0c: - case 0x0d: - case 0x0e: - m_vclk_num[index-0x0b] = data; - break; - case 0x10: - case 0x30: - case 0x50: - case 0x70: - case 0x90: - case 0xb0: - case 0xd0: - case 0xf0: // bits 5-7 of the register index are the low bits of the X co-ordinate - m_cursor_x = (data << 3) | ((index & 0xe0) >> 5); - break; - case 0x11: - case 0x31: - case 0x51: - case 0x71: - case 0x91: - case 0xb1: - case 0xd1: - case 0xf1: // bits 5-7 of the register index are the low bits of the Y co-ordinate - m_cursor_y = (data << 3) | ((index & 0xe0) >> 5); - break; - case 0x12: - // bit 0 - enable cursor - // bit 1 - enable extra palette (cursor colours are there) - // bit 2 - 64x64 cursor (32x32 if clear, GD5422+) - // bit 7 - overscan colour protect - if set, use colour 2 in the extra palette for the border (GD5424+) - m_cursor_attr = data; - m_ext_palette_enabled = data & 0x02; - break; - case 0x13: - m_cursor_addr = data; // bits 0 and 1 are ignored if using 64x64 cursor - break; - case 0x14: - m_scratchpad2 = data; - break; - case 0x15: - m_scratchpad3 = data; // GD543x BIOS writes VRAM size here - break; - case 0x1b: - case 0x1c: - case 0x1d: - case 0x1e: - m_vclk_denom[index-0x1b] = data; - break; - default: - vga.sequencer.data[vga.sequencer.index] = data; - seq_reg_write(vga.sequencer.index,data); - } -} - -uint8_t cirrus_gd5428_device::cirrus_gc_reg_read(uint8_t index) -{ - uint8_t res = 0xff; - - switch(index) - { - case 0x00: - if(gc_mode_ext & 0x04) - res = vga.gc.set_reset & 0xff; - else - res = vga.gc.set_reset & 0x0f; - break; - case 0x01: - if(gc_mode_ext & 0x04) - res = vga.gc.enable_set_reset & 0xff; - else - res = vga.gc.enable_set_reset & 0x0f; - break; - case 0x05: - res = (vga.gc.shift256 & 1) << 6; - res |= (vga.gc.shift_reg & 1) << 5; - res |= (vga.gc.host_oe & 1) << 4; - res |= (vga.gc.read_mode & 1) << 3; - if(gc_mode_ext & 0x04) - res |= (vga.gc.write_mode & 7); - else - res |= (vga.gc.write_mode & 3); - break; - case 0x09: // Offset register 0 - res = gc_bank_0; - break; - case 0x0a: // Offset register 1 - res = gc_bank_1; - break; - case 0x0b: // Graphics controller mode extensions - res = gc_mode_ext; - break; - case 0x0c: // Colour Key - break; - case 0x0d: // Colour Key Mask - break; - case 0x0e: // Miscellaneous Control - break; - case 0x10: // Background Colour Byte 1 - res = m_gr10; - break; - case 0x11: // Foreground Colour Byte 1 - res = m_gr11; - break; - case 0x20: // BLT Width 0 - res = m_blt_width & 0x00ff; - break; - case 0x21: // BLT Width 1 - res = m_blt_width >> 8; - break; - case 0x22: // BLT Height 0 - res = m_blt_height & 0x00ff; - break; - case 0x23: // BLT Height 1 - res = m_blt_height >> 8; - break; - case 0x24: // BLT Destination Pitch 0 - res = m_blt_dest_pitch & 0x00ff; - break; - case 0x25: // BLT Destination Pitch 1 - res = m_blt_dest_pitch >> 8; - break; - case 0x26: // BLT Source Pitch 0 - res = m_blt_source_pitch & 0x00ff; - break; - case 0x27: // BLT Source Pitch 1 - res = m_blt_source_pitch >> 8; - break; - case 0x28: // BLT Destination start 0 - res = m_blt_dest & 0x000000ff; - break; - case 0x29: // BLT Destination start 1 - res = (m_blt_dest & 0x0000ff00) >> 8; - break; - case 0x2a: // BLT Destination start 2 - res = (m_blt_dest & 0x00ff0000) >> 16; - break; - case 0x2c: // BLT source start 0 - res = m_blt_source & 0x000000ff; - break; - case 0x2d: // BLT source start 1 - res = (m_blt_source & 0x0000ff00) >> 8; - break; - case 0x2e: // BLT source start 2 - res = (m_blt_source & 0x00ff0000) >> 16; - break; - case 0x2f: // BLT destination write mask (GD5430/36/40) - // TODO - break; - case 0x30: // BLT Mode - res = m_blt_mode; - break; - case 0x31: // BitBLT Start / Status - res = m_blt_status; - break; - case 0x32: // BitBLT ROP mode - res = m_blt_rop; - break; - case 0x34: // BitBLT Transparent Colour - res = m_blt_trans_colour & 0x00ff; - break; - case 0x35: - res = m_blt_trans_colour >> 8; - break; - case 0x36: // BitBLT Transparent Colour Mask - res = m_blt_trans_colour_mask & 0x00ff; - break; - case 0x37: - res = m_blt_trans_colour_mask >> 8; - break; - default: - res = gc_reg_read(index); - } - - return res; -} - -void cirrus_gd5428_device::cirrus_gc_reg_write(uint8_t index, uint8_t data) -{ - LOGMASKED(LOG_REG, "CL: GC write %02x to GR%02x\n",data,index); - switch(index) - { - case 0x00: // if extended writes are enabled (bit 2 of index 0bh), then index 0 and 1 are extended to 8 bits, however XFree86 does not appear to do this... - vga.gc.set_reset = data & 0xff; - break; - case 0x01: - vga.gc.enable_set_reset = data & 0xff; - break; - case 0x05: - vga.gc.shift256 = (data & 0x40) >> 6; - vga.gc.shift_reg = (data & 0x20) >> 5; - vga.gc.host_oe = (data & 0x10) >> 4; - vga.gc.read_mode = (data & 8) >> 3; - if(gc_mode_ext & 0x04) - vga.gc.write_mode = data & 7; - else - vga.gc.write_mode = data & 3; - break; - case 0x09: // Offset register 0 - gc_bank_0 = data; - logerror("CL: Offset register 0 set to %i\n",data); - break; - case 0x0a: // Offset register 1 - gc_bank_1 = data; - logerror("CL: Offset register 1 set to %i\n",data); - break; - case 0x0b: // Graphics controller mode extensions - gc_mode_ext = data; - if(!(data & 0x04)) - { - vga.gc.set_reset &= 0x0f; - vga.gc.enable_set_reset &= 0x0f; - } - if(!(data & 0x08)) - vga.sequencer.map_mask &= 0x0f; - break; - case 0x0c: // Colour Key - break; - case 0x0d: // Colour Key Mask - break; - case 0x0e: // Miscellaneous Control - break; - case 0x10: // Background Colour Byte 1 - m_gr10 = data; - break; - case 0x11: // Foreground Colour Byte 1 - m_gr11 = data; - break; - case 0x20: // BLT Width 0 - m_blt_width = (m_blt_width & 0xff00) | data; - break; - case 0x21: // BLT Width 1 - m_blt_width = (m_blt_width & 0x00ff) | (data << 8); - break; - case 0x22: // BLT Height 0 - m_blt_height = (m_blt_height & 0xff00) | data; - break; - case 0x23: // BLT Height 1 - m_blt_height = (m_blt_height & 0x00ff) | (data << 8); - break; - case 0x24: // BLT Destination Pitch 0 - m_blt_dest_pitch = (m_blt_dest_pitch & 0xff00) | data; - break; - case 0x25: // BLT Destination Pitch 1 - m_blt_dest_pitch = (m_blt_dest_pitch & 0x00ff) | (data << 8); - break; - case 0x26: // BLT Source Pitch 0 - m_blt_source_pitch = (m_blt_source_pitch & 0xff00) | data; - break; - case 0x27: // BLT Source Pitch 1 - m_blt_source_pitch = (m_blt_source_pitch & 0x00ff) | (data << 8); - break; - case 0x28: // BLT Destination start 0 - m_blt_dest = (m_blt_dest & 0xffffff00) | data; - break; - case 0x29: // BLT Destination start 1 - m_blt_dest = (m_blt_dest & 0xffff00ff) | (data << 8); - break; - case 0x2a: // BLT Destination start 2 - m_blt_dest = (m_blt_dest & 0xff00ffff) | (data << 16); - break; - case 0x2c: // BLT source start 0 - m_blt_source = (m_blt_source & 0xffffff00) | data; - break; - case 0x2d: // BLT source start 1 - m_blt_source = (m_blt_source & 0xffff00ff) | (data << 8); - break; - case 0x2e: // BLT source start 2 - m_blt_source = (m_blt_source & 0xff00ffff) | (data << 16); - break; - case 0x2f: // BLT destination write mask (GD5430/36/40) - // TODO - break; - case 0x30: // BLT Mode - m_blt_mode = data; - break; - case 0x31: // BitBLT Start / Status - m_blt_status = data & ~0xf2; - if(data & 0x02) - { - if(m_blt_mode & 0x04) // blit source is system memory - start_system_bitblt(); - else - start_bitblt(); - } - break; - case 0x32: // BitBLT ROP mode - m_blt_rop = data; - break; - case 0x34: // BitBLT Transparent Colour - m_blt_trans_colour = (m_blt_trans_colour & 0xff00) | data; - break; - case 0x35: - m_blt_trans_colour = (m_blt_trans_colour & 0x00ff) | (data << 8); - break; - case 0x36: // BitBLT Transparent Colour Mask - m_blt_trans_colour_mask = (m_blt_trans_colour_mask & 0xff00) | data; - break; - case 0x37: - m_blt_trans_colour_mask = (m_blt_trans_colour_mask & 0x00ff) | (data << 8); - break; - default: - gc_reg_write(index,data); - } -} - -uint8_t cirrus_gd5428_device::port_03c0_r(offs_t offset) -{ - uint8_t res = 0xff; - - switch(offset) - { - case 0x05: - res = cirrus_seq_reg_read(vga.sequencer.index); - break; - case 0x09: - if(!m_ext_palette_enabled) - res = vga_device::port_03c0_r(offset); - else - { - if (vga.dac.read) - { - switch (vga.dac.state++) - { - case 0: - res = m_ext_palette[vga.dac.read_index & 0x0f].red; - break; - case 1: - res = m_ext_palette[vga.dac.read_index & 0x0f].green; - break; - case 2: - res = m_ext_palette[vga.dac.read_index & 0x0f].blue; - break; - } - - if (vga.dac.state==3) - { - vga.dac.state = 0; - vga.dac.read_index++; - } - } - } - break; - case 0x0f: - res = cirrus_gc_reg_read(vga.gc.index); - break; - default: - res = vga_device::port_03c0_r(offset); - break; - } - - return res; -} - -void cirrus_gd5428_device::port_03c0_w(offs_t offset, uint8_t data) -{ - switch(offset) - { - case 0x05: - cirrus_seq_reg_write(vga.sequencer.index,data); - break; - case 0x09: - if(!m_ext_palette_enabled) - vga_device::port_03c0_w(offset,data); - else - { - if (!vga.dac.read) - { - switch (vga.dac.state++) { - case 0: - m_ext_palette[vga.dac.write_index & 0x0f].red=data; - break; - case 1: - m_ext_palette[vga.dac.write_index & 0x0f].green=data; - break; - case 2: - m_ext_palette[vga.dac.write_index & 0x0f].blue=data; - break; - } - vga.dac.dirty=1; - if (vga.dac.state==3) - { - vga.dac.state=0; - vga.dac.write_index++; - } - } - } - break; - case 0x0f: - cirrus_gc_reg_write(vga.gc.index,data); - break; - default: - vga_device::port_03c0_w(offset,data); - break; - } - cirrus_define_video_mode(); -} - -uint8_t cirrus_gd5428_device::port_03b0_r(offs_t offset) -{ - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 5: - res = cirrus_crtc_reg_read(vga.crtc.index); - break; - default: - res = vga_device::port_03b0_r(offset); - break; - } - } - - return res; -} - -uint8_t cirrus_gd5428_device::port_03d0_r(offs_t offset) -{ - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - res = cirrus_crtc_reg_read(vga.crtc.index); - break; - default: - res = vga_device::port_03d0_r(offset); - break; - } - } - - return res; -} - -void cirrus_gd5428_device::port_03b0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 5: - vga.crtc.data[vga.crtc.index] = data; - cirrus_crtc_reg_write(vga.crtc.index,data); - break; - default: - vga_device::port_03b0_w(offset,data); - break; - } - } - cirrus_define_video_mode(); -} - -void cirrus_gd5428_device::port_03d0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - vga.crtc.data[vga.crtc.index] = data; - cirrus_crtc_reg_write(vga.crtc.index,data); - break; - default: - vga_device::port_03d0_w(offset,data); - break; - } - } - cirrus_define_video_mode(); -} - -uint8_t cirrus_gd5428_device::cirrus_crtc_reg_read(uint8_t index) -{ - uint8_t res; - - switch(index) - { - case 0x16: // VGA Vertical Blank end - some SVGA chipsets use all 8 bits, and this is one of them (according to MFGTST CRTC tests) - res = vga.crtc.vert_blank_end & 0x00ff; - break; - case 0x19: - res = m_cr19; - break; - case 0x1a: - res = m_cr1a; - break; - case 0x1b: - res = m_cr1b; - break; - case 0x27: - res = m_chip_id; - break; - default: - res = crtc_reg_read(index); - break; - } - - return res; -} - -void cirrus_gd5428_device::cirrus_crtc_reg_write(uint8_t index, uint8_t data) -{ - LOGMASKED(LOG_REG, "CL: CRTC write %02x to CR%02x\n",data,index); - switch(index) - { - case 0x16: // VGA Vertical Blank end - some SVGA chipsets use all 8 bits, and this is one of them (according to MFGTST CRTC tests) - vga.crtc.vert_blank_end &= ~0x00ff; - vga.crtc.vert_blank_end |= data; - break; - case 0x19: - m_cr19 = data; - break; - case 0x1a: - m_cr1a = data; - vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xff3f) | ((data & 0x30) << 2); - vga.crtc.vert_blank_end = (vga.crtc.vert_blank_end & 0xfcff) | ((data & 0xc0) << 2); - break; - case 0x1b: - m_cr1b = data; - vga.crtc.start_addr_latch &= ~0x070000; - vga.crtc.start_addr_latch |= ((data & 0x01) << 16); - vga.crtc.start_addr_latch |= ((data & 0x0c) << 15); - vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x10) << 4); - cirrus_define_video_mode(); - break; - case 0x1d: - //vga.crtc.start_addr_latch = (vga.crtc.start_addr_latch & 0xf7ffff) | ((data & 0x01) << 16); // GD543x - break; - case 0x27: - // Do nothing, read only - break; - default: - crtc_reg_write(index,data); - break; - } - -} - -uint8_t cirrus_gd5428_device::vga_latch_write(int offs, uint8_t data) -{ - uint8_t res = 0; - uint8_t mode_mask = (gc_mode_ext & 0x04) ? 0x07 : 0x03; - - switch (vga.gc.write_mode & mode_mask) { - case 0: - case 1: - case 2: - case 3: - res = vga_device::vga_latch_write(offs, data); - break; - case 4: - res = vga.gc.latch[offs]; - popmessage("CL: Unimplemented VGA write mode 4 enabled"); - break; - case 5: - res = vga.gc.latch[offs]; - popmessage("CL: Unimplemented VGA write mode 5 enabled"); - break; - } - - return res; -} - -uint8_t cirrus_gd5428_device::mem_r(offs_t offset) -{ - uint32_t addr; - uint8_t bank; - uint8_t cur_mode = pc_vga_choosevideomode(); - - if(gc_locked || offset >= 0x10000 || cur_mode == TEXT_MODE || cur_mode == SCREEN_OFF) - return vga_device::mem_r(offset); - - if(offset >= 0x8000 && offset < 0x10000 && (gc_mode_ext & 0x01)) // if accessing bank 1 (if enabled) - bank = gc_bank_1; - else - bank = gc_bank_0; - - if(gc_mode_ext & 0x20) // 16kB bank granularity - addr = bank * 0x4000; - else // 4kB bank granularity - addr = bank * 0x1000; - - // Is the display address adjusted automatically when not using Chain-4 addressing? The GD542x BIOS doesn't do it, but Virtual Pool expects it. - if(!(vga.sequencer.data[4] & 0x8)) - addr <<= 2; - - if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) - { - uint8_t data = 0; - if(gc_mode_ext & 0x01) - { - if(offset & 0x10000) - return 0; - if(offset < 0x8000) - offset &= 0x7fff; - else - { - offset -= 0x8000; - offset &= 0x7fff; - } - } - else - offset &= 0xffff; - - if(vga.sequencer.data[4] & 0x8) - data = vga.memory[(offset+addr) % vga.svga_intf.vram_size]; - else - { - { - int i; - - for(i=0;i<4;i++) - { - if(vga.sequencer.map_mask & 1 << i) - data |= vga.memory[((offset*4+i)+addr) % vga.svga_intf.vram_size]; - } - } - return data; - } - } - - switch(vga.gc.memory_map_sel & 0x03) - { - case 0: break; - case 1: if(gc_mode_ext & 0x01) offset &= 0x7fff; else offset &= 0x0ffff; break; - case 2: offset -= 0x10000; offset &= 0x07fff; break; - case 3: offset -= 0x18000; offset &= 0x07fff; break; - } - - if(vga.sequencer.data[4] & 4) - { - int data; - if (!machine().side_effects_disabled()) - { - vga.gc.latch[0]=vga.memory[(offset+addr) % vga.svga_intf.vram_size]; - vga.gc.latch[1]=vga.memory[((offset+addr)+0x10000) % vga.svga_intf.vram_size]; - vga.gc.latch[2]=vga.memory[((offset+addr)+0x20000) % vga.svga_intf.vram_size]; - vga.gc.latch[3]=vga.memory[((offset+addr)+0x30000) % vga.svga_intf.vram_size]; - } - - if (vga.gc.read_mode) - { - uint8_t byte,layer; - uint8_t fill_latch; - data=0; - - for(byte=0;byte<8;byte++) - { - fill_latch = 0; - for(layer=0;layer<4;layer++) - { - if(vga.gc.latch[layer] & 1 << byte) - fill_latch |= 1 << layer; - } - fill_latch &= vga.gc.color_dont_care; - if(fill_latch == vga.gc.color_compare) - data |= 1 << byte; - } - } - else - data=vga.gc.latch[vga.gc.read_map_sel]; - - return data; - } - else - { - // TODO: Lines up in 16-colour mode, likely different for 256-colour modes (docs say video addresses are shifted right 3 places) - uint8_t i,data; -// uint8_t bits = ((gc_mode_ext & 0x08) && (vga.gc.write_mode == 1)) ? 8 : 4; - - data = 0; - //printf("%08x\n",offset); - - if(gc_mode_ext & 0x02) - { - for(i=0;i<8;i++) - { - if(vga.sequencer.map_mask & 1 << i) - data |= vga.memory[(((offset+addr))+i*0x10000) % vga.svga_intf.vram_size]; - } - } - else - { - for(i=0;i<4;i++) - { - if(vga.sequencer.map_mask & 1 << i) - data |= vga.memory[(((offset+addr))+i*0x10000) % vga.svga_intf.vram_size]; - } - } - - return data; - } -} - -void cirrus_gd5428_device::mem_w(offs_t offset, uint8_t data) -{ - uint32_t addr; - uint8_t bank; - uint8_t cur_mode = pc_vga_choosevideomode(); - - if(m_blt_system_transfer) - { - if(m_blt_mode & 0x80) // colour expand - { - m_blt_system_buffer &= ~(0x000000ff); - m_blt_system_buffer |= data; - blit_byte(); - m_blt_system_count = 0; - } - else - { - m_blt_system_buffer &= ~(0x000000ff << (m_blt_system_count * 8)); - m_blt_system_buffer |= (data << (m_blt_system_count * 8)); - m_blt_system_count++; - if(m_blt_system_count >= 4) - { - blit_dword(); - m_blt_system_count = 0; - } - } - return; - } - - if(gc_locked || offset >= 0x10000 || cur_mode == TEXT_MODE || cur_mode == SCREEN_OFF) - { - vga_device::mem_w(offset,data); - return; - } - - if(offset >= 0x8000 && offset < 0x10000 && (gc_mode_ext & 0x01)) // if accessing bank 1 (if enabled) - bank = gc_bank_1; - else - bank = gc_bank_0; - - if(gc_mode_ext & 0x20) // 16kB bank granularity - addr = bank * 0x4000; - else // 4kB bank granularity - addr = bank * 0x1000; - - // Is the display address adjusted automatically when using Chain-4 addressing? The GD542x BIOS doesn't do it, but Virtual Pool expects it. - if(!(vga.sequencer.data[4] & 0x8)) - addr <<= 2; - - if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) - { - if(offset & 0x10000) - return; - if(gc_mode_ext & 0x01) - { - if(offset < 0x8000) - offset &= 0x7fff; - else - { - offset -= 0x8000; - offset &= 0x7fff; - } - } - else - offset &= 0xffff; - - // GR0 (and GR10 in 15/16bpp modes) = background colour in write mode 5 - // GR1 (and GR11 in 15/16bpp modes) = foreground colour in write modes 4 or 5 - if(vga.gc.write_mode == 4) - { - int i; - - for(i=0;i<8;i++) - { - if(svga.rgb8_en) - { - if(data & (0x01 << (7-i))) - vga.memory[((addr+offset)*8+i) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; - } - else if(svga.rgb15_en || svga.rgb16_en) - { - if(data & (0x01 << (7-i))) - { - vga.memory[((addr+offset)*16+(i*2)) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; - vga.memory[((addr+offset)*16+(i*2)+1) % vga.svga_intf.vram_size] = m_gr11; - } - } - } - return; - } - - if(vga.gc.write_mode == 5) - { - int i; - - for(i=0;i<8;i++) - { - if(svga.rgb8_en) - { - if(data & (0x01 << (7-i))) - vga.memory[((addr+offset)*8+i) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; - else - vga.memory[((addr+offset)*8+i) % vga.svga_intf.vram_size] = vga.gc.set_reset; - } - else if(svga.rgb15_en || svga.rgb16_en) - { - if(data & (0x01 << (7-i))) - { - vga.memory[((addr+offset)*16+(i*2)) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; - vga.memory[((addr+offset)*16+(i*2)+1) % vga.svga_intf.vram_size] = m_gr11; - } - else - { - vga.memory[((addr+offset)*16+(i*2)) % vga.svga_intf.vram_size] = vga.gc.set_reset; - vga.memory[((addr+offset)*16+(i*2)+1) % vga.svga_intf.vram_size] = m_gr10; - } - } - } - return; - } - - if(vga.sequencer.data[4] & 0x8) - vga.memory[(offset+addr) % vga.svga_intf.vram_size] = data; - else - { - int i; - for(i=0;i<4;i++) - { - if(vga.sequencer.map_mask & 1 << i) - vga.memory[((offset*4+i)+addr) % vga.svga_intf.vram_size] = data; - } - } - } - else - { - //Inside each case must prevent writes to non-mapped VGA memory regions, not only mask the offset. - switch(vga.gc.memory_map_sel & 0x03) - { - case 0: break; - case 1: - if(offset & 0x10000) - return; - - if(gc_mode_ext & 0x01) - offset &= 0x7fff; - else - offset &= 0xffff; - break; - case 2: - if((offset & 0x18000) != 0x10000) - return; - - offset &= 0x07fff; - break; - case 3: - if((offset & 0x18000) != 0x18000) - return; - - offset &= 0x07fff; - break; - } - - { - // TODO: Lines up in 16-colour mode, likely different for 256-colour modes (docs say video addresses are shifted right 3 places) - uint8_t i; -// uint8_t bits = ((gc_mode_ext & 0x08) && (vga.gc.write_mode == 1)) ? 8 : 4; - - for(i=0;i<4;i++) - { - if(vga.sequencer.map_mask & 1 << i) - { - if(gc_mode_ext & 0x02) - { - vga.memory[(((offset+addr) << 1)+i*0x10000) % vga.svga_intf.vram_size] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data; - vga.memory[(((offset+addr) << 1)+i*0x10000+1) % vga.svga_intf.vram_size] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data; - } - else - vga.memory[(((offset+addr))+i*0x10000) % vga.svga_intf.vram_size] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data; - } - } - return; - } - } -} diff --git a/src/devices/video/clgd542x.h b/src/devices/video/clgd542x.h deleted file mode 100644 index 950163ec35f..00000000000 --- a/src/devices/video/clgd542x.h +++ /dev/null @@ -1,132 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Barry Rodewald -/* - - Cirrus Logic GD542x/3x video chipsets - -*/ -#ifndef MAME_VIDEO_CLGD542X_H -#define MAME_VIDEO_CLGD542X_H - -#pragma once - -#include "video/pc_vga.h" - -class cirrus_gd5428_device : public svga_device -{ -public: - // construction/destruction - cirrus_gd5428_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - virtual uint8_t port_03c0_r(offs_t offset) override; - virtual void port_03c0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03b0_r(offs_t offset) override; - virtual void port_03b0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03d0_r(offs_t offset) override; - virtual void port_03d0_w(offs_t offset, uint8_t data) override; - virtual uint8_t mem_r(offs_t offset) override; - virtual void mem_w(offs_t offset, uint8_t data) override; - - virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) override; - -protected: - cirrus_gd5428_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); - - // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - virtual uint16_t offset() override; - - uint8_t m_chip_id; - - uint8_t gc_mode_ext; - uint8_t gc_bank_0; - uint8_t gc_bank_1; - bool gc_locked; - uint8_t m_lock_reg; - uint8_t m_gr10; // high byte of background colour (in 15/16bpp) - uint8_t m_gr11; // high byte of foreground colour (in 15/16bpp) - - uint8_t m_cr19; - uint8_t m_cr1a; - uint8_t m_cr1b; - - // hardware cursor - uint16_t m_cursor_x; - uint16_t m_cursor_y; - uint16_t m_cursor_addr; - uint8_t m_cursor_attr; - bool m_ext_palette_enabled; - struct { uint8_t red, green, blue; } m_ext_palette[16]; // extra palette, colour 0 is cursor background, colour 15 is cursor foreground, colour 2 is overscan border colour - - // BitBLT engine - uint8_t m_blt_status; - uint8_t m_blt_rop; - uint8_t m_blt_mode; - uint32_t m_blt_source; - uint32_t m_blt_dest; - uint16_t m_blt_source_pitch; - uint16_t m_blt_dest_pitch; - uint16_t m_blt_height; - uint16_t m_blt_width; - uint32_t m_blt_source_current; - uint32_t m_blt_dest_current; - uint16_t m_blt_trans_colour; - uint16_t m_blt_trans_colour_mask; - - bool m_blt_system_transfer; // blit from system memory - uint8_t m_blt_system_count; - uint32_t m_blt_system_buffer; - uint16_t m_blt_pixel_count; - uint16_t m_blt_scan_count; - - uint8_t m_scratchpad1; - uint8_t m_scratchpad2; - uint8_t m_scratchpad3; - uint8_t m_vclk_num[4]; - uint8_t m_vclk_denom[4]; - - virtual uint8_t vga_latch_write(int offs, uint8_t data) override; - -private: - void cirrus_define_video_mode(); - uint8_t cirrus_seq_reg_read(uint8_t index); - void cirrus_seq_reg_write(uint8_t index, uint8_t data); - uint8_t cirrus_gc_reg_read(uint8_t index); - void cirrus_gc_reg_write(uint8_t index, uint8_t data); - uint8_t cirrus_crtc_reg_read(uint8_t index); - void cirrus_crtc_reg_write(uint8_t index, uint8_t data); - - void start_bitblt(); - void start_reverse_bitblt(); - void start_system_bitblt(); - void blit_dword(); - void blit_byte(); // used for colour expanded system-to-vram bitblts - void copy_pixel(uint8_t src, uint8_t dst); -}; - -class cirrus_gd5430_device : public cirrus_gd5428_device -{ -public: - cirrus_gd5430_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - -protected: - virtual void device_start() override; -}; - -class cirrus_gd5446_device : public cirrus_gd5428_device -{ -public: - cirrus_gd5446_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - -protected: - virtual void device_start() override; -}; - - -// device type definition -DECLARE_DEVICE_TYPE(CIRRUS_GD5428, cirrus_gd5428_device) -DECLARE_DEVICE_TYPE(CIRRUS_GD5430, cirrus_gd5430_device) -DECLARE_DEVICE_TYPE(CIRRUS_GD5446, cirrus_gd5446_device) - -#endif // MAME_VIDEO_CLGD542X_H diff --git a/src/devices/video/clgd546x_laguna.cpp b/src/devices/video/clgd546x_laguna.cpp index 12d684bb7e8..fd9b4621612 100644 --- a/src/devices/video/clgd546x_laguna.cpp +++ b/src/devices/video/clgd546x_laguna.cpp @@ -110,9 +110,7 @@ void cirrus_gd5465_laguna3d_device::legacy_memory_map(address_map &map) void cirrus_gd5465_laguna3d_device::legacy_io_map(address_map &map) { - map(0x03b0, 0x03bf).rw(FUNC(cirrus_gd5465_laguna3d_device::vga_3b0_r), FUNC(cirrus_gd5465_laguna3d_device::vga_3b0_w)); - map(0x03c0, 0x03cf).rw(FUNC(cirrus_gd5465_laguna3d_device::vga_3c0_r), FUNC(cirrus_gd5465_laguna3d_device::vga_3c0_w)); - map(0x03d0, 0x03df).rw(FUNC(cirrus_gd5465_laguna3d_device::vga_3d0_r), FUNC(cirrus_gd5465_laguna3d_device::vga_3d0_w)); + map(0, 0x02f).m(m_svga, FUNC(cirrus_gd5446_device::io_map)); } uint8_t cirrus_gd5465_laguna3d_device::vram_r(offs_t offset) @@ -125,85 +123,6 @@ void cirrus_gd5465_laguna3d_device::vram_w(offs_t offset, uint8_t data) downcast(m_svga.target())->mem_w(offset, data); } -u32 cirrus_gd5465_laguna3d_device::vga_3b0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 3) << 24; - return result; -} - -void cirrus_gd5465_laguna3d_device::vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 3, data >> 24); -} - - -u32 cirrus_gd5465_laguna3d_device::vga_3c0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 3) << 24; - return result; -} - -void cirrus_gd5465_laguna3d_device::vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 3, data >> 24); -} - -u32 cirrus_gd5465_laguna3d_device::vga_3d0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 3) << 24; - return result; -} - -void cirrus_gd5465_laguna3d_device::vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 3, data >> 24); -} - void cirrus_gd5465_laguna3d_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) { @@ -211,9 +130,7 @@ void cirrus_gd5465_laguna3d_device::map_extra(uint64_t memory_window_start, uint { memory_space->install_readwrite_handler(0xa0000, 0xbffff, read8sm_delegate(*this, FUNC(cirrus_gd5465_laguna3d_device::vram_r)), write8sm_delegate(*this, FUNC(cirrus_gd5465_laguna3d_device::vram_w))); - io_space->install_readwrite_handler(0x3b0, 0x3bf, read32s_delegate(*this, FUNC(cirrus_gd5465_laguna3d_device::vga_3b0_r)), write32s_delegate(*this, FUNC(cirrus_gd5465_laguna3d_device::vga_3b0_w))); - io_space->install_readwrite_handler(0x3c0, 0x3cf, read32s_delegate(*this, FUNC(cirrus_gd5465_laguna3d_device::vga_3c0_r)), write32s_delegate(*this, FUNC(cirrus_gd5465_laguna3d_device::vga_3c0_w))); - io_space->install_readwrite_handler(0x3d0, 0x3df, read32s_delegate(*this, FUNC(cirrus_gd5465_laguna3d_device::vga_3d0_r)), write32s_delegate(*this, FUNC(cirrus_gd5465_laguna3d_device::vga_3d0_w))); + io_space->install_device(0x03b0, 0x03df, *this, &cirrus_gd5465_laguna3d_device::legacy_io_map); //memory_space->install_rom(0xc0000, 0xcffff, (void *)expansion_rom); } } diff --git a/src/devices/video/clgd546x_laguna.h b/src/devices/video/clgd546x_laguna.h index 96086f94ae6..8c4faaa89f9 100644 --- a/src/devices/video/clgd546x_laguna.h +++ b/src/devices/video/clgd546x_laguna.h @@ -6,8 +6,7 @@ #pragma once #include "machine/pci.h" -//#include "video/pc_vga.h" -#include "video/clgd542x.h" +#include "video/pc_vga_cirrus.h" class cirrus_gd5465_laguna3d_device : public pci_device { @@ -37,12 +36,6 @@ private: u8 vram_r(offs_t offset); void vram_w(offs_t offset, uint8_t data); - u32 vga_3b0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - u32 vga_3c0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - u32 vga_3d0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); // u32 unmap_log_r(offs_t offset, u32 mem_mask = ~0); // void unmap_log_w(offs_t offset, u32 data, u32 mem_mask = ~0); diff --git a/src/devices/video/ibm8514a.cpp b/src/devices/video/ibm8514a.cpp index 969d93d908c..5adac1dc434 100644 --- a/src/devices/video/ibm8514a.cpp +++ b/src/devices/video/ibm8514a.cpp @@ -1493,13 +1493,13 @@ uint8_t ibm8514a_device::ibm8514_status_r(offs_t offset) case 0: return m_vga->vga_vblank() << 1; case 2: - return m_vga->port_03c0_r(6); + return m_vga->ramdac_mask_r(0); case 3: - return m_vga->port_03c0_r(7); + return m_vga->ramdac_state_r(0); case 4: - return m_vga->port_03c0_r(8); + return m_vga->ramdac_write_index_r(0); case 5: - return m_vga->port_03c0_r(9); + return m_vga->ramdac_data_r(0); } return 0; } @@ -1512,16 +1512,16 @@ void ibm8514a_device::ibm8514_htotal_w(offs_t offset, uint8_t data) ibm8514.htotal = data & 0xff; break; case 2: - m_vga->port_03c0_w(6, data); + m_vga->ramdac_mask_w(0, data); break; case 3: - m_vga->port_03c0_w(7, data); + m_vga->ramdac_read_index_w(0, data); break; case 4: - m_vga->port_03c0_w(8, data); + m_vga->ramdac_write_index_w(0, data); break; case 5: - m_vga->port_03c0_w(9, data); + m_vga->ramdac_data_w(0, data); break; } //vga.crtc.horz_total = data & 0x01ff; diff --git a/src/devices/video/pc_vga.cpp b/src/devices/video/pc_vga.cpp index db3b71fbd03..2caa993854d 100644 --- a/src/devices/video/pc_vga.cpp +++ b/src/devices/video/pc_vga.cpp @@ -1,31 +1,26 @@ // license:BSD-3-Clause // copyright-holders:Nathan Woods, Peter Trauner, Angelo Salese -/*************************************************************************** +/************************************************************************************************** Video Graphics Adapter (VGA) section Nathan Woods npwoods@mess.org Peter Trauner PeT mess@utanet.at - This code takes care of installing the various VGA memory and port - handlers - - The VGA standard is compatible with MDA, CGA, Hercules, EGA - (mda, cga, hercules not real register compatible) - several vga cards drive also mda, cga, ega monitors - some vga cards have register compatible mda, cga, hercules modes - ega/vga 64k (early ega 16k) words of 32 bit memory TODO: - - modernize - - fix video update, still need to get that choosevideomode() out of it. - - rewrite video drawing functions (they are horrible) - - add per-gfx card VESA functions; - - (and many more ...) - - per-game issues: + - modernize (in progress); + - Make RAMDAC a subclassable entity; + \- Clients needs to be able to swap that to SVGA extensions of the original 6bpp; + - Attribute from graphics to text mode in DOS doesn't restore properly, particularly if you + have a custom background color defined (verify); + - Improve debugging; + - Make a VGA bus slot option, already needed by 3dfx Voodoo and other similar cards; + - Verify how CAD ISA cards needs to r/w the VRAM space (uPD7220, HD63484, others); + + per-game issues (very outdated, to be moved to SW list/to device files if necessary): - The Incredible Machine: fix partial updates - MAME 0.01: fix 92 Hz refresh rate bug (uses VESA register?). - Virtual Pool: ET4k unrecognized; @@ -33,12 +28,25 @@ - Jazz Jackrabbit: status bar is very jerky, but main screen scrolling is fine? - Catacombs: weird resolution (untested) - ROM declarations: + Notes: + - The VGA standard is compatible with MDA, CGA, Hercules, EGA + (MDA, EGA, Hercules not real register compatible) + - several vga cards drive also MDA, CGA, EGA monitors, some vga cards have register compatible + MDA, CGA, Hercules modes; + - SVGA is not a real interface but more like an overlay of the VGA standard that individual + manufacturers put together and which eventually became the VESA consortium. + It has incidentally a couple points in common across families but it's otherwise mostly a + commercial naming rather than a real physical change over the bus slot. + + References: + - http://www.osdever.net/FreeVGA/vga/vga.htm + + ROM declarations (move to pc_vga_oak): (oti 037 chip) ROM_LOAD("oakvga.bin", 0xc0000, 0x8000, CRC(318c5f43) SHA1(2aeb6cf737fd87dfd08c9f5b5bc421fcdbab4ce9) ) -***************************************************************************/ +***************************************************************************************************/ #include "emu.h" #include "pc_vga.h" @@ -99,15 +107,21 @@ ***************************************************************************/ // device type definition -DEFINE_DEVICE_TYPE(VGA, vga_device, "vga", "VGA") +DEFINE_DEVICE_TYPE(VGA, vga_device, "vga", "VGA") vga_device::vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, type, tag, owner, clock) , device_video_interface(mconfig, *this) , device_palette_interface(mconfig, *this) + , device_memory_interface(mconfig, *this) , vga(*this) , m_input_sense(*this, "VGA_SENSE") { + m_main_if_space_config = address_space_config("io_regs", ENDIANNESS_LITTLE, 8, 4, 0, address_map_constructor(FUNC(vga_device::io_3bx_3dx_map), this)); + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(vga_device::crtc_map), this)); + m_gc_space_config = address_space_config("gc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(vga_device::gc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(vga_device::sequencer_map), this)); + m_atc_space_config = address_space_config("attribute_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(vga_device::attribute_map), this)); } vga_device::vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) @@ -115,16 +129,9 @@ vga_device::vga_device(const machine_config &mconfig, const char *tag, device_t { } -svga_device::svga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) - : vga_device(mconfig, type, tag, owner, clock) -{ -} - // zero everything, keep vtbls void vga_device::zero() { - vga.svga_intf.seq_regcount = 0; - vga.svga_intf.crtc_regcount = 0; memset(vga.pens, 0, sizeof(vga.pens)); vga.miscellaneous_output = 0; vga.feature_control = 0; @@ -136,18 +143,15 @@ void vga_device::zero() memset(&vga.oak, 0, sizeof(vga.oak)); } -void svga_device::zero() -{ - vga_device::zero(); - memset(&svga, 0, sizeof(svga)); -} - -/* VBLANK callback, start address definitely updates AT vblank, not before. */ -TIMER_CALLBACK_MEMBER(vga_device::vblank_timer_cb) +device_memory_interface::space_config_vector vga_device::memory_space_config() const { - vga.crtc.start_addr = vga.crtc.start_addr_latch; - vga.attribute.pel_shift = vga.attribute.pel_shift_latch; - m_vblank_timer->adjust( screen().time_until_pos(vga.crtc.vert_blank_start + vga.crtc.vert_blank_end) ); + return space_config_vector { + std::make_pair(MAIN_IF_REG, &m_main_if_space_config), + std::make_pair(CRTC_REG, &m_crtc_space_config), + std::make_pair(GC_REG, &m_gc_space_config), + std::make_pair(SEQ_REG, &m_seq_space_config), + std::make_pair(ATC_REG, &m_atc_space_config) + }; } void vga_device::device_start() @@ -160,11 +164,7 @@ void vga_device::device_start() // Avoid an infinite loop when displaying. 0 is not possible anyway. vga.crtc.maximum_scan_line = 1; - // copy over interfaces - vga.svga_intf.seq_regcount = 0x05; - vga.svga_intf.crtc_regcount = 0x19; - vga.memory = std::make_unique(vga.svga_intf.vram_size); memset(&vga.memory[0], 0, vga.svga_intf.vram_size); save_pointer(NAME(vga.memory), vga.svga_intf.vram_size); @@ -261,530 +261,1204 @@ void vga_device::device_start() m_vblank_timer = timer_alloc(FUNC(vga_device::vblank_timer_cb), this); } -void svga_device::device_start() +void vga_device::device_reset() { - vga_device::device_start(); - memset(&svga, 0, sizeof(svga)); + /* clear out the VGA structure */ + memset(vga.pens, 0, sizeof(vga.pens)); + vga.miscellaneous_output = 0; + m_ioas = false; + vga.feature_control = 0; + vga.sequencer.index = 0; + memset(vga.sequencer.data, 0, sizeof(vga.sequencer.data)); + vga.crtc.index = 0; + memset(vga.crtc.data, 0, sizeof(vga.crtc.data)); + vga.gc.index = 0; + memset(vga.gc.latch, 0, sizeof(vga.gc.latch)); + memset(&vga.attribute, 0, sizeof(vga.attribute)); + memset(&vga.dac, 0, sizeof(vga.dac)); + memset(&vga.cursor, 0, sizeof(vga.cursor)); + memset(&vga.oak, 0, sizeof(vga.oak)); - save_item(NAME(svga.bank_r)); - save_item(NAME(svga.bank_w)); - save_item(NAME(svga.rgb8_en)); - save_item(NAME(svga.rgb15_en)); - save_item(NAME(svga.rgb16_en)); - save_item(NAME(svga.rgb24_en)); - save_item(NAME(svga.rgb32_en)); - save_item(NAME(svga.id)); + vga.gc.memory_map_sel = 0x3; /* prevent xtbios excepting vga ram as system ram */ +/* amstrad pc1640 bios relies on the position of + the video memory area, + so I introduced the reset to switch to b8000 area */ + vga.sequencer.data[4] = 0; + + /* TODO: real defaults */ + vga.crtc.line_compare = 0x3ff; + /* skeleton/indiana.cpp boot PROM doesn't set this and assumes it's 0xff */ + vga.dac.mask = 0xff; } -uint16_t vga_device::offset() +/************************************** + * + * Main I/O space + * + *************************************/ + +// A bare minimum VGA installs 3 main I/O areas, a fixed one at $3c0 and a moveable one at $3b0-$3bb +// (for MDA compatibility) and $3d0-$3df. $3bc-$3bf is canonically assigned to LPT3 in an IBM machine. +void vga_device::io_map(address_map &map) { -// popmessage("Offset: %04x %s %s **",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD"); - if(vga.crtc.dw) - return vga.crtc.offset << 3; - if(vga.crtc.word_mode) - return vga.crtc.offset << 1; - else - return vga.crtc.offset << 2; + map.unmap_value_high(); +// map(0x00, 0x0b).view(m_ioas_3bx_view); +// m_ioas_3bx_view[0](0x00, 0x0b).m(FUNC(vga_device::io_3bx_3dx_map)); +// m_ioas_3bx_view[1](0x00, 0x0b).unmaprw(); + map(0x00, 0x0b).lrw8( + NAME([this] (offs_t offset) { + if (m_ioas == false) + return space(MAIN_IF_REG).read_byte(offset); + return (u8)space().unmap(); + }), + NAME([this] (offs_t offset, u8 data) { + if (m_ioas == false) + { + space(MAIN_IF_REG).write_byte(offset, data); + } + }) + ); + + map(0x10, 0x1f).m(FUNC(vga_device::io_3cx_map)); + +// map(0x20, 0x2f).view(m_ioas_3dx_view); +// m_ioas_3dx_view[0](0x20, 0x2f).unmaprw(); +// m_ioas_3dx_view[1](0x20, 0x2f).m(FUNC(vga_device::io_3bx_3dx_map)); + map(0x20, 0x2f).lrw8( + NAME([this] (offs_t offset) { + if (m_ioas == true) + return space(MAIN_IF_REG).read_byte(offset); + return (u8)space().unmap(); + }), + NAME([this] (offs_t offset, u8 data) { + if (m_ioas == true) + { + space(MAIN_IF_REG).write_byte(offset, data); + } + }) + ); } -uint32_t vga_device::start_addr() +void vga_device::io_3bx_3dx_map(address_map &map) { -// popmessage("Offset: %04x %s %s **",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD"); - if(vga.crtc.dw) - return vga.crtc.start_addr << 2; - if(vga.crtc.word_mode) - return vga.crtc.start_addr << 0; - else - return vga.crtc.start_addr << 1; + map(0x04, 0x04).rw(FUNC(vga_device::crtc_address_r), FUNC(vga_device::crtc_address_w)); + map(0x05, 0x05).rw(FUNC(vga_device::crtc_data_r), FUNC(vga_device::crtc_data_w)); + map(0x0a, 0x0a).rw(FUNC(vga_device::input_status_1_r), FUNC(vga_device::feature_control_w)); + // TODO: move these to indicated subclasses + map(0x08, 0x08).lr8( + NAME([this] (offs_t offset) { + LOG("VGA: 0x3d8 read %s\n", machine().describe_context()); + // TODO: PC-200 reads back CGA register here, everything else returns open bus OR CGA emulation of register 0x3d8 + return 0; + }) + ); + map(0x0f, 0x0f).lr8( + NAME([this] (offs_t offset) { + LOG("VGA: 0x3df \"oak test\" read %s\n", machine().describe_context()); + /* oak test */ + //return 0; + /* pega bios on/off */ + return 0x80; + }) + ); } -void vga_device::vga_vh_text(bitmap_rgb32 &bitmap, const rectangle &cliprect) +void vga_device::io_3cx_map(address_map &map) { - int width=VGA_CH_WIDTH, height = (vga.crtc.maximum_scan_line) * (vga.crtc.scan_doubling + 1); + map(0x00, 0x00).rw(FUNC(vga_device::atc_address_r), FUNC(vga_device::atc_address_data_w)); + map(0x01, 0x01).r(FUNC(vga_device::atc_data_r)); + map(0x02, 0x02).rw(FUNC(vga_device::input_status_0_r), FUNC(vga_device::miscellaneous_output_w)); + map(0x04, 0x04).rw(FUNC(vga_device::sequencer_address_r), FUNC(vga_device::sequencer_address_w)); + map(0x05, 0x05).rw(FUNC(vga_device::sequencer_data_r), FUNC(vga_device::sequencer_data_w)); + map(0x06, 0x06).rw(FUNC(vga_device::ramdac_mask_r), FUNC(vga_device::ramdac_mask_w)); + map(0x07, 0x07).rw(FUNC(vga_device::ramdac_state_r), FUNC(vga_device::ramdac_read_index_w)); + map(0x08, 0x08).rw(FUNC(vga_device::ramdac_write_index_r), FUNC(vga_device::ramdac_write_index_w)); + map(0x09, 0x09).rw(FUNC(vga_device::ramdac_data_r), FUNC(vga_device::ramdac_data_w)); + map(0x0a, 0x0a).r(FUNC(vga_device::feature_control_r)); + map(0x0c, 0x0c).r(FUNC(vga_device::miscellaneous_output_r)); + map(0x0e, 0x0e).rw(FUNC(vga_device::gc_address_r), FUNC(vga_device::gc_address_w)); + map(0x0f, 0x0f).rw(FUNC(vga_device::gc_data_r), FUNC(vga_device::gc_data_w)); + // TODO: doesn't belong here + map(0x03, 0x03).lrw8( + NAME([this] (offs_t offset) { + return vga.oak.reg; + }), + NAME([this] (offs_t offset, u8 data) { + vga.oak.reg = data; + }) + ); +} - if(vga.crtc.cursor_enable) - vga.cursor.visible = screen().frame_number() & 0x10; - else - vga.cursor.visible = 0; +/************************************** + * + * 3bx/3dx implementation + * + *************************************/ - for (int addr = vga.crtc.start_addr, line = -vga.crtc.preset_row_scan; line < TEXT_LINES; - line += height, addr += (offset()>>1)) - { - for (int pos = addr, column=0; column> 4; - back_col |= (vga.attribute.data[0x10]&8) ? 0 : ((attr & 0x80) >> 4); +void vga_device::crtc_address_w(offs_t offset, u8 data) +{ + vga.crtc.index = data; +} - for (int h = std::max(-line, 0); (h < height) && (line+h < std::min(TEXT_LINES, bitmap.height())); h++) - { - uint32_t *const bitmapline = &bitmap.pix(line+h); - uint8_t bits = vga.memory[font_base+(h>>(vga.crtc.scan_doubling))]; +u8 vga_device::crtc_data_r(offs_t offset) +{ + return space(CRTC_REG).read_byte(vga.crtc.index); +} - int mask, w; - for (mask=0x80, w=0; (w>=1) - { - pen_t pen; - if (bits&mask) - pen = vga.pens[blink_en ? back_col : fore_col]; - else - pen = vga.pens[back_col]; +void vga_device::crtc_data_w(offs_t offset, u8 data) +{ + vga.crtc.data[vga.crtc.index] = data; + space(CRTC_REG).write_byte(vga.crtc.index, data); +} - if(!screen().visible_area().contains(column*width+w, line+h)) - continue; - bitmapline[column*width+w] = pen; +u8 vga_device::input_status_1_r(offs_t offset) +{ + u8 res = 0; + u8 hsync, vsync; + vga.attribute.state = 0; - } - if (w>2; + break; } + + return res; } -void vga_device::vga_vh_ega(bitmap_rgb32 &bitmap, const rectangle &cliprect) +void vga_device::feature_control_w(offs_t offset, u8 data) { - int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); - int pel_shift = (vga.attribute.pel_shift & 7); + vga.feature_control = data; +} -// popmessage("%08x %02x",EGA_START_ADDRESS,pel_shift); +/************************************** + * + * 3cx implementation + * + *************************************/ - /**/ - for (int addr=EGA_START_ADDRESS, line=0; line= 0; i--) - { - pen_t pen = vga.pens[(data[0]&1) | (data[1]&2) | (data[2]&4) | (data[3]&8)]; +u8 vga_device::input_status_0_r(offs_t offset) +{ + u8 res = 0x60; // is VGA + const u8 sense_bit = (3 - (vga.miscellaneous_output >> 2)) & 3; + LOGDSW("Reading sense bit %d\n", sense_bit); + if(BIT(m_input_sense->read(), sense_bit)) + res |= 0x10; + return res; +} - data[0]>>=1; - data[1]>>=1; - data[2]>>=1; - data[3]>>=1; +void vga_device::miscellaneous_output_w(offs_t offset, u8 data) +{ + vga.miscellaneous_output = data; + recompute_params(); + m_ioas = bool(BIT(data, 0)); +} - if(!screen().visible_area().contains(c+i-pel_shift, line + yi)) - continue; - bitmapline[c+i-pel_shift] = pen; - } - } - } - } +u8 vga_device::sequencer_address_r(offs_t offset) +{ + return vga.sequencer.index; } -/* TODO: I'm guessing that in 256 colors mode every pixel actually outputs two pixels. Is it right? */ -void vga_device::vga_vh_vga(bitmap_rgb32 &bitmap, const rectangle &cliprect) +u8 vga_device::sequencer_data_r(offs_t offset) { - int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); - int pel_shift = (vga.attribute.pel_shift & 6); - int addrmask = vga.crtc.no_wrap ? -1 : 0xffff; + return space(SEQ_REG).read_byte(vga.sequencer.index); +} - /* line compare is screen sensitive */ - uint16_t mask_comp = 0x3ff; //| (LINES & 0x300); +void vga_device::sequencer_address_w(offs_t offset, u8 data) +{ + vga.sequencer.index = data; +} -// popmessage("%02x %02x",vga.attribute.pel_shift,vga.sequencer.data[4] & 0x08); +void vga_device::sequencer_data_w(offs_t offset, u8 data) +{ + // TODO: temporary cheat for read-back + vga.sequencer.data[vga.sequencer.index] = data; + space(SEQ_REG).write_byte(vga.sequencer.index, data); + recompute_params(); +} - int curr_addr = 0; - if(!(vga.sequencer.data[4] & 0x08)) +u8 vga_device::ramdac_mask_r(offs_t offset) +{ + return vga.dac.mask; +} + +u8 vga_device::ramdac_state_r(offs_t offset) +{ + return (vga.dac.read) ? 3 : 0; +} + +u8 vga_device::ramdac_write_index_r(offs_t offset) +{ + return vga.dac.write_index; +} + +u8 vga_device::ramdac_data_r(offs_t offset) +{ + u8 res = space().unmap(); + if (vga.dac.read) { - for (int addr = start_addr(), line=0; line 0x80000/4) - return; - - for(int xi=0;xi<8;xi++) - { - if (!screen().visible_area().contains(c+xi-(pel_shift), line + yi)) - continue; - bitmapline[c+xi-(pel_shift)] = pen(vga.memory[(pos & addrmask)+((xi >> 1)*0x10000)]); - } - } - } + case 0: + res = vga.dac.color[3*vga.dac.read_index]; + break; + case 1: + res = vga.dac.color[3*vga.dac.read_index + 1]; + break; + case 2: + res = vga.dac.color[3*vga.dac.read_index + 2]; + break; } - } - else - { - for (int addr = start_addr(), line=0; line 0x80000) - return; - for (int xi=0;xi<0x10;xi++) - { - if(!screen().visible_area().contains(c+xi-(pel_shift), line + yi)) - continue; - bitmapline[c+xi-pel_shift] = pen(vga.memory[(pos+(xi >> 1)) & addrmask]); - } - } - } + if (vga.dac.state == 3) + { + vga.dac.state = 0; + vga.dac.read_index++; } } + return res; } -void vga_device::vga_vh_cga(bitmap_rgb32 &bitmap, const rectangle &cliprect) +u8 vga_device::feature_control_r(offs_t offset) { - int height = (vga.crtc.scan_doubling + 1); - - int width = (vga.crtc.horz_disp_end + 1) * 8; - - for(int y=0;y> 1) * width/4); - - for(int x=0;x> (6-xi*2)) & 3]; - if(!screen().visible_area().contains(x+xi, y * height + yi)) - continue; - bitmapline[x+xi] = pen; - } - } - - addr++; - } - } + return vga.feature_control; } -void vga_device::vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect) +u8 vga_device::miscellaneous_output_r(offs_t offset) { - int height = (vga.crtc.scan_doubling + 1); - - int width = (vga.crtc.horz_disp_end + 1) * 8; - - for(int y=0;y> 1) * width/8); - - for(int x=0;x> (7-xi)) & 1]; - if(!screen().visible_area().contains(x+xi, y * height + yi)) - continue; - bitmapline[x+xi] = pen; - } - } - - addr++; - } - } + return vga.miscellaneous_output; } -void svga_device::svga_vh_rgb8(bitmap_rgb32 &bitmap, const rectangle &cliprect) +u8 vga_device::gc_address_r(offs_t offset) { - int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + return vga.gc.index; +} - /* line compare is screen sensitive */ - uint16_t mask_comp = 0x3ff; - int curr_addr = 0; -// uint16_t line_length; -// if(vga.crtc.dw) -// line_length = vga.crtc.offset << 3; // doubleword mode -// else -// { -// line_length = vga.crtc.offset << 4; -// } +u8 vga_device::gc_data_r(offs_t offset) +{ + return space(GC_REG).read_byte(vga.gc.index); +} - uint8_t start_shift = (!(vga.sequencer.data[4] & 0x08) || svga.ignore_chain4) ? 2 : 0; - for (int addr = VGA_START_ADDRESS << start_shift, line=0; line= vga.svga_intf.vram_size) - return; - for (int xi=0;xi<8;xi++) - { - if(!screen().visible_area().contains(c+xi, line + yi)) - continue; - bitmapline[c+xi] = pen(vga.memory[(pos+(xi))]); - } - } - } - } +void vga_device::ramdac_mask_w(offs_t offset, u8 data) +{ + vga.dac.mask = data; + vga.dac.dirty = 1; } -void svga_device::svga_vh_rgb15(bitmap_rgb32 &bitmap, const rectangle &cliprect) +void vga_device::ramdac_read_index_w(offs_t offset, u8 data) { - #define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8)) - constexpr uint32_t IV = 0xff000000; - int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); - - /* line compare is screen sensitive */ -// uint16_t mask_comp = 0xff | (TLINES & 0x300); - int curr_addr = 0; - int yi=0; - for (int addr = TGA_START_ADDRESS, line=0; line= vga.svga_intf.vram_size) - return; - for(int xi=0,xm=0;xi<8;xi++,xm+=2) - { - if(!screen().visible_area().contains(c+xi, line + yi)) - continue; - - int r = (MV(pos+xm)&0x7c00)>>10; - int g = (MV(pos+xm)&0x03e0)>>5; - int b = (MV(pos+xm)&0x001f)>>0; - r = (r << 3) | (r & 0x7); - g = (g << 3) | (g & 0x7); - b = (b << 3) | (b & 0x7); - bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0); - } - } - } + vga.dac.read_index = data; + vga.dac.state = 0; + vga.dac.read = 1; } -void svga_device::svga_vh_rgb16(bitmap_rgb32 &bitmap, const rectangle &cliprect) +void vga_device::ramdac_write_index_w(offs_t offset, u8 data) { - #define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8)) - constexpr uint32_t IV = 0xff000000; - int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + vga.dac.write_index = data; + vga.dac.state = 0; + vga.dac.read = 0; +} - /* line compare is screen sensitive */ -// uint16_t mask_comp = 0xff | (TLINES & 0x300); - int curr_addr = 0; - int yi=0; - for (int addr = TGA_START_ADDRESS, line=0; line= vga.svga_intf.vram_size) - return; - for (int xi=0,xm=0;xi<8;xi++,xm+=2) - { - if(!screen().visible_area().contains(c+xi, line + yi)) - continue; + case 0: + vga.dac.color[3*vga.dac.write_index]=data; + break; + case 1: + vga.dac.color[3*vga.dac.write_index + 1]=data; + break; + case 2: + vga.dac.color[3*vga.dac.write_index + 2]=data; + break; + } - int r = (MV(pos+xm)&0xf800)>>11; - int g = (MV(pos+xm)&0x07e0)>>5; - int b = (MV(pos+xm)&0x001f)>>0; - r = (r << 3) | (r & 0x7); - g = (g << 2) | (g & 0x3); - b = (b << 3) | (b & 0x7); - bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0); - } + vga.dac.dirty=1; + if (vga.dac.state==3) + { + vga.dac.state = 0; + vga.dac.write_index++; } } } -void svga_device::svga_vh_rgb24(bitmap_rgb32 &bitmap, const rectangle &cliprect) +void vga_device::gc_address_w(offs_t offset, u8 data) { - #define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16)) - constexpr uint32_t ID = 0xff000000; - int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); - - /* line compare is screen sensitive */ -// uint16_t mask_comp = 0xff | (TLINES & 0x300); - int curr_addr = 0; - int yi=0; - for (int addr = TGA_START_ADDRESS<<1, line=0; line= vga.svga_intf.vram_size) - return; - for (int xi=0,xm=0;xi<8;xi++,xm+=3) - { - if(!screen().visible_area().contains(c+xi, line + yi)) - continue; - - int r = (MD(pos+xm)&0xff0000)>>16; - int g = (MD(pos+xm)&0x00ff00)>>8; - int b = (MD(pos+xm)&0x0000ff)>>0; - bitmapline[c+xi] = ID|(r<<16)|(g<<8)|(b<<0); - } - } - } + vga.gc.index=data; } -void svga_device::svga_vh_rgb32(bitmap_rgb32 &bitmap, const rectangle &cliprect) +void vga_device::gc_data_w(offs_t offset, u8 data) { - #define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16)) - constexpr uint32_t ID = 0xff000000; - int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + space(GC_REG).write_byte(vga.gc.index, data); +} -// uint16_t mask_comp; - /* line compare is screen sensitive */ -// mask_comp = 0xff | (TLINES & 0x300); - int curr_addr = 0; - int yi=0; - for (int addr = TGA_START_ADDRESS, line=0; line= vga.svga_intf.vram_size) - return; - for (int xi=0,xm=0;xi<8;xi++,xm+=4) - { - if(!screen().visible_area().contains(c+xi, line + yi)) - continue; +/************************************** + * + * CRTC + * + *************************************/ - int r = (MD(pos+xm)&0xff0000)>>16; - int g = (MD(pos+xm)&0x00ff00)>>8; - int b = (MD(pos+xm)&0x0000ff)>>0; - bitmapline[c+xi] = ID|(r<<16)|(g<<8)|(b<<0); +void vga_device::crtc_map(address_map &map) +{ + map(0x00, 0x00).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.horz_total & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + // doom (DOS) tries to write to protected regs + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_total = (vga.crtc.horz_total & ~0xff) | (data & 0xff); + recompute_params(); + }) + ); + map(0x01, 0x01).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.horz_disp_end & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_disp_end = (data & 0xff); + recompute_params(); + }) + ); + map(0x02, 0x02).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.horz_blank_start & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_blank_start = (data & 0xff); + }) + ); + map(0x03, 0x03).lrw8( + NAME([this](offs_t offset) { + u8 res = vga.crtc.horz_blank_end & 0x1f; + res |= (vga.crtc.disp_enable_skew & 3) << 5; + res |= (vga.crtc.evra & 1) << 7; + return res; + }), + NAME([this](offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_blank_end &= ~0x1f; + vga.crtc.horz_blank_end |= data & 0x1f; + vga.crtc.disp_enable_skew = (data & 0x60) >> 5; + vga.crtc.evra = BIT(data, 7); + }) + ); + map(0x04, 0x04).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.horz_retrace_start & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_retrace_start = data & 0xff; + }) + ); + map(0x05, 0x05).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.crtc.horz_blank_end & 0x20) << 2; + res |= (vga.crtc.horz_retrace_skew & 3) << 5; + res |= (vga.crtc.horz_retrace_end & 0x1f); + return res; + }), + NAME([this](offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_blank_end &= ~0x20; + vga.crtc.horz_blank_end |= ((data & 0x80) >> 2); + vga.crtc.horz_retrace_skew = ((data & 0x60) >> 5); + vga.crtc.horz_retrace_end = data & 0x1f; + }) + ); + map(0x06, 0x06).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.vert_total & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.vert_total &= ~0xff; + vga.crtc.vert_total |= data & 0xff; + recompute_params(); + }) + ); + // Overflow Register + map(0x07, 0x07).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.crtc.line_compare & 0x100) >> 4; + res |= (vga.crtc.vert_retrace_start & 0x200) >> 2; + res |= (vga.crtc.vert_disp_end & 0x200) >> 3; + res |= (vga.crtc.vert_total & 0x200) >> 4; + res |= (vga.crtc.vert_blank_start & 0x100) >> 5; + res |= (vga.crtc.vert_retrace_start & 0x100) >> 6; + res |= (vga.crtc.vert_disp_end & 0x100) >> 7; + res |= (vga.crtc.vert_total & 0x100) >> 8; + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.line_compare &= ~0x100; + vga.crtc.line_compare |= ((data & 0x10) << (8-4)); + if(vga.crtc.protect_enable) + return; + vga.crtc.vert_total &= ~0x300; + vga.crtc.vert_retrace_start &= ~0x300; + vga.crtc.vert_disp_end &= ~0x300; + vga.crtc.vert_blank_start &= ~0x100; + vga.crtc.vert_retrace_start |= ((data & 0x80) << (9-7)); + vga.crtc.vert_disp_end |= ((data & 0x40) << (9-6)); + vga.crtc.vert_total |= ((data & 0x20) << (9-5)); + vga.crtc.vert_blank_start |= ((data & 0x08) << (8-3)); + vga.crtc.vert_retrace_start |= ((data & 0x04) << (8-2)); + vga.crtc.vert_disp_end |= ((data & 0x02) << (8-1)); + vga.crtc.vert_total |= ((data & 0x01) << (8-0)); + recompute_params(); + }) + ); + // Preset Row Scan Register + map(0x08, 0x08).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.crtc.byte_panning & 3) << 5; + res |= (vga.crtc.preset_row_scan & 0x1f); + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.byte_panning = (data & 0x60) >> 5; + vga.crtc.preset_row_scan = (data & 0x1f); + }) + ); + // Maximum Scan Line Register + map(0x09, 0x09).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.crtc.maximum_scan_line - 1) & 0x1f; + res |= (vga.crtc.scan_doubling & 1) << 7; + res |= (vga.crtc.line_compare & 0x200) >> 3; + res |= (vga.crtc.vert_blank_start & 0x200) >> 4; + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.line_compare &= ~0x200; + vga.crtc.vert_blank_start &= ~0x200; + vga.crtc.scan_doubling = ((data & 0x80) >> 7); + vga.crtc.line_compare |= ((data & 0x40) << (9-6)); + vga.crtc.vert_blank_start |= ((data & 0x20) << (9-5)); + vga.crtc.maximum_scan_line = (data & 0x1f) + 1; + }) + ); + map(0x0a, 0x0a).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.crtc.cursor_scan_start & 0x1f); + res |= ((vga.crtc.cursor_enable & 1) ^ 1) << 5; + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.cursor_enable = ((data & 0x20) ^ 0x20) >> 5; + vga.crtc.cursor_scan_start = data & 0x1f; + }) + ); + map(0x0b, 0x0b).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.crtc.cursor_skew & 3) << 5; + res |= (vga.crtc.cursor_scan_end & 0x1f); + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.cursor_skew = (data & 0x60) >> 5; + vga.crtc.cursor_scan_end = data & 0x1f; + }) + ); + map(0x0c, 0x0d).lrw8( + NAME([this](offs_t offset) { + return (vga.crtc.start_addr_latch >> ((offset & 1) ^ 1) * 8) & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.start_addr_latch &= ~(0xff << (((offset & 1) ^ 1) * 8)); + vga.crtc.start_addr_latch |= (data << (((offset & 1) ^ 1) * 8)); + }) + ); + map(0x0e, 0x0f).lrw8( + NAME([this](offs_t offset) { + return (vga.crtc.cursor_addr >> ((offset & 1) ^ 1)*8) & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.cursor_addr &= ~(0xff << (((offset & 1) ^ 1) * 8)); + vga.crtc.cursor_addr |= (data << (((offset & 1) ^ 1) * 8)); + }) + ); + map(0x10, 0x10).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.vert_retrace_start & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.vert_retrace_start &= ~0xff; + vga.crtc.vert_retrace_start |= data & 0xff; + }) + ); + map(0x11, 0x11).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.crtc.protect_enable & 1) << 7; + res |= (vga.crtc.bandwidth & 1) << 6; + res |= (vga.crtc.vert_retrace_end & 0xf); + res |= (vga.crtc.irq_clear & 1) << 4; + res |= (vga.crtc.irq_disable & 1) << 5; + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.protect_enable = (data & 0x80) >> 7; + vga.crtc.bandwidth = (data & 0x40) >> 6; + vga.crtc.vert_retrace_end = data & 0x0f; + vga.crtc.irq_clear = (data & 0x10) >> 4; + vga.crtc.irq_disable = (data & 0x20) >> 5; + }) + ); + map(0x12, 0x12).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.vert_disp_end & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.vert_disp_end &= ~0xff; + vga.crtc.vert_disp_end |= data & 0xff; + recompute_params(); + }) + ); + map(0x13, 0x13).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.offset & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.offset &= ~0xff; + vga.crtc.offset |= data & 0xff; + }) + ); + map(0x14, 0x14).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.crtc.dw & 1) << 6; + res |= (vga.crtc.div4 & 1) << 5; + res |= (vga.crtc.underline_loc & 0x1f); + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.dw = (data & 0x40) >> 6; + vga.crtc.div4 = (data & 0x20) >> 5; + vga.crtc.underline_loc = (data & 0x1f); + }) + ); + map(0x15, 0x15).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.vert_blank_start & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.vert_blank_start &= ~0xff; + vga.crtc.vert_blank_start |= data & 0xff; + }) + ); + map(0x16, 0x16).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.vert_blank_end & 0x7f; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.vert_blank_end = data & 0x7f; + }) + ); + map(0x17, 0x17).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.crtc.sync_en & 1) << 7; + res |= (vga.crtc.word_mode & 1) << 6; + res |= (vga.crtc.aw & 1) << 5; + res |= (vga.crtc.div2 & 1) << 3; + res |= (vga.crtc.sldiv & 1) << 2; + res |= (vga.crtc.map14 & 1) << 1; + res |= (vga.crtc.map13 & 1) << 0; + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.sync_en = BIT(data, 7); + vga.crtc.word_mode = BIT(data, 6); + vga.crtc.aw = BIT(data, 5); + vga.crtc.div2 = BIT(data, 3); + vga.crtc.sldiv = BIT(data, 2); + vga.crtc.map14 = BIT(data, 1); + vga.crtc.map13 = BIT(data, 0); + }) + ); + map(0x18, 0x18).lrw8( + NAME([this](offs_t offset) { + return vga.crtc.line_compare & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + vga.crtc.line_compare &= ~0xff; + vga.crtc.line_compare |= data & 0xff; + }) + ); + // TODO: (undocumented) CR22 Memory Data Latch Register (read only) + // map(0x22, 0x22).lr8( + // (undocumented) CR24 Attribute Controller Toggle Register (read only) + // 0--- ---- index + // 1--- ---- data + map(0x24, 0x24).lr8( + NAME([this](offs_t offset) { + LOG("CR24 read undocumented Attribute reg\n"); + return vga.attribute.state << 7; + }) + ); +} + +/************************************** + * + * GC + * + *************************************/ + +void vga_device::gc_map(address_map &map) +{ + map.unmap_value_high(); + map(0x00, 0x00).lrw8( + NAME([this](offs_t offset) { + return vga.gc.set_reset & 0xf; + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.set_reset = data & 0xf; + }) + ); + map(0x01, 0x01).lrw8( + NAME([this](offs_t offset) { + return vga.gc.enable_set_reset & 0xf; + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.enable_set_reset = data & 0xf; + }) + ); + map(0x02, 0x02).lrw8( + NAME([this](offs_t offset) { + return vga.gc.color_compare & 0xf; + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.color_compare = data & 0xf; + }) + ); + map(0x03, 0x03).lrw8( + NAME([this](offs_t offset) { + return ((vga.gc.logical_op & 3) << 3) | (vga.gc.rotate_count & 7); + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.logical_op = (data & 0x18) >> 3; + vga.gc.rotate_count = data & 7; + }) + ); + map(0x04, 0x04).lrw8( + NAME([this](offs_t offset) { + return vga.gc.read_map_sel & 3; + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.read_map_sel = data & 3; + }) + ); + map(0x05, 0x05).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.gc.shift256 & 1) << 6; + res |= (vga.gc.shift_reg & 1) << 5; + res |= (vga.gc.host_oe & 1) << 4; + res |= (vga.gc.read_mode & 1) << 3; + res |= (vga.gc.write_mode & 3); + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.shift256 = BIT(data, 6); + vga.gc.shift_reg = BIT(data, 5); + vga.gc.host_oe = BIT(data, 4); + vga.gc.read_mode = BIT(data, 3); + vga.gc.write_mode = data & 3; + //if(data & 0x10 && vga.gc.alpha_dis) + // popmessage("Host O/E enabled, contact MAMEdev"); + }) + ); + map(0x06, 0x06).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.gc.memory_map_sel & 3) << 2; + res |= (vga.gc.chain_oe & 1) << 1; + res |= (vga.gc.alpha_dis & 1); + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.memory_map_sel = (data & 0xc) >> 2; + vga.gc.chain_oe = BIT(data, 1); + vga.gc.alpha_dis = BIT(data, 0); + //if(data & 2 && vga.gc.alpha_dis) + // popmessage("Chain O/E enabled, contact MAMEdev"); + }) + ); + map(0x07, 0x07).lrw8( + NAME([this](offs_t offset) { + return vga.gc.color_dont_care & 0xf; + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.color_dont_care = data & 0xf; + }) + ); + map(0x08, 0x08).lrw8( + NAME([this](offs_t offset) { + return vga.gc.bit_mask & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.bit_mask = data & 0xff; + }) + ); +} + +/************************************** + * + * Sequencer + * + *************************************/ + +void vga_device::sequencer_map(address_map &map) +{ + // TODO: legacy fallback trick + map(0x00, 0xff).lr8( + NAME([this] (offs_t offset) { + const u8 res = vga.sequencer.data[offset]; + if (!machine().side_effects_disabled()) + LOG("Reading unmapped sequencer read register [%02x] -> %02x (SVGA?)\n", offset, res); + return res; + }) + ); +// map(0x00, 0x00) Reset Register +// map(0x01, 0x01) Clocking Mode Register + map(0x02, 0x02).lw8( + NAME([this] (offs_t offset, u8 data) { + vga.sequencer.map_mask = data & 0xf; + }) + ); + map(0x03, 0x03).lw8( + NAME([this] (offs_t offset, u8 data) { + /* --2- 84-- character select A + ---2 --84 character select B */ + vga.sequencer.char_sel.A = (((data & 0xc) >> 2)<<1) | ((data & 0x20) >> 5); + vga.sequencer.char_sel.B = (((data & 0x3) >> 0)<<1) | ((data & 0x10) >> 4); + if(data) + popmessage("Char SEL checker, contact MAMEdev (%02x %02x)\n",vga.sequencer.char_sel.A,vga.sequencer.char_sel.B); + }) + ); + // Sequencer Memory Mode Register +// map(0x04, 0x04) + // (undocumented) Sequencer Horizontal Character Counter Reset + // Any write strobe to this register will lock the character generator until another write to other regs happens. +// map(0x07, 0x07) +} + +/************************************** + * + * Attribute (ATC) + * + *************************************/ + +/* + * xx-- ---- + * --x- ---- Palette RAM address source (0) CPU access (1) ATC access + * \- NB: leaving to '0' will disable video output from the ATC, + * and cause overscan drawing in canvas instead. + * ---x xxxx index register + * + */ +void vga_device::attribute_map(address_map &map) +{ + map.global_mask(0x3f); + map.unmap_value_high(); + map(0x00, 0x0f).lrw8( + NAME([this] (offs_t offset) { return vga.attribute.data[ offset & 0x1f]; }), + NAME([this] (offs_t offset, u8 data) { vga.attribute.data[offset & 0x1f] = data & 0x3f; }) + ); + map(0x20, 0x2f).noprw(); + // Mode Control + map(0x10, 0x10).mirror(0x20).lrw8( + NAME([this] (offs_t offset) { return vga.attribute.data[ 0x10 ]; }), + NAME([this] (offs_t offset, u8 data) { vga.attribute.data[ 0x10 ] = data & 0x3f; }) + ); + // Overscan Color + map(0x11, 0x11).mirror(0x20).lrw8( + NAME([this] (offs_t offset) { return vga.attribute.data[ 0x11 ]; }), + NAME([this] (offs_t offset, u8 data) { vga.attribute.data[ 0x11 ] = data & 0x3f; }) + ); + // Color Plane Enable + map(0x12, 0x12).mirror(0x20).lrw8( + NAME([this] (offs_t offset) { return vga.attribute.data[ 0x12 ]; }), + NAME([this] (offs_t offset, u8 data) { vga.attribute.data[ 0x12 ] = data & 0x3f; }) + ); + // Horizontal PEL shift + map(0x13, 0x13).mirror(0x20).lrw8( + NAME([this] (offs_t offset) { return vga.attribute.data[ 0x13 ]; }), + NAME([this] (offs_t offset, u8 data) { vga.attribute.pel_shift_latch = vga.attribute.data[ 0x13 ] = data & 0xf; }) + ); + // Color Select + map(0x14, 0x14).mirror(0x20).lrw8( + NAME([this] (offs_t offset) { return vga.attribute.data[ 0x14 ]; }), + NAME([this] (offs_t offset, u8 data) { vga.attribute.pel_shift_latch = vga.attribute.data[ 0x14 ] = data & 0xf; }) + ); +} + +/************************************** + * + * Drawing routines + * + *************************************/ + +uint16_t vga_device::offset() +{ +// popmessage("Offset: %04x %s %s **",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD"); + if(vga.crtc.dw) + return vga.crtc.offset << 3; + if(vga.crtc.word_mode) + return vga.crtc.offset << 1; + else + return vga.crtc.offset << 2; +} + +uint32_t vga_device::start_addr() +{ +// popmessage("Offset: %04x %s %s **",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD"); + if(vga.crtc.dw) + return vga.crtc.start_addr << 2; + if(vga.crtc.word_mode) + return vga.crtc.start_addr << 0; + else + return vga.crtc.start_addr << 1; +} + +uint8_t vga_device::vga_latch_write(int offs, uint8_t data) +{ + uint8_t res = 0; + + switch (vga.gc.write_mode & 3) { + case 0: + data = rotate_right(data); + if(vga.gc.enable_set_reset & 1<>1)) + { + for (int pos = addr, column=0; column> 4; + back_col |= (vga.attribute.data[0x10]&8) ? 0 : ((attr & 0x80) >> 4); + + for (int h = std::max(-line, 0); (h < height) && (line+h < std::min(TEXT_LINES, bitmap.height())); h++) + { + uint32_t *const bitmapline = &bitmap.pix(line+h); + uint8_t bits = vga.memory[font_base+(h>>(vga.crtc.scan_doubling))]; + + int mask, w; + for (mask=0x80, w=0; (w>=1) + { + pen_t pen; + if (bits&mask) + pen = vga.pens[blink_en ? back_col : fore_col]; + else + pen = vga.pens[back_col]; + + if(!screen().visible_area().contains(column*width+w, line+h)) + continue; + bitmapline[column*width+w] = pen; + + } + if (w= 0; i--) + { + pen_t pen = vga.pens[(data[0]&1) | (data[1]&2) | (data[2]&4) | (data[3]&8)]; + + data[0]>>=1; + data[1]>>=1; + data[2]>>=1; + data[3]>>=1; + + if(!screen().visible_area().contains(c+i-pel_shift, line + yi)) + continue; + bitmapline[c+i-pel_shift] = pen; + } + } + } + } +} + +/* TODO: I'm guessing that in 256 colors mode every pixel actually outputs two pixels. Is it right? */ +void vga_device::vga_vh_vga(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + int pel_shift = (vga.attribute.pel_shift & 6); + int addrmask = vga.crtc.no_wrap ? -1 : 0xffff; + + /* line compare is screen sensitive */ + uint16_t mask_comp = 0x3ff; //| (LINES & 0x300); + +// popmessage("%02x %02x",vga.attribute.pel_shift,vga.sequencer.data[4] & 0x08); + + int curr_addr = 0; + if(!(vga.sequencer.data[4] & 0x08)) + { + for (int addr = start_addr(), line=0; line 0x80000/4) + return; + + for(int xi=0;xi<8;xi++) + { + if (!screen().visible_area().contains(c+xi-(pel_shift), line + yi)) + continue; + bitmapline[c+xi-(pel_shift)] = pen(vga.memory[(pos & addrmask)+((xi >> 1)*0x10000)]); + } + } } } } -} - -uint8_t vga_device::pc_vga_choosevideomode() -{ - if (vga.crtc.sync_en) + else { - if (vga.dac.dirty) + for (int addr = start_addr(), line=0; line 0x80000) + return; + + for (int xi=0;xi<0x10;xi++) + { + if(!screen().visible_area().contains(c+xi-(pel_shift), line + yi)) + continue; + bitmapline[c+xi-pel_shift] = pen(vga.memory[(pos+(xi >> 1)) & addrmask]); + } + } } - vga.dac.dirty = 0; } + } +} - if (vga.attribute.data[0x10] & 0x80) +void vga_device::vga_vh_cga(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int height = (vga.crtc.scan_doubling + 1); + + int width = (vga.crtc.horz_disp_end + 1) * 8; + + for(int y=0;y> 1) * width/4); + + for(int x=0;x> (6-xi*2)) & 3]; + if(!screen().visible_area().contains(x+xi, y * height + yi)) + continue; + bitmapline[x+xi] = pen; + } } + + addr++; } - else + } +} + +void vga_device::vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + int height = (vga.crtc.scan_doubling + 1); + + int width = (vga.crtc.horz_disp_end + 1) * 8; + + for(int y=0;y> 1) * width/8); + + for(int x=0;x> (7-xi)) & 1]; + if(!screen().visible_area().contains(x+xi, y * height + yi)) + continue; + bitmapline[x+xi] = pen; + } } - } - if (!GRAPHIC_MODE) - { - return TEXT_MODE; - } - else if (vga.gc.shift256) - { - return VGA_MODE; - } - else if (vga.gc.shift_reg) - { - return CGA_MODE; - } - else if (vga.gc.memory_map_sel == 0x03) - { - return MONO_MODE; - } - else - { - return EGA_MODE; + addr++; } } - - return SCREEN_OFF; } - -uint8_t svga_device::pc_vga_choosevideomode() +uint8_t vga_device::pc_vga_choosevideomode() { if (vga.crtc.sync_en) { @@ -817,27 +1491,7 @@ uint8_t svga_device::pc_vga_choosevideomode() } } - if (svga.rgb32_en) - { - return RGB32_MODE; - } - else if (svga.rgb24_en) - { - return RGB24_MODE; - } - else if (svga.rgb16_en) - { - return RGB16_MODE; - } - else if (svga.rgb15_en) - { - return RGB15_MODE; - } - else if (svga.rgb8_en) - { - return RGB8_MODE; - } - else if (!GRAPHIC_MODE) + if (!GRAPHIC_MODE) { return TEXT_MODE; } @@ -862,206 +1516,29 @@ uint8_t svga_device::pc_vga_choosevideomode() return SCREEN_OFF; } -uint8_t svga_device::get_video_depth() -{ - switch(pc_vga_choosevideomode()) - { - case VGA_MODE: - case RGB8_MODE: - return 8; - case RGB15_MODE: - case RGB16_MODE: - return 16; - case RGB24_MODE: - case RGB32_MODE: - return 32; - } - return 0; -} - uint32_t vga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { uint8_t cur_mode = pc_vga_choosevideomode(); switch(cur_mode) - { - case SCREEN_OFF: bitmap.fill (black_pen(), cliprect);break; - case TEXT_MODE: vga_vh_text (bitmap, cliprect); break; - case VGA_MODE: vga_vh_vga (bitmap, cliprect); break; - case EGA_MODE: vga_vh_ega (bitmap, cliprect); break; - case CGA_MODE: vga_vh_cga (bitmap, cliprect); break; - case MONO_MODE: vga_vh_mono (bitmap, cliprect); break; - } - - return 0; -} - -uint32_t svga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) -{ - uint8_t cur_mode = pc_vga_choosevideomode(); - - switch(cur_mode) - { - case SCREEN_OFF: bitmap.fill (black_pen(), cliprect);break; - case TEXT_MODE: vga_vh_text (bitmap, cliprect); break; - case VGA_MODE: vga_vh_vga (bitmap, cliprect); break; - case EGA_MODE: vga_vh_ega (bitmap, cliprect); break; - case CGA_MODE: vga_vh_cga (bitmap, cliprect); break; - case MONO_MODE: vga_vh_mono (bitmap, cliprect); break; - case RGB8_MODE: svga_vh_rgb8 (bitmap, cliprect); break; - case RGB15_MODE: svga_vh_rgb15(bitmap, cliprect); break; - case RGB16_MODE: svga_vh_rgb16(bitmap, cliprect); break; - case RGB24_MODE: svga_vh_rgb24(bitmap, cliprect); break; - case RGB32_MODE: svga_vh_rgb32(bitmap, cliprect); break; - } - - return 0; -} - -/***************************************************************************/ - -uint8_t vga_device::vga_latch_write(int offs, uint8_t data) -{ - uint8_t res = 0; - - switch (vga.gc.write_mode & 3) { - case 0: - data = rotate_right(data); - if(vga.gc.enable_set_reset & 1<> 4; - res |= (vga.crtc.vert_retrace_start & 0x200) >> 2; - res |= (vga.crtc.vert_disp_end & 0x200) >> 3; - res |= (vga.crtc.vert_total & 0x200) >> 4; - res |= (vga.crtc.vert_blank_start & 0x100) >> 5; - res |= (vga.crtc.vert_retrace_start & 0x100) >> 6; - res |= (vga.crtc.vert_disp_end & 0x100) >> 7; - res |= (vga.crtc.vert_total & 0x100) >> 8; - break; - case 0x08: // Preset Row Scan Register - res = (vga.crtc.byte_panning & 3) << 5; - res |= (vga.crtc.preset_row_scan & 0x1f); - break; - case 0x09: // Maximum Scan Line Register - res = (vga.crtc.maximum_scan_line - 1) & 0x1f; - res |= (vga.crtc.scan_doubling & 1) << 7; - res |= (vga.crtc.line_compare & 0x200) >> 3; - res |= (vga.crtc.vert_blank_start & 0x200) >> 4; - break; - case 0x0a: - res = (vga.crtc.cursor_scan_start & 0x1f); - res |= ((vga.crtc.cursor_enable & 1) ^ 1) << 5; - break; - case 0x0b: - res = (vga.crtc.cursor_skew & 3) << 5; - res |= (vga.crtc.cursor_scan_end & 0x1f); - break; - case 0x0c: - case 0x0d: - res = (vga.crtc.start_addr_latch >> ((index & 1) ^ 1)*8) & 0xff; - break; - case 0x0e: - case 0x0f: - res = (vga.crtc.cursor_addr >> ((index & 1) ^ 1)*8) & 0xff; - break; - case 0x10: - res = vga.crtc.vert_retrace_start & 0xff; - break; - case 0x11: - res = (vga.crtc.protect_enable & 1) << 7; - res |= (vga.crtc.bandwidth & 1) << 6; - res |= (vga.crtc.vert_retrace_end & 0xf); - res |= (vga.crtc.irq_clear & 1) << 4; - res |= (vga.crtc.irq_disable & 1) << 5; - break; - case 0x12: - res = vga.crtc.vert_disp_end & 0xff; - break; - case 0x13: - res = vga.crtc.offset & 0xff; - break; - case 0x14: - res = (vga.crtc.dw & 1) << 6; - res |= (vga.crtc.div4 & 1) << 5; - res |= (vga.crtc.underline_loc & 0x1f); - break; - case 0x15: - res = vga.crtc.vert_blank_start & 0xff; - break; - case 0x16: - res = vga.crtc.vert_blank_end & 0x7f; - break; - case 0x17: - res = (vga.crtc.sync_en & 1) << 7; - res |= (vga.crtc.word_mode & 1) << 6; - res |= (vga.crtc.aw & 1) << 5; - res |= (vga.crtc.div2 & 1) << 3; - res |= (vga.crtc.sldiv & 1) << 2; - res |= (vga.crtc.map14 & 1) << 1; - res |= (vga.crtc.map13 & 1) << 0; - break; - case 0x18: - res = vga.crtc.line_compare & 0xff; - break; - default: - printf("Unhandled CRTC reg r %02x\n",index); - break; + { + case SCREEN_OFF: bitmap.fill (black_pen(), cliprect);break; + case TEXT_MODE: vga_vh_text (bitmap, cliprect); break; + case VGA_MODE: vga_vh_vga (bitmap, cliprect); break; + case EGA_MODE: vga_vh_ega (bitmap, cliprect); break; + case CGA_MODE: vga_vh_cga (bitmap, cliprect); break; + case MONO_MODE: vga_vh_mono (bitmap, cliprect); break; } - return res; + + return 0; } +/************************************** + * + * CRTC setups + * + *************************************/ + void vga_device::recompute_params_clock(int divisor, int xtal) { int vblank_period,hblank_period; @@ -1087,6 +1564,7 @@ void vga_device::recompute_params_clock(int divisor, int xtal) m_vblank_timer->adjust( screen().time_until_pos(vga.crtc.vert_blank_start + vga.crtc.vert_blank_end) ); } +// TODO: rename me void vga_device::recompute_params() { if(vga.miscellaneous_output & 8) @@ -1095,175 +1573,6 @@ void vga_device::recompute_params() recompute_params_clock(1, ((vga.miscellaneous_output & 0xc) ? XTAL(28'636'363) : XTAL(25'174'800)).value()); } -void vga_device::crtc_reg_write(uint8_t index, uint8_t data) -{ - /* Doom does this */ -// if(vga.crtc.protect_enable && index <= 0x07) -// printf("write to protected address %02x\n",index); - switch(index) - { - case 0x00: - if(vga.crtc.protect_enable) - break; - vga.crtc.horz_total = (vga.crtc.horz_total & ~0xff) | (data & 0xff); - recompute_params(); - break; - case 0x01: - if(vga.crtc.protect_enable) - break; - vga.crtc.horz_disp_end = (data & 0xff); - recompute_params(); - break; - case 0x02: - if(vga.crtc.protect_enable) - break; - vga.crtc.horz_blank_start = (data & 0xff); - break; - case 0x03: - if(vga.crtc.protect_enable) - break; - vga.crtc.horz_blank_end &= ~0x1f; - vga.crtc.horz_blank_end |= data & 0x1f; - vga.crtc.disp_enable_skew = (data & 0x60) >> 5; - vga.crtc.evra = (data & 0x80) >> 7; - break; - case 0x04: - if(vga.crtc.protect_enable) - break; - vga.crtc.horz_retrace_start = data & 0xff; - break; - case 0x05: - if(vga.crtc.protect_enable) - break; - vga.crtc.horz_blank_end &= ~0x20; - vga.crtc.horz_blank_end |= ((data & 0x80) >> 2); - vga.crtc.horz_retrace_skew = ((data & 0x60) >> 5); - vga.crtc.horz_retrace_end = data & 0x1f; - break; - case 0x06: - if(vga.crtc.protect_enable) - break; - vga.crtc.vert_total &= ~0xff; - vga.crtc.vert_total |= data & 0xff; - recompute_params(); - break; - case 0x07: // Overflow Register - vga.crtc.line_compare &= ~0x100; - vga.crtc.line_compare |= ((data & 0x10) << (8-4)); - if(vga.crtc.protect_enable) - break; - vga.crtc.vert_total &= ~0x300; - vga.crtc.vert_retrace_start &= ~0x300; - vga.crtc.vert_disp_end &= ~0x300; - vga.crtc.vert_blank_start &= ~0x100; - vga.crtc.vert_retrace_start |= ((data & 0x80) << (9-7)); - vga.crtc.vert_disp_end |= ((data & 0x40) << (9-6)); - vga.crtc.vert_total |= ((data & 0x20) << (9-5)); - vga.crtc.vert_blank_start |= ((data & 0x08) << (8-3)); - vga.crtc.vert_retrace_start |= ((data & 0x04) << (8-2)); - vga.crtc.vert_disp_end |= ((data & 0x02) << (8-1)); - vga.crtc.vert_total |= ((data & 0x01) << (8-0)); - recompute_params(); - break; - case 0x08: // Preset Row Scan Register - vga.crtc.byte_panning = (data & 0x60) >> 5; - vga.crtc.preset_row_scan = (data & 0x1f); - break; - case 0x09: // Maximum Scan Line Register - vga.crtc.line_compare &= ~0x200; - vga.crtc.vert_blank_start &= ~0x200; - vga.crtc.scan_doubling = ((data & 0x80) >> 7); - vga.crtc.line_compare |= ((data & 0x40) << (9-6)); - vga.crtc.vert_blank_start |= ((data & 0x20) << (9-5)); - vga.crtc.maximum_scan_line = (data & 0x1f) + 1; - break; - case 0x0a: - vga.crtc.cursor_enable = ((data & 0x20) ^ 0x20) >> 5; - vga.crtc.cursor_scan_start = data & 0x1f; - break; - case 0x0b: - vga.crtc.cursor_skew = (data & 0x60) >> 5; - vga.crtc.cursor_scan_end = data & 0x1f; - break; - case 0x0c: - case 0x0d: - vga.crtc.start_addr_latch &= ~(0xff << (((index & 1)^1) * 8)); - vga.crtc.start_addr_latch |= (data << (((index & 1)^1) * 8)); - break; - case 0x0e: - case 0x0f: - vga.crtc.cursor_addr &= ~(0xff << (((index & 1)^1) * 8)); - vga.crtc.cursor_addr |= (data << (((index & 1)^1) * 8)); - break; - case 0x10: - vga.crtc.vert_retrace_start &= ~0xff; - vga.crtc.vert_retrace_start |= data & 0xff; - break; - case 0x11: - vga.crtc.protect_enable = (data & 0x80) >> 7; - vga.crtc.bandwidth = (data & 0x40) >> 6; - vga.crtc.vert_retrace_end = data & 0x0f; - vga.crtc.irq_clear = (data & 0x10) >> 4; - vga.crtc.irq_disable = (data & 0x20) >> 5; - break; - case 0x12: - vga.crtc.vert_disp_end &= ~0xff; - vga.crtc.vert_disp_end |= data & 0xff; - recompute_params(); - break; - case 0x13: - vga.crtc.offset &= ~0xff; - vga.crtc.offset |= data & 0xff; - break; - case 0x14: - vga.crtc.dw = (data & 0x40) >> 6; - vga.crtc.div4 = (data & 0x20) >> 5; - vga.crtc.underline_loc = (data & 0x1f); - break; - case 0x15: - vga.crtc.vert_blank_start &= ~0xff; - vga.crtc.vert_blank_start |= data & 0xff; - break; - case 0x16: - vga.crtc.vert_blank_end = data & 0x7f; - break; - case 0x17: - vga.crtc.sync_en = (data & 0x80) >> 7; - vga.crtc.word_mode = (data & 0x40) >> 6; - vga.crtc.aw = (data & 0x20) >> 5; - vga.crtc.div2 = (data & 0x08) >> 3; - vga.crtc.sldiv = (data & 0x04) >> 2; - vga.crtc.map14 = (data & 0x02) >> 1; - vga.crtc.map13 = (data & 0x01) >> 0; - break; - case 0x18: - vga.crtc.line_compare &= ~0xff; - vga.crtc.line_compare |= data & 0xff; - break; - default: - LOG( "Unhandled CRTC reg w %02x %02x\n",index,data); - break; - } -} - -void vga_device::seq_reg_write(uint8_t index, uint8_t data) -{ - switch(index) - { - case 0x02: - vga.sequencer.map_mask = data & 0xf; - break; - case 0x03: - /* --2- 84-- character select A - ---2 --84 character select B */ - vga.sequencer.char_sel.A = (((data & 0xc) >> 2)<<1) | ((data & 0x20) >> 5); - vga.sequencer.char_sel.B = (((data & 0x3) >> 0)<<1) | ((data & 0x10) >> 4); - if(data) - popmessage("Char SEL checker, contact MAMEdev (%02x %02x)\n",vga.sequencer.char_sel.A,vga.sequencer.char_sel.B); - break; - } -} - uint8_t vga_device::vga_vblank() { uint8_t res; @@ -1293,148 +1602,6 @@ uint8_t vga_device::vga_vblank() return res; } -uint8_t vga_device::vga_crtc_r(offs_t offset) -{ - uint8_t data = 0xff; - - switch (offset) { - case 4: - data = vga.crtc.index; - break; - case 5: - data = crtc_reg_read(vga.crtc.index); - break; - case 0xa: - uint8_t hsync,vsync; - vga.attribute.state = 0; - data = 0; - - hsync = screen().hblank() & 1; - vsync = vga_vblank(); //screen().vblank() & 1; - - data |= (hsync | vsync) & 1; // DD - display disable register - data |= (vsync & 1) << 3; // VRetrace register - - /* ega diagnostic readback enough for oak bios */ - switch (vga.attribute.data[0x12]&0x30) { - case 0: - if (vga.attribute.data[0x11]&1) data|=0x10; - if (vga.attribute.data[0x11]&4) data|=0x20; - break; - case 0x10: - data|=(vga.attribute.data[0x11]&0x30); - break; - case 0x20: - if (vga.attribute.data[0x11]&2) data|=0x10; - if (vga.attribute.data[0x11]&8) data|=0x20; - break; - case 0x30: - data|=(vga.attribute.data[0x11]&0xc0)>>2; - break; - } - break; - case 0xf: - /* oak test */ - //data=0; - /* pega bios on/off */ - data=0x80; - break; - } - return data; -} - -void vga_device::vga_crtc_w(offs_t offset, uint8_t data) -{ - switch (offset) - { - case 4: - vga.crtc.index = data; - break; - - case 5: - LOGREGS("vga_crtc_w(): CRTC[0x%02X%s] = 0x%02X\n", - vga.crtc.index, - (vga.crtc.index < vga.svga_intf.crtc_regcount) ? "" : "?", - data); - - crtc_reg_write(vga.crtc.index,data); - //screen().update_partial(screen().vpos()); - #if 0 - if((vga.crtc.index & 0xfe) != 0x0e) - printf("%02x %02x %d\n",vga.crtc.index,data,screen().vpos()); - #endif - break; - - case 0xa: - vga.feature_control = data; - break; - } -} - - - -uint8_t vga_device::port_03b0_r(offs_t offset) -{ - uint8_t data = 0xff; - if (get_crtc_port() == 0x3b0) - data = vga_crtc_r(offset); - return data; -} - -uint8_t vga_device::gc_reg_read(uint8_t index) -{ - uint8_t res; - - switch(index) - { - case 0x00: - res = vga.gc.set_reset & 0xf; - break; - case 0x01: - res = vga.gc.enable_set_reset & 0xf; - break; - case 0x02: - res = vga.gc.color_compare & 0xf; - break; - case 0x03: - res = (vga.gc.logical_op & 3) << 3; - res |= (vga.gc.rotate_count & 7); - break; - case 0x04: - res = vga.gc.read_map_sel & 3; - break; - case 0x05: - res = (vga.gc.shift256 & 1) << 6; - res |= (vga.gc.shift_reg & 1) << 5; - res |= (vga.gc.host_oe & 1) << 4; - res |= (vga.gc.read_mode & 1) << 3; - res |= (vga.gc.write_mode & 3); - break; - case 0x06: - res = (vga.gc.memory_map_sel & 3) << 2; - res |= (vga.gc.chain_oe & 1) << 1; - res |= (vga.gc.alpha_dis & 1); - break; - case 0x07: - res = vga.gc.color_dont_care & 0xf; - break; - case 0x08: - res = vga.gc.bit_mask & 0xff; - break; - default: - res = 0xff; - break; - } - - return res; -} - -uint8_t vga_device::seq_reg_read(uint8_t index) -{ - LOG( "Reading unmapped sequencer read register %02x (SVGA?)\n", index); - return 0; -} - /* 4 additional dipswitches seems to have emulation modes at register level @@ -1469,424 +1636,461 @@ static INPUT_PORTS_START(vga_sense) PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) INPUT_PORTS_END -ioport_constructor vga_device::device_input_ports() const -{ - return INPUT_PORTS_NAME(vga_sense); +ioport_constructor vga_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(vga_sense); +} + +// TODO: convert to mapped space +uint8_t vga_device::mem_r(offs_t offset) +{ + switch(vga.gc.memory_map_sel & 0x03) + { + case 0: break; + case 1: offset &= 0x0ffff; break; + case 2: offset -= 0x10000; offset &= 0x07fff; break; + case 3: offset -= 0x18000; offset &= 0x07fff; break; + } + + if(vga.sequencer.data[4] & 4) + { + int data; + if (!machine().side_effects_disabled()) + { + vga.gc.latch[0]=vga.memory[(offset)]; + vga.gc.latch[1]=vga.memory[(offset)+0x10000]; + vga.gc.latch[2]=vga.memory[(offset)+0x20000]; + vga.gc.latch[3]=vga.memory[(offset)+0x30000]; + } + + if (vga.gc.read_mode) + { + // In Read Mode 1 latch is checked against this + // cfr. lombrall & intsocch where they RMW sprite-like objects + // and anything outside this formula goes transparent. + const u8 target_color = (vga.gc.color_compare & vga.gc.color_dont_care); + data = 0; + + for(u8 byte = 0; byte < 8; byte++) + { + u8 fill_latch = 0; + for(u8 layer = 0; layer < 4; layer++) + { + if(vga.gc.latch[layer] & 1 << byte) + fill_latch |= 1 << layer; + } + fill_latch &= vga.gc.color_dont_care; + if(fill_latch == target_color) + data |= 1 << byte; + } + } + else + data=vga.gc.latch[vga.gc.read_map_sel]; + + return data; + } + else + { + uint8_t i,data; + + data = 0; + //printf("%08x\n",offset); + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + data |= vga.memory[offset+i*0x10000]; + } + + return data; + } + + // never executed + //return 0; } -uint8_t vga_device::port_03c0_r(offs_t offset) +void vga_device::mem_w(offs_t offset, uint8_t data) { - uint8_t data = 0xff; - - switch (offset) + //Inside each case must prevent writes to non-mapped VGA memory regions, not only mask the offset. + switch(vga.gc.memory_map_sel & 0x03) { - case 0: - data = vga.attribute.index; - break; + case 0: break; case 1: - if((vga.attribute.index&0x20) - && ((vga.attribute.index&0x1f)<0x10)) - data = 0; // palette access is disabled in this mode - else if ((vga.attribute.index&0x1f)> 2)) & 3; - LOGDSW("Reading sense bit %d\n", sense_bit); - if(BIT(m_input_sense->read(), sense_bit)) - data |= 0x10; + offset &= 0x0ffff; break; - } + case 2: + if((offset & 0x18000) != 0x10000) + return; - case 3: - data = vga.oak.reg; + offset &= 0x07fff; break; + case 3: + if((offset & 0x18000) != 0x18000) + return; - case 4: - data = vga.sequencer.index; + offset &= 0x07fff; break; + } - case 5: - if (vga.sequencer.index < vga.svga_intf.seq_regcount) - data = vga.sequencer.data[vga.sequencer.index]; - else - data = seq_reg_read(vga.sequencer.index); - break; + { + uint8_t i; - case 6: - data = vga.dac.mask; - break; + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + vga.memory[offset+i*0x10000] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data; + } + return; + } +} - case 7: - data = (vga.dac.read) ? 3 : 0; - break; +// TODO: is there any non-SVGA capable board capable of linear access? +uint8_t vga_device::mem_linear_r(offs_t offset) +{ + return vga.memory[offset % vga.svga_intf.vram_size]; +} - case 8: - data = vga.dac.write_index; - break; +void vga_device::mem_linear_w(offs_t offset, uint8_t data) +{ + vga.memory[offset % vga.svga_intf.vram_size] = data; +} - case 9: - if (vga.dac.read) - { - switch (vga.dac.state++) - { - case 0: - data = vga.dac.color[3*vga.dac.read_index]; - break; - case 1: - data = vga.dac.color[3*vga.dac.read_index + 1]; - break; - case 2: - data = vga.dac.color[3*vga.dac.read_index + 2]; - break; - } +/* VBLANK callback, start address definitely updates AT vblank, not before. */ +TIMER_CALLBACK_MEMBER(vga_device::vblank_timer_cb) +{ + vga.crtc.start_addr = vga.crtc.start_addr_latch; + vga.attribute.pel_shift = vga.attribute.pel_shift_latch; + m_vblank_timer->adjust( screen().time_until_pos(vga.crtc.vert_blank_start + vga.crtc.vert_blank_end) ); +} - if (vga.dac.state==3) - { - vga.dac.state = 0; - vga.dac.read_index++; - } - } - break; +/************************************** + * + * SVGA overrides + * + *************************************/ - case 0xa: - data = vga.feature_control; - break; +svga_device::svga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : vga_device(mconfig, type, tag, owner, clock) +{ +} - case 0xc: - data = vga.miscellaneous_output; - break; +void svga_device::zero() +{ + vga_device::zero(); + memset(&svga, 0, sizeof(svga)); +} - case 0xe: - data = vga.gc.index; - break; +void svga_device::device_start() +{ + vga_device::device_start(); + memset(&svga, 0, sizeof(svga)); - case 0xf: - data = gc_reg_read(vga.gc.index); - break; - } - return data; + save_item(NAME(svga.bank_r)); + save_item(NAME(svga.bank_w)); + save_item(NAME(svga.rgb8_en)); + save_item(NAME(svga.rgb15_en)); + save_item(NAME(svga.rgb16_en)); + save_item(NAME(svga.rgb24_en)); + save_item(NAME(svga.rgb32_en)); + save_item(NAME(svga.id)); } -uint8_t vga_device::port_03d0_r(offs_t offset) +void svga_device::svga_vh_rgb8(bitmap_rgb32 &bitmap, const rectangle &cliprect) { - uint8_t data = 0xff; - if (get_crtc_port() == 0x3d0) - data = vga_crtc_r(offset); - if(offset == 8) + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + + /* line compare is screen sensitive */ + uint16_t mask_comp = 0x3ff; + int curr_addr = 0; +// uint16_t line_length; +// if(vga.crtc.dw) +// line_length = vga.crtc.offset << 3; // doubleword mode +// else +// { +// line_length = vga.crtc.offset << 4; +// } + + uint8_t start_shift = (!(vga.sequencer.data[4] & 0x08) || svga.ignore_chain4) ? 2 : 0; + for (int addr = VGA_START_ADDRESS << start_shift, line=0; line= vga.svga_intf.vram_size) + return; - return data; + for (int xi=0;xi<8;xi++) + { + if(!screen().visible_area().contains(c+xi, line + yi)) + continue; + bitmapline[c+xi] = pen(vga.memory[(pos+(xi))]); + } + } + } + } } -void vga_device::port_03b0_w(offs_t offset, uint8_t data) +void svga_device::svga_vh_rgb15(bitmap_rgb32 &bitmap, const rectangle &cliprect) { - if (get_crtc_port() == 0x3b0) - vga_crtc_w(offset, data); -} + #define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8)) + constexpr uint32_t IV = 0xff000000; + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); -void vga_device::attribute_reg_write(uint8_t index, uint8_t data) -{ - if((index & 0x30) == 0) - { - //if(vga.sequencer.data[1]&0x20) // ok? - vga.attribute.data[index & 0x1f] = data & 0x3f; - } - else + /* line compare is screen sensitive */ +// uint16_t mask_comp = 0xff | (TLINES & 0x300); + int curr_addr = 0; + int yi=0; + for (int addr = TGA_START_ADDRESS, line=0; line= vga.svga_intf.vram_size) + return; + for(int xi=0,xm=0;xi<8;xi++,xm+=2) + { + if(!screen().visible_area().contains(c+xi, line + yi)) + continue; + + int r = (MV(pos+xm)&0x7c00)>>10; + int g = (MV(pos+xm)&0x03e0)>>5; + int b = (MV(pos+xm)&0x001f)>>0; + r = (r << 3) | (r & 0x7); + g = (g << 3) | (g & 0x7); + b = (b << 3) | (b & 0x7); + bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0); + } } } } -void vga_device::gc_reg_write(uint8_t index,uint8_t data) +void svga_device::svga_vh_rgb16(bitmap_rgb32 &bitmap, const rectangle &cliprect) { - switch(index) + #define MV(x) (vga.memory[x]+(vga.memory[x+1]<<8)) + constexpr uint32_t IV = 0xff000000; + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); + + /* line compare is screen sensitive */ +// uint16_t mask_comp = 0xff | (TLINES & 0x300); + int curr_addr = 0; + int yi=0; + for (int addr = TGA_START_ADDRESS, line=0; line> 3; - vga.gc.rotate_count = data & 7; - break; - case 0x04: - vga.gc.read_map_sel = data & 3; - break; - case 0x05: - vga.gc.shift256 = (data & 0x40) >> 6; - vga.gc.shift_reg = (data & 0x20) >> 5; - vga.gc.host_oe = (data & 0x10) >> 4; - vga.gc.read_mode = (data & 8) >> 3; - vga.gc.write_mode = data & 3; - //if(data & 0x10 && vga.gc.alpha_dis) - // popmessage("Host O/E enabled, contact MAMEdev"); - break; - case 0x06: - vga.gc.memory_map_sel = (data & 0xc) >> 2; - vga.gc.chain_oe = (data & 2) >> 1; - vga.gc.alpha_dis = (data & 1); - //if(data & 2 && vga.gc.alpha_dis) - // popmessage("Chain O/E enabled, contact MAMEdev"); - break; - case 0x07: - vga.gc.color_dont_care = data & 0xf; - break; - case 0x08: - vga.gc.bit_mask = data & 0xff; - break; + uint32_t *const bitmapline = &bitmap.pix(line); + addr %= vga.svga_intf.vram_size; + for (int pos=addr, c=0, column=0; column= vga.svga_intf.vram_size) + return; + for (int xi=0,xm=0;xi<8;xi++,xm+=2) + { + if(!screen().visible_area().contains(c+xi, line + yi)) + continue; + + int r = (MV(pos+xm)&0xf800)>>11; + int g = (MV(pos+xm)&0x07e0)>>5; + int b = (MV(pos+xm)&0x001f)>>0; + r = (r << 3) | (r & 0x7); + g = (g << 2) | (g & 0x3); + b = (b << 3) | (b & 0x7); + bitmapline[c+xi] = IV|(r<<16)|(g<<8)|(b<<0); + } + } } } -void vga_device::port_03c0_w(offs_t offset, uint8_t data) +void svga_device::svga_vh_rgb24(bitmap_rgb32 &bitmap, const rectangle &cliprect) { - switch (offset) { - case 0: - if (vga.attribute.state==0) - { - vga.attribute.index=data; - } - else - { - attribute_reg_write(vga.attribute.index,data); - } - vga.attribute.state=!vga.attribute.state; - break; - case 2: - vga.miscellaneous_output=data; - recompute_params(); - break; - case 3: - vga.oak.reg = data; - break; - case 4: - vga.sequencer.index = data; - break; - case 5: - LOGREGS("vga_port_03c0_w(): SEQ[0x%02X%s] = 0x%02X\n", - vga.sequencer.index, - (vga.sequencer.index < vga.svga_intf.seq_regcount) ? "" : "?", - data); - if (vga.sequencer.index < vga.svga_intf.seq_regcount) - { - vga.sequencer.data[vga.sequencer.index] = data; - } + #define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16)) + constexpr uint32_t ID = 0xff000000; + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); - seq_reg_write(vga.sequencer.index,data); - recompute_params(); - break; - case 6: - vga.dac.mask=data; - vga.dac.dirty=1; - break; - case 7: - vga.dac.read_index=data; - vga.dac.state=0; - vga.dac.read=1; - break; - case 8: - vga.dac.write_index=data; - vga.dac.state=0; - vga.dac.read=0; - break; - case 9: - if (!vga.dac.read) - { - switch (vga.dac.state++) { - case 0: - vga.dac.color[3*vga.dac.write_index]=data; - break; - case 1: - vga.dac.color[3*vga.dac.write_index + 1]=data; - break; - case 2: - vga.dac.color[3*vga.dac.write_index + 2]=data; - break; - } - vga.dac.dirty=1; - if (vga.dac.state==3) { - vga.dac.state=0; vga.dac.write_index++; + /* line compare is screen sensitive */ +// uint16_t mask_comp = 0xff | (TLINES & 0x300); + int curr_addr = 0; + int yi=0; + for (int addr = TGA_START_ADDRESS<<1, line=0; line= vga.svga_intf.vram_size) + return; + for (int xi=0,xm=0;xi<8;xi++,xm+=3) + { + if(!screen().visible_area().contains(c+xi, line + yi)) + continue; + + int r = (MD(pos+xm)&0xff0000)>>16; + int g = (MD(pos+xm)&0x00ff00)>>8; + int b = (MD(pos+xm)&0x0000ff)>>0; + bitmapline[c+xi] = ID|(r<<16)|(g<<8)|(b<<0); } } - break; - case 0xe: - vga.gc.index=data; - break; - case 0xf: - gc_reg_write(vga.gc.index,data); - break; } } - - -void vga_device::port_03d0_w(offs_t offset, uint8_t data) +void svga_device::svga_vh_rgb32(bitmap_rgb32 &bitmap, const rectangle &cliprect) { - if (get_crtc_port() == 0x3d0) - vga_crtc_w(offset, data); -} + #define MD(x) (vga.memory[x]+(vga.memory[x+1]<<8)+(vga.memory[x+2]<<16)) + constexpr uint32_t ID = 0xff000000; + int height = vga.crtc.maximum_scan_line * (vga.crtc.scan_doubling + 1); -void vga_device::device_reset() -{ - /* clear out the VGA structure */ - memset(vga.pens, 0, sizeof(vga.pens)); - vga.miscellaneous_output = 0; - vga.feature_control = 0; - vga.sequencer.index = 0; - memset(vga.sequencer.data, 0, sizeof(vga.sequencer.data)); - vga.crtc.index = 0; - memset(vga.crtc.data, 0, sizeof(vga.crtc.data)); - vga.gc.index = 0; - memset(vga.gc.latch, 0, sizeof(vga.gc.latch)); - memset(&vga.attribute, 0, sizeof(vga.attribute)); - memset(&vga.dac, 0, sizeof(vga.dac)); - memset(&vga.cursor, 0, sizeof(vga.cursor)); - memset(&vga.oak, 0, sizeof(vga.oak)); +// uint16_t mask_comp; - vga.gc.memory_map_sel = 0x3; /* prevent xtbios excepting vga ram as system ram */ -/* amstrad pc1640 bios relies on the position of - the video memory area, - so I introduced the reset to switch to b8000 area */ - vga.sequencer.data[4] = 0; + /* line compare is screen sensitive */ +// mask_comp = 0xff | (TLINES & 0x300); + int curr_addr = 0; + int yi=0; + for (int addr = TGA_START_ADDRESS, line=0; line= vga.svga_intf.vram_size) + return; + for (int xi=0,xm=0;xi<8;xi++,xm+=4) + { + if(!screen().visible_area().contains(c+xi, line + yi)) + continue; - /* TODO: real defaults */ - vga.crtc.line_compare = 0x3ff; - /* skeleton/indiana.cpp boot PROM doesn't set this and assumes it's 0xff */ - vga.dac.mask = 0xff; + int r = (MD(pos+xm)&0xff0000)>>16; + int g = (MD(pos+xm)&0x00ff00)>>8; + int b = (MD(pos+xm)&0x0000ff)>>0; + bitmapline[c+xi] = ID|(r<<16)|(g<<8)|(b<<0); + } + } + } } -uint8_t vga_device::mem_r(offs_t offset) +// TODO: inherit from base class +uint8_t svga_device::pc_vga_choosevideomode() { - /* TODO: check me */ - switch(vga.gc.memory_map_sel & 0x03) - { - case 0: break; - case 1: offset &= 0x0ffff; break; - case 2: offset -= 0x10000; offset &= 0x07fff; break; - case 3: offset -= 0x18000; offset &= 0x07fff; break; - } - - if(vga.sequencer.data[4] & 4) + if (vga.crtc.sync_en) { - int data; - if (!machine().side_effects_disabled()) + if (vga.dac.dirty) { - vga.gc.latch[0]=vga.memory[(offset)]; - vga.gc.latch[1]=vga.memory[(offset)+0x10000]; - vga.gc.latch[2]=vga.memory[(offset)+0x20000]; - vga.gc.latch[3]=vga.memory[(offset)+0x30000]; + for (int i=0; i<256;i++) + { + /* TODO: color shifters? */ + set_pen_color(i, (vga.dac.color[3*(i & vga.dac.mask)] & 0x3f) << 2, + (vga.dac.color[3*(i & vga.dac.mask) + 1] & 0x3f) << 2, + (vga.dac.color[3*(i & vga.dac.mask) + 2] & 0x3f) << 2); + } + vga.dac.dirty = 0; } - if (vga.gc.read_mode) + if (vga.attribute.data[0x10] & 0x80) { - // In Read Mode 1 latch is checked against this - // cfr. lombrall & intsocch where they RMW sprite-like objects - // and anything outside this formula goes transparent. - const u8 target_color = (vga.gc.color_compare & vga.gc.color_dont_care); - data = 0; - - for(u8 byte = 0; byte < 8; byte++) + for (int i=0; i<16;i++) { - u8 fill_latch = 0; - for(u8 layer = 0; layer < 4; layer++) - { - if(vga.gc.latch[layer] & 1 << byte) - fill_latch |= 1 << layer; - } - fill_latch &= vga.gc.color_dont_care; - if(fill_latch == target_color) - data |= 1 << byte; + vga.pens[i] = pen((vga.attribute.data[i]&0x0f) + |((vga.attribute.data[0x14]&0xf)<<4)); } } else - data=vga.gc.latch[vga.gc.read_map_sel]; - - return data; - } - else - { - // TODO: Guesswork, probably not right - uint8_t i,data; - - data = 0; - //printf("%08x\n",offset); - - for(i=0;i<4;i++) { - if(vga.sequencer.map_mask & 1 << i) - data |= vga.memory[offset+i*0x10000]; + for (int i=0; i<16;i++) + { + vga.pens[i] = pen((vga.attribute.data[i]&0x3f) + |((vga.attribute.data[0x14]&0xc)<<4)); + } } - return data; + if (svga.rgb32_en) + { + return RGB32_MODE; + } + else if (svga.rgb24_en) + { + return RGB24_MODE; + } + else if (svga.rgb16_en) + { + return RGB16_MODE; + } + else if (svga.rgb15_en) + { + return RGB15_MODE; + } + else if (svga.rgb8_en) + { + return RGB8_MODE; + } + else if (!GRAPHIC_MODE) + { + return TEXT_MODE; + } + else if (vga.gc.shift256) + { + return VGA_MODE; + } + else if (vga.gc.shift_reg) + { + return CGA_MODE; + } + else if (vga.gc.memory_map_sel == 0x03) + { + return MONO_MODE; + } + else + { + return EGA_MODE; + } } - // never executed - //return 0; + return SCREEN_OFF; } -void vga_device::mem_w(offs_t offset, uint8_t data) +uint8_t svga_device::get_video_depth() { - //Inside each case must prevent writes to non-mapped VGA memory regions, not only mask the offset. - switch(vga.gc.memory_map_sel & 0x03) - { - case 0: break; - case 1: - if(offset & 0x10000) - return; - - offset &= 0x0ffff; - break; - case 2: - if((offset & 0x18000) != 0x10000) - return; - - offset &= 0x07fff; - break; - case 3: - if((offset & 0x18000) != 0x18000) - return; - - offset &= 0x07fff; - break; - } - + switch(pc_vga_choosevideomode()) { - uint8_t i; - - for(i=0;i<4;i++) - { - if(vga.sequencer.map_mask & 1 << i) - vga.memory[offset+i*0x10000] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data; - } - return; + case VGA_MODE: + case RGB8_MODE: + return 8; + case RGB15_MODE: + case RGB16_MODE: + return 16; + case RGB24_MODE: + case RGB32_MODE: + return 32; } + return 0; } -uint8_t vga_device::mem_linear_r(offs_t offset) +// TODO: inherit from base class +uint32_t svga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { - return vga.memory[offset % vga.svga_intf.vram_size]; -} + uint8_t cur_mode = pc_vga_choosevideomode(); -void vga_device::mem_linear_w(offs_t offset, uint8_t data) -{ - vga.memory[offset % vga.svga_intf.vram_size] = data; + switch(cur_mode) + { + case SCREEN_OFF: bitmap.fill (black_pen(), cliprect);break; + case TEXT_MODE: vga_vh_text (bitmap, cliprect); break; + case VGA_MODE: vga_vh_vga (bitmap, cliprect); break; + case EGA_MODE: vga_vh_ega (bitmap, cliprect); break; + case CGA_MODE: vga_vh_cga (bitmap, cliprect); break; + case MONO_MODE: vga_vh_mono (bitmap, cliprect); break; + case RGB8_MODE: svga_vh_rgb8 (bitmap, cliprect); break; + case RGB15_MODE: svga_vh_rgb15(bitmap, cliprect); break; + case RGB16_MODE: svga_vh_rgb16(bitmap, cliprect); break; + case RGB24_MODE: svga_vh_rgb24(bitmap, cliprect); break; + case RGB32_MODE: svga_vh_rgb32(bitmap, cliprect); break; + } + + return 0; } diff --git a/src/devices/video/pc_vga.h b/src/devices/video/pc_vga.h index 54f2ef168ae..64715853808 100644 --- a/src/devices/video/pc_vga.h +++ b/src/devices/video/pc_vga.h @@ -20,7 +20,10 @@ // ======================> vga_device -class vga_device : public device_t, public device_video_interface, public device_palette_interface +class vga_device : public device_t + , public device_video_interface + , public device_palette_interface + , public device_memory_interface { friend class ibm8514a_device; @@ -31,12 +34,8 @@ public: virtual void zero(); virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); - virtual uint8_t port_03b0_r(offs_t offset); - virtual void port_03b0_w(offs_t offset, uint8_t data); - virtual uint8_t port_03c0_r(offs_t offset); - virtual void port_03c0_w(offs_t offset, uint8_t data); - virtual uint8_t port_03d0_r(offs_t offset); - virtual void port_03d0_w(offs_t offset, uint8_t data); + void io_map(address_map &map); + virtual uint8_t mem_r(offs_t offset); virtual void mem_w(offs_t offset, uint8_t data); virtual uint8_t mem_linear_r(offs_t offset); @@ -81,17 +80,51 @@ protected: void vga_vh_mono(bitmap_rgb32 &bitmap, const rectangle &cliprect); virtual uint8_t pc_vga_choosevideomode(); void recompute_params_clock(int divisor, int xtal); - virtual uint8_t crtc_reg_read(uint8_t index); virtual void recompute_params(); - virtual void crtc_reg_write(uint8_t index, uint8_t data); - virtual uint8_t seq_reg_read(uint8_t index); - virtual void seq_reg_write(uint8_t index, uint8_t data); uint8_t vga_vblank(); - uint8_t vga_crtc_r(offs_t offset); - void vga_crtc_w(offs_t offset, uint8_t data); - uint8_t gc_reg_read(uint8_t index); - void attribute_reg_write(uint8_t index, uint8_t data); - void gc_reg_write(uint8_t index,uint8_t data); + + virtual space_config_vector memory_space_config() const override; + + virtual void io_3bx_3dx_map(address_map &map); + + u8 crtc_address_r(offs_t offset); + void crtc_address_w(offs_t offset, u8 data); + virtual u8 crtc_data_r(offs_t offset); + virtual void crtc_data_w(offs_t offset, u8 data); + u8 input_status_1_r(offs_t offset); + void feature_control_w(offs_t offset, u8 data); + + virtual void io_3cx_map(address_map &map); + + u8 atc_address_r(offs_t offset); + void atc_address_data_w(offs_t offset, u8 data); + u8 atc_data_r(offs_t offset); + u8 input_status_0_r(offs_t offset); + void miscellaneous_output_w(offs_t offset, u8 data); + u8 sequencer_address_r(offs_t offset); + void sequencer_address_w(offs_t offset, u8 data); + virtual u8 sequencer_data_r(offs_t offset); + virtual void sequencer_data_w(offs_t offset, u8 data); + u8 ramdac_mask_r(offs_t offset); + void ramdac_mask_w(offs_t offset, u8 data); + u8 ramdac_state_r(offs_t offset); + void ramdac_read_index_w(offs_t offset, u8 data); + u8 ramdac_write_index_r(offs_t offset); + void ramdac_write_index_w(offs_t offset, u8 data); + u8 ramdac_data_r(offs_t offset); + void ramdac_data_w(offs_t offset, u8 data); + u8 feature_control_r(offs_t offset); + u8 miscellaneous_output_r(offs_t offset); + virtual u8 gc_address_r(offs_t offset); + virtual void gc_address_w(offs_t offset, u8 data); + virtual u8 gc_data_r(offs_t offset); + virtual void gc_data_w(offs_t offset, u8 data); + + virtual void crtc_map(address_map &map); + virtual void sequencer_map(address_map &map); + virtual void gc_map(address_map &map); + virtual void attribute_map(address_map &map); + virtual uint16_t offset(); virtual uint32_t start_addr(); virtual uint8_t vga_latch_write(int offs, uint8_t data); @@ -125,8 +158,6 @@ protected: struct { size_t vram_size; - int seq_regcount; - int crtc_regcount; } svga_intf; std::unique_ptr memory; @@ -245,6 +276,23 @@ protected: required_ioport m_input_sense; emu_timer *m_vblank_timer; + + enum { + MAIN_IF_REG = 0, + CRTC_REG, + GC_REG, + SEQ_REG, + ATC_REG + }; + + address_space_config m_main_if_space_config; + address_space_config m_crtc_space_config; + address_space_config m_gc_space_config; + address_space_config m_seq_space_config; + address_space_config m_atc_space_config; + +private: + bool m_ioas = false; }; @@ -273,7 +321,7 @@ protected: virtual void device_start() override; struct { - uint8_t bank_r,bank_w; + uint8_t bank_r, bank_w; uint8_t rgb8_en; uint8_t rgb15_en; uint8_t rgb16_en; diff --git a/src/devices/video/pc_vga_ati.cpp b/src/devices/video/pc_vga_ati.cpp index b50d7b562ff..171ab494a37 100644 --- a/src/devices/video/pc_vga_ati.cpp +++ b/src/devices/video/pc_vga_ati.cpp @@ -43,23 +43,6 @@ void ati_vga_device::device_add_mconfig(machine_config &config) EEPROM_93C46_16BIT(config, "ati_eeprom"); } -uint8_t ati_vga_device::port_03c0_r(offs_t offset) -{ - uint8_t data = 0xff; - - switch(offset) - { - case 1: - if ((vga.attribute.index&0x1f) < sizeof(vga.attribute.data)) - data = vga.attribute.data[vga.attribute.index&0x1f]; - break; - default: - data = vga_device::port_03c0_r(offset); - break; - } - return data; -} - uint16_t ati_vga_device::offset() { //popmessage("Offset: %04x %s %s %s %s",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD",(ati.ext_reg[0x33] & 0x40) ? "PEL" : "---",(ati.ext_reg[0x30] & 0x20) ? "256" : "---"); diff --git a/src/devices/video/pc_vga_ati.h b/src/devices/video/pc_vga_ati.h index 70c83f50e11..beeae3c3053 100644 --- a/src/devices/video/pc_vga_ati.h +++ b/src/devices/video/pc_vga_ati.h @@ -23,7 +23,6 @@ public: virtual void mem_w(offs_t offset, uint8_t data) override; // VGA registers - virtual uint8_t port_03c0_r(offs_t offset) override; uint8_t ati_port_ext_r(offs_t offset); void ati_port_ext_w(offs_t offset, uint8_t data); diff --git a/src/devices/video/pc_vga_cirrus.cpp b/src/devices/video/pc_vga_cirrus.cpp new file mode 100644 index 00000000000..d1a0df36379 --- /dev/null +++ b/src/devices/video/pc_vga_cirrus.cpp @@ -0,0 +1,1485 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * + * Cirrus Logic CL-GD542x/3x video chipsets + * + * TODO: + * - Original Acumos AVGA1/2 chipsets (Cirrus Logic eventually bought Acumos and rebranded); + * - Fix or implement hidden DAC modes (15bpp + mixed, true color, others); + * - bebox: logo at startup is squashed; + * - Merge with trs/vis.cpp implementation (CL-GD5200 RAMDAC with custom VGA controller) + * + */ + +#include "emu.h" +#include "pc_vga_cirrus.h" + +#include "screen.h" + + +#define LOG_REG (1U << 1) +#define LOG_BLIT (1U << 2) +#define LOG_HDAC (1U << 3) // log hidden DAC + +#define VERBOSE (LOG_GENERAL | LOG_HDAC) +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + +// TODO: remove these macros +//#define TEXT_LINES (LINES_HELPER) +#define LINES (vga.crtc.vert_disp_end+1) +#define TEXT_LINES (vga.crtc.vert_disp_end+1) + +#define GRAPHIC_MODE (vga.gc.alpha_dis) /* else text mode */ + +#define EGA_COLUMNS (vga.crtc.horz_disp_end+1) +#define EGA_START_ADDRESS (vga.crtc.start_addr) +#define EGA_LINE_LENGTH (vga.crtc.offset<<1) + +#define VGA_COLUMNS (vga.crtc.horz_disp_end+1) +#define VGA_START_ADDRESS (vga.crtc.start_addr) +#define VGA_LINE_LENGTH (vga.crtc.offset<<3) + +#define IBM8514_LINE_LENGTH (m_vga->offset()) + +#define VGA_CH_WIDTH ((vga.sequencer.data[1]&1)?8:9) + +#define TEXT_COLUMNS (vga.crtc.horz_disp_end+1) +#define TEXT_START_ADDRESS (vga.crtc.start_addr<<3) +#define TEXT_LINE_LENGTH (vga.crtc.offset<<1) + +#define TEXT_COPY_9COLUMN(ch) (((ch & 0xe0) == 0xc0)&&(vga.attribute.data[0x10]&4)) + +DEFINE_DEVICE_TYPE(CIRRUS_GD5428, cirrus_gd5428_device, "clgd5428", "Cirrus Logic GD5428") +DEFINE_DEVICE_TYPE(CIRRUS_GD5430, cirrus_gd5430_device, "clgd5430", "Cirrus Logic GD5430") +DEFINE_DEVICE_TYPE(CIRRUS_GD5446, cirrus_gd5446_device, "clgd5446", "Cirrus Logic GD5446") + + +cirrus_gd5428_device::cirrus_gd5428_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : cirrus_gd5428_device(mconfig, CIRRUS_GD5428, tag, owner, clock) +{ + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(cirrus_gd5428_device::crtc_map), this)); + m_gc_space_config = address_space_config("gc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(cirrus_gd5428_device::gc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(cirrus_gd5428_device::sequencer_map), this)); +} + +cirrus_gd5428_device::cirrus_gd5428_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : svga_device(mconfig, type, tag, owner, clock) +{ +} + +cirrus_gd5430_device::cirrus_gd5430_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : cirrus_gd5428_device(mconfig, CIRRUS_GD5430, tag, owner, clock) +{ + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(cirrus_gd5430_device::crtc_map), this)); + m_gc_space_config = address_space_config("gc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(cirrus_gd5430_device::gc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(cirrus_gd5430_device::sequencer_map), this)); +} + +cirrus_gd5446_device::cirrus_gd5446_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : cirrus_gd5428_device(mconfig, CIRRUS_GD5446, tag, owner, clock) +{ + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(cirrus_gd5446_device::crtc_map), this)); + m_gc_space_config = address_space_config("gc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(cirrus_gd5446_device::gc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(cirrus_gd5446_device::sequencer_map), this)); +} + +void cirrus_gd5428_device::io_3cx_map(address_map &map) +{ + svga_device::io_3cx_map(map); + map(0x06, 0x06).rw(FUNC(cirrus_gd5428_device::ramdac_hidden_mask_r), FUNC(cirrus_gd5428_device::ramdac_hidden_mask_w)); + map(0x09, 0x09).rw(FUNC(cirrus_gd5428_device::ramdac_overlay_r), FUNC(cirrus_gd5428_device::ramdac_overlay_w)); +} + +u8 cirrus_gd5428_device::ramdac_hidden_mask_r(offs_t offset) +{ + if (!machine().side_effects_disabled()) + m_hidden_dac_phase ++; + if (m_hidden_dac_phase >= 4) + { + u8 res; + // TODO: '5420 doesn't have this + // TODO: '5428 reads do not lock the Hidden DAC + res = m_hidden_dac_mode; + //m_hidden_dac_phase = 0; + LOGMASKED(LOG_HDAC, "CL: Hidden DAC read (%02x)\n", res); + return res; + } + + return vga_device::ramdac_mask_r(0); +} + +void cirrus_gd5428_device::ramdac_hidden_mask_w(offs_t offset, u8 data) +{ + if (m_hidden_dac_phase >= 4) + { + // TODO: '5420 doesn't have this + // TODO: '5428 reads do not lock the Hidden DAC + m_hidden_dac_mode = data; + m_hidden_dac_phase = 0; + LOGMASKED(LOG_HDAC, "CL: Hidden DAC write %02x\n", data); + return; + } + + vga_device::ramdac_mask_w(0, data); +} + +u8 cirrus_gd5428_device::ramdac_overlay_r(offs_t offset) +{ + if(!m_ext_palette_enabled) + return vga_device::ramdac_data_r(0); + + u8 res = 0xff; + if (vga.dac.read && !machine().side_effects_disabled()) + { + switch (vga.dac.state++) + { + case 0: + res = m_ext_palette[vga.dac.read_index & 0x0f].red; + break; + case 1: + res = m_ext_palette[vga.dac.read_index & 0x0f].green; + break; + case 2: + res = m_ext_palette[vga.dac.read_index & 0x0f].blue; + break; + } + + if (vga.dac.state == 3) + { + vga.dac.state = 0; + vga.dac.read_index++; + } + } + + return res; +} + +void cirrus_gd5428_device::ramdac_overlay_w(offs_t offset, u8 data) +{ + if(!m_ext_palette_enabled) + { + vga_device::ramdac_data_w(0, data); + return; + } + + if (!vga.dac.read) + { + switch (vga.dac.state++) { + case 0: + m_ext_palette[vga.dac.write_index & 0x0f].red=data; + break; + case 1: + m_ext_palette[vga.dac.write_index & 0x0f].green=data; + break; + case 2: + m_ext_palette[vga.dac.write_index & 0x0f].blue=data; + break; + } + vga.dac.dirty=1; + if (vga.dac.state==3) + { + vga.dac.state=0; + vga.dac.write_index++; + } + } +} + +void cirrus_gd5428_device::crtc_map(address_map &map) +{ + svga_device::crtc_map(map); + // VGA Vertical Blank end + // some SVGA chipsets use all 8 bits, and this is one of them (according to MFGTST CRTC tests) + map(0x16, 0x16).lrw8( + NAME([this] (offs_t offset) { + return vga.crtc.vert_blank_end & 0x00ff; + }), + NAME([this] (offs_t offset, u8 data) { + vga.crtc.vert_blank_end &= ~0x00ff; + vga.crtc.vert_blank_end |= data; + cirrus_define_video_mode(); + }) + ); + map(0x19, 0x19).lrw8( + NAME([this] (offs_t offset) { + return m_cr19; + }), + NAME([this] (offs_t offset, u8 data) { + m_cr19 = data; + }) + ); + map(0x1a, 0x1a).lrw8( + NAME([this] (offs_t offset) { + return m_cr1a; + }), + NAME([this] (offs_t offset, u8 data) { + m_cr1a = data; + vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xff3f) | ((data & 0x30) << 2); + vga.crtc.vert_blank_end = (vga.crtc.vert_blank_end & 0xfcff) | ((data & 0xc0) << 2); + cirrus_define_video_mode(); + }) + ); + map(0x1b, 0x1b).lrw8( + NAME([this] (offs_t offset) { + return m_cr1b; + }), + NAME([this] (offs_t offset, u8 data) { + m_cr1b = data; + vga.crtc.start_addr_latch &= ~0x070000; + vga.crtc.start_addr_latch |= ((data & 0x01) << 16); + vga.crtc.start_addr_latch |= ((data & 0x0c) << 15); + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x10) << 4); + cirrus_define_video_mode(); + }) + ); + // TODO: CR1D for GD543x + //vga.crtc.start_addr_latch = (vga.crtc.start_addr_latch & 0xf7ffff) | ((data & 0x01) << 16); + map(0x27, 0x27).lr8( + NAME([this] (offs_t offset) { + return m_chip_id; + }) + ); +} + +void cirrus_gd5428_device::gc_map(address_map &map) +{ + svga_device::gc_map(map); + map(0x00, 0x00).lrw8( + NAME([this](offs_t offset) { + return vga.gc.set_reset & ((gc_mode_ext & 0x04) ? 0xff : 0x0f); + }), + NAME([this](offs_t offset, u8 data) { + // if extended writes are enabled (bit 2 of index 0bh), then index 0 and 1 are extended to 8 bits, + // however XFree86 does not appear to do this... + vga.gc.set_reset = data & 0xff; + }) + ); + map(0x01, 0x01).lrw8( + NAME([this](offs_t offset) { + return vga.gc.enable_set_reset & ((gc_mode_ext & 0x04) ? 0xff : 0x0f); + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.enable_set_reset = data & 0xff; + }) + ); + map(0x05, 0x05).lrw8( + NAME([this](offs_t offset) { + u8 res = (vga.gc.shift256 & 1) << 6; + res |= (vga.gc.shift_reg & 1) << 5; + res |= (vga.gc.host_oe & 1) << 4; + res |= (vga.gc.read_mode & 1) << 3; + if(gc_mode_ext & 0x04) + res |= (vga.gc.write_mode & 7); + else + res |= (vga.gc.write_mode & 3); + return res; + }), + NAME([this](offs_t offset, u8 data) { + vga.gc.shift256 = (data & 0x40) >> 6; + vga.gc.shift_reg = (data & 0x20) >> 5; + vga.gc.host_oe = (data & 0x10) >> 4; + vga.gc.read_mode = (data & 8) >> 3; + if(gc_mode_ext & 0x04) + vga.gc.write_mode = data & 7; + else + vga.gc.write_mode = data & 3; + }) + ); + // Offset register 0 + map(0x09, 0x09).lrw8( + NAME([this](offs_t offset) { + return gc_bank_0; + }), + NAME([this](offs_t offset, u8 data) { + gc_bank_0 = data; + LOG("CL: Offset register 0 set to %i\n", data); + }) + ); + // Offset register 1 + map(0x0a, 0x0a).lrw8( + NAME([this](offs_t offset) { + return gc_bank_1; + }), + NAME([this](offs_t offset, u8 data) { + gc_bank_1 = data; + LOG("CL: Offset register 1 set to %i\n", data); + }) + ); + // Graphics controller mode extensions + map(0x0b, 0x0b).lrw8( + NAME([this](offs_t offset) { + return gc_mode_ext; + }), + NAME([this](offs_t offset, u8 data) { + gc_mode_ext = data; + if(!(data & 0x04)) + { + vga.gc.set_reset &= 0x0f; + vga.gc.enable_set_reset &= 0x0f; + } + if(!(data & 0x08)) + vga.sequencer.map_mask &= 0x0f; + }) + ); + // Colour Key + // map(0x0c, 0x0c) + // Colour Key Mask + // map(0x0d, 0x0d) + // Miscellaneous Control + // map(0x0e, 0x0e) + // Background Colour Byte 1 + map(0x10, 0x10).lrw8( + NAME([this](offs_t offset) { + return m_gr10; + }), + NAME([this](offs_t offset, u8 data) { + m_gr10 = data; + }) + ); + // Foreground Colour Byte 1 + map(0x11, 0x11).lrw8( + NAME([this](offs_t offset) { + return m_gr11; + }), + NAME([this](offs_t offset, u8 data) { + m_gr11 = data; + }) + ); + // BLT Width 0 + map(0x20, 0x20).lrw8( + NAME([this](offs_t offset) { + return m_blt_width & 0x00ff; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_width = (m_blt_width & 0xff00) | data; + }) + ); + // BLT Width 1 + map(0x21, 0x21).lrw8( + NAME([this](offs_t offset) { + return m_blt_width >> 8; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_width = (m_blt_width & 0x00ff) | (data << 8); + }) + ); + // BLT Height 0 + map(0x22, 0x22).lrw8( + NAME([this](offs_t offset) { + return m_blt_height & 0x00ff; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_height = (m_blt_height & 0xff00) | data; + }) + ); + // BLT Height 1 + map(0x23, 0x23).lrw8( + NAME([this](offs_t offset) { + return m_blt_height >> 8; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_height = (m_blt_height & 0x00ff) | (data << 8); + }) + ); + // BLT Destination Pitch 0 + map(0x24, 0x24).lrw8( + NAME([this](offs_t offset) { + return m_blt_dest_pitch & 0x00ff; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_dest_pitch = (m_blt_dest_pitch & 0xff00) | data; + }) + ); + // BLT Destination Pitch 1 + map(0x25, 0x25).lrw8( + NAME([this](offs_t offset) { + return m_blt_dest_pitch >> 8; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_dest_pitch = (m_blt_dest_pitch & 0x00ff) | (data << 8); + }) + ); + // BLT Source Pitch 0 + map(0x26, 0x26).lrw8( + NAME([this](offs_t offset) { + return m_blt_source_pitch & 0x00ff; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_source_pitch = (m_blt_source_pitch & 0xff00) | data; + }) + ); + // BLT Source Pitch 1 + map(0x27, 0x27).lrw8( + NAME([this](offs_t offset) { + return m_blt_source_pitch >> 8; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_source_pitch = (m_blt_source_pitch & 0x00ff) | (data << 8); + }) + ); + // BLT Destination start 0/1/2 + map(0x28, 0x2a).lrw8( + NAME([this](offs_t offset) { + return (m_blt_dest >> (8 * (offset & 3))) & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + const u8 byte_access = (8 * (offset & 3)); + const u32 old_mask = ~(0xff << byte_access); + m_blt_dest = (m_blt_dest & old_mask) | (data << byte_access); + }) + ); + // BLT source start 0/1/2 + map(0x2c, 0x2e).lrw8( + NAME([this](offs_t offset) { + return (m_blt_source >> (8 * (offset & 3))) & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + const u8 byte_access = (8 * (offset & 3)); + const u32 old_mask = ~(0xff << byte_access); + m_blt_source = (m_blt_source & old_mask) | (data << byte_access); + }) + ); + // BLT destination write mask (GD5430/36/40 only) + // map(0x2f, 0x2f) + // BLT Mode + map(0x30, 0x30).lrw8( + NAME([this](offs_t offset) { + return m_blt_mode; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_mode = data; + }) + ); + // BitBLT Start / Status + map(0x31, 0x31).lrw8( + NAME([this](offs_t offset) { + return m_blt_status; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_status = data & ~0xf2; + if(data & 0x02) + { + if(m_blt_mode & 0x04) // blit source is system memory + start_system_bitblt(); + else + start_bitblt(); + } + }) + ); + // BitBLT ROP mode + map(0x32, 0x32).lrw8( + NAME([this](offs_t offset) { + return m_blt_rop; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_rop = data; + }) + ); + // BitBLT Transparent Colour 0 + map(0x34, 0x34).lrw8( + NAME([this](offs_t offset) { + return m_blt_trans_colour & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_trans_colour = (m_blt_trans_colour & 0xff00) | data; + }) + ); + // BitBLT Transparent Colour 1 + map(0x35, 0x35).lrw8( + NAME([this](offs_t offset) { + return m_blt_trans_colour >> 8; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_trans_colour = (m_blt_trans_colour & 0x00ff) | (data << 8); + }) + ); + // BitBLT Transparent Colour Mask 0 + map(0x36, 0x36).lrw8( + NAME([this](offs_t offset) { + return m_blt_trans_colour_mask & 0xff; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_trans_colour_mask = (m_blt_trans_colour_mask & 0xff00) | data; + }) + ); + // BitBLT Transparent Colour Mask 1 + map(0x37, 0x37).lrw8( + NAME([this](offs_t offset) { + return m_blt_trans_colour_mask >> 8; + }), + NAME([this](offs_t offset, u8 data) { + m_blt_trans_colour_mask = (m_blt_trans_colour_mask & 0x00ff) | (data << 8); + }) + ); +} + +void cirrus_gd5428_device::sequencer_map(address_map &map) +{ + svga_device::sequencer_map(map); + map(0x02, 0x02).lrw8( + NAME([this] (offs_t offset) { + return vga.sequencer.map_mask & ((gc_mode_ext & 0x08) ? 0xff : 0x0f); + }), + NAME([this] (offs_t offset, u8 data) { + vga.sequencer.map_mask = data & ((gc_mode_ext & 0x08) ? 0xff : 0x0f); + }) + ); + map(0x06, 0x06).lrw8( + NAME([this] (offs_t offset) { + return (gc_locked) ? 0x0f : m_lock_reg; + }), + NAME([this] (offs_t offset, u8 data) { + // TODO: extensions are always enabled on the GD5429 + // bits 3,5,6,7 ignored + + gc_locked = (data & 0x17) != 0x12; + LOG("Cirrus register extensions %s\n", gc_locked ? "unlocked" : "locked"); + m_lock_reg = data & 0x17; + }) + ); + map(0x07, 0x07).lw8( + NAME([this] (offs_t offset, u8 data) { + // TODO: bebox startup enables this + if((data & 0xf0) != 0) + popmessage("1MB framebuffer window enabled at %iMB (%02x)",data >> 4,data); + vga.sequencer.data[0x07] = data; + cirrus_define_video_mode(); + }) + ); + // TODO: check me + map(0x09, 0x09).lrw8( + NAME([this] (offs_t offset) { + return vga.sequencer.data[0x09]; + }), + NAME([this] (offs_t offset, u8 data) { + vga.sequencer.data[0x09] = data; + }) + ); + map(0x0a, 0x0a).lrw8( + NAME([this] (offs_t offset) { + return m_scratchpad1; + }), + NAME([this] (offs_t offset, u8 data) { + // GD5402/GD542x BIOS writes VRAM size here + m_scratchpad1 = data; + }) + ); + map(0x0b, 0x0e).lrw8( + NAME([this] (offs_t offset) { + return m_vclk_num[offset]; + }), + NAME([this] (offs_t offset, u8 data) { + m_vclk_num[offset] = data; + }) + ); + map(0x0f, 0x0f).lrw8( + NAME([this] (offs_t offset) { + u8 res = vga.sequencer.data[0x0f] & 0xe7; + // 32-bit DRAM data bus width (1MB-2MB) + res |= 0x18; + return res; + }), + NAME([this] (offs_t offset, u8 data) { + vga.sequencer.data[0x0f] = data; + }) + ); + // bits 5-7 of the register index are the low bits of the X co-ordinate + map(0x10, 0x10).select(0xe0).lw8( + NAME([this] (offs_t offset, u8 data) { + m_cursor_x = (data << 3) | ((offset & 0xe0) >> 5); + }) + ); + // bits 5-7 of the register index are the low bits of the Y co-ordinate + map(0x11, 0x11).select(0xe0).lw8( + NAME([this] (offs_t offset, u8 data) { + m_cursor_y = (data << 3) | ((offset & 0xe0) >> 5); + }) + ); + map(0x12, 0x12).lrw8( + NAME([this] (offs_t offset) { + return m_cursor_attr; + }), + NAME([this] (offs_t offset, u8 data) { + // bit 0 - enable cursor + // bit 1 - enable extra palette (cursor colours are there) + // bit 2 - 64x64 cursor (32x32 if clear, GD5422+) + // bit 7 - overscan colour protect - if set, use colour 2 in the extra palette for the border (GD5424+) + m_cursor_attr = data; + m_ext_palette_enabled = data & 0x02; + }) + ); + map(0x13, 0x13).lw8( + NAME([this] (offs_t offset, u8 data) { + // bits 0 and 1 are ignored if using 64x64 cursor + m_cursor_addr = data; + }) + ); + map(0x14, 0x14).lrw8( + NAME([this] (offs_t offset) { + return m_scratchpad2; + }), + NAME([this] (offs_t offset, u8 data) { + m_scratchpad2 = data; + }) + ); + map(0x15, 0x15).lrw8( + NAME([this] (offs_t offset) { + return m_scratchpad3; + }), + NAME([this] (offs_t offset, u8 data) { + // GD543x BIOS writes VRAM size here + m_scratchpad3 = data; + }) + ); + map(0x1b, 0x1e).lrw8( + NAME([this] (offs_t offset) { + return m_vclk_denom[offset]; + }), + NAME([this] (offs_t offset, u8 data) { + m_vclk_denom[offset] = data; + }) + ); +} + +void cirrus_gd5428_device::device_start() +{ + zero(); + + for (int i = 0; i < 0x100; i++) + set_pen_color(i, 0, 0, 0); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + // copy over interfaces + vga.memory = std::make_unique(vga.svga_intf.vram_size); + memset(&vga.memory[0], 0, vga.svga_intf.vram_size); + + save_pointer(NAME(vga.memory), vga.svga_intf.vram_size); + save_pointer(vga.crtc.data,"CRTC Registers",0x100); + save_pointer(vga.sequencer.data,"Sequencer Registers",0x100); + save_pointer(vga.attribute.data,"Attribute Registers", 0x15); + save_item(NAME(m_chip_id)); + save_item(NAME(m_hidden_dac_phase)); + save_item(NAME(m_hidden_dac_mode)); + + m_vblank_timer = timer_alloc(FUNC(vga_device::vblank_timer_cb), this); + + m_chip_id = 0x98; // GD5428 - Rev 0 +} + +void cirrus_gd5430_device::device_start() +{ + cirrus_gd5428_device::device_start(); + m_chip_id = 0xa0; // GD5430 - Rev 0 +} + +void cirrus_gd5446_device::device_start() +{ + cirrus_gd5428_device::device_start(); + m_chip_id = 0x80 | 0x39; // GD5446 +} + + +void cirrus_gd5428_device::device_reset() +{ + vga_device::device_reset(); + gc_locked = true; + gc_mode_ext = 0; + gc_bank_0 = gc_bank_1 = 0; + m_lock_reg = 0; + m_blt_status = 0; + m_cursor_attr = 0x00; // disable hardware cursor and extra palette + m_cursor_x = m_cursor_y = 0; + m_cursor_addr = 0; + m_scratchpad1 = m_scratchpad2 = m_scratchpad3 = 0; + m_cr19 = m_cr1a = m_cr1b = 0; + m_vclk_num[0] = 0x4a; + m_vclk_denom[0] = 0x2b; + m_vclk_num[1] = 0x5b; + m_vclk_denom[1] = 0x2f; + m_blt_source = m_blt_dest = m_blt_source_current = m_blt_dest_current = 0; + memset(m_ext_palette, 0, sizeof(m_ext_palette)); + m_ext_palette_enabled = false; + m_blt_system_transfer = false; + m_hidden_dac_phase = 0; + m_hidden_dac_mode = 0; +} + +uint32_t cirrus_gd5428_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) +{ + uint32_t ptr = (vga.svga_intf.vram_size - 0x4000); // cursor patterns are stored in the last 16kB of VRAM + svga_device::screen_update(screen, bitmap, cliprect); + + /*uint8_t cur_mode =*/ pc_vga_choosevideomode(); + if(m_cursor_attr & 0x01) // hardware cursor enabled + { + // draw hardware graphics cursor + if(m_cursor_attr & 0x04) // 64x64 + { + ptr += ((m_cursor_addr & 0x3c) * 256); + for(int y=0;y<64;y++) + { + for(int x=0;x<64;x+=8) + { + for(int bit=0;bit<8;bit++) + { + uint8_t pixel1 = vga.memory[ptr % vga.svga_intf.vram_size] >> (7-bit); + uint8_t pixel2 = vga.memory[(ptr+512) % vga.svga_intf.vram_size] >> (7-bit); + uint8_t output = ((pixel1 & 0x01) << 1) | (pixel2 & 0x01); + switch(output) + { + case 0: // transparent - do nothing + break; + case 1: // background + bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 16) | (m_ext_palette[0].green << 8) | (m_ext_palette[0].blue); + break; + case 2: // XOR + bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit); + break; + case 3: // foreground + bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 16) | (m_ext_palette[15].green << 8) | (m_ext_palette[15].blue); + break; + } + } + } + } + } + else + { + ptr += ((m_cursor_addr & 0x3f) * 256); + for(int y=0;y<32;y++) + { + for(int x=0;x<32;x+=8) + { + for(int bit=0;bit<8;bit++) + { + uint8_t pixel1 = vga.memory[ptr % vga.svga_intf.vram_size] >> (7-bit); + uint8_t pixel2 = vga.memory[(ptr+128) % vga.svga_intf.vram_size] >> (7-bit); + uint8_t output = ((pixel1 & 0x01) << 1) | (pixel2 & 0x01); + switch(output) + { + case 0: // transparent - do nothing + break; + case 1: // background + bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[0].red << 18) | (m_ext_palette[0].green << 10) | (m_ext_palette[0].blue << 2); + break; + case 2: // XOR + bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = ~bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit); + break; + case 3: // foreground + bitmap.pix(m_cursor_y+y,m_cursor_x+x+bit) = (m_ext_palette[15].red << 18) | (m_ext_palette[15].green << 10) | (m_ext_palette[15].blue << 2); + break; + } + } + ptr++; + } + } + } + } + return 0; +} + +void cirrus_gd5428_device::cirrus_define_video_mode() +{ + uint8_t divisor = 1; + float clock; + const XTAL xtal = XTAL(14'318'181); + uint8_t clocksel = (vga.miscellaneous_output & 0xc) >> 2; + + svga.rgb8_en = 0; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb24_en = 0; + svga.rgb32_en = 0; + + if(gc_locked || m_vclk_num[clocksel] == 0 || m_vclk_denom[clocksel] == 0) + clock = ((vga.miscellaneous_output & 0xc) ? xtal*2: xtal*1.75).dvalue(); + else + { + int numerator = m_vclk_num[clocksel] & 0x7f; + int denominator = (m_vclk_denom[clocksel] & 0x3e) >> 1; + int mul = m_vclk_denom[clocksel] & 0x01 ? 2 : 1; + clock = (xtal * numerator / denominator / mul).dvalue(); + } + + if (!gc_locked) + { + svga.rgb8_en = svga.rgb15_en = svga.rgb16_en = svga.rgb24_en = 0; + // gambl186 relies on this, don't setup any hidden DAC but only this + if (vga.sequencer.data[0x07] & 0x01) + svga.rgb8_en = 1; + + if (BIT(m_hidden_dac_mode, 7)) + { + // TODO: needs subclassing, earlier chips don't have all of these modes + if (BIT(m_hidden_dac_mode, 4)) + popmessage("Cirrus: Unsupported mixed 5-5-5 / 8bpp mode selected"); + switch(m_hidden_dac_mode & 0x4f) + { + case 0x00: + case 0x40: + // 5-5-5 Sierra + svga.rgb15_en = 1; + break; + case 0x41: + svga.rgb16_en = 1; + break; + case 0x43: // CCIR601 YUV422 16-bit + case 0x44: // YUV411 8-bit + case 0x4a: // 16bpp + YUV422 overlay + case 0x4b: // 16bpp + YUV411 overlay + popmessage("Cirrus: CL-GD545 YUV mode selected %02x", m_hidden_dac_mode); + break; + case 0x45: + svga.rgb24_en = 1; + break; + case 0x46: + case 0x47: + popmessage("Cirrus: CL-GD545+ DAC power down selected %02x", m_hidden_dac_mode); + break; + case 0x48: + popmessage("Cirrus: CL-GD545+ 8-bit grayscale selected"); + break; + case 0x49: + svga.rgb8_en = 1; + break; + default: + popmessage("Cirrus: reserved mode selected %02x", m_hidden_dac_mode); + break; + } + } + + switch(vga.sequencer.data[0x07] & 0x06) // bit 3 is reserved on GD542x + { + case 0x00: break; + case 0x02: clock /= 2; break; // Clock / 2 for 16-bit data + case 0x04: clock /= 3; break; // Clock / 3 for 24-bit data + case 0x06: divisor = 2; break; // Clock rate for 16-bit data + } + } + recompute_params_clock(divisor, (int)clock); +} + +uint16_t cirrus_gd5428_device::offset() +{ + uint16_t off = vga_device::offset(); + + // TODO: check true enable condition + if (svga.rgb8_en == 1) + off <<= 2; + if (svga.rgb16_en == 1) + off <<= 2; + if (svga.rgb24_en == 1) + off <<= 2; + if (svga.rgb32_en == 1) + off <<= 2; +// popmessage("Offset: %04x %s %s ** -- actual: %04x",vga.crtc.offset,vga.crtc.dw?"DW":"--",vga.crtc.word_mode?"BYTE":"WORD",off); + return off; +} + +void cirrus_gd5428_device::start_bitblt() +{ + uint32_t x,y; + + if(m_blt_mode & 0x01) + { + start_reverse_bitblt(); + return; + } + + LOGMASKED(LOG_BLIT, "CL: BitBLT started: Src: %06x Dst: %06x Width: %i Height %i ROP: %02x Mode: %02x\n",m_blt_source,m_blt_dest,m_blt_width,m_blt_height,m_blt_rop,m_blt_mode); + + m_blt_source_current = m_blt_source; + m_blt_dest_current = m_blt_dest; + + for(y=0;y<=m_blt_height;y++) + { + for(x=0;x<=m_blt_width;x++) + { + if(m_blt_mode & 0x80) // colour expand + { + if(m_blt_mode & 0x10) // 16-bit colour expansion / transparency width + { + // use GR0/1/10/11 background/foreground regs + uint16_t pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-((x/2) % 8)) & 0x01) ? ((m_gr11 << 8) | vga.gc.enable_set_reset) : ((m_gr10 << 8) | vga.gc.set_reset); + + if(m_blt_dest_current & 1) + copy_pixel(pixel >> 8, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + else + copy_pixel(pixel & 0xff, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't increment if a pattern (it's only 8 bits) + m_blt_source_current++; + } + else + { + uint8_t pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-(x % 8)) & 0x01) ? vga.gc.enable_set_reset : vga.gc.set_reset; // use GR0/1/10/11 background/foreground regs + + copy_pixel(pixel, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't increment if a pattern (it's only 8 bits) + m_blt_source_current++; + } + } + else + { + copy_pixel(vga.memory[m_blt_source_current % vga.svga_intf.vram_size], vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + m_blt_source_current++; + } + + m_blt_dest_current++; + if(m_blt_mode & 0x40 && (x % 8) == 7) // 8x8 pattern - reset pattern source location + { + if(m_blt_mode & 0x80) // colour expand + m_blt_source_current = m_blt_source + (1*(y % 8)); // patterns are linear data + else if(svga.rgb15_en || svga.rgb16_en) + { + if(m_blt_mode & 0x40 && (x % 16) == 15) + m_blt_source_current = m_blt_source + (16*(y % 8)); + } + else + m_blt_source_current = m_blt_source + (8*(y % 8)); + } + } + if(m_blt_mode & 0x40) // 8x8 pattern + { + if(m_blt_mode & 0x80) // colour expand + m_blt_source_current = m_blt_source + (1*(y % 8)); // patterns are linear data + else if(svga.rgb15_en || svga.rgb16_en) + { + if(m_blt_mode & 0x40 && (x % 16) == 15) + m_blt_source_current = m_blt_source + (16*(y % 8)); + } + else + m_blt_source_current = m_blt_source + (8*(y % 8)); + } + else + m_blt_source_current = m_blt_source + (m_blt_source_pitch*(y+1)); + m_blt_dest_current = m_blt_dest + (m_blt_dest_pitch*(y+1)); + } + m_blt_status &= ~0x02; +} + +void cirrus_gd5428_device::start_reverse_bitblt() +{ + uint32_t x,y; + + LOGMASKED(LOG_BLIT, "CL: Reverse BitBLT started: Src: %06x Dst: %06x Width: %i Height %i ROP: %02x Mode: %02x\n",m_blt_source,m_blt_dest,m_blt_width,m_blt_height,m_blt_rop,m_blt_mode); + + // Start at end of blit + m_blt_source_current = m_blt_source; + m_blt_dest_current = m_blt_dest; + + for(y=0;y<=m_blt_height;y++) + { + for(x=0;x<=m_blt_width;x++) + { + if(m_blt_mode & 0x80) // colour expand + { + if(m_blt_mode & 0x10) // 16-bit colour expansion / transparency width + { + // use GR0/1/10/11 background/foreground regs + uint16_t pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-((x/2) % 8)) & 0x01) ? ((m_gr11 << 8) | vga.gc.enable_set_reset) : ((m_gr10 << 8) | vga.gc.set_reset); + + if(m_blt_dest_current & 1) + copy_pixel(pixel >> 8, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + else + copy_pixel(pixel & 0xff, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't increment if a pattern (it's only 8 bits) + m_blt_source_current--; + } + else + { + uint8_t pixel = (vga.memory[m_blt_source_current % vga.svga_intf.vram_size] >> (7-(x % 8)) & 0x01) ? vga.gc.enable_set_reset : vga.gc.set_reset; // use GR0/1/10/11 background/foreground regs + + copy_pixel(pixel, vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + if((x % 8) == 7 && !(m_blt_mode & 0x40)) // don't decrement if a pattern (it's only 8 bits) + m_blt_source_current--; + } + } + else + { + copy_pixel(vga.memory[m_blt_source_current % vga.svga_intf.vram_size], vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + m_blt_source_current--; + } + m_blt_dest_current--; + if(m_blt_mode & 0x40 && (x % 8) == 7) // 8x8 pattern - reset pattern source location + { + if(m_blt_mode & 0x80) // colour expand + m_blt_source_current = m_blt_source - (1*(y % 8)); // patterns are linear data + else if(svga.rgb15_en || svga.rgb16_en) + { + if(m_blt_mode & 0x40 && (x % 16) == 15) + m_blt_source_current = m_blt_source - (16*(y % 8)); + } + else + m_blt_source_current = m_blt_source - (8*(y % 8)); + } + } + if(m_blt_mode & 0x40) // 8x8 pattern + { + if(m_blt_mode & 0x80) // colour expand + m_blt_source_current = m_blt_source - (1*(y % 8)); // patterns are linear data + else if(svga.rgb15_en || svga.rgb16_en) + { + if(m_blt_mode & 0x40 && (x % 16) == 15) + m_blt_source_current = m_blt_source - (16*(y % 8)); + } + else + m_blt_source_current = m_blt_source - (8*(y % 8)); + } + else + m_blt_source_current = m_blt_source - (m_blt_source_pitch*(y+1)); + m_blt_dest_current = m_blt_dest - (m_blt_dest_pitch*(y+1)); + } + m_blt_status &= ~0x02; +} + +void cirrus_gd5428_device::start_system_bitblt() +{ + LOGMASKED(LOG_BLIT, "CL: BitBLT from system memory started: Src: %06x Dst: %06x Width: %i Height %i ROP: %02x Mode: %02x\n",m_blt_source,m_blt_dest,m_blt_width,m_blt_height,m_blt_rop,m_blt_mode); + m_blt_system_transfer = true; + m_blt_system_count = 0; + m_blt_system_buffer = 0; + m_blt_pixel_count = m_blt_scan_count = 0; + m_blt_source_current = m_blt_source; + m_blt_dest_current = m_blt_dest; + m_blt_status |= 0x09; +} + +// non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored +void cirrus_gd5428_device::blit_dword() +{ + // TODO: add support for reverse direction + uint8_t x,pixel; + + for(x=0;x<32;x+=8) + { + pixel = ((m_blt_system_buffer & (0x000000ff << x)) >> x); + if(m_blt_pixel_count <= m_blt_width) + copy_pixel(pixel,vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + m_blt_dest_current++; + m_blt_pixel_count++; + } + if(m_blt_pixel_count > m_blt_width) + { + m_blt_pixel_count = 0; + m_blt_scan_count++; + m_blt_dest_current = m_blt_dest + (m_blt_dest_pitch*m_blt_scan_count); + } + if(m_blt_scan_count > m_blt_height) + { + m_blt_system_transfer = false; // BitBLT complete + m_blt_status &= ~0x0b; + } +} + +// colour-expanded BitBLTs from system memory are on a byte boundary, unused bits are ignored +void cirrus_gd5428_device::blit_byte() +{ + // TODO: add support for reverse direction + uint8_t x,pixel; + + for(x=0;x<8;x++) + { + // use GR0/1/10/11 background/foreground regs + if(m_blt_dest_current & 1) + pixel = ((m_blt_system_buffer & (0x00000001 << (7-x))) >> (7-x)) ? m_gr11 : m_gr10; + else + pixel = ((m_blt_system_buffer & (0x00000001 << (7-x))) >> (7-x)) ? vga.gc.enable_set_reset : vga.gc.set_reset; + if(m_blt_pixel_count <= m_blt_width - 1) + copy_pixel(pixel,vga.memory[m_blt_dest_current % vga.svga_intf.vram_size]); + m_blt_dest_current++; + m_blt_pixel_count++; + } + if(m_blt_pixel_count > m_blt_width) + { + m_blt_pixel_count = 0; + m_blt_scan_count++; + m_blt_dest_current = m_blt_dest + (m_blt_dest_pitch*m_blt_scan_count); + } + if(m_blt_scan_count > m_blt_height) + { + m_blt_system_transfer = false; // BitBLT complete + m_blt_status &= ~0x0b; + } +} + +void cirrus_gd5428_device::copy_pixel(uint8_t src, uint8_t dst) +{ + uint8_t res = src; + + switch(m_blt_rop) + { + case 0x00: // BLACK + res = 0x00; + break; + case 0x0b: // DSTINVERT + res = ~dst; + break; + case 0x0d: // SRC + res = src; + break; + case 0x0e: // WHITE + res = 0xff; + break; + case 0x59: // SRCINVERT + res = src ^ dst; + break; + default: + popmessage("CL: Unsupported BitBLT ROP mode %02x",m_blt_rop); + } + + // handle transparency compare + if(m_blt_mode & 0x08) // TODO: 16-bit compare + { + // if ROP result matches the transparency colour, don't change the pixel + if((res & (~m_blt_trans_colour_mask & 0xff)) == ((m_blt_trans_colour & 0xff) & (~m_blt_trans_colour_mask & 0xff))) + return; + } + + vga.memory[m_blt_dest_current % vga.svga_intf.vram_size] = res; +} + +uint8_t cirrus_gd5428_device::vga_latch_write(int offs, uint8_t data) +{ + uint8_t res = 0; + uint8_t mode_mask = (gc_mode_ext & 0x04) ? 0x07 : 0x03; + + switch (vga.gc.write_mode & mode_mask) { + case 0: + case 1: + case 2: + case 3: + res = vga_device::vga_latch_write(offs, data); + break; + case 4: + res = vga.gc.latch[offs]; + popmessage("CL: Unimplemented VGA write mode 4 enabled"); + break; + case 5: + res = vga.gc.latch[offs]; + popmessage("CL: Unimplemented VGA write mode 5 enabled"); + break; + } + + return res; +} + +uint8_t cirrus_gd5428_device::mem_r(offs_t offset) +{ + uint32_t addr; + uint8_t bank; + uint8_t cur_mode = pc_vga_choosevideomode(); + + if(gc_locked || offset >= 0x10000 || cur_mode == TEXT_MODE || cur_mode == SCREEN_OFF) + return vga_device::mem_r(offset); + + if(offset >= 0x8000 && offset < 0x10000 && (gc_mode_ext & 0x01)) // if accessing bank 1 (if enabled) + bank = gc_bank_1; + else + bank = gc_bank_0; + + if(gc_mode_ext & 0x20) // 16kB bank granularity + addr = bank * 0x4000; + else // 4kB bank granularity + addr = bank * 0x1000; + + // Is the display address adjusted automatically when not using Chain-4 addressing? + // The GD542x BIOS doesn't do it, but Virtual Pool expects it. + + if(!(vga.sequencer.data[4] & 0x8)) + addr <<= 2; + + if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) + { + uint8_t data = 0; + if(gc_mode_ext & 0x01) + { + if(offset & 0x10000) + return 0; + if(offset < 0x8000) + offset &= 0x7fff; + else + { + offset -= 0x8000; + offset &= 0x7fff; + } + } + else + offset &= 0xffff; + + if(vga.sequencer.data[4] & 0x8) + data = vga.memory[(offset+addr) % vga.svga_intf.vram_size]; + else + { + { + int i; + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + data |= vga.memory[((offset*4+i)+addr) % vga.svga_intf.vram_size]; + } + } + return data; + } + } + + switch(vga.gc.memory_map_sel & 0x03) + { + case 0: break; + case 1: if(gc_mode_ext & 0x01) offset &= 0x7fff; else offset &= 0x0ffff; break; + case 2: offset -= 0x10000; offset &= 0x07fff; break; + case 3: offset -= 0x18000; offset &= 0x07fff; break; + } + + if(vga.sequencer.data[4] & 4) + { + int data; + if (!machine().side_effects_disabled()) + { + vga.gc.latch[0]=vga.memory[(offset+addr) % vga.svga_intf.vram_size]; + vga.gc.latch[1]=vga.memory[((offset+addr)+0x10000) % vga.svga_intf.vram_size]; + vga.gc.latch[2]=vga.memory[((offset+addr)+0x20000) % vga.svga_intf.vram_size]; + vga.gc.latch[3]=vga.memory[((offset+addr)+0x30000) % vga.svga_intf.vram_size]; + } + + if (vga.gc.read_mode) + { + uint8_t byte,layer; + uint8_t fill_latch; + data=0; + + for(byte=0;byte<8;byte++) + { + fill_latch = 0; + for(layer=0;layer<4;layer++) + { + if(vga.gc.latch[layer] & 1 << byte) + fill_latch |= 1 << layer; + } + fill_latch &= vga.gc.color_dont_care; + if(fill_latch == vga.gc.color_compare) + data |= 1 << byte; + } + } + else + data=vga.gc.latch[vga.gc.read_map_sel]; + + return data; + } + else + { + // TODO: Lines up in 16-colour mode, likely different for 256-colour modes (docs say video addresses are shifted right 3 places) + uint8_t i,data; +// uint8_t bits = ((gc_mode_ext & 0x08) && (vga.gc.write_mode == 1)) ? 8 : 4; + + data = 0; + //printf("%08x\n",offset); + + if(gc_mode_ext & 0x02) + { + for(i=0;i<8;i++) + { + if(vga.sequencer.map_mask & 1 << i) + data |= vga.memory[(((offset+addr))+i*0x10000) % vga.svga_intf.vram_size]; + } + } + else + { + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + data |= vga.memory[(((offset+addr))+i*0x10000) % vga.svga_intf.vram_size]; + } + } + + return data; + } +} + +void cirrus_gd5428_device::mem_w(offs_t offset, uint8_t data) +{ + uint32_t addr; + uint8_t bank; + uint8_t cur_mode = pc_vga_choosevideomode(); + + if(m_blt_system_transfer) + { + if(m_blt_mode & 0x80) // colour expand + { + m_blt_system_buffer &= ~(0x000000ff); + m_blt_system_buffer |= data; + blit_byte(); + m_blt_system_count = 0; + } + else + { + m_blt_system_buffer &= ~(0x000000ff << (m_blt_system_count * 8)); + m_blt_system_buffer |= (data << (m_blt_system_count * 8)); + m_blt_system_count++; + if(m_blt_system_count >= 4) + { + blit_dword(); + m_blt_system_count = 0; + } + } + return; + } + + if(gc_locked || offset >= 0x10000 || cur_mode == TEXT_MODE || cur_mode == SCREEN_OFF) + { + vga_device::mem_w(offset,data); + return; + } + + if(offset >= 0x8000 && offset < 0x10000 && (gc_mode_ext & 0x01)) // if accessing bank 1 (if enabled) + bank = gc_bank_1; + else + bank = gc_bank_0; + + if(gc_mode_ext & 0x20) // 16kB bank granularity + addr = bank * 0x4000; + else // 4kB bank granularity + addr = bank * 0x1000; + + // Is the display address adjusted automatically when using Chain-4 addressing? The GD542x BIOS doesn't do it, but Virtual Pool expects it. + if(!(vga.sequencer.data[4] & 0x8)) + addr <<= 2; + + if(svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en) + { + if(offset & 0x10000) + return; + if(gc_mode_ext & 0x01) + { + if(offset < 0x8000) + offset &= 0x7fff; + else + { + offset -= 0x8000; + offset &= 0x7fff; + } + } + else + offset &= 0xffff; + + // GR0 (and GR10 in 15/16bpp modes) = background colour in write mode 5 + // GR1 (and GR11 in 15/16bpp modes) = foreground colour in write modes 4 or 5 + if(vga.gc.write_mode == 4) + { + int i; + + for(i=0;i<8;i++) + { + if(svga.rgb8_en) + { + if(data & (0x01 << (7-i))) + vga.memory[((addr+offset)*8+i) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; + } + else if(svga.rgb15_en || svga.rgb16_en) + { + if(data & (0x01 << (7-i))) + { + vga.memory[((addr+offset)*16+(i*2)) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; + vga.memory[((addr+offset)*16+(i*2)+1) % vga.svga_intf.vram_size] = m_gr11; + } + } + } + return; + } + + if(vga.gc.write_mode == 5) + { + int i; + + for(i=0;i<8;i++) + { + if(svga.rgb8_en) + { + if(data & (0x01 << (7-i))) + vga.memory[((addr+offset)*8+i) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; + else + vga.memory[((addr+offset)*8+i) % vga.svga_intf.vram_size] = vga.gc.set_reset; + } + else if(svga.rgb15_en || svga.rgb16_en) + { + if(data & (0x01 << (7-i))) + { + vga.memory[((addr+offset)*16+(i*2)) % vga.svga_intf.vram_size] = vga.gc.enable_set_reset; + vga.memory[((addr+offset)*16+(i*2)+1) % vga.svga_intf.vram_size] = m_gr11; + } + else + { + vga.memory[((addr+offset)*16+(i*2)) % vga.svga_intf.vram_size] = vga.gc.set_reset; + vga.memory[((addr+offset)*16+(i*2)+1) % vga.svga_intf.vram_size] = m_gr10; + } + } + } + return; + } + + if(vga.sequencer.data[4] & 0x8) + vga.memory[(offset+addr) % vga.svga_intf.vram_size] = data; + else + { + int i; + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + vga.memory[((offset*4+i)+addr) % vga.svga_intf.vram_size] = data; + } + } + } + else + { + //Inside each case must prevent writes to non-mapped VGA memory regions, not only mask the offset. + switch(vga.gc.memory_map_sel & 0x03) + { + case 0: break; + case 1: + if(offset & 0x10000) + return; + + if(gc_mode_ext & 0x01) + offset &= 0x7fff; + else + offset &= 0xffff; + break; + case 2: + if((offset & 0x18000) != 0x10000) + return; + + offset &= 0x07fff; + break; + case 3: + if((offset & 0x18000) != 0x18000) + return; + + offset &= 0x07fff; + break; + } + + { + // TODO: Lines up in 16-colour mode, likely different for 256-colour modes (docs say video addresses are shifted right 3 places) + uint8_t i; +// uint8_t bits = ((gc_mode_ext & 0x08) && (vga.gc.write_mode == 1)) ? 8 : 4; + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + { + if(gc_mode_ext & 0x02) + { + vga.memory[(((offset+addr) << 1)+i*0x10000) % vga.svga_intf.vram_size] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data; + vga.memory[(((offset+addr) << 1)+i*0x10000+1) % vga.svga_intf.vram_size] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data; + } + else + vga.memory[(((offset+addr))+i*0x10000) % vga.svga_intf.vram_size] = (vga.sequencer.data[4] & 4) ? vga_latch_write(i,data) : data; + } + } + return; + } + } +} diff --git a/src/devices/video/pc_vga_cirrus.h b/src/devices/video/pc_vga_cirrus.h new file mode 100644 index 00000000000..38425d6d0cd --- /dev/null +++ b/src/devices/video/pc_vga_cirrus.h @@ -0,0 +1,132 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + + Cirrus Logic GD542x/3x video chipsets + +*/ +#ifndef MAME_VIDEO_CIRRUS_H +#define MAME_VIDEO_CIRRUS_H + +#pragma once + +#include "video/pc_vga.h" + +class cirrus_gd5428_device : public svga_device +{ +public: + // construction/destruction + cirrus_gd5428_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual uint8_t mem_r(offs_t offset) override; + virtual void mem_w(offs_t offset, uint8_t data) override; + + virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) override; + +protected: + cirrus_gd5428_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual uint16_t offset() override; + + virtual void io_3cx_map(address_map &map) override; + + u8 ramdac_hidden_mask_r(offs_t offset); + void ramdac_hidden_mask_w(offs_t offset, u8 data); + u8 ramdac_overlay_r(offs_t offset); + void ramdac_overlay_w(offs_t offset, u8 data); + u8 m_hidden_dac_mode = 0; + u8 m_hidden_dac_phase = 0; + uint8_t m_chip_id; + + uint8_t gc_mode_ext; + uint8_t gc_bank_0; + uint8_t gc_bank_1; + bool gc_locked; + uint8_t m_lock_reg; + uint8_t m_gr10; // high byte of background colour (in 15/16bpp) + uint8_t m_gr11; // high byte of foreground colour (in 15/16bpp) + + uint8_t m_cr19; + uint8_t m_cr1a; + uint8_t m_cr1b; + + // hardware cursor + uint16_t m_cursor_x; + uint16_t m_cursor_y; + uint16_t m_cursor_addr; + uint8_t m_cursor_attr; + bool m_ext_palette_enabled; + struct { uint8_t red, green, blue; } m_ext_palette[16]; // extra palette, colour 0 is cursor background, colour 15 is cursor foreground, colour 2 is overscan border colour + + // BitBLT engine + uint8_t m_blt_status; + uint8_t m_blt_rop; + uint8_t m_blt_mode; + uint32_t m_blt_source; + uint32_t m_blt_dest; + uint16_t m_blt_source_pitch; + uint16_t m_blt_dest_pitch; + uint16_t m_blt_height; + uint16_t m_blt_width; + uint32_t m_blt_source_current; + uint32_t m_blt_dest_current; + uint16_t m_blt_trans_colour; + uint16_t m_blt_trans_colour_mask; + + bool m_blt_system_transfer; // blit from system memory + uint8_t m_blt_system_count; + uint32_t m_blt_system_buffer; + uint16_t m_blt_pixel_count; + uint16_t m_blt_scan_count; + + uint8_t m_scratchpad1; + uint8_t m_scratchpad2; + uint8_t m_scratchpad3; + uint8_t m_vclk_num[4]; + uint8_t m_vclk_denom[4]; + + virtual uint8_t vga_latch_write(int offs, uint8_t data) override; + + virtual void crtc_map(address_map &map) override; + virtual void gc_map(address_map &map) override; + virtual void sequencer_map(address_map &map) override; + +private: + void cirrus_define_video_mode(); + + void start_bitblt(); + void start_reverse_bitblt(); + void start_system_bitblt(); + void blit_dword(); + void blit_byte(); // used for colour expanded system-to-vram bitblts + void copy_pixel(uint8_t src, uint8_t dst); +}; + +class cirrus_gd5430_device : public cirrus_gd5428_device +{ +public: + cirrus_gd5430_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_start() override; +}; + +class cirrus_gd5446_device : public cirrus_gd5428_device +{ +public: + cirrus_gd5446_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual void device_start() override; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(CIRRUS_GD5428, cirrus_gd5428_device) +DECLARE_DEVICE_TYPE(CIRRUS_GD5430, cirrus_gd5430_device) +DECLARE_DEVICE_TYPE(CIRRUS_GD5446, cirrus_gd5446_device) + +#endif // MAME_VIDEO_CIRRUS_H diff --git a/src/devices/video/pc_vga_nvidia.cpp b/src/devices/video/pc_vga_nvidia.cpp index 2615b10fab1..372a17a5b1a 100644 --- a/src/devices/video/pc_vga_nvidia.cpp +++ b/src/devices/video/pc_vga_nvidia.cpp @@ -51,6 +51,8 @@ DEFINE_DEVICE_TYPE(NVIDIA_NV3_VGA, nvidia_nv3_vga_device, "nvidia_nv3_vga", " nvidia_nv3_vga_device::nvidia_nv3_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : svga_device(mconfig, NVIDIA_NV3_VGA, tag, owner, clock) { + m_main_if_space_config = address_space_config("io_regs", ENDIANNESS_LITTLE, 8, 4, 0, address_map_constructor(FUNC(nvidia_nv3_vga_device::io_3bx_3dx_map), this)); + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(nvidia_nv3_vga_device::crtc_map), this)); } void nvidia_nv3_vga_device::device_add_mconfig(machine_config &config) @@ -78,8 +80,6 @@ void nvidia_nv3_vga_device::device_start() vga.crtc.maximum_scan_line = 1; - vga.svga_intf.seq_regcount = 0x05; - vga.svga_intf.crtc_regcount = 0x40; // TODO: shared with main GPU, fake it for now // Start address ends at 20 bits so 0x1fffff mask / 2,097,151 bytes / 2MB window is (theorically) given // we assume that is really 4 MB, VESA tests extensively tests with 0x7f banks @@ -93,113 +93,18 @@ void nvidia_nv3_vga_device::device_start() save_item(NAME(m_ext_offset)); } -// TODO: should really calculate the access bit internally -uint8_t nvidia_nv3_vga_device::port_03b0_r(offs_t offset) +void nvidia_nv3_vga_device::io_3bx_3dx_map(address_map &map) { - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 0: - case 1: - case 2: - case 3: - LOGRMA("RMA_ACCESS R %02x\n", offset & 3); - break; - - case 5: - res = crtc_reg_read(vga.crtc.index); - break; - - default: - res = vga_device::port_03b0_r(offset); - break; - } - } - - return res; -} - -void nvidia_nv3_vga_device::port_03b0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 0: - case 1: - case 2: - case 3: - LOGRMA("RMA_ACCESS W %02x -> %02x\n", offset & 3, data); - break; - - case 5: - vga.crtc.data[vga.crtc.index] = data; - crtc_reg_write(vga.crtc.index, data); - break; - - default: - vga_device::port_03b0_w(offset, data); - break; - } - } - //define_video_mode(); -} - -uint8_t nvidia_nv3_vga_device::port_03d0_r(offs_t offset) -{ - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 0: - case 1: - case 2: - case 3: - LOGRMA("RMA_ACCESS R %02x\n", offset & 3); - break; - - case 5: - res = crtc_reg_read(vga.crtc.index); - break; - - default: - res = vga_device::port_03d0_r(offset); - break; - } - } - - return res; -} - -void nvidia_nv3_vga_device::port_03d0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 0: - case 1: - case 2: - case 3: - LOGRMA("RMA_ACCESS W %02x -> %02x\n", offset & 3, data); - break; - - case 5: - vga.crtc.data[vga.crtc.index] = data; - crtc_reg_write(vga.crtc.index, data); - break; - - default: - vga_device::port_03d0_w(offset, data); - break; - } - } - //define_video_mode(); + svga_device::io_3bx_3dx_map(map); + map(0x00, 0x03).lrw8( + NAME([this] (offs_t offset) { + LOGRMA("RMA_ACCESS R %02x\n", offset & 3); + return space().unmap(); + }), + NAME([this] (offs_t offset, u8 data) { + LOGRMA("RMA_ACCESS W %02x -> %02x\n", offset & 3, data); + }) + ); } uint8_t nvidia_nv3_vga_device::mem_r(offs_t offset) @@ -221,133 +126,26 @@ void nvidia_nv3_vga_device::mem_w(offs_t offset, uint8_t data) uint16_t nvidia_nv3_vga_device::offset() { + // TODO: check true enable condition if (svga.rgb8_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) return (vga.crtc.offset << 3) + m_ext_offset; return svga_device::offset(); } +// TODO: lock mechanism +void nvidia_nv3_vga_device::crtc_map(address_map &map) +{ + svga_device::crtc_map(map); + // REPAINT_0 /* * xxx- ---- Row offset bits 3-5 * ---x xxxx Start address bits 16-20 */ -// map(0x19, 0x19) REPAINT_0 - -/* - * ???? ?-?? - * ---- -x-- Shifts row offset by 1 bit (verify) - */ -// map(0x1a, 0x1a) REPAINT_1 - -/* - * --xx xxxx write bank, in 32k units - */ -// map(0x1d, 0x1d) WRITE_BANK - -/* - * --xx xxxx read bank - */ -// map(0x1e, 0x1e) READ_BANK - -/* - * ---x ---- Horizontal Total bit 8 - * ---- x--- Vertical Sync Start bit 10 - * ---- -x-- Vertical Blank Start bit 10 - * ---- --x- Vertical Display End bit 10 - * ---- ---x Vertical Total bit 10 - */ -// map(0x25, 0x25) EXTENDED_VERT - -/* - * ---- --xx Pixel Format - * ---- --00 VGA - * ---- --01 8bpp - * ---- --10 16bpp - * ---- --11 32bpp - */ -// map(0x28, 0x28) PIXEL_FMT - -/* - * ---- ---x Horizontal Display End bit 8 - */ -// map(0x2d, 0x2d) EXTENDED_HORZ - -/* - * ---- xxx- RMA index - * ---- ---x enable RMA - */ -// map(0x38, 0x38) RMA_MODE - -/* - * ---- x--- SDA - * ---- -x-- SCL - */ -// map(0x3e, 0x3e) I2C_READ - -/* - * ---x ---- SCL - * ---- x--- SDA - */ -// map(0x3f, 0x3f) I2C_WRITE - -uint8_t nvidia_nv3_vga_device::crtc_reg_read(uint8_t index) -{ - uint8_t res = 0; - - //index &= 0x3f; - - if(index <= 0x18) - return svga_device::crtc_reg_read(index); - - switch(index) - { - case 0x19: - res = m_repaint[0]; - break; - case 0x1a: - res = m_repaint[1]; - break; - case 0x1d: - res = svga.bank_w; - break; - case 0x1e: - res = svga.bank_r; - break; - case 0x25: - res = vga.crtc.data[0x25]; - break; - case 0x28: - res = svga.rgb32_en ? 3 : svga.rgb16_en ? 2 : svga.rgb8_en ? 1 : 0; - break; - case 0x2d: - res = (vga.crtc.horz_disp_end >> 10) & 1; - break; - case 0x38: - res = vga.crtc.data[0x38]; - LOGRMA("RMA_MODE read %02x\n", res); - break; - default: - LOGCRTC("EXT CRTC: %02x Read\n", index); - //machine().debug_break(); - res = vga.crtc.data[index]; - - break; - } - - return res; -} - -void nvidia_nv3_vga_device::crtc_reg_write(uint8_t index, uint8_t data) -{ - //index &= 0x3f; - if(index <= 0x18) - { - svga_device::crtc_reg_write(index,data); - return; - } - - switch(index) - { - case 0x19: + map(0x19, 0x19).lrw8( + NAME([this] (offs_t offset) { + return m_repaint[0]; + }), + NAME([this] (offs_t offset, u8 data) { // TODO: untested, likely used in extended text modes //vga.crtc.start_addr_latch &= ~0x1f0000; //vga.crtc.start_addr_latch |= ((data & 0x1f) << 16); @@ -355,8 +153,18 @@ void nvidia_nv3_vga_device::crtc_reg_write(uint8_t index, uint8_t data) m_repaint[0] = data; //m_ext_offset = recalculate_ext_offset(); LOGCRTC("EXT CRTC: REPAINT_0 %02x\n", data); - break; - case 0x1a: + }) + ); + // REPAINT_1 +/* + * ???? ?-?? + * ---- -x-- Shifts row offset by 1 bit (verify) + */ + map(0x1a, 0x1a).lrw8( + NAME([this] (offs_t offset) { + return m_repaint[1]; + }), + NAME([this] (offs_t offset, u8 data) { // TODO: this definitely uses more regs in the equation // REPAINT_0 REPAINT_1 base_offset // 10eh 320x200 16bpp 0x00 0x3c 0x50 560 / 0x230 (with scan doubler?) @@ -372,18 +180,49 @@ void nvidia_nv3_vga_device::crtc_reg_write(uint8_t index, uint8_t data) m_repaint[1] = data; //m_ext_offset = recalculate_ext_offset(); LOGCRTC("EXT CRTC: REPAINT_1 %02x\n", data); - break; - case 0x1d: + }) + ); + // WRITE_BANK +/* + * --xx xxxx write bank, in 32k units + */ + map(0x1d, 0x1d).lrw8( + NAME([this] (offs_t offset) { + return svga.bank_w; + }), + NAME([this] (offs_t offset, u8 data) { if (data & 0x80) LOGWARN("WRITE_BANK: attempt to write to undocumented bits %02x\n", data); svga.bank_w = data & 0x7f; - break; - case 0x1e: + }) + ); + // READ_BANK +/* + * --xx xxxx read bank + */ + map(0x1e, 0x1e).lrw8( + NAME([this] (offs_t offset) { + return svga.bank_r; + }), + NAME([this] (offs_t offset, u8 data) { if (data & 0x80) LOGWARN("READ_BANK: attempt to write to undocumented bits %02x\n", data); svga.bank_r = data & 0x7f; - break; - case 0x25: + }) + ); + // EXTENDED_VERT +/* + * ---x ---- Horizontal Total bit 8 + * ---- x--- Vertical Sync Start bit 10 + * ---- -x-- Vertical Blank Start bit 10 + * ---- --x- Vertical Display End bit 10 + * ---- ---x Vertical Total bit 10 + */ + map(0x25, 0x25).lrw8( + NAME([this] (offs_t offset) { + return vga.crtc.data[0x25]; + }), + NAME([this] (offs_t offset, u8 data) { if (data & 0xe0) LOGWARN("EXTENDED_VERT: attempt to write to undocumented bits %02x\n", data); LOGCRTC("EXT CRTC: EXTENDED_VERT %02x\n", data & 0x1f); @@ -394,8 +233,21 @@ void nvidia_nv3_vga_device::crtc_reg_write(uint8_t index, uint8_t data) vga.crtc.vert_total = (vga.crtc.vert_total & 0x03ff) | ((BIT(data, 0) << 10)); vga.crtc.data[0x25] = data; recompute_params(); - break; - case 0x28: + }) + ); + // PIXEL_FMT +/* + * ---- --xx Pixel Format + * ---- --00 VGA + * ---- --01 8bpp + * ---- --10 16bpp + * ---- --11 32bpp + */ + map(0x28, 0x28).lrw8( + NAME([this] (offs_t offset) { + return svga.rgb32_en ? 3 : svga.rgb16_en ? 2 : svga.rgb8_en ? 1 : 0; + }), + NAME([this] (offs_t offset, u8 data) { if (data & 0xfc) LOGWARN("PIXEL_FMT: attempt to write to undocumented bits %02x\n", data); data &= 3; @@ -419,22 +271,50 @@ void nvidia_nv3_vga_device::crtc_reg_write(uint8_t index, uint8_t data) LOGCRTC("PIXEL_FMT: SVGA 32bpp mode selected\n"); break; } - break; - case 0x2d: + }) + ); + // EXTENDED_HORZ +/* + * ---- ---x Horizontal Display End bit 8 + */ + map(0x2d, 0x2d).lrw8( + NAME([this] (offs_t offset) { + return (vga.crtc.horz_disp_end >> 10) & 1; + }), + NAME([this] (offs_t offset, u8 data) { if (data & 0xfc) LOGWARN("EXTENDED_HORZ: attempt to write to undocumented bits %02x\n", data); LOGCRTC("EXT CRTC: EXTENDED_HORZ %02x\n", data & 1); vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0x00ff) | ((data & 0x01) << 8); recompute_params(); - break; - case 0x38: - vga.crtc.data[index] = data; + }) + ); + // RMA_MODE +/* + * ---- xxx- RMA index + * ---- ---x enable RMA + */ + map(0x38, 0x38).lrw8( + NAME([this] (offs_t offset) { + u8 res = vga.crtc.data[0x38]; + LOGRMA("RMA_MODE read %02x\n", res); + return res; + }), + NAME([this] (offs_t offset, u8 data) { + vga.crtc.data[0x38] = data; LOGRMA("RMA_MODE write %s, index %d\n", data & 1 ? "enable" : "disable", (data & 0xe) >> 1); - break; - default: - vga.crtc.data[index] = data; - - LOGCRTC("EXT CRTC [%02x] <- %02x\n",index,data); - break; - } + }) + ); + // I2C_READ +/* + * ---- x--- SDA + * ---- -x-- SCL + */ +// map(0x3e, 0x3e) + // I2C_WRITE +/* + * ---x ---- SCL + * ---- x--- SDA + */ +// map(0x3f, 0x3f) } diff --git a/src/devices/video/pc_vga_nvidia.h b/src/devices/video/pc_vga_nvidia.h index 14213e64af2..9981b55f530 100644 --- a/src/devices/video/pc_vga_nvidia.h +++ b/src/devices/video/pc_vga_nvidia.h @@ -22,19 +22,11 @@ public: virtual uint8_t mem_r(offs_t offset) override; virtual void mem_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03b0_r(offs_t offset) override; - virtual void port_03b0_w(offs_t offset, uint8_t data) override; -// virtual uint8_t port_03c0_r(offs_t offset) override; -// virtual void port_03c0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03d0_r(offs_t offset) override; - virtual void port_03d0_w(offs_t offset, uint8_t data) override; -// virtual uint8_t mem_r(offs_t offset) override; -// virtual void mem_w(offs_t offset, uint8_t data) override; + virtual void io_3bx_3dx_map(address_map &map) override; protected: virtual void device_start() override; - virtual uint8_t crtc_reg_read(uint8_t index) override; - virtual void crtc_reg_write(uint8_t index, uint8_t data) override; + virtual void crtc_map(address_map &map) override; virtual ioport_constructor device_input_ports() const override; diff --git a/src/devices/video/pc_vga_s3.cpp b/src/devices/video/pc_vga_s3.cpp index 28bc2b5de90..140a6b493fa 100644 --- a/src/devices/video/pc_vga_s3.cpp +++ b/src/devices/video/pc_vga_s3.cpp @@ -27,11 +27,14 @@ DEFINE_DEVICE_TYPE(S3_VGA, s3_vga_device, "s3_vga", "S3 Graphics VGA s3_vga_device::s3_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : s3_vga_device(mconfig, S3_VGA, tag, owner, clock) { + } s3_vga_device::s3_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : svga_device(mconfig, type, tag, owner, clock) { + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(s3_vga_device::crtc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(s3_vga_device::sequencer_map), this)); } void s3_vga_device::device_add_mconfig(machine_config &config) @@ -125,188 +128,129 @@ void s3_vga_device::s3_define_video_mode() recompute_params_clock(divisor, xtal); } -uint8_t s3_vga_device::crtc_reg_read(uint8_t index) +void s3_vga_device::crtc_map(address_map &map) { - uint8_t res; - - if(index <= 0x18) - res = svga_device::crtc_reg_read(index); - else - { - switch(index) - { - case 0x2d: - res = s3.id_high; - break; - case 0x2e: - res = s3.id_low; - break; - case 0x2f: - res = s3.revision; - break; - case 0x30: // CR30 Chip ID/REV register - res = s3.id_cr30; - break; - case 0x31: - res = s3.memory_config; - break; - case 0x35: - res = s3.crt_reg_lock; - break; - case 0x36: // Configuration register 1 - res = s3.strapping & 0x000000ff; // PCI (not really), Fast Page Mode DRAM - break; - case 0x37: // Configuration register 2 - res = (s3.strapping & 0x0000ff00) >> 8; // enable chipset, 64k BIOS size, internal DCLK/MCLK - break; - case 0x38: - res = s3.reg_lock1; - break; - case 0x39: - res = s3.reg_lock2; - break; - case 0x42: // CR42 Mode Control - res = s3.cr42 & 0x0f; // bit 5 set if interlaced, leave it unset for now. - break; - case 0x43: - res = s3.cr43; - break; - case 0x45: - res = s3.cursor_mode; - s3.cursor_fg_ptr = 0; - s3.cursor_bg_ptr = 0; - break; - case 0x46: - res = (s3.cursor_x & 0xff00) >> 8; - break; - case 0x47: - res = s3.cursor_x & 0x00ff; - break; - case 0x48: - res = (s3.cursor_y & 0xff00) >> 8; - break; - case 0x49: - res = s3.cursor_y & 0x00ff; - break; - case 0x4a: - res = s3.cursor_fg[s3.cursor_fg_ptr++]; - s3.cursor_fg_ptr %= 4; - break; - case 0x4b: - res = s3.cursor_bg[s3.cursor_bg_ptr++]; - s3.cursor_bg_ptr %= 4; - break; - case 0x4c: - res = (s3.cursor_start_addr & 0xff00) >> 8; - break; - case 0x4d: - res = s3.cursor_start_addr & 0x00ff; - break; - case 0x4e: - res = s3.cursor_pattern_x; - break; - case 0x4f: - res = s3.cursor_pattern_y; - break; - case 0x51: - res = (vga.crtc.start_addr_latch & 0x0c0000) >> 18; - res |= ((svga.bank_w & 0x30) >> 2); - res |= ((vga.crtc.offset & 0x0300) >> 4); - break; - case 0x53: - res = s3.cr53; - break; - case 0x55: - res = s3.extended_dac_ctrl; - break; - case 0x5c: - // if VGA dot clock is set to 3 (misc reg bits 2-3), then selected dot clock is read, otherwise read VGA clock select - if((vga.miscellaneous_output & 0xc) == 0x0c) - res = s3.cr42 & 0x0f; - else - res = (vga.miscellaneous_output & 0xc) >> 2; - break; - case 0x67: - res = s3.ext_misc_ctrl_2; - break; - case 0x68: // Configuration register 3 - res = (s3.strapping & 0x00ff0000) >> 16; // no /CAS,/OE stretch time, 32-bit data bus size - break; - case 0x69: - res = vga.crtc.start_addr_latch >> 16; - break; - case 0x6a: - res = svga.bank_r & 0x7f; - break; - case 0x6f: // Configuration register 4 (Trio64V+) - res = (s3.strapping & 0xff000000) >> 24; // LPB(?) mode, Serial port I/O at port 0xe8, Serial port I/O disabled (MMIO only), no WE delay - break; - default: - res = vga.crtc.data[index]; - //machine().debug_break(); - //printf("%02x\n",index); - break; - } - } - - return res; -} - -void s3_vga_device::crtc_reg_write(uint8_t index, uint8_t data) -{ - if(index <= 0x18) - svga_device::crtc_reg_write(index,data); - else - { - switch(index) - { - case 0x31: // CR31 Memory Configuration Register - s3.memory_config = data; - vga.crtc.start_addr_latch &= ~0x30000; - vga.crtc.start_addr_latch |= ((data & 0x30) << 12); - s3_define_video_mode(); - break; - case 0x35: - if((s3.reg_lock1 & 0xc) != 8 || ((s3.reg_lock1 & 0xc0) == 0)) // lock register - return; - s3.crt_reg_lock = data; - svga.bank_w = data & 0xf; - svga.bank_r = svga.bank_w; - break; - case 0x36: - if(s3.reg_lock2 == 0xa5) - { - s3.strapping = (s3.strapping & 0xffffff00) | data; - LOG("CR36: Strapping data = %08x\n",s3.strapping); - } - break; - case 0x37: - if(s3.reg_lock2 == 0xa5) - { - s3.strapping = (s3.strapping & 0xffff00ff) | (data << 8); - LOG("CR37: Strapping data = %08x\n",s3.strapping); - } - break; - case 0x38: - s3.reg_lock1 = data; - break; - case 0x39: - /* TODO: reg lock mechanism */ - s3.reg_lock2 = data; - break; - case 0x40: - s3.enable_8514 = data & 0x01; // enable 8514/A registers (x2e8, x6e8, xae8, xee8) - break; - case 0x42: - s3.cr42 = data; // bit 5 = interlace, bits 0-3 = dot clock (seems to be undocumented) - break; - case 0x43: - s3.cr43 = data; // bit 2 = bit 8 of offset register, but only if bits 4-5 of CR51 are 00h. - vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x04) << 6); - s3_define_video_mode(); - break; + svga_device::crtc_map(map); + map(0x2d, 0x2d).lr8( + NAME([this] (offs_t offset) { + return s3.id_high; + }) + ); + map(0x2e, 0x2e).lr8( + NAME([this] (offs_t offset) { + return s3.id_low; + }) + ); + map(0x2f, 0x2f).lr8( + NAME([this] (offs_t offset) { + return s3.revision; + }) + ); + // CR30 Chip ID/REV register + map(0x30, 0x30).lr8( + NAME([this] (offs_t offset) { + return s3.id_cr30; + }) + ); + // CR31 Memory Configuration Register + map(0x31, 0x31).lrw8( + NAME([this] (offs_t offset) { + return s3.memory_config; + }), + NAME([this] (offs_t offset, u8 data) { + s3.memory_config = data; + vga.crtc.start_addr_latch &= ~0x30000; + vga.crtc.start_addr_latch |= ((data & 0x30) << 12); + s3_define_video_mode(); + }) + ); + map(0x35, 0x35).lrw8( + NAME([this] (offs_t offset) { + return s3.crt_reg_lock; + }), + NAME([this] (offs_t offset, u8 data) { + // lock register + if((s3.reg_lock1 & 0xc) != 8 || ((s3.reg_lock1 & 0xc0) == 0)) + return; + s3.crt_reg_lock = data; + svga.bank_w = data & 0xf; + svga.bank_r = svga.bank_w; + }) + ); + // Configuration register 1 + map(0x36, 0x36).lrw8( + NAME([this] (offs_t offset) { + // PCI (not really), Fast Page Mode DRAM + return s3.strapping & 0x000000ff; + }), + NAME([this] (offs_t offset, u8 data) { + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0xffffff00) | data; + LOG("CR36: Strapping data = %08x\n",s3.strapping); + } + }) + ); + // Configuration register 2 + map(0x37, 0x37).lrw8( + NAME([this] (offs_t offset) { + return (s3.strapping & 0x0000ff00) >> 8; // enable chipset, 64k BIOS size, internal DCLK/MCLK + }), + NAME([this] (offs_t offset, u8 data) { + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0xffff00ff) | (data << 8); + LOG("CR37: Strapping data = %08x\n",s3.strapping); + } + }) + ); + map(0x38, 0x38).lrw8( + NAME([this] (offs_t offset) { + return s3.reg_lock1; + }), + NAME([this] (offs_t offset, u8 data) { + s3.reg_lock1 = data; + }) + ); + map(0x39, 0x39).lrw8( + NAME([this] (offs_t offset) { + return s3.reg_lock2; + }), + NAME([this] (offs_t offset, u8 data) { + // TODO: reg lock mechanism + s3.reg_lock2 = data; + }) + ); + map(0x40, 0x40).lw8( + NAME([this] (offs_t offset, u8 data) { + // enable 8514/A registers (x2e8, x6e8, xae8, xee8) + s3.enable_8514 = BIT(data, 0); + }) + ); + // CR42 Mode Control + map(0x42, 0x42).lrw8( + NAME([this] (offs_t offset) { + // bit 5 set if interlaced, leave it unset for now. + return s3.cr42 & 0x0f; + }), + NAME([this] (offs_t offset, u8 data) { + // bit 5 = interlace, bits 0-3 = dot clock (seems to be undocumented) + // TODO: interlace used by modes 116h / 117h at least (1024x768) + s3.cr42 = data; + }) + ); + map(0x43, 0x43).lrw8( + NAME([this] (offs_t offset) { + return s3.cr43; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cr43 = data; // bit 2 = bit 8 of offset register, but only if bits 4-5 of CR51 are 00h. + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x04) << 6); + s3_define_video_mode(); + }) + ); /* -3d4h index 45h (R/W): CR45 Hardware Graphics Cursor Mode +CR45 Hardware Graphics Cursor Mode bit 0 HWGC ENB. Hardware Graphics Cursor Enable. Set to enable the HardWare Cursor in VGA and enhanced modes. 1 (911/24) Delay Timing for Pattern Data Fetch @@ -330,36 +274,66 @@ bit 0 HWGC ENB. Hardware Graphics Cursor Enable. Set to enable the /ODF) is the ODF output to a Bt485A compatible RamDAC (low for even fields and high for odd fields), if clear pin185 is the RS3 output. */ - case 0x45: - s3.cursor_mode = data; - break; + map(0x45, 0x45).lrw8( + NAME([this] (offs_t offset) { + const u8 res = s3.cursor_mode; + if (!machine().side_effects_disabled()) + { + s3.cursor_fg_ptr = 0; + s3.cursor_bg_ptr = 0; + } + return res; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_mode = data; + }) + ); /* -3d4h index 46h M(R/W): CR46/7 Hardware Graphics Cursor Origin-X +CR46/7 Hardware Graphics Cursor Origin-X bit 0-10 The HardWare Cursor X position. For 64k modes this value should be twice the actual X co-ordinate. */ - case 0x46: - s3.cursor_x = (s3.cursor_x & 0x00ff) | (data << 8); - break; - case 0x47: - s3.cursor_x = (s3.cursor_x & 0xff00) | data; - break; + map(0x46, 0x46).lrw8( + NAME([this] (offs_t offset) { + return (s3.cursor_x & 0xff00) >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_x = (s3.cursor_x & 0x00ff) | (data << 8); + }) + ); + map(0x47, 0x47).lrw8( + NAME([this] (offs_t offset) { + return s3.cursor_x & 0x00ff; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_x = (s3.cursor_x & 0xff00) | data; + }) + ); /* -3d4h index 48h M(R/W): CR48/9 Hardware Graphics Cursor Origin-Y +CR48/9 Hardware Graphics Cursor Origin-Y bit 0-9 (911/24) The HardWare Cursor Y position. 0-10 (80x +) The HardWare Cursor Y position. Note: The position is activated when the high byte of the Y coordinate (index 48h) is written, so this byte should be written last (not 911/924 ?) */ - case 0x48: - s3.cursor_y = (s3.cursor_y & 0x00ff) | (data << 8); - break; - case 0x49: - s3.cursor_y = (s3.cursor_y & 0xff00) | data; - break; - + map(0x48, 0x48).lrw8( + NAME([this] (offs_t offset) { + return (s3.cursor_y & 0xff00) >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_y = (s3.cursor_y & 0x00ff) | (data << 8); + }) + ); + map(0x49, 0x49).lrw8( + NAME([this] (offs_t offset) { + return s3.cursor_y & 0x00ff; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_y = (s3.cursor_y & 0xff00) | data; + }) + ); /* -3d4h index 4Ah (R/W): Hardware Graphics Cursor Foreground Stack (80x +) +CR4A Hardware Graphics Cursor Foreground Stack (80x +) bit 0-7 The Foreground Cursor color. Three bytes (4 for the 864/964) are stacked here. When the Cursor Mode register (3d4h index 45h) is read the stackpointer is reset. When a byte is written the byte is @@ -368,12 +342,23 @@ bit 0-7 The Foreground Cursor color. Three bytes (4 for the 864/964) are other two(3) only when Hardware Cursor Horizontal Stretch (3d4h index 45h bit 2-3) is enabled. */ - case 0x4a: - s3.cursor_fg[s3.cursor_fg_ptr++] = data; + map(0x4a, 0x4a).lrw8( + NAME([this] (offs_t offset) { + const u8 res = s3.cursor_fg[s3.cursor_fg_ptr]; + if (!machine().side_effects_disabled()) + { + s3.cursor_fg_ptr++; s3.cursor_fg_ptr %= 4; - break; + } + return res; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_fg[s3.cursor_fg_ptr++] = data; + s3.cursor_fg_ptr %= 4; + }) + ); /* -3d4h index 4Bh (R/W): Hardware Graphics Cursor Background Stack (80x +) +CR4B Hardware Graphics Cursor Background Stack (80x +) bit 0-7 The Background Cursor color. Three bytes (4 for the 864/964) are stacked here. When the Cursor Mode register (3d4h index 45h) is read the stackpointer is reset. When a byte is written the byte is @@ -382,12 +367,23 @@ bit 0-7 The Background Cursor color. Three bytes (4 for the 864/964) are other two(3) only when Hardware Cursor Horizontal Stretch (3d4h index 45h bit 2-3) is enabled. */ - case 0x4b: - s3.cursor_bg[s3.cursor_bg_ptr++] = data; + map(0x4b, 0x4b).lrw8( + NAME([this] (offs_t offset) { + const u8 res = s3.cursor_bg[s3.cursor_bg_ptr]; + if (!machine().side_effects_disabled()) + { + s3.cursor_bg_ptr++; s3.cursor_bg_ptr %= 4; - break; + } + return res; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_bg[s3.cursor_bg_ptr++] = data; + s3.cursor_bg_ptr %= 4; + }) + ); /* -3d4h index 4Ch M(R/W): CR4C/D Hardware Graphics Cursor Storage Start Address +CR4C/D Hardware Graphics Cursor Storage Start Address bit 0-9 (911,924) HCS_STADR. Hardware Graphics Cursor Storage Start Address 0-11 (80x,928) HWGC_STA. Hardware Graphics Cursor Storage Start Address 0-12 (864,964) HWGC_STA. Hardware Graphics Cursor Storage Start Address @@ -408,44 +404,77 @@ bit 0-9 (911,924) HCS_STADR. Hardware Graphics Cursor Storage Start Address (801/5,928) For Hi/True color modes use the Horizontal Stretch bits (3d4h index 45h bits 2 and 3). */ - case 0x4c: - s3.cursor_start_addr = (s3.cursor_start_addr & 0x00ff) | (data << 8); - popmessage("HW Cursor Data Address %04x\n",s3.cursor_start_addr); - break; - case 0x4d: - s3.cursor_start_addr = (s3.cursor_start_addr & 0xff00) | data; - popmessage("HW Cursor Data Address %04x\n",s3.cursor_start_addr); - break; + map(0x4c, 0x4c).lrw8( + NAME([this] (offs_t offset) { + return (s3.cursor_start_addr & 0xff00) >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_start_addr = (s3.cursor_start_addr & 0x00ff) | (data << 8); + //popmessage("HW Cursor Data Address %04x\n",s3.cursor_start_addr); + }) + ); + map(0x4d, 0x4d).lrw8( + NAME([this] (offs_t offset) { + return s3.cursor_start_addr & 0x00ff; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_start_addr = (s3.cursor_start_addr & 0xff00) | data; + //popmessage("HW Cursor Data Address %04x\n",s3.cursor_start_addr); + }) + ); /* -3d4h index 4Eh (R/W): CR4E HGC Pattern Disp Start X-Pixel Position +CR4E HGC Pattern Disp Start X-Pixel Position bit 0-5 Pattern Display Start X-Pixel Position. */ - case 0x4e: - s3.cursor_pattern_x = data; - break; + map(0x4e, 0x4e).lrw8( + NAME([this] (offs_t offset) { + return s3.cursor_pattern_x; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_pattern_x = data; + }) + ); /* -3d4h index 4Fh (R/W): CR4F HGC Pattern Disp Start Y-Pixel Position +CR4F HGC Pattern Disp Start Y-Pixel Position bit 0-5 Pattern Display Start Y-Pixel Position. */ - case 0x4f: - s3.cursor_pattern_y = data; - break; - case 0x51: - vga.crtc.start_addr_latch &= ~0xc0000; - vga.crtc.start_addr_latch |= ((data & 0x3) << 18); - svga.bank_w = (svga.bank_w & 0xcf) | ((data & 0x0c) << 2); - svga.bank_r = svga.bank_w; - if((data & 0x30) != 0x00) - vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x30) << 4); - else - vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr43 & 0x04) << 6); - s3_define_video_mode(); - break; - case 0x53: - s3.cr53 = data; - break; + map(0x4f, 0x4f).lrw8( + NAME([this] (offs_t offset) { + return s3.cursor_pattern_y; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_pattern_y = data; + }) + ); + map(0x51, 0x51).lrw8( + NAME([this] (offs_t offset) { + u8 res = (vga.crtc.start_addr_latch & 0x0c0000) >> 18; + res |= ((svga.bank_w & 0x30) >> 2); + res |= ((vga.crtc.offset & 0x0300) >> 4); + return res; + }), + NAME([this] (offs_t offset, u8 data) { + vga.crtc.start_addr_latch &= ~0xc0000; + vga.crtc.start_addr_latch |= ((data & 0x3) << 18); + svga.bank_w = (svga.bank_w & 0xcf) | ((data & 0x0c) << 2); + svga.bank_r = svga.bank_w; + if((data & 0x30) != 0x00) + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x30) << 4); + else + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr43 & 0x04) << 6); + s3_define_video_mode(); + }) + ); + map(0x53, 0x53).lrw8( + NAME([this] (offs_t offset) { + return s3.cr53; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cr53 = data; + }) + ); /* -3d4h index 55h (R/W): Extended Video DAC Control Register (80x +) +CR55 Extended Video DAC Control Register (80x +) bit 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the RAMDAC, allowing access to all 8 or 16 registers on advanced RAMDACs. If this field is 0, 3d4h index 43h bit 1 is active. @@ -465,11 +494,28 @@ bit 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the (864/964) TOFF VCLK. Tri-State Off VCLK Output. VCLK output tri -stated if set */ - case 0x55: - s3.extended_dac_ctrl = data; - break; + map(0x55, 0x55).lrw8( + NAME([this] (offs_t offset) { + return s3.extended_dac_ctrl; + }), + NAME([this] (offs_t offset, u8 data) { + s3.extended_dac_ctrl = data; + }) + ); + map(0x5c, 0x5c).lr8( + NAME([this] (offs_t offset) { + u8 res = 0; + // if VGA dot clock is set to 3 (misc reg bits 2-3), then selected dot clock is read, otherwise read VGA clock select + if((vga.miscellaneous_output & 0xc) == 0x0c) + res = s3.cr42 & 0x0f; + else + res = (vga.miscellaneous_output & 0xc) >> 2; + return res; + }) + ); +// TODO: following two registers must be read-backable /* -3d4h index 5Dh (R/W): Extended Horizontal Overflow Register (80x +) +CR5D Extended Horizontal Overflow Register (80x +) bit 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h index 0) 1 Horizontal Display End bit 8. Bit 8 of the Horizontal Display End @@ -489,17 +535,19 @@ bit 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h 7 (928,964) Bus-Grant Terminate Position bit 8. Bit 8 of the Bus Grant Termination register (3d4h index 5Fh). */ - case 0x5d: - vga.crtc.horz_total = (vga.crtc.horz_total & 0xfeff) | ((data & 0x01) << 8); - vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0xfeff) | ((data & 0x02) << 7); - vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0xfeff) | ((data & 0x04) << 6); - vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xffbf) | ((data & 0x08) << 3); - vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0xfeff) | ((data & 0x10) << 4); - vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0xffdf) | (data & 0x20); - s3_define_video_mode(); - break; + map(0x5d, 0x5d).lw8( + NAME([this] (offs_t offset, u8 data) { + vga.crtc.horz_total = (vga.crtc.horz_total & 0xfeff) | ((data & 0x01) << 8); + vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0xfeff) | ((data & 0x02) << 7); + vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0xfeff) | ((data & 0x04) << 6); + vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xffbf) | ((data & 0x08) << 3); + vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0xfeff) | ((data & 0x10) << 4); + vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0xffdf) | (data & 0x20); + s3_define_video_mode(); + }) + ); /* -3d4h index 5Eh (R/W): Extended Vertical Overflow Register (80x +) +CR5E: Extended Vertical Overflow Register (80x +) bit 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h index 6). Bits 8 and 9 are in 3d4h index 7 bit 0 and 5. 1 Vertical Display End bit 10. Bit 10 of the Vertical Display End @@ -515,117 +563,108 @@ bit 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h (3d4h index 18h). Bit 8 is in 3d4h index 7 bit 4 and bit 9 in 3d4h index 9 bit 6. */ - case 0x5e: - vga.crtc.vert_total = (vga.crtc.vert_total & 0xfbff) | ((data & 0x01) << 10); - vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0xfbff) | ((data & 0x02) << 9); - vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0xfbff) | ((data & 0x04) << 8); - vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0xfbff) | ((data & 0x10) << 6); - vga.crtc.line_compare = (vga.crtc.line_compare & 0xfbff) | ((data & 0x40) << 4); - s3_define_video_mode(); - break; - case 0x67: - s3.ext_misc_ctrl_2 = data; - s3_define_video_mode(); - break; - case 0x68: - if(s3.reg_lock2 == 0xa5) - { - s3.strapping = (s3.strapping & 0xff00ffff) | (data << 16); - LOG("CR68: Strapping data = %08x\n",s3.strapping); - } - break; - case 0x69: - vga.crtc.start_addr_latch &= ~0x1f0000; - vga.crtc.start_addr_latch |= ((data & 0x1f) << 16); - s3_define_video_mode(); - break; - case 0x6a: - svga.bank_w = data & 0x3f; - svga.bank_r = svga.bank_w; - break; - case 0x6f: - if(s3.reg_lock2 == 0xa5) - { - s3.strapping = (s3.strapping & 0x00ffffff) | (data << 24); - LOG("CR6F: Strapping data = %08x\n",s3.strapping); - } - break; - default: - LOG( "S3: 3D4 index %02x write %02x\n",index,data); - break; - } - } -} - -uint8_t s3_vga_device::s3_seq_reg_read(uint8_t index) -{ - uint8_t res = 0xff; - - if(index <= 0x0c) - res = vga.sequencer.data[index]; - else - { - switch(index) - { - case 0x10: - res = s3.sr10; - break; - case 0x11: - res = s3.sr11; - break; - case 0x12: - res = s3.sr12; - break; - case 0x13: - res = s3.sr13; - break; - case 0x15: - res = s3.sr15; - break; - case 0x17: - res = s3.sr17; // CLKSYN test register - s3.sr17--; // who knows what it should return, docs only say it defaults to 0, and is reserved for testing of the clock synthesiser - break; - } - } - - return res; + map(0x5e, 0x5e).lw8( + NAME([this] (offs_t offset, u8 data) { + vga.crtc.vert_total = (vga.crtc.vert_total & 0xfbff) | ((data & 0x01) << 10); + vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0xfbff) | ((data & 0x02) << 9); + vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0xfbff) | ((data & 0x04) << 8); + vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0xfbff) | ((data & 0x10) << 6); + vga.crtc.line_compare = (vga.crtc.line_compare & 0xfbff) | ((data & 0x40) << 4); + s3_define_video_mode(); + }) + ); + map(0x67, 0x67).lrw8( + NAME([this] (offs_t offset) { + return s3.ext_misc_ctrl_2; + }), + NAME([this] (offs_t offset, u8 data) { + s3.ext_misc_ctrl_2 = data; + s3_define_video_mode(); + }) + ); + map(0x68, 0x68).lrw8( + NAME([this] (offs_t offset) { // Configuration register 3 + // no /CAS,/OE stretch time, 32-bit data bus size + return (s3.strapping & 0x00ff0000) >> 16; + }), + NAME([this] (offs_t offset, u8 data) { + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0xff00ffff) | (data << 16); + LOG("CR68: Strapping data = %08x\n",s3.strapping); + } + }) + ); + map(0x69, 0x69).lrw8( + NAME([this] (offs_t offset) { + return vga.crtc.start_addr_latch >> 16; + }), + NAME([this] (offs_t offset, u8 data) { + vga.crtc.start_addr_latch &= ~0x1f0000; + vga.crtc.start_addr_latch |= ((data & 0x1f) << 16); + s3_define_video_mode(); + }) + ); + // TODO: doesn't match number of bits + map(0x6a, 0x6a).lrw8( + NAME([this] (offs_t offset) { + return svga.bank_r & 0x7f; + }), + NAME([this] (offs_t offset, u8 data) { + svga.bank_w = data & 0x3f; + svga.bank_r = svga.bank_w; + }) + ); + // Configuration register 4 (Trio64V+) + map(0x6f, 0x6f).lrw8( + NAME([this] (offs_t offset) { + // LPB(?) mode, Serial port I/O at port 0xe8, Serial port I/O disabled (MMIO only), no WE delay + return (s3.strapping & 0xff000000) >> 24; + }), + NAME([this] (offs_t offset, u8 data) { + if(s3.reg_lock2 == 0xa5) + { + s3.strapping = (s3.strapping & 0x00ffffff) | (data << 24); + LOG("CR6F: Strapping data = %08x\n",s3.strapping); + } + }) + ); } -void s3_vga_device::s3_seq_reg_write(uint8_t index, uint8_t data) +void s3_vga_device::sequencer_map(address_map &map) { - if(index <= 0x0c) - { - vga.sequencer.data[vga.sequencer.index] = data; - seq_reg_write(vga.sequencer.index,data); - } - else - { - switch(index) - { - // Memory CLK PLL - case 0x10: - s3.sr10 = data; - break; - case 0x11: - s3.sr11 = data; - break; - // Video CLK PLL - case 0x12: - s3.sr12 = data; - break; - case 0x13: - s3.sr13 = data; - break; - case 0x15: - if(data & 0x02) // load DCLK frequency (would normally have a small variable delay) + svga_device::sequencer_map(map); + // Memory CLK PLL + map(0x10, 0x10).lrw8( + NAME([this] (offs_t offset) { return s3.sr10; }), + NAME([this] (offs_t offset, u8 data) { s3.sr10 = data; }) + ); + map(0x11, 0x11).lrw8( + NAME([this] (offs_t offset) { return s3.sr11; }), + NAME([this] (offs_t offset, u8 data) { s3.sr11 = data; }) + ); + // Video CLK PLL + map(0x12, 0x12).lrw8( + NAME([this] (offs_t offset) { return s3.sr12; }), + NAME([this] (offs_t offset, u8 data) { s3.sr12 = data; }) + ); + map(0x13, 0x13).lrw8( + NAME([this] (offs_t offset) { return s3.sr13; }), + NAME([this] (offs_t offset, u8 data) { s3.sr13 = data; }) + ); + map(0x15, 0x15).lrw8( + NAME([this] (offs_t offset) { return s3.sr15; }), + NAME([this] (offs_t offset, u8 data) { + // load DCLK frequency (would normally have a small variable delay) + if(data & 0x02) { s3.clk_pll_n = s3.sr12 & 0x1f; s3.clk_pll_r = (s3.sr12 & 0x60) >> 5; s3.clk_pll_m = s3.sr13 & 0x7f; s3_define_video_mode(); } - if(data & 0x20) // immediate DCLK/MCLK load + // immediate DCLK/MCLK load + if(data & 0x20) { s3.clk_pll_n = s3.sr12 & 0x1f; s3.clk_pll_r = (s3.sr12 & 0x60) >> 5; @@ -633,114 +672,18 @@ void s3_vga_device::s3_seq_reg_write(uint8_t index, uint8_t data) s3_define_video_mode(); } s3.sr15 = data; - } - } -} - - - -uint8_t s3_vga_device::port_03b0_r(offs_t offset) -{ - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 5: - res = s3_vga_device::crtc_reg_read(vga.crtc.index); - break; - default: - res = vga_device::port_03b0_r(offset); - break; - } - } - - return res; -} - -void s3_vga_device::port_03b0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 5: - vga.crtc.data[vga.crtc.index] = data; - s3_vga_device::crtc_reg_write(vga.crtc.index,data); - break; - default: - vga_device::port_03b0_w(offset,data); - break; - } - } -} - -uint8_t s3_vga_device::port_03c0_r(offs_t offset) -{ - uint8_t res; - - switch(offset) - { - case 5: - res = s3_seq_reg_read(vga.sequencer.index); - break; - default: - res = vga_device::port_03c0_r(offset); - break; - } - - return res; -} - -void s3_vga_device::port_03c0_w(offs_t offset, uint8_t data) -{ - switch(offset) - { - case 5: - s3_seq_reg_write(vga.sequencer.index,data); - break; - default: - vga_device::port_03c0_w(offset,data); - break; - } -} - -uint8_t s3_vga_device::port_03d0_r(offs_t offset) -{ - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - res = s3_vga_device::crtc_reg_read(vga.crtc.index); - break; - default: - res = vga_device::port_03d0_r(offset); - break; - } - } - - return res; -} - -void s3_vga_device::port_03d0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - vga.crtc.data[vga.crtc.index] = data; - crtc_reg_write(vga.crtc.index,data); - break; - default: - vga_device::port_03d0_w(offset,data); - break; - } - } + }) + ), + map(0x17, 0x17).lr8( + NAME([this] (offs_t offset) { + // CLKSYN test register + const u8 res = s3.sr17; + // who knows what it should return, docs only say it defaults to 0, and is reserved for testing of the clock synthesiser + if (!machine().side_effects_disabled()) + s3.sr17--; + return res; + }) + ); } uint8_t s3_vga_device::mem_r(offs_t offset) diff --git a/src/devices/video/pc_vga_s3.h b/src/devices/video/pc_vga_s3.h index a7de03db80c..700077fef05 100644 --- a/src/devices/video/pc_vga_s3.h +++ b/src/devices/video/pc_vga_s3.h @@ -17,12 +17,6 @@ public: // construction/destruction s3_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - virtual uint8_t port_03b0_r(offs_t offset) override; - virtual void port_03b0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03c0_r(offs_t offset) override; - virtual void port_03c0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03d0_r(offs_t offset) override; - virtual void port_03d0_w(offs_t offset, uint8_t data) override; virtual uint8_t mem_r(offs_t offset) override; virtual void mem_w(offs_t offset, uint8_t data) override; @@ -40,6 +34,10 @@ protected: virtual void device_reset() override; virtual void device_add_mconfig(machine_config &config) override; + virtual void crtc_map(address_map &map) override; + virtual void sequencer_map(address_map &map) override; + + // TODO: remove this leaky abstraction struct { uint8_t memory_config; @@ -89,15 +87,9 @@ protected: } s3; virtual uint16_t offset() override; -protected: - uint8_t crtc_reg_read(uint8_t index) override; - void crtc_reg_write(uint8_t index, uint8_t data) override; + virtual void s3_define_video_mode(void); private: - - void s3_define_video_mode(void); - uint8_t s3_seq_reg_read(uint8_t index); - void s3_seq_reg_write(uint8_t index, uint8_t data); ibm8514a_device* m_8514; }; diff --git a/src/devices/video/pc_vga_sis.cpp b/src/devices/video/pc_vga_sis.cpp new file mode 100644 index 00000000000..50ec30ad110 --- /dev/null +++ b/src/devices/video/pc_vga_sis.cpp @@ -0,0 +1,301 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/************************************************************************************************** + +Implementation of SiS family (S)VGA chipset + +TODO: +- interlace (cfr. xubuntu 6.10 splash screen on 1024x768x32); +- backport to earlier variants; + +**************************************************************************************************/ + +#include "emu.h" +#include "pc_vga_sis.h" + +#include "screen.h" + +#define VERBOSE (LOG_GENERAL) +//#define LOG_OUTPUT_FUNC osd_printf_info +#include "logmacro.h" + +// TODO: later variant of 5598 +// (definitely doesn't have dual segment mode for instance) +DEFINE_DEVICE_TYPE(SIS630_SVGA, sis630_svga_device, "sis630_svga", "SiS 630 SVGA") + +sis630_svga_device::sis630_svga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : svga_device(mconfig, SIS630_SVGA, tag, owner, clock) +{ + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(sis630_svga_device::crtc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(sis630_svga_device::sequencer_map), this)); +} + +void sis630_svga_device::device_start() +{ + svga_device::device_start(); + zero(); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + // copy over interfaces + vga.svga_intf.vram_size = 64*1024*1024; + //vga.memory = std::make_unique(vga.svga_intf.vram_size); +} + +void sis630_svga_device::device_reset() +{ + svga_device::device_reset(); + + m_unlock_reg = false; + //m_dual_seg_mode = false; +} + +void sis630_svga_device::io_3cx_map(address_map &map) +{ + svga_device::io_3cx_map(map); + // TODO: for '630 it's always with dual segment enabled? + // May be like trident_vga where there's a specific register + + // read by gamecstl Kontron BIOS + map(0x0b, 0x0b).lrw8( + NAME([this] (offs_t offset) { + return svga.bank_r; + }), + NAME([this] (offs_t offset, u8 data) { + svga.bank_r = data; + }) + ); + map(0x0d, 0x0d).lrw8( + NAME([this] (offs_t offset) { + return svga.bank_w; + }), + NAME([this] (offs_t offset, u8 data) { + svga.bank_w = data & 0x3f; + }) + ); +} + +// Page 144 +void sis630_svga_device::crtc_map(address_map &map) +{ + svga_device::crtc_map(map); + // CR19/CR1A Extended Signature Read-Back 0/1 + // CR1B CRT horizontal counter (r/o) + // CR1C CRT vertical counter (r/o) + // CR1D CRT overflow counter (r/o) + // CR1E Extended Signature Read-Back 2 + // CR26 Attribute Controller Index read-back + // TODO: is this an undocumented VGA or a SiS extension? + map(0x26, 0x26).lr8( + NAME([this] (offs_t offset) { return vga.attribute.index; }) + ); + // TODO: very preliminary, undocumented stuff + map(0x30, 0xff).lrw8( + NAME([this] (offs_t offset) { + return vga.crtc.data[offset]; + }), + NAME([this] (offs_t offset, u8 data) { + // TODO: if one of these is 0xff then it enables a single port transfer to $b8000 + vga.crtc.data[offset] = data; + }) + ); + // make sure '301 CRT2 is not enabled for now + map(0x30, 0x30).lr8( + NAME([] (offs_t offset) { return 0; }) + ); + map(0x31, 0x31).lr8( + NAME([] (offs_t offset) { return 0x60; }) + ); + map(0x32, 0x32).lr8( + NAME([] (offs_t offset) { return 0x20; }) + ); +} + +void sis630_svga_device::sequencer_map(address_map &map) +{ + svga_device::sequencer_map(map); + // extended ID register + map(0x05, 0x05).lrw8( + NAME([this] (offs_t offset) { + return m_unlock_reg ? 0xa1 : 0x21; + }), + NAME([this] (offs_t offset, u8 data) { + // TODO: reimplement me thru memory_view or direct handler override + m_unlock_reg = (data == 0x86); + LOG("Unlock register write %02x (%s)\n", data, m_unlock_reg ? "unlocked" : "locked"); + }) + ); + /* + * x--- ---- GFX mode linear addressing enable + * -x-- ---- GFX hardware cursor display + * --x- ---- GFX mode interlace + * ---x ---- True Color enable (ties with index 0x07 bit 2) + * ---- x--- RGB16 enable + * ---- -x-- RGB15 enable + * ---- --x- enhanced GFX mode enable + * ---- ---x enhanced text mode enable + */ + map(0x06, 0x06).lrw8( + NAME([this] (offs_t offset) { + return m_ramdac_mode; + }), + NAME([this] (offs_t offset, u8 data) { + m_ramdac_mode = data; + LOG("RAMDAC mode %02x\n", data); + + if (!BIT(data, 1)) + { + svga.rgb8_en = svga.rgb15_en = svga.rgb16_en = svga.rgb24_en = svga.rgb32_en = 0; + } + else + { + if (BIT(data, 2)) + svga.rgb15_en = 1; + if (BIT(data, 3)) + svga.rgb16_en = 1; + std::tie(svga.rgb24_en, svga.rgb32_en) = flush_true_color_mode(); + } + }) + ); + map(0x07, 0x07).lrw8( + NAME([this] (offs_t offset) { + return m_ext_misc_ctrl_0; + }), + NAME([this] (offs_t offset, u8 data) { + LOG("Extended Misc. Control register 0 SR07 %02x\n", data); + m_ext_misc_ctrl_0 = data; + std::tie(svga.rgb24_en, svga.rgb32_en) = flush_true_color_mode(); + }) + ); + map(0x0a, 0x0a).lrw8( + NAME([this] (offs_t offset) { + return m_ext_vert_overflow; + }), + NAME([this] (offs_t offset, u8 data) { + LOG("Extended vertical Overflow register SR0A %02x\n", data); + m_ext_vert_overflow = data; + vga.crtc.vert_retrace_end = (vga.crtc.vert_retrace_end & 0xf) | ((data & 0x20) >> 1); + vga.crtc.vert_blank_end = (vga.crtc.vert_blank_end & 0x00ff) | ((data & 0x10) << 4); + vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0x03ff) | ((data & 0x08) << 7); + vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0x03ff) | ((data & 0x04) << 8); + vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0x03ff) | ((data & 0x02) << 9); + vga.crtc.vert_total = (vga.crtc.vert_total & 0x03ff) | ((data & 0x01) << 10); + recompute_params(); + }) + ); + map(0x0b, 0x0c).lr8( + NAME([this] (offs_t offset) { + return m_ext_horz_overflow[offset]; + }) + ); + map(0x0b, 0x0b).lw8( + NAME([this] (offs_t offset, u8 data) { + //m_dual_seg_mode = bool(BIT(data, 3)); + LOG("Extended horizontal Overflow 1 SR0B %02x\n", data); + m_ext_horz_overflow[0] = data; + + vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0x00ff) | ((data & 0xc0) << 2); + vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0x00ff) | ((data & 0x30) << 4); + vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0x00ff) | ((data & 0x0c) << 6); + vga.crtc.horz_total = (vga.crtc.horz_total & 0x00ff) | ((data & 0x03) << 8); + + recompute_params(); + }) + ); + map(0x0c, 0x0c).lw8( + NAME([this] (offs_t offset, u8 data) { + LOG("Extended horizontal Overflow 2 SR0C %02x\n", data); + m_ext_horz_overflow[1] = data; + + vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0x001f) | ((data & 0x04) << 3); + vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0x003f) | ((data & 0x03) << 6); + recompute_params(); + }) + ); + map(0x0d, 0x0d).lrw8( + NAME([this] (offs_t offset) { + return vga.crtc.start_addr_latch >> 16; + }), + NAME([this] (offs_t offset, u8 data) { + LOG("Extended starting address register SR0D %02x\n", data); + vga.crtc.start_addr_latch &= ~0xff0000; + vga.crtc.start_addr_latch |= data << 16; + }) + ); + map(0x0e, 0x0e).lw8( + NAME([this] (offs_t offset, u8 data) { + LOG("Extended pitch register SR0E %02x\n", data); + // sis_main.c implicitly sets this with bits 0-3 granularity, assume being right + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x0f) << 8); + }) + ); + map(0x14, 0x14).lrw8( + NAME([this] (offs_t offset) { + // sis_main.c calculates VRAM size in two ways: + // 1. the legacy way ('300), by probing this register + // 2. by reading '630 PCI host register $63 (as shared DRAM?) + // Method 1 seems enough to enforce "64MB" message at POST, + // 2 is probably more correct but unsure about how to change the shared area in BIOS + // (shutms11 will always write a "0x41" on fresh CMOS then a "0x47" + // on successive boots no matter what) + return (m_bus_width) | ((vga.svga_intf.vram_size / (1024 * 1024) - 1) & 0x3f); + }), + NAME([this] (offs_t offset, u8 data) { + m_bus_width = data & 0xc0; + }) + ); + map(0x1e, 0x1e).lw8( + NAME([this] (offs_t offset, u8 data) { + if (BIT(data, 6)) + popmessage("Warning: enable 2d engine"); + }) + ); + map(0x20, 0x20).lw8( + NAME([this] (offs_t offset, u8 data) { + if (data & 0x81) + popmessage("Warning: %s %s", BIT(data, 7) ? "PCI address enabled" : "", BIT(data, 0) ? "memory map I/O enable" : ""); + }) + ); +} + +std::tuple sis630_svga_device::flush_true_color_mode() +{ + // punt if extended or true color is off + if ((m_ramdac_mode & 0x12) != 0x12) + return std::make_tuple(0, 0); + + const u8 res = (m_ext_misc_ctrl_0 & 4) >> 2; + + return std::make_tuple(res, res ^ 1); +} + +void sis630_svga_device::recompute_params() +{ + // TODO: ext clock + recompute_params_clock(1, XTAL(25'174'800).value()); +} + +uint16_t sis630_svga_device::offset() +{ + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) + return vga.crtc.offset << 3; + return svga_device::offset(); +} + +uint8_t sis630_svga_device::mem_r(offs_t offset) +{ + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) + return svga_device::mem_linear_r(offset + svga.bank_r * 0x10000); + return svga_device::mem_r(offset); +} + +void sis630_svga_device::mem_w(offs_t offset, uint8_t data) +{ + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) + { + svga_device::mem_linear_w(offset + svga.bank_w * 0x10000, data); + return; + } + svga_device::mem_w(offset, data); +} diff --git a/src/devices/video/pc_vga_sis.h b/src/devices/video/pc_vga_sis.h new file mode 100644 index 00000000000..4d410b20dfa --- /dev/null +++ b/src/devices/video/pc_vga_sis.h @@ -0,0 +1,44 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese + +#ifndef MAME_VIDEO_SIS_H +#define MAME_VIDEO_SIS_H + +#pragma once + +#include "video/pc_vga.h" + +class sis630_svga_device : public svga_device +{ +public: + sis630_svga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual uint8_t mem_r(offs_t offset) override; + virtual void mem_w(offs_t offset, uint8_t data) override; + +protected: + virtual void device_start() override; + virtual void device_reset() override; + + virtual void io_3cx_map(address_map &map) override; + + virtual void crtc_map(address_map &map) override; + virtual void sequencer_map(address_map &map) override; + + virtual uint16_t offset() override; + virtual void recompute_params() override; + + u8 m_ramdac_mode = 0; + u8 m_ext_misc_ctrl_0 = 0; + u8 m_ext_vert_overflow = 0; + u8 m_ext_horz_overflow[2]{}; + u8 m_bus_width = 0; + bool m_unlock_reg = false; + + std::tuple flush_true_color_mode(); +// bool m_dual_seg_mode = false; +}; + +DECLARE_DEVICE_TYPE(SIS630_SVGA, sis630_svga_device) + +#endif // MAME_VIDEO_SIS_H diff --git a/src/devices/video/pc_vga_trident.cpp b/src/devices/video/pc_vga_trident.cpp index 53d34ea571d..9ef9e55bc19 100644 --- a/src/devices/video/pc_vga_trident.cpp +++ b/src/devices/video/pc_vga_trident.cpp @@ -10,7 +10,7 @@ * - TVGA8800 early SVGA * - TVGA8900 (2MB VRAM) * - TVGA9000 needs to be downgraded from '9680 - * \- none of the SVGA modes works + * \- none of the SVGA modes works properly; * \- subclassed from TGUI9680 just for pntnpuzl, consider swapping inheritance or even decouple; * \- it's also really a downgraded version of '8900 * - TVGA92xx, TVGA938x (2d accelerator) @@ -47,6 +47,10 @@ DEFINE_DEVICE_TYPE(TVGA9000_VGA, tvga9000_device, "tvga9000_vga", "Trident TVGA9 trident_vga_device::trident_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : svga_device(mconfig, type, tag, owner, clock) { + m_main_if_space_config = address_space_config("io_regs", ENDIANNESS_LITTLE, 8, 4, 0, address_map_constructor(FUNC(trident_vga_device::io_3bx_3dx_map), this)); + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(trident_vga_device::crtc_map), this)); + m_gc_space_config = address_space_config("gc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(trident_vga_device::gc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(trident_vga_device::sequencer_map), this)); } tgui9860_device::tgui9860_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) @@ -61,6 +65,543 @@ tvga9000_device::tvga9000_device(const machine_config &mconfig, const char *tag, m_version = 0x43; } +void trident_vga_device::io_3cx_map(address_map &map) +{ + svga_device::io_3cx_map(map); + map(0x06, 0x06).rw(FUNC(trident_vga_device::ramdac_hidden_mask_r), FUNC(trident_vga_device::ramdac_hidden_mask_w)); + map(0x07, 0x09).rw(FUNC(trident_vga_device::ramdac_overlay_r), FUNC(trident_vga_device::ramdac_overlay_w)); +} + +u8 trident_vga_device::ramdac_hidden_mask_r(offs_t offset) +{ + if (!machine().side_effects_disabled()) + tri.dac_count++; + if(tri.dac_count > 3) + tri.dac_active = true; + if(tri.dac_active) + return tri.dac; + + return vga_device::ramdac_mask_r(offset); +} + +void trident_vga_device::ramdac_hidden_mask_w(offs_t offset, u8 data) +{ + if(tri.dac_active) + { + tri.dac = data; // DAC command register + tri.dac_active = false; + tri.dac_count = 0; + recompute_params(); + return; + } + + vga_device::ramdac_mask_w(offset, data); +} + +u8 trident_vga_device::ramdac_overlay_r(offs_t offset) +{ + if (!machine().side_effects_disabled()) + { + tri.dac_active = false; + tri.dac_count = 0; + } + + switch(offset) + { + case 0: + return vga_device::ramdac_state_r(0); + case 1: + return vga_device::ramdac_write_index_r(0); + case 2: + return vga_device::ramdac_data_r(0); + } + + return space().unmap(); +} + +void trident_vga_device::ramdac_overlay_w(offs_t offset, u8 data) +{ + tri.dac_active = false; + tri.dac_count = 0; + + switch(offset) + { + case 0: + vga_device::ramdac_read_index_w(0, data); + break; + case 1: + vga_device::ramdac_write_index_w(0, data); + break; + case 2: + vga_device::ramdac_data_w(0, data); + break; + } +} + +void trident_vga_device::io_3bx_3dx_map(address_map &map) +{ + svga_device::io_3bx_3dx_map(map); + map(0x08, 0x08).rw(FUNC(trident_vga_device::svga_bank_write_r), FUNC(trident_vga_device::svga_bank_write_w)); + map(0x09, 0x09).rw(FUNC(trident_vga_device::svga_bank_read_r), FUNC(trident_vga_device::svga_bank_read_w)); + // no info on this port + // Bit 5 appears to be a clock divider + map(0x0b, 0x0b).lrw8( + NAME([this] (offs_t offset) { + return tri.port_3db; + }), + NAME([this] (offs_t offset, u8 data) { + tri.port_3db = data; + recompute_params(); + }) + ); +} + +u8 trident_vga_device::svga_bank_write_r(offs_t offset) +{ + // if enabled + if(tri.gc0f & 0x04) + return svga.bank_w & 0x3f; + + return space().unmap(); +} + +void trident_vga_device::svga_bank_write_w(offs_t offset, u8 data) +{ + // if enabled + if(tri.gc0f & 0x04) + { + svga.bank_w = data & 0x3f; + LOG("Trident: Write Bank set to %02x\n",data); + // if bank regs are not separated ... + if(!(tri.gc0f & 0x01)) + { + // ... then this is also the read bank register + svga.bank_r = data & 0x3f; + LOG("Trident: Read Bank set to %02x\n",data); + } + } +} + +u8 trident_vga_device::svga_bank_read_r(offs_t offset) +{ + // if enabled & if bank regs are separated + if(tri.gc0f & 0x04) + return svga.bank_r & 0x3f; + + return space().unmap(); +} + +void trident_vga_device::svga_bank_read_w(offs_t offset, u8 data) +{ + // if enabled & if bank regs are separated + if(tri.gc0f & 0x04 && tri.gc0f & 0x01) + { + svga.bank_r = data & 0x3f; + LOG("Trident: Read Bank set to %02x\n",data); + } +} + +void trident_vga_device::crtc_map(address_map &map) +{ + svga_device::crtc_map(map); + // Module Testing Register + map(0x1e, 0x1e).lrw8( + NAME([this] (offs_t offset) { + return tri.cr1e; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cr1e = data; + vga.crtc.start_addr = (vga.crtc.start_addr & 0xfffeffff) | ((data & 0x20)<<11); + recompute_params(); + }) + ); + // "Software Programming Register" written to by the BIOS + map(0x1f, 0x1f).lrw8( + NAME([this] (offs_t offset) { + return tri.cr1f; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cr1f = data; + }) + ); + // FIFO Control (old MMIO enable? no documentation of this register) + map(0x20, 0x20).lrw8( + NAME([this] (offs_t offset) { + return tri.cr20; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cr20 = data; + }) + ); + // Linear aperture + map(0x21, 0x21).lrw8( + NAME([this] (offs_t offset) { + return tri.cr21; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cr21 = data; + tri.linear_address = ((data & 0xc0)<<18) | ((data & 0x0f)<<20); + tri.linear_active = data & 0x20; + if(tri.linear_active) + popmessage("Trident: Linear Aperture active - %08x, %s",tri.linear_address,(tri.cr21 & 0x10) ? "2MB" : "1MB" ); + }) + ); + map(0x27, 0x27).lrw8( + NAME([this] (offs_t offset) { + return (vga.crtc.start_addr & 0x60000) >> 17; + }), + NAME([this] (offs_t offset, u8 data) { + vga.crtc.start_addr = (vga.crtc.start_addr & 0xfff9ffff) | ((data & 0x03)<<17); + }) + ); + map(0x29, 0x29).lrw8( + NAME([this] (offs_t offset) { + return tri.cr29; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cr29 = data; + vga.crtc.offset = (vga.crtc.offset & 0xfeff) | ((data & 0x10)<<4); + }) + ); + map(0x2a, 0x2a).lrw8( + NAME([this] (offs_t offset) { + return tri.cr2a; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cr2a = data; + }) + ); + map(0x38, 0x38).lrw8( + NAME([this] (offs_t offset) { + return tri.pixel_depth; + }), + NAME([this] (offs_t offset, u8 data) { + // bit 0: 16 bit bus + // bits 2-3: pixel depth (1=15/16bit, 2=24/32bit, 0=anything else) + // bit 5: packed mode + tri.pixel_depth = data; + recompute_params(); + }) + ); + map(0x39, 0x39).lrw8( + NAME([this] (offs_t offset) { + return tri.cr39; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cr39 = data; + tri.mmio_active = data & 0x01; + if(tri.mmio_active) + popmessage("Trident: MMIO activated"); + }) + ); + map(0x40, 0x40).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_x & 0x00ff); + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_x = (tri.cursor_x & 0xff00) | data; + }) + ); + map(0x41, 0x41).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_x & 0xff00) >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_x = (tri.cursor_x & 0x00ff) | (data << 8); + }) + ); + map(0x42, 0x42).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_y & 0x00ff); + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_y = (tri.cursor_y & 0xff00) | data; + }) + ); + map(0x43, 0x43).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_y & 0xff00) >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_y = (tri.cursor_y & 0x00ff) | (data << 8); + }) + ); + map(0x44, 0x44).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_loc & 0x00ff); + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_loc = (tri.cursor_loc & 0xff00) | data; + }) + ); + map(0x45, 0x45).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_loc & 0xff00) >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_loc = (tri.cursor_loc & 0x00ff) | (data << 8); + }) + ); + map(0x46, 0x46).lrw8( + NAME([this] (offs_t offset) { + return tri.cursor_x_off; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_x_off = data; + }) + ); + map(0x47, 0x47).lrw8( + NAME([this] (offs_t offset) { + return tri.cursor_y_off; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_y_off = data; + }) + ); + map(0x48, 0x48).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_fg & 0x000000ff); + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_fg = (tri.cursor_fg & 0xffffff00) | data; + }) + ); + map(0x49, 0x49).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_fg & 0x0000ff00) >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_fg = (tri.cursor_fg & 0xffff00ff) | (data << 8); + }) + ); + map(0x4a, 0x4a).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_fg & 0x00ff0000) >> 16; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_fg = (tri.cursor_fg & 0xff00ffff) | (data << 16); + }) + ); + map(0x4b, 0x4b).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_fg & 0xff000000) >> 24; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_fg = (tri.cursor_fg & 0x00ffffff) | (data << 24); + }) + ); + map(0x4c, 0x4c).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_bg & 0x000000ff); + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_bg = (tri.cursor_bg & 0xffffff00) | data; + }) + ); + map(0x4d, 0x4d).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_bg & 0x0000ff00) >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_bg = (tri.cursor_bg & 0xffff00ff) | (data << 8); + }) + ); + map(0x4e, 0x4e).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_bg & 0x00ff0000) >> 16; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_bg = (tri.cursor_bg & 0xff00ffff) | (data << 16); + }) + ); + map(0x4f, 0x4f).lrw8( + NAME([this] (offs_t offset) { + return (tri.cursor_bg & 0xff000000) >> 24; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_bg = (tri.cursor_bg & 0x00ffffff) | (data << 24); + }) + ); + map(0x50, 0x50).lrw8( + NAME([this] (offs_t offset) { + return tri.cursor_ctrl; + }), + NAME([this] (offs_t offset, u8 data) { + tri.cursor_ctrl = data; + }) + ); +} + +void trident_vga_device::gc_map(address_map &map) +{ + svga_device::gc_map(map); + // New Source Address Register (bit 1 is inverted here, also) + map(0x0e, 0x0e).lrw8( + NAME([this] (offs_t offset) { + return tri.gc0e; + }), + NAME([this] (offs_t offset, u8 data) { + tri.gc0e = data ^ 0x02; + if(!(tri.gc0f & 0x04)) // if bank regs at 0x3d8/9 are not enabled + { + if(tri.gc0f & 0x01) // if bank regs are separated + svga.bank_r = (data & 0x1f) ^ 0x02; + } + }) + ); + map(0x0f, 0x0f).lrw8( + NAME([this] (offs_t offset) { + return tri.gc0f; + }), + NAME([this] (offs_t offset, u8 data) { + tri.gc0f = data; + recompute_params(); + }) + ); + // XFree86 refers to this register as "MiscIntContReg", setting bit 2, but gives no indication as to what it does + map(0x2f, 0x2f).lrw8( + NAME([this] (offs_t offset) { + return tri.gc2f; + }), + NAME([this] (offs_t offset, u8 data) { + tri.gc2f = data; + }) + ); +} + +void trident_vga_device::sequencer_map(address_map &map) +{ + svga_device::sequencer_map(map); + map(0x09, 0x09).lr8( + NAME([this] (offs_t offset) { + return tri.revision; + }) + ); + map(0x0b, 0x0b).lrw8( + NAME([this] (offs_t offset) { + if (!machine().side_effects_disabled()) + tri.new_mode = true; + return svga.id; + }), + NAME([this] (offs_t offset, u8 data) { + tri.new_mode = false; + }) + ); + // Power Up Mode register 1 + map(0x0c, 0x0c).lrw8( + NAME([this] (offs_t offset) { + u8 res = tri.sr0c & 0xef; + if(tri.port_3c3) + res |= 0x10; + return res; + }), + NAME([this] (offs_t offset, u8 data) { + // ---1 ---- 'post port at 0x3c3' + // ---0 ---- 'post port at 0x46e8' + tri.port_3c3 = bool(BIT(data, 4)); + tri.sr0c = data; + }) + ); + // Mode Control 2 + map(0x0d, 0x0d).lrw8( + NAME([this] (offs_t offset) { + return (tri.new_mode) ? tri.sr0d_new : tri.sr0d_old; + }), + NAME([this] (offs_t offset, u8 data) { + if(tri.new_mode) + { + tri.sr0d_new = data; + tri.clock = ((vga.miscellaneous_output & 0x0c) >> 2) | ((data & 0x01) << 2) | ((data & 0x40) >> 3); + recompute_params(); + } + else + tri.sr0d_old = data; + }) + ); + // Mode Control 1 + map(0x0e, 0x0e).lrw8( + NAME([this] (offs_t offset) { + return (tri.new_mode) ? tri.sr0e_new : tri.sr0e_old; + }), + NAME([this] (offs_t offset, u8 data) { + if(tri.new_mode) + { + tri.sr0e_new = data ^ 0x02; + svga.bank_w = (data & 0x3f) ^ 0x02; // bit 1 is inverted, used for card detection, it is not XORed on reading + if(!(tri.gc0f & 0x01)) + svga.bank_r = (data & 0x3f) ^ 0x02; + // TODO: handle planar modes, where bits 0 and 2 only are used + } + else + { + tri.sr0e_old = data; + svga.bank_w = data & 0x0e; + if(!(tri.gc0f & 0x01)) + svga.bank_r = data & 0x0e; + } + }) + ); + // Power Up Mode 2 + map(0x0f, 0x0f).lrw8( + NAME([this] (offs_t offset) { + return tri.sr0f; + }), + NAME([this] (offs_t offset, u8 data) { + tri.sr0f = data; + }) + ); +} + +void trident_vga_device::device_start() +{ + zero(); + + for (int i = 0; i < 0x100; i++) + set_pen_color(i, 0, 0, 0); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + + // copy over interfaces + vga.memory = std::make_unique(vga.svga_intf.vram_size); + memset(&vga.memory[0], 0, vga.svga_intf.vram_size); + + save_pointer(NAME(vga.memory), vga.svga_intf.vram_size); + save_pointer(vga.crtc.data,"CRTC Registers",0x100); + save_pointer(vga.sequencer.data,"Sequencer Registers",0x100); + save_pointer(vga.attribute.data,"Attribute Registers", 0x15); + save_pointer(tri.accel_pattern,"Pattern Data", 0x80); + save_pointer(tri.lutdac_reg,"LUTDAC registers", 0x100); + + m_vblank_timer = timer_alloc(FUNC(vga_device::vblank_timer_cb), this); + svga.ignore_chain4 = true; + memset(&tri, 0, sizeof(tri)); +} + +void trident_vga_device::device_reset() +{ + svga_device::device_reset(); + svga.id = m_version; + tri.revision = 0x01; // revision identifies as TGUI9680 + tri.new_mode = false; // start up in old mode + tri.dac_active = false; + tri.linear_active = false; + tri.mmio_active = false; + tri.sr0f = 0x6f; + tri.sr0c = 0x70; + tri.cr2a = 0x03; // set ISA interface? + tri.mem_clock = 0x2c6; // 50MHz default + tri.vid_clock = 0; + tri.port_3c3 = true; + tri.accel_busy = false; + tri.accel_memwrite_active = false; + // Windows 3.1 TGUI9440AGi drivers do not set the pointer colour registers? + tri.cursor_bg = 0x00000000; + tri.cursor_fg = 0xffffffff; + tri.pixel_depth = 0x10; //disable 8bpp mode by default +} + uint8_t trident_vga_device::READPIXEL8(int16_t x, int16_t y) { return (vga.memory[((y & 0xfff)*offset() + (x & 0xfff)) % vga.svga_intf.vram_size]); @@ -176,59 +717,6 @@ void trident_vga_device::WRITEPIXEL(int16_t x,int16_t y, uint32_t data) WRITEPIXEL32(x,y,data); } - -void trident_vga_device::device_start() -{ - zero(); - - for (int i = 0; i < 0x100; i++) - set_pen_color(i, 0, 0, 0); - - // Avoid an infinite loop when displaying. 0 is not possible anyway. - vga.crtc.maximum_scan_line = 1; - - - // copy over interfaces - vga.memory = std::make_unique(vga.svga_intf.vram_size); - memset(&vga.memory[0], 0, vga.svga_intf.vram_size); - - save_pointer(NAME(vga.memory), vga.svga_intf.vram_size); - save_pointer(vga.crtc.data,"CRTC Registers",0x100); - save_pointer(vga.sequencer.data,"Sequencer Registers",0x100); - save_pointer(vga.attribute.data,"Attribute Registers", 0x15); - save_pointer(tri.accel_pattern,"Pattern Data", 0x80); - save_pointer(tri.lutdac_reg,"LUTDAC registers", 0x100); - - m_vblank_timer = timer_alloc(FUNC(vga_device::vblank_timer_cb), this); - vga.svga_intf.seq_regcount = 0x0f; - vga.svga_intf.crtc_regcount = 0x60; - svga.ignore_chain4 = true; - memset(&tri, 0, sizeof(tri)); -} - -void trident_vga_device::device_reset() -{ - svga_device::device_reset(); - svga.id = m_version; - tri.revision = 0x01; // revision identifies as TGUI9680 - tri.new_mode = false; // start up in old mode - tri.dac_active = false; - tri.linear_active = false; - tri.mmio_active = false; - tri.sr0f = 0x6f; - tri.sr0c = 0x70; - tri.cr2a = 0x03; // set ISA interface? - tri.mem_clock = 0x2c6; // 50MHz default - tri.vid_clock = 0; - tri.port_3c3 = true; - tri.accel_busy = false; - tri.accel_memwrite_active = false; - // Windows 3.1 TGUI9440AGi drivers do not set the pointer colour registers? - tri.cursor_bg = 0x00000000; - tri.cursor_fg = 0xffffffff; - tri.pixel_depth = 0x10; //disable 8bpp mode by default -} - uint32_t trident_vga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) { svga_device::screen_update(screen,bitmap,cliprect); @@ -349,7 +837,7 @@ int trident_vga_device::calculate_clock() return freq * 1000000; } -void trident_vga_device::trident_define_video_mode() +void trident_vga_device::recompute_params() { int divisor = 1; int xtal; @@ -416,543 +904,6 @@ void trident_vga_device::trident_define_video_mode() recompute_params_clock(divisor, xtal); } -uint8_t trident_vga_device::trident_seq_reg_read(uint8_t index) -{ - uint8_t res; - - res = 0xff; - - if(index <= 0x04) - res = vga.sequencer.data[index]; - else - { - switch(index) - { - case 0x09: - res = tri.revision; - break; - case 0x0b: - res = svga.id; - tri.new_mode = true; - break; - case 0x0c: // Power Up Mode register 1 - res = tri.sr0c & 0xef; - if(tri.port_3c3) - res |= 0x10; - break; - case 0x0d: // Mode Control 2 - //res = svga.rgb15_en; - if(tri.new_mode) - res = tri.sr0d_new; - else - res = tri.sr0d_old; - break; - case 0x0e: // Mode Control 1 - if(tri.new_mode) - res = tri.sr0e_new; - else - res = tri.sr0e_old; - break; - case 0x0f: // Power Up Mode 2 - res = tri.sr0f; - break; - default: - res = vga.sequencer.data[index]; - LOGWARN("Trident: Sequencer index %02x read\n",index); - } - } - LOG("Trident SR%02X: read %02x\n",index,res); - return res; -} - -void trident_vga_device::trident_seq_reg_write(uint8_t index, uint8_t data) -{ - vga.sequencer.data[vga.sequencer.index] = data; - if(index <= 0x04) - { - seq_reg_write(vga.sequencer.index,data); - recompute_params(); - } - else - { - switch(index) - { - case 0x0b: - tri.new_mode = false; - break; - case 0x0c: // Power Up Mode register 1 - if(data & 0x10) - tri.port_3c3 = true; // 'post port at 0x3c3' - else - tri.port_3c3 = false; // 'post port at 0x46e8' - tri.sr0c = data; - break; - case 0x0d: // Mode Control 2 - if(tri.new_mode) - { - tri.sr0d_new = data; - tri.clock = ((vga.miscellaneous_output & 0x0c) >> 2) | ((data & 0x01) << 2) | ((data & 0x40) >> 3); - trident_define_video_mode(); - } - else - tri.sr0d_old = data; - break; - case 0x0e: // Mode Control 1 - if(tri.new_mode) - { - tri.sr0e_new = data ^ 0x02; - svga.bank_w = (data & 0x3f) ^ 0x02; // bit 1 is inverted, used for card detection, it is not XORed on reading - if(!(tri.gc0f & 0x01)) - svga.bank_r = (data & 0x3f) ^ 0x02; - // TODO: handle planar modes, where bits 0 and 2 only are used - } - else - { - tri.sr0e_old = data; - svga.bank_w = data & 0x0e; - if(!(tri.gc0f & 0x01)) - svga.bank_r = data & 0x0e; - } - break; - case 0x0f: // Power Up Mode 2 - tri.sr0f = data; - break; - default: - LOGWARN("Trident: Sequencer index %02x read\n",index); - } - } - LOG("Trident SR%02X: %s mode write %02x\n",index,tri.new_mode ? "new" : "old",data); -} - -uint8_t trident_vga_device::trident_crtc_reg_read(uint8_t index) -{ - uint8_t res = 0; - - if(index <= 0x18) - res = crtc_reg_read(index); - else - { - switch(index) - { - case 0x1e: - res = tri.cr1e; - break; - case 0x1f: - res = tri.cr1f; - break; - case 0x20: - res = tri.cr20; - break; - case 0x21: - res = tri.cr21; - break; - case 0x24: - if(vga.attribute.state != 0) - res |= 0x80; - break; - case 0x26: - res = vga.attribute.index; - break; - case 0x27: - res = (vga.crtc.start_addr & 0x60000) >> 17; - break; - case 0x29: - res = tri.cr29; - break; - case 0x2a: - res = tri.cr2a; - break; - case 0x38: - res = tri.pixel_depth; - break; - case 0x39: - res = tri.cr39; - break; - case 0x40: - res = (tri.cursor_x & 0x00ff); - break; - case 0x41: - res = (tri.cursor_x & 0xff00) >> 8; - break; - case 0x42: - res = (tri.cursor_y & 0x00ff); - break; - case 0x43: - res = (tri.cursor_y & 0xff00) >> 8; - break; - case 0x44: - res = (tri.cursor_loc & 0x00ff); - break; - case 0x45: - res = (tri.cursor_loc & 0xff00) >> 8; - break; - case 0x46: - res = tri.cursor_x_off; - break; - case 0x47: - res = tri.cursor_y_off; - break; - case 0x48: - res = (tri.cursor_fg & 0x000000ff); - break; - case 0x49: - res = (tri.cursor_fg & 0x0000ff00) >> 8; - break; - case 0x4a: - res = (tri.cursor_fg & 0x00ff0000) >> 16; - break; - case 0x4b: - res = (tri.cursor_fg & 0xff000000) >> 24; - break; - case 0x4c: - res = (tri.cursor_bg & 0x000000ff); - break; - case 0x4d: - res = (tri.cursor_bg & 0x0000ff00) >> 8; - break; - case 0x4e: - res = (tri.cursor_bg & 0x00ff0000) >> 16; - break; - case 0x4f: - res = (tri.cursor_bg & 0xff000000) >> 24; - break; - case 0x50: - res = tri.cursor_ctrl; - break; - default: - res = vga.crtc.data[index]; - LOGWARN("Trident: CRTC index %02x read\n",index); - break; - } - } - LOG("Trident CR%02X: read %02x\n",index,res); - return res; -} -void trident_vga_device::trident_crtc_reg_write(uint8_t index, uint8_t data) -{ - if(index <= 0x18) - { - crtc_reg_write(index,data); - trident_define_video_mode(); - } - else - { - switch(index) - { - case 0x1e: // Module Testing Register - tri.cr1e = data; - vga.crtc.start_addr = (vga.crtc.start_addr & 0xfffeffff) | ((data & 0x20)<<11); - trident_define_video_mode(); - break; - case 0x1f: - tri.cr1f = data; // "Software Programming Register" written to by the BIOS - break; - case 0x20: // FIFO Control (old MMIO enable? no documentation of this register) - tri.cr20 = data; - break; - case 0x21: // Linear aperture - tri.cr21 = data; - tri.linear_address = ((data & 0xc0)<<18) | ((data & 0x0f)<<20); - tri.linear_active = data & 0x20; - if(tri.linear_active) - popmessage("Trident: Linear Aperture active - %08x, %s",tri.linear_address,(tri.cr21 & 0x10) ? "2MB" : "1MB" ); - break; - case 0x27: - vga.crtc.start_addr = (vga.crtc.start_addr & 0xfff9ffff) | ((data & 0x03)<<17); - break; - case 0x29: - tri.cr29 = data; - vga.crtc.offset = (vga.crtc.offset & 0xfeff) | ((data & 0x10)<<4); - break; - case 0x2a: - tri.cr2a = data; - break; - case 0x38: - // bit 0: 16 bit bus - // bits 2-3: pixel depth (1=15/16bit, 2=24/32bit, 0=anything else) - // bit 5: packed mode - tri.pixel_depth = data; - trident_define_video_mode(); - break; - case 0x39: - tri.cr39 = data; - tri.mmio_active = data & 0x01; - if(tri.mmio_active) - popmessage("Trident: MMIO activated"); - break; - case 0x40: - tri.cursor_x = (tri.cursor_x & 0xff00) | data; - break; - case 0x41: - tri.cursor_x = (tri.cursor_x & 0x00ff) | (data << 8); - break; - case 0x42: - tri.cursor_y = (tri.cursor_y & 0xff00) | data; - break; - case 0x43: - tri.cursor_y = (tri.cursor_y & 0x00ff) | (data << 8); - break; - case 0x44: - tri.cursor_loc = (tri.cursor_loc & 0xff00) | data; - break; - case 0x45: - tri.cursor_loc = (tri.cursor_loc & 0x00ff) | (data << 8); - break; - case 0x46: - tri.cursor_x_off = data; - break; - case 0x47: - tri.cursor_y_off = data; - break; - case 0x48: - tri.cursor_fg = (tri.cursor_fg & 0xffffff00) | data; - break; - case 0x49: - tri.cursor_fg = (tri.cursor_fg & 0xffff00ff) | (data << 8); - break; - case 0x4a: - tri.cursor_fg = (tri.cursor_fg & 0xff00ffff) | (data << 16); - break; - case 0x4b: - tri.cursor_fg = (tri.cursor_fg & 0x00ffffff) | (data << 24); - break; - case 0x4c: - tri.cursor_bg = (tri.cursor_bg & 0xffffff00) | data; - break; - case 0x4d: - tri.cursor_bg = (tri.cursor_bg & 0xffff00ff) | (data << 8); - break; - case 0x4e: - tri.cursor_bg = (tri.cursor_bg & 0xff00ffff) | (data << 16); - break; - case 0x4f: - tri.cursor_bg = (tri.cursor_bg & 0x00ffffff) | (data << 24); - break; - case 0x50: - tri.cursor_ctrl = data; - break; - default: - LOGWARN("Trident: 3D4 index %02x write %02x\n",index,data); - break; - } - } - LOG("Trident CR%02X: write %02x\n",index,data); -} - -uint8_t trident_vga_device::trident_gc_reg_read(uint8_t index) -{ - uint8_t res; - - if(index <= 0x0d) - res = gc_reg_read(index); - else - { - switch(index) - { - case 0x0e: - res = tri.gc0e; - break; - case 0x0f: - res = tri.gc0f; - break; - case 0x2f: - res = tri.gc2f; - break; - default: - res = 0xff; - LOGWARN("Trident: Sequencer index %02x read\n",index); - break; - } - } - LOG("Trident GC%02X: read %02x\n",index,res); - return res; -} - -void trident_vga_device::trident_gc_reg_write(uint8_t index, uint8_t data) -{ - if(index <= 0x0d) - gc_reg_write(index,data); - else - { - LOG("Trident GC%02X: write %02x\n",index,data); - switch(index) - { - case 0x0e: // New Source Address Register (bit 1 is inverted here, also) - tri.gc0e = data ^ 0x02; - if(!(tri.gc0f & 0x04)) // if bank regs at 0x3d8/9 are not enabled - { - if(tri.gc0f & 0x01) // if bank regs are separated - svga.bank_r = (data & 0x1f) ^ 0x02; - } - break; - case 0x0f: - tri.gc0f = data; - trident_define_video_mode(); - break; - case 0x2f: // XFree86 refers to this register as "MiscIntContReg", setting bit 2, but gives no indication as to what it does - tri.gc2f = data; - break; - default: - LOGWARN("Trident: Unimplemented GC register %02x write %02x\n",index,data); - break; - } - } - LOG("Trident GC%02X: write %02x\n",index,data); -} - -uint8_t trident_vga_device::port_03c0_r(offs_t offset) -{ - uint8_t res; - - switch(offset) - { - case 0x05: - res = trident_seq_reg_read(vga.sequencer.index); - break; - case 0x06: - tri.dac_count++; - if(tri.dac_count > 3) - tri.dac_active = true; - if(tri.dac_active) - res = tri.dac; - else - res = vga_device::port_03c0_r(offset); - break; - case 0x07: - case 0x08: - case 0x09: - tri.dac_active = false; - tri.dac_count = 0; - res = vga_device::port_03c0_r(offset); - break; - case 0x0f: - res = trident_gc_reg_read(vga.gc.index); - break; - default: - res = vga_device::port_03c0_r(offset); - break; - } - - return res; -} - -void trident_vga_device::port_03c0_w(offs_t offset, uint8_t data) -{ - switch(offset) - { - case 0x05: - trident_seq_reg_write(vga.sequencer.index,data); - break; - case 0x06: - if(tri.dac_active) - { - tri.dac = data; // DAC command register - tri.dac_active = false; - tri.dac_count = 0; - trident_define_video_mode(); - } - else - vga_device::port_03c0_w(offset,data); - break; - case 0x07: - case 0x08: - case 0x09: - tri.dac_active = false; - tri.dac_count = 0; - vga_device::port_03c0_w(offset,data); - break; - case 0x0f: - trident_gc_reg_write(vga.gc.index,data); - break; - default: - vga_device::port_03c0_w(offset,data); - break; - } -} - - -uint8_t trident_vga_device::port_03d0_r(offs_t offset) -{ - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - res = trident_crtc_reg_read(vga.crtc.index); - break; - case 8: - if(tri.gc0f & 0x04) // if enabled - { - res = svga.bank_w & 0x3f; - } - else - res = 0xff; - break; - case 9: - if(tri.gc0f & 0x04) // if enabled - if(tri.gc0f & 0x01) // and if bank regs are separated - res = svga.bank_r & 0x3f; - else - res = 0xff; - else - res = 0xff; - break; - case 11: - res = tri.port_3db; - break; - default: - res = vga_device::port_03d0_r(offset); - break; - } - } - - return res; -} - -void trident_vga_device::port_03d0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - vga.crtc.data[vga.crtc.index] = data; - trident_crtc_reg_write(vga.crtc.index,data); - break; - case 8: - if(tri.gc0f & 0x04) // if enabled - { - svga.bank_w = data & 0x3f; - LOG("Trident: Write Bank set to %02x\n",data); - if(!(tri.gc0f & 0x01)) // if bank regs are not separated - { - svga.bank_r = data & 0x3f; // then this is also the read bank register - LOG("Trident: Read Bank set to %02x\n",data); - } - } - break; - case 9: - if(tri.gc0f & 0x04) // if enabled - { - if(tri.gc0f & 0x01) // and if bank regs are separated - { - svga.bank_r = data & 0x3f; - LOG("Trident: Read Bank set to %02x\n",data); - } - } - break; - case 11: - tri.port_3db = data; // no info on this port? Bit 5 appears to be a clock divider... - break; - default: - vga_device::port_03d0_w(offset,data); - break; - } - } -} - uint8_t trident_vga_device::port_43c6_r(offs_t offset) { uint8_t res = 0xff; @@ -1647,7 +1598,7 @@ void trident_vga_device::accel_data_write(uint32_t data) // tvga9000 CRTC override // not extensively tested, just enough for pntnpuzl to not throw a 168 Hz refresh rate. -void tvga9000_device::trident_define_video_mode() +void tvga9000_device::recompute_params() { int divisor = 1; int xtal; diff --git a/src/devices/video/pc_vga_trident.h b/src/devices/video/pc_vga_trident.h index c0c72b0b939..6a1f6b97984 100644 --- a/src/devices/video/pc_vga_trident.h +++ b/src/devices/video/pc_vga_trident.h @@ -17,10 +17,6 @@ class trident_vga_device : public svga_device { public: - virtual uint8_t port_03c0_r(offs_t offset) override; - virtual void port_03c0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03d0_r(offs_t offset) override; - virtual void port_03d0_w(offs_t offset, uint8_t data) override; uint8_t port_83c6_r(offs_t offset); void port_83c6_w(offs_t offset, uint8_t data); uint8_t port_43c6_r(offs_t offset); @@ -43,6 +39,28 @@ protected: virtual void device_start() override; virtual void device_reset() override; + virtual void io_3bx_3dx_map(address_map &map) override; + virtual void io_3cx_map(address_map &map) override; + + u8 ramdac_hidden_mask_r(offs_t offset); + void ramdac_hidden_mask_w(offs_t offset, u8 data); + u8 ramdac_overlay_r(offs_t offset); + void ramdac_overlay_w(offs_t offset, u8 data); + + u8 svga_bank_write_r(offs_t offset); + void svga_bank_write_w(offs_t offset, u8 data); + u8 svga_bank_read_r(offs_t offset); + void svga_bank_read_w(offs_t offset, u8 data); + + + virtual void crtc_map(address_map &map) override; + virtual void sequencer_map(address_map &map) override; + virtual void gc_map(address_map &map) override; + + virtual void recompute_params() override; + + + // TODO: remove this leaky abstraction struct { uint8_t sr0c; @@ -117,13 +135,6 @@ protected: } tri; uint8_t m_version; private: - uint8_t trident_seq_reg_read(uint8_t index); - void trident_seq_reg_write(uint8_t index, uint8_t data); - virtual void trident_define_video_mode(); - uint8_t trident_crtc_reg_read(uint8_t index); - void trident_crtc_reg_write(uint8_t index, uint8_t data); - uint8_t trident_gc_reg_read(uint8_t index); - void trident_gc_reg_write(uint8_t index, uint8_t data); int calculate_clock(); @@ -162,7 +173,8 @@ public: tvga9000_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - virtual void trident_define_video_mode() override; +protected: + virtual void recompute_params() override; }; // device type definition diff --git a/src/devices/video/pc_vga_tseng.cpp b/src/devices/video/pc_vga_tseng.cpp index 6e4f7e8d7d8..5558a1d2f00 100644 --- a/src/devices/video/pc_vga_tseng.cpp +++ b/src/devices/video/pc_vga_tseng.cpp @@ -7,7 +7,7 @@ * - ET3000 (VGA only?) * - ET4000AX * \- No logging whatsoever; - * \- Unsupported True Color modes; + * \- Unsupported True Color modes, also "Return current video mode failed" in VESA24_2 test; * - ET4000/W32 (2d accelerator) * - ET4000/W32p (PCI version) * @@ -24,6 +24,10 @@ DEFINE_DEVICE_TYPE(TSENG_VGA, tseng_vga_device, "tseng_vga", "Tseng Labs ET40 tseng_vga_device::tseng_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : svga_device(mconfig, TSENG_VGA, tag, owner, clock) { + m_main_if_space_config = address_space_config("io_regs", ENDIANNESS_LITTLE, 8, 4, 0, address_map_constructor(FUNC(tseng_vga_device::io_3bx_3dx_map), this)); + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(tseng_vga_device::crtc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(tseng_vga_device::sequencer_map), this)); + m_atc_space_config = address_space_config("attribute_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(tseng_vga_device::attribute_map), this)); } void tseng_vga_device::device_start() @@ -41,213 +45,131 @@ void tseng_vga_device::device_start() save_item(NAME(et4k.misc2)); } -void tseng_vga_device::tseng_define_video_mode() +void tseng_vga_device::io_3bx_3dx_map(address_map &map) { - int divisor; - int xtal = 0; - svga.rgb8_en = 0; - svga.rgb15_en = 0; - svga.rgb16_en = 0; - svga.rgb24_en = 0; - switch(((et4k.aux_ctrl << 1) & 4)|(vga.miscellaneous_output & 0xc)>>2) - { - case 0: - xtal = XTAL(25'174'800).value(); - break; - case 1: - xtal = XTAL(28'636'363).value(); - break; - case 2: - xtal = 16257000*2; //2xEGA clock - break; - case 3: - xtal = XTAL(40'000'000).value(); - break; - case 4: - xtal = XTAL(36'000'000).value(); - break; - case 5: - xtal = XTAL(45'000'000).value(); - break; - case 6: - xtal = 31000000; - break; - case 7: - xtal = 38000000; - break; - } - switch(et4k.dac_ctrl & 0xe0) - { - case 0xa0: - svga.rgb15_en = 1; - divisor = 2; - break; - case 0xe0: - svga.rgb16_en = 1; - divisor = 2; - break; - case 0x60: - svga.rgb24_en = 1; - divisor = 3; - xtal *= 2.0f/3.0f; - break; - default: - svga.rgb8_en = (!(vga.sequencer.data[1] & 8) && (vga.sequencer.data[4] & 8) && vga.gc.shift256 && vga.crtc.div2 && GRAPHIC_MODE); - divisor = 1; - break; - } - recompute_params_clock(divisor, xtal); + svga_device::io_3bx_3dx_map(map); + map(0x08, 0x08).lrw8( + NAME([this] (offs_t offset) { + return et4k.reg_3d8; + }), + NAME([this] (offs_t offset, u8 data) { + et4k.reg_3d8 = data; + if(data == 0xa0) + et4k.ext_reg_ena = true; + else if(data == 0x29) + et4k.ext_reg_ena = false; + }) + ); } -uint8_t tseng_vga_device::tseng_crtc_reg_read(uint8_t index) +void tseng_vga_device::io_3cx_map(address_map &map) { - uint8_t res; - - if(index <= 0x18) - res = crtc_reg_read(index); - else - { - switch(index) - { - case 0x34: - res = et4k.aux_ctrl; - break; - case 0x3f: - res = et4k.horz_overflow; - break; - default: - res = vga.crtc.data[index]; - //printf("%02x\n",index); - break; - } - } - - return res; + svga_device::io_3cx_map(map); + map(0x06, 0x06).rw(FUNC(tseng_vga_device::ramdac_hidden_mask_r), FUNC(tseng_vga_device::ramdac_hidden_mask_w)); + map(0x08, 0x08).r(FUNC(tseng_vga_device::ramdac_hidden_windex_r)); + map(0x0d, 0x0d).lrw8( + NAME([this] (offs_t offset) { + u8 res = svga.bank_w & 0xf; + res |= (svga.bank_r & 0xf) << 4; + return res; + }), + NAME([this] (offs_t offset, u8 data) { + svga.bank_w = data & 0xf; + svga.bank_r = (data & 0xf0) >> 4; + }) + ); } -void tseng_vga_device::tseng_crtc_reg_write(uint8_t index, uint8_t data) +u8 tseng_vga_device::ramdac_hidden_mask_r(offs_t offset) { - if(index <= 0x18) - crtc_reg_write(index,data); - else + if(et4k.dac_state == 4) { - switch(index) - { - case 0x34: - et4k.aux_ctrl = data; - break; - case 0x3f: - et4k.horz_overflow = data; - vga.crtc.horz_total = (vga.crtc.horz_total & 0xff) | ((data & 1) << 8); - break; - default: - //printf("%02x %02x\n",index,data); - break; - } + if(!et4k.dac_ctrl) + et4k.dac_ctrl = 0x80; + return et4k.dac_ctrl; } + if (!machine().side_effects_disabled()) + et4k.dac_state++; + return vga_device::ramdac_mask_r(offset); } -uint8_t tseng_vga_device::tseng_seq_reg_read(uint8_t index) +void tseng_vga_device::ramdac_hidden_mask_w(offs_t offset, u8 data) { - uint8_t res; - - res = 0xff; - - if(index <= 0x04) - res = vga.sequencer.data[index]; - else + if(et4k.dac_state == 4) { - switch(index) - { - case 0x06: - case 0x07: - //printf("%02x\n",index); - break; - } + et4k.dac_ctrl = data; + recompute_params(); + return; } - return res; + vga_device::ramdac_write_index_w(offset, data); } -void tseng_vga_device::tseng_seq_reg_write(uint8_t index, uint8_t data) +u8 tseng_vga_device::ramdac_hidden_windex_r(offs_t offset) { - if(index <= 0x04) - { - vga.sequencer.data[vga.sequencer.index] = data; - seq_reg_write(vga.sequencer.index,data); - } - else - { - switch(index) - { - case 0x06: - case 0x07: - //printf("%02x %02x\n",index,data); - break; - } - } + if (!machine().side_effects_disabled()) + et4k.dac_state = 0; + return vga_device::ramdac_write_index_r(offset); } -uint8_t tseng_vga_device::port_03b0_r(offs_t offset) +void tseng_vga_device::crtc_map(address_map &map) { - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 5: - res = tseng_crtc_reg_read(vga.crtc.index); - break; - case 8: - res = et4k.reg_3d8; - break; - default: - res = vga_device::port_03b0_r(offset); - break; - } - } - - return res; + svga_device::crtc_map(map); + map(0x34, 0x34).lrw8( + NAME([this] (offs_t offset) { + return et4k.aux_ctrl; + }), + NAME([this] (offs_t offset, u8 data) { + et4k.aux_ctrl = data; + recompute_params(); + }) + ); + map(0x3f, 0x3f).lrw8( + NAME([this] (offs_t offset) { + return et4k.horz_overflow; + }), + NAME([this] (offs_t offset, u8 data) { + et4k.horz_overflow = data; + vga.crtc.horz_total = (vga.crtc.horz_total & 0xff) | ((data & 1) << 8); + recompute_params(); + }) + ); } -void tseng_vga_device::port_03b0_w(offs_t offset, uint8_t data) +void tseng_vga_device::sequencer_map(address_map &map) { - if (get_crtc_port() == 0x3b0) - { - switch(offset) - { - case 5: - vga.crtc.data[vga.crtc.index] = data; - tseng_crtc_reg_write(vga.crtc.index,data); - break; - case 8: - et4k.reg_3d8 = data; - if(data == 0xa0) - et4k.ext_reg_ena = true; - else if(data == 0x29) - et4k.ext_reg_ena = false; - break; - default: - vga_device::port_03b0_w(offset,data); - break; - } - } - tseng_define_video_mode(); + svga_device::sequencer_map(map); + // TODO: preseve legacy hookup, to be investigated + map(0x05, 0xff).unmaprw(); } -void tseng_vga_device::tseng_attribute_reg_write(uint8_t index, uint8_t data) +void tseng_vga_device::attribute_map(address_map &map) { - switch(index) - { - case 0x16: + map.global_mask(0x3f); + map.unmap_value_high(); + svga_device::attribute_map(map); + // Miscellaneous 1 + /* + * x--- ---- Bypass the internal palette + * -x-- ---- 2 byte character code (presumably for the Korean variants TBD) + * --xx ---- Select High resolution/color mode + * --00 ---- Normal power-up + * --01 ---- + * --10 ---- 8bpp + * --11 ---- 16bpp + * ---- xxxx + */ + // TODO: implement KEY protection + map(0x16, 0x16).mirror(0x20).lrw8( + NAME([this] (offs_t offset) { return et4k.misc1; }), + NAME([this] (offs_t offset, u8 data) { et4k.misc1 = data; + // TODO: this should be taken into account for recompute_params #if 0 svga.rgb8_en = 0; svga.rgb15_en = 0; svga.rgb16_en = 0; svga.rgb32_en = 0; - /* TODO: et4k and w32 are different here */ switch(et4k.misc1 & 0x30) { case 0: @@ -262,147 +184,76 @@ void tseng_vga_device::tseng_attribute_reg_write(uint8_t index, uint8_t data) break; } #endif - break; - case 0x17: et4k.misc2 = data; break; - default: - attribute_reg_write(index,data); - } - + }) + ); + // Miscellaneous 2 + // TODO: not on stock et4k? + map(0x17, 0x17).mirror(0x20).lrw8( + NAME([this] (offs_t offset) { return et4k.misc2; }), + NAME([this] (offs_t offset, u8 data) { + et4k.misc2 = data; + }) + ); } -uint8_t tseng_vga_device::port_03c0_r(offs_t offset) +void tseng_vga_device::recompute_params() { - uint8_t res; - - switch(offset) + int divisor; + int xtal = 0; + svga.rgb8_en = 0; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb24_en = 0; + switch(((et4k.aux_ctrl << 1) & 4)|(vga.miscellaneous_output & 0xc)>>2) { - case 0x01: - switch(vga.attribute.index) - { - case 0x16: res = et4k.misc1; break; - case 0x17: res = et4k.misc2; break; - default: - res = vga_device::port_03c0_r(offset); - break; - } - + case 0: + xtal = XTAL(25'174'800).value(); break; - - case 0x05: - res = tseng_seq_reg_read(vga.sequencer.index); + case 1: + xtal = XTAL(28'636'363).value(); break; - case 0x0d: - res = svga.bank_w & 0xf; - res |= (svga.bank_r & 0xf) << 4; + case 2: + xtal = 16257000*2; //2xEGA clock break; - case 0x06: - if(et4k.dac_state == 4) - { - if(!et4k.dac_ctrl) - et4k.dac_ctrl = 0x80; - res = et4k.dac_ctrl; - break; - } - et4k.dac_state++; - res = vga_device::port_03c0_r(offset); + case 3: + xtal = XTAL(40'000'000).value(); break; - case 0x08: - et4k.dac_state = 0; - [[fallthrough]]; - default: - res = vga_device::port_03c0_r(offset); + case 4: + xtal = XTAL(36'000'000).value(); + break; + case 5: + xtal = XTAL(45'000'000).value(); + break; + case 6: + xtal = 31000000; + break; + case 7: + xtal = 38000000; break; } - - return res; -} - -void tseng_vga_device::port_03c0_w(offs_t offset, uint8_t data) -{ - switch(offset) + switch(et4k.dac_ctrl & 0xe0) { - case 0: - if (vga.attribute.state==0) - { - vga.attribute.index=data; - } - else - { - tseng_attribute_reg_write(vga.attribute.index,data); - } - vga.attribute.state=!vga.attribute.state; + case 0xa0: + svga.rgb15_en = 1; + divisor = 2; break; - - case 0x05: - tseng_seq_reg_write(vga.sequencer.index,data); + case 0xe0: + svga.rgb16_en = 1; + divisor = 2; break; - case 0x0d: - svga.bank_w = data & 0xf; - svga.bank_r = (data & 0xf0) >> 4; + case 0x60: + svga.rgb24_en = 1; + divisor = 3; + xtal *= 2.0f/3.0f; break; - case 0x06: - if(et4k.dac_state == 4) - { - et4k.dac_ctrl = data; - break; - } - [[fallthrough]]; default: - vga_device::port_03c0_w(offset,data); + svga.rgb8_en = (!(vga.sequencer.data[1] & 8) && (vga.sequencer.data[4] & 8) && vga.gc.shift256 && vga.crtc.div2 && GRAPHIC_MODE); + divisor = 1; break; } - tseng_define_video_mode(); -} - -uint8_t tseng_vga_device::port_03d0_r(offs_t offset) -{ - uint8_t res = 0xff; - - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - res = tseng_crtc_reg_read(vga.crtc.index); - break; - case 8: - res = et4k.reg_3d8; - break; - default: - res = vga_device::port_03d0_r(offset); - break; - } - } - - return res; + recompute_params_clock(divisor, xtal); } -void tseng_vga_device::port_03d0_w(offs_t offset, uint8_t data) -{ - if (get_crtc_port() == 0x3d0) - { - switch(offset) - { - case 5: - vga.crtc.data[vga.crtc.index] = data; - tseng_crtc_reg_write(vga.crtc.index,data); - //if((vga.crtc.index & 0xfe) != 0x0e) - // printf("%02x %02x %d\n",vga.crtc.index,data,screen().vpos()); - break; - case 8: - et4k.reg_3d8 = data; - if(data == 0xa0) - et4k.ext_reg_ena = true; - else if(data == 0x29) - et4k.ext_reg_ena = false; - break; - default: - vga_device::port_03d0_w(offset,data); - break; - } - } - tseng_define_video_mode(); -} uint8_t tseng_vga_device::mem_r(offs_t offset) { diff --git a/src/devices/video/pc_vga_tseng.h b/src/devices/video/pc_vga_tseng.h index 85279de7580..cda09fa0acc 100644 --- a/src/devices/video/pc_vga_tseng.h +++ b/src/devices/video/pc_vga_tseng.h @@ -19,26 +19,25 @@ public: // construction/destruction tseng_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - virtual uint8_t port_03b0_r(offs_t offset) override; - virtual void port_03b0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03c0_r(offs_t offset) override; - virtual void port_03c0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03d0_r(offs_t offset) override; - virtual void port_03d0_w(offs_t offset, uint8_t data) override; virtual uint8_t mem_r(offs_t offset) override; virtual void mem_w(offs_t offset, uint8_t data) override; protected: virtual void device_start() override; -private: - void tseng_define_video_mode(); - uint8_t tseng_crtc_reg_read(uint8_t index); - void tseng_crtc_reg_write(uint8_t index, uint8_t data); - uint8_t tseng_seq_reg_read(uint8_t index); - void tseng_seq_reg_write(uint8_t index, uint8_t data); - void tseng_attribute_reg_write(uint8_t index, uint8_t data); + virtual void io_3bx_3dx_map(address_map &map) override; + virtual void io_3cx_map(address_map &map) override; + + u8 ramdac_hidden_mask_r(offs_t offset); + void ramdac_hidden_mask_w(offs_t offset, u8 data); + u8 ramdac_hidden_windex_r(offs_t offset); + virtual void crtc_map(address_map &map) override; + virtual void sequencer_map(address_map &map) override; + virtual void attribute_map(address_map &map) override; + + virtual void recompute_params() override; +private: struct { uint8_t reg_3d8; diff --git a/src/devices/video/pc_xga.cpp b/src/devices/video/pc_xga.cpp index 60dc15a8538..84ca7766ccf 100644 --- a/src/devices/video/pc_xga.cpp +++ b/src/devices/video/pc_xga.cpp @@ -761,6 +761,7 @@ oak_oti111_vga_device::oak_oti111_vga_device(const machine_config &mconfig, cons : svga_device(mconfig, OTI111, tag, owner, clock) , m_xga(*this, "xga") { + m_main_if_space_config = address_space_config("io_regs", ENDIANNESS_LITTLE, 8, 4, 0, address_map_constructor(FUNC(oak_oti111_vga_device::io_3bx_3dx_map), this)); } void oak_oti111_vga_device::device_add_mconfig(machine_config &config) @@ -771,6 +772,38 @@ void oak_oti111_vga_device::device_add_mconfig(machine_config &config) m_xga->set_type(xga_copro_device::TYPE::OTI111); } +void oak_oti111_vga_device::io_3bx_3dx_map(address_map &map) +{ + svga_device::io_3bx_3dx_map(map); + // TODO: convert to address_space + map(0x0e, 0xe).lrw8( + NAME([this] (offs_t offset) { + return m_oak_idx; + }), + NAME([this] (offs_t offset, u8 data) { + m_oak_idx = data; + }) + ); + map(0x0f, 0xf).lrw8( + NAME([this] (offs_t offset) { + return m_oak_idx <= 0x3a ? m_oak_regs[m_oak_idx] : space().unmap(); + }), + NAME([this] (offs_t offset, u8 data) { + m_oak_regs[m_oak_idx] = data; + switch(m_oak_idx) + { + case 0x21: + svga.rgb8_en = BIT(data, 2); + break; + case 0x33: + vga.crtc.no_wrap = BIT(data, 0); + break; + } + }) + ); +} + +// TODO: convert to map u8 oak_oti111_vga_device::xga_read(offs_t offset) { switch(offset) @@ -794,64 +827,14 @@ void oak_oti111_vga_device::device_start() std::fill(std::begin(m_oak_regs), std::end(m_oak_regs), 0); } -u8 oak_oti111_vga_device::dac_read(offs_t offset) -{ - if(offset >= 6) - return vga_device::port_03c0_r(offset); - return 0; -} - -void oak_oti111_vga_device::dac_write(offs_t offset, u8 data) -{ - if(offset >= 6) - vga_device::port_03c0_w(offset, data); -} - - -u8 oak_oti111_vga_device::port_03d0_r(offs_t offset) -{ - uint8_t res = 0xff; - switch(offset) - { - case 14: - return m_oak_idx; - case 15: - return m_oak_idx <= 0x3a ? m_oak_regs[m_oak_idx] : 0; - default: - if (get_crtc_port() == 0x3d0) - res = vga_device::port_03d0_r(offset); - break; - } - - return res; -} - -void oak_oti111_vga_device::port_03d0_w(offs_t offset, uint8_t data) +void oak_oti111_vga_device::ramdac_mmio_map(address_map &map) { - switch(offset) - { - case 14: - m_oak_idx = data; - break; - case 15: - if(m_oak_idx > 0x3a) - break; - m_oak_regs[m_oak_idx] = data; - switch(m_oak_idx) - { - case 0x21: - svga.rgb8_en = BIT(data, 2); - break; - case 0x33: - vga.crtc.no_wrap = BIT(data, 0); - break; - } - break; - default: - if (get_crtc_port() == 0x3d0) - vga_device::port_03d0_w(offset,data); - break; - } + map.unmap_value_high(); +// TODO: 0x04, 0x05 alt accesses for CRTC? + map(0x06, 0x06).rw(FUNC(oak_oti111_vga_device::ramdac_mask_r), FUNC(oak_oti111_vga_device::ramdac_mask_w)); + map(0x07, 0x07).rw(FUNC(oak_oti111_vga_device::ramdac_state_r), FUNC(oak_oti111_vga_device::ramdac_read_index_w)); + map(0x08, 0x08).rw(FUNC(oak_oti111_vga_device::ramdac_write_index_r), FUNC(oak_oti111_vga_device::ramdac_write_index_w)); + map(0x09, 0x09).rw(FUNC(oak_oti111_vga_device::ramdac_data_r), FUNC(oak_oti111_vga_device::ramdac_data_w)); } uint16_t oak_oti111_vga_device::offset() diff --git a/src/devices/video/pc_xga.h b/src/devices/video/pc_xga.h index b3973608187..05dc7b4bca1 100644 --- a/src/devices/video/pc_xga.h +++ b/src/devices/video/pc_xga.h @@ -77,14 +77,15 @@ public: u8 xga_read(offs_t offset); void xga_write(offs_t offset, u8 data); - u8 dac_read(offs_t offset); - void dac_write(offs_t offset, u8 data); - virtual u8 port_03d0_r(offs_t offset) override; - virtual void port_03d0_w(offs_t offset, uint8_t data) override; + + void ramdac_mmio_map(address_map &map); + protected: virtual void device_add_mconfig(machine_config &config) override; virtual void device_start() override; virtual uint16_t offset() override; + + virtual void io_3bx_3dx_map(address_map &map) override; private: u8 m_oak_regs[0x3b]; u8 m_oak_idx; diff --git a/src/devices/video/riva128.cpp b/src/devices/video/riva128.cpp index 4be3204bf8e..f36885fd76c 100644 --- a/src/devices/video/riva128.cpp +++ b/src/devices/video/riva128.cpp @@ -194,9 +194,7 @@ void riva128_device::legacy_memory_map(address_map &map) void riva128_device::legacy_io_map(address_map &map) { - map(0x03b0, 0x03bf).rw(FUNC(riva128_device::vga_3b0_r), FUNC(riva128_device::vga_3b0_w)); - map(0x03c0, 0x03cf).rw(FUNC(riva128_device::vga_3c0_r), FUNC(riva128_device::vga_3c0_w)); - map(0x03d0, 0x03df).rw(FUNC(riva128_device::vga_3d0_r), FUNC(riva128_device::vga_3d0_w)); + map(0, 0x02f).m(m_svga, FUNC(nvidia_nv3_vga_device::io_map)); } uint8_t riva128_device::vram_r(offs_t offset) @@ -209,85 +207,6 @@ void riva128_device::vram_w(offs_t offset, uint8_t data) downcast(m_svga.target())->mem_w(offset, data); } -u32 riva128_device::vga_3b0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_svga.target())->port_03b0_r(offset * 4 + 3) << 24; - return result; -} - -void riva128_device::vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_svga.target())->port_03b0_w(offset * 4 + 3, data >> 24); -} - - -u32 riva128_device::vga_3c0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_svga.target())->port_03c0_r(offset * 4 + 3) << 24; - return result; -} - -void riva128_device::vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_svga.target())->port_03c0_w(offset * 4 + 3, data >> 24); -} - -u32 riva128_device::vga_3d0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_svga.target())->port_03d0_r(offset * 4 + 3) << 24; - return result; -} - -void riva128_device::vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_svga.target())->port_03d0_w(offset * 4 + 3, data >> 24); -} - void riva128_device::map_extra(uint64_t memory_window_start, uint64_t memory_window_end, uint64_t memory_offset, address_space *memory_space, uint64_t io_window_start, uint64_t io_window_end, uint64_t io_offset, address_space *io_space) { @@ -295,9 +214,7 @@ void riva128_device::map_extra(uint64_t memory_window_start, uint64_t memory_win { memory_space->install_readwrite_handler(0xa0000, 0xbffff, read8sm_delegate(*this, FUNC(riva128_device::vram_r)), write8sm_delegate(*this, FUNC(riva128_device::vram_w))); - io_space->install_readwrite_handler(0x3b0, 0x3bf, read32s_delegate(*this, FUNC(riva128_device::vga_3b0_r)), write32s_delegate(*this, FUNC(riva128_device::vga_3b0_w))); - io_space->install_readwrite_handler(0x3c0, 0x3cf, read32s_delegate(*this, FUNC(riva128_device::vga_3c0_r)), write32s_delegate(*this, FUNC(riva128_device::vga_3c0_w))); - io_space->install_readwrite_handler(0x3d0, 0x3df, read32s_delegate(*this, FUNC(riva128_device::vga_3d0_r)), write32s_delegate(*this, FUNC(riva128_device::vga_3d0_w))); + io_space->install_device(0x03b0, 0x03df, *this, &riva128_device::legacy_io_map); //memory_space->install_rom(0xc0000, 0xcffff, (void *)expansion_rom); } } diff --git a/src/devices/video/riva128.h b/src/devices/video/riva128.h index a70bf909c16..ce03de39a68 100644 --- a/src/devices/video/riva128.h +++ b/src/devices/video/riva128.h @@ -42,12 +42,6 @@ protected: private: u8 vram_r(offs_t offset); void vram_w(offs_t offset, uint8_t data); - u32 vga_3b0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - u32 vga_3c0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - u32 vga_3d0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); u32 unmap_log_r(offs_t offset, u32 mem_mask = ~0); void unmap_log_w(offs_t offset, u32 data, u32 mem_mask = ~0); diff --git a/src/devices/video/s3virge.cpp b/src/devices/video/s3virge.cpp new file mode 100644 index 00000000000..3d3bdd023a5 --- /dev/null +++ b/src/devices/video/s3virge.cpp @@ -0,0 +1,1238 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * s3virge.cpp + * + * Implementation of the S3 Virge series of video card + * + * Current status: + * - Working on getting VESA video modes working better - 800x600 and higher skip every other line at + * 8-bit depth, but are fine at 15/16-bit depth. + * - S3D is not implemented at all, so no 2D/3D acceleration yet. + * + * TODO: + * - Proper FIFOs; + * - Implement 3d commands; + * - Implement remaining ROP commands; + * - Secondary stream mixing; + * - S3 Scenic Highway i/f (SAA7110 + S3 Scenic/MX2 MPEG-1); + * - DMAs; + * - interrupts; + * - big endian support for non-x86 machines; + * - DDC/I2C i/f, cfr. serial port on MMFF20 + * - win98se: doesn't show transparent layer on shut down screen; + * + */ + +#include "emu.h" +#include "s3virge.h" + +#include "screen.h" + +//#include + +#define VERBOSE (LOG_REG | LOG_CMD | LOG_MMIO) +//#define LOG_OUTPUT_STREAM std::cout + +#include "logmacro.h" + +#define LOG_REG (1U << 1) +#define LOG_CMD (1U << 2) +#define LOG_MMIO (1U << 3) + +#define LOGREG(...) LOGMASKED(LOG_REG, __VA_ARGS__) +#define LOGCMD(...) LOGMASKED(LOG_CMD, __VA_ARGS__) +#define LOGMMIO(...) LOGMASKED(LOG_MMIO, __VA_ARGS__) + + +#define CRTC_PORT_ADDR ((vga.miscellaneous_output & 1) ? 0x3d0 : 0x3b0) + +DEFINE_DEVICE_TYPE(S3VIRGE, s3virge_vga_device, "virge_vga", "S3 86C325") +DEFINE_DEVICE_TYPE(S3VIRGEDX, s3virgedx_vga_device, "virgedx_vga", "S3 86C375") +DEFINE_DEVICE_TYPE(S3VIRGEDX1, s3virgedx_rev1_vga_device, "virgedx_vga_r1", "S3 86C375 (rev 1)") + +s3virge_vga_device::s3virge_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : s3virge_vga_device(mconfig, S3VIRGE, tag, owner, clock) +{ + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(s3virge_vga_device::crtc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(s3virge_vga_device::sequencer_map), this)); +} + +s3virge_vga_device::s3virge_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : s3_vga_device(mconfig, type, tag, owner, clock) + , m_linear_config_changed_cb(*this) +{ +} + +s3virgedx_vga_device::s3virgedx_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : s3virgedx_vga_device(mconfig, S3VIRGEDX, tag, owner, clock) +{ + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(s3virgedx_vga_device::crtc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(s3virgedx_vga_device::sequencer_map), this)); +} + +s3virgedx_vga_device::s3virgedx_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : s3virge_vga_device(mconfig, type, tag, owner, clock) +{ +} + +s3virgedx_rev1_vga_device::s3virgedx_rev1_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : s3virgedx_vga_device(mconfig, S3VIRGEDX1, tag, owner, clock) +{ + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(s3virgedx_rev1_vga_device::crtc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(s3virgedx_rev1_vga_device::sequencer_map), this)); +} + +void s3virge_vga_device::device_start() +{ + zero(); + + for (int i = 0; i < 0x100; i++) + set_pen_color(i, 0, 0, 0); + + // Avoid an infinite loop when displaying. 0 is not possible anyway. + vga.crtc.maximum_scan_line = 1; + + // copy over interfaces + vga.memory = std::make_unique(vga.svga_intf.vram_size); + memset(&vga.memory[0], 0, vga.svga_intf.vram_size); + + save_pointer(vga.memory, "Video RAM", vga.svga_intf.vram_size); + save_item(vga.crtc.data,"CRTC Registers"); + save_item(vga.sequencer.data,"Sequencer Registers"); + save_item(vga.attribute.data,"Attribute Registers"); + + m_vblank_timer = timer_alloc(FUNC(vga_device::vblank_timer_cb), this); + m_draw_timer = timer_alloc(FUNC(s3virge_vga_device::draw_step_tick), this); + + memset(&s3, 0, sizeof(s3)); + memset(&s3virge, 0, sizeof(s3virge)); + s3virge.linear_address = 0x70000000; + s3virge.linear_address_size_full = 0x10000; + s3virge.s3d.cmd_fifo_slots_free = 16; + save_item(s3virge.s3d.pattern,"S3D Pattern Data"); + save_item(s3virge.s3d.reg[0],"S3D Registers: BitBLT"); + save_item(s3virge.s3d.reg[1],"S3D Registers: 2D Line"); + save_item(s3virge.s3d.reg[2],"S3D Registers: 2D Polygon"); + save_item(s3virge.s3d.reg[3],"S3D Registers: 3D Line"); + save_item(s3virge.s3d.reg[4],"S3D Registers: 3D Triangle"); + + // Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason + for (int x = 0; x < 4; x++) + { + s3.cursor_fg[x] = 0xff; + s3.cursor_bg[x] = 0x00; + } + // set device ID + s3.id_high = 0x56; // CR2D + s3.id_low = 0x31; // CR2E + s3.revision = 0x00; // CR2F (value unknown) + s3.id_cr30 = 0xe1; // CR30 +} + +void s3virgedx_vga_device::device_start() +{ + s3virge_vga_device::device_start(); + + // set device ID + s3.id_high = 0x8a; // CR2D + s3.id_low = 0x01; // CR2E + s3.revision = 0x00; // CR2F (value unknown) + s3.id_cr30 = 0xe1; // CR30 +} + +void s3virgedx_rev1_vga_device::device_start() +{ + s3virge_vga_device::device_start(); + + // set device ID + s3.id_high = 0x8a; // CR2D + s3.id_low = 0x01; // CR2E + s3.revision = 0x01; // CR2F + s3.id_cr30 = 0xe1; // CR30 +} + +void s3virge_vga_device::device_reset() +{ + s3_vga_device::device_reset(); + // Power-on strapping bits. Sampled at reset, but can be modified later. + // These are just assumed defaults. + s3.strapping = 0x000f0912; + + // TODO: fix soft reset state + // On Windows 98 shutdown message sometimes leads to an hang the next boot around + s3virge.s3d.state = S3D_STATE_IDLE; + s3virge.s3d.cmd_fifo_current_ptr = 0; + s3virge.s3d.cmd_fifo_slots_free = 16; + s3virge.s3d.busy = false; + //m_draw_timer->adjust(attotime::never); +} + +void s3virgedx_vga_device::device_reset() +{ + s3virge_vga_device::device_reset(); + // Power-on strapping bits. Sampled at reset, but can be modified later. + // These are just assumed defaults. + s3.strapping = 0x000f0912; +} + +void s3virgedx_rev1_vga_device::device_reset() +{ + s3virgedx_vga_device::device_reset(); + // Power-on strapping bits. Sampled at reset, but can be modified later. + // These are based on results from a Diamond Stealth 3D 2000 Pro (Virge/DX based) + // bits 8-15 are still unknown, S3ID doesn't show config register 2 (CR37) + s3.strapping = 0x0aff0912; +} + +uint16_t s3virge_vga_device::offset() +{ + if(svga.rgb24_en) + return vga.crtc.offset * 6; // special handling for 24bpp packed mode + return s3_vga_device::offset(); +} + +void s3virge_vga_device::crtc_map(address_map &map) +{ + s3_vga_device::crtc_map(map); + // TODO: verify these overrides + map(0x3a, 0x3a).lw8( + NAME([this] (offs_t offset, u8 data) { + s3.cr3a = data; + s3_define_video_mode(); + }) + ); + map(0x40, 0x40).lw8( + NAME([this] (offs_t offset, u8 data) { + // enable S3D registers + s3.enable_s3d = data & 0x01; + }) + ); + map(0x43, 0x43).lw8( + NAME([this] (offs_t offset, u8 data) { + // bit 2 = bit 8 of offset register, but only if bits 4-5 of CR51 are 00h. + s3.cr43 = data; + if((s3.cr51 & 0x30) == 0) + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x04) << 6); + else + vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr51 & 0x30) << 4); + s3_define_video_mode(); + }) + ); + map(0x45, 0x45).lrw8( + NAME([this] (offs_t offset) { + return s3.cursor_mode; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cursor_mode = data; + }) + ); + map(0x4a, 0x4a).lr8( + NAME([this] (offs_t offset) { + u8 res = s3.cursor_fg[s3.cursor_fg_ptr]; + s3.cursor_fg_ptr = 0; + return res; + }) + ); + map(0x4b, 0x4b).lr8( + NAME([this] (offs_t offset) { + u8 res = s3.cursor_bg[s3.cursor_bg_ptr]; + s3.cursor_bg_ptr = 0; + return res; + }) + ); + map(0x51, 0x51).lr8( + NAME([this] (offs_t offset) { + u8 res = (vga.crtc.start_addr_latch & 0x0c0000) >> 18; + res |= ((svga.bank_w & 0x30) >> 2); + //res |= ((vga.crtc.offset & 0x0300) >> 4); + return res; + }) + ); + map(0x53, 0x53).lrw8( + NAME([this] (offs_t offset) { + return s3.cr53; + }), + NAME([this] (offs_t offset, u8 data) { + s3.cr53 = data; + //m_linear_config_changed_cb(s3virge.linear_address_enable); + }) + ); + map(0x58, 0x58).lrw8( + NAME([this] (offs_t offset) { + u8 res = s3virge.linear_address_size & 0x03; + res |= s3virge.linear_address_enable ? 0x10 : 0x00; + return res; + }), + NAME([this] (offs_t offset, u8 data) { + const uint8_t old_size = s3virge.linear_address_size; + const bool old_enable = s3virge.linear_address_enable; + const bool size_changed = old_size != s3virge.linear_address_size; + + s3virge.linear_address_size = data & 0x03; + s3virge.linear_address_enable = data & 0x10; + + switch(data & 0x03) + { + case LAW_64K: + s3virge.linear_address_size_full = 0x10000; + break; + case LAW_1MB: + s3virge.linear_address_size_full = 0x100000; + break; + case LAW_2MB: + s3virge.linear_address_size_full = 0x200000; + break; + case LAW_4MB: + s3virge.linear_address_size_full = 0x400000; + break; + } + + if ((s3virge.linear_address_enable != old_enable) || size_changed) + { + m_linear_config_changed_cb(s3virge.linear_address_enable); + } + + LOGREG("CR58: write %02x\n", data); + }) + ); + map(0x59, 0x59).lrw8( + NAME([this] (offs_t offset) { + return (s3virge.linear_address & 0xff000000) >> 24;; + }), + NAME([this] (offs_t offset, u8 data) { + const uint32_t old_address = s3virge.linear_address; + s3virge.linear_address = (s3virge.linear_address & 0x00ff0000) | (data << 24); + LOGREG("Linear framebuffer address = %08x\n",s3virge.linear_address); + + if (old_address != s3virge.linear_address && s3virge.linear_address_enable) + { + m_linear_config_changed_cb(1); + } + }) + ); + map(0x5a, 0x5a).lrw8( + NAME([this] (offs_t offset) { + u8 res = 0; + switch(s3virge.linear_address_size & 0x03) + { + case 0: // 64kB + default: + res = (s3virge.linear_address & 0x00ff0000) >> 16; + break; + case 1: // 1MB + res = (s3virge.linear_address & 0x00f00000) >> 16; + break; + case 2: // 2MB + res = (s3virge.linear_address & 0x00e00000) >> 16; + break; + case 3: // 4MB + res = (s3virge.linear_address & 0x00c00000) >> 16; + break; + } + return res; + }), + NAME([this] (offs_t offset, u8 data) { + const uint32_t old_address = s3virge.linear_address; + s3virge.linear_address = (s3virge.linear_address & 0xff000000) | (data << 16); + LOGREG("Linear framebuffer address = %08x\n",s3virge.linear_address); + + if (old_address != s3virge.linear_address && s3virge.linear_address_enable) + { + m_linear_config_changed_cb(1); + } + }) + ); + //map(0x5d, 0x5e).unmapr(); +} + +void s3virge_vga_device::s3_define_video_mode() +{ + int divisor = 1; + const XTAL base_xtal = XTAL(14'318'181); + XTAL xtal = (vga.miscellaneous_output & 0xc) ? base_xtal*2 : base_xtal*1.75; + + if((vga.miscellaneous_output & 0xc) == 0x0c) + { + // Dot clock is set via SR12 and SR13 + // DCLK calculation + double ratio = (double)(s3.clk_pll_m+2) / (double)((s3.clk_pll_n+2)*(pow(2.0,s3.clk_pll_r))); // clock between XIN and XOUT + xtal = base_xtal * ratio; + //printf("DCLK set to %dHz M=%i N=%i R=%i\n",xtal,s3.clk_pll_m,s3.clk_pll_n,s3.clk_pll_r); + } + + if((s3.ext_misc_ctrl_2) >> 4) + { + svga.rgb8_en = 0; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb24_en = 0; + switch((s3.ext_misc_ctrl_2) >> 4) + { + case 0x01: svga.rgb8_en = 1; break; + case 0x03: svga.rgb15_en = 1; divisor = 2; break; + case 0x05: svga.rgb16_en = 1; divisor = 2; break; + case 0x0d: svga.rgb24_en = 1; divisor = 1; break; + default: fatalerror("TODO: s3 video mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4)); + } + } + else + { + svga.rgb8_en = (s3.cr3a & 0x10) >> 4; + svga.rgb15_en = 0; + svga.rgb16_en = 0; + svga.rgb24_en = 0; + } + if(s3.cr43 & 0x80) // Horizontal clock doubling (technically, doubles horizontal CRT parameters) + divisor *= 2; + recompute_params_clock(divisor, xtal.value()); +} + +uint8_t s3virge_vga_device::mem_r(offs_t offset) +{ + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb24_en || svga.rgb32_en) + { + uint8_t data; + if(offset & 0x10000) + return 0; + data = 0xff; + if(vga.sequencer.data[4] & 0x8) + { + if(offset + (svga.bank_r*0x10000) < vga.svga_intf.vram_size) + data = vga.memory[offset + (svga.bank_r*0x10000)]; + } + else + { + int i; + + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + { + if(offset*4+i+(svga.bank_r*0x10000) < vga.svga_intf.vram_size) + data |= vga.memory[offset*4+i+(svga.bank_r*0x10000)]; + } + } + } + return data; + } + if((offset + (svga.bank_r*0x10000)) < vga.svga_intf.vram_size) + return vga_device::mem_r(offset); + else + return 0xff; +} + +void s3virge_vga_device::mem_w(offs_t offset, uint8_t data) +{ + // bit 4 of CR53 enables memory-mapped I/O + if(s3.cr53 & 0x10) + { + // TODO + } + + if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en) + { + // printf("%08x %02x (%02x %02x) %02X\n",offset,data,vga.sequencer.map_mask,svga.bank_w,(vga.sequencer.data[4] & 0x08)); + if(offset & 0x10000) + return; + if(vga.sequencer.data[4] & 0x8) + { + if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size) + vga.memory[(offset + (svga.bank_w*0x10000))] = data; + } + else + { + int i; + for(i=0;i<4;i++) + { + if(vga.sequencer.map_mask & 1 << i) + { + if((offset*4+i+(svga.bank_w*0x10000)) < vga.svga_intf.vram_size) + vga.memory[(offset*4+i+(svga.bank_w*0x10000))] = data; + } + } + } + return; + } + + if((offset + (svga.bank_w*0x10000)) < vga.svga_intf.vram_size) + vga_device::mem_w(offset,data); +} + +uint8_t s3virge_vga_device::fb_r(offs_t offset) +{ + if(offset < s3virge.linear_address_size_full) + return vga.memory[offset % vga.svga_intf.vram_size]; + return 0xff; +} + +void s3virge_vga_device::fb_w(offs_t offset, uint8_t data) +{ + if(offset < s3virge.linear_address_size_full) + vga.memory[offset % vga.svga_intf.vram_size] = data; +} + +void s3virge_vga_device::add_command(int cmd_type) +{ + // add command to S3D FIFO + if(s3virge.s3d.cmd_fifo_slots_free == 0) + { + LOGCMD("Attempt to add command when all command slots are full\n"); + return; + } + memcpy(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].reg,s3virge.s3d.reg[cmd_type],256*4); + s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type = cmd_type; + LOGCMD("Added command type %i cmd %08x ptr %u\n",s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].op_type,s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_next_ptr].reg[S3D_REG_COMMAND],s3virge.s3d.cmd_fifo_next_ptr); + s3virge.s3d.cmd_fifo_next_ptr++; + if(s3virge.s3d.cmd_fifo_next_ptr >= 16) + s3virge.s3d.cmd_fifo_next_ptr = 0; + if(s3virge.s3d.cmd_fifo_slots_free == 16) // if all slots are free, start command now + command_start(); + s3virge.s3d.cmd_fifo_slots_free--; + // TODO: handle full FIFO +} + +void s3virge_vga_device::command_start() +{ + // start next command in FIFO + int cmd_type = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].op_type; + + switch(cmd_type) + { + case OP_2DLINE: + LOGCMD("2D Line command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + break; + case OP_2DPOLY: + LOGCMD("2D Poly command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + break; + case OP_3DLINE: + LOGCMD("3D Line command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + break; + case OP_3DTRI: + LOGCMD("3D Tri command (unsupported) [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + break; + case OP_BITBLT: + s3virge.s3d.state = S3D_STATE_BITBLT; + s3virge.s3d.busy = true; + s3virge.s3d.bitblt_x_src = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RSRC_XY] & 0x07ff0000) >> 16; + s3virge.s3d.bitblt_y_src = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RSRC_XY] & 0x000007ff); + s3virge.s3d.bitblt_x_dst = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RDEST_XY] & 0x07ff0000) >> 16; + s3virge.s3d.bitblt_y_dst = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RDEST_XY] & 0x000007ff); + s3virge.s3d.bitblt_width = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RWIDTH_HEIGHT] & 0xffff0000) >> 16; + s3virge.s3d.bitblt_height = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_RWIDTH_HEIGHT] & 0x0000ffff); + s3virge.s3d.bitblt_x_current = s3virge.s3d.bitblt_x_dst; + s3virge.s3d.bitblt_x_src_current = s3virge.s3d.bitblt_x_src; + s3virge.s3d.bitblt_y_current = s3virge.s3d.bitblt_y_dst; + s3virge.s3d.bitblt_y_src_current = s3virge.s3d.bitblt_y_src; + s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8; + s3virge.s3d.bitblt_pat_y = s3virge.s3d.bitblt_y_current % 8; + s3virge.s3d.clip_r = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_L_R] & 0x000007ff; + s3virge.s3d.clip_l = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_L_R] & 0x07ff0000) >> 16; + s3virge.s3d.clip_b = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_T_B] & 0x000007ff; + s3virge.s3d.clip_t = (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_CLIP_T_B] & 0x07ff0000) >> 16; + if(!(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000080)) + m_draw_timer->adjust(attotime::from_nsec(250),0,attotime::from_nsec(250)); + s3virge.s3d.bitblt_step_count = 0; + s3virge.s3d.bitblt_mono_pattern = + s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_MONO_PAT_0] | (uint64_t)(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_MONO_PAT_1]) << 32; + s3virge.s3d.bitblt_current_pixel = 0; + s3virge.s3d.bitblt_pixel_pos = 0; + s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR] = 0xffffffff; // win31 never sets this? + LOGCMD("Started BitBLT command [%u]\n", s3virge.s3d.cmd_fifo_current_ptr); + //if(((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x01fe0000) >> 17) == 0xf0) machine().debug_break(); + break; + } +} + +void s3virge_vga_device::command_finish() +{ + s3virge.s3d.state = S3D_STATE_IDLE; + s3virge.s3d.cmd_fifo_current_ptr++; + if(s3virge.s3d.cmd_fifo_current_ptr >= 16) + s3virge.s3d.cmd_fifo_current_ptr = 0; + s3virge.s3d.cmd_fifo_slots_free++; + if(s3virge.s3d.cmd_fifo_slots_free > 16) + s3virge.s3d.cmd_fifo_slots_free = 16; + m_draw_timer->adjust(attotime::never); + + // check if there is another command in the FIFO + if(s3virge.s3d.cmd_fifo_slots_free < 16) + command_start(); + else + s3virge.s3d.busy = false; + + LOGMMIO("Command finished [%u] (%u slots free)\n",s3virge.s3d.cmd_fifo_current_ptr,s3virge.s3d.cmd_fifo_slots_free); +} + +void s3virge_vga_device::line2d_step() +{ + command_finish(); +} + +void s3virge_vga_device::poly2d_step() +{ + command_finish(); +} + +void s3virge_vga_device::line3d_step() +{ + command_finish(); +} + +void s3virge_vga_device::poly3d_step() +{ + command_finish(); +} + + +uint32_t s3virge_vga_device::GetROP(uint8_t rop, uint32_t src, uint32_t dst, uint32_t pat) +{ + uint32_t ret = 0; + + switch(rop) + { + case 0x00: // 0 + ret = 0; + break; + case 0x0a: // DPna + ret = (dst & (~pat)); + break; + case 0x22: // DSna + ret = (dst & (~src)); + break; + case 0x33: // Sn + ret = ~src; + break; + case 0x55: // Dn + ret = ~dst; + break; + case 0x5a: // DPx + ret = dst ^ pat; + break; + case 0x66: // DSx + ret = dst ^ src; + break; + case 0x88: // DSa + ret = dst & src; + break; + case 0xb8: // PSDPxax + ret = ((dst ^ pat) & src) ^ pat; + break; + case 0xbb: // DSno + ret = (dst | (~src)); + break; + case 0xcc: + ret = src; + break; + case 0xe2: // DSPDxax + ret = ((pat ^ dst) & src) ^ dst; + break; + case 0xee: // DSo + ret = (dst | src); + break; + case 0xf0: + ret = pat; + break; + case 0xff: // 1 + ret = 0xffffffff; + break; + default: + popmessage("video/s3virge.cpp: Unimplemented ROP 0x%02x",rop); + } + + return ret; +} + +bool s3virge_vga_device::advance_pixel() +{ + bool xpos, ypos; + int16_t top, left, right, bottom; + // advance src/dst and pattern location + xpos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x02000000; // X Positive + ypos = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x04000000; // Y Positive + if(xpos) + { + left = s3virge.s3d.bitblt_x_dst; + right = s3virge.s3d.bitblt_x_dst + s3virge.s3d.bitblt_width + 1; + s3virge.s3d.bitblt_x_current++; + s3virge.s3d.bitblt_x_src_current++; + s3virge.s3d.bitblt_pat_x++; + } + else + { + left = s3virge.s3d.bitblt_x_dst - s3virge.s3d.bitblt_width - 1; + right = s3virge.s3d.bitblt_x_dst; + s3virge.s3d.bitblt_x_current--; + s3virge.s3d.bitblt_x_src_current--; + s3virge.s3d.bitblt_pat_x--; +// machine().debug_break(); + } + if(ypos) + { + top = s3virge.s3d.bitblt_y_dst; + bottom = s3virge.s3d.bitblt_y_dst + s3virge.s3d.bitblt_height; + } + else + { + top = s3virge.s3d.bitblt_y_dst - s3virge.s3d.bitblt_height; + bottom = s3virge.s3d.bitblt_y_dst; + } + if(s3virge.s3d.bitblt_pat_x < 0 || s3virge.s3d.bitblt_pat_x >= 8) + s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8; + if((s3virge.s3d.bitblt_x_current >= right) || (s3virge.s3d.bitblt_x_current <= left)) + { + s3virge.s3d.bitblt_x_current = s3virge.s3d.bitblt_x_dst; + s3virge.s3d.bitblt_x_src_current = s3virge.s3d.bitblt_x_src; + if(ypos) + { + s3virge.s3d.bitblt_y_current++; + s3virge.s3d.bitblt_y_src_current++; + s3virge.s3d.bitblt_pat_y++; + } + else + { + s3virge.s3d.bitblt_y_current--; + s3virge.s3d.bitblt_y_src_current--; + s3virge.s3d.bitblt_pat_y--; + } + s3virge.s3d.bitblt_pat_x = s3virge.s3d.bitblt_x_current % 8; + if(s3virge.s3d.bitblt_pat_y >= 8 || s3virge.s3d.bitblt_pat_y < 0) + s3virge.s3d.bitblt_pat_y = s3virge.s3d.bitblt_y_current % 8; + logerror("SRC: %i,%i DST: %i,%i PAT: %i,%i Bounds: %i,%i,%i,%i\n", + s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, + s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, + s3virge.s3d.bitblt_pat_x,s3virge.s3d.bitblt_pat_y, + left,right,top,bottom); + if((s3virge.s3d.bitblt_y_current >= bottom) || (s3virge.s3d.bitblt_y_current <= top)) + return true; + } + return false; +} + +void s3virge_vga_device::bitblt_step() +{ + if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x40)) + bitblt_monosrc_step(); + else + bitblt_colour_step(); +} + +void s3virge_vga_device::bitblt_colour_step() +{ + // progress current BitBLT operation + // get source and destination addresses + uint32_t src_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BASE] & 0x003ffff8; + uint32_t dst_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_BASE] & 0x003ffff8; + + const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND]; + const uint8_t pixel_size = (current_command & 0x0000001c) >> 2; + const uint8_t rop = (current_command & 0x01fe0000) >> 17; + const int align = (current_command & 0x000000c00) >> 10; + //const bool tp = bool(BIT(current_command, 9)); + const bool de = bool(BIT(current_command, 5)); + + uint32_t src = 0; + uint32_t dst = 0; + uint32_t pat = 0; + int x; + bool done = false; + + switch(pixel_size) + { + case 0: // 8bpp + for(x=0;x<4;x++) + { + if(current_command & 0x80) + src = s3virge.s3d.image_xfer >> (x*8); + else + src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); + if(current_command & 0x100) + { + pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) + ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + } + else + { + pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y * 8) + s3virge.s3d.bitblt_pat_x]; + } + dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + + if (de) + write_pixel8(dst_base, s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, GetROP(rop, src, dst, pat) & 0xff); + + done = advance_pixel(); + if(done) + { + command_finish(); + break; + } + if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + { + if(align == 2) // doubleword aligned, end here + break; + if(align == 1) // word aligned, move to next word + { + if(x < 2) + x = 2; + else + break; + } + } + } + break; + case 1: // 16bpp + if(current_command & 0x80) + src = s3virge.s3d.image_xfer; + else + src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); + dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + if(current_command & 0x100) + { + pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) + ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + } + else + pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2) + 1]) << 8; + + if (de) + write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff); + done = advance_pixel(); + if(done) + { + command_finish(); + break; + } + if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst && align == 2) + break; // if a new line of an image transfer, and is dword aligned, stop here + if(current_command & 0x80) + src = s3virge.s3d.image_xfer >> 16; + else + src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); + dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + if(current_command & 0x100) + { + pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) + ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + } + else + pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*16) + (s3virge.s3d.bitblt_pat_x*2) + 1]) << 8; + if (de) + write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat) & 0xffff); + if(advance_pixel()) + command_finish(); + break; + case 2: // 24bpp + if(current_command & 0x80) + { + src = s3virge.s3d.image_xfer; + for(x=0;x<4;x++) + { + s3virge.s3d.bitblt_current_pixel |= ((s3virge.s3d.image_xfer >> (x*8)) & 0xff) << s3virge.s3d.bitblt_pixel_pos*8; + s3virge.s3d.bitblt_pixel_pos++; + if(s3virge.s3d.bitblt_pixel_pos > 2) + { + s3virge.s3d.bitblt_pixel_pos = 0; + dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + if(current_command & 0x100) + { + pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) + ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + } + else + pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 1]) << 8 + | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 2]) << 16; + if (de) + write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.bitblt_current_pixel, dst, pat)); + s3virge.s3d.bitblt_current_pixel = 0; + done = advance_pixel(); + if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + { + if(align == 2) // doubleword aligned, end here + x = 4; + if(align == 1) // word aligned, move to next word + { + if(x < 2) + x = 2; + else + x = 4; + } + } + if(done) + command_finish(); + } + } + break; + } + else + { + src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); + dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + if(current_command & 0x100) + { + pat = (s3virge.s3d.bitblt_mono_pattern & (1 << ((s3virge.s3d.bitblt_pat_y*8) + (7-s3virge.s3d.bitblt_pat_x))) + ? s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR] : s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_BG_CLR]); + } + else + pat = s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3)] | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 1]) << 8 + | (s3virge.s3d.pattern[(s3virge.s3d.bitblt_pat_y*24) + (s3virge.s3d.bitblt_pat_x*3) + 2]) << 16; + } + if (de) + write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, src, dst, pat)); + if(advance_pixel()) + command_finish(); + break; + } + + s3virge.s3d.bitblt_step_count++; +} + +void s3virge_vga_device::bitblt_monosrc_step() +{ + // progress current monochrome source BitBLT operation + uint32_t src_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BASE] & 0x003ffff8; + uint32_t dst_base = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_BASE] & 0x003ffff8; + + const u32 current_command = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND]; + const uint8_t pixel_size = (current_command & 0x0000001c) >> 2; + const uint8_t rop = (current_command & 0x01fe0000) >> 17; + //const bool tp = bool(BIT(current_command, 9)); + const bool de = bool(BIT(current_command, 5)); + const int align = (current_command & 0x000000c00) >> 10; + + uint32_t src = 0; + uint32_t dst = 0; + // Windows 98 cares about this being initialized to non-zero for + // greyed back/forward icons in Explorer, system icons and right click disabled Paste command. + uint32_t pat = s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_PAT_FG_CLR]; + int x; + bool done = false; + + switch(pixel_size) + { + case 0: // 8bpp + for(x=31;x>=0;x--) + { + if(current_command & 0x80) + src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); + else + src = read_pixel8(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); + dst = read_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + + if (de) + { + if(src & (1 << x)) + write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xff); + else if(!(current_command & 0x200)) // only draw background colour if transparency is not set + write_pixel8(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xff); + } + //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop); + done = advance_pixel(); + if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + { + switch(align) + { + case 0: + x &= ~7; + break; + case 1: + x &= ~15; + break; + case 2: + x = -1; + break; + } + if(done) + { + command_finish(); + break; + } + } + } + break; + case 1: // 16bpp + for(x=31;x>=0;x--) + { + if(current_command & 0x80) + src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); + else + src = read_pixel16(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); + dst = read_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + + if (de) + { + if(src & (1 << x)) + write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat) & 0xffff); + else if(!(current_command & 0x200)) // only draw background colour if transparency is not set + write_pixel16(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat) & 0xffff); + } + //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop); + done = advance_pixel(); + if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + { + switch(align) + { + case 0: + x &= ~7; + break; + case 1: + x &= ~15; + break; + case 2: + x = -1; + break; + } + if(done) + { + command_finish(); + break; + } + } + } + break; + case 2: // 24bpp + for(x=31;x>=0;x--) + { + if(current_command & 0x80) + src = bitswap<32>(s3virge.s3d.image_xfer,7,6,5,4,3,2,1,0,15,14,13,12,11,10,9,8,23,22,21,20,19,18,17,16,31,30,29,28,27,26,25,24); + else + src = read_pixel24(src_base,s3virge.s3d.bitblt_x_src_current,s3virge.s3d.bitblt_y_src_current, src_stride()); + dst = read_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current, dest_stride()); + + if (de) + { + if(src & (1 << x)) + write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_FG_CLR], dst, pat)); + else if(!(current_command & 0x200)) // only draw background colour if transparency is not set + write_pixel24(dst_base,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_y_current,GetROP(rop, s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_SRC_BG_CLR], dst, pat)); + } + //printf("Pixel write(%i): X: %i Y: %i SRC: %04x DST: %04x PAT: %04x ROP: %02x\n",x,s3virge.s3d.bitblt_x_current, s3virge.s3d.bitblt_y_current, src, dst, pat, rop); + done = advance_pixel(); + if((current_command & 0x80) && s3virge.s3d.bitblt_x_current == s3virge.s3d.bitblt_x_dst) + { + switch(align) + { + case 0: + x &= ~7; + break; + case 1: + x &= ~15; + break; + case 2: + x = -1; + break; + } + if(done) + { + command_finish(); + break; + } + } + } + break; + } + + s3virge.s3d.bitblt_step_count++; +} + +TIMER_CALLBACK_MEMBER(s3virge_vga_device::draw_step_tick) +{ + // TODO: S3D state timing + switch(s3virge.s3d.state) + { + case S3D_STATE_IDLE: + m_draw_timer->adjust(attotime::zero); + break; + case S3D_STATE_2DLINE: + line2d_step(); + break; + case S3D_STATE_2DPOLY: + poly2d_step(); + break; + case S3D_STATE_3DLINE: + line3d_step(); + break; + case S3D_STATE_3DPOLY: + poly3d_step(); + break; + case S3D_STATE_BITBLT: + bitblt_step(); + break; + } +} + +inline void s3virge_vga_device::write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val) +{ + if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002) + if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b) + return; + vga.memory[(base + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = val & 0xff; + vga.memory[(base + 1 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 8) & 0xff; + vga.memory[(base + 2 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 16) & 0xff; + vga.memory[(base + 3 + (x*4) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 24) & 0xff; +} + +inline void s3virge_vga_device::write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val) +{ + if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002) + if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b) + return; + vga.memory[(base + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] = val & 0xff; + vga.memory[(base + 1 + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 8) & 0xff; + vga.memory[(base + 2 + (x*3) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 16) & 0xff; +} + +inline void s3virge_vga_device::write_pixel16(uint32_t base, uint16_t x, uint16_t y, uint16_t val) +{ + if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002) + if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b) + return; + vga.memory[(base + (x*2) + (y*dest_stride())) % vga.svga_intf.vram_size] = val & 0xff; + vga.memory[(base + 1 + (x*2) + (y*dest_stride())) % vga.svga_intf.vram_size] = (val >> 8) & 0xff; +} + +inline void s3virge_vga_device::write_pixel8(uint32_t base, uint16_t x, uint16_t y, uint8_t val) +{ + if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000002) + if(x < s3virge.s3d.clip_l || x > s3virge.s3d.clip_r || y < s3virge.s3d.clip_t || y > s3virge.s3d.clip_b) + return; + vga.memory[(base + x + (y*dest_stride())) % vga.svga_intf.vram_size] = val; +} + +inline uint32_t s3virge_vga_device::read_pixel32(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) +{ + return (vga.memory[(base + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 24) | + (vga.memory[(base + 1 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 16) | + (vga.memory[(base + 2 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size] << 8) | + vga.memory[(base + 3 + (x * 4) + (y * stride_select)) % vga.svga_intf.vram_size]; +} + +inline uint32_t s3virge_vga_device::read_pixel24(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) +{ + return (vga.memory[(base + (x * 3) + (y * stride_select)) % vga.svga_intf.vram_size]) | + (vga.memory[(base + 1 + (x * 3) + (y * stride_select)) % vga.svga_intf.vram_size] << 8) | + (vga.memory[(base + 2 + (x * 3) + (y * stride_select)) % vga.svga_intf.vram_size] << 16); +} + +inline uint16_t s3virge_vga_device::read_pixel16(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) +{ + return (vga.memory[(base + (x * 2) + (y * stride_select) % vga.svga_intf.vram_size)]) | + (vga.memory[(base + 1 + (x * 2) + (y * stride_select)) % vga.svga_intf.vram_size] << 8); +} + +inline uint8_t s3virge_vga_device::read_pixel8(uint32_t base, uint16_t x, uint16_t y, u16 stride_select) +{ + return vga.memory[(base + x + (y * stride_select)) % vga.svga_intf.vram_size]; +} + +// 2D command register format - A500 (BitBLT), A900 (2D line), AD00 (2D Polygon) +// bit 0 - Autoexecute, if set command is executed when the highest relevant register is written to (A50C / A97C / AD7C) +// bit 1 - Enable hardware clipping +// bits 2-4 - Destination colour format - (0 = 8bpp palettised, 1 = 16bpp RGB1555 or RGB565, 2 = 24bpp RGB888 +// bit 5 - Draw enable - if reset, doesn't draw anything, but is still executed +// bit 6 - Image source Mono transfer, if set source is mono, otherwise source is the same pixel depth as the destination +// bit 7 - Image data source - 0 = source is in video memory, 1 = source is from the image transfer port (CPU / system memory) +// bit 8 - Mono pattern - if set, pattern data is mono, otherwise pattern data is the same pixel depth as the destination +// Cleared to 0 if using an ROP with a colour source Must be set to 1 if doing a rectangle fill operation +// bit 9 - Transparency - if set, does not update if a background colour is selected. Effectively only if bit 7 is set, Typically used for text display. +// bits 10-11 - Image transfer alignment - Data for an image transfer is byte (0), word (1), or doubleword (2) aligned. All image transfers are doubleword in size. +// bits 12-13 - First doubleword offset - (Image transfers) - start with the given byte (+1) in a doubleword for an image transfer +// bits 17-24 - MS Windows Raster Operation +// bit 25 - X Positive - if set, BitBLT is performed from left to right, otherwise, from right to left +// bit 26 - Y Positive - if set, BitBLT is performed from top to bottom, otherwise from bottom to top +// bits 27-30 - 2D Command - 0000 = BitBLT, 0010 = Rectangle Fill, 0011 = Line Draw, 0101 = Polygon Fill, 1111 = NOP (Turns off autoexecute without executing a command) +// bit 31 - 2D / 3D Select + + +uint32_t s3virge_vga_device::s3d_sub_status_r() +{ + uint32_t res = 0x00000000; + + if(!s3virge.s3d.busy) + res |= 0x00002000; // S3d engine is idle + + //res |= (s3virge.s3d.cmd_fifo_slots_free << 8); + if(s3virge.s3d.cmd_fifo_slots_free == 16) + res |= 0x1f00; + + return res; +} + +void s3virge_vga_device::s3d_sub_control_w(uint32_t data) +{ + s3virge.interrupt_enable = data & 0x00003f80; + // TODO: bits 14-15==10 - reset engine + LOGMMIO("Sub control = %08x\n", data); +} + +/* + * Advanced Function Control Register (MM850C) + * ---- --xx xx-- ---- command fifo status + * ---- ---- ---x ---- LA ENB Linear Addressing Enable (mirror of CR58 bit 4) + * ---- ---- ---- --x- RST DM Reset read DMA + * ---- ---- ---- ---x ENB EHFC Enable enhanced functions (mirror of CR66 bit 0) + */ +uint32_t s3virge_vga_device::s3d_func_ctrl_r() +{ + uint32_t ret = 0; + + ret |= (s3virge.s3d.cmd_fifo_slots_free << 6); + return ret; +} + +uint32_t s3virge_vga_device::s3d_register_r(offs_t offset) +{ + uint32_t res = 0; + int op_type = (((offset*4) & 0x1c00) >> 10) - 1; + + // unused registers + if(offset < 0x100/4) + return 0; + if(offset >= 0x1c0/4 && offset < 0x400/4) + return 0; + + // handle BitBLT pattern registers + if((offset >= 0x100/4) && (offset < 0x1c0/4)) + return s3virge.s3d.pattern[offset - (0x100/4)]; + + res = s3virge.s3d.reg[op_type][((offset*4) & 0x03ff) / 4]; + LOGMMIO("MM%04X returning %08x\n", (offset*4)+0xa000, res); + + return res; +} + +void s3virge_vga_device::s3d_register_w(offs_t offset, uint32_t data) +{ + int op_type = (((offset*4) & 0x1c00) >> 10) - 1; + + // unused registers + if(offset < 0x100/4) + return; + if(offset >= 0x1c0/4 && offset < 0x400/4) + return; + + // handle BitBLT pattern registers + if((offset >= 0x100/4) && (offset < 0x1c0/4)) + { + //COMBINE_DATA(&s3virge.s3d.pattern[(offset*4) - (0x100/4)]); + s3virge.s3d.pattern[((offset - 0x100/4)*4)+3] = (data & 0xff000000) >> 24; + s3virge.s3d.pattern[((offset - 0x100/4)*4)+2] = (data & 0x00ff0000) >> 16; + s3virge.s3d.pattern[((offset - 0x100/4)*4)+1] = (data & 0x0000ff00) >> 8; + s3virge.s3d.pattern[((offset - 0x100/4)*4)] = (data & 0x000000ff); + return; + } + + s3virge.s3d.reg[op_type][((offset*4) & 0x03ff) / 4] = data; + LOGMMIO("MM%04X = %08x\n", (offset*4)+0xa000, data); + switch(offset) + { + case 0x500/4: + if(!(data & 0x00000001)) + add_command(op_type); + break; + case 0x50c/4: + if(s3virge.s3d.reg[op_type][S3D_REG_COMMAND] & 0x00000001) // autoexecute enabled + add_command(op_type); + break; + } +} + diff --git a/src/devices/video/s3virge.h b/src/devices/video/s3virge.h new file mode 100644 index 00000000000..67eef830e71 --- /dev/null +++ b/src/devices/video/s3virge.h @@ -0,0 +1,248 @@ +// license:BSD-3-Clause +// copyright-holders:Barry Rodewald +/* + * s3virge.h + * + * S3 ViRGE 2D/3D video card + * + */ + +#ifndef MAME_BUS_ISA_S3VIRGE_H +#define MAME_BUS_ISA_S3VIRGE_H + +#pragma once + +#include "video/pc_vga_s3.h" + +// ======================> s3virge_vga_device + +class s3virge_vga_device : public s3_vga_device +{ +public: + // construction/destruction + s3virge_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + auto linear_config_changed() { return m_linear_config_changed_cb.bind(); } + + virtual uint8_t mem_r(offs_t offset) override; + virtual void mem_w(offs_t offset, uint8_t data) override; + + uint8_t fb_r(offs_t offset); + void fb_w(offs_t offset, uint8_t data); + uint32_t s3d_sub_status_r(); + void s3d_sub_control_w(uint32_t data); + uint32_t s3d_func_ctrl_r(); + + uint32_t s3d_register_r(offs_t offset); + void s3d_register_w(offs_t offset, uint32_t data); + + void image_xfer(uint32_t data) + { +// if(s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x00000080) + { +// logerror("IMG Xfer:(%u):%08x X:%u(%u) Y:%u(%u)\n",s3virge.s3d.bitblt_step_count,data,s3virge.s3d.bitblt_x_current,s3virge.s3d.bitblt_width,s3virge.s3d.bitblt_y_current,s3virge.s3d.bitblt_height); + s3virge.s3d.image_xfer = data; + bitblt_step(); + } + } + + uint32_t get_linear_address() { return s3virge.linear_address; } + void set_linear_address(uint32_t addr) { s3virge.linear_address = addr; } + uint8_t get_linear_address_size() { return s3virge.linear_address_size; } + uint32_t get_linear_address_size_full() { return s3virge.linear_address_size_full; } + bool is_linear_address_active() { return s3virge.linear_address_enable; } + bool is_new_mmio_active() { return s3.cr53 & 0x08; } + uint16_t src_stride() + { + return (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 0) & 0xfff8; + } + uint16_t dest_stride() + { +// if((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_COMMAND] & 0x0000001c) == 0x08) +// { +// popmessage("Stride=%08x",(((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8) / 3) +// + ((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8)); +// return (((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8) / 3) +// + ((s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8); +// } +// else + return (s3virge.s3d.cmd_fifo[s3virge.s3d.cmd_fifo_current_ptr].reg[S3D_REG_DEST_SRC_STR] >> 16) & 0xfff8; + } + + ibm8514a_device* get_8514() { fatalerror("s3virge requested non-existent 8514/A device\n"); return nullptr; } + +protected: + s3virge_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual uint16_t offset() override; + + virtual void crtc_map(address_map &map) override; + + enum + { + LAW_64K = 0, + LAW_1MB, + LAW_2MB, + LAW_4MB + }; + + // register groups + enum + { + OP_BITBLT = 0, + OP_2DLINE, + OP_2DPOLY, + OP_3DLINE, + OP_3DTRI + }; + + enum + { + S3D_STATE_IDLE = 0, + S3D_STATE_BITBLT, + S3D_STATE_2DLINE, + S3D_STATE_2DPOLY, + S3D_STATE_3DLINE, + S3D_STATE_3DPOLY + }; + + enum + { + S3D_REG_SRC_BASE = 0xd4/4, + S3D_REG_DEST_BASE = 0xd8/4, + S3D_REG_CLIP_L_R = 0xdc/4, + S3D_REG_CLIP_T_B = 0xe0/4, + S3D_REG_DEST_SRC_STR = 0xe4/4, + S3D_REG_MONO_PAT_0 = 0xe8/4, + S3D_REG_MONO_PAT_1 = 0xec/4, + S3D_REG_PAT_BG_CLR = 0xf0/4, + S3D_REG_PAT_FG_CLR = 0xf4/4, + S3D_REG_SRC_BG_CLR = 0xf8/4, + S3D_REG_SRC_FG_CLR = 0xfc/4, + S3D_REG_COMMAND = 0x100/4, + S3D_REG_RWIDTH_HEIGHT = 0x104/4, + S3D_REG_RSRC_XY = 0x108/4, + S3D_REG_RDEST_XY = 0x10c/4 + }; + + struct + { + uint32_t linear_address; + uint8_t linear_address_size; + uint32_t linear_address_size_full; + bool linear_address_enable; + uint32_t interrupt_enable; + + struct + { + int state; + bool busy; + struct + { + uint32_t reg[256]; + int op_type; + } cmd_fifo[16]; + int cmd_fifo_next_ptr; // command added here in FIFO + int cmd_fifo_current_ptr; // command currently being processed in FIFO + int cmd_fifo_slots_free; + + uint8_t pattern[0xc0]; + uint32_t reg[5][256]; + + // BitBLT command state + uint16_t bitblt_x_src; + uint16_t bitblt_y_src; + uint16_t bitblt_x_dst; + uint16_t bitblt_y_dst; + int16_t bitblt_x_current; + int16_t bitblt_y_current; + int16_t bitblt_x_src_current; + int16_t bitblt_y_src_current; + int8_t bitblt_pat_x; + int8_t bitblt_pat_y; + uint16_t bitblt_height; + uint16_t bitblt_width; + uint32_t bitblt_step_count; + uint64_t bitblt_mono_pattern; + uint32_t bitblt_current_pixel; + uint32_t bitblt_pixel_pos; // current position in a pixel (for packed 24bpp colour image transfers) + uint32_t image_xfer; // source data via image transfer ports + uint16_t clip_l; + uint16_t clip_r; + uint16_t clip_t; + uint16_t clip_b; + } s3d; + } s3virge; + + TIMER_CALLBACK_MEMBER(draw_step_tick); + + inline void write_pixel32(uint32_t base, uint16_t x, uint16_t y, uint32_t val); + inline void write_pixel24(uint32_t base, uint16_t x, uint16_t y, uint32_t val); + inline void write_pixel16(uint32_t base, uint16_t x, uint16_t y, uint16_t val); + inline void write_pixel8(uint32_t base, uint16_t x, uint16_t y, uint8_t val); + inline uint32_t read_pixel32(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); + inline uint32_t read_pixel24(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); + inline uint16_t read_pixel16(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); + inline uint8_t read_pixel8(uint32_t base, uint16_t x, uint16_t y, u16 stride_select); + + uint32_t GetROP(uint8_t rop, uint32_t src, uint32_t dst, uint32_t pat); + bool advance_pixel(); + + devcb_write_line m_linear_config_changed_cb; + + virtual void s3_define_video_mode(void) override; + // has no 8514/A device +private: + emu_timer* m_draw_timer; + void bitblt_step(); + void bitblt_colour_step(); + void bitblt_monosrc_step(); + void line2d_step(); + void poly2d_step(); + void line3d_step(); + void poly3d_step(); + void add_command(int cmd_type); + void command_start(); + void command_finish(); +}; + + +// ======================> s3virgedx_vga_device + +class s3virgedx_vga_device : public s3virge_vga_device +{ +public: + // construction/destruction + s3virgedx_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + s3virgedx_vga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; +}; + +// ======================> s3virgedx_vga_device + +class s3virgedx_rev1_vga_device : public s3virgedx_vga_device +{ +public: + // construction/destruction + s3virgedx_rev1_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; +}; + +// device type definition +DECLARE_DEVICE_TYPE(S3VIRGE, s3virge_vga_device) +DECLARE_DEVICE_TYPE(S3VIRGEDX, s3virgedx_vga_device) +DECLARE_DEVICE_TYPE(S3VIRGEDX1, s3virgedx_rev1_vga_device) + +#endif // MAME_BUS_ISA_S3VIRGE_H diff --git a/src/devices/video/virge_pci.cpp b/src/devices/video/virge_pci.cpp index 08f392a8e0d..cd5ea859a85 100644 --- a/src/devices/video/virge_pci.cpp +++ b/src/devices/video/virge_pci.cpp @@ -36,9 +36,7 @@ void virge_pci_device::mmio_map(address_map& map) //map(0x1008220,0x1008227) DMA control // MMIO address map - map(0x10083b0,0x10083bf).rw(FUNC(virge_pci_device::vga_3b0_r), FUNC(virge_pci_device::vga_3b0_w)); - map(0x10083c0,0x10083df).rw(FUNC(virge_pci_device::vga_3c0_r), FUNC(virge_pci_device::vga_3c0_w)); - map(0x10083d0,0x10083df).rw(FUNC(virge_pci_device::vga_3d0_r), FUNC(virge_pci_device::vga_3d0_w)); + map(0x10083b0,0x10083df).m(m_vga, FUNC(s3virge_vga_device::io_map)); map(0x1008504,0x1008507).rw(m_vga, FUNC(s3virge_vga_device::s3d_sub_status_r), FUNC(s3virge_vga_device::s3d_sub_control_w)); map(0x100850c,0x100850f).r(m_vga, FUNC(s3virge_vga_device::s3d_func_ctrl_r)); @@ -67,6 +65,11 @@ void virge_pci_device::config_map(address_map &map) map(0x10, 0x13).rw(FUNC(virge_pci_device::base_address_r),FUNC(virge_pci_device::base_address_w)); } +void virge_pci_device::legacy_io_map(address_map &map) +{ + map(0x00, 0x2f).m(m_vga, FUNC(s3virge_vga_device::io_map)); +} + void virge_pci_device::refresh_linear_window() { if(downcast(m_vga.target())->is_linear_address_active()) @@ -114,132 +117,10 @@ void virge_pci_device::base_address_w(offs_t offset, uint32_t data) refresh_linear_window(); } -uint32_t virge_pci_device::vga_3b0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_vga.target())->port_03b0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_vga.target())->port_03b0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_vga.target())->port_03b0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_vga.target())->port_03b0_r(offset * 4 + 3) << 24; - return result; -} - -void virge_pci_device::vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - { - downcast(m_vga.target())->port_03b0_w(offset * 4 + 0, data >> 0); - if(offset == 1 && downcast(m_vga.target())->get_crtc_port() == 0x3b0) - m_current_crtc_reg = data & 0xff; - } - if (ACCESSING_BITS_8_15) - { - downcast(m_vga.target())->port_03b0_w(offset * 4 + 1, data >> 8); - // TODO: make this more transparent - // it shouldn't expose the S3 CRTC regs directly and don't repeat on 0x3d0 I/O below. - if(offset == 1 && downcast(m_vga.target())->get_crtc_port() == 0x3b0) - { - if (m_current_crtc_reg == 0x53) - { - refresh_linear_window(); - remap_cb(); - } - else if(m_current_crtc_reg == 0x58) - { - refresh_linear_window(); - remap_cb(); - } - else if(m_current_crtc_reg == 0x59 || m_current_crtc_reg == 0x5a) - { - refresh_linear_window(); - remap_cb(); - } - } - } - if (ACCESSING_BITS_16_23) - downcast(m_vga.target())->port_03b0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_vga.target())->port_03b0_w(offset * 4 + 3, data >> 24); -} - -uint32_t virge_pci_device::vga_3c0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_vga.target())->port_03c0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_vga.target())->port_03c0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_vga.target())->port_03c0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_vga.target())->port_03c0_r(offset * 4 + 3) << 24; - return result; -} - -void virge_pci_device::vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask) -{ - if (ACCESSING_BITS_0_7) - downcast(m_vga.target())->port_03c0_w(offset * 4 + 0, data >> 0); - if (ACCESSING_BITS_8_15) - downcast(m_vga.target())->port_03c0_w(offset * 4 + 1, data >> 8); - if (ACCESSING_BITS_16_23) - downcast(m_vga.target())->port_03c0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_vga.target())->port_03c0_w(offset * 4 + 3, data >> 24); -} - -uint32_t virge_pci_device::vga_3d0_r(offs_t offset, uint32_t mem_mask) -{ - uint32_t result = 0; - if (ACCESSING_BITS_0_7) - result |= downcast(m_vga.target())->port_03d0_r(offset * 4 + 0) << 0; - if (ACCESSING_BITS_8_15) - result |= downcast(m_vga.target())->port_03d0_r(offset * 4 + 1) << 8; - if (ACCESSING_BITS_16_23) - result |= downcast(m_vga.target())->port_03d0_r(offset * 4 + 2) << 16; - if (ACCESSING_BITS_24_31) - result |= downcast(m_vga.target())->port_03d0_r(offset * 4 + 3) << 24; - return result; -} - -void virge_pci_device::vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask) +void virge_pci_device::linear_config_changed_w(int state) { - if (ACCESSING_BITS_0_7) - { - downcast(m_vga.target())->port_03d0_w(offset * 4 + 0, data >> 0); - if(offset == 1 && downcast(m_vga.target())->get_crtc_port() == 0x3d0) - m_current_crtc_reg = data & 0xff; - } - if (ACCESSING_BITS_8_15) - { - downcast(m_vga.target())->port_03d0_w(offset * 4 + 1, data >> 8); - if(offset == 1 && downcast(m_vga.target())->get_crtc_port() == 0x3d0) - { - if (m_current_crtc_reg == 0x53) - { - refresh_linear_window(); - remap_cb(); - } - else if(m_current_crtc_reg == 0x58) - { - refresh_linear_window(); - remap_cb(); - } - else if(m_current_crtc_reg == 0x59 || m_current_crtc_reg == 0x5a) - { - refresh_linear_window(); - remap_cb(); - } - } - } - if (ACCESSING_BITS_16_23) - downcast(m_vga.target())->port_03d0_w(offset * 4 + 2, data >> 16); - if (ACCESSING_BITS_24_31) - downcast(m_vga.target())->port_03d0_w(offset * 4 + 3, data >> 24); + refresh_linear_window(); + remap_cb(); } uint8_t virge_pci_device::vram_r(offs_t offset) @@ -294,9 +175,7 @@ void virge_pci_device::map_extra(uint64_t memory_window_start, uint64_t memory_w { memory_space->install_readwrite_handler(0xa0000, 0xbffff, read8sm_delegate(*this, FUNC(virge_pci_device::vram_r)), write8sm_delegate(*this, FUNC(virge_pci_device::vram_w))); - io_space->install_readwrite_handler(0x3b0, 0x3bf, read32s_delegate(*this, FUNC(virge_pci_device::vga_3b0_r)), write32s_delegate(*this, FUNC(virge_pci_device::vga_3b0_w))); - io_space->install_readwrite_handler(0x3c0, 0x3cf, read32s_delegate(*this, FUNC(virge_pci_device::vga_3c0_r)), write32s_delegate(*this, FUNC(virge_pci_device::vga_3c0_w))); - io_space->install_readwrite_handler(0x3d0, 0x3df, read32s_delegate(*this, FUNC(virge_pci_device::vga_3d0_r)), write32s_delegate(*this, FUNC(virge_pci_device::vga_3d0_w))); + io_space->install_device(0x03b0, 0x03df, *this, &virge_pci_device::legacy_io_map); } void virge_pci_device::device_add_mconfig(machine_config &config) @@ -308,6 +187,7 @@ void virge_pci_device::device_add_mconfig(machine_config &config) S3VIRGE(config, m_vga, 0); m_vga->set_screen("screen"); m_vga->set_vram_size(0x400000); + m_vga->linear_config_changed().set(FUNC(virge_pci_device::linear_config_changed_w)); } void virgedx_pci_device::device_add_mconfig(machine_config &config) @@ -319,6 +199,7 @@ void virgedx_pci_device::device_add_mconfig(machine_config &config) S3VIRGEDX(config, m_vga, 0); m_vga->set_screen("screen"); m_vga->set_vram_size(0x400000); + m_vga->linear_config_changed().set(FUNC(virgedx_pci_device::linear_config_changed_w)); } diff --git a/src/devices/video/virge_pci.h b/src/devices/video/virge_pci.h index f4b6ce29009..51c902c871e 100644 --- a/src/devices/video/virge_pci.h +++ b/src/devices/video/virge_pci.h @@ -11,7 +11,7 @@ #pragma once #include "machine/pci.h" -#include "bus/isa/s3virge.h" +#include "video/s3virge.h" class virge_pci_device : public pci_device { @@ -37,17 +37,13 @@ public: void lfb_map(address_map &map); void mmio_map(address_map& map); - uint32_t vga_3b0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3b0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - uint32_t vga_3c0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3c0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); - uint32_t vga_3d0_r(offs_t offset, uint32_t mem_mask = ~0); - void vga_3d0_w(offs_t offset, uint32_t data, uint32_t mem_mask = ~0); uint8_t vram_r(offs_t offset); void vram_w(offs_t offset, uint8_t data); uint32_t base_address_r(); void base_address_w(offs_t offset, uint32_t data); + void legacy_io_map(address_map &map); + protected: virtual void device_start() override; virtual void device_add_mconfig(machine_config &config) override; @@ -63,10 +59,10 @@ protected: required_memory_region m_bios; optional_device m_screen; + void linear_config_changed_w(int state); + private: void refresh_linear_window(); - - uint8_t m_current_crtc_reg; }; class virgedx_pci_device : public virge_pci_device diff --git a/src/mame/be/bebox.cpp b/src/mame/be/bebox.cpp index 13fa5df8354..6f8e358035c 100644 --- a/src/mame/be/bebox.cpp +++ b/src/mame/be/bebox.cpp @@ -13,13 +13,14 @@ #include "bebox.h" /* Components */ -#include "video/clgd542x.h" #include "bus/lpci/cirrus.h" +#include "bus/lpci/mpc105.h" +#include "bus/scsi/scsi.h" #include "sound/ymopl.h" #include "machine/mc146818.h" #include "machine/pckeybrd.h" -#include "bus/lpci/mpc105.h" -#include "bus/scsi/scsi.h" +#include "video/pc_vga_cirrus.h" + #include "speaker.h" /* Devices */ @@ -51,9 +52,7 @@ void bebox_state::main_mem(address_map &map) map(0x800002F8, 0x800002FF).rw("ns16550_1", FUNC(ns16550_device::ins8250_r), FUNC(ns16550_device::ins8250_w)); map(0x80000380, 0x80000387).rw("ns16550_2", FUNC(ns16550_device::ins8250_r), FUNC(ns16550_device::ins8250_w)); map(0x80000388, 0x8000038F).rw("ns16550_3", FUNC(ns16550_device::ins8250_r), FUNC(ns16550_device::ins8250_w)); - map(0x800003b0, 0x800003bf).rw(m_vga, FUNC(cirrus_gd5428_device::port_03b0_r), FUNC(cirrus_gd5428_device::port_03b0_w)); - map(0x800003c0, 0x800003cf).rw(m_vga, FUNC(cirrus_gd5428_device::port_03c0_r), FUNC(cirrus_gd5428_device::port_03c0_w)); - map(0x800003d0, 0x800003df).rw(m_vga, FUNC(cirrus_gd5428_device::port_03d0_r), FUNC(cirrus_gd5428_device::port_03d0_w)); + map(0x800003B0, 0x800003DF).m(m_vga, FUNC(cirrus_gd5428_device::io_map)); map(0x800003F0, 0x800003F7).rw("ide", FUNC(ide_controller_device::cs1_r), FUNC(ide_controller_device::cs1_w)); map(0x800003F0, 0x800003F7).m(m_smc37c78, FUNC(smc37c78_device::map)); map(0x800003F8, 0x800003FF).rw("ns16550_0", FUNC(ns16550_device::ins8250_r), FUNC(ns16550_device::ins8250_w)); diff --git a/src/mame/funworld/photoply.cpp b/src/mame/funworld/photoply.cpp index 9cda9a4b2ce..6ec7dc91eb9 100644 --- a/src/mame/funworld/photoply.cpp +++ b/src/mame/funworld/photoply.cpp @@ -8,12 +8,14 @@ TODO (old notes, to be resorted with new PCI conversion): - BIOS CMOS doesn't save at all (needed for setting up the Hard Disk); - DISK BOOT FAILURE after EEPROM checking (many unknown IDE cs1 reads/writes); - Partition boot sector is missing from the CHD dump, protection? -- Detects CPU type as "-S 16 MHz"? Sometimes it detects it as 486SX, unknown repro (after fiddling with CMOS settings anyway) +- Detects CPU type as "-S 16 MHz"? Sometimes it detects it as 486SX, unknown repro + (after fiddling with CMOS settings anyway) - VGA BIOS reports being a Cirrus Logic GD5436 / 5446, it is unknown what exactly this game uses. -- PCI hookups (no idea about what this uses), and improve/device-ify SiS85C49x; +- PCI hookups (SiS496/SiS497 according to POST), and improve/device-ify SiS85C49x; - ISA bus cards are completely guessworked; - EEPROM timings are hacked (writes mostly fail otherwise); -- Eventually needs AudioDrive ES688 / ES1688 / ES1788 & ES1868 devices and serial ports "for linking" before actually booting; +- Eventually needs AudioDrive ES688 / ES1688 / ES1788 & ES1868 devices and serial ports "for linking" + before actually booting; INFO ABOUT SECURITY DONGLES: @@ -62,7 +64,7 @@ USB Dongle #include "machine/lpci.h" #include "machine/pckeybrd.h" #include "machine/idectrl.h" -#include "video/clgd542x.h" +#include "video/pc_vga_cirrus.h" namespace { @@ -252,9 +254,7 @@ void photoply_state::photoply_io(address_map &map) // map(0x0278, 0x027f).ram(); //parallel port 2 map(0x0370, 0x0377).rw("ide2", FUNC(ide_controller_32_device::cs1_r), FUNC(ide_controller_32_device::cs1_w)); // map(0x0378, 0x037f).ram(); //parallel port - map(0x03b0, 0x03bf).rw("vga", FUNC(cirrus_gd5446_device::port_03b0_r), FUNC(cirrus_gd5446_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw("vga", FUNC(cirrus_gd5446_device::port_03c0_r), FUNC(cirrus_gd5446_device::port_03c0_w)); - map(0x03d0, 0x03df).rw("vga", FUNC(cirrus_gd5446_device::port_03d0_r), FUNC(cirrus_gd5446_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(cirrus_gd5446_device::io_map)); map(0x03f0, 0x03f7).rw("ide", FUNC(ide_controller_32_device::cs1_r), FUNC(ide_controller_32_device::cs1_w)); diff --git a/src/mame/konami/konmedal020.cpp b/src/mame/konami/konmedal020.cpp index 9fcdaf79d62..0859b6452cd 100644 --- a/src/mame/konami/konmedal020.cpp +++ b/src/mame/konami/konmedal020.cpp @@ -72,10 +72,9 @@ void konmedal020_state::gs471_main(address_map &map) [this](offs_t a, u8 data){ m_vga->xga_write(0x70 + (a ^ 1), data); }, "srcxw"); map(0xe00078, 0xe00079).lrw8([this](offs_t a){ return m_vga->xga_read(0x78 + (a ^ 1)); }, "dstxr", [this](offs_t a, u8 data){ m_vga->xga_write(0x78 + (a ^ 1), data); }, "dstxw"); - map(0xf003b0, 0xf003bf).rw(m_vga, FUNC(oak_oti111_vga_device::port_03b0_r), FUNC(oak_oti111_vga_device::port_03b0_w)); - map(0xf003c0, 0xf003cf).rw(m_vga, FUNC(oak_oti111_vga_device::port_03c0_r), FUNC(oak_oti111_vga_device::port_03c0_w)); - map(0xf003d0, 0xf003df).rw(m_vga, FUNC(oak_oti111_vga_device::port_03d0_r), FUNC(oak_oti111_vga_device::port_03d0_w)); - map(0xf021e0, 0xf021e9).rw(m_vga, FUNC(oak_oti111_vga_device::dac_read), FUNC(oak_oti111_vga_device::dac_write)); + map(0xf003b0, 0xf003df).m(m_vga, FUNC(oak_oti111_vga_device::io_map)); + // was 0xf021e0-0xf021e9 (fails -validate) + map(0xf021e0, 0xf021ef).m(m_vga, FUNC(oak_oti111_vga_device::ramdac_mmio_map)); } static INPUT_PORTS_START( gs471 ) diff --git a/src/mame/misc/gambl186.cpp b/src/mame/misc/gambl186.cpp index e8817604696..1cddc2a96eb 100644 --- a/src/mame/misc/gambl186.cpp +++ b/src/mame/misc/gambl186.cpp @@ -57,7 +57,7 @@ TODO: #include "cpu/mcs51/mcs51.h" #include "machine/nvram.h" #include "sound/upd7759.h" -#include "video/clgd542x.h" +#include "video/pc_vga_cirrus.h" #include "speaker.h" @@ -393,9 +393,7 @@ void gambl186_state::gambl186_map(address_map &map) void gambl186_state::gambl186_io(address_map &map) { - map(0x03b0, 0x03bf).rw("vga", FUNC(cirrus_gd5428_device::port_03b0_r), FUNC(cirrus_gd5428_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw("vga", FUNC(cirrus_gd5428_device::port_03c0_r), FUNC(cirrus_gd5428_device::port_03c0_w)); - map(0x03d0, 0x03df).rw("vga", FUNC(cirrus_gd5428_device::port_03d0_r), FUNC(cirrus_gd5428_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(cirrus_gd5428_device::io_map)); map(0x0400, 0x0401).w(FUNC(gambl186_state::upd_w)); // upd7759 sample index/input map(0x0500, 0x0501).portr("IN0"); map(0x0502, 0x0503).portr("IN1"); diff --git a/src/mame/misc/gammagic.cpp b/src/mame/misc/gammagic.cpp index fea109d8305..0cb8a3f3b4d 100644 --- a/src/mame/misc/gammagic.cpp +++ b/src/mame/misc/gammagic.cpp @@ -93,9 +93,7 @@ void gammagic_state::gammagic_io(address_map &map) map(0x00e8, 0x00ef).noprw(); // map(0x00f0, 0x01ef).noprw(); // map(0x01f8, 0x03af).noprw(); -// map(0x03b0, 0x03bf).rw("vga", FUNC(vga_device::port_03b0_r), FUNC(vga_device::port_03b0_w)); -// map(0x03c0, 0x03cf).rw("vga", FUNC(vga_device::port_03c0_r), FUNC(vga_device::port_03c0_w)); -// map(0x03d0, 0x03df).rw("vga", FUNC(vga_device::port_03d0_r), FUNC(vga_device::port_03d0_w)); +// map(0x03b0, 0x03df).m("vga", FUNC(vga_device::io_map)); // map(0x03e0, 0x03ef).noprw(); // map(0x0cf8, 0x0cff).rw("pcibus", FUNC(pci_bus_device::read), FUNC(pci_bus_device::write)); // map(0x0400, 0xffff).noprw(); diff --git a/src/mame/misc/gamtor.cpp b/src/mame/misc/gamtor.cpp index e333f626c44..ba69765337b 100644 --- a/src/mame/misc/gamtor.cpp +++ b/src/mame/misc/gamtor.cpp @@ -38,25 +38,21 @@ // 65550 is used by Apple PowerBook 2400c // 65535 is used by IBM PC-110 -class gamtor_vga_device : public svga_device +class gamtor_vga_device : public svga_device { public: // construction/destruction gamtor_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - virtual uint8_t port_03b0_r(offs_t offset) override; - virtual void port_03b0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03c0_r(offs_t offset) override; - virtual void port_03c0_w(offs_t offset, uint8_t data) override; - virtual uint8_t port_03d0_r(offs_t offset) override; - virtual void port_03d0_w(offs_t offset, uint8_t data) override; // virtual uint8_t mem_r(offs_t offset) override; // virtual void mem_w(offs_t offset, uint8_t data) override; virtual uint8_t mem_linear_r(offs_t offset) override; virtual void mem_linear_w(offs_t offset,uint8_t data) override; protected: + virtual void io_3cx_map(address_map &map) override; + virtual void io_3bx_3dx_map(address_map &map) override; + virtual uint16_t offset() override; }; @@ -65,6 +61,32 @@ DEFINE_DEVICE_TYPE(GAMTOR_VGA, gamtor_vga_device, "gamtor_vga", "CT-65550 SVGA") gamtor_vga_device::gamtor_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : svga_device(mconfig, GAMTOR_VGA, tag, owner, clock) { + m_main_if_space_config = address_space_config("io_regs", ENDIANNESS_LITTLE, 8, 4, 0, address_map_constructor(FUNC(gamtor_vga_device::io_3bx_3dx_map), this)); +} + +// A0/A1 are inverted (protection or ct55550 feature?) +void gamtor_vga_device::io_3bx_3dx_map(address_map &map) +{ + map(0x04 ^ 3, 0x04 ^ 3).rw(FUNC(gamtor_vga_device::crtc_address_r), FUNC(gamtor_vga_device::crtc_address_w)); + map(0x05 ^ 3, 0x05 ^ 3).rw(FUNC(gamtor_vga_device::crtc_data_r), FUNC(gamtor_vga_device::crtc_data_w)); + map(0x0a ^ 3, 0x0a ^ 3).rw(FUNC(gamtor_vga_device::input_status_1_r), FUNC(gamtor_vga_device::feature_control_w)); +} + +void gamtor_vga_device::io_3cx_map(address_map &map) +{ + map(0x00 ^ 3, 0x00 ^ 3).rw(FUNC(gamtor_vga_device::atc_address_r), FUNC(gamtor_vga_device::atc_address_data_w)); + map(0x01 ^ 3, 0x01 ^ 3).r(FUNC(gamtor_vga_device::atc_data_r)); + map(0x02 ^ 3, 0x02 ^ 3).rw(FUNC(gamtor_vga_device::input_status_0_r), FUNC(gamtor_vga_device::miscellaneous_output_w)); + map(0x04 ^ 3, 0x04 ^ 3).rw(FUNC(gamtor_vga_device::sequencer_address_r), FUNC(gamtor_vga_device::sequencer_address_w)); + map(0x05 ^ 3, 0x05 ^ 3).rw(FUNC(gamtor_vga_device::sequencer_data_r), FUNC(gamtor_vga_device::sequencer_data_w)); + map(0x06 ^ 3, 0x06 ^ 3).rw(FUNC(gamtor_vga_device::ramdac_mask_r), FUNC(gamtor_vga_device::ramdac_mask_w)); + map(0x07 ^ 3, 0x07 ^ 3).rw(FUNC(gamtor_vga_device::ramdac_state_r), FUNC(gamtor_vga_device::ramdac_read_index_w)); + map(0x08 ^ 3, 0x08 ^ 3).rw(FUNC(gamtor_vga_device::ramdac_write_index_r), FUNC(gamtor_vga_device::ramdac_write_index_w)); + map(0x09 ^ 3, 0x09 ^ 3).rw(FUNC(gamtor_vga_device::ramdac_data_r), FUNC(gamtor_vga_device::ramdac_data_w)); + map(0x0a ^ 3, 0x0a ^ 3).r(FUNC(gamtor_vga_device::feature_control_r)); + map(0x0c ^ 3, 0x0c ^ 3).r(FUNC(gamtor_vga_device::miscellaneous_output_r)); + map(0x0e ^ 3, 0x0e ^ 3).rw(FUNC(gamtor_vga_device::gc_address_r), FUNC(gamtor_vga_device::gc_address_w)); + map(0x0f ^ 3, 0x0f ^ 3).rw(FUNC(gamtor_vga_device::gc_data_r), FUNC(gamtor_vga_device::gc_data_w)); } uint8_t gamtor_vga_device::mem_linear_r(offs_t offset) @@ -82,79 +104,6 @@ void gamtor_vga_device::mem_linear_w(offs_t offset, uint8_t data) vga.memory[(offset & 1) | (offset >> 1)] = data; } - -uint8_t gamtor_vga_device::port_03b0_r(offs_t offset) -{ - uint8_t res; - - switch(offset) - { - default: - res = vga_device::port_03b0_r(offset ^ 3); - break; - } - - return res; -} - -void gamtor_vga_device::port_03b0_w(offs_t offset, uint8_t data) -{ - switch(offset) - { - default: - vga_device::port_03b0_w(offset ^ 3,data); - break; - } -} - -uint8_t gamtor_vga_device::port_03c0_r(offs_t offset) -{ - uint8_t res; - - switch(offset) - { - default: - res = vga_device::port_03c0_r(offset ^ 3); - break; - } - - return res; -} - -void gamtor_vga_device::port_03c0_w(offs_t offset, uint8_t data) -{ - switch(offset) - { - default: - vga_device::port_03c0_w(offset ^ 3,data); - break; - } -} - -uint8_t gamtor_vga_device::port_03d0_r(offs_t offset) -{ - uint8_t res; - - switch(offset) - { - default: - res = vga_device::port_03d0_r(offset ^ 3); - break; - } - - return res; -} - -void gamtor_vga_device::port_03d0_w(offs_t offset, uint8_t data) -{ - switch(offset) - { - default: - vga_device::port_03d0_w(offset ^ 3,data); - break; - } -} - uint16_t gamtor_vga_device::offset() { // TODO: pinpoint whatever extra register that wants this shifted by 1 @@ -198,9 +147,7 @@ void gaminator_state::gaminator_map(address_map &map) /* standard VGA */ //map(0x40000000, 0x40000fff).ram(); // regs - map(0x400003b0, 0x400003bf).rw("vga", FUNC(gamtor_vga_device::port_03b0_r), FUNC(gamtor_vga_device::port_03b0_w)); - map(0x400003c0, 0x400003cf).rw("vga", FUNC(gamtor_vga_device::port_03c0_r), FUNC(gamtor_vga_device::port_03c0_w)); - map(0x400003d0, 0x400003df).rw("vga", FUNC(gamtor_vga_device::port_03d0_r), FUNC(gamtor_vga_device::port_03d0_w)); + map(0x400003b0, 0x400003df).m("vga", FUNC(gamtor_vga_device::io_map)); // TODO: revisit mapping in VGA core once it enters non-text mode map(0x44000000, 0x4401ffff).rw("vga", FUNC(gamtor_vga_device::mem_linear_r), FUNC(gamtor_vga_device::mem_linear_w)); diff --git a/src/mame/misc/magtouch.cpp b/src/mame/misc/magtouch.cpp index 01ea3e3c644..3157d90ee7c 100644 --- a/src/mame/misc/magtouch.cpp +++ b/src/mame/misc/magtouch.cpp @@ -160,9 +160,7 @@ void magtouch_state::magtouch_io(address_map &map) { pcat32_io_common(map); map(0x02e0, 0x02e7).rw(FUNC(magtouch_state::magtouch_io_r), FUNC(magtouch_state::magtouch_io_w)); - map(0x03b0, 0x03bf).rw("vga", FUNC(tvga9000_device::port_03b0_r), FUNC(tvga9000_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw("vga", FUNC(tvga9000_device::port_03c0_r), FUNC(tvga9000_device::port_03c0_w)); - map(0x03d0, 0x03df).rw("vga", FUNC(tvga9000_device::port_03d0_r), FUNC(tvga9000_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(tvga9000_device::io_map)); map(0x03f8, 0x03ff).rw("ns16450_0", FUNC(ns16450_device::ins8250_r), FUNC(ns16450_device::ins8250_w)); } diff --git a/src/mame/misc/pntnpuzl.cpp b/src/mame/misc/pntnpuzl.cpp index c11cfb5e46d..911881c3d90 100644 --- a/src/mame/misc/pntnpuzl.cpp +++ b/src/mame/misc/pntnpuzl.cpp @@ -307,11 +307,8 @@ void pntnpuzl_state::pntnpuzl_map(address_map &map) map(0x280018, 0x280019).w(FUNC(pntnpuzl_state::pntnpuzl_280018_w)); map(0x28001a, 0x28001b).r(FUNC(pntnpuzl_state::pntnpuzl_28001a_r)); - /* standard VGA */ map(0x3a0000, 0x3bffff).rw(m_svga, FUNC(tvga9000_device::mem_r), FUNC(tvga9000_device::mem_w)); - map(0x3c03b0, 0x3c03bf).rw(m_svga, FUNC(tvga9000_device::port_03b0_r), FUNC(tvga9000_device::port_03b0_w)); - map(0x3c03c0, 0x3c03cf).rw(m_svga, FUNC(tvga9000_device::port_03c0_r), FUNC(tvga9000_device::port_03c0_w)); - map(0x3c03d0, 0x3c03df).rw(m_svga, FUNC(tvga9000_device::port_03d0_r), FUNC(tvga9000_device::port_03d0_w)); + map(0x3c03b0, 0x3c03df).m(m_svga, FUNC(tvga9000_device::io_map)); // TODO: accesses $46e8 & 4ae8 at POST map(0x3c43c4, 0x3c43cb).rw(m_svga, FUNC(tvga9000_device::port_43c6_r), FUNC(tvga9000_device::port_43c6_w)); map(0x3c83c4, 0x3c83cb).rw(m_svga, FUNC(tvga9000_device::port_83c6_r), FUNC(tvga9000_device::port_83c6_w)); diff --git a/src/mame/misc/savquest.cpp b/src/mame/misc/savquest.cpp index 5c62923d21f..68813d0e71b 100644 --- a/src/mame/misc/savquest.cpp +++ b/src/mame/misc/savquest.cpp @@ -789,9 +789,7 @@ void savquest_state::savquest_io(address_map &map) map(0x0170, 0x0177).rw("ide2", FUNC(ide_controller_32_device::cs0_r), FUNC(ide_controller_32_device::cs0_w)); map(0x01f0, 0x01f7).rw("ide", FUNC(ide_controller_32_device::cs0_r), FUNC(ide_controller_32_device::cs0_w)); map(0x0378, 0x037b).rw(FUNC(savquest_state::parallel_port_r), FUNC(savquest_state::parallel_port_w)); - map(0x03b0, 0x03bf).rw(m_vga, FUNC(vga_device::port_03b0_r), FUNC(vga_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw(m_vga, FUNC(vga_device::port_03c0_r), FUNC(vga_device::port_03c0_w)); - map(0x03d0, 0x03df).rw(m_vga, FUNC(vga_device::port_03d0_r), FUNC(vga_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(s3_vga_device::io_map)); map(0x0370, 0x0377).rw("ide2", FUNC(ide_controller_32_device::cs1_r), FUNC(ide_controller_32_device::cs1_w)); map(0x03f0, 0x03f7).rw("ide", FUNC(ide_controller_32_device::cs1_r), FUNC(ide_controller_32_device::cs1_w)); diff --git a/src/mame/misc/su2000.cpp b/src/mame/misc/su2000.cpp index db9d238a528..886e57a0a8f 100644 --- a/src/mame/misc/su2000.cpp +++ b/src/mame/misc/su2000.cpp @@ -111,9 +111,7 @@ void su2000_state::pcat_map(address_map &map) void su2000_state::pcat_io(address_map &map) { pcat32_io_common(map); - map(0x03b0, 0x03bf).rw("vga", FUNC(vga_device::port_03b0_r), FUNC(vga_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw("vga", FUNC(vga_device::port_03c0_r), FUNC(vga_device::port_03c0_w)); - map(0x03d0, 0x03df).rw("vga", FUNC(vga_device::port_03d0_r), FUNC(vga_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(vga_device::io_map)); } diff --git a/src/mame/pc/fruitpc.cpp b/src/mame/pc/fruitpc.cpp index 639f077233a..5342c1284be 100644 --- a/src/mame/pc/fruitpc.cpp +++ b/src/mame/pc/fruitpc.cpp @@ -78,9 +78,7 @@ void fruitpc_state::fruitpc_io(address_map &map) pcat32_io_common(map); map(0x01f0, 0x01f7).rw("ide", FUNC(ide_controller_device::cs0_r), FUNC(ide_controller_device::cs0_w)); map(0x0310, 0x0313).r(FUNC(fruitpc_state::fruit_inp_r)); - map(0x03b0, 0x03bf).rw("vga", FUNC(vga_device::port_03b0_r), FUNC(vga_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw("vga", FUNC(vga_device::port_03c0_r), FUNC(vga_device::port_03c0_w)); - map(0x03d0, 0x03df).rw("vga", FUNC(vga_device::port_03d0_r), FUNC(vga_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(vga_device::io_map)); map(0x03f0, 0x03f7).rw("ide", FUNC(ide_controller_device::cs1_r), FUNC(ide_controller_device::cs1_w)); // map(0x0cf8, 0x0cff).rw(m_pcibus, FUNC(pci_bus_device::read), FUNC(pci_bus_device::write)); } diff --git a/src/mame/pc/pangofun.cpp b/src/mame/pc/pangofun.cpp index 17e6c547282..2e0712eb67b 100644 --- a/src/mame/pc/pangofun.cpp +++ b/src/mame/pc/pangofun.cpp @@ -142,9 +142,7 @@ void pangofun_state::pcat_io(address_map &map) { pcat32_io_common(map); map(0x00e0, 0x00e3).nopw(); - map(0x03b0, 0x03bf).rw("vga", FUNC(vga_device::port_03b0_r), FUNC(vga_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw("vga", FUNC(vga_device::port_03c0_r), FUNC(vga_device::port_03c0_w)); - map(0x03d0, 0x03df).rw("vga", FUNC(vga_device::port_03d0_r), FUNC(vga_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(vga_device::io_map)); } static INPUT_PORTS_START( pangofun ) diff --git a/src/mame/pc/paokaipc.cpp b/src/mame/pc/paokaipc.cpp index f10ad66b390..19dc62a72ce 100644 --- a/src/mame/pc/paokaipc.cpp +++ b/src/mame/pc/paokaipc.cpp @@ -64,9 +64,7 @@ void paokaipc_state::main_io(address_map &map) { pcat32_io_common(map); map(0x01f0, 0x01f7).rw("ide", FUNC(ide_controller_device::cs0_r), FUNC(ide_controller_device::cs0_w)); -// map(0x03b0, 0x03bf).rw("vga", FUNC(vga_device::port_03b0_r), FUNC(vga_device::port_03b0_w)); -// map(0x03c0, 0x03cf).rw("vga", FUNC(vga_device::port_03c0_r), FUNC(vga_device::port_03c0_w)); -// map(0x03d0, 0x03df).rw("vga", FUNC(vga_device::port_03d0_r), FUNC(vga_device::port_03d0_w)); +// map(0x03b0, 0x03df).m("vga", FUNC(vga_device::io_map)); map(0x03f0, 0x03f7).rw("ide", FUNC(ide_controller_device::cs1_r), FUNC(ide_controller_device::cs1_w)); // map(0x0880, 0x0880) extensively accessed at POST, hangs if returns wrong values // map(0x0cf8, 0x0cff).rw(m_pcibus, FUNC(pci_bus_device::read), FUNC(pci_bus_device::write)); diff --git a/src/mame/pc/pcat_dyn.cpp b/src/mame/pc/pcat_dyn.cpp index 906ed02fd68..e27f6439e26 100644 --- a/src/mame/pc/pcat_dyn.cpp +++ b/src/mame/pc/pcat_dyn.cpp @@ -121,9 +121,7 @@ void pcat_dyn_state::pcat_map(address_map &map) void pcat_dyn_state::pcat_io(address_map &map) { pcat32_io_common(map); - map(0x03b0, 0x03bf).rw("vga", FUNC(tvga9000_device::port_03b0_r), FUNC(tvga9000_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw("vga", FUNC(tvga9000_device::port_03c0_r), FUNC(tvga9000_device::port_03c0_w)); - map(0x03d0, 0x03df).rw("vga", FUNC(tvga9000_device::port_03d0_r), FUNC(tvga9000_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(tvga9000_device::io_map)); map(0x03f8, 0x03ff).rw("ns16550", FUNC(ns16550_device::ins8250_r), FUNC(ns16550_device::ins8250_w)); map(0x0530, 0x0533).r(FUNC(pcat_dyn_state::audio_r)); map(0x0534, 0x0537).rw("ad1848", FUNC(ad1848_device::read), FUNC(ad1848_device::write)); diff --git a/src/mame/pc/pcat_nit.cpp b/src/mame/pc/pcat_nit.cpp index ac24650b42f..ba46242612f 100644 --- a/src/mame/pc/pcat_nit.cpp +++ b/src/mame/pc/pcat_nit.cpp @@ -91,7 +91,7 @@ Smitdogg #include "machine/ins8250.h" #include "machine/microtch.h" #include "machine/nvram.h" -#include "video/clgd542x.h" +#include "video/pc_vga_cirrus.h" namespace { @@ -210,9 +210,7 @@ void pcat_nit_state::pcat_nit_io(address_map &map) pcat32_io_common(map); map(0x0278, 0x027f).r(FUNC(pcat_nit_state::pcat_nit_io_r)).nopw(); map(0x0280, 0x0283).nopr(); - map(0x03b0, 0x03bf).rw("vga", FUNC(vga_device::port_03b0_r), FUNC(vga_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw("vga", FUNC(vga_device::port_03c0_r), FUNC(vga_device::port_03c0_w)); - map(0x03d0, 0x03df).rw("vga", FUNC(vga_device::port_03d0_r), FUNC(vga_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(vga_device::io_map)); map(0x03f8, 0x03ff).rw(m_uart, FUNC(ns16450_device::ins8250_r), FUNC(ns16450_device::ins8250_w)); } @@ -221,9 +219,7 @@ void pcat_nit_state::bonanza_io_map(address_map &map) pcat32_io_common(map); map(0x0278, 0x027f).r(FUNC(pcat_nit_state::pcat_nit_io_r)).nopw(); map(0x0280, 0x0283).nopr(); - map(0x03b0, 0x03bf).rw("vga", FUNC(cirrus_gd5428_device::port_03b0_r), FUNC(cirrus_gd5428_device::port_03b0_w)); - map(0x03c0, 0x03cf).rw("vga", FUNC(cirrus_gd5428_device::port_03c0_r), FUNC(cirrus_gd5428_device::port_03c0_w)); - map(0x03d0, 0x03df).rw("vga", FUNC(cirrus_gd5428_device::port_03d0_r), FUNC(cirrus_gd5428_device::port_03d0_w)); + map(0x03b0, 0x03df).m("vga", FUNC(cirrus_gd5428_device::io_map)); map(0x03f8, 0x03ff).rw(m_uart, FUNC(ns16450_device::ins8250_r), FUNC(ns16450_device::ins8250_w)); } diff --git a/src/mame/pc/queen.cpp b/src/mame/pc/queen.cpp index f19f1be74a0..062f5fcc8c9 100644 --- a/src/mame/pc/queen.cpp +++ b/src/mame/pc/queen.cpp @@ -263,9 +263,7 @@ void queen_state::queen_io(address_map &map) map(0x0170, 0x0177).rw("ide2", FUNC(ide_controller_32_device::cs0_r), FUNC(ide_controller_32_device::cs0_w)); map(0x01f0, 0x01f7).rw("ide", FUNC(ide_controller_device::cs0_r), FUNC(ide_controller_device::cs0_w)); map(0x0370, 0x0377).rw("ide2", FUNC(ide_controller_32_device::cs1_r), FUNC(ide_controller_32_device::cs1_w)); -// map(0x03b0, 0x03bf).rw("vga", FUNC(vga_device::port_03b0_r), FUNC(vga_device::port_03b0_w)); -// map(0x03c0, 0x03cf).rw("vga", FUNC(vga_device::port_03c0_r), FUNC(vga_device::port_03c0_w)); -// map(0x03d0, 0x03df).rw("vga", FUNC(vga_device::port_03d0_r), FUNC(vga_device::port_03d0_w)); +// map(0x03b0, 0x03df).m("vga", FUNC(vga_device::io_map)); map(0x03f0, 0x03f7).rw("ide", FUNC(ide_controller_device::cs1_r), FUNC(ide_controller_device::cs1_w)); map(0x0cf8, 0x0cff).rw("pcibus", FUNC(pci_bus_legacy_device::read), FUNC(pci_bus_legacy_device::write)); diff --git a/src/mame/trs/vis.cpp b/src/mame/trs/vis.cpp index f214fa57330..60bb409a386 100644 --- a/src/mame/trs/vis.cpp +++ b/src/mame/trs/vis.cpp @@ -237,8 +237,7 @@ class vis_vga_device : public svga_device, { public: vis_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - uint8_t vga_r(offs_t offset); - void vga_w(offs_t offset, uint8_t data); + uint8_t visvgamem_r(offs_t offset); void visvgamem_w(offs_t offset, uint8_t data); protected: @@ -246,18 +245,30 @@ protected: virtual void device_reset() override; virtual void device_add_mconfig(machine_config &config) override; virtual void recompute_params() override; + + virtual void io_3cx_map(address_map &map) override; + + virtual void crtc_map(address_map &map) override; + virtual void gc_map(address_map &map) override; + virtual void sequencer_map(address_map &map) override; + + void io_isa_map(address_map &map); private: + u8 ramdac_hidden_mask_r(offs_t offset); + void ramdac_hidden_mask_w(offs_t offset, u8 data); + void vga_vh_yuv8(bitmap_rgb32 &bitmap, const rectangle &cliprect); void vga_vh_yuv422(bitmap_rgb32 &bitmap, const rectangle &cliprect); rgb_t yuv_to_rgb(int y, int u, int v) const; virtual uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) override; + inline void flush_8bpp_mode(); + int m_extcnt = 0; uint8_t m_extreg = 0U; uint8_t m_interlace = 0U; uint16_t m_wina = 0U, m_winb = 0U; uint8_t m_shift256 = 0U, m_dw = 0U, m_8bit_640 = 0U; - uint8_t m_crtc_regs[0x32]{}; }; DEFINE_DEVICE_TYPE(VIS_VGA, vis_vga_device, "vis_vga", "vis_vga") @@ -268,6 +279,9 @@ vis_vga_device::vis_vga_device(const machine_config &mconfig, const char *tag, d { set_screen(*this, "screen"); set_vram_size(0x100000); + m_crtc_space_config = address_space_config("crtc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(vis_vga_device::crtc_map), this)); + m_gc_space_config = address_space_config("gc_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(vis_vga_device::gc_map), this)); + m_seq_space_config = address_space_config("sequencer_regs", ENDIANNESS_LITTLE, 8, 8, 0, address_map_constructor(FUNC(vis_vga_device::sequencer_map), this)); } void vis_vga_device::device_add_mconfig(machine_config &config) @@ -277,6 +291,279 @@ void vis_vga_device::device_add_mconfig(machine_config &config) screen.set_screen_update(FUNC(vis_vga_device::screen_update)); } +void vis_vga_device::io_3cx_map(address_map &map) +{ + svga_device::io_3cx_map(map); + map(0x06, 0x06).rw(FUNC(vis_vga_device::ramdac_hidden_mask_r), FUNC(vis_vga_device::ramdac_hidden_mask_w)); +} + +void vis_vga_device::crtc_map(address_map &map) +{ + svga_device::crtc_map(map); + // Override with interlace into account + map(0x00, 0x00).lw8( + NAME([this] (offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_total = data / (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); + recompute_params(); + }) + ); + map(0x01, 0x01).lw8( + NAME([this] (offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_disp_end = (data / (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1)) | 1; + recompute_params(); + }) + ); + map(0x02, 0x02).lw8( + NAME([this] (offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_blank_start = data / (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); + }) + ); + map(0x03, 0x03).lw8( + NAME([this] (offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_blank_end = (vga.crtc.data[0x05] & 0x80) >> 2; + vga.crtc.horz_blank_end |= data & 0x1f; + vga.crtc.horz_blank_end /= (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); + vga.crtc.disp_enable_skew = (data & 0x60) >> 5; + vga.crtc.evra = (data & 0x80) >> 7; + }) + ); + map(0x04, 0x04).lw8( + NAME([this] (offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_retrace_start = data / (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); + }) + ); + map(0x05, 0x05).lw8( + NAME([this] (offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.horz_blank_end = vga.crtc.data[0x05] & 0x1f; + vga.crtc.horz_blank_end |= ((data & 0x80) >> 2); + vga.crtc.horz_blank_end /= (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); + vga.crtc.horz_retrace_skew = ((data & 0x60) >> 5); + vga.crtc.horz_retrace_end = data & 0x1f; + }) + ); + map(0x06, 0x06).lw8( + NAME([this] (offs_t offset, u8 data) { + if(vga.crtc.protect_enable) + return; + vga.crtc.vert_total = ((vga.crtc.data[0x07] & 0x20) << (9-6)) | ((vga.crtc.data[0x07] & 0x01) << (8-0)); + vga.crtc.vert_total |= data; + vga.crtc.vert_total *= (m_interlace ? 2 : 1); + recompute_params(); + }) + ); + map(0x07, 0x07).lw8( + NAME([this] (offs_t offset, u8 data) { // Overflow Register + vga.crtc.line_compare &= ~0x100; + vga.crtc.line_compare |= ((data & 0x10) << (8-4)); + if(vga.crtc.protect_enable) + return; + vga.crtc.vert_total = vga.crtc.data[0x05]; + vga.crtc.vert_retrace_start = vga.crtc.data[0x10]; + vga.crtc.vert_disp_end = vga.crtc.data[0x12]; + vga.crtc.vert_blank_start = vga.crtc.data[0x15] | ((vga.crtc.data[0x09] & 0x20) << (9-5)); + vga.crtc.vert_retrace_start |= ((data & 0x80) << (9-7)); + vga.crtc.vert_disp_end |= ((data & 0x40) << (9-6)); + vga.crtc.vert_total |= ((data & 0x20) << (9-5)); + vga.crtc.vert_blank_start |= ((data & 0x08) << (8-3)); + vga.crtc.vert_retrace_start |= ((data & 0x04) << (8-2)); + vga.crtc.vert_disp_end |= ((data & 0x02) << (8-1)); + vga.crtc.vert_total |= ((data & 0x01) << (8-0)); + vga.crtc.vert_total *= (m_interlace ? 2 : 1); + vga.crtc.vert_blank_start *= (m_interlace ? 2 : 1); + vga.crtc.vert_retrace_start *= (m_interlace ? 2 : 1); + vga.crtc.vert_disp_end *= (m_interlace ? 2 : 1); + recompute_params(); + }) + ); + map(0x09, 0x09).lw8( + NAME([this] (offs_t offset, u8 data) { // Maximum Scan Line Register + vga.crtc.line_compare &= ~0x200; + vga.crtc.vert_blank_start = vga.crtc.data[0x15] | ((vga.crtc.data[0x07] & 0x02) << (8-3)); + vga.crtc.scan_doubling = ((data & 0x80) >> 7); + vga.crtc.line_compare |= ((data & 0x40) << (9-6)); + vga.crtc.vert_blank_start |= ((data & 0x20) << (9-5)); + vga.crtc.maximum_scan_line = (data & 0x1f) + 1; + vga.crtc.vert_blank_start *= (m_interlace ? 2 : 1); + }) + ); + map(0x10, 0x10).lw8( + NAME([this] (offs_t offset, u8 data) { + vga.crtc.vert_retrace_start = ((vga.crtc.data[0x07] & 0x80) << (9-7)) | ((vga.crtc.data[0x07] & 0x40) << (8-2)); + vga.crtc.vert_retrace_start |= data; + vga.crtc.vert_retrace_start *= (m_interlace ? 2 : 1); + }) + ); + map(0x12, 0x12).lw8( + NAME([this] (offs_t offset, u8 data) { + vga.crtc.vert_disp_end = ((vga.crtc.data[0x07] & 0x40) << (9-6)) | ((vga.crtc.data[0x07] & 0x02) << (8-1)); + vga.crtc.vert_disp_end |= data; + vga.crtc.vert_disp_end *= (m_interlace ? 2 : 1); + recompute_params(); + }) + ); + map(0x15, 0x15).lw8( + NAME([this] (offs_t offset, u8 data) { + vga.crtc.vert_blank_start = ((vga.crtc.data[0x09] & 0x20) << (9-5)) | ((vga.crtc.data[0x07] & 0x02) << (8-3)); + vga.crtc.vert_blank_start |= data; + vga.crtc.vert_blank_start *= (m_interlace ? 2 : 1); + }) + ); + map(0x16, 0x16).lw8( + NAME([this] (offs_t offset, u8 data) { + vga.crtc.vert_blank_end = (data & 0x7f) * (m_interlace ? 2 : 1); + }) + ); + map(0x14, 0x14).lw8( + NAME([this] (offs_t offset, u8 data) { + m_dw = data & 0x40 ? 1 : 0; + if(vga.sequencer.data[0x1f] & 0x10) + data |= 0x40; + }) + ); + map(0x30, 0x30).lrw8( + NAME([this] (offs_t offset) { + return vga.crtc.data[0x30]; + }), + NAME([this] (offs_t offset, u8 data) { + if(data && !m_interlace) + { + if(!(vga.sequencer.data[0x25] & 0x20)) + { + vga.crtc.horz_total /= 2; + vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end / 2) | 1; + vga.crtc.horz_blank_end /= 2; + vga.crtc.horz_retrace_start /= 2; + vga.crtc.horz_retrace_end /= 2; + } + vga.crtc.vert_total *= 2; + vga.crtc.vert_retrace_start *= 2; + vga.crtc.vert_disp_end *= 2; + vga.crtc.vert_blank_start *= 2; + vga.crtc.vert_blank_end *= 2; + recompute_params(); + } + else if(!data && m_interlace) + { + if(!(vga.sequencer.data[0x25] & 0x20)) + { + vga.crtc.horz_total *= 2; + vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end * 2) | 1; + vga.crtc.horz_blank_end *= 2; + vga.crtc.horz_retrace_start *= 2; + vga.crtc.horz_retrace_end *= 2; + } + vga.crtc.vert_total /= 2; + vga.crtc.vert_retrace_start /= 2; + vga.crtc.vert_disp_end /= 2; + vga.crtc.vert_blank_start /= 2; + vga.crtc.vert_blank_end /= 2; + recompute_params(); + } + m_interlace = data; + }) + ); +} + +void vis_vga_device::gc_map(address_map &map) +{ + svga_device::gc_map(map); + map(0x05, 0x05).lw8( + NAME([this] (offs_t offset, u8 data) { + vga.gc.shift256 = BIT(data, 6); + // TODO: is this an hack? + if (vga.sequencer.data[0x1f] & 0x10) + vga.gc.shift256 = 1; + vga.gc.shift_reg = BIT(data, 5); + vga.gc.host_oe = BIT(data, 4); + vga.gc.read_mode = BIT(data, 3); + vga.gc.write_mode = data & 3; + //if(data & 0x10 && vga.gc.alpha_dis) + // popmessage("Host O/E enabled, contact MAMEdev"); + }) + ); +} + +void vis_vga_device::sequencer_map(address_map &map) +{ + svga_device::sequencer_map(map); + map(0x01, 0x01).lw8( + NAME([this] (offs_t offset, u8 data) { + m_8bit_640 = !BIT(data, 3); + flush_8bpp_mode(); + }) + ); + map(0x18, 0x18).lrw8( + NAME([this] (offs_t offset) { + return m_wina >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + m_wina = (m_wina & 0xff) | (data << 8); + }) + ); + map(0x19, 0x19).lrw8( + NAME([this] (offs_t offset) { + return m_wina & 0xff; + }), + NAME([this] (offs_t offset, u8 data) { + m_wina = (m_wina & 0xff00) | data; + }) + ); + map(0x1c, 0x1c).lrw8( + NAME([this] (offs_t offset) { + return m_winb >> 8; + }), + NAME([this] (offs_t offset, u8 data) { + m_winb = (m_winb & 0xff) | (data << 8); + }) + ); + map(0x1d, 0x1d).lrw8( + NAME([this] (offs_t offset) { + return m_winb & 0xff; + }), + NAME([this] (offs_t offset, u8 data) { + m_winb = (m_winb & 0xff00) | data; + }) + ); + map(0x1f, 0x1f).lw8( + NAME([this] (offs_t offset, u8 data) { + if(data & 0x10) + { + vga.gc.shift256 = 1; + vga.crtc.dw = 1; + vga.crtc.no_wrap = 1; + } + else + { + vga.gc.shift256 = m_shift256; + vga.crtc.dw = m_dw; + vga.crtc.no_wrap = 0; + } + flush_8bpp_mode(); + }) + ); +} +void vis_vga_device::io_isa_map(address_map &map) +{ + map(0x00, 0x2f).m(FUNC(vis_vga_device::io_map)); +} + +void vis_vga_device::flush_8bpp_mode() +{ + svga.rgb8_en = m_8bit_640 && BIT(vga.sequencer.data[0x1f], 4); +} + void vis_vga_device::recompute_params() { int vblank_period,hblank_period; @@ -437,11 +724,10 @@ void vis_vga_device::vga_vh_yuv422(bitmap_rgb32 &bitmap, const rectangle &clipre void vis_vga_device::device_start() { set_isa_device(); - m_isa->install_device(0x03b0, 0x03df, read8sm_delegate(*this, FUNC(vis_vga_device::vga_r)), write8sm_delegate(*this, FUNC(vis_vga_device::vga_w))); m_isa->install_memory(0x0a0000, 0x0bffff, read8sm_delegate(*this, FUNC(vis_vga_device::visvgamem_r)), write8sm_delegate(*this, FUNC(vis_vga_device::visvgamem_w))); + m_isa->install_device(0x03b0, 0x03df, *this, &vis_vga_device::io_isa_map); + svga_device::device_start(); - vga.svga_intf.seq_regcount = 0x2d; - save_pointer(m_crtc_regs,"VIS CRTC",0x32); } void vis_vga_device::device_reset() @@ -507,249 +793,31 @@ void vis_vga_device::visvgamem_w(offs_t offset, uint8_t data) return mem_linear_w((offset + (m_wina * 64)) & 0x3ffff, data); } -uint8_t vis_vga_device::vga_r(offs_t offset) +u8 vis_vga_device::ramdac_hidden_mask_r(offs_t offset) { - switch(offset) + if(m_extcnt == 4) { - case 0x16: - if(m_extcnt == 4) - { - m_extcnt = 0; - return m_extreg; - } - m_extcnt++; - break; - case 0x05: - case 0x25: - return m_crtc_regs[vga.crtc.index]; + m_extcnt = 0; + return m_extreg; } - if(offset < 0x10) - return port_03b0_r(offset); - else if(offset < 0x20) - return port_03c0_r(offset - 0x10); - else - return port_03d0_r(offset - 0x20); + + if (!machine().side_effects_disabled()) + m_extcnt++; + + return vga_device::ramdac_mask_r(offset); } -void vis_vga_device::vga_w(offs_t offset, uint8_t data) +void vis_vga_device::ramdac_hidden_mask_w(offs_t offset, u8 data) { - switch(offset) + if(m_extcnt == 4) { - case 0x15: - switch(vga.sequencer.index) - { - case 0x01: - m_8bit_640 = (data & 8) ? 0 : 1; - if(m_8bit_640 && (vga.sequencer.data[0x1f] & 0x10)) - svga.rgb8_en = 1; - else - svga.rgb8_en = 0; - break; - case 0x19: - m_wina = (m_wina & 0xff00) | data; - break; - case 0x18: - m_wina = (m_wina & 0xff) | (data << 8); - break; - case 0x1d: - m_winb = (m_winb & 0xff00) | data; - break; - case 0x1c: - m_winb = (m_winb & 0xff) | (data << 8); - break; - case 0x1f: - if(data & 0x10) - { - vga.gc.shift256 = 1; - vga.crtc.dw = 1; - vga.crtc.no_wrap = 1; - if(m_8bit_640) - svga.rgb8_en = 1; - else - svga.rgb8_en = 0; - } - else - { - vga.gc.shift256 = m_shift256; - vga.crtc.dw = m_dw; - vga.crtc.no_wrap = 0; - svga.rgb8_en = 0; - } - break; - } - break; - case 0x16: - if(m_extcnt == 4) - { - if((data & 0xc7) != 0xc7) - m_extreg = data; - m_extcnt = 0; - return; - } - break; - case 0x1f: - if(vga.gc.index == 0x05) - { - m_shift256 = data & 0x40 ? 1 : 0; - if(vga.sequencer.data[0x1f] & 0x10) - data |= 0x40; - } - break; - case 0x05: - case 0x25: - assert(vga.crtc.index < std::size(m_crtc_regs)); - m_crtc_regs[vga.crtc.index] = data; - switch(vga.crtc.index) - { - case 0x00: - if(vga.crtc.protect_enable) - return; - vga.crtc.horz_total = data / (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); - recompute_params(); - return; - case 0x01: - if(vga.crtc.protect_enable) - return; - vga.crtc.horz_disp_end = (data / (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1)) | 1; - recompute_params(); - return; - case 0x02: - if(vga.crtc.protect_enable) - return; - vga.crtc.horz_blank_start = data / (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); - return; - case 0x03: - if(vga.crtc.protect_enable) - return; - vga.crtc.horz_blank_end = (m_crtc_regs[0x05] & 0x80) >> 2; - vga.crtc.horz_blank_end |= data & 0x1f; - vga.crtc.horz_blank_end /= (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); - vga.crtc.disp_enable_skew = (data & 0x60) >> 5; - vga.crtc.evra = (data & 0x80) >> 7; - return; - case 0x04: - if(vga.crtc.protect_enable) - return; - vga.crtc.horz_retrace_start = data / (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); - return; - case 0x05: - if(vga.crtc.protect_enable) - return; - vga.crtc.horz_blank_end = m_crtc_regs[0x05] & 0x1f; - vga.crtc.horz_blank_end |= ((data & 0x80) >> 2); - vga.crtc.horz_blank_end /= (m_interlace && !(vga.sequencer.data[0x25] & 0x20) ? 2 : 1); - vga.crtc.horz_retrace_skew = ((data & 0x60) >> 5); - vga.crtc.horz_retrace_end = data & 0x1f; - return; - case 0x06: - if(vga.crtc.protect_enable) - return; - vga.crtc.vert_total = ((m_crtc_regs[0x07] & 0x20) << (9-6)) | ((m_crtc_regs[0x07] & 0x01) << (8-0)); - vga.crtc.vert_total |= data; - vga.crtc.vert_total *= (m_interlace ? 2 : 1); - recompute_params(); - return; - case 0x07: // Overflow Register - vga.crtc.line_compare &= ~0x100; - vga.crtc.line_compare |= ((data & 0x10) << (8-4)); - if(vga.crtc.protect_enable) - return; - vga.crtc.vert_total = m_crtc_regs[0x05]; - vga.crtc.vert_retrace_start = m_crtc_regs[0x10]; - vga.crtc.vert_disp_end = m_crtc_regs[0x12]; - vga.crtc.vert_blank_start = m_crtc_regs[0x15] | ((m_crtc_regs[0x09] & 0x20) << (9-5)); - vga.crtc.vert_retrace_start |= ((data & 0x80) << (9-7)); - vga.crtc.vert_disp_end |= ((data & 0x40) << (9-6)); - vga.crtc.vert_total |= ((data & 0x20) << (9-5)); - vga.crtc.vert_blank_start |= ((data & 0x08) << (8-3)); - vga.crtc.vert_retrace_start |= ((data & 0x04) << (8-2)); - vga.crtc.vert_disp_end |= ((data & 0x02) << (8-1)); - vga.crtc.vert_total |= ((data & 0x01) << (8-0)); - vga.crtc.vert_total *= (m_interlace ? 2 : 1); - vga.crtc.vert_blank_start *= (m_interlace ? 2 : 1); - vga.crtc.vert_retrace_start *= (m_interlace ? 2 : 1); - vga.crtc.vert_disp_end *= (m_interlace ? 2 : 1); - recompute_params(); - return; - case 0x09: // Maximum Scan Line Register - vga.crtc.line_compare &= ~0x200; - vga.crtc.vert_blank_start = m_crtc_regs[0x15] | ((m_crtc_regs[0x07] & 0x02) << (8-3)); - vga.crtc.scan_doubling = ((data & 0x80) >> 7); - vga.crtc.line_compare |= ((data & 0x40) << (9-6)); - vga.crtc.vert_blank_start |= ((data & 0x20) << (9-5)); - vga.crtc.maximum_scan_line = (data & 0x1f) + 1; - vga.crtc.vert_blank_start *= (m_interlace ? 2 : 1); - return; - case 0x10: - vga.crtc.vert_retrace_start = ((m_crtc_regs[0x07] & 0x80) << (9-7)) | ((m_crtc_regs[0x07] & 0x40) << (8-2)); - vga.crtc.vert_retrace_start |= data; - vga.crtc.vert_retrace_start *= (m_interlace ? 2 : 1); - return; - case 0x12: - vga.crtc.vert_disp_end = ((m_crtc_regs[0x07] & 0x40) << (9-6)) | ((m_crtc_regs[0x07] & 0x02) << (8-1)); - vga.crtc.vert_disp_end |= data; - vga.crtc.vert_disp_end *= (m_interlace ? 2 : 1); - recompute_params(); - return; - case 0x15: - vga.crtc.vert_blank_start = ((m_crtc_regs[0x09] & 0x20) << (9-5)) | ((m_crtc_regs[0x07] & 0x02) << (8-3)); - vga.crtc.vert_blank_start |= data; - vga.crtc.vert_blank_start *= (m_interlace ? 2 : 1); - return; - case 0x16: - vga.crtc.vert_blank_end = (data & 0x7f) * (m_interlace ? 2 : 1); - return; - case 0x14: - m_dw = data & 0x40 ? 1 : 0; - if(vga.sequencer.data[0x1f] & 0x10) - data |= 0x40; - break; - case 0x30: - if(data && !m_interlace) - { - if(!(vga.sequencer.data[0x25] & 0x20)) - { - vga.crtc.horz_total /= 2; - vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end / 2) | 1; - vga.crtc.horz_blank_end /= 2; - vga.crtc.horz_retrace_start /= 2; - vga.crtc.horz_retrace_end /= 2; - } - vga.crtc.vert_total *= 2; - vga.crtc.vert_retrace_start *= 2; - vga.crtc.vert_disp_end *= 2; - vga.crtc.vert_blank_start *= 2; - vga.crtc.vert_blank_end *= 2; - recompute_params(); - } - else if(!data && m_interlace) - { - if(!(vga.sequencer.data[0x25] & 0x20)) - { - vga.crtc.horz_total *= 2; - vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end * 2) | 1; - vga.crtc.horz_blank_end *= 2; - vga.crtc.horz_retrace_start *= 2; - vga.crtc.horz_retrace_end *= 2; - } - vga.crtc.vert_total /= 2; - vga.crtc.vert_retrace_start /= 2; - vga.crtc.vert_disp_end /= 2; - vga.crtc.vert_blank_start /= 2; - vga.crtc.vert_blank_end /= 2; - recompute_params(); - } - m_interlace = data; - return; - } - break; + if((data & 0xc7) != 0xc7) + m_extreg = data; + m_extcnt = 0; + return; } - if(offset < 0x10) - port_03b0_w(offset, data); - else if(offset < 0x20) - port_03c0_w(offset - 0x10, data); - else - port_03d0_w(offset - 0x20, data); + + vga_device::ramdac_write_index_w(offset, data); } class vis_state : public driver_device -- cgit v1.2.3