From 94832b7f0f781da539800c675db7afd3299933db Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Sun, 2 Feb 2025 13:46:52 +0200 Subject: [PATCH] Matrox PCI card emulation. Misc 86box merges. --- gfxboard.cpp | 176 +- include/gfxboard.h | 8 +- od-win32/winuae_msvc15/winuae_msvc.vcxproj | 6 +- .../winuae_msvc15/winuae_msvc.vcxproj.filters | 6 + pcem/cpu.cpp | 2 + pcem/device.h | 71 +- pcem/dma.cpp | 1 + pcem/dma.h | 3 + pcem/ibm.h | 2 +- pcem/keyboard_at.cpp | 1 + pcem/mem.cpp | 1 + pcem/model.h | 4 +- pcem/nvr.cpp | 8 +- pcem/pcemglue.cpp | 190 +- pcem/pcemglue.h | 1 + pcem/pci.h | 30 +- pcem/pic.cpp | 2 + pcem/sound.h | 2 +- pcem/sound_cms.cpp | 7 +- pcem/sound_opl.cpp | 1 + pcem/sound_speaker.cpp | 2 + pcem/thread.h | 8 +- pcem/timer.h | 1 + pcem/vid_bt482_ramdac.cpp | 20 +- pcem/vid_cl5429.cpp | 173 +- pcem/vid_et4000.cpp | 20 +- pcem/vid_et4000w32.cpp | 50 +- pcem/vid_inmos.cpp | 63 +- pcem/vid_mga.cpp | 7120 +++++++++++++++++ pcem/vid_ncr.cpp | 46 +- pcem/vid_permedia2.cpp | 52 +- pcem/vid_s3.cpp | 38 +- pcem/vid_s3_virge.cpp | 30 +- pcem/vid_sc1502x_ramdac.cpp | 1 + pcem/vid_sdac_ramdac.cpp | 1 + pcem/vid_svga.cpp | 134 +- pcem/vid_svga.h | 47 +- pcem/vid_svga_render.cpp | 22 +- pcem/vid_tvp3026_ramdac.cpp | 756 ++ pcem/vid_voodoo.cpp | 19 +- pcem/vid_voodoo_banshee.cpp | 118 +- pcem/vid_voodoo_display.cpp | 12 +- pcem/vid_voodoo_fifo.cpp | 6 +- pcem/vid_voodoo_reg.cpp | 8 +- pcem/video.h | 93 +- x86.cpp | 11 +- 46 files changed, 8905 insertions(+), 468 deletions(-) create mode 100644 pcem/vid_mga.cpp create mode 100644 pcem/vid_tvp3026_ramdac.cpp diff --git a/gfxboard.cpp b/gfxboard.cpp index 80d83263..1bafeba3 100644 --- a/gfxboard.cpp +++ b/gfxboard.cpp @@ -33,6 +33,17 @@ static bool memlogw = true; #include "options.h" #include "uae.h" + +#include "pcem/device.h" +#include "pcem/vid_s3_virge.h" +#include "pcem/vid_cl5429.h" +#include "pcem/vid_s3.h" +#include "pcem/vid_voodoo_banshee.h" +#include "pcem/vid_ncr.h" +#include "pcem/vid_permedia2.h" +#include "pcem/vid_inmos.h" +#include "pcem/vid_et4000.h" + #include "memory.h" #include "debug.h" #include "custom.h" @@ -47,15 +58,6 @@ static bool memlogw = true; #include "devices.h" #include "gfxfilter.h" #include "flashrom.h" -#include "pcem/device.h" -#include "pcem/vid_s3_virge.h" -#include "pcem/vid_cl5429.h" -#include "pcem/vid_s3.h" -#include "pcem/vid_voodoo_banshee.h" -#include "pcem/vid_ncr.h" -#include "pcem/vid_permedia2.h" -#include "pcem/vid_inmos.h" -#include "pcem/vid_et4000.h" #include "pci.h" #include "pci_hw.h" #include "pcem/pcemglue.h" @@ -63,6 +65,7 @@ static bool memlogw = true; #include "qemuvga/vga.h" #include "draco.h" + extern void put_io_pcem(uaecptr, uae_u32, int); extern uae_u32 get_io_pcem(uaecptr, int); extern void put_mem_pcem(uaecptr, uae_u32, int); @@ -128,7 +131,7 @@ struct gfxboard uae_u32 romtype; uae_u8 er_type; struct gfxboard_func *func; - device_t *pcemdev; + const device_t *pcemdev; uae_u8 er_flags; int bustype; }; @@ -391,6 +394,34 @@ static const struct gfxboard boards[] = 0x00000000, 0x00200000, 0x00400000, 0x10000000, 0, 0, -1, false, false, 0, 0, NULL, &s3_trio64_device, 0, GFXBOARD_BUSTYPE_PCI }, + { + GFXBOARD_ID_MATROX_MILLENNIUM_PCI, + _T("Matrox Millennium [PCI]"), _T("Matrox"), _T("Matrox_Millennium"), + 0, 0, 0, 0, + 0x00000000, 0x00200000, 0x00400000, 0x10000000, 0, 0, -1, false, false, + 0, 0, NULL, &millennium_device, 0, GFXBOARD_BUSTYPE_PCI + }, + { + GFXBOARD_ID_MATROX_MILLENNIUM_II_PCI, + _T("Matrox Millennium II [PCI]"), _T("Matrox"), _T("Matrox_Millennium_II"), + 0, 0, 0, 0, + 0x00000000, 0x00200000, 0x01000000, 0x10000000, 0, 0, -1, false, false, + 0, 0, NULL, &millennium_ii_device, 0, GFXBOARD_BUSTYPE_PCI + }, + { + GFXBOARD_ID_MATROX_MYSTIQUE_PCI, + _T("Matrox Mystique [PCI]"), _T("Matrox"), _T("Matrox_Mystique"), + 0, 0, 0, 0, + 0x00000000, 0x00200000, 0x00800000, 0x10000000, 0, 0, -1, false, false, + 0, 0, NULL, &mystique_device, 0, GFXBOARD_BUSTYPE_PCI + }, + { + GFXBOARD_ID_MATROX_MYSTIQUE220_PCI, + _T("Matrox Mystique 220 [PCI]"), _T("Matrox"), _T("Matrox_Mystique220"), + 0, 0, 0, 0, + 0x00000000, 0x00200000, 0x00800000, 0x10000000, 0, 0, -1, false, false, + 0, 0, NULL, &mystique_220_device, 0, GFXBOARD_BUSTYPE_PCI + }, #if 0 { GFXBOARD_ID_GD5446_PCI, @@ -509,7 +540,7 @@ struct rtggfxboard struct gfxboard_func *func; - device_t *pcemdev; + const device_t *pcemdev; void *pcemobject; // device_t void *pcemobject2; // svga_t int pcem_mmio_offset; @@ -527,6 +558,7 @@ struct rtggfxboard int mmiobyteswapmode; struct pci_board_state *pcibs; bool pcem_direct; + int lfbbar; int width_redraw, height_redraw; @@ -1072,7 +1104,7 @@ static void init_board (struct rtggfxboard *gb) extern void initpcemvideo(void*, bool); extern void *svga_get_object(void); initpcemvideo(gb, gb->board->swap); - gb->pcemobject = gb->pcemdev->init(); + gb->pcemobject = gb->pcemdev->init(gb->pcemdev); gb->pcemobject2 = svga_get_object(); } picasso_allocatewritewatch(gb->rbc->rtg_index, gb->rbc->rtgmem_size); @@ -1164,6 +1196,7 @@ static void gfxboard_free_slot2(struct rtggfxboard *gb) } if (gb->pcemdev) { if (gb->pcemobject) { + pcemfreeaddeddevices(); gb->pcemdev->close(gb->pcemobject); gb->pcemobject = NULL; } @@ -1683,6 +1716,7 @@ void gfxboard_vsync_handler(bool full_redraw_required, bool redraw_required) } gb->pcem_vblank = 0; extern int console_logging; +#if 0 if (console_logging) { fcount++; if ((fcount % 50) == 0) { @@ -1696,6 +1730,7 @@ void gfxboard_vsync_handler(bool full_redraw_required, bool redraw_required) } } } +#endif if (!gb->board->hasswitcher && gb->vram) { bool svga_on(void *p); bool on = svga_on(gb->pcemobject2); @@ -3459,6 +3494,7 @@ static void gfxboard_free_board(struct rtggfxboard *gb) } if (gb->pcemdev) { if (gb->pcemobject) { + pcemfreeaddeddevices(); gb->pcemdev->close(gb->pcemobject); gb->pcemobject = NULL; gb->pcemobject2 = NULL; @@ -3912,6 +3948,20 @@ void gfxboard_voodoo_lfb_endianswap(int m) } } +void gfxboard_matrox_lfb_endianswap(int m) +{ + for (int i = 0; i < MAX_RTG_BOARDS; i++) { + struct rtggfxboard *gb = &rtggfxboards[i]; + if (gb->active && gb->board->bustype == GFXBOARD_BUSTYPE_PCI) { + write_log("%d\n", m); + if (m == 1) { + m = 3; + } + gb->lfbbyteswapmode = m; + } + } +} + static void pci_change_config(struct pci_board_state *pci) { struct rtggfxboard *gb = (struct rtggfxboard *)pci->userdata; @@ -3946,8 +3996,12 @@ static void pci_change_config(struct pci_board_state *pci) } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_S3VIRGE_PCI || gb->rbc->rtgmem_type == GFXBOARD_ID_S3TRIO64_PCI || gb->rbc->rtgmem_type == GFXBOARD_ID_PERMEDIA2_PCI || - gb->rbc->rtgmem_type == GFXBOARD_ID_GD5446_PCI) { - if (pci->memory_map_active) { + gb->rbc->rtgmem_type == GFXBOARD_ID_GD5446_PCI || + gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MILLENNIUM_PCI || + gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MILLENNIUM_II_PCI || + gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MYSTIQUE_PCI || + gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MYSTIQUE220_PCI) { + if (pci->memory_map_active) { struct pci_bridge *pcib = pci->bridge; reinit_vram(gb, pci->bar[0] + pcib->memory_start_offset[pcib->windowindex], false); } @@ -4008,7 +4062,7 @@ static void REGPARAM2 voodoo3_mb1_lput(struct pci_board_state *pcibs, uaecptr ad { struct rtggfxboard *gb = (struct rtggfxboard*)pcibs->userdata; int m = gb->lfbbyteswapmode; - addr -= pcibs->bar[1]; + addr -= pcibs->bar[gb->lfbbar]; addr &= 0x00ffffff; switch (m) { @@ -4039,7 +4093,7 @@ static uae_u32 REGPARAM2 voodoo3_mb1_lget(struct pci_board_state* pcibs, uaecptr struct rtggfxboard* gb = (struct rtggfxboard*)pcibs->userdata; int m = gb->lfbbyteswapmode; uae_u32 v = 0; - addr -= pcibs->bar[1]; + addr -= pcibs->bar[gb->lfbbar]; addr &= 0x00ffffff; switch (m) { @@ -4071,7 +4125,7 @@ static void REGPARAM2 voodoo3_mb1_wput(struct pci_board_state *pcibs, uaecptr ad { struct rtggfxboard *gb = (struct rtggfxboard*)pcibs->userdata; int m = gb->lfbbyteswapmode; - addr -= pcibs->bar[1]; + addr -= pcibs->bar[gb->lfbbar]; addr &= 0x00ffffff; switch (m) { @@ -4102,7 +4156,7 @@ static uae_u32 REGPARAM2 voodoo3_mb1_wget(struct pci_board_state* pcibs, uaecptr struct rtggfxboard* gb = (struct rtggfxboard*)pcibs->userdata; int m = gb->lfbbyteswapmode; uae_u32 v = 0; - addr -= pcibs->bar[1]; + addr -= pcibs->bar[gb->lfbbar]; addr &= 0x00ffffff; switch (m) { @@ -4134,7 +4188,7 @@ static void REGPARAM2 voodoo3_mb1_bput(struct pci_board_state *pcibs, uaecptr ad { struct rtggfxboard *gb = (struct rtggfxboard*)pcibs->userdata; int m = gb->lfbbyteswapmode; - addr -= pcibs->bar[1]; + addr -= pcibs->bar[gb->lfbbar]; addr &= 0x00ffffff; switch (m) { @@ -4150,7 +4204,7 @@ static uae_u32 REGPARAM2 voodoo3_mb1_bget(struct pci_board_state *pcibs, uaecptr { struct rtggfxboard *gb = (struct rtggfxboard*)pcibs->userdata; int m = gb->lfbbyteswapmode; - addr -= pcibs->bar[1]; + addr -= pcibs->bar[gb->lfbbar]; addr &= 0x00ffffff; switch (m) { @@ -4441,6 +4495,75 @@ static uae_u32 REGPARAM2 s3virge_io_bget(struct pci_board_state *pcibs, uaecptr return v; } +static void REGPARAM2 matrox_io_lput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b) +{ + put_mem_pcem(addr, b, 2); +} +static void REGPARAM2 matrox_io_wput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b) +{ + put_mem_pcem(addr, b, 1); +} +static void REGPARAM2 matrox_io_bput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b) +{ + put_mem_pcem(addr, b, 0); +} +static uae_u32 REGPARAM2 matrox_io_lget(struct pci_board_state *pcibs, uaecptr addr) +{ + uae_u32 b = get_mem_pcem(addr, 2); + return b; +} +static uae_u32 REGPARAM2 matrox_io_wget(struct pci_board_state *pcibs, uaecptr addr) +{ + uae_u16 b = get_mem_pcem(addr, 1); + return b; +} +static uae_u32 REGPARAM2 matrox_io_bget(struct pci_board_state *pcibs, uaecptr addr) +{ + uae_u32 v = get_mem_pcem(addr, 0); + return v; +} + +static const struct pci_config matrox_pci_config = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } +}; + +static const struct pci_board matrox_pci_board2 = +{ + _T("MATROX"), + &matrox_pci_config, NULL, NULL, NULL, NULL, NULL, + { + { voodoo3_mb1_lget, voodoo3_mb1_wget, voodoo3_mb1_bget, voodoo3_mb1_lput, voodoo3_mb1_wput, voodoo3_mb1_bput }, + { matrox_io_lget, matrox_io_wget, matrox_io_bget, matrox_io_lput, matrox_io_wput, matrox_io_bput }, + { NULL }, + { NULL }, + { NULL }, + { NULL }, + { voodoo3_bios_lget, voodoo3_bios_wget, voodoo3_bios_bget, NULL, NULL, NULL }, + { NULL }, + }, + true, + get_pci_pcem, put_pci_pcem, pci_change_config +}; + +static const struct pci_board matrox_pci_board = +{ + _T("MATROX"), + &matrox_pci_config, NULL, NULL, NULL, NULL, NULL, + { + { matrox_io_lget, matrox_io_wget, matrox_io_bget, matrox_io_lput, matrox_io_wput, matrox_io_bput }, + { voodoo3_mb1_lget, voodoo3_mb1_wget, voodoo3_mb1_bget, voodoo3_mb1_lput, voodoo3_mb1_wput, voodoo3_mb1_bput }, + { NULL }, + { NULL }, + { NULL }, + { NULL }, + { voodoo3_bios_lget, voodoo3_bios_wget, voodoo3_bios_bget, NULL, NULL, NULL }, + { NULL }, + }, + true, + get_pci_pcem, put_pci_pcem, pci_change_config +}; + static const struct pci_config s3virge_pci_config = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 } @@ -4451,7 +4574,7 @@ static const struct pci_board s3virge_pci_board = _T("S3VIRGE"), &s3virge_pci_config, NULL, NULL, NULL, NULL, NULL, { - { s3virge_mb0_lget, s3virge_mb0_wget, s3virge_mb0_bget, s3virge_mb0_lput, s3virge_mb0_wput, s3virge_mb0_bput }, + { voodoo3_mb0_lget, voodoo3_mb0_wget, voodoo3_mb0_bget, voodoo3_mb0_lput, voodoo3_mb0_wput, voodoo3_mb0_bput }, { NULL }, { NULL }, { NULL }, @@ -4947,6 +5070,7 @@ bool gfxboard_init_memory (struct autoconfig_info *aci) copyvrambank(&gb->gfxboard_bank_memory, gb->gfxmem_bank, false); gb->configured_mem = 1; gb->configured_regs = 1; + gb->lfbbar = 1; struct pci_bridge *b = pci_bridge_get(); if (b) { if (gb->rbc->rtgmem_type == GFXBOARD_ID_VOODOO3_PCI || gb->rbc->rtgmem_type == GFXBOARD_ID_VOODOO5_PCI) { @@ -4963,6 +5087,16 @@ bool gfxboard_init_memory (struct autoconfig_info *aci) gb->pcibs = pci_board_add(b, &s3trio_pci_board, -1, -1, aci, gb); } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_S3VIRGE_PCI) { gb->pcibs = pci_board_add(b, &s3virge_pci_board, -1, -1, aci, gb); + } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MILLENNIUM_PCI) { + gb->pcibs = pci_board_add(b, &matrox_pci_board, -1, -1, aci, gb); + } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MILLENNIUM_II_PCI) { + gb->pcibs = pci_board_add(b, &matrox_pci_board2, -1, -1, aci, gb); + gb->lfbbar = 0; + } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MYSTIQUE_PCI) { + gb->pcibs = pci_board_add(b, &matrox_pci_board, -1, -1, aci, gb); + } else if (gb->rbc->rtgmem_type == GFXBOARD_ID_MATROX_MYSTIQUE220_PCI) { + gb->pcibs = pci_board_add(b, &matrox_pci_board2, -1, -1, aci, gb); + gb->lfbbar = 0; } } gb->gfxboard_intena = 1; diff --git a/include/gfxboard.h b/include/gfxboard.h index dff51b12..9aa8ec7f 100644 --- a/include/gfxboard.h +++ b/include/gfxboard.h @@ -98,8 +98,12 @@ int pcem_getvramsize(void); #define GFXBOARD_ID_GRAFFITY_Z2 34 #define GFXBOARD_ID_GRAFFITY_Z3 35 #define GFXBOARD_ID_RAINBOWII 36 -#define GFXBOARD_ID_GD5446_PCI 37 -#define GFXBOARD_ID_VOODOO5_PCI 38 +#define GFXBOARD_ID_MATROX_MILLENNIUM_PCI 37 +#define GFXBOARD_ID_MATROX_MILLENNIUM_II_PCI 38 +#define GFXBOARD_ID_MATROX_MYSTIQUE_PCI 39 +#define GFXBOARD_ID_MATROX_MYSTIQUE220_PCI 40 +#define GFXBOARD_ID_GD5446_PCI 41 +#define GFXBOARD_ID_VOODOO5_PCI 42 #define GFXBOARD_BUSTYPE_Z 0 #define GFXBOARD_BUSTYPE_PCI 1 diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj b/od-win32/winuae_msvc15/winuae_msvc.vcxproj index fc43f670..6f944546 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj @@ -359,9 +359,9 @@ 4996;%(DisableSpecificWarnings) %(ForcedIncludeFiles) true - stdcpp20 + stdcpplatest /Zc:strictStrings- %(AdditionalOptions) - stdc17 + stdclatest false @@ -1393,6 +1393,7 @@ + @@ -1401,6 +1402,7 @@ + diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters index 839ce97f..829f6f01 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters @@ -1048,6 +1048,12 @@ common + + pcem + + + pcem + diff --git a/pcem/cpu.cpp b/pcem/cpu.cpp index 9d6ac58d..46f648bd 100644 --- a/pcem/cpu.cpp +++ b/pcem/cpu.cpp @@ -1,4 +1,6 @@ + #include "ibm.h" +#include "device.h" #include "cpu.h" #include "model.h" #include "io.h" diff --git a/pcem/device.h b/pcem/device.h index e7152b38..1f3248e7 100644 --- a/pcem/device.h +++ b/pcem/device.h @@ -25,19 +25,29 @@ typedef struct device_config_t typedef struct device_t { - char name[50]; - uint32_t flags; - void *(*init)(); - void (*close)(void *p); - int (*available)(); - void (*speed_changed)(void *p); - void (*force_redraw)(void *p); - void (*add_status_info)(char *s, int max_len, void *p); - device_config_t *config; + const char *name; + const char *internal_name; + uint32_t flags; /* system flags */ + uintptr_t local; /* flags local to device */ + + union { + void *(*init)(const struct device_t *); + void *(*init_ext)(const struct device_t *, void *); + }; + void (*close)(void *priv); + void (*reset)(void *priv); + union { + int (*available)(void); + int (*poll)(void *priv); + }; + void (*speed_changed)(void *priv); + void (*force_redraw)(void *priv); + + const device_config_t *config; } device_t; void device_init(); -void device_add(device_t *d); +void *device_add(const device_t *d); void device_close_all(); int device_available(device_t *d); void device_speed_changed(); @@ -49,16 +59,43 @@ extern char *current_device_name; int device_get_config_int(const char *name); char *device_get_config_string(const char *name); -enum -{ - DEVICE_NOT_WORKING = 1, /*Device does not currently work correctly and will be disabled in a release build*/ - DEVICE_AT = 2, /*Device requires an AT-compatible system*/ - DEVICE_MCA = 0x20, /*Device requires an MCA system*/ - DEVICE_PCI = 0x40, /*Device requires a PCI system*/ - DEVICE_PS1 = 0x80 /*Device is only for IBM PS/1 Model 2011*/ +enum { + DEVICE_PCJR = 2, /* requires an IBM PCjr */ + DEVICE_XTKBC = 4, /* requires an XT-compatible keyboard controller */ + DEVICE_AT = 8, /* requires an AT-compatible system */ + DEVICE_ATKBC = 0x10, /* requires an AT-compatible keyboard controller */ + DEVICE_PS2 = 0x20, /* requires a PS/1 or PS/2 system */ + DEVICE_ISA = 0x40, /* requires the ISA bus */ + DEVICE_CBUS = 0x80, /* requires the C-BUS bus */ + DEVICE_PCMCIA = 0x100, /* requires the PCMCIA bus */ + DEVICE_MCA = 0x200, /* requires the MCA bus */ + DEVICE_HIL = 0x400, /* requires the HP HIL bus */ + DEVICE_EISA = 0x800, /* requires the EISA bus */ + DEVICE_AT32 = 0x1000, /* requires the Mylex AT/32 local bus */ + DEVICE_OLB = 0x2000, /* requires the OPTi local bus */ + DEVICE_VLB = 0x4000, /* requires the VLB bus */ + DEVICE_PCI = 0x8000, /* requires the PCI bus */ + DEVICE_CARDBUS = 0x10000, /* requires the CardBus bus */ + DEVICE_USB = 0x20000, /* requires the USB bus */ + DEVICE_AGP = 0x40000, /* requires the AGP bus */ + DEVICE_AC97 = 0x80000, /* requires the AC'97 bus */ + DEVICE_COM = 0x100000, /* requires a serial port */ + DEVICE_LPT = 0x200000, /* requires a parallel port */ + DEVICE_KBC = 0x400000, /* is a keyboard controller */ + DEVICE_SOFTRESET = 0x800000, /* requires to be reset on soft reset */ + + DEVICE_ONBOARD = 0x40000000, /* is on-board */ + DEVICE_PIT = 0x80000000, /* device is a PIT */ + + DEVICE_ALL = 0xffffffff /* match all devices */ }; int model_get_config_int(const char *s); char *model_get_config_string(const char *s); +extern const device_t millennium_device; +extern const device_t millennium_ii_device; +extern const device_t mystique_device; +extern const device_t mystique_220_device; + #endif diff --git a/pcem/dma.cpp b/pcem/dma.cpp index e38fb07d..9c2cb079 100644 --- a/pcem/dma.cpp +++ b/pcem/dma.cpp @@ -1,5 +1,6 @@ #include "ibm.h" +#include "device.h" #include "dma.h" #include "fdc.h" #include "io.h" diff --git a/pcem/dma.h b/pcem/dma.h index d4b2c71f..ebede632 100644 --- a/pcem/dma.h +++ b/pcem/dma.h @@ -15,3 +15,6 @@ void writedma2(uint8_t temp); int dma_channel_read(int channel); int dma_channel_write(int channel, uint16_t val); + +void dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int TransferSize); +void dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, int TransferSize); diff --git a/pcem/ibm.h b/pcem/ibm.h index a4d405e7..48397a2a 100644 --- a/pcem/ibm.h +++ b/pcem/ibm.h @@ -501,7 +501,7 @@ void speedchanged(); void saveconfig(char *fn); void saveconfig_global_only(); -#define UNUSED(x) (void)x +#define UNUSED(x) x #define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/pcem/keyboard_at.cpp b/pcem/keyboard_at.cpp index 07729ac6..48c9bb76 100644 --- a/pcem/keyboard_at.cpp +++ b/pcem/keyboard_at.cpp @@ -1,6 +1,7 @@ #include "ibm.h" #include "io.h" #include "mem.h" +#include "device.h" #include "pic.h" #include "pit.h" #include "sound.h" diff --git a/pcem/mem.cpp b/pcem/mem.cpp index f2fcbb6c..7f5173f0 100644 --- a/pcem/mem.cpp +++ b/pcem/mem.cpp @@ -11,6 +11,7 @@ #include "config.h" #include "mem.h" +#include "device.h" #include "video.h" #include "x86.h" #include "cpu.h" diff --git a/pcem/model.h b/pcem/model.h index 6834e439..5b1c9846 100644 --- a/pcem/model.h +++ b/pcem/model.h @@ -30,7 +30,7 @@ typedef struct int min_ram, max_ram; int ram_granularity; void (*init)(); - struct device_t *device; + device_t *device; } MODEL; extern MODEL models[]; @@ -45,6 +45,6 @@ char *model_getname(); char *model_get_internal_name(); int model_get_model_from_internal_name(char *s); void model_init(); -struct device_t *model_getdevice(int model); +device_t *model_getdevice(int model); int model_has_fixed_gfx(int model); int model_has_optional_gfx(int model); diff --git a/pcem/nvr.cpp b/pcem/nvr.cpp index 7668a80a..fae178e2 100644 --- a/pcem/nvr.cpp +++ b/pcem/nvr.cpp @@ -490,7 +490,7 @@ void savenvr() } #endif -static void *nvr_init() +static void *nvr_init(const device_t *info) { nvr_t *nvr = (nvr_t *)malloc(sizeof(nvr_t)); memset(nvr, 0, sizeof(nvr_t)); @@ -512,13 +512,13 @@ static void nvr_close(void *p) device_t nvr_device = { - "Motorola MC146818 RTC", - 0, + "Motorola MC146818 RTC", NULL, + 0, 0, nvr_init, nvr_close, NULL, - nvr_speed_changed, NULL, + nvr_speed_changed, NULL, NULL }; diff --git a/pcem/pcemglue.cpp b/pcem/pcemglue.cpp index e9829cc6..866c1d97 100644 --- a/pcem/pcemglue.cpp +++ b/pcem/pcemglue.cpp @@ -4,6 +4,7 @@ #include "pit.h" #include "pic.h" #include "cpu.h" +#include "device.h" #include "model.h" #include "x86.h" #include "x86_ops.h" @@ -396,6 +397,7 @@ uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ uint8_t fontdat12x18[256][36]; /* IM1024 font */ uint8_t fontdatksc5601[16384][32]; /* Korean KSC-5601 font */ uint8_t fontdatksc5601_user[192][32]; /* Korean KSC-5601 user defined font */ +uint32_t *video_6to8; int PCI; int readflash; @@ -412,6 +414,8 @@ uint64_t timer_freq; uint8_t edatlookup[4][4]; uint8_t rotatevga[8][256]; uint32_t *video_15to32, *video_16to32; +monitor_t monitors[MONITORS_NUM]; +bitmap_t target_bitmap; static void *gfxboard_priv; @@ -516,6 +520,19 @@ static void timer_remove_headx(void) timer->enabled = 0; } } +void timer_advance_u64x(pc_timer_t *timer, uint64_t delay) +{ + uint32_t int_delay = delay >> 32; + uint32_t frac_delay = delay & 0xffffffff; + + if ((frac_delay + timer->ts_frac) < frac_delay) + timer->ts_integer++; + timer->ts_frac += frac_delay; + timer->ts_integer += int_delay; + + timer_enablex(timer); +} + void pcemglue_hsync(void) { @@ -541,6 +558,23 @@ void pcemvideorbswap(bool swapped) } } +static int calc_6to8(int c) +{ + int ic; + int i8; + double d8; + + ic = c; + if (ic == 64) + ic = 63; + else + ic &= 0x3f; + d8 = (ic / 63.0) * 255.0; + i8 = (int)d8; + + return (i8 & 0xff); +} + void initpcemvideo(void *p, bool swapped) { int c, d, e; @@ -596,12 +630,21 @@ void initpcemvideo(void *p, bool swapped) buffer32 = (PCBITMAP *)calloc(sizeof(PCBITMAP) + sizeof(uint8_t *) * 4096, 1); buffer32->w = 2048; buffer32->h = 4096; + target_bitmap.w = buffer32->w; + target_bitmap.h = buffer32->h; buffer32->dat = xcalloc(uae_u8, buffer32->w * buffer32->h * 4); + target_bitmap.dat = (uae_u32*)buffer32->dat; for (int i = 0; i < buffer32->h; i++) { buffer32->line[i] = buffer32->dat + buffer32->w * 4 * i; + target_bitmap.line[i] = (uae_u32*)buffer32->line[i]; } } + video_6to8 = (uint32_t*)malloc(4 * 256); + for (uint16_t c = 0; c < 256; c++) { + video_6to8[c] = calc_6to8(c); + } + pcem_linear_read_b = dummy_bread; pcem_linear_read_w = dummy_wread; pcem_linear_read_l = dummy_lread; @@ -611,6 +654,9 @@ void initpcemvideo(void *p, bool swapped) pcem_mapping_linear = NULL; pcem_mapping_linear_offset = 0; timer_head = NULL; + + monitors[0].mon_changeframecount = 2; + monitors[0].target_buffer = &target_bitmap; } extern void *svga_get_object(void); @@ -659,6 +705,11 @@ uae_u8 *getpcembuffer32(int x, int y, int yy) return buffer32->line[y + yy] + x * 4; } +void video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index) +{ +} + +int monitor_index_global; void video_wait_for_buffer(void) { @@ -670,6 +721,37 @@ void updatewindowsize(int x, int mx, int y, int my) gfxboard_resize(x, y, mx, my, gfxboard_priv); } +#define MAX_ADDED_DEVICES 8 + +struct addeddevice { + const device_t *dev; + void *priv; +}; + +static addeddevice added_devices[MAX_ADDED_DEVICES]; + +void *device_add(const device_t *d) +{ + for (int i = 0; i < MAX_ADDED_DEVICES; i++) { + if (!added_devices[i].dev) { + added_devices[i].dev = d; + added_devices[i].priv = d->init(d); + return added_devices[i].priv; + } + } + return NULL; +} + +void pcemfreeaddeddevices(void) +{ + for (int i = 0; i < MAX_ADDED_DEVICES; i++) { + if (added_devices[i].dev) { + added_devices[i].dev->close(added_devices[i].priv); + added_devices[i].dev = NULL; + } + } +} + static void (*pci_card_write)(int func, int addr, uint8_t val, void *priv); static uint8_t(*pci_card_read)(int func, int addr, void *priv); static void *pci_card_priv; @@ -689,6 +771,14 @@ uae_u8 get_pci_pcem(uaecptr addr) return v; } +void pci_add_card(uint8_t add_type, uint8_t(*read)(int func, int addr, void *priv), + void (*write)(int func, int addr, uint8_t val, void *priv), void *priv, uint8_t *slot) +{ + pci_card_read = read; + pci_card_write = write; + pci_card_priv = priv; +} + int pci_add(uint8_t(*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) { pci_card_read = read; @@ -701,12 +791,12 @@ void pci_set_irq_routing(int card, int irq) { //write_log(_T("pci_set_irq_routing %d %d\n"), card, irq); } -void pci_set_irq(int card, int pci_int) +void pci_set_irq(int card, int pci_int, uint8_t *state) { //write_log(_T("pci_set_irq %d %d\n"), card, pci_int); gfxboard_intreq(gfxboard_priv, 1, true); } -void pci_clear_irq(int card, int pci_int) +void pci_clear_irq(int card, int pci_int, uint8_t *state) { //write_log(_T("pci_clear_irq %d %d\n"), card, pci_int); gfxboard_intreq(gfxboard_priv, 0, true); @@ -737,6 +827,14 @@ event_t *thread_create_event(void) uae_sem_init(&sem, 1, 0); return sem; } +int thread_wait(thread_t *arg) +{ + if (!arg) { + return 0; + } + uae_sem_wait((uae_sem_t*)&arg); + return 1; +} void thread_set_event(event_t *event) { uae_sem_post((uae_sem_t*)&event); @@ -767,25 +865,47 @@ mutex_t* thread_create_mutex(void) return mutex; } -void thread_lock_mutex(mutex_t *_mutex) +int thread_wait_mutex(mutex_t *_mutex) { + if (!_mutex) { + return 0; + } win_mutex_t *mutex = (win_mutex_t*)_mutex; WaitForSingleObject(mutex->handle, INFINITE); + return 1; } -void thread_unlock_mutex(mutex_t *_mutex) +int thread_release_mutex(mutex_t *_mutex) { + if (!_mutex) { + return 0; + } win_mutex_t *mutex = (win_mutex_t*)_mutex; ReleaseSemaphore(mutex->handle, 1, NULL); + return 1; } -void thread_destroy_mutex(mutex_t *_mutex) +void thread_close_mutex(mutex_t *_mutex) { win_mutex_t *mutex = (win_mutex_t*)_mutex; CloseHandle(mutex->handle); xfree(mutex); } +int thread_test_mutex(mutex_t *_mutex) +{ + if (!_mutex) { + return 0; + } + win_mutex_t *mutex = (win_mutex_t *)_mutex; + DWORD ret = WaitForSingleObject(mutex->handle, 0); + if (ret == WAIT_OBJECT_0) + return 1; + return 0; +} + + + static mem_mapping_t *getmm(uaecptr *addrp) { uaecptr addr = *addrp; @@ -1105,3 +1225,63 @@ char *model_get_config_string(const char *s) void upc_set_mouse(void (*mouse_write)(uint8_t, void*), void *p) { } + + +/* DMA Bus Master Page Read/Write */ +void +dma_bm_read(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize, int TransferSize) +{ +#if 0 + uint32_t n; + uint32_t n2; + uint8_t bytes[4] = { 0, 0, 0, 0 }; + + n = TotalSize & ~(TransferSize - 1); + n2 = TotalSize - n; + + /* Do the divisible block, if there is one. */ + if (n) { + for (uint32_t i = 0; i < n; i += TransferSize) + mem_read_phys((void *)&(DataRead[i]), PhysAddress + i, TransferSize); + } + + /* Do the non-divisible block, if there is one. */ + if (n2) { + mem_read_phys((void *)bytes, PhysAddress + n, TransferSize); + memcpy((void *)&(DataRead[n]), bytes, n2); + } +#endif +} + +void +dma_bm_write(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize, int TransferSize) +{ +#if 0 + uint32_t n; + uint32_t n2; + uint8_t bytes[4] = { 0, 0, 0, 0 }; + + n = TotalSize & ~(TransferSize - 1); + n2 = TotalSize - n; + + /* Do the divisible block, if there is one. */ + if (n) { + for (uint32_t i = 0; i < n; i += TransferSize) + mem_write_phys((void *)&(DataWrite[i]), PhysAddress + i, TransferSize); + } + + /* Do the non-divisible block, if there is one. */ + if (n2) { + mem_read_phys((void *)bytes, PhysAddress + n, TransferSize); + memcpy(bytes, (void *)&(DataWrite[n]), n2); + mem_write_phys((void *)bytes, PhysAddress + n, TransferSize); + } + + if (dma_at) + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); +#endif +} + +void video_force_resize_set_monitor(uint8_t res, int monitor_index) +{ +} diff --git a/pcem/pcemglue.h b/pcem/pcemglue.h index 1a8a32b9..de674a56 100644 --- a/pcem/pcemglue.h +++ b/pcem/pcemglue.h @@ -1,6 +1,7 @@ extern void pcem_close(void); extern void pcemglue_hsync(void); +extern void pcemfreeaddeddevices(void); uint8_t keyboard_at_read(uint16_t port, void *priv); uint8_t mem_read_romext(uint32_t addr, void *priv); diff --git a/pcem/pci.h b/pcem/pci.h index 6a8778e0..88463b65 100644 --- a/pcem/pci.h +++ b/pcem/pci.h @@ -1,11 +1,15 @@ void pci_init(int type); void pci_slot(int card); + void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); int pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); +void pci_add_card(uint8_t add_type, uint8_t(*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv, uint8_t *slot); + void pci_set_irq_routing(int card, int irq); void pci_set_card_routing(int card, int pci_int); -void pci_set_irq(int card, int pci_int); -void pci_clear_irq(int card, int pci_int); +void pci_set_irq(int card, int pci_int, uint8_t *state); +void pci_clear_irq(int card, int pci_int, uint8_t *state); + #define PCI_REG_COMMAND 0x04 @@ -22,4 +26,26 @@ void pci_clear_irq(int card, int pci_int); #define PCI_IRQ_DISABLED -1 +enum { + PCI_ADD_NORTHBRIDGE = 0, + PCI_ADD_NORTHBRIDGE_SEC = 1, + PCI_ADD_AGPBRIDGE = 2, + PCI_ADD_SOUTHBRIDGE = 3, + PCI_ADD_SOUTHBRIDGE_IDE = 4, + PCI_ADD_SOUTHBRIDGE_PMU = 5, + PCI_ADD_SOUTHBRIDGE_USB = 6, + PCI_ADD_AGP = 0x0f, + PCI_ADD_NORMAL = 0x10, + PCI_ADD_VIDEO = 0x11, + PCI_ADD_HANGUL = 0x12, + PCI_ADD_IDE = 0x13, + PCI_ADD_SCSI = 0x14, + PCI_ADD_SOUND = 0x15, + PCI_ADD_MODEM = 0x16, + PCI_ADD_NETWORK = 0x17, + PCI_ADD_UART = 0x18, + PCI_ADD_USB = 0x19, + PCI_ADD_BRIDGE = 0x1a +}; + extern int pci_burst_time, pci_nonburst_time; diff --git a/pcem/pic.cpp b/pcem/pic.cpp index 59a41434..97db7d6e 100644 --- a/pcem/pic.cpp +++ b/pcem/pic.cpp @@ -1,4 +1,6 @@ + #include "ibm.h" +#include "device.h" #include "io.h" #include "pic.h" #include "pit.h" diff --git a/pcem/sound.h b/pcem/sound.h index 7c5bc984..2178820c 100644 --- a/pcem/sound.h +++ b/pcem/sound.h @@ -6,7 +6,7 @@ extern int sound_card_current; int sound_card_available(int card); char *sound_card_getname(int card); -struct device_t *sound_card_getdevice(int card); +device_t *sound_card_getdevice(int card); int sound_card_has_config(int card); char *sound_card_get_internal_name(int card); int sound_card_get_from_internal_name(char *s); diff --git a/pcem/sound_cms.cpp b/pcem/sound_cms.cpp index 470227dc..d582906a 100644 --- a/pcem/sound_cms.cpp +++ b/pcem/sound_cms.cpp @@ -174,7 +174,7 @@ uint8_t cms_read(uint16_t addr, void *p) return 0xff; } -void *cms_init() +void *cms_init(const device_t *info) { cms_t *cms = (cms_t*)malloc(sizeof(cms_t)); memset(cms, 0, sizeof(cms_t)); @@ -194,12 +194,11 @@ void cms_close(void *p) device_t cms_device = { - "Creative Music System / Game Blaster", - 0, + "Creative Music System / Game Blaster", NULL, + 0, 0, cms_init, cms_close, NULL, NULL, - NULL, NULL }; diff --git a/pcem/sound_opl.cpp b/pcem/sound_opl.cpp index 44c1af7d..d6eb50cc 100644 --- a/pcem/sound_opl.cpp +++ b/pcem/sound_opl.cpp @@ -1,6 +1,7 @@ #include #include #include "ibm.h" +#include "device.h" #include "io.h" #include "sound.h" #include "sound_opl.h" diff --git a/pcem/sound_speaker.cpp b/pcem/sound_speaker.cpp index 3eddc9db..73508dd6 100644 --- a/pcem/sound_speaker.cpp +++ b/pcem/sound_speaker.cpp @@ -1,4 +1,6 @@ + #include "ibm.h" +#include "device.h" #include "sound.h" #include "sound_speaker.h" diff --git a/pcem/thread.h b/pcem/thread.h index c8bcd0b4..0e82547f 100644 --- a/pcem/thread.h +++ b/pcem/thread.h @@ -1,6 +1,7 @@ typedef void thread_t; thread_t *thread_create(void (*thread_rout)(void *param), void *param); void thread_kill(thread_t *handle); +int thread_wait(thread_t *arg); typedef void event_t; event_t *thread_create_event(); @@ -11,8 +12,9 @@ void thread_destroy_event(event_t *_event); typedef void mutex_t; mutex_t *thread_create_mutex(void); -void thread_lock_mutex(mutex_t *mutex); -void thread_unlock_mutex(mutex_t *mutex); -void thread_destroy_mutex(mutex_t *mutex); +void thread_close_mutex(mutex_t *arg); +int thread_test_mutex(mutex_t *arg); +int thread_wait_mutex(mutex_t *arg); +int thread_release_mutex(mutex_t *mutex); void thread_sleep(int t); diff --git a/pcem/timer.h b/pcem/timer.h index d790bbd8..c2b4cd28 100644 --- a/pcem/timer.h +++ b/pcem/timer.h @@ -144,6 +144,7 @@ void timer_addx(pc_timer_t* timer, void (*callback)(void* p), void* p, int start void timer_enablex(pc_timer_t *timer); void timer_disablex(pc_timer_t *timer); void timer_set_delay_u64x(pc_timer_t *timer, uint64_t delay); +void timer_advance_u64x(pc_timer_t *timer, uint64_t delay); #endif diff --git a/pcem/vid_bt482_ramdac.cpp b/pcem/vid_bt482_ramdac.cpp index 3b1eb60a..9c4d8264 100644 --- a/pcem/vid_bt482_ramdac.cpp +++ b/pcem/vid_bt482_ramdac.cpp @@ -4,6 +4,7 @@ #include #include "ibm.h" #include "mem.h" +#include "device.h" #include "video.h" #include "vid_svga.h" #include "vid_sdac_ramdac.h" @@ -55,7 +56,6 @@ bt482_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga) svga->dac_pos = 0; svga->dac_status = addr & 0x03; svga->dac_addr = val; - svga->dac_write = val; if (svga->dac_status) svga->dac_addr = (svga->dac_addr + 1) & da_mask; break; @@ -72,25 +72,25 @@ bt482_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *priv, svga_t *svga) break; case 3: // cursor ramdac->cursor_r = val; - svga->dac_hwcursor.xsize = 32; - svga->dac_hwcursor.ysize = 32; + svga->dac_hwcursor.cur_xsize = 32; + svga->dac_hwcursor.cur_ysize = 32; svga->dac_hwcursor.ena = (val & 0x03) != 0; break; case 4: // cursor x low ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; break; case 5: // cursor x high ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; break; case 6: // cursor y low ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; break; case 7: // cursor y high ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; break; } } else { @@ -208,9 +208,9 @@ bt482_hwcursor_draw(svga_t *svga, int displine) /* The planes come in two parts, and each plane is 1bpp, 32x32 cursor has 4 bytes per line */ - pitch = (svga->dac_hwcursor_latch.xsize >> 3); /* Bytes per line. */ + pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */ /* A 32x32 cursor has 128 bytes per line */ - bppl = (pitch * svga->dac_hwcursor_latch.ysize); /* Bytes per plane. */ + bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */ if (svga->interlace && svga->dac_hwcursor_oddeven) svga->dac_hwcursor_latch.addr += pitch; @@ -218,7 +218,7 @@ bt482_hwcursor_draw(svga_t *svga, int displine) cd = (uint8_t *) ramdac->cursor32_data; mode = ramdac->cursor_r & 3; - for (int x = 0; x < svga->dac_hwcursor_latch.xsize; x += 16) { + for (int x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += 16) { dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | cd[svga->dac_hwcursor_latch.addr + 1]; dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | cd[svga->dac_hwcursor_latch.addr + bppl + 1]; diff --git a/pcem/vid_cl5429.cpp b/pcem/vid_cl5429.cpp index a76f0e3a..40d93b6d 100644 --- a/pcem/vid_cl5429.cpp +++ b/pcem/vid_cl5429.cpp @@ -169,14 +169,14 @@ static int gd5429_vga_vsync_enabled(gd5429_t *gd5429) static void gd5429_update_irqs(gd5429_t *gd5429) { if (gd5429->vblank_irq > 0 && gd5429_vga_vsync_enabled(gd5429)) - pci_set_irq(NULL, PCI_INTA); + pci_set_irq(NULL, PCI_INTA, NULL); else - pci_clear_irq(NULL, PCI_INTA); + pci_clear_irq(NULL, PCI_INTA, NULL); } static void gd5429_vblank_start(svga_t *svga) { - gd5429_t *gd5429 = (gd5429_t*)svga->p; + gd5429_t *gd5429 = (gd5429_t*)svga->priv; if (gd5429->vblank_irq >= 0) { gd5429->vblank_irq = 1; gd5429_update_irqs(gd5429); @@ -405,7 +405,7 @@ static void gd5429_vblank_start(svga_t *svga) // 5446 overlay static void gd5429_overlay_draw(svga_t *svga, int displine) { - gd5429_t *gd5429 = (gd5429_t*)svga->p; + gd5429_t *gd5429 = (gd5429_t*)svga->priv; int shift = gd5429->type >= CL_TYPE_GD5446 ? 2 : 0; int h_acc = svga->overlay_latch.h_acc; int r[8], g[8], b[8]; @@ -477,7 +477,7 @@ static void gd5429_update_overlay(gd5429_t *gd5429) svga_t *svga = &gd5429->svga; int bpp = svga->bpp; - svga->overlay.ysize = gd5429->overlay.wve - gd5429->overlay.wvs + 1; + svga->overlay.cur_ysize = gd5429->overlay.wve - gd5429->overlay.wvs + 1; gd5429->overlay.region1size = 32 * gd5429->overlay.r1sz / bpp + (gd5429->overlay.r1adjust * 8 / bpp); gd5429->overlay.region2size = 32 * gd5429->overlay.r2sz / bpp + (gd5429->overlay.r2adjust * 8 / bpp); @@ -539,16 +539,16 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p) break; case 0x12: svga->hwcursor.ena = val & 1; - svga->hwcursor.ysize = (val & 4) ? 64 : 32; + svga->hwcursor.cur_ysize = (val & 4) ? 64 : 32; svga->hwcursor.yoff = 0; - if (svga->hwcursor.ysize == 64) + if (svga->hwcursor.cur_ysize == 64) svga->hwcursor.addr = (0x3fc000 + ((svga->seqregs[0x13] & 0x3c) * 256)) & svga->vram_mask; else svga->hwcursor.addr = (0x3fc000 + ((svga->seqregs[0x13] & 0x3f) * 256)) & svga->vram_mask; // pclog("svga->hwcursor.ena = %i\n", svga->hwcursor.ena); break; case 0x13: - if (svga->hwcursor.ysize == 64) + if (svga->hwcursor.cur_ysize == 64) svga->hwcursor.addr = (0x3fc000 + ((val & 0x3c) * 256)) & svga->vram_mask; else svga->hwcursor.addr = (0x3fc000 + ((val & 0x3f) * 256)) & svga->vram_mask; @@ -591,7 +591,7 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p) gd5429->dac_3c6_count = 0; // Hidden CLUT entries 256 - 258 if (svga->dac_pos == 2 && (svga->seqregs[0x12] & 2)) { - hidden_dac_index = svga->dac_write; + hidden_dac_index = svga->dac_addr; pal_temp0 = svga->pallook[hidden_dac_index]; memcpy(&pal_temp1, &svga->vgapal[hidden_dac_index], sizeof(PALETTE)); } @@ -1157,7 +1157,7 @@ void gd5429_recalc_mapping(gd5429_t *gd5429) void gd5429_recalctimings(svga_t *svga) { - gd5429_t *gd5429 = (gd5429_t *)svga->p; + gd5429_t *gd5429 = (gd5429_t *)svga->priv; int clock = (svga->miscout >> 2) & 3; int n, d, p; double vclk; @@ -1253,7 +1253,7 @@ void gd5429_recalctimings(svga_t *svga) static void gd5429_adjust_panning(svga_t *svga) { - gd5429_t *gd5429 = (gd5429_t *)svga->p; + gd5429_t *gd5429 = (gd5429_t *)svga->priv; int ar11 = svga->attrregs[0x13] & 7; int src = 0, dst = 8; switch (svga->bpp) @@ -1291,7 +1291,7 @@ static void gd5429_adjust_panning(svga_t *svga) void gd5429_hwcursor_draw(svga_t *svga, int displine) { - gd5429_t *gd5429 = (gd5429_t *)svga->p; + gd5429_t *gd5429 = (gd5429_t *)svga->priv; int x; uint8_t dat[2]; int xx; @@ -2836,7 +2836,7 @@ static void *cl_init(int type, char *fn, int pci_card, uint32_t force_vram_size) if (fn) rom_init(&gd5429->bios_rom, fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - svga_init(&gd5429->svga, gd5429, (vram_size >= 256) ? (vram_size << 10) : (vram_size << 20), + svga_init(NULL, &gd5429->svga, gd5429, (vram_size >= 256) ? (vram_size << 10) : (vram_size << 20), gd5429_recalctimings, gd5429_in, gd5429_out, gd5429_hwcursor_draw, @@ -2903,39 +2903,39 @@ static void *cl_init(int type, char *fn, int pci_card, uint32_t force_vram_size) } -static void *avga2_init() +static void *avga2_init(const device_t *info) { return cl_init(CL_TYPE_AVGA2, "avga2vram.vbi", -1, 0); } -static void *avga2_cbm_sl386sx_init() +static void *avga2_cbm_sl386sx_init(const device_t *info) { return cl_init(CL_TYPE_AVGA2, "cbm_sl386sx25/c000.rom", -1, 0); } -static void *gd5426_ps1_init() +static void *gd5426_ps1_init(const device_t *info) { return cl_init(CL_TYPE_GD5426, NULL, -1, 1); } -static void *gd5426_init() +static void *gd5426_init(const device_t *info) { return cl_init(CL_TYPE_GD5426, "Picasso II", -1, 0); } -static void *gd5426_swapped_init() +static void *gd5426_swapped_init(const device_t *info) { gd5429_t *gd5429 = (gd5429_t*)cl_init(CL_TYPE_GD5426, "Picasso II", -1, 0); gd5429->svga.swaprb = 1; return gd5429; } -static void *gd5428_init() +static void *gd5428_init(const device_t *info) { return cl_init(CL_TYPE_GD5428, "Machspeed_VGA_GUI_2100_VLB.vbi", -1, 0); } -static void *gd5428_swapped_init() +static void *gd5428_swapped_init(const device_t *info) { gd5429_t *gd5429 = (gd5429_t *)cl_init(CL_TYPE_GD5428, "Picasso II", -1, 0); gd5429->svga.swaprb = 1; return gd5429; } -static void *ibm_gd5428_init() +static void *ibm_gd5428_init(const device_t *info) { gd5429_t *gd5429; svga_t *mb_vga = svga_get_pri(); @@ -2956,37 +2956,37 @@ static void *ibm_gd5428_init() return gd5429; } -static void *gd5429_init() +static void *gd5429_init(const device_t *info) { return cl_init(CL_TYPE_GD5429, "5429.vbi", -1, 0); } -static void *gd5430_init() +static void *gd5430_init(const device_t *info) { return cl_init(CL_TYPE_GD5430, "gd5430/pci.bin", -1, 0); } -static void *gd5430_pb570_init() +static void *gd5430_pb570_init(const device_t *info) { return cl_init(CL_TYPE_GD5430, "pb570/gd5430.bin", 8, 0); } -static void *gd5434_init() +static void *gd5434_init(const device_t *info) { return cl_init(CL_TYPE_GD5434, "gd5434.bin", -1, 0); } -static void *gd5434_vlb_swapped_init() +static void *gd5434_vlb_swapped_init(const device_t *info) { gd5429_t *gd5429 = (gd5429_t *)cl_init(CL_TYPE_GD5434, "CL", -1, 0); has_vlb = 1; gd5429->svga.swaprb = 1; return gd5429; } -static void *gd5434_vlb_init() +static void *gd5434_vlb_init(const device_t *info) { gd5429_t *gd5429 = (gd5429_t *)cl_init(CL_TYPE_GD5434, "CL", -1, 0); has_vlb = 1; gd5429->svga.swaprb = 0; return gd5429; } -static void *gd5446_init() +static void *gd5446_init(const device_t *info) { PCI = 1; gd5429_t *gd5429 = (gd5429_t *)cl_init(CL_TYPE_GD5446, "gd5446.bin", -1, 0); @@ -2994,7 +2994,7 @@ static void *gd5446_init() return gd5429; } -static void *gd5434_pb520r_init() +static void *gd5434_pb520r_init(const device_t *info) { return cl_init(CL_TYPE_GD5434, "pb520r/gd5434.bin", 3, 0); } @@ -3136,209 +3136,202 @@ static device_config_t gd5434_config[] = device_t avga2_device = { - "AVGA2 / Cirrus Logic GD5402", - 0, + "AVGA2 / Cirrus Logic GD5402", NULL, + 0, 0, avga2_init, gd5429_close, + NULL, avga2_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, avga2_config }; device_t avga2_cbm_sl386sx_device = { - "AVGA2 (Commodore SL386SX-25)", - 0, + "AVGA2 (Commodore SL386SX-25)", NULL, + 0, 0, avga2_cbm_sl386sx_init, gd5429_close, + NULL, gd5430_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, avga2_config }; device_t gd5426_ps1_device = { - "Cirrus Logic GD5426 (IBM PS/1)", - 0, + "Cirrus Logic GD5426 (IBM PS/1)", NULL, + 0, 0, gd5426_ps1_init, gd5429_close, NULL, + NULL, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, NULL }; device_t gd5426_device = { - "Cirrus Logic GD5426", - 0, + "Cirrus Logic GD5426", NULL, + 0, 0, gd5426_init, gd5429_close, + NULL, gd5428_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, gd5429_config }; device_t gd5426_swapped_device = { - "Cirrus Logic GD5426", - 0, + "Cirrus Logic GD5426", NULL, + 0, 0, gd5426_swapped_init, gd5429_close, + NULL, gd5428_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, gd5429_config }; device_t gd5428_device = { - "Cirrus Logic GD5428", - 0, + "Cirrus Logic GD5428", NULL, + 0, 0, gd5428_init, gd5429_close, + NULL, gd5428_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, gd5429_config }; device_t gd5428_swapped_device = { - "Cirrus Logic GD5428", - 0, + "Cirrus Logic GD5428", NULL, + 0, 0, gd5428_swapped_init, gd5429_close, + NULL, gd5428_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, gd5429_config }; device_t ibm_gd5428_device = { - "IBM 1MB SVGA Adapter/A (Cirrus Logic GD5428)", - DEVICE_MCA, + "IBM 1MB SVGA Adapter/A (Cirrus Logic GD5428)", NULL, + DEVICE_MCA, 0, ibm_gd5428_init, gd5429_close, + NULL, ibm_gd5428_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, NULL }; device_t gd5429_device = { - "Cirrus Logic GD5429", - 0, + "Cirrus Logic GD5429", NULL, + 0, 0, gd5429_init, gd5429_close, + NULL, gd5429_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, gd5429_config }; device_t gd5430_device = { - "Cirrus Logic GD5430", - 0, + "Cirrus Logic GD5430", NULL, + 0, 0, gd5430_init, gd5429_close, + NULL, gd5430_available, gd5429_speed_changed, - gd5429_force_redraw, - gd5429_add_status_info, - gd5429_config + gd5429_force_redraw }; device_t gd5430_pb570_device = { - "Cirrus Logic GD5430 (PB570)", - 0, + "Cirrus Logic GD5430 (PB570)", NULL, + 0, 0, gd5430_pb570_init, gd5429_close, + NULL, gd5430_available, gd5429_speed_changed, - gd5429_force_redraw, - gd5429_add_status_info, - gd5429_config + gd5429_force_redraw }; device_t gd5434_device = { - "Cirrus Logic GD5434", - 0, + "Cirrus Logic GD5434", NULL, + 0, 0, gd5434_init, gd5429_close, + NULL, gd5434_available, gd5429_speed_changed, - gd5429_force_redraw, - gd5429_add_status_info, - gd5434_config + gd5429_force_redraw }; device_t gd5434_vlb_device = { - "Cirrus Logic GD5434", - 0, + "Cirrus Logic GD5434", NULL, + 0, 0, gd5434_vlb_init, gd5429_close, + NULL, gd5434_available, gd5429_speed_changed, - gd5429_force_redraw, - gd5429_add_status_info, - gd5434_config + gd5429_force_redraw }; device_t gd5434_vlb_swapped_device = { - "Cirrus Logic GD5434", - 0, + "Cirrus Logic GD5434", NULL, + 0, 0, gd5434_vlb_swapped_init, gd5429_close, + NULL, gd5434_available, gd5429_speed_changed, - gd5429_force_redraw, - gd5429_add_status_info, - gd5434_config + gd5429_force_redraw }; device_t gd5434_pb520r_device = { - "Cirrus Logic GD5434 (PB520r)", - 0, + "Cirrus Logic GD5434 (PB520r)", NULL, + 0, 0, gd5434_pb520r_init, gd5429_close, + NULL, gd5434_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info, - gd5434_config }; device_t gd5446_device = { - "Cirrus Logic GD5446", - 0, + "Cirrus Logic GD5446", NULL, + 0, 0, gd5446_init, gd5429_close, + NULL, gd5434_available, gd5429_speed_changed, - gd5429_force_redraw, - gd5429_add_status_info, - gd5434_config + gd5429_force_redraw }; diff --git a/pcem/vid_et4000.cpp b/pcem/vid_et4000.cpp index 10f1b9f4..e0c1de70 100644 --- a/pcem/vid_et4000.cpp +++ b/pcem/vid_et4000.cpp @@ -657,7 +657,7 @@ get_et4000_addr(uint32_t addr, void *priv) static void et4000_recalctimings(svga_t *svga) { - const et4000_t *dev = (et4000_t *) svga->p; + const et4000_t *dev = (et4000_t *) svga->priv; svga->ma_latch |= (svga->crtc[0x33] & 3) << 16; @@ -820,7 +820,7 @@ et4000_init(const device_t *info) case ET4000_TYPE_ISA: /* ISA ET4000AX */ dev->vram_size = device_get_config_int("memory") << 20; //video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_et4000_isa); - svga_init(&dev->svga, dev, dev->vram_size, + svga_init(info, &dev->svga, dev, dev->vram_size, et4000_recalctimings, et4000_in, et4000_out, NULL, NULL); io_sethandlerx(0x03c0, 32, @@ -1180,7 +1180,7 @@ const device_t et4000_kasan_isa_device = { }; #endif -void *et4000_domino_init() +void *et4000_domino_init(const device_t *info) { void *p = et4000_init(NULL); et4000_t *et4000 = (et4000_t *)p; @@ -1191,7 +1191,7 @@ void *et4000_domino_init() return p; } -void *et4000_omnibus_init() +void *et4000_omnibus_init(const device_t *info) { void *p = et4000_init(NULL); et4000_t *et4000 = (et4000_t *)p; @@ -1203,26 +1203,26 @@ void *et4000_omnibus_init() } device_t et4000_domino_device = { - "Domino", - 0, + "Domino", NULL, + 0, 0, et4000_domino_init, et4000_close, NULL, + NULL, et4000_speed_changed, et4000_force_redraw, - NULL, NULL }; device_t et4000_omnibus_device = { - "oMniBus", - 0, + "oMniBus", NULL, + 0, 0, et4000_omnibus_init, et4000_close, NULL, + NULL, et4000_speed_changed, et4000_force_redraw, - NULL, NULL }; diff --git a/pcem/vid_et4000w32.cpp b/pcem/vid_et4000w32.cpp index d2ecc1ab..e0775a32 100644 --- a/pcem/vid_et4000w32.cpp +++ b/pcem/vid_et4000w32.cpp @@ -162,14 +162,14 @@ static int et4000_vga_vsync_enabled(et4000w32p_t *et4000) static void et4000_update_irqs(et4000w32p_t *et4000) { if (et4000->vblank_irq > 0 && et4000_vga_vsync_enabled(et4000)) - pci_set_irq(NULL, PCI_INTA); + pci_set_irq(NULL, PCI_INTA, NULL); else - pci_clear_irq(NULL, PCI_INTA); + pci_clear_irq(NULL, PCI_INTA, NULL); } static void et4000_vblank_start(svga_t *svga) { - et4000w32p_t *et4000 = (et4000w32p_t*)svga->p; + et4000w32p_t *et4000 = (et4000w32p_t*)svga->priv; if (et4000->vblank_irq >= 0) { et4000->vblank_irq = 1; et4000_update_irqs(et4000); @@ -325,15 +325,15 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv) svga->hwcursor.ena = !!(et4000->regs[0xF7] & 0x80); svga->hwcursor.xoff = et4000->regs[0xE2]; svga->hwcursor.yoff = et4000->regs[0xE6]; - svga->hwcursor.xsize = svga->hwcursor.ysize = ((et4000->regs[0xEF] & 4) || ((et4000->type == ET4000W32) && (et4000->regs[0xe2] >= 0x1f) && (et4000->regs[0xe6] >= 0x1f))) ? 128 : 64; + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = ((et4000->regs[0xEF] & 4) || ((et4000->type == ET4000W32) && (et4000->regs[0xe2] >= 0x1f) && (et4000->regs[0xe6] >= 0x1f))) ? 128 : 64; if (et4000->type == ET4000W32) { if ((svga->bpp == 15) || (svga->bpp == 16)) { - svga->hwcursor.xsize = svga->hwcursor.ysize = 128; + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = 128; } } - if ((et4000->type == ET4000W32) && (svga->hwcursor.xsize == 128)) { + if ((et4000->type == ET4000W32) && (svga->hwcursor.cur_xsize == 128)) { switch (svga->bpp) { case 8: svga->hwcursor.xoff += 32; @@ -344,7 +344,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv) } } - if (svga->hwcursor.xsize == 128) { + if (svga->hwcursor.cur_xsize == 128) { svga->hwcursor.xoff &= 0x7f; svga->hwcursor.yoff &= 0x7f; if (et4000->type > ET4000W32P_REVC) { @@ -363,7 +363,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv) } svga->hwcursor.addr = (et4000->regs[0xe8] | (et4000->regs[0xe9] << 8) | ((et4000->regs[0xea] & 7) << 16)) << 2; - add2addr = svga->hwcursor.yoff * ((svga->hwcursor.xsize == 128) ? 32 : 16); + add2addr = svga->hwcursor.yoff * ((svga->hwcursor.cur_xsize == 128) ? 32 : 16); svga->hwcursor.addr += add2addr; return; @@ -488,7 +488,7 @@ et4000w32p_in(uint16_t addr, void *priv) void et4000w32p_recalctimings(svga_t *svga) { - et4000w32p_t *et4000 = (et4000w32p_t *) svga->p; + et4000w32p_t *et4000 = (et4000w32p_t *) svga->priv; svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; @@ -2809,13 +2809,13 @@ et4000w32p_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32 void et4000w32p_hwcursor_draw(svga_t *svga, int displine) { - const et4000w32p_t *et4000 = (et4000w32p_t *) svga->p; + const et4000w32p_t *et4000 = (et4000w32p_t *) svga->priv; int offset; int xx; int xx2; int shift = (et4000->adjust_cursor + 1); - int width = (svga->hwcursor_latch.xsize - svga->hwcursor_latch.xoff); - int pitch = (svga->hwcursor_latch.xsize == 128) ? 32 : 16; + int width = (svga->hwcursor_latch.cur_xsize - svga->hwcursor_latch.xoff); + int pitch = (svga->hwcursor_latch.cur_xsize == 128) ? 32 : 16; int x_acc = 4; int minus_width = 0; uint8_t dat; @@ -3103,7 +3103,7 @@ et4000w32p_init(const device_t *info) et4000->type = ET4000W32I; - svga_init(&et4000->svga, et4000, vram_size << 20, + svga_init(info, &et4000->svga, et4000, vram_size << 20, et4000w32p_recalctimings, et4000w32p_in, et4000w32p_out, et4000w32p_hwcursor_draw, @@ -3572,7 +3572,7 @@ const device_t et4000w32p_pci_device = { }; #endif -void *et4000w32_merlin_z3_init() +void *et4000w32_merlin_z3_init(const device_t *info) { void *p = et4000w32p_init(NULL); et4000w32p_t *et4000w32p = (et4000w32p_t *)p; @@ -3584,7 +3584,7 @@ void *et4000w32_merlin_z3_init() return p; } -void *et4000w32_merlin_z2_init() +void *et4000w32_merlin_z2_init(const device_t *info) { void *p = et4000w32p_init(NULL); et4000w32p_t *et4000w32p = (et4000w32p_t *)p; @@ -3596,7 +3596,7 @@ void *et4000w32_merlin_z2_init() return p; } -void *et4000w32_omnibus_z2_init() +void *et4000w32_omnibus_z2_init(const device_t *info) { void *p = et4000w32p_init(NULL); et4000w32p_t *et4000w32p = (et4000w32p_t *)p; @@ -3609,40 +3609,40 @@ void *et4000w32_omnibus_z2_init() device_t et4000w32_omnibus_device = { - "oMniBus", - 0, + "oMniBus", NULL, + 0, 0, et4000w32_omnibus_z2_init, et4000w32p_close_sc, NULL, + NULL, et4000w32p_speed_changed, et4000w32p_force_redraw, - NULL, NULL }; device_t et4000w32_merlin_z2_device = { - "Merlin Z2", - 0, + "Merlin Z2", NULL, + 0, 0, et4000w32_merlin_z2_init, et4000w32p_close_bt, NULL, + NULL, et4000w32p_speed_changed, et4000w32p_force_redraw, - NULL, NULL }; device_t et4000w32_merlin_z3_device = { - "Merlin Z3", - 0, + "Merlin Z3", NULL, + 0, 0, et4000w32_merlin_z3_init, et4000w32p_close_bt, NULL, + NULL, et4000w32p_speed_changed, et4000w32p_force_redraw, - NULL, NULL }; diff --git a/pcem/vid_inmos.cpp b/pcem/vid_inmos.cpp index 6ece0147..b2d405df 100644 --- a/pcem/vid_inmos.cpp +++ b/pcem/vid_inmos.cpp @@ -62,14 +62,14 @@ static void inmos_update_irqs(inmos_t *inmos) { if (inmos->vblank_irq) { inmos->vblank_irq = 0; - pci_set_irq(NULL, PCI_INTA); - pci_clear_irq(NULL, PCI_INTA); + pci_set_irq(NULL, PCI_INTA, NULL); + pci_clear_irq(NULL, PCI_INTA, NULL); } } static void inmos_vblank_start(svga_t *svga) { - inmos_t *inmos = (inmos_t*)svga->p; + inmos_t *inmos = (inmos_t*)svga->priv; uint32_t control = inmos->regs[0x160]; if (control & 1) { inmos->vblank_irq = 1; @@ -79,7 +79,7 @@ static void inmos_vblank_start(svga_t *svga) void inmos_hwcursor_draw(svga_t *svga, int displine) { - inmos_t *inmos = (inmos_t*)svga->p; + inmos_t *inmos = (inmos_t*)svga->priv; int addr = svga->hwcursor_latch.addr; int offset = svga->hwcursor_latch.x; int line_offset = 0; @@ -110,7 +110,7 @@ void inmos_hwcursor_draw(svga_t *svga, int displine) void inmos_recalctimings(svga_t *svga) { - inmos_t *inmos = (inmos_t*)svga->p; + inmos_t *inmos = (inmos_t*)svga->priv; if (inmos->chip == INMOS_TYPE_G300) { @@ -377,7 +377,7 @@ static uint32_t inmos_mmio_readl(uint32_t addr, void *p) static uint8_t inmos_read_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t*)p; - inmos_t *inmos = (inmos_t*)svga->p; + inmos_t *inmos = (inmos_t*)svga->priv; uint8_t *fbp = (uint8_t*)(&svga->vram[addr & svga->vram_mask]); uint8_t v = *fbp; return v; @@ -385,7 +385,7 @@ static uint8_t inmos_read_linear(uint32_t addr, void *p) static uint16_t inmos_readw_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t*)p; - inmos_t *inmos = (inmos_t*)svga->p; + inmos_t *inmos = (inmos_t*)svga->priv; uint16_t *fbp = (uint16_t*)(&svga->vram[addr & svga->vram_mask]); uint16_t v = *fbp; return v; @@ -393,7 +393,7 @@ static uint16_t inmos_readw_linear(uint32_t addr, void *p) static uint32_t inmos_readl_linear(uint32_t addr, void *p) { svga_t *svga = (svga_t*)p; - inmos_t *inmos = (inmos_t*)svga->p; + inmos_t *inmos = (inmos_t*)svga->priv; uint32_t *fbp = (uint32_t*)(&svga->vram[addr & svga->vram_mask]); uint32_t v = *fbp; return v; @@ -402,7 +402,7 @@ static uint32_t inmos_readl_linear(uint32_t addr, void *p) static void inmos_write_linear(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t*)p; - inmos_t *inmos = (inmos_t*)svga->p; + inmos_t *inmos = (inmos_t*)svga->priv; addr &= svga->vram_mask; uint8_t *fbp = (uint8_t*)(&svga->vram[addr]); *fbp = val; @@ -411,7 +411,7 @@ static void inmos_write_linear(uint32_t addr, uint8_t val, void *p) static void inmos_writew_linear(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t*)p; - inmos_t *inmos = (inmos_t*)svga->p; + inmos_t *inmos = (inmos_t*)svga->priv; addr &= svga->vram_mask; uint16_t *fbp = (uint16_t*)(&svga->vram[addr]); *fbp = val; @@ -420,7 +420,7 @@ static void inmos_writew_linear(uint32_t addr, uint16_t val, void *p) static void inmos_writel_linear(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t*)p; - inmos_t *inmos = (inmos_t*)svga->p; + inmos_t *inmos = (inmos_t*)svga->priv; addr &= svga->vram_mask; uint32_t *fbp = (uint32_t*)(&svga->vram[addr]); *fbp = val; @@ -463,7 +463,7 @@ void inmos_updatemapping(inmos_t *inmos) static void inmos_adjust_panning(svga_t *svga) { - inmos_t *inmos = (inmos_t *)svga->p; + inmos_t *inmos = (inmos_t *)svga->priv; int src = 0, dst = 8; dst += 24; @@ -492,7 +492,7 @@ static void *inmos_init(int chip) vram_size = 512 << 10; inmos->vram_mask = vram_size - 1; - svga_init(&inmos->svga, inmos, vram_size, + svga_init(NULL, &inmos->svga, inmos, vram_size, inmos_recalctimings, NULL, NULL, inmos_hwcursor_draw, @@ -528,15 +528,15 @@ static void *inmos_init(int chip) inmos->chip = chip; inmos->addressalign = 2; - inmos->svga.hwcursor.xsize = 64; - inmos->svga.hwcursor.ysize = 64; + inmos->svga.hwcursor.cur_xsize = 64; + inmos->svga.hwcursor.cur_ysize = 64; inmos_updatemapping(inmos); return inmos; } -void *inmos_rainbow3_z3_init() +void *inmos_rainbow3_z3_init(const device_t *info) { inmos_t *inmos = (inmos_t*)inmos_init(INMOS_TYPE_G360); @@ -550,7 +550,7 @@ void *inmos_rainbow3_z3_init() return inmos; } -void *inmos_visiona_z2_init() +void *inmos_visiona_z2_init(const device_t *info) { inmos_t *inmos = (inmos_t*)inmos_init(INMOS_TYPE_G300); @@ -564,7 +564,7 @@ void *inmos_visiona_z2_init() return inmos; } -void *inmos_egs_110_24_init() +void *inmos_egs_110_24_init(const device_t *info) { inmos_t *inmos = (inmos_t *)inmos_init(INMOS_TYPE_G364); @@ -616,39 +616,36 @@ void inmos_add_status_info(char *s, int max_len, void *p) device_t inmos_visiona_z2_device = { - "Visiona", - 0, + "Visiona", NULL, + 0, 0, inmos_visiona_z2_init, inmos_close, NULL, + NULL, inmos_speed_changed, - inmos_force_redraw, - inmos_add_status_info, - NULL + inmos_force_redraw }; device_t inmos_rainbow3_z3_device = { - "Rainbow III", - 0, + "Rainbow III", NULL, + 0, 0, inmos_rainbow3_z3_init, inmos_close, NULL, + NULL, inmos_speed_changed, - inmos_force_redraw, - inmos_add_status_info, - NULL + inmos_force_redraw }; device_t inmos_egs_110_24_device = { - "EGS 110/24", - 0, + "EGS 110/24", NULL, + 0, 0, inmos_egs_110_24_init, inmos_close, NULL, + NULL, inmos_speed_changed, - inmos_force_redraw, - inmos_add_status_info, - NULL + inmos_force_redraw }; diff --git a/pcem/vid_mga.cpp b/pcem/vid_mga.cpp new file mode 100644 index 00000000..7c341201 --- /dev/null +++ b/pcem/vid_mga.cpp @@ -0,0 +1,7120 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Matrox MGA graphics card emulation. + * + * + * + * Authors: Sarah Walker, + * + * Copyright 2008-2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "pci.h" +#include "mem.h" +#include "rom.h" +#include "dma.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +#if 1 + +extern void activate_debugger(void); + +#define ROM_MILLENNIUM "roms/video/matrox/matrox2064wr2.BIN" +#define ROM_MILLENNIUM_II "roms/video/matrox/matrox2164wpc.BIN" +#define ROM_MYSTIQUE "roms/video/matrox/MYSTIQUE.VBI" +#define ROM_MYSTIQUE_220 "roms/video/matrox/Myst220_66-99mhz.vbi" +#define ROM_G100 "roms/video/matrox/productiva8mbsdr.BIN" + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) +#define FIFO_THRESHOLD 0xe000 + +#define WAKE_DELAY (100 * TIMER_USEC) /* 100us */ + +#define FIFO_ENTRIES (mystique->fifo_write_idx - mystique->fifo_read_idx) +#define FIFO_FULL ((mystique->fifo_write_idx - mystique->fifo_read_idx) >= (FIFO_SIZE - 1)) +#define FIFO_EMPTY (mystique->fifo_read_idx == mystique->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +#define DMA_POLL_TIME_US 100 /*100us*/ +#define DMA_MAX_WORDS (20 * 14) /*280 quad words per 100us poll*/ + +/*These registers are also mirrored into 0x1dxx, with the mirrored versions starting + the blitter*/ +#define REG_DWGCTL 0x1c00 +#define REG_MACCESS 0x1c04 +#define REG_MCTLWTST 0x1c08 +#define REG_ZORG 0x1c0c +#define REG_PAT0 0x1c10 +#define REG_PAT1 0x1c14 +#define REG_PLNWT 0x1c1c +#define REG_BCOL 0x1c20 +#define REG_FCOL 0x1c24 +#define REG_SRC0 0x1c30 +#define REG_SRC1 0x1c34 +#define REG_SRC2 0x1c38 +#define REG_SRC3 0x1c3c +#define REG_XYSTRT 0x1c40 +#define REG_XYEND 0x1c44 +#define REG_SHIFT 0x1c50 +#define REG_DMAPAD 0x1c54 +#define REG_SGN 0x1c58 +#define REG_LEN 0x1c5c +#define REG_AR0 0x1c60 +#define REG_AR1 0x1c64 +#define REG_AR2 0x1c68 +#define REG_AR3 0x1c6c +#define REG_AR4 0x1c70 +#define REG_AR5 0x1c74 +#define REG_AR6 0x1c78 +#define REG_CXBNDRY 0x1c80 +#define REG_FXBNDRY 0x1c84 +#define REG_YDSTLEN 0x1c88 +#define REG_PITCH 0x1c8c +#define REG_YDST 0x1c90 +#define REG_YDSTORG 0x1c94 +#define REG_YTOP 0x1c98 +#define REG_YBOT 0x1c9c +#define REG_CXLEFT 0x1ca0 +#define REG_CXRIGHT 0x1ca4 +#define REG_FXLEFT 0x1ca8 +#define REG_FXRIGHT 0x1cac +#define REG_XDST 0x1cb0 +#define REG_DR0 0x1cc0 +#define REG_DR2 0x1cc8 +#define REG_DR3 0x1ccc +#define REG_DR4 0x1cd0 +#define REG_DR6 0x1cd8 +#define REG_DR7 0x1cdc +#define REG_DR8 0x1ce0 +#define REG_DR10 0x1ce8 +#define REG_DR11 0x1cec +#define REG_DR12 0x1cf0 +#define REG_DR14 0x1cf8 +#define REG_DR15 0x1cfc + +#define REG_DR0_Z32LSB 0x2c50 +#define REG_DR0_Z32MSB 0x2c54 +#define REG_DR2_Z32LSB 0x2c60 +#define REG_DR2_Z32MSB 0x2c64 +#define REG_DR3_Z32LSB 0x2c68 +#define REG_DR3_Z32MSB 0x2c6c +#define REG_TEXFILTER 0x2c58 + +#define REG_FIFOSTATUS 0x1e10 +#define REG_STATUS 0x1e14 +#define REG_ICLEAR 0x1e18 +#define REG_IEN 0x1e1c +#define REG_VCOUNT 0x1e20 +#define REG_DMAMAP 0x1e30 +#define REG_RST 0x1e40 +#define REG_OPMODE 0x1e54 +#define REG_PRIMADDRESS 0x1e58 +#define REG_PRIMEND 0x1e5c +#define REG_DWG_INDIR_WT 0x1e80 + +#define REG_ATTR_IDX 0x1fc0 +#define REG_ATTR_DATA 0x1fc1 +#define REG_INSTS0 0x1fc2 +#define REG_MISC 0x1fc2 +#define REG_SEQ_IDX 0x1fc4 +#define REG_SEQ_DATA 0x1fc5 +#define REG_MISCREAD 0x1fcc +#define REG_GCTL_IDX 0x1fce +#define REG_GCTL_DATA 0x1fcf +#define REG_CRTC_IDX 0x1fd4 +#define REG_CRTC_DATA 0x1fd5 +#define REG_INSTS1 0x1fda +#define REG_CRTCEXT_IDX 0x1fde +#define REG_CRTCEXT_DATA 0x1fdf +#define REG_CACHEFLUSH 0x1fff + +/*Mystique only*/ +#define REG_TMR0 0x2c00 +#define REG_TMR1 0x2c04 +#define REG_TMR2 0x2c08 +#define REG_TMR3 0x2c0c +#define REG_TMR4 0x2c10 +#define REG_TMR5 0x2c14 +#define REG_TMR6 0x2c18 +#define REG_TMR7 0x2c1c +#define REG_TMR8 0x2c20 +#define REG_TEXORG 0x2c24 +#define REG_TEXWIDTH 0x2c28 +#define REG_TEXHEIGHT 0x2c2c +#define REG_TEXCTL 0x2c30 +#define REG_TEXTRANS 0x2c34 +#define REG_SECADDRESS 0x2c40 +#define REG_SECEND 0x2c44 +#define REG_SOFTRAP 0x2c48 +#define REG_ALPHASTART 0x2c70 +#define REG_ALPHACTRL 0x2c7c +#define REG_ALPHAXINC 0x2c74 +#define REG_ALPHAYINC 0x2c78 +#define REG_FOGSTART 0x1cc4 +#define REG_FOGXINC 0x1cd4 +#define REG_FOGYINC 0x1ce4 +#define REG_FOGCOL 0x1cf4 + +/*Mystique only*/ +#define REG_PALWTADD 0x3c00 +#define REG_PALDATA 0x3c01 +#define REG_PIXRDMSK 0x3c02 +#define REG_PALRDADD 0x3c03 +#define REG_X_DATAREG 0x3c0a +#define REG_CURPOSX 0x3c0c +#define REG_CURPOSY 0x3c0e + +#define REG_STATUS_VSYNCSTS (1 << 3) + +#define CRTCX_R0_STARTADD_MASK (0xf << 0) +#define CRTCX_R0_OFFSET_MASK (3 << 4) + +#define CRTCX_R1_HTOTAL8 (1 << 0) +#define CRTCX_R1_HBLKSTRT8 (1 << 1) +#define CRTCX_R1_HBLKEND6 (1 << 6) + +#define CRTCX_R2_VTOTAL10 (1 << 0) +#define CRTCX_R2_VTOTAL11 (1 << 1) +#define CRTCX_R2_VDISPEND10 (1 << 2) +#define CRTCX_R2_VBLKSTR10 (1 << 3) +#define CRTCX_R2_VBLKSTR11 (1 << 4) +#define CRTCX_R2_VSYNCSTR10 (1 << 5) +#define CRTCX_R2_VSYNCSTR11 (1 << 6) +#define CRTCX_R2_LINECOMP10 (1 << 7) + +#define CRTCX_R3_MGAMODE (1 << 7) + +#define XREG_XCURADDL 0x04 +#define XREG_XCURADDH 0x05 +#define XREG_XCURCTRL 0x06 + +#define XREG_XCURCOL0R 0x08 +#define XREG_XCURCOL0G 0x09 +#define XREG_XCURCOL0B 0x0a + +#define XREG_XCURCOL1R 0x0c +#define XREG_XCURCOL1G 0x0d +#define XREG_XCURCOL1B 0x0e + +#define XREG_XCURCOL2R 0x10 +#define XREG_XCURCOL2G 0x11 +#define XREG_XCURCOL2B 0x12 + +#define XREG_XVREFCTRL 0x18 +#define XREG_XMULCTRL 0x19 +#define XREG_XPIXCLKCTRL 0x1a +#define XREG_XGENCTRL 0x1d +#define XREG_XMISCCTRL 0x1e + +#define XREG_XGENIOCTRL 0x2a +#define XREG_XGENIODATA 0x2b + +#define XREG_XSYSPLLM 0x2c +#define XREG_XSYSPLLN 0x2d +#define XREG_XSYSPLLP 0x2e +#define XREG_XSYSPLLSTAT 0x2f + +#define XREG_XZOOMCTRL 0x38 + +#define XREG_XSENSETEST 0x3a + +#define XREG_XCRCREML 0x3c +#define XREG_XCRCREMH 0x3d +#define XREG_XCRCBITSEL 0x3e + +#define XREG_XCOLKEYMSKL 0x40 +#define XREG_XCOLKEYMSKH 0x41 +#define XREG_XCOLKEYL 0x42 +#define XREG_XCOLKEYH 0x43 + +#define XREG_XPIXPLLCM 0x4c +#define XREG_XPIXPLLCN 0x4d +#define XREG_XPIXPLLCP 0x4e +#define XREG_XPIXPLLSTAT 0x4f + +#define XMISCCTRL_VGA8DAC (1 << 3) +#define XMISCCTRL_RAMCS (1 << 4) + +#define XMULCTRL_DEPTH_MASK (7 << 0) +#define XMULCTRL_DEPTH_8 (0 << 0) +#define XMULCTRL_DEPTH_15 (1 << 0) +#define XMULCTRL_DEPTH_16 (2 << 0) +#define XMULCTRL_DEPTH_24 (3 << 0) +#define XMULCTRL_DEPTH_32_OVERLAYED (4 << 0) +#define XMULCTRL_DEPTH_2G8V16 (5 << 0) +#define XMULCTRL_DEPTH_G16V16 (6 << 0) +#define XMULCTRL_DEPTH_32 (7 << 0) + +#define XSYSPLLSTAT_SYSLOCK (1 << 6) + +#define XPIXPLLSTAT_SYSLOCK (1 << 6) + +#define XCURCTRL_CURMODE_MASK (3 << 0) +#define XCURCTRL_CURMODE_3COL (1 << 0) +#define XCURCTRL_CURMODE_XGA (2 << 0) +#define XCURCTRL_CURMODE_XWIN (3 << 0) + +#define DWGCTRL_OPCODE_MASK (0xf << 0) +#define DWGCTRL_OPCODE_LINE_OPEN (0x0 << 0) +#define DWGCTRL_OPCODE_AUTOLINE_OPEN (0x1 << 0) +#define DWGCTRL_OPCODE_LINE_CLOSE (0x2 << 0) +#define DWGCTRL_OPCODE_AUTOLINE_CLOSE (0x3 << 0) +#define DWGCTRL_OPCODE_TRAP (0x4 << 0) +#define DWGCTRL_OPCODE_TEXTURE_TRAP (0x6 << 0) +#define DWGCTRL_OPCODE_ILOAD_HIGH (0x7 << 0) +#define DWGCTRL_OPCODE_BITBLT (0x8 << 0) +#define DWGCTRL_OPCODE_ILOAD (0x9 << 0) +#define DWGCTRL_OPCODE_IDUMP (0xa << 0) +#define DWGCTRL_OPCODE_FBITBLT (0xc << 0) +#define DWGCTRL_OPCODE_ILOAD_SCALE (0xd << 0) +#define DWGCTRL_OPCODE_ILOAD_HIGHV (0xe << 0) +#define DWGCTRL_OPCODE_ILOAD_FILTER (0xf << 0) /* Not implemented. */ +#define DWGCTRL_ATYPE_MASK (7 << 4) +#define DWGCTRL_ATYPE_RPL (0 << 4) +#define DWGCTRL_ATYPE_RSTR (1 << 4) +#define DWGCTRL_ATYPE_ZI (3 << 4) +#define DWGCTRL_ATYPE_BLK (4 << 4) +#define DWGCTRL_ATYPE_I (7 << 4) +#define DWGCTRL_LINEAR (1 << 7) +#define DWGCTRL_ZMODE_MASK (7 << 8) +#define DWGCTRL_ZMODE_NOZCMP (0 << 8) +#define DWGCTRL_ZMODE_ZE (2 << 8) +#define DWGCTRL_ZMODE_ZNE (3 << 8) +#define DWGCTRL_ZMODE_ZLT (4 << 8) +#define DWGCTRL_ZMODE_ZLTE (5 << 8) +#define DWGCTRL_ZMODE_ZGT (6 << 8) +#define DWGCTRL_ZMODE_ZGTE (7 << 8) +#define DWGCTRL_SOLID (1 << 11) +#define DWGCTRL_ARZERO (1 << 12) +#define DWGCTRL_SGNZERO (1 << 13) +#define DWGCTRL_SHTZERO (1 << 14) +#define DWGCTRL_BOP_MASK (0xf << 16) +#define DWGCTRL_TRANS_SHIFT (20) +#define DWGCTRL_TRANS_MASK (0xf << DWGCTRL_TRANS_SHIFT) +#define DWGCTRL_BLTMOD_MASK (0xf << 25) +#define DWGCTRL_BLTMOD_BMONOLEF (0x0 << 25) +#define DWGCTRL_BLTMOD_BPLAN (0x1 << 25) +#define DWGCTRL_BLTMOD_BFCOL (0x2 << 25) +#define DWGCTRL_BLTMOD_BU32BGR (0x3 << 25) +#define DWGCTRL_BLTMOD_BMONOWF (0x4 << 25) +#define DWGCTRL_BLTMOD_BU32RGB (0x7 << 25) +#define DWGCTRL_BLTMOD_BUYUV (0xe << 25) +#define DWGCTRL_BLTMOD_BU24RGB (0xf << 25) +#define DWGCTRL_PATTERN (1 << 29) +#define DWGCTRL_TRANSC (1 << 30) +#define BOP(x) ((x) << 16) + +#define MACCESS_PWIDTH_MASK (3 << 0) +#define MACCESS_PWIDTH_8 (0 << 0) +#define MACCESS_PWIDTH_16 (1 << 0) +#define MACCESS_PWIDTH_32 (2 << 0) +#define MACCESS_PWIDTH_24 (3 << 0) +#define MACCESS_ZWIDTH (1 << 3) +#define MACCESS_FOGEN (1 << 26) +#define MACCESS_TLUTLOAD (1 << 29) +#define MACCESS_NODITHER (1 << 30) +#define MACCESS_DIT555 (1 << 31) + +#define PITCH_MASK 0xfe0 +#define PITCH_YLIN (1 << 15) + +#define SGN_SDYDXL (1 << 0) +#define SGN_SCANLEFT (1 << 0) +#define SGN_SDXL (1 << 1) +#define SGN_SDY (1 << 2) +#define SGN_SDXR (1 << 5) + +#define DMA_ADDR_MASK 0xfffffffc +#define DMA_MODE_MASK 3 + +#define DMA_MODE_REG 0 +#define DMA_MODE_BLIT 1 +#define DMA_MODE_VECTOR 2 + +#define STATUS_SOFTRAPEN (1 << 0) +#define STATUS_VSYNCPEN (1 << 4) +#define STATUS_VLINEPEN (1 << 5) +#define STATUS_DWGENGSTS (1 << 16) +#define STATUS_ENDPRDMASTS (1 << 17) + +#define ICLEAR_SOFTRAPICLR (1 << 0) +#define ICLEAR_VLINEICLR (1 << 5) + +#define IEN_SOFTRAPEN (1 << 0) + +#define TEXCTL_TEXFORMAT_MASK (7 << 0) +#define TEXCTL_TEXFORMAT_TW4 (0 << 0) +#define TEXCTL_TEXFORMAT_TW8 (1 << 0) +#define TEXCTL_TEXFORMAT_TW15 (2 << 0) +#define TEXCTL_TEXFORMAT_TW16 (3 << 0) +#define TEXCTL_TEXFORMAT_TW12 (4 << 0) +#define TEXCTL_PALSEL_MASK (0xf << 4) +#define TEXCTL_TPITCH_SHIFT (16) +#define TEXCTL_TPITCH_MASK (7 << TEXCTL_TPITCH_SHIFT) +#define TEXCTL_TPITCHLIN (1 << 8) +#define TEXCTL_TPITCHEXT_MASK (0x7ff << 9) +#define TEXCTL_NPCEN (1 << 21) +#define TEXCTL_AZEROEXTEND (1 << 23) +#define TEXCTL_DECALCKEY (1 << 24) +#define TEXCTL_TAKEY (1 << 25) +#define TEXCTL_TAMASK (1 << 26) +#define TEXCTL_CLAMPV (1 << 27) +#define TEXCTL_CLAMPU (1 << 28) +#define TEXCTL_TMODULATE (1 << 29) +#define TEXCTL_STRANS (1 << 30) +#define TEXCTL_ITRANS (1 << 31) + +#define TEXHEIGHT_TH_MASK (0x3f << 0) +#define TEXHEIGHT_THMASK_SHIFT (18) +#define TEXHEIGHT_THMASK_MASK (0x7ff << TEXHEIGHT_THMASK_SHIFT) + +#define TEXWIDTH_TW_MASK (0x3f << 0) +#define TEXWIDTH_TWMASK_SHIFT (18) +#define TEXWIDTH_TWMASK_MASK (0x7ff << TEXWIDTH_TWMASK_SHIFT) + +#define TEXTRANS_TCKEY_MASK (0xffff) +#define TEXTRANS_TKMASK_SHIFT (16) +#define TEXTRANS_TKMASK_MASK (0xffff << TEXTRANS_TKMASK_SHIFT) + +#define DITHER_565 0 +#define DITHER_NONE_565 1 +#define DITHER_555 2 +#define DITHER_NONE_555 3 + +/*PCI configuration registers*/ +#define OPTION_INTERLEAVE (1 << 12) +#define OPTION_POWERPC (1 << 31) + +enum { + MGA_2064W, /*Millennium*/ + MGA_1064SG, /*Mystique*/ + MGA_1164SG, /*Mystique 220*/ + MGA_2164W, /*Millennium II*/ + MGA_G100, /*Productiva G100*/ +}; + +enum { + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_CTRL_BYTE = (0x01 << 24), + FIFO_WRITE_CTRL_LONG = (0x02 << 24), + FIFO_WRITE_ILOAD_LONG = (0x03 << 24) +}; + +enum { + DMA_STATE_IDLE = 0, + DMA_STATE_PRI, + DMA_STATE_SEC +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct mystique_t { + svga_t svga; + + rom_t bios_rom; + + int type; + + mem_mapping_t lfb_mapping, ctrl_mapping, + iload_mapping; + + uint8_t int_line, xcurctrl, + xsyspllm, xsysplln, xsyspllp, + xgenioctrl, xgeniodata, + xmulctrl, xgenctrl, + xmiscctrl, xpixclkctrl, + xvrefctrl, ien, dmamod, + dmadatasiz, dirdatasiz, + xcolkeymskl, xcolkeymskh, + xcolkeyl, xcolkeyh, + xcrcbitsel; + + uint8_t pci_slot, irq_state, pad, pad0; + + uint8_t pci_regs[256], crtcext_regs[6], + xreg_regs[256], dmamap[16]; + + int vram_size, crtcext_idx, xreg_idx, xzoomctrl; + + atomic_int busy, blitter_submit_refcount, + blitter_submit_dma_refcount, blitter_complete_refcount, + endprdmasts_pending, softrap_pending, + fifo_read_idx, fifo_write_idx; + + uint32_t vram_mask, vram_mask_w, vram_mask_l, + lfb_base, ctrl_base, iload_base, + ma_latch_old, maccess, mctlwtst, maccess_running, + softrap_pending_val; + + atomic_uint status; + atomic_bool softrap_status_read; + + uint64_t blitter_time, status_time; + + pc_timer_t softrap_pending_timer, wake_timer; + + fifo_entry_t fifo[FIFO_SIZE]; + + thread_t *fifo_thread; + + event_t *wake_fifo_thread, *fifo_not_full_event; + + struct + { + int m, n, p, s; + } xpixpll[3]; + + struct + { + uint8_t funcnt : 7, stylelen, + dmamod; + + int16_t fxleft, fxright, + xdst; + + uint16_t cxleft, cxright, + length; + + int xoff, yoff, selline, ydst, + length_cur, iload_rem_count, idump_end_of_line, words, + ta_key, ta_mask, lastpix_r, lastpix_g, + lastpix_b, highv_line, beta, dither, err, k1, k2; + + bool pattern[8][16]; + + uint32_t dwgctrl, dwgctrl_running, bcol, fcol, + pitch, plnwt, ybot, ydstorg, + ytop, texorg, texwidth, texheight, + texctl, textrans, zorg, ydst_lin, + src_addr, z_base, iload_rem_data, highv_data, + fogcol, fogxinc : 24, fogyinc : 24, fogstart : 24, + alphactrl, alphaxinc : 24, alphayinc : 24, alphastart : 24, + texfilter; + + uint32_t src[4], ar[7], + dr[16], tmr[9]; + + uint64_t extended_dr[4]; + + struct + { + int sdydxl, scanleft, sdxl, sdy, + sdxr; + } sgn; + } dwgreg; + + struct + { + uint8_t r, g, b; + } lut[256]; + + struct + { + uint16_t pos_x, pos_y, + addr; + uint32_t col[3]; + } cursor; + + struct + { + int32_t pri_state, sec_state, iload_state, state; + + uint32_t primaddress, primend, secaddress, secend, + pri_header, sec_header, + iload_header; + + uint32_t words_expected; + + mutex_t *lock; + } dma; + + uint8_t thread_run; + + void *i2c, *i2c_ddc, *ddc; +} mystique_t; + +static const uint8_t trans_masks[16][16] = { + // clang-format off + { + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1 + }, + { + 1, 0, 1, 0, + 0, 1, 0, 1, + 1, 0, 1, 0, + 0, 1, 0, 1 + }, + { + 0, 1, 0, 1, + 1, 0, 1, 0, + 0, 1, 0, 1, + 1, 0, 1, 0 + }, + { + 1, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 1, 0, + 0, 0, 0, 0 + }, + { + 0, 1, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 1, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 1, 0 + }, + { + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 1 + }, + { + 1, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 0 + }, + { + 0, 1, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 0 + }, + { + 0, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + } + // clang-format on +}; + +static int8_t dither5[256][2][2]; +static int8_t dither6[256][2][2]; +static double bayer_mat[4][4] = +{ + { 0.0, 8. / 16., 2. / 16., 10. / 16.}, + { 12. / 16., 4. / 16., 14. / 16., 6. / 16.}, + { 3. / 16., 11. / 16., 1. / 16., 9. / 16.}, + { 15. / 16., 7. / 16., 13. / 16., 5. / 16.}, +}; + +static video_timings_t timing_matrox_millennium = { .type = VIDEO_PCI, .write_b = 2, .write_w = 2, .write_l = 1, .read_b = 10, .read_w = 10, .read_l = 10 }; +static video_timings_t timing_matrox_mystique = { .type = VIDEO_PCI, .write_b = 4, .write_w = 4, .write_l = 4, .read_b = 10, .read_w = 10, .read_l = 10 }; + +static void mystique_start_blit(mystique_t *mystique); +static void mystique_update_irqs(mystique_t *mystique); + +static void wake_fifo_thread(mystique_t *mystique); +static void wait_fifo_idle(mystique_t *mystique); +static void mystique_queue(mystique_t *mystique, uint32_t addr, uint32_t val, uint32_t type); + +static uint8_t mystique_readb_linear(uint32_t addr, void *priv); +static uint16_t mystique_readw_linear(uint32_t addr, void *priv); +static uint32_t mystique_readl_linear(uint32_t addr, void *priv); +static void mystique_writeb_linear(uint32_t addr, uint8_t val, void *priv); +static void mystique_writew_linear(uint32_t addr, uint16_t val, void *priv); +static void mystique_writel_linear(uint32_t addr, uint32_t val, void *priv); + +static void mystique_recalc_mapping(mystique_t *mystique); +static int mystique_line_compare(svga_t *svga); + +static uint8_t mystique_iload_read_b(uint32_t addr, void *priv); +static uint32_t mystique_iload_read_l(uint32_t addr, void *priv); +static void mystique_iload_write_b(uint32_t addr, uint8_t val, void *priv); +static void mystique_iload_write_l(uint32_t addr, uint32_t val, void *priv); + +static uint32_t blit_idump_read(mystique_t *mystique); +static void blit_iload_write(mystique_t *mystique, uint32_t data, int size); + +static bool powerpc(mystique_t *mystique, uint32_t addr) +{ + if (mystique->pci_regs[0x43] & (OPTION_POWERPC >> 24)) { + if ((addr & 0x3ffc) >= 0x1c00 && (addr & 0x3ffc) < 0x1f00) + return true; + if (mystique->type == MGA_1064SG || mystique->type == MGA_1164SG) { + if ((addr & 0x3ffc) >= 0x2c00 && (addr & 0x3ffc) < 0x2e00) + return true; + } + } + return false; +} + +void +mystique_out(uint16_t addr, uint8_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + svga_t *svga = &mystique->svga; + uint8_t old; + + if ((((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c8: + mystique->xreg_idx = val; + //fallthrough; + case 0x3c6: + case 0x3c7: + case 0x3c9: + if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) { + tvp3026_ramdac_out(addr, 0, 0, val, svga->ramdac, svga); + return; + } + break; + + case 0x3cf: + if ((svga->gdcaddr & 15) == 6 && svga->gdcreg[6] != val) { + svga->gdcreg[svga->gdcaddr & 15] = val; + mystique_recalc_mapping(mystique); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (((svga->crtcreg & 0x3f) < 7) && (svga->crtc[0x11] & 0x80)) + return; + if (((svga->crtcreg & 0x3f) == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg & 0x3f]; + svga->crtc[svga->crtcreg & 0x3f] = val; + if (old != val) { + if ((svga->crtcreg & 0x3f) < 0xE || (svga->crtcreg & 0x3f) > 0x10) { + if (((svga->crtcreg & 0x3f) == 0xc) || ((svga->crtcreg & 0x3f) == 0xd)) { + svga->fullchange = 3; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + } else { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + if (svga->crtcreg == 0x11) { + if (!(val & 0x10)) + mystique->status &= ~STATUS_VSYNCPEN; + mystique_update_irqs(mystique); + } + } + break; + + case 0x3de: + mystique->crtcext_idx = val; + break; + case 0x3df: + if (mystique->crtcext_idx == 1) + svga->dpms = !!(val & 0x30); + old = mystique->crtcext_regs[mystique->crtcext_idx]; + if (mystique->crtcext_idx < 6) + mystique->crtcext_regs[mystique->crtcext_idx] = val; + + if ((mystique->type >= MGA_1064SG) && (mystique->crtcext_idx == 0) && + (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE)) { + svga->rowoffset = svga->crtc[0x13] | + ((mystique->crtcext_regs[0] & CRTCX_R0_OFFSET_MASK) << 4); + + if (!(mystique->type >= MGA_2164W)) + svga->rowoffset <<= 1; + + svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | + (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + if ((mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8))) { + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; + } + + if (!(mystique->type >= MGA_2164W)) + svga->ma_latch <<= 1; + + if (svga->ma_latch != mystique->ma_latch_old) { + if (svga->interlace && svga->oddeven) + svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + + (svga->ma_latch << 2) + (svga->rowoffset << 1); + else + svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + + (svga->ma_latch << 2); + mystique->ma_latch_old = svga->ma_latch; + } + } + + if (mystique->crtcext_idx == 4) { + if (svga->gdcreg[6] & 0xc) { + /*64k banks*/ + if (mystique->type >= MGA_2164W) { + svga->read_bank = val << 16; + svga->write_bank = val << 16; + } else { + svga->read_bank = (val & 0x7f) << 16; + svga->write_bank = (val & 0x7f) << 16; + } + } else { + /*128k banks*/ + if (mystique->type >= MGA_2164W) { + svga->read_bank = (val & 0xfe) << 16; + svga->write_bank = (val & 0xfe) << 16; + } else { + svga->read_bank = (val & 0x7e) << 16; + svga->write_bank = (val & 0x7e) << 16; + } + } + } + if (!((mystique->type >= MGA_1064SG) && (mystique->crtcext_idx == 0) && + (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE))) + svga_recalctimings(svga); + + break; + + default: + break; + } + + svga_out(addr, val, svga); +} + +uint8_t +mystique_in(uint16_t addr, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + svga_t *svga = &mystique->svga; + uint8_t temp = 0xff; + + if ((((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c1: + if (svga->attraddr >= 0x15) + temp = 0; + else + temp = svga->attrregs[svga->attraddr]; + break; + + case 0x3c6: + case 0x3c7: + case 0x3c8: + case 0x3c9: + if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) + temp = tvp3026_ramdac_in(addr, 0, 0, svga->ramdac, svga); + else + temp = svga_in(addr, svga); + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + if ((svga->crtcreg >= 0x19 && svga->crtcreg <= 0x21) || svga->crtcreg == 0x23 || svga->crtcreg == 0x25 || svga->crtcreg >= 0x27) + temp = 0; + else + temp = svga->crtc[svga->crtcreg & 0x3f]; + break; + + case 0x3de: + temp = mystique->crtcext_idx; + break; + + case 0x3df: + if (mystique->crtcext_idx < 6) + temp = mystique->crtcext_regs[mystique->crtcext_idx]; + break; + + default: + temp = svga_in(addr, svga); + break; + } + + return temp; +} + +static int +mystique_line_compare(svga_t *svga) +{ + mystique_t *mystique = (mystique_t *) svga->priv; + + mystique->status |= STATUS_VLINEPEN; + mystique_update_irqs(mystique); + + return 0; +} + +static void +mystique_vblank_start(svga_t *svga) +{ + mystique_t *mystique = (mystique_t *) svga->priv; + + if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) { + svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + if (mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8)) + svga->ma_latch <<= 1; + } +} + +static void +mystique_vsync_callback(svga_t *svga) +{ + mystique_t *mystique = (mystique_t *) svga->priv; + + if (svga->crtc[0x11] & 0x10) { + mystique->status |= STATUS_VSYNCPEN; + mystique_update_irqs(mystique); + } +} + +static float +mystique_getclock(int clock, void *priv) +{ + const mystique_t *mystique = (mystique_t *) priv; + + if (clock == 0) + return 25175000.0; + if (clock == 1) + return 28322000.0; + + int m = mystique->xpixpll[2].m; + int n = mystique->xpixpll[2].n; + int pl = mystique->xpixpll[2].p; + + float fvco = 14318181.0f * (n + 1) / (m + 1); + float fo = fvco / (pl + 1); + + return fo; +} + +void +mystique_recalctimings(svga_t *svga) +{ + mystique_t *mystique = (mystique_t *) svga->priv; + int clk_sel = (svga->miscout >> 2) & 3; + + //svga->clock = (cpuclock * (float) (1ULL << 32)) / svga->getclock(clk_sel & 3, svga->clock_gen); + + if (mystique->crtcext_regs[1] & CRTCX_R1_HTOTAL8) + svga->htotal |= 0x100; + + svga->hblankstart = (((mystique->crtcext_regs[1] & 0x02) >> 2) << 8) + svga->crtc[2]; + + if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL10) + svga->vtotal |= 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL11) + svga->vtotal |= 0x800; + if (mystique->crtcext_regs[2] & CRTCX_R2_VDISPEND10) + svga->dispend |= 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VBLKSTR10) + svga->vblankstart |= 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VBLKSTR11) + svga->vblankstart |= 0x800; + if (mystique->crtcext_regs[2] & CRTCX_R2_VSYNCSTR10) + svga->vsyncstart |= 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VSYNCSTR11) + svga->vsyncstart |= 0x800; + if (mystique->crtcext_regs[2] & CRTCX_R2_LINECOMP10) + svga->split |= 0x400; + + if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) { + tvp3026_recalctimings(svga->ramdac, svga); + svga->interlace |= !!(mystique->crtcext_regs[0] & 0x80); + } else + svga->interlace = !!(mystique->crtcext_regs[0] & 0x80); + + if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) { + svga->lowres = 0; + svga->char_width = 8; + svga->hdisp = (svga->crtc[1] + 1) << 3; + svga->hdisp_time = svga->hdisp; + svga->rowoffset = svga->crtc[0x13] | ((mystique->crtcext_regs[0] & CRTCX_R0_OFFSET_MASK) << 4); + + svga->dots_per_clock = 8; + svga->hblank_end_val = (svga->crtc[3] & 0x1f) | (((svga->crtc[5] & 0x80) >> 7) << 5) | + (((mystique->crtcext_regs[1] & 0x40) >> 6) << 6); + svga->hblank_end_mask = 0x0000007f; + + if (mystique->type != MGA_2164W && mystique->type != MGA_2064W) + svga->lut_map = !!(mystique->xmiscctrl & XMISCCTRL_RAMCS); + + svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + + if ((mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8))) { + svga->rowoffset <<= 1; + if (mystique->type >= MGA_1064SG) + svga->ma_latch <<= 1; + } + + if (mystique->type >= MGA_1064SG) { + /*Mystique and later, unlike most SVGA cards, allows display start to take + effect mid-screen*/ + if (!(mystique->type >= MGA_2164W)) + svga->ma_latch <<= 1; + /* Only change maback so the new display start will take effect on the next + horizontal retrace. */ + if (svga->ma_latch != mystique->ma_latch_old) { + if (svga->interlace && svga->oddeven) + svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + + (svga->ma_latch << 2) + (svga->rowoffset << 1); + else + svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + + (svga->ma_latch << 2); + mystique->ma_latch_old = svga->ma_latch; + } + + if (!(mystique->type >= MGA_2164W)) + svga->rowoffset <<= 1; + if (mystique->type != MGA_2164W) { + switch (mystique->xmulctrl & XMULCTRL_DEPTH_MASK) { + case XMULCTRL_DEPTH_8: + case XMULCTRL_DEPTH_2G8V16: + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + break; + case XMULCTRL_DEPTH_15: + case XMULCTRL_DEPTH_G16V16: + svga->render = svga_render_15bpp_highres; + svga->bpp = 15; + break; + case XMULCTRL_DEPTH_16: + svga->render = svga_render_16bpp_highres; + svga->bpp = 16; + break; + case XMULCTRL_DEPTH_24: + svga->render = svga_render_24bpp_highres; + svga->bpp = 24; + break; + case XMULCTRL_DEPTH_32: + case XMULCTRL_DEPTH_32_OVERLAYED: + svga->render = svga_render_32bpp_highres; + svga->bpp = 32; + break; + + default: + break; + } + } else { + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; + } + } + } else { + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; + } + } + svga->packed_chain4 = 1; + svga->line_compare = mystique_line_compare; + if (mystique->type < MGA_1064SG) + svga->vblank_start = mystique_vblank_start; + } else { + svga->packed_chain4 = 0; + svga->line_compare = NULL; + svga->lut_map = 0; + if (mystique->type >= MGA_1064SG) + svga->bpp = 8; + else + svga->vblank_start = NULL; + } + + svga->fb_only = svga->packed_chain4; + svga->disable_blink = (svga->bpp > 4); + video_force_resize_set_monitor(1, svga->monitor_index); +#if 0 + pclog("PackedChain4=%d, chain4=%x, fast=%x, bit6 attrreg10=%02x, bits 5-6 gdcreg5=%02x, extmode=%02x.\n", svga->packed_chain4, svga->chain4, svga->fast, svga->attrregs[0x10] & 0x40, svga->gdcreg[5] & 0x60, mystique->pci_regs[0x41] & 1, mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE); +#endif +} + +static void +mystique_recalc_mapping(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + + io_removehandlerx(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); + if ((mystique->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (mystique->pci_regs[0x41] & 1)) + io_sethandlerx(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); + + if (!(mystique->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + mem_mapping_disablex(&svga->mapping); + mem_mapping_disablex(&mystique->ctrl_mapping); + mem_mapping_disablex(&mystique->lfb_mapping); + mem_mapping_disablex(&mystique->iload_mapping); + return; + } + + if (mystique->ctrl_base) + mem_mapping_set_addrx(&mystique->ctrl_mapping, mystique->ctrl_base, 0x4000); + else + mem_mapping_disablex(&mystique->ctrl_mapping); + + if (mystique->lfb_base) + mem_mapping_set_addrx(&mystique->lfb_mapping, mystique->lfb_base, (mystique->type >= MGA_2164W) ? 0x1000000 : 0x800000); + else + mem_mapping_disablex(&mystique->lfb_mapping); + + if (mystique->iload_base) + mem_mapping_set_addrx(&mystique->iload_mapping, mystique->iload_base, 0x800000); + else + mem_mapping_disablex(&mystique->iload_mapping); + + if (mystique->pci_regs[0x41] & 1) { + switch (svga->gdcreg[6] & 0x0C) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addrx(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addrx(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + + default: + break; + } + if (svga->gdcreg[6] & 0xc) { + /*64k banks*/ + svga->read_bank = (mystique->crtcext_regs[4] & 0x7f) << 16; + svga->write_bank = (mystique->crtcext_regs[4] & 0x7f) << 16; + } else { + /*128k banks*/ + svga->read_bank = (mystique->crtcext_regs[4] & 0x7e) << 16; + svga->write_bank = (mystique->crtcext_regs[4] & 0x7e) << 16; + } + } else + mem_mapping_disablex(&svga->mapping); +} + +static void +mystique_update_irqs(mystique_t *mystique) +{ + const svga_t *svga = &mystique->svga; + int irq = 0; + + if ((mystique->status & mystique->ien) & STATUS_SOFTRAPEN) + irq = 1; + if ((mystique->status & mystique->ien) & STATUS_VLINEPEN) + irq = 1; + if ((mystique->status & STATUS_VSYNCPEN) && (svga->crtc[0x11] & 0x30) == 0x10) + irq = 1; + + if (irq) + pci_set_irq(mystique->pci_slot, PCI_INTA, &mystique->irq_state); + else + pci_clear_irq(mystique->pci_slot, PCI_INTA, &mystique->irq_state); +} + +#define READ8(addr, var) \ + switch ((addr) &3) { \ + case 0: \ + ret = (var) &0xff; \ + break; \ + case 1: \ + ret = ((var) >> 8) & 0xff; \ + break; \ + case 2: \ + ret = ((var) >> 16) & 0xff; \ + break; \ + case 3: \ + ret = ((var) >> 24) & 0xff; \ + break; \ + } + +#define WRITE8(addr, var, val) \ + switch ((addr) &3) { \ + case 0: \ + var = (var & 0xffffff00) | (val); \ + break; \ + case 1: \ + var = (var & 0xffff00ff) | ((val) << 8); \ + break; \ + case 2: \ + var = (var & 0xff00ffff) | ((val) << 16); \ + break; \ + case 3: \ + var = (var & 0x00ffffff) | ((val) << 24); \ + break; \ + } + +#define READ8R(addr, var) \ + switch ((addr) &3) { \ + case 2: \ + ret = (var) &0xff; \ + break; \ + case 1: \ + ret = ((var) >> 8) & 0xff; \ + break; \ + case 0: \ + ret = ((var) >> 16) & 0xff; \ + break; \ + } + +#define WRITE8R(addr, var, val) \ + switch ((addr) &3) { \ + case 2: \ + var = (var & 0xffffff00) | (val); \ + break; \ + case 1: \ + var = (var & 0xffff00ff) | ((val) << 8); \ + break; \ + case 0: \ + var = (var & 0xff00ffff) | ((val) << 16); \ + break; \ + } + + +static uint8_t +mystique_read_xreg(mystique_t *mystique, int reg) +{ + uint8_t ret = 0xff; + + switch (reg) { + case XREG_XCURADDL: + ret = mystique->cursor.addr & 0xff; + break; + case XREG_XCURADDH: + ret = mystique->cursor.addr >> 8; + break; + case XREG_XCURCTRL: + ret = mystique->xcurctrl; + break; + + case XREG_XCURCOL0R: + case XREG_XCURCOL0G: + case XREG_XCURCOL0B: + READ8R(reg, mystique->cursor.col[0]); + break; + case XREG_XCURCOL1R: + case XREG_XCURCOL1G: + case XREG_XCURCOL1B: + READ8R(reg, mystique->cursor.col[1]); + break; + case XREG_XCURCOL2R: + case XREG_XCURCOL2G: + case XREG_XCURCOL2B: + READ8R(reg, mystique->cursor.col[2]); + break; + + case XREG_XMULCTRL: + ret = mystique->xmulctrl; + break; + + case XREG_XMISCCTRL: + ret = mystique->xmiscctrl; + break; + + case XREG_XGENCTRL: + ret = mystique->xgenctrl; + break; + + case XREG_XVREFCTRL: + ret = mystique->xvrefctrl; + break; + + case XREG_XGENIOCTRL: + ret = mystique->xgenioctrl; + break; + case XREG_XGENIODATA: + ret = mystique->xgeniodata & 0xf0; +#if 0 + if (i2c_gpio_get_scl(mystique->i2c_ddc)) + ret |= 0x08; + if (i2c_gpio_get_scl(mystique->i2c)) + ret |= 0x04; + if (i2c_gpio_get_sda(mystique->i2c_ddc)) + ret |= 0x02; + if (i2c_gpio_get_sda(mystique->i2c)) + ret |= 0x01; +#endif + break; + + case XREG_XSYSPLLM: + ret = mystique->xsyspllm; + break; + case XREG_XSYSPLLN: + ret = mystique->xsysplln; + break; + case XREG_XSYSPLLP: + ret = mystique->xsyspllp; + break; + + case XREG_XZOOMCTRL: + ret = mystique->xzoomctrl; + break; + + case XREG_XSENSETEST: + ret = 0; + if (mystique->svga.vgapal[0].b < 0x80) + ret |= 1; + if (mystique->svga.vgapal[0].g < 0x80) + ret |= 2; + if (mystique->svga.vgapal[0].r < 0x80) + ret |= 4; + break; + + case XREG_XCRCREML: /*CRC not implemented*/ + ret = 0; + break; + case XREG_XCRCREMH: + ret = 0; + break; + case XREG_XCRCBITSEL: + ret = mystique->xcrcbitsel; + break; + + case XREG_XCOLKEYMSKL: + ret = mystique->xcolkeymskl; + break; + case XREG_XCOLKEYMSKH: + ret = mystique->xcolkeymskh; + break; + case XREG_XCOLKEYL: + ret = mystique->xcolkeyl; + break; + case XREG_XCOLKEYH: + ret = mystique->xcolkeyh; + break; + + case XREG_XPIXCLKCTRL: + ret = mystique->xpixclkctrl; + break; + + case XREG_XSYSPLLSTAT: + ret = XSYSPLLSTAT_SYSLOCK; + break; + + case XREG_XPIXPLLSTAT: + ret = XPIXPLLSTAT_SYSLOCK; + break; + + case XREG_XPIXPLLCM: + ret = mystique->xpixpll[2].m; + break; + case XREG_XPIXPLLCN: + ret = mystique->xpixpll[2].n; + break; + case XREG_XPIXPLLCP: + ret = mystique->xpixpll[2].p | (mystique->xpixpll[2].s << 3); + break; + + case 0x00: + case 0x20: + case 0x3f: + ret = 0xff; + break; + + default: + if (reg >= 0x50) + ret = 0xff; + break; + } + + return ret; +} + +static void +mystique_write_xreg(mystique_t *mystique, int reg, uint8_t val) +{ + svga_t *svga = &mystique->svga; + + switch (reg) { + case XREG_XCURADDL: + mystique->cursor.addr = (mystique->cursor.addr & 0x1f00) | val; + svga->hwcursor.addr = mystique->cursor.addr << 10; + break; + case XREG_XCURADDH: + mystique->cursor.addr = (mystique->cursor.addr & 0x00ff) | ((val & 0x1f) << 8); + svga->hwcursor.addr = mystique->cursor.addr << 10; + break; + + case XREG_XCURCTRL: + mystique->xcurctrl = val; + svga->hwcursor.ena = (val & 3) ? 1 : 0; + break; + + case XREG_XCURCOL0R: + case XREG_XCURCOL0G: + case XREG_XCURCOL0B: + WRITE8R(reg, mystique->cursor.col[0], val); + break; + case XREG_XCURCOL1R: + case XREG_XCURCOL1G: + case XREG_XCURCOL1B: + WRITE8R(reg, mystique->cursor.col[1], val); + break; + case XREG_XCURCOL2R: + case XREG_XCURCOL2G: + case XREG_XCURCOL2B: + WRITE8R(reg, mystique->cursor.col[2], val); + break; + + case XREG_XMULCTRL: + mystique->xmulctrl = val; + break; + + case XREG_XMISCCTRL: + mystique->xmiscctrl = val; + svga_set_ramdac_type(svga, (val & XMISCCTRL_VGA8DAC) ? RAMDAC_8BIT : RAMDAC_6BIT); + if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) + svga->lut_map = !!(mystique->xmiscctrl & XMISCCTRL_RAMCS); + break; + + case XREG_XGENCTRL: + mystique->xgenctrl = val; + break; + + case XREG_XVREFCTRL: + mystique->xvrefctrl = val; + break; + + case XREG_XGENIOCTRL: + mystique->xgenioctrl = val; +#if 0 + i2c_gpio_set(mystique->i2c_ddc, !(mystique->xgenioctrl & 0x08) || (mystique->xgeniodata & 0x08), !(mystique->xgenioctrl & 0x02) || (mystique->xgeniodata & 0x02)); + i2c_gpio_set(mystique->i2c, !(mystique->xgenioctrl & 0x04) || (mystique->xgeniodata & 0x04), !(mystique->xgenioctrl & 0x01) || (mystique->xgeniodata & 0x01)); +#endif + break; + case XREG_XGENIODATA: + mystique->xgeniodata = val; + break; + + case XREG_XSYSPLLM: + mystique->xsyspllm = val; + break; + case XREG_XSYSPLLN: + mystique->xsysplln = val; + break; + case XREG_XSYSPLLP: + mystique->xsyspllp = val; + break; + + case XREG_XZOOMCTRL: + mystique->xzoomctrl = val & 3; + break; + + case XREG_XSENSETEST: + break; + + case XREG_XCRCREML: /*CRC not implemented*/ + break; + case XREG_XCRCREMH: + break; + case XREG_XCRCBITSEL: + mystique->xcrcbitsel = val & 0x1f; + break; + + case XREG_XCOLKEYMSKL: + mystique->xcolkeymskl = val; + break; + case XREG_XCOLKEYMSKH: + mystique->xcolkeymskh = val; + break; + case XREG_XCOLKEYL: + mystique->xcolkeyl = val; + break; + case XREG_XCOLKEYH: + mystique->xcolkeyh = val; + break; + + case XREG_XSYSPLLSTAT: + break; + + case XREG_XPIXPLLSTAT: + break; + + case XREG_XPIXCLKCTRL: + mystique->xpixclkctrl = val; + break; + + case XREG_XPIXPLLCM: + mystique->xpixpll[2].m = val; + break; + case XREG_XPIXPLLCN: + mystique->xpixpll[2].n = val; + break; + case XREG_XPIXPLLCP: + mystique->xpixpll[2].p = val & 7; + mystique->xpixpll[2].s = (val >> 3) & 3; + break; + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x07: + case 0x0b: + case 0x0f: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x1b: + case 0x1c: + case 0x20: + case 0x39: + case 0x3b: + case 0x3f: + case 0x47: + case 0x4b: + break; + + default: + break; + } +} + +static uint8_t +mystique_ctrl_read_bx(uint32_t addr, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + svga_t *svga = &mystique->svga; + uint8_t ret = 0xff; + int fifocount; + uint8_t addr_0x0f = 0; + uint16_t addr_0x03 = 0; + int rs2 = 0; + int rs3 = 0; + + if ((mystique->type == MGA_2064W || mystique->type == MGA_2164W) && (addr & 0x3e00) == 0x3c00) { + /*RAMDAC*/ + addr_0x0f = addr & 0x0f; + + if ((addr_0x0f & 3) == 0) + addr_0x03 = 0x3c8; + else if ((addr_0x0f & 3) == 1) + addr_0x03 = 0x3c9; + else if ((addr_0x0f & 3) == 2) + addr_0x03 = 0x3c6; + else if ((addr_0x0f & 3) == 3) + addr_0x03 = 0x3c7; + + if ((addr_0x0f >= 0x04) && (addr_0x0f <= 0x07)) { + rs2 = 1; + rs3 = 0; + } else if ((addr_0x0f >= 0x08) && (addr_0x0f <= 0x0b)) { + rs2 = 0; + rs3 = 1; + } else if ((addr_0x0f >= 0x0c) && (addr_0x0f <= 0x0f)) { + rs2 = 1; + rs3 = 1; + } + + ret = tvp3026_ramdac_in(addr_0x03, rs2, rs3, svga->ramdac, svga); + } else + switch (addr & 0x3fff) { + case REG_FIFOSTATUS: + fifocount = FIFO_SIZE - FIFO_ENTRIES; + if (fifocount > (mystique->type <= MGA_1064SG ? 32 : 64)) + fifocount = (mystique->type <= MGA_1064SG ? 32 : 64); + ret = fifocount; + break; + case REG_FIFOSTATUS + 1: + if (FIFO_EMPTY) + ret |= 2; + else if (FIFO_ENTRIES >= (mystique->type <= MGA_1064SG ? 32 : 64)) + ret |= 1; + break; + case REG_FIFOSTATUS + 2: + case REG_FIFOSTATUS + 3: + ret = 0; + break; + + case REG_STATUS: + ret = mystique->status & 0xff; + if (svga->cgastat & 8) + ret |= REG_STATUS_VSYNCSTS; + if (ret & 1) + mystique->softrap_status_read = 1; + if (mystique->softrap_status_read == 0 && !(ret & 1)) { + mystique->softrap_status_read = 1; + ret |= 1; + } + break; + case REG_STATUS + 1: + ret = (mystique->status >> 8) & 0xff; + break; + case REG_STATUS + 2: + ret = (mystique->status >> 16) & 0xff; + if (mystique->busy || ((mystique->blitter_submit_refcount + mystique->blitter_submit_dma_refcount) != mystique->blitter_complete_refcount) || !FIFO_EMPTY + || mystique->dma.state != DMA_STATE_IDLE || mystique->softrap_pending || mystique->endprdmasts_pending) + ret |= (STATUS_DWGENGSTS >> 16); + break; + case REG_STATUS + 3: + ret = (mystique->status >> 24) & 0xff; + break; + + case REG_IEN: + ret = mystique->ien & 0x65; + break; + case REG_IEN + 1: + case REG_IEN + 2: + case REG_IEN + 3: + ret = 0; + break; + + case REG_OPMODE: + ret = mystique->dmamod << 2; + break; + case REG_OPMODE + 1: + ret = mystique->dmadatasiz; + break; + case REG_OPMODE + 2: + ret = mystique->dirdatasiz; + break; + case REG_OPMODE + 3: + ret = 0; + break; + + case REG_PRIMADDRESS: + case REG_PRIMADDRESS + 1: + case REG_PRIMADDRESS + 2: + case REG_PRIMADDRESS + 3: + READ8(addr, mystique->dma.primaddress); + break; + case REG_PRIMEND: + case REG_PRIMEND + 1: + case REG_PRIMEND + 2: + case REG_PRIMEND + 3: + READ8(addr, mystique->dma.primend); + break; + + case REG_SECADDRESS: + case REG_SECADDRESS + 1: + case REG_SECADDRESS + 2: + case REG_SECADDRESS + 3: + READ8(addr, mystique->dma.secaddress); + break; + + case REG_VCOUNT: + case REG_VCOUNT + 1: + case REG_VCOUNT + 2: + case REG_VCOUNT + 3: + READ8(addr, svga->vc); + break; + + case REG_ATTR_IDX: + ret = svga_in(0x3c0, svga); + break; + case REG_ATTR_DATA: + ret = svga_in(0x3c1, svga); + break; + + case REG_INSTS0: + ret = svga_in(0x3c2, svga); + break; + + case REG_SEQ_IDX: + ret = svga_in(0x3c4, svga); + break; + case REG_SEQ_DATA: + ret = svga_in(0x3c5, svga); + break; + + case REG_MISCREAD: + ret = svga_in(0x3cc, svga); + break; + + case REG_GCTL_IDX: + ret = mystique_in(0x3ce, mystique); + break; + case REG_GCTL_DATA: + ret = mystique_in(0x3cf, mystique); + break; + + case REG_CRTC_IDX: + ret = mystique_in(0x3d4, mystique); + break; + case REG_CRTC_DATA: + ret = mystique_in(0x3d5, mystique); + break; + + case REG_INSTS1: + ret = mystique_in(0x3da, mystique); + break; + + case REG_CRTCEXT_IDX: + ret = mystique_in(0x3de, mystique); + break; + case REG_CRTCEXT_DATA: + ret = mystique_in(0x3df, mystique); + break; + + case REG_PALWTADD: + ret = svga_in(0x3c8, svga); + break; + case REG_PALDATA: + ret = svga_in(0x3c9, svga); + break; + case REG_PIXRDMSK: + ret = svga_in(0x3c6, svga); + break; + case REG_PALRDADD: + ret = svga_in(0x3c7, svga); + break; + + case REG_X_DATAREG: + ret = mystique_read_xreg(mystique, mystique->xreg_idx); + break; + + case 0x1c40: + case 0x1c41: + case 0x1c42: + case 0x1c43: + case 0x1d44: + case 0x1d45: + case 0x1d46: + case 0x1d47: + case 0x1e50: + case 0x1e51: + case 0x1e52: + case 0x1e53: + case REG_ICLEAR: + case REG_ICLEAR + 1: + case REG_ICLEAR + 2: + case REG_ICLEAR + 3: + case 0x2c30: + case 0x2c31: + case 0x2c32: + case 0x2c33: + case 0x3e08: + break; + + case 0x3c08: + case 0x3c09: + case 0x3c0b: + break; + + default: + if ((addr & 0x3fff) >= 0x2c00 && (addr & 0x3fff) < 0x2c40) + break; + if ((addr & 0x3fff) >= 0x3e00) + break; + break; + } + + return ret; +} + +static uint8_t +mystique_ctrl_read_b(uint32_t addr, void *priv) +{ + mystique_t *mystique = (mystique_t *)priv; + + if (powerpc(mystique, addr)) { + addr ^= 3; + } + return mystique_ctrl_read_bx(addr, priv); +} + +static void +mystique_accel_ctrl_write_b(uint32_t addr, uint8_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + int start_blit = 0; + + //pclog("B %08x %02x\n", addr, val); + + if ((addr & 0x300) == 0x100) { + addr &= ~0x100; + start_blit = 1; + } + + switch (addr & 0x3fff) { + case REG_MACCESS: + case REG_MACCESS + 1: + case REG_MACCESS + 2: + case REG_MACCESS + 3: + WRITE8(addr, mystique->maccess, val); + mystique->dwgreg.dither = mystique->maccess >> 30; + if (mystique->type < MGA_2164W) + mystique->maccess &= ~MACCESS_ZWIDTH; + else + mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * ((mystique->maccess & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg; + break; + + case REG_MCTLWTST: + case REG_MCTLWTST + 1: + case REG_MCTLWTST + 2: + case REG_MCTLWTST + 3: + WRITE8(addr, mystique->mctlwtst, val); + break; + + case REG_PAT0: + case REG_PAT0 + 1: + case REG_PAT0 + 2: + case REG_PAT0 + 3: + case REG_PAT1: + case REG_PAT1 + 1: + case REG_PAT1 + 2: + case REG_PAT1 + 3: + for (uint8_t x = 0; x < 8; x++) + mystique->dwgreg.pattern[addr & 7][x] = mystique->dwgreg.pattern[addr & 7][x + 8] = val & (1 << (7 - x)); + break; + + case REG_XYSTRT: + case REG_XYSTRT + 1: + WRITE8(addr & 1, mystique->dwgreg.ar[5], val); + if (mystique->dwgreg.ar[5] & 0x8000) + mystique->dwgreg.ar[5] |= 0xffff8000; + else + mystique->dwgreg.ar[5] &= ~0xffff8000; + WRITE8(addr & 1, mystique->dwgreg.xdst, val); + break; + case REG_XYSTRT + 2: + case REG_XYSTRT + 3: + WRITE8(addr & 1, mystique->dwgreg.ar[6], val); + if (mystique->dwgreg.ar[6] & 0x8000) + mystique->dwgreg.ar[6] |= 0xffff8000; + else + mystique->dwgreg.ar[6] &= ~0xffff8000; + WRITE8(addr & 1, mystique->dwgreg.ydst, val); + mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + break; + + case REG_XYEND: + case REG_XYEND + 1: + WRITE8(addr & 1, mystique->dwgreg.ar[0], val); + if (mystique->dwgreg.ar[0] & 0x8000) + mystique->dwgreg.ar[0] |= 0xffff8000; + else + mystique->dwgreg.ar[0] &= ~0xffff8000; + break; + case REG_XYEND + 2: + case REG_XYEND + 3: + WRITE8(addr & 1, mystique->dwgreg.ar[2], val); + if (mystique->dwgreg.ar[2] & 0x8000) + mystique->dwgreg.ar[2] |= 0xffff8000; + else + mystique->dwgreg.ar[2] &= ~0xffff8000; + break; + + case REG_SGN: + mystique->dwgreg.sgn.sdydxl = val & SGN_SDYDXL; + mystique->dwgreg.sgn.scanleft = val & SGN_SCANLEFT; + mystique->dwgreg.sgn.sdxl = val & SGN_SDXL; + mystique->dwgreg.sgn.sdy = val & SGN_SDY; + mystique->dwgreg.sgn.sdxr = val & SGN_SDXR; + break; + case REG_SGN + 1: + case REG_SGN + 2: + case REG_SGN + 3: + break; + + case REG_LEN: + case REG_LEN + 1: + WRITE8(addr, mystique->dwgreg.length, val); + break; + case REG_LEN + 2: + break; + case REG_LEN + 3: + mystique->dwgreg.beta = val >> 4; + if (!mystique->dwgreg.beta) + mystique->dwgreg.beta = 16; + break; + + case REG_CXBNDRY: + case REG_CXBNDRY + 1: + WRITE8(addr, mystique->dwgreg.cxleft, val); + break; + case REG_CXBNDRY + 2: + case REG_CXBNDRY + 3: + WRITE8(addr & 1, mystique->dwgreg.cxright, val); + break; + case REG_FXBNDRY: + case REG_FXBNDRY + 1: + WRITE8(addr, mystique->dwgreg.fxleft, val); + break; + case REG_FXBNDRY + 2: + case REG_FXBNDRY + 3: + WRITE8(addr & 1, mystique->dwgreg.fxright, val); + break; + + case REG_YDSTLEN: + case REG_YDSTLEN + 1: + WRITE8(addr, mystique->dwgreg.length, val); +#if 0 + pclog("Write YDSTLEN+%i %i\n", addr&1, mystique->dwgreg.length); +#endif + break; + case REG_YDSTLEN + 2: + mystique->dwgreg.ydst = (mystique->dwgreg.ydst & ~0xff) | val; + if (mystique->dwgreg.pitch & PITCH_YLIN) + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + else { + mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + mystique->dwgreg.selline = val & 7; + } + break; + case REG_YDSTLEN + 3: + mystique->dwgreg.ydst = (mystique->dwgreg.ydst & 0xff) | (((int32_t) (int8_t) val) << 8); + if (mystique->dwgreg.pitch & PITCH_YLIN) + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + else + mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + break; + + case REG_XDST: + case REG_XDST + 1: + WRITE8(addr & 1, mystique->dwgreg.xdst, val); + break; + case REG_XDST + 2: + case REG_XDST + 3: + break; + + case REG_YDSTORG: + case REG_YDSTORG + 1: + case REG_YDSTORG + 2: + case REG_YDSTORG + 3: + WRITE8(addr, mystique->dwgreg.ydstorg, val); + mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * ((mystique->maccess & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg; + break; + case REG_YTOP: + case REG_YTOP + 1: + case REG_YTOP + 2: + case REG_YTOP + 3: + WRITE8(addr, mystique->dwgreg.ytop, val); + break; + case REG_YBOT: + case REG_YBOT + 1: + case REG_YBOT + 2: + case REG_YBOT + 3: + WRITE8(addr, mystique->dwgreg.ybot, val); + break; + + case REG_CXLEFT: + case REG_CXLEFT + 1: + WRITE8(addr, mystique->dwgreg.cxleft, val); + break; + case REG_CXLEFT + 2: + case REG_CXLEFT + 3: + break; + case REG_CXRIGHT: + case REG_CXRIGHT + 1: + WRITE8(addr, mystique->dwgreg.cxright, val); + break; + case REG_CXRIGHT + 2: + case REG_CXRIGHT + 3: + break; + + case REG_FXLEFT: + case REG_FXLEFT + 1: + WRITE8(addr, mystique->dwgreg.fxleft, val); + break; + case REG_FXLEFT + 2: + case REG_FXLEFT + 3: + break; + case REG_FXRIGHT: + case REG_FXRIGHT + 1: + WRITE8(addr, mystique->dwgreg.fxright, val); + break; + case REG_FXRIGHT + 2: + case REG_FXRIGHT + 3: + break; + + case REG_SECADDRESS: + case REG_SECADDRESS + 1: + case REG_SECADDRESS + 2: + case REG_SECADDRESS + 3: + WRITE8(addr, mystique->dma.secaddress, val); + mystique->dma.sec_state = 0; + break; + + case REG_TMR0: + case REG_TMR0 + 1: + case REG_TMR0 + 2: + case REG_TMR0 + 3: + WRITE8(addr, mystique->dwgreg.tmr[0], val); + break; + case REG_TMR1: + case REG_TMR1 + 1: + case REG_TMR1 + 2: + case REG_TMR1 + 3: + WRITE8(addr, mystique->dwgreg.tmr[1], val); + break; + case REG_TMR2: + case REG_TMR2 + 1: + case REG_TMR2 + 2: + case REG_TMR2 + 3: + WRITE8(addr, mystique->dwgreg.tmr[2], val); + break; + case REG_TMR3: + case REG_TMR3 + 1: + case REG_TMR3 + 2: + case REG_TMR3 + 3: + WRITE8(addr, mystique->dwgreg.tmr[3], val); + break; + case REG_TMR4: + case REG_TMR4 + 1: + case REG_TMR4 + 2: + case REG_TMR4 + 3: + WRITE8(addr, mystique->dwgreg.tmr[4], val); + break; + case REG_TMR5: + case REG_TMR5 + 1: + case REG_TMR5 + 2: + case REG_TMR5 + 3: + WRITE8(addr, mystique->dwgreg.tmr[5], val); + break; + case REG_TMR6: + case REG_TMR6 + 1: + case REG_TMR6 + 2: + case REG_TMR6 + 3: + WRITE8(addr, mystique->dwgreg.tmr[6], val); + break; + case REG_TMR7: + case REG_TMR7 + 1: + case REG_TMR7 + 2: + case REG_TMR7 + 3: + WRITE8(addr, mystique->dwgreg.tmr[7], val); + break; + case REG_TMR8: + case REG_TMR8 + 1: + case REG_TMR8 + 2: + case REG_TMR8 + 3: + WRITE8(addr, mystique->dwgreg.tmr[8], val); + break; + + case REG_TEXORG: + case REG_TEXORG + 1: + case REG_TEXORG + 2: + case REG_TEXORG + 3: + WRITE8(addr, mystique->dwgreg.texorg, val); + break; + case REG_TEXWIDTH: + case REG_TEXWIDTH + 1: + case REG_TEXWIDTH + 2: + case REG_TEXWIDTH + 3: + WRITE8(addr, mystique->dwgreg.texwidth, val); + break; + case REG_TEXHEIGHT: + case REG_TEXHEIGHT + 1: + case REG_TEXHEIGHT + 2: + case REG_TEXHEIGHT + 3: + WRITE8(addr, mystique->dwgreg.texheight, val); + break; + case REG_TEXCTL: + case REG_TEXCTL + 1: + case REG_TEXCTL + 2: + case REG_TEXCTL + 3: + WRITE8(addr, mystique->dwgreg.texctl, val); + mystique->dwgreg.ta_key = (mystique->dwgreg.texctl & TEXCTL_TAKEY) ? 1 : 0; + mystique->dwgreg.ta_mask = (mystique->dwgreg.texctl & TEXCTL_TAMASK) ? 1 : 0; + break; + case REG_TEXTRANS: + case REG_TEXTRANS + 1: + case REG_TEXTRANS + 2: + case REG_TEXTRANS + 3: + WRITE8(addr, mystique->dwgreg.textrans, val); + break; + + case 0x1c18: + case 0x1c19: + case 0x1c1a: + case 0x1c1b: + case 0x1c28: + case 0x1c29: + case 0x1c2a: + case 0x1c2b: + case 0x1c2c: + case 0x1c2d: + case 0x1c2e: + case 0x1c2f: + case 0x1cc4: + case 0x1cc5: + case 0x1cc6: + case 0x1cc7: + case 0x1cd4: + case 0x1cd5: + case 0x1cd6: + case 0x1cd7: + case 0x1ce4: + case 0x1ce5: + case 0x1ce6: + case 0x1ce7: + case 0x1cf4: + case 0x1cf5: + case 0x1cf6: + case 0x1cf7: + break; + + case REG_OPMODE: + mystique->dwgreg.dmamod = (val >> 2) & 3; + mystique->dma.iload_state = 0; + break; + + default: + if ((addr & 0x3fff) >= 0x2c4c && (addr & 0x3fff) <= 0x2cff) + break; + break; + } + + if (start_blit) + mystique_start_blit(mystique); +} + +static void +mystique_ctrl_write_bx(uint32_t addr, uint8_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + svga_t *svga = &mystique->svga; + uint8_t addr_0x0f = 0; + uint16_t addr_0x03 = 0; + int rs2 = 0; + int rs3 = 0; + + if ((mystique->type == MGA_2064W || mystique->type == MGA_2164W) && (addr & 0x3e00) == 0x3c00) { + /*RAMDAC*/ + addr_0x0f = addr & 0x0f; + + if ((addr & 3) == 0) + addr_0x03 = 0x3c8; + else if ((addr & 3) == 1) + addr_0x03 = 0x3c9; + else if ((addr & 3) == 2) + addr_0x03 = 0x3c6; + else if ((addr & 3) == 3) + addr_0x03 = 0x3c7; + + if ((addr_0x0f >= 0x04) && (addr_0x0f <= 0x07)) { + rs2 = 1; + rs3 = 0; + } else if ((addr_0x0f >= 0x08) && (addr_0x0f <= 0x0b)) { + rs2 = 0; + rs3 = 1; + } else if ((addr_0x0f >= 0x0c) && (addr_0x0f <= 0x0f)) { + rs2 = 1; + rs3 = 1; + } + + tvp3026_ramdac_out(addr_0x03, rs2, rs3, val, svga->ramdac, svga); + return; + } + + if ((addr & 0x3fff) < 0x1c00) { + mystique_iload_write_b(addr, val, priv); + return; + } + if ((addr & 0x3e00) == 0x1c00 || (addr & 0x3e00) == 0x2c00) { + if ((addr & 0x300) == 0x100) + mystique->blitter_submit_refcount++; + mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_BYTE); + return; + } + + switch (addr & 0x3fff) { + case REG_ICLEAR: + if (val & ICLEAR_SOFTRAPICLR) { + //pclog("softrapiclr\n"); + mystique->status &= ~STATUS_SOFTRAPEN; + mystique_update_irqs(mystique); + } + if (val & ICLEAR_VLINEICLR) { + mystique->status &= ~STATUS_VLINEPEN; + mystique_update_irqs(mystique); + } + break; + case REG_ICLEAR + 1: + case REG_ICLEAR + 2: + case REG_ICLEAR + 3: + break; + + case REG_IEN: + mystique->ien = val & 0x65; + break; + case REG_IEN + 1: + case REG_IEN + 2: + case REG_IEN + 3: + break; + + case REG_OPMODE: + thread_wait_mutex(mystique->dma.lock); + mystique->dma.state = DMA_STATE_IDLE; /* Interrupt DMA. */ + thread_release_mutex(mystique->dma.lock); + mystique->dmamod = (val >> 2) & 3; + mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_BYTE); + break; + case REG_OPMODE + 1: + mystique->dmadatasiz = val & 3; + break; + case REG_OPMODE + 2: + mystique->dirdatasiz = val & 3; + extern void gfxboard_matrox_lfb_endianswap(int); + gfxboard_matrox_lfb_endianswap(val & 3); + break; + case REG_OPMODE + 3: + break; + + case REG_PRIMADDRESS: + case REG_PRIMADDRESS + 1: + case REG_PRIMADDRESS + 2: + case REG_PRIMADDRESS + 3: + thread_wait_mutex(mystique->dma.lock); + WRITE8(addr, mystique->dma.primaddress, val); + mystique->dma.pri_state = 0; + if (mystique->dma.state == DMA_STATE_IDLE && !(mystique->softrap_pending || mystique->endprdmasts_pending || !mystique->softrap_status_read)) { + mystique->dma.words_expected = 0; + } + mystique->dma.state = DMA_STATE_IDLE; + thread_release_mutex(mystique->dma.lock); + break; + + case REG_DMAMAP: + case REG_DMAMAP + 0x1: + case REG_DMAMAP + 0x2: + case REG_DMAMAP + 0x3: + case REG_DMAMAP + 0x4: + case REG_DMAMAP + 0x5: + case REG_DMAMAP + 0x6: + case REG_DMAMAP + 0x7: + case REG_DMAMAP + 0x8: + case REG_DMAMAP + 0x9: + case REG_DMAMAP + 0xa: + case REG_DMAMAP + 0xb: + case REG_DMAMAP + 0xc: + case REG_DMAMAP + 0xd: + case REG_DMAMAP + 0xe: + case REG_DMAMAP + 0xf: + mystique->dmamap[addr & 0xf] = val; + break; + + case REG_RST: + case REG_RST + 1: + case REG_RST + 2: + case REG_RST + 3: + wait_fifo_idle(mystique); + mystique->busy = 0; + mystique->blitter_submit_refcount = 0; + mystique->blitter_submit_dma_refcount = 0; + mystique->blitter_complete_refcount = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->status = STATUS_ENDPRDMASTS; + thread_wait_mutex(mystique->dma.lock); + mystique->dma.pri_state = 0; + mystique->dma.sec_state = 0; + mystique->dma.state = DMA_STATE_IDLE; + mystique->dma.words_expected = 0; + thread_release_mutex(mystique->dma.lock); + break; + + case REG_ATTR_IDX: + svga_out(0x3c0, val, svga); + break; + case REG_ATTR_DATA: + svga_out(0x3c1, val, svga); + break; + + case REG_MISC: + svga_out(0x3c2, val, svga); + break; + + case REG_SEQ_IDX: + svga_out(0x3c4, val, svga); + break; + case REG_SEQ_DATA: + svga_out(0x3c5, val, svga); + break; + + case REG_GCTL_IDX: + mystique_out(0x3ce, val, mystique); + break; + case REG_GCTL_DATA: + mystique_out(0x3cf, val, mystique); + break; + + case REG_CRTC_IDX: + mystique_out(0x3d4, val, mystique); + break; + case REG_CRTC_DATA: + mystique_out(0x3d5, val, mystique); + break; + + case REG_CRTCEXT_IDX: + mystique_out(0x3de, val, mystique); + break; + case REG_CRTCEXT_DATA: + mystique_out(0x3df, val, mystique); + break; + + case REG_CACHEFLUSH: + break; + + case REG_PALWTADD: + svga_out(0x3c8, val, svga); + mystique->xreg_idx = val; + break; + case REG_PALDATA: + svga_out(0x3c9, val, svga); + break; + case REG_PIXRDMSK: + svga_out(0x3c6, val, svga); + break; + case REG_PALRDADD: + svga_out(0x3c7, val, svga); + mystique->xreg_idx = val; + break; + + case REG_X_DATAREG: + mystique_write_xreg(mystique, mystique->xreg_idx, val); + break; + + case REG_CURPOSX: + case REG_CURPOSX + 1: + WRITE8(addr, mystique->cursor.pos_x, val); + svga->hwcursor.x = mystique->cursor.pos_x - 64; + break; + case REG_CURPOSY: + case REG_CURPOSY + 1: + WRITE8(addr & 1, mystique->cursor.pos_y, val); + svga->hwcursor.y = mystique->cursor.pos_y - 64; + break; + + case 0x1e50: + case 0x1e51: + case 0x1e52: + case 0x1e53: + case 0x3c0b: + case 0x3e02: + case 0x3e08: + break; + + default: + if ((addr & 0x3fff) >= 0x2c4c && (addr & 0x3fff) <= 0x2cff) + break; + if ((addr & 0x3fff) >= 0x3e00) + break; + break; + } +} + +static void +mystique_ctrl_write_b(uint32_t addr, uint8_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *)priv; + + if (powerpc(mystique, addr)) { + addr ^= 3; + } + + //pclog("B %08x %02x\n", addr, val); + + mystique_ctrl_write_bx(addr, val, priv); +} + +static uint16_t +mystique_ctrl_read_w(uint32_t addr, void *priv) +{ + mystique_t *mystique = (mystique_t *)priv; + uint32_t ret; + + if (powerpc(mystique, addr)) { + addr ^= 2; + } + + ret = mystique_ctrl_read_bx(addr, priv); + ret |= mystique_ctrl_read_bx(addr + 1, priv) << 8; + + return ret; +} + + +static uint32_t +mystique_ctrl_read_l(uint32_t addr, void *priv) +{ + mystique_t *mystique = (mystique_t *)priv; + uint32_t ret; + + if ((addr & 0x3fff) < 0x1c00) + return mystique_iload_read_l(addr, priv); + + ret = mystique_ctrl_read_bx(addr, priv); + ret |= mystique_ctrl_read_bx(addr + 1, priv) << 8; + ret |= mystique_ctrl_read_bx(addr + 2, priv) << 16; + ret |= mystique_ctrl_read_bx(addr + 3, priv) << 24; + + if (powerpc(mystique, addr)) { + ret = _byteswap_ulong(ret); + } + + return ret; +} + +static void +mystique_accel_ctrl_write_l(uint32_t addr, uint32_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + int start_blit = 0; + + //pclog("L %08x %08x\n", addr, val); + + if ((addr & 0x300) == 0x100) { + addr &= ~0x100; + start_blit = 1; + } + + switch (addr & 0x3ffc) { + case REG_DWGCTL: + mystique->dwgreg.dwgctrl = val; + + if (val & DWGCTRL_SOLID) { + for (uint8_t y = 0; y < 8; y++) { + for (uint8_t x = 0; x < 16; x++) + mystique->dwgreg.pattern[y][x] = 1; + } + mystique->dwgreg.src[0] = 0xffffffff; + mystique->dwgreg.src[1] = 0xffffffff; + mystique->dwgreg.src[2] = 0xffffffff; + mystique->dwgreg.src[3] = 0xffffffff; + } + if (val & DWGCTRL_ARZERO) { + mystique->dwgreg.ar[0] = 0; + mystique->dwgreg.ar[1] = 0; + mystique->dwgreg.ar[2] = 0; + mystique->dwgreg.ar[4] = 0; + mystique->dwgreg.ar[5] = 0; + mystique->dwgreg.ar[6] = 0; + } + if (val & DWGCTRL_SGNZERO) { + mystique->dwgreg.sgn.sdydxl = 0; + mystique->dwgreg.sgn.scanleft = 0; + mystique->dwgreg.sgn.sdxl = 0; + mystique->dwgreg.sgn.sdy = 0; + mystique->dwgreg.sgn.sdxr = 0; + } + if (val & DWGCTRL_SHTZERO) { + mystique->dwgreg.funcnt = 0; + mystique->dwgreg.stylelen = 0; + mystique->dwgreg.xoff = 0; + mystique->dwgreg.yoff = 0; + } + break; + + case REG_ZORG: + mystique->dwgreg.zorg = val; + mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * ((mystique->maccess & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg; + break; + + case REG_PLNWT: + mystique->dwgreg.plnwt = val; + break; + + case REG_SHIFT: + mystique->dwgreg.funcnt = val & 0x7f; + mystique->dwgreg.xoff = val & 7; + mystique->dwgreg.yoff = (val >> 4) & 7; + mystique->dwgreg.stylelen = (val >> 16) & 0x7f; + break; + + case REG_PITCH: + mystique->dwgreg.pitch = val & 0xffff; + if (mystique->dwgreg.pitch & PITCH_YLIN) + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + else + mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + break; + + case REG_YDST: + mystique->dwgreg.ydst = val & 0x3fffff; + if (mystique->dwgreg.pitch & PITCH_YLIN) { + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + mystique->dwgreg.selline = val >> 29; + } else { + mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + mystique->dwgreg.selline = val & 7; + } + break; + case REG_BCOL: + mystique->dwgreg.bcol = val; + break; + case REG_FCOL: + mystique->dwgreg.fcol = val; + break; + + case REG_SRC0: + { + mystique->dwgreg.src[0] = val; + for (uint8_t y = 0; y < 2; y++) { + for (uint8_t x = 0; x < 16; x++) { + mystique->dwgreg.pattern[y][x] = val & (1 << (x + (y * 16))); + } + } +#if 0 + pclog("SRC0 = 0x%08X\n", val); +#endif + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[0], 32); + } + break; + case REG_SRC1: + { + mystique->dwgreg.src[1] = val; + for (uint8_t y = 2; y < 4; y++) { + for (uint8_t x = 0; x < 16; x++) { + mystique->dwgreg.pattern[y][x] = val & (1 << (x + ((y - 2) * 16))); + } + } +#if 0 + pclog("SRC1 = 0x%08X\n", val); +#endif + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[1], 32); + } + break; + case REG_SRC2: + { + mystique->dwgreg.src[2] = val; + for (uint8_t y = 4; y < 6; y++) { + for (uint8_t x = 0; x < 16; x++) { + mystique->dwgreg.pattern[y][x] = val & (1 << (x + ((y - 4) * 16))); + } + } +#if 0 + pclog("SRC2 = 0x%08X\n", val); +#endif + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[2], 32); + break; + } + case REG_SRC3: + { + mystique->dwgreg.src[3] = val; + for (uint8_t y = 6; y < 8; y++) { + for (uint8_t x = 0; x < 16; x++) { + mystique->dwgreg.pattern[y][x] = val & (1 << (x + ((y - 6) * 16))); + } + } +#if 0 + pclog("SRC3 = 0x%08X\n", val); +#endif + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[3], 32); + break; + } + + case REG_DMAPAD: + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, val, 32); + break; + + case REG_AR0: + mystique->dwgreg.ar[0] = val; + break; + case REG_AR1: + mystique->dwgreg.ar[1] = val; + break; + case REG_AR2: + mystique->dwgreg.ar[2] = val; + break; + case REG_AR3: + mystique->dwgreg.ar[3] = val; + break; + case REG_AR4: + mystique->dwgreg.ar[4] = val; + break; + case REG_AR5: + mystique->dwgreg.ar[5] = val; + break; + case REG_AR6: + mystique->dwgreg.ar[6] = val; + break; + + case REG_DR0_Z32LSB: + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFFFFF) | val; + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + break; + + case REG_DR0_Z32MSB: + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & 0xFFFFFFFF) | ((val & 0xFFFFull) << 32ull); + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + break; + + case REG_DR2_Z32LSB: + mystique->dwgreg.extended_dr[2] = (mystique->dwgreg.extended_dr[2] & ~0xFFFFFFFF) | val; + mystique->dwgreg.dr[2] = (mystique->dwgreg.extended_dr[2] >> 16) & 0xFFFFFFFF; + break; + + case REG_DR2_Z32MSB: + mystique->dwgreg.extended_dr[2] = (mystique->dwgreg.extended_dr[2] & 0xFFFFFFFF) | ((val & 0xFFFFull) << 32ull); + mystique->dwgreg.dr[2] = (mystique->dwgreg.extended_dr[2] >> 16) & 0xFFFFFFFF; + break; + + case REG_DR3_Z32LSB: + mystique->dwgreg.extended_dr[3] = (mystique->dwgreg.extended_dr[3] & ~0xFFFFFFFF) | val; + mystique->dwgreg.dr[3] = (mystique->dwgreg.extended_dr[3] >> 16) & 0xFFFFFFFF; + break; + + case REG_DR3_Z32MSB: + mystique->dwgreg.extended_dr[3] = (mystique->dwgreg.extended_dr[3] & 0xFFFFFFFF) | ((val & 0xFFFFull) << 32ull); + mystique->dwgreg.dr[3] = (mystique->dwgreg.extended_dr[3] >> 16) & 0xFFFFFFFF; + break; + + case REG_DR0: + mystique->dwgreg.dr[0] = val; + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)val << 16ull); + break; + case REG_DR2: + mystique->dwgreg.dr[2] = val; + mystique->dwgreg.extended_dr[2] = (mystique->dwgreg.extended_dr[2] & ~0xFFFFull) | ((uint64_t)val << 16ull); + break; + case REG_DR3: + mystique->dwgreg.dr[3] = val; + mystique->dwgreg.extended_dr[3] = (mystique->dwgreg.extended_dr[3] & ~0xFFFFull) | ((uint64_t)val << 16ull); + break; + case REG_DR4: + mystique->dwgreg.dr[4] = val; + break; + case REG_DR6: + mystique->dwgreg.dr[6] = val; + break; + case REG_DR7: + mystique->dwgreg.dr[7] = val; + break; + case REG_DR8: + mystique->dwgreg.dr[8] = val; + break; + case REG_DR10: + mystique->dwgreg.dr[10] = val; + break; + case REG_DR11: + mystique->dwgreg.dr[11] = val; + break; + case REG_DR12: + mystique->dwgreg.dr[12] = val; + break; + case REG_DR14: + mystique->dwgreg.dr[14] = val; + break; + case REG_DR15: + mystique->dwgreg.dr[15] = val; + break; + + case REG_SECEND: + mystique->dma.secend = val; + if (mystique->dma.state != DMA_STATE_SEC && (mystique->dma.secaddress & DMA_ADDR_MASK) != (mystique->dma.secend & DMA_ADDR_MASK)) + mystique->dma.state = DMA_STATE_SEC; + break; + + case REG_SOFTRAP: + mystique->dma.state = DMA_STATE_IDLE; + mystique->dma.pri_state = 0; + mystique->dma.words_expected = 0; + mystique->endprdmasts_pending = 1; + mystique->softrap_pending_val = val; + mystique->softrap_pending += 1; + break; + + case REG_ALPHACTRL: + mystique->dwgreg.alphactrl = val; + break; + + case REG_ALPHASTART: + mystique->dwgreg.alphastart = val; + break; + + case REG_ALPHAXINC: + mystique->dwgreg.alphaxinc = val; + break; + + case REG_ALPHAYINC: + mystique->dwgreg.alphayinc = val; + break; + + case REG_FOGCOL: + mystique->dwgreg.fogcol = val; + break; + + case REG_FOGSTART: + mystique->dwgreg.fogstart = val; + break; + + case REG_FOGXINC: + mystique->dwgreg.fogxinc = val; + break; + + case REG_FOGYINC: + mystique->dwgreg.fogyinc = val; + break; + + case REG_TEXFILTER: + mystique->dwgreg.texfilter = val; + break; + + default: + mystique_accel_ctrl_write_b(addr, val & 0xff, priv); + mystique_accel_ctrl_write_b(addr + 1, (val >> 8) & 0xff, priv); + mystique_accel_ctrl_write_b(addr + 2, (val >> 16) & 0xff, priv); + mystique_accel_ctrl_write_b(addr + 3, (val >> 24) & 0xff, priv); + break; + } + + if (start_blit) + mystique_start_blit(mystique); +} + +static void +mystique_ctrl_write_l(uint32_t addr, uint32_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + uint32_t reg_addr; + + if ((addr & 0x3fff) < 0x1c00) { + mystique_iload_write_l(addr, val, priv); + return; + } + + if (powerpc(mystique, addr)) { + val = _byteswap_ulong(val); + } + + //pclog("L %08x %04x\n", addr, val); + + if ((addr & 0x3e00) == 0x1c00 || (addr & 0x3e00) == 0x2c00) { + if ((addr & 0x300) == 0x100) + mystique->blitter_submit_refcount++; + mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_LONG); + return; + } + + switch (addr & 0x3ffc) { + case REG_PRIMEND: + thread_wait_mutex(mystique->dma.lock); + mystique->dma.primend = val; + //pclog("PRIMADDRESS = 0x%08X, PRIMEND = 0x%08X\n", mystique->dma.primaddress, mystique->dma.primend); + if (mystique->dma.state == DMA_STATE_IDLE && (mystique->dma.primaddress & DMA_ADDR_MASK) != (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 0; + mystique->status &= ~STATUS_ENDPRDMASTS; + + mystique->dma.state = DMA_STATE_PRI; + //mystique->dma.pri_state = 0; + wake_fifo_thread(mystique); + } + /* HACK: For DirectX 9.0b Direct3D testing on Windows 98 SE. + + The 4.12.013 drivers give an out-of-bounds busmastering range when dxdiag enumerates Direct3D, with exactly 16384 bytes of difference. + Don't attempt busmastering in such cases. This isn't ideal, but there are no more crashes faced in this case. */ + if ((mystique->dma.primend & DMA_ADDR_MASK) < (mystique->dma.primaddress & DMA_ADDR_MASK) && ((mystique->dma.primaddress & DMA_ADDR_MASK) - (mystique->dma.primend & DMA_ADDR_MASK)) == 0x4000) + { + mystique->dma.primaddress = mystique->dma.primend; + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + } + thread_release_mutex(mystique->dma.lock); + break; + + case REG_DWG_INDIR_WT: + case REG_DWG_INDIR_WT + 0x04: + case REG_DWG_INDIR_WT + 0x08: + case REG_DWG_INDIR_WT + 0x0c: + case REG_DWG_INDIR_WT + 0x10: + case REG_DWG_INDIR_WT + 0x14: + case REG_DWG_INDIR_WT + 0x18: + case REG_DWG_INDIR_WT + 0x1c: + case REG_DWG_INDIR_WT + 0x20: + case REG_DWG_INDIR_WT + 0x24: + case REG_DWG_INDIR_WT + 0x28: + case REG_DWG_INDIR_WT + 0x2c: + case REG_DWG_INDIR_WT + 0x30: + case REG_DWG_INDIR_WT + 0x34: + case REG_DWG_INDIR_WT + 0x38: + case REG_DWG_INDIR_WT + 0x3c: + reg_addr = (mystique->dmamap[(addr >> 2) & 0xf] & 0x7f) << 2; + if (mystique->dmamap[(addr >> 2) & 0xf] & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_refcount++; + + mystique_queue(mystique, reg_addr, val, FIFO_WRITE_CTRL_LONG); + break; + + default: + mystique_ctrl_write_bx(addr, val & 0xff, priv); + mystique_ctrl_write_bx(addr + 1, (val >> 8) & 0xff, priv); + mystique_ctrl_write_bx(addr + 2, (val >> 16) & 0xff, priv); + mystique_ctrl_write_bx(addr + 3, (val >> 24) & 0xff, priv); + break; + } +} + +static void +mystique_ctrl_write_w(uint32_t addr, uint16_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *)priv; + uint32_t reg_addr; + + if (powerpc(mystique, addr)) { + addr ^= 2; + } + + //pclog("W %08x %04x\n", addr, val); + + mystique_ctrl_write_bx(addr, val & 0xff, priv); + mystique_ctrl_write_bx(addr + 1, (val >> 8) & 0xff, priv); +} + + +static uint8_t +mystique_iload_read_b(UNUSED(uint32_t addr), void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + wait_fifo_idle(mystique); + + if (!mystique->busy) + return 0xff; + + return blit_idump_read(mystique); +} + +static uint32_t +mystique_iload_read_l(UNUSED(uint32_t addr), void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + wait_fifo_idle(mystique); + + if (!mystique->busy) + return 0xffffffff; + + mystique->dwgreg.words++; + return blit_idump_read(mystique); +} + +static void +mystique_iload_write_b(UNUSED(uint32_t addr), UNUSED(uint8_t val), UNUSED(void *priv)) +{ + // +} + +static void +mystique_iload_write_l(UNUSED(uint32_t addr), uint32_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + mystique_queue(mystique, 0, val, FIFO_WRITE_ILOAD_LONG); +} + +static void +mystique_accel_iload_write_l(UNUSED(uint32_t addr), uint32_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + switch (mystique->dwgreg.dmamod) { + case DMA_MODE_REG: + if (mystique->dma.iload_state == 0) { + mystique->dma.iload_header = val; + mystique->dma.iload_state = 1; + } else { + uint32_t reg_addr = (mystique->dma.iload_header & 0x7f) << 2; + if (mystique->dma.iload_header & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_dma_refcount++; + mystique_accel_ctrl_write_l(reg_addr, val, mystique); + + mystique->dma.iload_header >>= 8; + mystique->dma.iload_state = (mystique->dma.iload_state == 4) ? 0 : (mystique->dma.iload_state + 1); + } + break; + + case DMA_MODE_BLIT: + if (mystique->busy) + blit_iload_write(mystique, val, 32); + break; + + default: +#if 0 + pclog("ILOAD write DMAMOD %i\n", mystique->dwgreg.dmamod); */ +#endif + break; + } +} + +static uint8_t +mystique_readb_linear(uint32_t addr, void *priv) +{ + const svga_t *svga = (svga_t *) priv; + + cycles -= svga->monitor->mon_video_timing_read_b; + + if (!svga->fast) { + if (svga->chain2_read) { + addr &= ~1; + addr <<= 2; + } + } + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + return svga->vram[addr & svga->vram_mask]; +} + +static uint16_t +mystique_readw_linear(uint32_t addr, void *priv) +{ + svga_t *svga = (svga_t *) priv; + + cycles -= svga->monitor->mon_video_timing_read_w; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffff; + + return *(uint16_t *) &svga->vram[addr & svga->vram_mask]; +} + +static uint32_t +mystique_readl_linear(uint32_t addr, void *priv) +{ + svga_t *svga = (svga_t *) priv; + + cycles -= svga->monitor->mon_video_timing_read_l; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffffffff; + + return *(uint32_t *) &svga->vram[addr & svga->vram_mask]; +} + +static void +mystique_writeb_linear(uint32_t addr, uint8_t val, void *priv) +{ + svga_t *svga = (svga_t *) priv; + + cycles -= svga->monitor->mon_video_timing_write_b; + + if (!svga->fast) { + if (svga->chain2_write) { + addr &= ~1; + addr <<= 2; + } + } + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = svga->monitor->mon_changeframecount; + svga->vram[addr] = val; +} + +static void +mystique_writew_linear(uint32_t addr, uint16_t val, void *priv) +{ + svga_t *svga = (svga_t *) priv; + + cycles -= svga->monitor->mon_video_timing_write_w; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = svga->monitor->mon_changeframecount; + *(uint16_t *) &svga->vram[addr] = val; +} + +static void +mystique_writel_linear(uint32_t addr, uint32_t val, void *priv) +{ + svga_t *svga = (svga_t *) priv; + + cycles -= svga->monitor->mon_video_timing_write_l; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = svga->monitor->mon_changeframecount; + *(uint32_t *) &svga->vram[addr] = val; +} + +static void +run_dma(mystique_t *mystique) +{ + int words_transferred = 0; + + thread_wait_mutex(mystique->dma.lock); + + if (mystique->softrap_pending || mystique->endprdmasts_pending || !mystique->softrap_status_read) + { + thread_release_mutex(mystique->dma.lock); + return; + } + + if (mystique->dma.state == DMA_STATE_IDLE) { + if (!(mystique->status & STATUS_ENDPRDMASTS)) + { + /* Force this to appear. */ + mystique->endprdmasts_pending = 1; + } + thread_release_mutex(mystique->dma.lock); + return; + } + + while (words_transferred < DMA_MAX_WORDS && mystique->dma.state != DMA_STATE_IDLE) { + switch (mystique->dma.state) { + case DMA_STATE_PRI: + switch (mystique->dma.primaddress & DMA_MODE_MASK) { + case DMA_MODE_REG: + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + break; + } + if (mystique->dma.pri_state == 0 && !mystique->dma.words_expected) { + dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.pri_header, 4, 4); + //pclog("DMA header: 0x%08X\n", mystique->dma.pri_header); + mystique->dma.primaddress += 4; + mystique->dma.words_expected = 4; + words_transferred++; + } + + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + break; + } + + { + uint32_t val; + uint32_t reg_addr; + + dma_bm_read(mystique->dma.primaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4); + words_transferred++; + + reg_addr = (mystique->dma.pri_header & 0x7f) << 2; + if (mystique->dma.pri_header & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_dma_refcount++; + + //pclog("DMA value: 0x%08X to reg 0x%04X\n", val, reg_addr); + mystique_accel_ctrl_write_l(reg_addr, val, mystique); + if (reg_addr == REG_SOFTRAP) { + mystique->dma.primaddress += 4; + break; + } + } + + if (mystique->dma.words_expected) + mystique->dma.words_expected--; + mystique->dma.primaddress += 4; + + mystique->dma.pri_header >>= 8; + mystique->dma.pri_state = (mystique->dma.pri_state + 1) & 3; + + if (mystique->dma.state == DMA_STATE_SEC) { + mystique->dma.sec_state = 0; + } + else if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + } + break; + + default: + fatal("DMA_STATE_PRI: mode %i\n", mystique->dma.primaddress & DMA_MODE_MASK); + } + break; + + case DMA_STATE_SEC: + switch (mystique->dma.secaddress & DMA_MODE_MASK) { + case DMA_MODE_REG: + if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + mystique->dma.pri_state = 0; + mystique->dma.words_expected = 0; + } else { + mystique->dma.state = DMA_STATE_PRI; + mystique->dma.words_expected = 0; + mystique->dma.pri_state = 0; + } + } + if (mystique->dma.sec_state == 0) { + dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &mystique->dma.sec_header, 4, 4); + mystique->dma.secaddress += 4; + //pclog("DMA header (secondary): 0x%08X\n", mystique->dma.sec_header); + words_transferred++; + } + + if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + mystique->dma.pri_state = 0; + mystique->dma.words_expected = 0; + } else { + mystique->dma.state = DMA_STATE_PRI; + mystique->dma.words_expected = 0; + mystique->dma.pri_state = 0; + } + } + + uint32_t val; + uint32_t reg_addr; + + dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4); + mystique->dma.secaddress += 4; + + reg_addr = (mystique->dma.sec_header & 0x7f) << 2; + if (mystique->dma.sec_header & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_dma_refcount++; + + mystique_accel_ctrl_write_l(reg_addr, val, mystique); + //pclog("DMA value (secondary): 0x%08X\n", val); + mystique->dma.sec_header >>= 8; + mystique->dma.sec_state = (mystique->dma.sec_state + 1) & 3; + + words_transferred++; + if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + mystique->dma.pri_state = 0; + mystique->dma.words_expected = 0; + } else { + mystique->dma.state = DMA_STATE_PRI; + mystique->dma.words_expected = 0; + mystique->dma.pri_state = 0; + } + } + break; + + case DMA_MODE_BLIT: + { + uint32_t val; + if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + mystique->dma.words_expected = 0; + mystique->dma.pri_state = 0; + } else { + mystique->dma.state = DMA_STATE_PRI; + mystique->dma.words_expected = 0; + mystique->dma.pri_state = 0; + } + } + + dma_bm_read(mystique->dma.secaddress & DMA_ADDR_MASK, (uint8_t *) &val, 4, 4); + mystique->dma.secaddress += 4; + + if (mystique->busy) + blit_iload_write(mystique, val, 32); + + words_transferred++; + if ((mystique->dma.secaddress & DMA_ADDR_MASK) >= (mystique->dma.secend & DMA_ADDR_MASK)) { + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) { + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + mystique->dma.words_expected = 0; + mystique->dma.pri_state = 0; + } else { + mystique->dma.state = DMA_STATE_PRI; + mystique->dma.words_expected = 0; + mystique->dma.pri_state = 0; + } + } + } + break; + + default: + fatal("DMA_STATE_SEC: mode %i\n", mystique->dma.secaddress & DMA_MODE_MASK); + } + break; + + default: + break; + } + } + + thread_release_mutex(mystique->dma.lock); +} + +static void +fifo_thread(void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + while (mystique->thread_run) { + thread_set_event(mystique->fifo_not_full_event); + thread_wait_event(mystique->wake_fifo_thread, -1); + thread_reset_event(mystique->wake_fifo_thread); + + while (!FIFO_EMPTY || mystique->dma.state != DMA_STATE_IDLE) { + int words_transferred = 0; + + while (!FIFO_EMPTY && words_transferred < 100) { + fifo_entry_t *fifo = &mystique->fifo[mystique->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) { + case FIFO_WRITE_CTRL_BYTE: + mystique_accel_ctrl_write_b(fifo->addr_type & FIFO_ADDR, fifo->val, mystique); + break; + case FIFO_WRITE_CTRL_LONG: + mystique_accel_ctrl_write_l(fifo->addr_type & FIFO_ADDR, fifo->val, mystique); + break; + case FIFO_WRITE_ILOAD_LONG: + mystique_accel_iload_write_l(fifo->addr_type & FIFO_ADDR, fifo->val, mystique); + break; + + default: + break; + } + + fifo->addr_type = FIFO_INVALID; + mystique->fifo_read_idx++; + + if (FIFO_ENTRIES > FIFO_THRESHOLD) + thread_set_event(mystique->fifo_not_full_event); + + words_transferred++; + } + + /*Only run DMA once the FIFO is empty. Required by + Screamer 2 / Rally which will incorrectly clip an ILOAD + if DMA runs ahead*/ + if (!words_transferred) + run_dma(mystique); + } + } +} + +static void +wake_fifo_thread(mystique_t *mystique) +{ + if (!timer_is_enabled(&mystique->wake_timer)) { + /* Don't wake FIFO thread immediately - if we do that it will probably + process one word and go back to sleep, requiring it to be woken on + almost every write. Instead, wait a short while so that the CPU + emulation writes more data so we have more batched-up work. */ + timer_set_delay_u64x(&mystique->wake_timer, WAKE_DELAY); + } +} + +static void +wake_fifo_thread_now(mystique_t *mystique) +{ + thread_set_event(mystique->wake_fifo_thread); +} + +static void +mystique_wake_timer(void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + thread_set_event(mystique->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void +wait_fifo_idle(mystique_t *mystique) +{ + while (!FIFO_EMPTY) { + wake_fifo_thread_now(mystique); + thread_wait_event(mystique->fifo_not_full_event, 1); + } +} + +/*IRQ code (PCI & PIC) is not currently thread safe. SOFTRAP IRQ requests must + therefore be submitted from the main emulation thread, in this case via a timer + callback. End-of-DMA status is also deferred here to prevent races between + SOFTRAP IRQs and code reading the status register. Croc will get into an IRQ + loop and triple fault if the ENDPRDMASTS flag is seen before the IRQ is taken*/ +static void +mystique_softrap_pending_timer(void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + timer_advance_u64x(&mystique->softrap_pending_timer, TIMER_USEC * 100); + + if (mystique->endprdmasts_pending) { + mystique->endprdmasts_pending = 0; + mystique->status |= STATUS_ENDPRDMASTS; + } + if (mystique->softrap_pending) { + mystique->dma.secaddress = mystique->softrap_pending_val; + mystique->status |= STATUS_SOFTRAPEN; + mystique->softrap_status_read = 0; + //pclog("softrapen\n"); + mystique_update_irqs(mystique); + mystique->softrap_pending--; + } + +} + +static void +mystique_queue(mystique_t *mystique, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &mystique->fifo[mystique->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) { + thread_reset_event(mystique->fifo_not_full_event); + if (FIFO_FULL) + thread_wait_event(mystique->fifo_not_full_event, -1); /* Wait for room in ringbuffer */ + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + mystique->fifo_write_idx++; + + if (FIFO_ENTRIES > FIFO_THRESHOLD || FIFO_ENTRIES < 8) + wake_fifo_thread(mystique); +} + +static uint32_t +bitop(uint32_t src, uint32_t dst, uint32_t dwgctrl) +{ + switch (dwgctrl & DWGCTRL_BOP_MASK) { + case BOP(0x0): + return 0; + case BOP(0x1): + return ~(dst | src); + case BOP(0x2): + return dst & ~src; + case BOP(0x3): + return ~src; + case BOP(0x4): + return ~dst & src; + case BOP(0x5): + return ~dst; + case BOP(0x6): + return dst ^ src; + case BOP(0x7): + return ~(dst & src); + case BOP(0x8): + return dst & src; + case BOP(0x9): + return ~(dst ^ src); + case BOP(0xa): + return dst; + case BOP(0xb): + return dst | ~src; + case BOP(0xc): + return src; + case BOP(0xd): + return ~dst | src; + case BOP(0xe): + return dst | src; + case BOP(0xf): + return ~0; + + default: + break; + } + + return 0; +} + +static uint16_t +dither(mystique_t *mystique, int r, int g, int b, int x, int y) +{ + switch (mystique->dwgreg.dither) { + case DITHER_NONE_555: + return (b >> 3) | ((g >> 3) << 5) | ((r >> 3) << 10); + + case DITHER_NONE_565: + return (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11); + + case DITHER_555: + return dither5[b][y][x] | (dither5[g][y][x] << 5) | (dither5[r][y][x] << 10); + + case DITHER_565: + default: + return dither5[b][y][x] | (dither6[g][y][x] << 5) | (dither5[r][y][x] << 11); + } +} + +static uint32_t +blit_idump_idump(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint64_t val64 = 0; + uint32_t val = 0; + int count = 0; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BU32RGB: + case DWGCTRL_BLTMOD_BFCOL: + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + while (count < 32) { + val |= (svga->vram[mystique->dwgreg.src_addr & mystique->vram_mask] << count); + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + + count += 8; + } + break; + + case MACCESS_PWIDTH_16: + while (count < 32) { + val |= (((uint16_t *) svga->vram)[mystique->dwgreg.src_addr & mystique->vram_mask_w] << count); + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + + count += 16; + } + break; + + case MACCESS_PWIDTH_24: + if (mystique->dwgreg.idump_end_of_line) { + mystique->dwgreg.idump_end_of_line = 0; + val = mystique->dwgreg.iload_rem_data; + mystique->dwgreg.iload_rem_count = 0; + mystique->dwgreg.iload_rem_data = 0; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + } + break; + } + + count += mystique->dwgreg.iload_rem_count; + val64 = mystique->dwgreg.iload_rem_data; + + while ((count < 32) && !mystique->dwgreg.idump_end_of_line) { + val64 |= (uint64_t) ((*(uint32_t *) &svga->vram[(mystique->dwgreg.src_addr * 3) & mystique->vram_mask]) & 0xffffff) << count; + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + if (count > 8) + mystique->dwgreg.idump_end_of_line = 1; + else { + count = 32; + mystique->busy = 0; + mystique->blitter_complete_refcount++; + } + break; + } + if (!(mystique->dwgreg.dwgctrl_running & DWGCTRL_LINEAR)) { + if (count > 8) + mystique->dwgreg.idump_end_of_line = 1; + else { + count = 32; + break; + } + } + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + + count += 24; + } + if (count > 32) + mystique->dwgreg.iload_rem_count = count - 32; + else + mystique->dwgreg.iload_rem_count = 0; + mystique->dwgreg.iload_rem_data = (uint32_t) (val64 >> 32); + val = val64 & 0xffffffff; + break; + + case MACCESS_PWIDTH_32: + val = (((uint32_t *) svga->vram)[mystique->dwgreg.src_addr & mystique->vram_mask_l] << count); + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + break; + + default: + fatal("IDUMP DWGCTRL_BLTMOD_BU32RGB %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->maccess_running); + } + break; + + default: + fatal("IDUMP DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown IDUMP atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + return val; +} + +static uint32_t +blit_idump_read(mystique_t *mystique) +{ + uint32_t ret = 0xffffffff; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) { + case DWGCTRL_OPCODE_IDUMP: + ret = blit_idump_idump(mystique); + break; + + default: + /* pclog("blit_idump_read: bad opcode %08x\n", mystique->dwgreg.dwgctrl_running); */ + break; + } + + return ret; +} + +static void +blit_fbitblt(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint32_t src_addr; + int x_dir = mystique->dwgreg.sgn.scanleft ? -1 : 1; + int16_t x_start = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxright : mystique->dwgreg.fxleft; + int16_t x_end = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxleft : mystique->dwgreg.fxright; + + src_addr = mystique->dwgreg.ar[3]; + + for (uint16_t y = 0; y < mystique->dwgreg.length; y++) { + int16_t x = x_start; + while (1) { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint32_t src; + uint32_t old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + src = svga->vram[src_addr & mystique->vram_mask]; + + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = src; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + src = ((uint16_t *) svga->vram)[src_addr & mystique->vram_mask_w]; + + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = src; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + src = *(uint32_t *) &svga->vram[(src_addr * 3) & mystique->vram_mask]; + old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (src & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + src = ((uint32_t *) svga->vram)[src_addr & mystique->vram_mask_l]; + + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = src; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("BITBLT RPL BFCOL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + break; + } else + src_addr += x_dir; + + if (x != x_end) + x += x_dir; + else + break; + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + + mystique->blitter_complete_refcount++; +} + +static uint8_t +dither_24_to_8(int r, int g, int b) +{ + return ((b >> 6) & 3) | (((g >> 5) & 7) << 2) | (((r >> 5) & 7) << 5); +} + +static void +blit_iload_iload(mystique_t *mystique, uint32_t data, int size) +{ + svga_t *svga = &mystique->svga; + uint32_t src; + uint32_t dst; + uint32_t dst2; + uint64_t data64; + int min_size = 8; + uint32_t bltckey = mystique->dwgreg.fcol; + uint32_t bltcmsk = mystique->dwgreg.bcol; + const int transc = mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint32_t data_mask = 1; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + bltckey &= 0xff; + bltcmsk &= 0xff; + break; + case MACCESS_PWIDTH_16: + bltckey &= 0xffff; + bltcmsk &= 0xffff; + break; + } + + mystique->dwgreg.words++; + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + if (mystique->maccess_running & MACCESS_TLUTLOAD) { + while ((mystique->dwgreg.length_cur > 0) && (size >= 16)) { + uint16_t src = data & 0xffff; + + mystique->lut[mystique->dwgreg.ydst & 0xff].r = (src >> 11) << 3; + mystique->lut[mystique->dwgreg.ydst & 0xff].g = ((src >> 5) & 0x3f) << 2; + mystique->lut[mystique->dwgreg.ydst & 0xff].b = (src & 0x1f) << 3; + mystique->dwgreg.ydst++; + mystique->dwgreg.length_cur--; + data >>= 16; + size -= 16; + } + + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + } + break; + } + case DWGCTRL_ATYPE_RSTR: + case DWGCTRL_ATYPE_BLK: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BFCOL: + size += mystique->dwgreg.iload_rem_count; + data64 = mystique->dwgreg.iload_rem_data | ((uint64_t) data << mystique->dwgreg.iload_rem_count); + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + min_size = 8; + break; + case MACCESS_PWIDTH_16: + min_size = 16; + break; + case MACCESS_PWIDTH_24: + min_size = 24; + break; + case MACCESS_PWIDTH_32: + min_size = 32; + break; + + default: + break; + } + + while (size >= min_size) { + int draw = (!transc || (data & bltcmsk) != bltckey) && trans[mystique->dwgreg.xdst & 3]; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) { + dst = svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]; + + dst = bitop(data & 0xff, dst, mystique->dwgreg.dwgctrl_running); + svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount; + } + + data >>= 8; + size -= 8; + break; + + case MACCESS_PWIDTH_16: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) { + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + + dst = bitop(data & 0xffff, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + } + + data >>= 16; + size -= 16; + break; + + case MACCESS_PWIDTH_24: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint32_t old_dst = *((uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]); + + dst = bitop(data64, old_dst, mystique->dwgreg.dwgctrl_running); + *((uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]) = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask) >> 12] = changeframecount; + } + + data64 >>= 24; + size -= 24; + break; + + case MACCESS_PWIDTH_32: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) { + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + + dst = bitop(data, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + } + + size = 0; + break; + + default: + fatal("ILOAD RSTR/RPL BFCOL pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + data64 = 0; + size = 0; + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + mystique->dwgreg.iload_rem_count = size; + mystique->dwgreg.iload_rem_data = data64; + break; + + case DWGCTRL_BLTMOD_BMONOWF: + data = (data >> 24) | ((data & 0x00ff0000) >> 8) | ((data & 0x0000ff00) << 8) | (data << 24); + data_mask = (1 << 31); + case DWGCTRL_BLTMOD_BMONOLEF: + while (size) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && ((data & data_mask) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && trans[mystique->dwgreg.xdst & 3]) { + uint32_t old_dst; + + src = (data & data_mask) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); + + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD RSTR/RPL BMONOWF pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + if (!(mystique->dwgreg.dwgctrl_running & DWGCTRL_LINEAR)) + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + if (data_mask == 1) + data >>= 1; + else + data <<= 1; + size--; + } + break; + + case DWGCTRL_BLTMOD_BU24RGB: + size += mystique->dwgreg.iload_rem_count; + data64 = mystique->dwgreg.iload_rem_data | ((uint64_t) data << mystique->dwgreg.iload_rem_count); + + while (size >= 24) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_16: + { + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + + dst = bitop(dither(mystique, (data64 >> 16) & 0xFF, (data64 >> 8) & 0xFF, data64 & 0xFF, mystique->dwgreg.xdst & 1, mystique->dwgreg.selline & 1), dst, mystique->dwgreg.dwgctrl_running); + + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + } + case MACCESS_PWIDTH_8: + { + dst = ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]; + + dst = bitop(dither_24_to_8((data64 >> 16) & 0xFF, (data64 >> 8) & 0xFF, data64 & 0xFF), dst, mystique->dwgreg.dwgctrl_running); + + ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount; + break; + } + case MACCESS_PWIDTH_32: + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + + dst = bitop(data64 & 0xffffff, dst, mystique->dwgreg.dwgctrl_running); + + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD RSTR/RPL BU24RGB pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + data64 >>= 24; + size -= 24; + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + data64 = 0; + size = 0; + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + + mystique->dwgreg.iload_rem_count = size; + mystique->dwgreg.iload_rem_data = data64; + break; + + case DWGCTRL_BLTMOD_BU32RGB: + size += mystique->dwgreg.iload_rem_count; + data64 = mystique->dwgreg.iload_rem_data | ((uint64_t) data << mystique->dwgreg.iload_rem_count); + while (size >= 32) { + int draw = (!transc || (data & bltcmsk) != bltckey) && trans[mystique->dwgreg.xdst & 3]; + + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) { + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_16: + { + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + + dst = bitop(dither(mystique, (data64 >> 16) & 0xFF, (data64 >> 8) & 0xFF, data64 & 0xFF, mystique->dwgreg.xdst & 1, mystique->dwgreg.selline & 1), dst, mystique->dwgreg.dwgctrl_running); + + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + } + case MACCESS_PWIDTH_8: + { + dst = ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]; + + dst = bitop(dither_24_to_8((data64 >> 16) & 0xFF, (data64 >> 8) & 0xFF, data64 & 0xFF), dst, mystique->dwgreg.dwgctrl_running); + + ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount; + break; + } + default: { + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + + dst = bitop(data, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + } + } + } + + size = 0; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + data64 = 0; + size = 0; + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + mystique->dwgreg.iload_rem_count = size; + mystique->dwgreg.iload_rem_data = data64; + break; + + case DWGCTRL_BLTMOD_BU32BGR: + size += mystique->dwgreg.iload_rem_count; + while (size >= 32) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_32: + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + dst2 = ((dst >> 16) & 0xff) | (dst & 0xff00) | ((dst & 0xff) << 16); /* BGR to RGB */ + + dst = bitop(data, dst2, mystique->dwgreg.dwgctrl_running); + + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD RSTR/RPL BU32RGB pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + size = 0; + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + + mystique->dwgreg.iload_rem_count = size; + break; + + default: + fatal("ILOAD DWGCTRL_ATYPE_RPL\n"); + break; + } + break; + + default: + fatal("Unknown ILOAD iload atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +#define CLAMP(x) \ + do { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } while (0) + +static void +blit_iload_iload_scale(mystique_t *mystique, uint32_t data, int size) +{ + svga_t *svga = &mystique->svga; + uint64_t data64 = 0; + int y0; + int y1; + int u; + int v; + int dR; + int dG; + int dB; + int r0; + int g0; + int b0; + int r1; + int g1; + int b1; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + y0 = (298 * ((int) (data & 0xff) - 16)) >> 8; + u = ((data >> 8) & 0xff) - 0x80; + y1 = (298 * ((int) ((data >> 16) & 0xff) - 16)) >> 8; + v = ((data >> 24) & 0xff) - 0x80; + + dR = (309 * v) >> 8; + dG = (100 * u + 208 * v) >> 8; + dB = (516 * u) >> 8; + + r0 = y0 + dR; + CLAMP(r0); + g0 = y0 - dG; + CLAMP(g0); + b0 = y0 + dB; + CLAMP(b0); + r1 = y1 + dR; + CLAMP(r1); + g1 = y1 - dG; + CLAMP(g1); + b1 = y1 + dB; + CLAMP(b1); + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_16: + data = (b0 >> 3) | ((g0 >> 2) << 5) | ((r0 >> 3) << 11); + data |= (((b1 >> 3) | ((g1 >> 2) << 5) | ((r1 >> 3) << 11)) << 16); + size = 32; + break; + case MACCESS_PWIDTH_32: + data64 = b0 | (g0 << 8) | (r0 << 16); + data64 |= ((uint64_t) b0 << 32) | ((uint64_t) g0 << 40) | ((uint64_t) r0 << 48); + size = 64; + break; + + default: + fatal("blit_iload_iload_scale BUYUV pwidth %i\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + break; + + default: + fatal("blit_iload_iload_scale bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_16: + while (size >= 16) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint16_t dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + dst = bitop(data & 0xffff, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + } + + mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2]; + if ((int32_t) mystique->dwgreg.ar[6] >= 0) { + mystique->dwgreg.ar[6] -= (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + data >>= 16; + size -= 16; + } + + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } + } + break; + + case MACCESS_PWIDTH_32: + while (size >= 32) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint32_t dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + dst = bitop(data64, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + } + + mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2]; + if ((int32_t) mystique->dwgreg.ar[6] >= 0) { + mystique->dwgreg.ar[6] -= (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + data64 >>= 32; + size -= 32; + } + + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } + } + break; + + default: + fatal("ILOAD_SCALE pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } +} + +static void +blit_iload_iload_high(mystique_t *mystique, uint32_t data, int size) +{ + svga_t *svga = &mystique->svga; + uint32_t out_data; + int y0; + int y1; + int u; + int v; + int dR; + int dG; + int dB; + int r = 0; + int g = 0; + int b = 0; + int next_r = 0; + int next_g = 0; + int next_b = 0; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + y0 = (298 * ((int) (data & 0xff) - 16)) >> 8; + u = ((data >> 8) & 0xff) - 0x80; + y1 = (298 * ((int) ((data >> 16) & 0xff) - 16)) >> 8; + v = ((data >> 24) & 0xff) - 0x80; + + dR = (309 * v) >> 8; + dG = (100 * u + 208 * v) >> 8; + dB = (516 * u) >> 8; + + r = y0 + dR; + CLAMP(r); + g = y0 - dG; + CLAMP(g); + b = y0 + dB; + CLAMP(b); + + next_r = y1 + dR; + CLAMP(next_r); + next_g = y1 - dG; + CLAMP(next_g); + next_b = y1 + dB; + CLAMP(next_b); + + size = 32; + break; + + case DWGCTRL_BLTMOD_BU32BGR: + r = ((data >> 16) & 0xff); + CLAMP(r); + g = ((data >> 8) & 0xff); + CLAMP(g); + b = (data & 0xff); + CLAMP(b); + + next_r = r; + next_g = g; + next_b = b; + + size = 32; + break; + + default: + fatal("blit_iload_iload_high bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } + + while (size >= 16) { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint32_t dst; + int f1 = (mystique->dwgreg.ar[6] >> 12) & 0xf; + int f0 = 0x10 - f1; + int out_r = ((mystique->dwgreg.lastpix_r * f0) + (r * f1)) >> 4; + int out_g = ((mystique->dwgreg.lastpix_g * f0) + (g * f1)) >> 4; + int out_b = ((mystique->dwgreg.lastpix_b * f0) + (b * f1)) >> 4; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_16: + out_data = (out_b >> 3) | ((out_g >> 2) << 5) | ((out_r >> 3) << 11); + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + dst = bitop(out_data, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + case MACCESS_PWIDTH_32: + out_data = out_b | (out_g << 8) | (out_r << 16); + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + dst = bitop(out_data, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD_SCALE_HIGH RSTR/RPL BUYUV pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2]; + if ((int32_t) mystique->dwgreg.ar[6] >= 0) { + mystique->dwgreg.ar[6] -= 65536; + size -= 16; + + mystique->dwgreg.lastpix_r = r; + mystique->dwgreg.lastpix_g = g; + mystique->dwgreg.lastpix_b = b; + r = next_r; + g = next_g; + b = next_b; + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + mystique->dwgreg.lastpix_r = 0; + mystique->dwgreg.lastpix_g = 0; + mystique->dwgreg.lastpix_b = 0; + + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } +} + +static void +blit_iload_iload_highv(mystique_t *mystique, uint32_t data, UNUSED(int size)) +{ + const uint8_t *src0; + uint8_t *src1; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + if (!mystique->dwgreg.highv_line) { + mystique->dwgreg.highv_data = data; + mystique->dwgreg.highv_line = 1; + return; + } + mystique->dwgreg.highv_line = 0; + + src0 = (uint8_t *) &mystique->dwgreg.highv_data; + src1 = (uint8_t *) &data; + + src1[0] = ((src0[0] * mystique->dwgreg.beta) + (src1[0] * (16 - mystique->dwgreg.beta))) >> 4; + src1[1] = ((src0[1] * mystique->dwgreg.beta) + (src1[1] * (16 - mystique->dwgreg.beta))) >> 4; + src1[2] = ((src0[2] * mystique->dwgreg.beta) + (src1[2] * (16 - mystique->dwgreg.beta))) >> 4; + src1[3] = ((src0[3] * mystique->dwgreg.beta) + (src1[3] * (16 - mystique->dwgreg.beta))) >> 4; + blit_iload_iload_high(mystique, data, 32); + break; + + default: + fatal("blit_iload_iload_highv bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } +} + +static void +blit_iload_write(mystique_t *mystique, uint32_t data, int size) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) { + case DWGCTRL_OPCODE_ILOAD: + blit_iload_iload(mystique, data, size); + break; + + case DWGCTRL_OPCODE_ILOAD_SCALE: + blit_iload_iload_scale(mystique, data, size); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGH: + blit_iload_iload_high(mystique, data, size); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGHV: + blit_iload_iload_highv(mystique, data, size); + break; + + default: + fatal("blit_iload_write: bad opcode %08x\n", mystique->dwgreg.dwgctrl_running); + } +} + +static int +z_check(uint16_t z, uint16_t old_z, uint32_t z_mode) // mystique->dwgreg.dwgctrl & DWGCTRL_ZMODE_MASK) +{ + switch (z_mode) { + case DWGCTRL_ZMODE_ZE: + return (z == old_z); + case DWGCTRL_ZMODE_ZNE: + return (z != old_z); + case DWGCTRL_ZMODE_ZLT: + return (z < old_z); + case DWGCTRL_ZMODE_ZLTE: + return (z <= old_z); + case DWGCTRL_ZMODE_ZGT: + return (z > old_z); + case DWGCTRL_ZMODE_ZGTE: + return (z >= old_z); + + case DWGCTRL_ZMODE_NOZCMP: + default: + return 1; + } +} + +static int +z_check_32(uint32_t z, uint32_t old_z, uint32_t z_mode) // mystique->dwgreg.dwgctrl & DWGCTRL_ZMODE_MASK) +{ + switch (z_mode) { + case DWGCTRL_ZMODE_ZE: + return (z == old_z); + case DWGCTRL_ZMODE_ZNE: + return (z != old_z); + case DWGCTRL_ZMODE_ZLT: + return (z < old_z); + case DWGCTRL_ZMODE_ZLTE: + return (z <= old_z); + case DWGCTRL_ZMODE_ZGT: + return (z > old_z); + case DWGCTRL_ZMODE_ZGTE: + return (z >= old_z); + + case DWGCTRL_ZMODE_NOZCMP: + default: + return 1; + } +} + +static void +blit_line(mystique_t *mystique, int closed, int autoline) +{ + svga_t *svga = &mystique->svga; + uint32_t src = 0; + uint32_t dst; + uint32_t old_dst; + int x = mystique->dwgreg.xdst; + int z_write; + int pattern_x, pattern_y; + bool transc = !!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC); + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RSTR: + case DWGCTRL_ATYPE_RPL: + while (mystique->dwgreg.length >= 0) { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + pattern_y = ((mystique->dwgreg.funcnt % (mystique->dwgreg.stylelen + 1)) >> 4) & 0x7; + pattern_x = (mystique->dwgreg.funcnt % (mystique->dwgreg.stylelen + 1)) & 0xf; + if (!transc || (transc && (mystique->dwgreg.pattern[pattern_y][pattern_x]))) + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + src = mystique->dwgreg.pattern[pattern_y][pattern_x] ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + if (closed) { + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + } else if (!closed && (mystique->dwgreg.length > 0) && ((mystique->dwgreg.err > 0) || (mystique->dwgreg.err < 0)) && !autoline) { + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + } else if (!closed && (mystique->dwgreg.length > 0) && autoline) { + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + } + break; + + case MACCESS_PWIDTH_16: + src = mystique->dwgreg.pattern[pattern_y][pattern_x] ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + if (closed) { + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + } else if (!closed && (mystique->dwgreg.length > 0) && ((mystique->dwgreg.err > 0) || (mystique->dwgreg.err < 0)) && !autoline) { + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + } else if (!closed && (mystique->dwgreg.length > 0) && autoline) { + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + } + break; + + case MACCESS_PWIDTH_24: + src = mystique->dwgreg.pattern[pattern_y][pattern_x] ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); + if (closed) { + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + } else if (!closed && (mystique->dwgreg.length > 0) && ((mystique->dwgreg.err > 0) || (mystique->dwgreg.err < 0)) && !autoline) { + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + } else if (!closed && (mystique->dwgreg.length > 0) && autoline) { + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + } + break; + + case MACCESS_PWIDTH_32: + src = mystique->dwgreg.pattern[pattern_y][pattern_x] ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + if (closed) { + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + } else if (!closed && (mystique->dwgreg.length > 0) && ((mystique->dwgreg.err > 0) || (mystique->dwgreg.err < 0)) && !autoline) { + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + } else if (!closed && (mystique->dwgreg.length > 0) && autoline) { + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + } + break; + + default: + fatal("LINE RSTR/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (!mystique->dwgreg.length) + break; + + if (mystique->dwgreg.sgn.sdydxl) + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + else { + mystique->dwgreg.ydst += (mystique->dwgreg.sgn.sdy ? -1 : 1); + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + } + if (mystique->dwgreg.err >= 0) { + mystique->dwgreg.err += mystique->dwgreg.k2; + if (mystique->dwgreg.sgn.sdydxl) { + mystique->dwgreg.ydst += (mystique->dwgreg.sgn.sdy ? -1 : 1); + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + } else + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } else + mystique->dwgreg.err += mystique->dwgreg.k1; + + mystique->dwgreg.length--; + mystique->dwgreg.funcnt--; + } + break; + + case DWGCTRL_ATYPE_I: + case DWGCTRL_ATYPE_ZI: + z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI); + while (mystique->dwgreg.length > 0) { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + bool z_check_pass = false; + if (mystique->maccess_running & MACCESS_ZWIDTH) { + uint32_t z = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull); + uint32_t *z_p = (uint32_t *) &svga->vram[(mystique->dwgreg.ydst_lin * 4 + mystique->dwgreg.zorg) & mystique->vram_mask]; + uint32_t old_z = z_p[x]; + z_check_pass = z_check_32(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK); + if (z_write && z_check_pass) { + z_p[x] = z; + } + } else { + uint16_t z = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + uint16_t *z_p = (uint16_t *) &svga->vram[(mystique->dwgreg.ydst_lin * 2 + mystique->dwgreg.zorg) & mystique->vram_mask]; + uint16_t old_z = z_p[x]; + z_check_pass = z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK); + if (z_write && z_check_pass) { + z_p[x] = z; + } + } + + if (z_check_pass) { + int r = 0; + int g = 0; + int b = 0; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + r = (mystique->dwgreg.dr[4] >> 20) & 0x7; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + g = (mystique->dwgreg.dr[8] >> 20) & 0x7; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + b = (mystique->dwgreg.dr[12] >> 21) & 0x3; + dst = (r << 5) | (g << 2) | b; + + ((uint8_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + r = (mystique->dwgreg.dr[4] >> 18) & 0x1f; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + g = (mystique->dwgreg.dr[8] >> 17) & 0x3f; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + b = (mystique->dwgreg.dr[12] >> 18) & 0x1f; + dst = (r << 11) | (g << 5) | b; + + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + r = (mystique->dwgreg.dr[4] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + g = (mystique->dwgreg.dr[8] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + b = (mystique->dwgreg.dr[12] >> 15) & 0xff; + dst = (r << 16) | (g << 8) | b; + + ((uint32_t *) svga->vram)[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = dst | (old_dst & 0xFF000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + r = (mystique->dwgreg.dr[4] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + g = (mystique->dwgreg.dr[8] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + b = (mystique->dwgreg.dr[12] >> 15) & 0xff; + dst = (r << 16) | (g << 8) | b; + + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("LINE I/ZI PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + } + + if (mystique->dwgreg.sgn.sdydxl) + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + + if (mystique->maccess_running & MACCESS_ZWIDTH) { + mystique->dwgreg.extended_dr[0] += mystique->dwgreg.extended_dr[2]; + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + } else { + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2]; + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull); + } + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14]; + + if (mystique->dwgreg.err >= 0) { + mystique->dwgreg.err += mystique->dwgreg.k2; + + if (mystique->dwgreg.sgn.sdydxl) + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + else + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + + if (mystique->maccess_running & MACCESS_ZWIDTH) { + mystique->dwgreg.extended_dr[0] += mystique->dwgreg.extended_dr[3]; + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + } else { + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[3]; + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull); + } + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[7]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[11]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[15]; + } else + mystique->dwgreg.err += mystique->dwgreg.k1; + + mystique->dwgreg.length--; + } + break; + + default: +#if 0 + pclog("Unknown atype %03x %08x LINE\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); +#endif + break; + } + + mystique->blitter_complete_refcount++; +} + +static void +blit_line_start(mystique_t *mystique, int closed, int autoline) +{ + int start_x = (int32_t) mystique->dwgreg.ar[5]; + int start_y = (int32_t) mystique->dwgreg.ar[6]; + int end_x = (int32_t) mystique->dwgreg.ar[0]; + int end_y = (int32_t) mystique->dwgreg.ar[2]; + int dx = end_x - start_x; + int dy = end_y - start_y; + + if (autoline) { + if (ABS(dx) > ABS(dy)) { + mystique->dwgreg.sgn.sdydxl = 1; + mystique->dwgreg.k1 = 2 * ABS(dy); + mystique->dwgreg.err = 2 * ABS(dy) - ABS(dx) - ((start_y > end_y) ? 1 : 0); + mystique->dwgreg.k2 = 2 * ABS(dy) - 2 * ABS(dx); + mystique->dwgreg.length = ABS(end_x - start_x); + } else { + mystique->dwgreg.sgn.sdydxl = 0; + mystique->dwgreg.k1 = 2 * ABS(dx); + mystique->dwgreg.err = 2 * ABS(dx) - ABS(dy) - ((start_y > end_y) ? 1 : 0); + mystique->dwgreg.k2 = 2 * ABS(dx) - 2 * ABS(dy); + mystique->dwgreg.length = ABS(end_y - start_y); + } + mystique->dwgreg.sgn.sdxl = (start_x > end_x) ? 1 : 0; + mystique->dwgreg.sgn.sdy = (start_y > end_y) ? 1 : 0; + } else { + mystique->dwgreg.k1 = (int32_t) mystique->dwgreg.ar[0]; + mystique->dwgreg.err = (int32_t) mystique->dwgreg.ar[1]; + mystique->dwgreg.k2 = (int32_t) mystique->dwgreg.ar[2]; + } + + blit_line(mystique, closed, autoline); + + if (autoline) { + mystique->dwgreg.ar[5] = end_x; + mystique->dwgreg.xdst = end_x; + mystique->dwgreg.ar[6] = end_y; + mystique->dwgreg.ydst = end_y; + mystique->dwgreg.ydst_lin = ((int32_t) (int16_t) mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + } +} + +static void +blit_trap(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint64_t z_back_32; + uint32_t z_back; + uint32_t r_back; + uint32_t g_back; + uint32_t b_back; + int z_write; + int y; + int err_l = (int32_t)mystique->dwgreg.ar[1]; + int err_r = (int32_t)mystique->dwgreg.ar[4]; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_BLK: + case DWGCTRL_ATYPE_RPL: + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int16_t x_l = mystique->dwgreg.fxleft & 0xffff; + int16_t x_r = mystique->dwgreg.fxright & 0xffff; + int yoff = (mystique->dwgreg.yoff + mystique->dwgreg.ydst) & 7; + int len; + + if (x_l > x_r) + len = x_l - x_r; + else + len = x_r - x_l; + + while (len > 0) { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x_l & 3]) { + int xoff = (mystique->dwgreg.xoff + (x_l & 7)) & 15; + int pattern = mystique->dwgreg.pattern[yoff][xoff]; + uint32_t dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = (pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xff; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = (pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffff; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + dst = *(uint32_t *) (&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) & 0xff000000; + *(uint32_t *) (&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) = ((pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffffff) | dst; + svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("TRAP BLK/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + len--; + x_l++; + } + + while ((err_l < 0) && mystique->dwgreg.ar[0]) { + err_l += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + err_l += mystique->dwgreg.ar[2]; + + while ((err_r < 0) && mystique->dwgreg.ar[6]) { + err_r += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + err_r += mystique->dwgreg.ar[5]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + case DWGCTRL_ATYPE_RSTR: + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int16_t x_l = mystique->dwgreg.fxleft & 0xffff; + int16_t x_r = mystique->dwgreg.fxright & 0xffff; + int yoff = (mystique->dwgreg.yoff + mystique->dwgreg.ydst) & 7; + int len; + + if (x_l > x_r) + len = x_l - x_r; + else + len = x_r - x_l; + + while (len > 0) { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x_l & 3]) { + int xoff = (mystique->dwgreg.xoff + (x_l & 7)) & 15; + int pattern = mystique->dwgreg.pattern[yoff][xoff]; + uint32_t src = pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + uint32_t dst; + uint32_t old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("TRAP RSTR PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + x_l++; + len--; + } + + while ((err_l < 0) && mystique->dwgreg.ar[0]) { + err_l += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + err_l += mystique->dwgreg.ar[2]; + + while ((err_r < 0) && mystique->dwgreg.ar[6]) { + err_r += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + err_r += mystique->dwgreg.ar[5]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + case DWGCTRL_ATYPE_I: + case DWGCTRL_ATYPE_ZI: + z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI); + + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint16_t *z_p = (uint16_t *) &svga->vram[(mystique->dwgreg.ydst_lin * ((mystique->maccess_running & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg) & mystique->vram_mask]; + int16_t x_l = mystique->dwgreg.fxleft & 0xffff; + int16_t x_r = mystique->dwgreg.fxright & 0xffff; + int16_t old_x_l = x_l; + int dx; + + z_back_32 = mystique->dwgreg.extended_dr[0]; + + z_back = mystique->dwgreg.dr[0]; + r_back = mystique->dwgreg.dr[4]; + g_back = mystique->dwgreg.dr[8]; + b_back = mystique->dwgreg.dr[12]; + + while (x_l != x_r) { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x_l & 3]) { + bool z_check_pass = false; + if (mystique->maccess_running & MACCESS_ZWIDTH) { + uint32_t z = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull); + uint32_t old_z = *(uint32_t*)&z_p[x_l * 2]; + z_check_pass = z_check_32(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK); + } else { + uint16_t z = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + uint16_t old_z = z_p[x_l]; + z_check_pass = z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK); + } + + if (z_check_pass) { + uint32_t dst = 0; + uint32_t old_dst; + int r = 0; + int g = 0; + int b = 0; + + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + r = (mystique->dwgreg.dr[4] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + g = (mystique->dwgreg.dr[8] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + b = (mystique->dwgreg.dr[12] >> 15) & 0xff; + + if (z_write) { + if (mystique->maccess_running & MACCESS_ZWIDTH) { + *(uint32_t*)(&z_p[x_l * 2]) = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull); + } + else + z_p[x_l] = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + } + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = dither(mystique, r, g, b, x_l & 1, mystique->dwgreg.selline & 1); + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *) (&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) & 0xff000000; + *(uint32_t *) (&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) = old_dst | dst; + svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = b | (g << 8) | (r << 16); + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("TRAP BLK/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + } + + if (mystique->maccess_running & MACCESS_ZWIDTH) { + mystique->dwgreg.extended_dr[0] += mystique->dwgreg.extended_dr[2]; + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + } else { + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2]; + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull); + } + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14]; + + if (x_l > x_r) + x_l--; + else + x_l++; + } + + if (mystique->maccess_running & MACCESS_ZWIDTH) { + mystique->dwgreg.extended_dr[0] = z_back_32 + mystique->dwgreg.extended_dr[3]; + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + } else { + mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3]; + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull); + } + mystique->dwgreg.dr[4] = r_back + mystique->dwgreg.dr[7]; + mystique->dwgreg.dr[8] = g_back + mystique->dwgreg.dr[11]; + mystique->dwgreg.dr[12] = b_back + mystique->dwgreg.dr[15]; + + while ((int32_t) mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + while ((int32_t) mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + dx = (int16_t) ((mystique->dwgreg.fxleft - old_x_l) & 0xffff); + if (mystique->maccess_running & MACCESS_ZWIDTH) { + mystique->dwgreg.extended_dr[0] += dx * mystique->dwgreg.extended_dr[2]; + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + } else { + mystique->dwgreg.dr[0] += dx * mystique->dwgreg.dr[2]; + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull); + } + mystique->dwgreg.dr[4] += dx * mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += dx * mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += dx * mystique->dwgreg.dr[14]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + default: +#if 0 + pclog("Unknown atype %03x %08x TRAP\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); +#endif + break; + } + + mystique->blitter_complete_refcount++; +} + +static uint16_t texture_texel_fetch(mystique_t *mystique, int *tex_r, int *tex_g, int *tex_b, int *tex_a, int *atransp, int s, int t, int tex_pitch) +{ + const unsigned int w_mask = (mystique->dwgreg.texwidth & TEXWIDTH_TWMASK_MASK) >> TEXWIDTH_TWMASK_SHIFT; + const unsigned int h_mask = (mystique->dwgreg.texheight & TEXHEIGHT_THMASK_MASK) >> TEXHEIGHT_THMASK_SHIFT; + const unsigned int palsel = mystique->dwgreg.texctl & TEXCTL_PALSEL_MASK; + svga_t* svga = &mystique->svga; + uint16_t src = 0x0; + + int atransp_dummy = 0; + + if (!atransp) + atransp = &atransp_dummy; + + if (mystique->dwgreg.texctl & TEXCTL_CLAMPU) { + if (s < 0) + s = 0; + else if (s > w_mask) + s = w_mask; + } else + s &= w_mask; + + if (mystique->dwgreg.texctl & TEXCTL_CLAMPV) { + if (t < 0) + t = 0; + else if (t > h_mask) + t = h_mask; + } else + t &= h_mask; + + switch (mystique->dwgreg.texctl & TEXCTL_TEXFORMAT_MASK) { + case TEXCTL_TEXFORMAT_TW4: + src = svga->vram[(mystique->dwgreg.texorg + (((t * tex_pitch) + s) >> 1)) & mystique->vram_mask]; + if (s & 1) + src >>= 4; + else + src &= 0xf; + *tex_r = mystique->lut[src | palsel].r; + *tex_g = mystique->lut[src | palsel].g; + *tex_b = mystique->lut[src | palsel].b; + *atransp = 0; + break; + case TEXCTL_TEXFORMAT_TW8: + src = svga->vram[(mystique->dwgreg.texorg + (t * tex_pitch) + s) & mystique->vram_mask]; + *tex_r = mystique->lut[src].r; + *tex_g = mystique->lut[src].g; + *tex_b = mystique->lut[src].b; + *atransp = 0; + break; + case TEXCTL_TEXFORMAT_TW15: + src = ((uint16_t *) svga->vram)[((mystique->dwgreg.texorg >> 1) + (t * tex_pitch) + s) & mystique->vram_mask_w]; + *tex_r = ((src >> 10) & 0x1f) << 3; + *tex_g = ((src >> 5) & 0x1f) << 3; + *tex_b = (src & 0x1f) << 3; + if (((src >> 15) & mystique->dwgreg.ta_mask) == mystique->dwgreg.ta_key) + *atransp = 1; + else + *atransp = 0; + break; + case TEXCTL_TEXFORMAT_TW12: + src = ((uint16_t *) svga->vram)[((mystique->dwgreg.texorg >> 1) + (t * tex_pitch) + s) & mystique->vram_mask_w]; + *tex_r = ((src >> 8) & 0xf) << 4; + *tex_g = ((src >> 4) & 0xf) << 4; + *tex_b = (src & 0xf) << 4; + *tex_a = ((src >> 12) & 0xf) << 4; + if (mystique->dwgreg.texctl & TEXCTL_AZEROEXTEND) { + *atransp = (((src >> 12) & 0xf) & mystique->dwgreg.ta_mask) == mystique->dwgreg.ta_key; + } else { + uint8_t ta_mask = mystique->dwgreg.ta_mask ? 0xf : 0x0; + uint8_t ta_key = mystique->dwgreg.ta_key ? 0xf : 0x0; + *atransp = (((src >> 12) & 0xf) & ta_mask) == ta_key; + } + break; + case TEXCTL_TEXFORMAT_TW16: + src = ((uint16_t *) svga->vram)[((mystique->dwgreg.texorg >> 1) + (t * tex_pitch) + s) & mystique->vram_mask_w]; + *tex_r = (src >> 11) << 3; + *tex_g = ((src >> 5) & 0x3f) << 2; + *tex_b = (src & 0x1f) << 3; + *atransp = 0; + break; + default: + fatal("Unknown texture format %i\n", mystique->dwgreg.texctl & TEXCTL_TEXFORMAT_MASK); + break; + } + return src; +} + +static double lerp(double v0, double v1, double t) { + return (1. - t) * v0 + t * v1; +} + +static int +texture_read(mystique_t *mystique, int *tex_r, int *tex_g, int *tex_b, int *atransp, int *tex_a) +{ + const int tex_shift = 3 + ((mystique->dwgreg.texctl & TEXCTL_TPITCH_MASK) >> TEXCTL_TPITCH_SHIFT); + const uint16_t tckey = mystique->dwgreg.textrans & TEXTRANS_TCKEY_MASK; + const uint16_t tkmask = (mystique->dwgreg.textrans & TEXTRANS_TKMASK_MASK) >> TEXTRANS_TKMASK_SHIFT; + const unsigned int w_mask = (mystique->dwgreg.texwidth & TEXWIDTH_TWMASK_MASK) >> TEXWIDTH_TWMASK_SHIFT; + const unsigned int h_mask = (mystique->dwgreg.texheight & TEXHEIGHT_THMASK_MASK) >> TEXHEIGHT_THMASK_SHIFT; + uint16_t src = 0; + int s; + int t; + int tex_pitch = 1 << tex_shift; + double s_frac = 0; + double t_frac = 0; + + *tex_a = 255; + + if (mystique->type >= MGA_G100 && (mystique->dwgreg.texctl & TEXCTL_TPITCHLIN)) + { + tex_pitch = (mystique->dwgreg.texctl & TEXCTL_TPITCHEXT_MASK) >> 9; + if (tex_pitch == 0) + tex_pitch = 2048; + } + + if (mystique->dwgreg.texctl & TEXCTL_NPCEN) { + const int s_shift = 20 - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK); + const int t_shift = 20 - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK); + + s = (int32_t) mystique->dwgreg.tmr[6] >> s_shift; + t = (int32_t) mystique->dwgreg.tmr[7] >> t_shift; + s_frac = (((int32_t) mystique->dwgreg.tmr[6]) & ((1 << s_shift) - 1)) / (double)(1 << s_shift); + t_frac = (((int32_t) mystique->dwgreg.tmr[7]) & ((1 << t_shift) - 1)) / (double)(1 << t_shift); + } else { + const int s_shift = (20 + 16) - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK); + const int t_shift = (20 + 16) - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK); + int64_t q = mystique->dwgreg.tmr[8] ? (0x100000000LL / (int64_t) (int32_t) mystique->dwgreg.tmr[8]) : 0; + + s = ((int64_t) (int32_t) mystique->dwgreg.tmr[6] * q) >> s_shift; + t = ((int64_t) (int32_t) mystique->dwgreg.tmr[7] * q) >> t_shift; + s_frac = (((int64_t) (int32_t) mystique->dwgreg.tmr[6] * q) & ((1 << s_shift) - 1)) / (double)(1 << s_shift); + t_frac = (((int64_t) (int32_t) mystique->dwgreg.tmr[7] * q) & ((1 << t_shift) - 1)) / (double)(1 << t_shift); + } + + if (mystique->dwgreg.texctl & TEXCTL_CLAMPU) { + if (s < 0) + s = 0; + else if (s > w_mask) + s = w_mask; + } else + s &= w_mask; + + if (mystique->dwgreg.texctl & TEXCTL_CLAMPV) { + if (t < 0) + t = 0; + else if (t > h_mask) + t = h_mask; + } else + t &= h_mask; + + src = texture_texel_fetch(mystique, tex_r, tex_g, tex_b, tex_a, atransp, s, t, tex_pitch); + switch (mystique->dwgreg.texfilter & 3) + { + case 0: + s_frac = t_frac = 0; + break; + case 1: + case 2: + break; + case 3: + s_frac = t_frac = .25; + break; + } + if (s_frac && s != w_mask) + { + int s_tex_r = 0, s_tex_g = 0, s_tex_b = 0, s_tex_a = 255; + texture_texel_fetch(mystique, &s_tex_r, &s_tex_g, &s_tex_b, &s_tex_a, NULL, s + 1, t, tex_pitch); + *tex_r = (int)lerp(*tex_r, s_tex_r, s_frac); + *tex_g = (int)lerp(*tex_g, s_tex_g, s_frac); + *tex_b = (int)lerp(*tex_b, s_tex_b, s_frac); + *tex_a = (int)lerp(*tex_a, s_tex_a, s_frac); + if (*tex_r > 255) *tex_r = 255; + if (*tex_g > 255) *tex_g = 255; + if (*tex_b > 255) *tex_b = 255; + if (*tex_a > 255) *tex_a = 255; + } + if (t_frac && t != h_mask) + { + int t_tex_r = 0, t_tex_g = 0, t_tex_b = 0, t_tex_a = 255; + texture_texel_fetch(mystique, &t_tex_r, &t_tex_g, &t_tex_b, &t_tex_a, NULL, s, t + 1, tex_pitch); + *tex_r = (int)lerp(*tex_r, t_tex_r, t_frac); + *tex_g = (int)lerp(*tex_g, t_tex_g, t_frac); + *tex_b = (int)lerp(*tex_b, t_tex_b, t_frac); + *tex_a = (int)lerp(*tex_a, t_tex_a, t_frac); + if (*tex_r > 255) *tex_r = 255; + if (*tex_g > 255) *tex_g = 255; + if (*tex_b > 255) *tex_b = 255; + if (*tex_a > 255) *tex_a = 255; + } + + return ((src & tkmask) == tckey); +} + +static void +blit_texture_trap(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + int y; + int z_write; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + const int dest32 = ((mystique->maccess_running & MACCESS_PWIDTH_MASK) == MACCESS_PWIDTH_32); + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_I: + case DWGCTRL_ATYPE_ZI: + z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI); + + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint16_t *z_p = (uint16_t *) &svga->vram[(mystique->dwgreg.ydst_lin * ((mystique->maccess_running & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg) & mystique->vram_mask]; + int16_t x_l = mystique->dwgreg.fxleft & 0xffff; + int16_t x_r = mystique->dwgreg.fxright & 0xffff; + int16_t old_x_l = x_l; + int dx; + + uint64_t z_back_32 = mystique->dwgreg.extended_dr[0]; + + uint32_t z_back = mystique->dwgreg.dr[0]; + uint32_t r_back = mystique->dwgreg.dr[4]; + uint32_t g_back = mystique->dwgreg.dr[8]; + uint32_t b_back = mystique->dwgreg.dr[12]; + uint32_t s_back = mystique->dwgreg.tmr[6]; + uint32_t t_back = mystique->dwgreg.tmr[7]; + uint32_t q_back = mystique->dwgreg.tmr[8]; + uint32_t a_back = mystique->dwgreg.alphastart; + uint32_t fog_back = mystique->dwgreg.fogstart; + + while (x_l != x_r) { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x_l & 3]) { + bool z_check_pass = false; + if (mystique->maccess_running & MACCESS_ZWIDTH) { + uint32_t z = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull); + uint32_t old_z = *(uint32_t*)&z_p[x_l * 2]; + z_check_pass = z_check_32(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK); + } else { + uint16_t z = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + uint16_t old_z = z_p[x_l]; + z_check_pass = z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK); + } + + if (z_check_pass) { + int tex_r = 0; + int tex_g = 0; + int tex_b = 0; + int tex_a = 255; + int ctransp; + int atransp = 0; + int i_r = 0; + int i_g = 0; + int i_b = 0; + int i_a = 255; + int i_fog = 0; + uint8_t final_a = 255; + + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + i_r = (mystique->dwgreg.dr[4] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + i_g = (mystique->dwgreg.dr[8] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + i_b = (mystique->dwgreg.dr[12] >> 15) & 0xff; + + if (mystique->type >= MGA_G100) + { + if (!(mystique->dwgreg.alphastart & (1 << 23))) + i_a = (mystique->dwgreg.alphastart >> 15) & 0xff; + else + i_a = 0; + + if (!(mystique->dwgreg.fogstart & (1 << 23))) + i_fog = (mystique->dwgreg.fogstart >> 15) & 0xff; + else + i_fog = 0; + } + + ctransp = texture_read(mystique, &tex_r, &tex_g, &tex_b, &atransp, &tex_a); + + if (mystique->type >= MGA_G100) + { + uint8_t alpha_sel = (mystique->dwgreg.alphactrl >> 24) & 3; + + switch (alpha_sel) + { + case 0x0: /* alpha from texture */ + final_a = tex_a; + break; + default: + case 0x1: /* interpolated alpha */ + if ((mystique->dwgreg.alphactrl & (1 << 11))) + final_a = i_a; + break; + case 0x2: /* modulated alpha */ + if (!(mystique->dwgreg.alphactrl & (1 << 11))) + final_a = tex_a; + else + final_a = ((i_a * tex_a) >> 8) & 0xFF; + break; + } + } + + switch (mystique->dwgreg.texctl & (TEXCTL_TMODULATE | TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY)) { + case 0: + if (ctransp) + goto skip_pixel; + if (atransp) { + tex_r = i_r; + tex_g = i_g; + tex_b = i_b; + } + break; + + case TEXCTL_DECALCKEY: + if (ctransp) { + tex_r = i_r; + tex_g = i_g; + tex_b = i_b; + } + break; + + case (TEXCTL_STRANS | TEXCTL_DECALCKEY): + if (ctransp) + goto skip_pixel; + break; + + case TEXCTL_TMODULATE: + if (ctransp) + goto skip_pixel; + if (mystique->dwgreg.texctl & TEXCTL_TMODULATE) { + tex_r = (tex_r * i_r) >> 8; + tex_g = (tex_g * i_g) >> 8; + tex_b = (tex_b * i_b) >> 8; + } + break; + + case (TEXCTL_TMODULATE | TEXCTL_STRANS): + if (ctransp || atransp) + goto skip_pixel; + if (mystique->dwgreg.texctl & TEXCTL_TMODULATE) { + tex_r = (tex_r * i_r) >> 8; + tex_g = (tex_g * i_g) >> 8; + tex_b = (tex_b * i_b) >> 8; + } + break; + + case (TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY): + if (!ctransp) + goto skip_pixel; + + tex_r = i_r; + tex_g = i_g; + tex_b = i_b; + break; + + default: + fatal("Bad TEXCTL %08x %08x\n", mystique->dwgreg.texctl, mystique->dwgreg.texctl & (TEXCTL_TMODULATE | TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY)); + } + + if (mystique->type >= MGA_G100 && (mystique->maccess_running & MACCESS_FOGEN)) + { + tex_r = (tex_r * ((i_fog) / 255.)) + (mystique->dwgreg.fogcol >> 16) * ((255 - i_fog) / 255.); + tex_g = (tex_g * ((i_fog) / 255.)) + ((mystique->dwgreg.fogcol >> 8) & 0xFF) * ((255 - i_fog) / 255.); + tex_b = (tex_b * ((i_fog) / 255.)) + ((mystique->dwgreg.fogcol) & 0xFF) * ((255 - i_fog) / 255.); + } + + if (final_a != 255) + { + { + double threshold = bayer_mat[mystique->dwgreg.selline & 3][x_l & 3]; + double final_a_frac = (final_a) / 255.; + if (final_a_frac >= threshold) { + final_a = 255; + } else { + goto skip_pixel; + } + } + } + + if (dest32) { + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = tex_b | (tex_g << 8) | (tex_r << 16); + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + } else { + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dither(mystique, tex_r, tex_g, tex_b, x_l & 1, mystique->dwgreg.selline & 1); + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + } + if (z_write) { + if (mystique->maccess_running & MACCESS_ZWIDTH) { + *(uint32_t*)(&z_p[x_l * 2]) = (mystique->dwgreg.extended_dr[0] & (1ull << 47ull)) ? 0 : (mystique->dwgreg.extended_dr[0] >> 15ull); + } + else + z_p[x_l] = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + } + } + } +skip_pixel: + if (x_l > x_r) + x_l--; + else + x_l++; + + if (mystique->maccess_running & MACCESS_ZWIDTH) { + mystique->dwgreg.extended_dr[0] += mystique->dwgreg.extended_dr[2]; + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + } else { + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2]; + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull); + } + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14]; + mystique->dwgreg.tmr[6] += mystique->dwgreg.tmr[0]; + mystique->dwgreg.tmr[7] += mystique->dwgreg.tmr[2]; + mystique->dwgreg.tmr[8] += mystique->dwgreg.tmr[4]; + mystique->dwgreg.fogstart += mystique->dwgreg.fogxinc; + mystique->dwgreg.alphastart += mystique->dwgreg.alphaxinc; + mystique->dwgreg.fogstart &= 0xFFFFFF; + mystique->dwgreg.alphastart &= 0xFFFFFF; + } + + if (mystique->maccess_running & MACCESS_ZWIDTH) { + mystique->dwgreg.extended_dr[0] = z_back_32 + mystique->dwgreg.extended_dr[3]; + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + } else { + mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3]; + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull); + } + mystique->dwgreg.dr[4] = r_back + mystique->dwgreg.dr[7]; + mystique->dwgreg.dr[8] = g_back + mystique->dwgreg.dr[11]; + mystique->dwgreg.dr[12] = b_back + mystique->dwgreg.dr[15]; + mystique->dwgreg.tmr[6] = s_back + mystique->dwgreg.tmr[1]; + mystique->dwgreg.tmr[7] = t_back + mystique->dwgreg.tmr[3]; + mystique->dwgreg.tmr[8] = q_back + mystique->dwgreg.tmr[5]; + mystique->dwgreg.fogstart = fog_back + mystique->dwgreg.fogyinc; + mystique->dwgreg.alphastart = a_back + mystique->dwgreg.alphayinc; + mystique->dwgreg.fogstart &= 0xFFFFFF; + mystique->dwgreg.alphastart &= 0xFFFFFF; + + while ((int32_t) mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + while ((int32_t) mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + dx = (int16_t) ((mystique->dwgreg.fxleft - old_x_l) & 0xffff); + if (mystique->maccess_running & MACCESS_ZWIDTH) { + mystique->dwgreg.extended_dr[0] += dx * mystique->dwgreg.extended_dr[2]; + mystique->dwgreg.dr[0] = (mystique->dwgreg.extended_dr[0] >> 16) & 0xFFFFFFFF; + } else { + mystique->dwgreg.dr[0] += dx * mystique->dwgreg.dr[2]; + mystique->dwgreg.extended_dr[0] = (mystique->dwgreg.extended_dr[0] & ~0xFFFFull) | ((uint64_t)mystique->dwgreg.dr[0] << 16ull); + } + mystique->dwgreg.dr[4] += dx * mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += dx * mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += dx * mystique->dwgreg.dr[14]; + mystique->dwgreg.tmr[6] += dx * mystique->dwgreg.tmr[0]; + mystique->dwgreg.tmr[7] += dx * mystique->dwgreg.tmr[2]; + mystique->dwgreg.tmr[8] += dx * mystique->dwgreg.tmr[4]; + mystique->dwgreg.fogstart += dx * mystique->dwgreg.fogxinc; + mystique->dwgreg.alphastart += dx * mystique->dwgreg.alphaxinc; + mystique->dwgreg.fogstart &= 0xFFFFFF; + mystique->dwgreg.alphastart &= 0xFFFFFF; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + default: + fatal("Unknown atype %03x %08x TEXTURE_TRAP\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + mystique->blitter_complete_refcount++; +} + +static void +blit_bitblt(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint32_t src_addr; + int y; + int x_dir = mystique->dwgreg.sgn.scanleft ? -1 : 1; + int16_t x_start = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxright : mystique->dwgreg.fxleft; + int16_t x_end = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxleft : mystique->dwgreg.fxright; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + uint32_t bltckey = mystique->dwgreg.fcol; + uint32_t bltcmsk = mystique->dwgreg.bcol; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + bltckey &= 0xff; + bltcmsk &= 0xff; + break; + case MACCESS_PWIDTH_16: + bltckey &= 0xffff; + bltcmsk &= 0xffff; + break; + } + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_BLK: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BMONOLEF: + case DWGCTRL_BLTMOD_BMONOWF: + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) { + int16_t x = x_start; + + while (1) { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) { + uint32_t byte_addr = (src_addr >> 3) & mystique->vram_mask; + int bit_offset = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) == DWGCTRL_BLTMOD_BMONOWF) ? (7 - (src_addr & 7)) : (src_addr & 7); + uint32_t old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) { + if (svga->vram[byte_addr] & (1 << bit_offset)) + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = mystique->dwgreg.fcol; + } else + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) { + if (svga->vram[byte_addr] & (1 << bit_offset)) + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = mystique->dwgreg.fcol; + } else + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) { + if (svga->vram[byte_addr] & (1 << bit_offset)) + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (old_dst & 0xff000000) | (mystique->dwgreg.fcol & 0xffffff); + } else + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (old_dst & 0xff000000) | (((svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffffff); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) { + if (svga->vram[byte_addr] & (1 << bit_offset)) + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = mystique->dwgreg.fcol; + } else + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 11] = changeframecount; + break; + + default: + fatal("BITBLT DWGCTRL_ATYPE_BLK unknown MACCESS %i\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + if (src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } else + src_addr += x_dir; + + if (x != x_end) { + if ((x > x_end) && (x_dir == 1)) + x--; + else if ((x < x_end) && (x_dir == -1)) + x++; + else + x += x_dir; + } else + break; + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + + default: + fatal("BITBLT BLK %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } + break; + + case DWGCTRL_ATYPE_RPL: + if (mystique->maccess_running & MACCESS_TLUTLOAD) { + src_addr = mystique->dwgreg.ar[3]; + + y = mystique->dwgreg.ydst; + + while (mystique->dwgreg.length) { + uint16_t src = ((uint16_t *) svga->vram)[src_addr & mystique->vram_mask_w]; + + mystique->lut[y & 0xff].r = (src >> 11) << 3; + mystique->lut[y & 0xff].g = ((src >> 5) & 0x3f) << 2; + mystique->lut[y & 0xff].b = (src & 0x1f) << 3; + src_addr++; + y++; + mystique->dwgreg.length--; + } + break; + } + case DWGCTRL_ATYPE_RSTR: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + /* TODO: This isn't exactly perfect. */ + case DWGCTRL_BLTMOD_BPLAN: + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) + fatal("BITBLT RPL/RSTR BPLAN with pattern\n"); + + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int16_t x = x_start; + + while (1) { + uint32_t byte_addr = src_addr & mystique->vram_mask; + + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && ((svga->vram[byte_addr] & 1) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && trans[x & 3]) { + uint32_t src = (svga->vram[byte_addr] & 1) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + uint32_t dst; + uint32_t old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); // & DWGCTRL_BOP_MASK + + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("BITBLT RPL BPLAN PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } else + src_addr += x_dir; + + if (x != x_end) { + if ((x > x_end) && (x_dir == 1)) + x--; + else if ((x < x_end) && (x_dir == -1)) + x++; + else + x += x_dir; + } else + break; + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + case DWGCTRL_BLTMOD_BMONOLEF: + case DWGCTRL_BLTMOD_BMONOWF: + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) + fatal("BITBLT RPL/RSTR BMONOLEF with pattern\n"); + + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int16_t x = x_start; + + while (1) { + uint32_t byte_addr = (src_addr >> 3) & mystique->vram_mask; + int bit_offset = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) == DWGCTRL_BLTMOD_BMONOWF) ? (7 - (src_addr & 7)) : (src_addr & 7); + + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && ((svga->vram[byte_addr] & (1 << bit_offset)) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && trans[x & 3]) { + uint32_t src = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + uint32_t dst; + uint32_t old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); // & DWGCTRL_BOP_MASK + + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("BITBLT RPL BMONOLEF PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } else + src_addr += x_dir; + + if (x != x_end) { + if ((x > x_end) && (x_dir == 1)) + x--; + else if ((x < x_end) && (x_dir == -1)) + x++; + else + x += x_dir; + } else + break; + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + + case DWGCTRL_BLTMOD_BFCOL: + case DWGCTRL_BLTMOD_BU32RGB: + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) { + uint8_t const *const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint32_t old_src_addr = src_addr; + int16_t x = x_start; + + while (1) { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && trans[x & 3]) { + uint32_t src; + uint32_t dst; + uint32_t old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) { + case MACCESS_PWIDTH_8: + src = svga->vram[src_addr & mystique->vram_mask]; + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + if (!((!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) || (src & bltcmsk) != bltckey))) + break; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + src = ((uint16_t *) svga->vram)[src_addr & mystique->vram_mask_w]; + dst = ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + if (!((!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) || (src & bltcmsk) != bltckey))) + break; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint16_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + src = *(uint32_t *) &svga->vram[(src_addr * 3) & mystique->vram_mask]; + old_dst = *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + if (!((!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) || (src & bltcmsk) != bltckey))) + break; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); + + *(uint32_t *) &svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + src = ((uint32_t *) svga->vram)[src_addr & mystique->vram_mask_l]; + dst = ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l]; + if (!((!(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) || (src & bltcmsk) != bltckey))) + break; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + + ((uint32_t *) svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("BITBLT RPL BFCOL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) + src_addr = ((src_addr + x_dir) & 7) | (src_addr & ~7); + else if (src_addr == mystique->dwgreg.ar[0]) { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } else + src_addr += x_dir; + + if (x != x_end) { + if ((x > x_end) && (x_dir == 1)) + x--; + else if ((x < x_end) && (x_dir == -1)) + x++; + else + x += x_dir; + } else + break; + } + + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) { + src_addr = old_src_addr; + if (mystique->dwgreg.sgn.sdy) + src_addr = ((src_addr - 32) & 0xe0) | (src_addr & ~0xe0); + else + src_addr = ((src_addr + 32) & 0xe0) | (src_addr & ~0xe0); + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + + default: + fatal("BITBLT DWGCTRL_ATYPE_RPL unknown BLTMOD %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + } + break; + + default: +#if 0 + pclog("Unknown BITBLT atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); +#endif + break; + } + + mystique->blitter_complete_refcount++; +} + +static void +blit_iload(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + case DWGCTRL_ATYPE_RSTR: + case DWGCTRL_ATYPE_BLK: +#if 0 + pclog("ILOAD BLTMOD DWGCTRL = %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); +#endif + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BFCOL: + case DWGCTRL_BLTMOD_BMONOLEF: + case DWGCTRL_BLTMOD_BMONOWF: + case DWGCTRL_BLTMOD_BU24RGB: + case DWGCTRL_BLTMOD_BU32RGB: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; +#if 0 + pclog("ILOAD busy\n"); +#endif + mystique->dwgreg.words = 0; + break; + + default: + fatal("ILOAD DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +static void +blit_idump(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + mystique->dwgreg.words = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.idump_end_of_line = 0; + mystique->busy = 1; +#if 0 + pclog("IDUMP ATYPE RPL busy\n"); +#endif + break; + + default: + fatal("Unknown IDUMP atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +static void +blit_iload_scale(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + /* pclog("ILOAD SCALE ATYPE RPL BLTMOD BUYUV busy\n"); */ + break; + + default: + fatal("ILOAD_SCALE DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD_SCALE atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +static void +blit_iload_high(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + case DWGCTRL_BLTMOD_BU32BGR: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + /* pclog("ILOAD HIGH ATYPE RPL BLTMOD BUYUV busy\n"); */ + break; + + default: + fatal("ILOAD_HIGH DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD_HIGH atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +static void +blit_iload_highv(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) { + case DWGCTRL_BLTMOD_BUYUV: + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + mystique->dwgreg.highv_line = 0; + mystique->dwgreg.lastpix_r = 0; + mystique->dwgreg.lastpix_g = 0; + mystique->dwgreg.lastpix_b = 0; + /* pclog("ILOAD HIGHV ATYPE RPL BLTMOD BUYUV busy\n"); */ + break; + + default: + fatal("ILOAD_HIGHV DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD_HIGHV atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +static void +mystique_start_blit(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + //uint64_t start_time = plat_timer_read(); + //uint64_t end_time; + + /*Make sure we don't get any artifacts.*/ + svga->chain2_write = 0; + svga->chain2_read = 0; + + mystique->dwgreg.dwgctrl_running = mystique->dwgreg.dwgctrl; + mystique->maccess_running = mystique->maccess; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) { + case DWGCTRL_OPCODE_LINE_OPEN: + blit_line_start(mystique, 0, 0); + break; + + case DWGCTRL_OPCODE_AUTOLINE_OPEN: + blit_line_start(mystique, 0, 1); + break; + + case DWGCTRL_OPCODE_LINE_CLOSE: + blit_line_start(mystique, 1, 0); + break; + + case DWGCTRL_OPCODE_AUTOLINE_CLOSE: + blit_line_start(mystique, 1, 1); + break; + + case DWGCTRL_OPCODE_TRAP: + blit_trap(mystique); + break; + + case DWGCTRL_OPCODE_TEXTURE_TRAP: + blit_texture_trap(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGH: + blit_iload_high(mystique); + break; + + case DWGCTRL_OPCODE_BITBLT: + blit_bitblt(mystique); + break; + + case DWGCTRL_OPCODE_FBITBLT: + blit_fbitblt(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD: + blit_iload(mystique); + break; + + case DWGCTRL_OPCODE_IDUMP: + blit_idump(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_SCALE: + blit_iload_scale(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGHV: + blit_iload_highv(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_FILTER: + /* TODO: Actually implement this. */ + break; + + default: + fatal("mystique_start_blit: unknown blit %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK); + break; + } + + //end_time = plat_timer_read(); + //mystique->blitter_time += end_time - start_time; +} + +static void +mystique_hwcursor_draw(svga_t *svga, int displine) +{ + const mystique_t *mystique = (mystique_t *) svga->priv; + uint64_t dat[2]; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; + + dat[0] = *(uint64_t *) (&svga->vram[svga->hwcursor_latch.addr]); + dat[1] = *(uint64_t *) (&svga->vram[svga->hwcursor_latch.addr + 8]); + svga->hwcursor_latch.addr += 16; + switch (mystique->xcurctrl & XCURCTRL_CURMODE_MASK) { + + case XCURCTRL_CURMODE_3COL: + for (uint8_t x = 0; x < 64; x++) { + int c = ((dat[0] & (1ULL << 63)) ? 1 : 0) | ((dat[1] & (1ULL << 63)) ? 2 : 0); + if (c) { + svga->monitor->target_buffer->line[displine][(offset + svga->x_add) & 2047] = mystique->cursor.col[c - 1]; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + break; + + case XCURCTRL_CURMODE_XGA: + for (uint8_t x = 0; x < 64; x++) { + if (!(dat[1] & (1ULL << 63))) + svga->monitor->target_buffer->line[displine][(offset + svga->x_add) & 2047] = (dat[0] & (1ULL << 63)) ? svga_lookup_lut_ram(svga, mystique->cursor.col[1]) : svga_lookup_lut_ram(svga, mystique->cursor.col[0]); + else if (dat[0] & (1ULL << 63)) + svga->monitor->target_buffer->line[displine][(offset + svga->x_add) & 2047] ^= 0xffffff; + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + break; + + case XCURCTRL_CURMODE_XWIN: + for (uint8_t x = 0; x < 64; x++) { + if ((dat[1] & (1ULL << 63))) + svga->monitor->target_buffer->line[displine][(offset + svga->x_add) & 2047] = (dat[0] & (1ULL << 63)) ? (mystique->cursor.col[1]) : (mystique->cursor.col[0]); + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + break; + + default: + break; + } + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + +static uint8_t +mystique_tvp3026_gpio_read(uint8_t cntl, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + uint8_t ret = 0xff; +#if 0 + if (!i2c_gpio_get_scl(mystique->i2c_ddc)) + ret &= ~0x10; + if (!i2c_gpio_get_sda(mystique->i2c_ddc)) + ret &= ~0x04; +#endif + return ret; +} + +static void +mystique_tvp3026_gpio_write(uint8_t cntl, uint8_t data, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + +#if 0 + i2c_gpio_set(mystique->i2c_ddc, !(cntl & 0x10) || (data & 0x10), !(cntl & 0x04) || (data & 0x04)); +#endif +} + +static uint8_t +mystique_pci_read(UNUSED(int func), int addr, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + uint8_t ret = 0x00; + + if ((addr >= 0x30) && (addr <= 0x33) && !(mystique->pci_regs[0x43] & 0x40)) + ret = 0x00; + else + switch (addr) { + case 0x00: + ret = 0x2b; + break; /*Matrox*/ + case 0x01: + ret = 0x10; + break; + + case 0x02: + if (mystique->type == MGA_G100) + ret = 0x01; + else + ret = (mystique->type == MGA_2164W) ? 0x1b : ((mystique->type == MGA_2064W) ? 0x19 : 0x1a); + break; /*MGA*/ + case 0x03: + if (mystique->type == MGA_G100) + ret = 0x10; + else + ret = 0x05; + break; + + case PCI_REG_COMMAND: + ret = mystique->pci_regs[PCI_REG_COMMAND] | 0x80; + break; /*Respond to IO and memory accesses*/ + case 0x05: + ret = 0x00; + break; + + case 0x06: + ret = 0x80; + break; + case 0x07: + ret = mystique->pci_regs[0x07]; + break; /*Fast DEVSEL timing*/ + + case 0x08: + ret = (mystique->type == MGA_1164SG) ? 3 : 0; + break; /*Revision ID*/ + case 0x09: + ret = 0; + break; /*Programming interface*/ + + case 0x0a: + ret = 0x00; + break; /*Supports VGA interface*/ + case 0x0b: + ret = 0x03; + break; + + case 0x10: + ret = 0x00; + break; /*Control aperture for Millennium and Mystique, LFB for Mystique 220 and later*/ + case 0x11: + if (mystique->type >= MGA_1164SG) + ret = 0x00; + else + ret = (mystique->ctrl_base >> 8) & 0xc0; + break; + case 0x12: + if (mystique->type >= MGA_1164SG) + ret = (mystique->type >= MGA_2164W) ? 0x00 : ((mystique->lfb_base >> 16) & 0x80); + else + ret = mystique->ctrl_base >> 16; + break; + case 0x13: + if (mystique->type >= MGA_1164SG) + ret = mystique->lfb_base >> 24; + else + ret = mystique->ctrl_base >> 24; + break; + + case 0x14: + ret = 0x00; + break; /*LFB for Millennium and Mystique, Control aperture for Mystique 220 and later*/ + case 0x15: + if (mystique->type >= MGA_1164SG) + ret = (mystique->ctrl_base >> 8) & 0xc0; + else + ret = 0x00; + break; + case 0x16: + if (mystique->type >= MGA_1164SG) + ret = mystique->ctrl_base >> 16; + else + ret = (mystique->lfb_base >> 16) & 0x80; + break; + case 0x17: + if (mystique->type >= MGA_1164SG) + ret = mystique->ctrl_base >> 24; + else + ret = mystique->lfb_base >> 24; + break; + + case 0x18: + ret = 0x00; + break; /*Pseudo-DMA (ILOAD)*/ + case 0x1a: + ret = (mystique->iload_base >> 16) & 0x80; + break; + case 0x1b: + ret = mystique->iload_base >> 24; + break; + + case 0x2c: + ret = mystique->pci_regs[0x2c]; + break; + case 0x2d: + ret = mystique->pci_regs[0x2d]; + break; + case 0x2e: + ret = mystique->pci_regs[0x2e]; + break; + case 0x2f: + ret = mystique->pci_regs[0x2f]; + break; + + case 0x30: + ret = mystique->pci_regs[0x30] & 0x01; + break; /*BIOS ROM address*/ + case 0x31: + ret = 0x00; + break; + case 0x32: + ret = mystique->pci_regs[0x32]; + break; + case 0x33: + ret = mystique->pci_regs[0x33]; + break; + + case 0x34: + ret = (mystique->type == MGA_G100) ? 0xdc : 0x00; + break; + + case 0x3c: + ret = mystique->int_line; + break; + case 0x3d: + ret = PCI_INTA; + break; + + case 0x40: + ret = mystique->pci_regs[0x40]; + break; + case 0x41: + ret = mystique->pci_regs[0x41]; + break; + case 0x42: + ret = mystique->pci_regs[0x42]; + break; + case 0x43: + ret = mystique->pci_regs[0x43]; + break; + + case 0x44: + ret = mystique->pci_regs[0x44]; + break; + case 0x45: + ret = mystique->pci_regs[0x45]; + break; + + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + addr = (mystique->pci_regs[0x44] & 0xfc) | ((mystique->pci_regs[0x45] & 0x3f) << 8) | (addr & 3); + ret = mystique_ctrl_read_bx(addr, mystique); + break; + + case 0xdc: + ret = 0x01; + break; + + case 0xdd: + ret = 0xf0; + break; + + case 0xde: + ret = 0x21; + break; + + /* No support for turning off the video adapter yet. */ + case 0xe0: + ret = 0x0; + break; + + case 0xf0: + ret = 0x02; + break; + + case 0xf1: + ret = 0x00; + break; + + case 0xf2: + ret = 0x10; + break; + + case 0xf4: + ret = 0x1; + break; + + case 0xf5: + ret = 0x2; + break; + + case 0xf7: + ret = 0x1; + break; + + case 0xf8: + ret = mystique->pci_regs[0xf8] & 0x7; + break; + + case 0xf9: + ret = mystique->pci_regs[0xf9] & 0x3; + break; + + case 0xfb: + ret = mystique->pci_regs[0xfb]; + break; + + default: + break; + } + + return ret; +} + +static void +mystique_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + switch (addr) { + case PCI_REG_COMMAND: + mystique->pci_regs[PCI_REG_COMMAND] = (val & 0x27) | 0x80; + mystique_recalc_mapping(mystique); + break; + + case 0x07: + mystique->pci_regs[0x07] &= ~(val & 0x38); + break; + + case 0x0d: + mystique->pci_regs[0x0d] = val; + break; + + case 0x11: + if (mystique->type >= MGA_1164SG) + break; + else { + mystique->ctrl_base = (mystique->ctrl_base & 0xffff0000) | ((val & 0xc0) << 8); + mystique_recalc_mapping(mystique); + } + break; + case 0x12: + if (mystique->type >= MGA_1164SG) { + if (mystique->type >= MGA_2164W) + break; + mystique->lfb_base = (mystique->lfb_base & 0xff000000) | ((val & 0x80) << 16); + mystique_recalc_mapping(mystique); + } else { + mystique->ctrl_base = (mystique->ctrl_base & 0xff00c000) | (val << 16); + mystique_recalc_mapping(mystique); + } + break; + case 0x13: + if (mystique->type >= MGA_1164SG) { + if (mystique->type >= MGA_2164W) + mystique->lfb_base = val << 24; + else + mystique->lfb_base = (mystique->lfb_base & 0x00800000) | (val << 24); + + mystique_recalc_mapping(mystique); + } else { + mystique->ctrl_base = (mystique->ctrl_base & 0x00ffc000) | (val << 24); + mystique_recalc_mapping(mystique); + } + break; + + case 0x15: + if (mystique->type >= MGA_1164SG) { + mystique->ctrl_base = (mystique->ctrl_base & 0xffff0000) | ((val & 0xc0) << 8); + mystique_recalc_mapping(mystique); + } + break; + case 0x16: + if (mystique->type >= MGA_1164SG) { + mystique->ctrl_base = (mystique->ctrl_base & 0xff00c000) | (val << 16); + mystique_recalc_mapping(mystique); + } else { + mystique->lfb_base = (mystique->lfb_base & 0xff000000) | ((val & 0x80) << 16); + mystique_recalc_mapping(mystique); + } + break; + case 0x17: + if (mystique->type >= MGA_1164SG) { + mystique->ctrl_base = (mystique->ctrl_base & 0x00ffc000) | (val << 24); + mystique_recalc_mapping(mystique); + } else { + mystique->lfb_base = (mystique->lfb_base & 0x00800000) | (val << 24); + mystique_recalc_mapping(mystique); + } + break; + + case 0x1a: + mystique->iload_base = (mystique->iload_base & 0xff000000) | ((val & 0x80) << 16); + mystique_recalc_mapping(mystique); + break; + case 0x1b: + mystique->iload_base = (mystique->iload_base & 0x00800000) | (val << 24); + mystique_recalc_mapping(mystique); + break; + + case 0x30: + case 0x32: + case 0x33: + if (!(mystique->pci_regs[0x43] & 0x40)) + return; + mystique->pci_regs[addr] = val; + if (addr == 0x30) + mystique->pci_regs[addr] &= 1; + if (mystique->pci_regs[0x30] & 0x01) { + uint32_t biosaddr = (mystique->pci_regs[0x32] << 16) | (mystique->pci_regs[0x33] << 24); + mem_mapping_set_addrx(&mystique->bios_rom.mapping, biosaddr, (mystique->type == MGA_G100) ? 0x10000 : 0x8000); + } else + mem_mapping_disablex(&mystique->bios_rom.mapping); + return; + + case 0x3c: + mystique->int_line = val; + return; + + case 0x40: + mystique->pci_regs[addr] = val & 0x3f; + break; + case 0x41: + mystique->pci_regs[addr] = val; + break; + case 0x42: + mystique->pci_regs[addr] = val & 0x1f; + break; + case 0x43: + mystique->pci_regs[addr] = val; + //pclog("%08x\n", (mystique->pci_regs[0x40] << 0) | (mystique->pci_regs[0x41] << 8) | (mystique->pci_regs[0x42] << 16) | (mystique->pci_regs[0x43] << 24)); + if (addr == 0x43) { + if (val & 0x40) { + if (mystique->pci_regs[0x30] & 0x01) { + uint32_t biosaddr = (mystique->pci_regs[0x32] << 16) | (mystique->pci_regs[0x33] << 24); + mem_mapping_set_addrx(&mystique->bios_rom.mapping, biosaddr, (mystique->type == MGA_G100) ? 0x10000 : 0x8000); + } else + mem_mapping_disablex(&mystique->bios_rom.mapping); + } else + mem_mapping_set_addrx(&mystique->bios_rom.mapping, 0x000c0000, (mystique->type == MGA_G100) ? 0x10000 : 0x8000); + } + break; + + case 0x4c: + case 0x4d: + case 0x4e: + case 0x4f: + mystique->pci_regs[addr - 0x20] = val; + break; + + case 0x44: + mystique->pci_regs[addr] = val & 0xfc; + break; + case 0x45: + mystique->pci_regs[addr] = val & 0x3f; + break; + + case 0x48: + case 0x49: + case 0x4a: + case 0x4b: + addr = (mystique->pci_regs[0x44] & 0xfc) | ((mystique->pci_regs[0x45] & 0x3f) << 8) | (addr & 3); +#if 0 + pclog("mystique_ctrl_write_bx(%04X, %02X)\n", addr, val); +#endif + mystique_ctrl_write_bx(addr, val, mystique); + break; + + case 0xf8: + mystique->pci_regs[0xf8] = val & 0x7; + break; + + case 0xf9: + mystique->pci_regs[0xf9] = val & 0x3; + break; + + case 0xfb: + mystique->pci_regs[0xfb] = val; + break; + + default: + break; + } +} + +static uint32_t +mystique_conv_16to32(svga_t* svga, uint16_t color, uint8_t bpp) +{ + mystique_t *mystique = (mystique_t*)svga->priv; + uint32_t ret = 0x00000000; + + if (svga->lut_map) { + if (bpp == 15) { + if (mystique->xgenctrl & (1 << 2)) + color &= 0x7FFF; +#if 0 + uint8_t b = getcolr(svga->pallook[(color & 0x1F) | (!!(color & 0x8000) >> 8)]); + uint8_t g = getcolg(svga->pallook[((color & 0x3E0) >> 5) | (!!(color & 0x8000) >> 8)]); + uint8_t r = getcolb(svga->pallook[((color & 0x7C00) >> 10) | (!!(color & 0x8000) >> 8)]); +#else + uint8_t b = getcolr(svga->pallook[color & 0x1f]); + uint8_t g = getcolg(svga->pallook[(color & 0x3e0) >> 5]); + uint8_t r = getcolb(svga->pallook[(color & 0x7c00) >> 10]); +#endif + ret = (video_15to32[color] & 0xFF000000) | makecol(r, g, b); + } else { + uint8_t b = getcolr(svga->pallook[color & 0x1f]); + uint8_t g = getcolg(svga->pallook[(color & 0x7e0) >> 5]); + uint8_t r = getcolb(svga->pallook[(color & 0xf800) >> 11]); + ret = (video_16to32[color] & 0xFF000000) | makecol(r, g, b); + } + } else + ret = (bpp == 15) ? video_15to32[color] : video_16to32[color]; + + return ret; +} + +static void * +mystique_init(const device_t *info) +{ + mystique_t *mystique = (mystique_t*)malloc(sizeof(mystique_t)); + const char *romfn = NULL; + + memset(mystique, 0, sizeof(mystique_t)); + + mystique->type = info->local; + + if (mystique->type == MGA_2064W) + romfn = ROM_MILLENNIUM; + else if (mystique->type == MGA_2164W) + romfn = ROM_MILLENNIUM_II; + else if (mystique->type == MGA_1064SG) + romfn = ROM_MYSTIQUE; + else if (mystique->type == MGA_G100) + romfn = ROM_G100; + else + romfn = ROM_MYSTIQUE_220; + + if (mystique->type == MGA_G100) + rom_init(&mystique->bios_rom, romfn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + else + rom_init(&mystique->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disablex(&mystique->bios_rom.mapping); + + mystique->vram_size = device_get_config_int("memory"); + mystique->vram_mask = (mystique->vram_size << 20) - 1; + mystique->vram_mask_w = mystique->vram_mask >> 1; + mystique->vram_mask_l = mystique->vram_mask >> 2; + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique); + + if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) { + mystique->svga.dac_hwcursor_draw = tvp3026_hwcursor_draw; + mystique->svga.ramdac = device_add(&tvp3026_ramdac_device); + mystique->svga.clock_gen = mystique->svga.ramdac; + mystique->svga.getclock = tvp3026_getclock; + mystique->svga.conv_16to32 = tvp3026_conv_16to32; + if (mystique->type == MGA_2164W) + mystique->svga.decode_mask = 0xffffff; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, (mystique->type == MGA_2164W) ? &timing_matrox_mystique : &timing_matrox_millennium); + svga_init(info, &mystique->svga, mystique, mystique->vram_size << 20, + mystique_recalctimings, + mystique_in, mystique_out, + NULL, + NULL); + tvp3026_gpio(mystique_tvp3026_gpio_read, mystique_tvp3026_gpio_write, mystique, mystique->svga.ramdac); + } else { + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique); + mystique->svga.clock_gen = mystique; + mystique->svga.getclock = mystique_getclock; + if (mystique->type == MGA_G100) + mystique->svga.decode_mask = 0xffffff; + svga_init(info, &mystique->svga, mystique, mystique->vram_size << 20, + mystique_recalctimings, + mystique_in, mystique_out, + mystique_hwcursor_draw, + NULL); + } + + io_sethandler(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); + mem_mapping_addx(&mystique->ctrl_mapping, 0, 0, + mystique_ctrl_read_b, mystique_ctrl_read_w, mystique_ctrl_read_l, + mystique_ctrl_write_b, mystique_ctrl_write_w, mystique_ctrl_write_l, + NULL, 0, mystique); + mem_mapping_disablex(&mystique->ctrl_mapping); + + mem_mapping_addx(&mystique->lfb_mapping, 0, 0, + mystique_readb_linear, mystique_readw_linear, mystique_readl_linear, + mystique_writeb_linear, mystique_writew_linear, mystique_writel_linear, + NULL, 0, &mystique->svga); + mem_mapping_disablex(&mystique->lfb_mapping); + + mem_mapping_addx(&mystique->iload_mapping, 0, 0, + mystique_iload_read_b, NULL, mystique_iload_read_l, + mystique_iload_write_b, NULL, mystique_iload_write_l, + NULL, 0, mystique); + mem_mapping_disablex(&mystique->iload_mapping); + + if (romfn == NULL) + pci_add_card(PCI_ADD_VIDEO, mystique_pci_read, mystique_pci_write, mystique, &mystique->pci_slot); + else + pci_add_card((info->flags & DEVICE_AGP) ? PCI_ADD_AGP : PCI_ADD_NORMAL, mystique_pci_read, mystique_pci_write, mystique, &mystique->pci_slot); + mystique->pci_regs[0x06] = 0x80; + mystique->pci_regs[0x07] = 0 << 1; +#if 0 + mystique->pci_regs[0x2c] = mystique->bios_rom.rom[0x7ff8]; + mystique->pci_regs[0x2d] = mystique->bios_rom.rom[0x7ff9]; + mystique->pci_regs[0x2e] = mystique->bios_rom.rom[0x7ffa]; + mystique->pci_regs[0x2f] = mystique->bios_rom.rom[0x7ffb]; +#endif + mystique->svga.miscout = 1; + mystique->pci_regs[0x41] = 0x01; /* vgaboot = 1 */ + mystique->pci_regs[0x43] = 0x40; /* biosen = 1 */ + + for (uint16_t c = 0; c < 256; c++) { + dither5[c][0][0] = c >> 3; + dither5[c][1][1] = (c + 2) >> 3; + dither5[c][1][0] = (c + 4) >> 3; + dither5[c][0][1] = (c + 6) >> 3; + + if (dither5[c][1][1] > 31) + dither5[c][1][1] = 31; + if (dither5[c][1][0] > 31) + dither5[c][1][0] = 31; + if (dither5[c][0][1] > 31) + dither5[c][0][1] = 31; + + dither6[c][0][0] = c >> 2; + dither6[c][1][1] = (c + 1) >> 2; + dither6[c][1][0] = (c + 2) >> 2; + dither6[c][0][1] = (c + 3) >> 2; + + if (dither6[c][1][1] > 63) + dither6[c][1][1] = 63; + if (dither6[c][1][0] > 63) + dither6[c][1][0] = 63; + if (dither6[c][0][1] > 63) + dither6[c][0][1] = 63; + } + + mystique->wake_fifo_thread = thread_create_event(); + mystique->fifo_not_full_event = thread_create_event(); + mystique->thread_run = 1; + mystique->fifo_thread = thread_create(fifo_thread, mystique); + mystique->dma.lock = thread_create_mutex(); + + timer_addx(&mystique->wake_timer, mystique_wake_timer, (void *) mystique, 0); + timer_addx(&mystique->softrap_pending_timer, mystique_softrap_pending_timer, (void *) mystique, 1); + + mystique->status = STATUS_ENDPRDMASTS; + + mystique->softrap_status_read = 1; + + mystique->svga.vsync_callback = mystique_vsync_callback; + + if (mystique->type != MGA_2064W && mystique->type != MGA_2164W) + mystique->svga.conv_16to32 = mystique_conv_16to32; + +#if 0 + mystique->i2c = i2c_gpio_init("i2c_mga"); + mystique->i2c_ddc = i2c_gpio_init("ddc_mga"); + mystique->ddc = ddc_init(i2c_gpio_get_bus(mystique->i2c_ddc)); +#endif + return mystique; +} + +static void +mystique_close(void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + mystique->thread_run = 0; + thread_set_event(mystique->wake_fifo_thread); + thread_wait(mystique->fifo_thread); + thread_destroy_event(mystique->wake_fifo_thread); + thread_destroy_event(mystique->fifo_not_full_event); + thread_close_mutex(mystique->dma.lock); + + svga_close(&mystique->svga); + +#if 0 + ddc_close(mystique->ddc); + i2c_gpio_close(mystique->i2c_ddc); + i2c_gpio_close(mystique->i2c); +#endif + free(mystique); +} + +static int +millennium_available(void) +{ + return rom_present(ROM_MILLENNIUM); +} + +static int +mystique_available(void) +{ + return rom_present(ROM_MYSTIQUE); +} + +static int +mystique_220_available(void) +{ + return rom_present(ROM_MYSTIQUE_220); +} + +static int +millennium_ii_available(void) +{ + return rom_present(ROM_MILLENNIUM_II); +} + +#ifdef USE_G100 +static int +matrox_g100_available(void) +{ + return rom_present(ROM_G100); +} +#endif + +static void +mystique_speed_changed(void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + svga_recalctimings(&mystique->svga); +} + +static void +mystique_force_redraw(void *priv) +{ + mystique_t *mystique = (mystique_t *) priv; + + mystique->svga.fullchange = changeframecount; +} + +#if 0 + +static const device_config_t mystique_config[] = { + // clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { .description = "" } + }, + .default_int = 8 + }, + { .type = CONFIG_END } + // clang-format on +}; + +static const device_config_t millennium_ii_config[] = { + // clang-format off + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = { + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "16 MB", + .value = 16 + }, + { .description = "" } + }, + .default_int = 8 + }, + { .type = CONFIG_END } + // clang-format on +}; +#endif + +const device_t millennium_device = { + .name = "Matrox Millennium", + .internal_name = "millennium", + .flags = DEVICE_PCI, + .local = MGA_2064W, + .init = mystique_init, + .close = mystique_close, + .reset = NULL, + .available = millennium_available, + .speed_changed = mystique_speed_changed, + .force_redraw = mystique_force_redraw, + //.config = mystique_config +}; + +const device_t mystique_device = { + .name = "Matrox Mystique", + .internal_name = "mystique", + .flags = DEVICE_PCI, + .local = MGA_1064SG, + .init = mystique_init, + .close = mystique_close, + .reset = NULL, + .available = mystique_available, + .speed_changed = mystique_speed_changed, + .force_redraw = mystique_force_redraw, + //.config = mystique_config +}; + +const device_t mystique_220_device = { + .name = "Matrox Mystique 220", + .internal_name = "mystique_220", + .flags = DEVICE_PCI, + .local = MGA_1164SG, + .init = mystique_init, + .close = mystique_close, + .reset = NULL, + .available = mystique_220_available, + .speed_changed = mystique_speed_changed, + .force_redraw = mystique_force_redraw, + //.config = mystique_config +}; + +const device_t millennium_ii_device = { + .name = "Matrox Millennium II", + .internal_name = "millennium_ii", + .flags = DEVICE_PCI, + .local = MGA_2164W, + .init = mystique_init, + .close = mystique_close, + .reset = NULL, + .available = millennium_ii_available, + .speed_changed = mystique_speed_changed, + .force_redraw = mystique_force_redraw, + //.config = millennium_ii_config +}; + +#ifdef USE_G100 +const device_t productiva_g100_device = { + .name = "Matrox Productiva G100", + .internal_name = "productiva_g100", + .flags = DEVICE_AGP, + .local = MGA_G100, + .init = mystique_init, + .close = mystique_close, + .reset = NULL, + .available = matrox_g100_available, + .speed_changed = mystique_speed_changed, + .force_redraw = mystique_force_redraw, + //.config = millennium_ii_config +}; +#endif + +#endif \ No newline at end of file diff --git a/pcem/vid_ncr.cpp b/pcem/vid_ncr.cpp index 854ef5e9..32ee860c 100644 --- a/pcem/vid_ncr.cpp +++ b/pcem/vid_ncr.cpp @@ -86,14 +86,14 @@ static int ncr_vga_vsync_enabled(ncr_t *ncr) static void ncr_update_irqs(ncr_t *ncr) { if (ncr->vblank_irq > 0 && ncr_vga_vsync_enabled(ncr)) - pci_set_irq(NULL, PCI_INTA); + pci_set_irq(NULL, PCI_INTA, NULL); else - pci_clear_irq(NULL, PCI_INTA); + pci_clear_irq(NULL, PCI_INTA, NULL); } static void ncr_vblank_start(svga_t *svga) { - ncr_t *ncr = (ncr_t *)svga->p; + ncr_t *ncr = (ncr_t *)svga->priv; if (ncr->vblank_irq >= 0) { ncr->vblank_irq = 1; ncr_update_irqs(ncr); @@ -103,7 +103,7 @@ static void ncr_vblank_start(svga_t *svga) void ncr_hwcursor_draw(svga_t *svga, int displine) { - ncr_t *ncr = (ncr_t*)svga->p; + ncr_t *ncr = (ncr_t*)svga->priv; int x; uint8_t dat[2]; uint32_t c[2]; @@ -138,7 +138,7 @@ void ncr_hwcursor_draw(svga_t *svga, int displine) if ((svga->bpp == 16 || svga->bpp == 15) && svga->hwcursor.h_acc > 0) { xdbl = 1 << (svga->hwcursor.h_acc - 1); } - for (x = 0; x < svga->hwcursor.xsize; x += 8) + for (x = 0; x < svga->hwcursor.cur_xsize; x += 8) { if (x == 32) { addr += (64 / 8); @@ -146,7 +146,7 @@ void ncr_hwcursor_draw(svga_t *svga, int displine) addr--; uint32_t addroffset = addr & svga->vram_display_mask; dat[0] = svga->vram[addroffset]; - addroffset = (addr + (svga->hwcursor.xsize / 8)) & svga->vram_display_mask; + addroffset = (addr + (svga->hwcursor.cur_xsize / 8)) & svga->vram_display_mask; dat[1] = svga->vram[addroffset]; for (xx = 0; xx < 8; xx++) { @@ -166,7 +166,7 @@ void ncr_hwcursor_draw(svga_t *svga, int displine) dat[1] <<= 1; } } - svga->hwcursor_latch.addr += (svga->hwcursor.xsize / 8) * 2; + svga->hwcursor_latch.addr += (svga->hwcursor.cur_xsize / 8) * 2; if (svga->interlace && !svga->hwcursor_oddeven) svga->hwcursor_latch.addr += line_offset; @@ -213,8 +213,8 @@ void ncr_out(uint16_t addr, uint8_t val, void *p) case 0x0c: svga->hwcursor.ena = val & 1; svga->hwcursor.h_acc = (val >> 5) & 3; - svga->hwcursor.ysize = 16 << ((val >> 1) & 3); - svga->hwcursor.xsize = (val & 0x80) && ncr->chip == NCR_TYPE_32BLT ? 64 : 32; + svga->hwcursor.cur_ysize = 16 << ((val >> 1) & 3); + svga->hwcursor.cur_xsize = (val & 0x80) && ncr->chip == NCR_TYPE_32BLT ? 64 : 32; break; case 0x0d: case 0x0e: @@ -359,7 +359,7 @@ static const int fontwidths[] = void ncr_recalctimings(svga_t *svga) { - ncr_t *ncr = (ncr_t*)svga->p; + ncr_t *ncr = (ncr_t*)svga->priv; bool ext_end = (svga->crtc[0x30] & 0x20) != 0; svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5); @@ -958,19 +958,19 @@ static uint32_t ncr_mmio_readl(uint32_t addr, void *p) static void ncr_write_linear(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; - ncr_t *ncr = (ncr_t *)svga->p; + ncr_t *ncr = (ncr_t *)svga->priv; svga_write_linear(addr, val, p); } static void ncr_writew_linear(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t *)p; - ncr_t *ncr = (ncr_t *)svga->p; + ncr_t *ncr = (ncr_t *)svga->priv; svga_writew_linear(addr, val, p); } static void ncr_writel_linear(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t *)p; - ncr_t *ncr = (ncr_t *)svga->p; + ncr_t *ncr = (ncr_t *)svga->priv; if (ncr->blt_fifo_write > 0) { blitter_write_fifo(ncr, val); return; @@ -1112,7 +1112,7 @@ static void *ncr_init(char *bios_fn, int chip) rom_init(&ncr->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - svga_init(&ncr->svga, ncr, vram_size, + svga_init(NULL, &ncr->svga, ncr, vram_size, ncr_recalctimings, ncr_in, ncr_out, ncr_hwcursor_draw, @@ -1159,7 +1159,7 @@ static void *ncr_init(char *bios_fn, int chip) return ncr; } -void *ncr_retina_z2_init() +void *ncr_retina_z2_init(const device_t *info) { ncr_t *ncr = (ncr_t *)ncr_init("ncr.bin", NCR_TYPE_22EP); @@ -1173,7 +1173,7 @@ void *ncr_retina_z2_init() return ncr; } -void *ncr_retina_z3_init() +void *ncr_retina_z3_init(const device_t *info) { ncr_t *ncr = (ncr_t *)ncr_init("ncr.bin", NCR_TYPE_32BLT); @@ -1229,26 +1229,24 @@ void ncr_add_status_info(char *s, int max_len, void *p) device_t ncr_retina_z2_device = { - "NCR 77C22E+", - 0, + "NCR 77C22E+", NULL, + 0, 0, ncr_retina_z2_init, ncr_close, NULL, + NULL, ncr_speed_changed, ncr_force_redraw, - ncr_add_status_info, - NULL }; device_t ncr_retina_z3_device = { - "NCR 77C32BLT", - 0, + "NCR 77C32BLT", NULL, + 0, 0, ncr_retina_z3_init, ncr_close, NULL, + NULL, ncr_speed_changed, ncr_force_redraw, - ncr_add_status_info, - NULL }; diff --git a/pcem/vid_permedia2.cpp b/pcem/vid_permedia2.cpp index e693a35b..f6b32adc 100644 --- a/pcem/vid_permedia2.cpp +++ b/pcem/vid_permedia2.cpp @@ -192,15 +192,15 @@ static void permedia2_update_irqs(permedia2_t *permedia2) { if (permedia2->vblank_irq > 0 && permedia2_vsync_enabled(permedia2)) { permedia2->intreq |= 0x10; - pci_set_irq(NULL, PCI_INTA); + pci_set_irq(NULL, PCI_INTA, NULL); } else { - pci_clear_irq(NULL, PCI_INTA); + pci_clear_irq(NULL, PCI_INTA, NULL); } } static void permedia2_vblank_start(svga_t *svga) { - permedia2_t *permedia2 = (permedia2_t *)svga->p; + permedia2_t *permedia2 = (permedia2_t *)svga->priv; if (permedia2->vblank_irq >= 0) { permedia2->vblank_irq = 1; permedia2_update_irqs(permedia2); @@ -318,7 +318,7 @@ uint8_t permedia2_in(uint16_t addr, void *p) void permedia2_recalctimings(svga_t *svga) { - permedia2_t *permedia2 = (permedia2_t*)svga->p; + permedia2_t *permedia2 = (permedia2_t*)svga->priv; bool svga_mode = (svga->seqregs[0x05] & 0x08) != 0; int bpp = 8; @@ -421,7 +421,7 @@ void permedia2_recalctimings(svga_t *svga) static void permedia2_hwcursor_draw(svga_t *svga, int displine) { - permedia2_t *permedia2 = (permedia2_t*)svga->p; + permedia2_t *permedia2 = (permedia2_t*)svga->priv; int addr = svga->hwcursor_latch.addr; int addradd = 0; uint8_t dat[2]; @@ -431,11 +431,11 @@ static void permedia2_hwcursor_draw(svga_t *svga, int displine) offset <<= svga->horizontal_linedbl; - if (svga->hwcursor.xsize == 32) { + if (svga->hwcursor.cur_xsize == 32) { addradd = ((control >> 4) & 3) * (32 * 32 / 8); } - for (int x = 0; x < svga->hwcursor.xsize; x += 8) + for (int x = 0; x < svga->hwcursor.cur_xsize; x += 8) { dat[0] = permedia2->ramdac_cram[addr + addradd]; dat[1] = permedia2->ramdac_cram[addr + 0x200 + addradd]; @@ -470,7 +470,7 @@ static void permedia2_hwcursor_draw(svga_t *svga, int displine) } addr++; } - svga->hwcursor_latch.addr += svga->hwcursor.xsize / 8; + svga->hwcursor_latch.addr += svga->hwcursor.cur_xsize / 8; } @@ -612,7 +612,7 @@ static void permedia2_ramdac_write(int reg, uint8_t v, void *p) { case 0x06: // cursorcontrol svga->hwcursor.ena = (v & 3) != 0; - svga->hwcursor.ysize = svga->hwcursor.xsize = (v & 0x40) ? 64 : 32; + svga->hwcursor.cur_ysize = svga->hwcursor.cur_xsize = (v & 0x40) ? 64 : 32; permedia2->ramdac_cramaddr &= 0x00ff; permedia2->ramdac_cramaddr |= ((v >> 2) & 3) << 8; break; @@ -1538,7 +1538,7 @@ static uint8_t permedia2_mmio_read(uint32_t addr, void *p) static uint8_t permedia2_read_linear1(uint32_t addr, void *p) { svga_t *svga = (svga_t*)p; - permedia2_t *permedia2 = (permedia2_t*)svga->p; + permedia2_t *permedia2 = (permedia2_t*)svga->priv; uint8_t *fbp = (uint8_t*)(&svga->vram[addr & svga->vram_mask]); uint8_t v = *fbp; @@ -1547,7 +1547,7 @@ static uint8_t permedia2_read_linear1(uint32_t addr, void *p) static uint16_t permedia2_readw_linear1(uint32_t addr, void *p) { svga_t *svga = (svga_t*)p; - permedia2_t *permedia2 = (permedia2_t*)svga->p; + permedia2_t *permedia2 = (permedia2_t*)svga->priv; uint16_t *fbp = (uint16_t*)(&svga->vram[addr & svga->vram_mask]); uint16_t v = *fbp; @@ -1561,7 +1561,7 @@ static uint16_t permedia2_readw_linear1(uint32_t addr, void *p) static uint32_t permedia2_readl_linear1(uint32_t addr, void *p) { svga_t *svga = (svga_t*)p; - permedia2_t *permedia2 = (permedia2_t*)svga->p; + permedia2_t *permedia2 = (permedia2_t*)svga->priv; uint32_t *fbp = (uint32_t*)(&svga->vram[addr & svga->vram_mask]); uint32_t v = *fbp; @@ -1579,7 +1579,7 @@ static uint32_t permedia2_readl_linear1(uint32_t addr, void *p) static uint8_t permedia2_read_linear2(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; - permedia2_t *permedia2 = (permedia2_t *)svga->p; + permedia2_t *permedia2 = (permedia2_t *)svga->priv; uint8_t *fbp = (uint8_t *)(&svga->vram[addr & svga->vram_mask]); uint8_t v = *fbp; @@ -1588,7 +1588,7 @@ static uint8_t permedia2_read_linear2(uint32_t addr, void *p) static uint16_t permedia2_readw_linear2(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; - permedia2_t *permedia2 = (permedia2_t *)svga->p; + permedia2_t *permedia2 = (permedia2_t *)svga->priv; uint16_t *fbp = (uint16_t *)(&svga->vram[addr & svga->vram_mask]); uint16_t v = *fbp; @@ -1602,7 +1602,7 @@ static uint16_t permedia2_readw_linear2(uint32_t addr, void *p) static uint32_t permedia2_readl_linear2(uint32_t addr, void *p) { svga_t *svga = (svga_t *)p; - permedia2_t *permedia2 = (permedia2_t *)svga->p; + permedia2_t *permedia2 = (permedia2_t *)svga->priv; uint32_t *fbp = (uint32_t *)(&svga->vram[addr & svga->vram_mask]); uint32_t v = *fbp; @@ -1620,7 +1620,7 @@ static uint32_t permedia2_readl_linear2(uint32_t addr, void *p) static void permedia2_write_linear1(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t*)p; - permedia2_t *permedia2 = (permedia2_t*)svga->p; + permedia2_t *permedia2 = (permedia2_t*)svga->priv; addr &= svga->vram_mask; uint8_t *fbp = (uint8_t*)(&svga->vram[addr]); @@ -1630,7 +1630,7 @@ static void permedia2_write_linear1(uint32_t addr, uint8_t val, void *p) static void permedia2_writew_linear1(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t*)p; - permedia2_t *permedia2 = (permedia2_t*)svga->p; + permedia2_t *permedia2 = (permedia2_t*)svga->priv; if (permedia2->linear_byte_control[0] == 2) { val = (val >> 8) | (val << 8); @@ -1644,7 +1644,7 @@ static void permedia2_writew_linear1(uint32_t addr, uint16_t val, void *p) static void permedia2_writel_linear1(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t*)p; - permedia2_t *permedia2 = (permedia2_t*)svga->p; + permedia2_t *permedia2 = (permedia2_t*)svga->priv; if (permedia2->linear_byte_control[0] == 2) { val = (val >> 16) | (val << 16); @@ -1662,7 +1662,7 @@ static void permedia2_writel_linear1(uint32_t addr, uint32_t val, void *p) static void permedia2_write_linear2(uint32_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; - permedia2_t *permedia2 = (permedia2_t *)svga->p; + permedia2_t *permedia2 = (permedia2_t *)svga->priv; addr &= svga->vram_mask; uint8_t *fbp = (uint8_t *)(&svga->vram[addr]); @@ -1672,7 +1672,7 @@ static void permedia2_write_linear2(uint32_t addr, uint8_t val, void *p) static void permedia2_writew_linear2(uint32_t addr, uint16_t val, void *p) { svga_t *svga = (svga_t *)p; - permedia2_t *permedia2 = (permedia2_t *)svga->p; + permedia2_t *permedia2 = (permedia2_t *)svga->priv; if (permedia2->linear_byte_control[1] == 2) { val = (val >> 8) | (val << 8); @@ -1686,7 +1686,7 @@ static void permedia2_writew_linear2(uint32_t addr, uint16_t val, void *p) static void permedia2_writel_linear2(uint32_t addr, uint32_t val, void *p) { svga_t *svga = (svga_t *)p; - permedia2_t *permedia2 = (permedia2_t *)svga->p; + permedia2_t *permedia2 = (permedia2_t *)svga->priv; if (permedia2->linear_byte_control[1] == 2) { val = (val >> 16) | (val << 16); @@ -1910,7 +1910,7 @@ static void *permedia2_init(char *bios_fn, int chip) rom_init(&permedia2->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - svga_init(&permedia2->svga, permedia2, vram_size, + svga_init(NULL, &permedia2->svga, permedia2, vram_size, permedia2_recalctimings, permedia2_in, permedia2_out, permedia2_hwcursor_draw, @@ -1949,7 +1949,7 @@ static void *permedia2_init(char *bios_fn, int chip) return permedia2; } -void *permedia2_init() +void *permedia2_init(const device_t *info) { permedia2_t *permedia2 = (permedia2_t *)permedia2_init("permedia2.bin", 0); @@ -1998,13 +1998,13 @@ void permedia2_add_status_info(char *s, int max_len, void *p) device_t permedia2_device = { - "Permedia 2", - 0, + "Permedia 2", NULL, + 0, 0, permedia2_init, permedia2_close, NULL, + NULL, permedia2_speed_changed, permedia2_force_redraw, - permedia2_add_status_info, NULL }; diff --git a/pcem/vid_s3.cpp b/pcem/vid_s3.cpp index f1f04ce1..b47d6c8a 100644 --- a/pcem/vid_s3.cpp +++ b/pcem/vid_s3.cpp @@ -190,9 +190,9 @@ static void s3_update_irqs(s3_t *s3) { int enabled = s3_vga_vsync_enabled(s3); if (((s3->subsys_cntl & s3->subsys_stat & INT_MASK) && (s3->svga.crtc[0x32] & 0x10)) || (enabled && (s3->subsys_stat & INT_VSY))) - pci_set_irq(s3->card, PCI_INTA); + pci_set_irq(s3->card, PCI_INTA, NULL); else - pci_clear_irq(s3->card, PCI_INTA); + pci_clear_irq(s3->card, PCI_INTA, NULL); if ((s3->subsys_stat & INT_VSY) && !(s3->subsys_cntl & INT_VSY) && !enabled) { s3->subsys_stat &= ~INT_VSY; @@ -202,7 +202,7 @@ static void s3_update_irqs(s3_t *s3) static void s3_update_irqs_thread(s3_t* s3, int mask) { if ((s3->subsys_cntl & s3->subsys_stat & mask) && (s3->svga.crtc[0x32] & 0x10)) - pci_set_irq(s3->card, PCI_INTA); + pci_set_irq(s3->card, PCI_INTA, NULL); } void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3); @@ -943,7 +943,7 @@ static void fifo_thread(void *param) static void s3_vblank_start(svga_t *svga) { - s3_t *s3 = (s3_t *)svga->p; + s3_t *s3 = (s3_t *)svga->priv; if (s3->vblank_irq >= 0) { s3->vblank_irq = 1; } @@ -1238,7 +1238,7 @@ uint8_t s3_in(uint16_t addr, void *p) void s3_recalctimings(svga_t *svga) { - s3_t *s3 = (s3_t *)svga->p; + s3_t *s3 = (s3_t *)svga->priv; svga->hdisp = svga->hdisp_old; int clk_sel = (svga->miscout >> 2) & 3; @@ -2548,7 +2548,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat void s3_hwcursor_draw(svga_t *svga, int displine) { - s3_t *s3 = (s3_t *)svga->p; + s3_t *s3 = (s3_t *)svga->priv; int x; uint16_t dat[2]; int xx; @@ -2810,7 +2810,7 @@ static void *s3_init(char *bios_fn, int chip) mem_mapping_addx(&s3->mmio_mapping, 0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3); mem_mapping_disablex(&s3->mmio_mapping); - svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/ + svga_init(NULL, &s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/ s3_recalctimings, s3_in, s3_out, s3_hwcursor_draw, @@ -2953,7 +2953,7 @@ int s3_phoenix_trio64_available() #endif -void *s3_trio64_init() +void *s3_trio64_init(const device_t *info) { s3_t *s3 = (s3_t*)s3_init("86c764x1.bin", S3_TRIO64); @@ -2969,7 +2969,7 @@ void *s3_trio64_init() } -void *s3_cybervision_init() +void *s3_cybervision_init(const device_t *info) { s3_t *s3 = (s3_t*)s3_init("86c764x1.bin", S3_TRIO64); @@ -3161,7 +3161,7 @@ static device_config_t s3_phoenix_trio64_config[] = device_t s3_bahamas64_device = { "Paradise Bahamas 64 (S3 Vision864)", - 0, + 0, 0, s3_bahamas64_init, s3_close, s3_bahamas64_available, @@ -3174,7 +3174,7 @@ device_t s3_bahamas64_device = device_t s3_9fx_device = { "Number 9 9FX (S3 Trio64)", - 0, + 0, 0, s3_9fx_init, s3_close, s3_9fx_available, @@ -3187,7 +3187,7 @@ device_t s3_9fx_device = device_t s3_phoenix_trio32_device = { "Phoenix S3 Trio32", - 0, + 0, 0, s3_phoenix_trio32_init, s3_close, s3_phoenix_trio32_available, @@ -3200,7 +3200,7 @@ device_t s3_phoenix_trio32_device = device_t s3_phoenix_trio64_device = { "Phoenix S3 Trio64", - 0, + 0, 0, s3_phoenix_trio64_init, s3_close, s3_phoenix_trio64_available, @@ -3214,27 +3214,27 @@ device_t s3_phoenix_trio64_device = device_t s3_cybervision_trio64_device = { - "CyberVision64", - 0, + "CyberVision64", NULL, + 0, 0, s3_cybervision_init, s3_close, NULL, + NULL, s3_speed_changed, s3_force_redraw, - s3_add_status_info, NULL }; device_t s3_trio64_device = { - "S3Trio64", - 0, + "S3Trio64", NULL, + 0, 0, s3_trio64_init, s3_close, NULL, + NULL, s3_speed_changed, s3_force_redraw, - s3_add_status_info, NULL }; diff --git a/pcem/vid_s3_virge.cpp b/pcem/vid_s3_virge.cpp index e4a49821..3de51d3c 100644 --- a/pcem/vid_s3_virge.cpp +++ b/pcem/vid_s3_virge.cpp @@ -328,15 +328,15 @@ static int virge_vga_vsync_enabled(virge_t *virge) static void s3_virge_update_irqs(virge_t *virge) { if (((virge->subsys_stat & virge->subsys_cntl & INT_MASK) && virge->svga.crtc[0x32] & 0x10) || virge_vga_vsync_enabled(virge)) - pci_set_irq(virge->card, PCI_INTA); + pci_set_irq(virge->card, PCI_INTA, NULL); else - pci_clear_irq(virge->card, PCI_INTA); + pci_clear_irq(virge->card, PCI_INTA, NULL); } static void s3_virge_update_irqs_thread(virge_t* virge, int mask) { if ((virge->subsys_stat & virge->subsys_cntl & INT_MASK & mask) && virge->svga.crtc[0x32] & 0x10) - pci_set_irq(virge->card, PCI_INTA); + pci_set_irq(virge->card, PCI_INTA, NULL); } @@ -593,7 +593,7 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) static void s3_virge_recalctimings(svga_t *svga) { - virge_t *virge = (virge_t *)svga->p; + virge_t *virge = (virge_t *)svga->priv; svga->hdisp = svga->crtc[1]; svga->hdisp++; @@ -682,7 +682,7 @@ static void s3_virge_recalctimings(svga_t *svga) svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; - svga->overlay.ysize = virge->streams.sec_h; + svga->overlay.cur_ysize = virge->streams.sec_h; if (virge->streams.buffer_ctrl & 2) svga->overlay.addr = virge->streams.sec_fb1; @@ -824,7 +824,7 @@ static void s3_virge_updatemapping(virge_t *virge) static void s3_virge_vblank_start(svga_t *svga) { - virge_t *virge = (virge_t *)svga->p; + virge_t *virge = (virge_t *)svga->priv; if (virge->vblank_irq >= 0) { virge->vblank_irq = 1; @@ -3499,7 +3499,7 @@ static void queue_triangle(virge_t *virge) static void s3_virge_hwcursor_draw(svga_t *svga, int displine) { - virge_t *virge = (virge_t *)svga->p; + virge_t *virge = (virge_t *)svga->priv; int x; uint16_t dat[2]; int xx; @@ -3804,7 +3804,7 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) static void s3_virge_overlay_draw(svga_t *svga, int displine) { - virge_t *virge = (virge_t *)svga->p; + virge_t *virge = (virge_t *)svga->priv; int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1; int h_acc = virge->streams.dda_horiz_accumulator; int r[8], g[8], b[8]; @@ -3949,7 +3949,7 @@ static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) } } -static void *s3_virge_init() +static void *s3_virge_init(const device_t *info) { virge_t *virge = (virge_t*)malloc(sizeof(virge_t)); memset(virge, 0, sizeof(virge_t)); @@ -3958,7 +3958,7 @@ static void *s3_virge_init() virge->dithering_enabled = device_get_config_int("dithering"); virge->memory_size = device_get_config_int("memory"); - svga_init(&virge->svga, virge, virge->memory_size << 20, + svga_init(NULL, &virge->svga, virge, virge->memory_size << 20, s3_virge_recalctimings, s3_virge_in, s3_virge_out, s3_virge_hwcursor_draw, @@ -4057,7 +4057,7 @@ static void *s3_virge_375_init() virge->dithering_enabled = device_get_config_int("dithering"); virge->memory_size = device_get_config_int("memory"); - svga_init(&virge->svga, virge, virge->memory_size << 20, + svga_init(NULL, &virge->svga, virge, virge->memory_size << 20, s3_virge_recalctimings, s3_virge_in, s3_virge_out, s3_virge_hwcursor_draw, @@ -4277,14 +4277,14 @@ static device_config_t s3_virge_config[] = device_t s3_virge_device = { - "Diamond Stealth 3D 2000 (S3 ViRGE)", - 0, + "Diamond Stealth 3D 2000 (S3 ViRGE)", NULL, + 0, 0, s3_virge_init, s3_virge_close, + NULL, s3_virge_available, s3_virge_speed_changed, s3_virge_force_redraw, - s3_virge_add_status_info, #ifndef UAE s3_virge_config #endif @@ -4294,7 +4294,7 @@ device_t s3_virge_device = device_t s3_virge_375_device = { "S3 ViRGE/DX", - 0, + 0, 0, s3_virge_375_init, s3_virge_close, s3_virge_375_available, diff --git a/pcem/vid_sc1502x_ramdac.cpp b/pcem/vid_sc1502x_ramdac.cpp index 57024c57..cf7ceb70 100644 --- a/pcem/vid_sc1502x_ramdac.cpp +++ b/pcem/vid_sc1502x_ramdac.cpp @@ -21,6 +21,7 @@ #include #include "ibm.h" #include "mem.h" +#include "device.h" #include "video.h" #include "vid_svga.h" #include "vid_sdac_ramdac.h" diff --git a/pcem/vid_sdac_ramdac.cpp b/pcem/vid_sdac_ramdac.cpp index 08288ac0..c39fbf53 100644 --- a/pcem/vid_sdac_ramdac.cpp +++ b/pcem/vid_sdac_ramdac.cpp @@ -1,6 +1,7 @@ /*87C716 'SDAC' true colour RAMDAC emulation*/ #include "ibm.h" #include "mem.h" +#include "device.h" #include "video.h" #include "vid_svga.h" #include "vid_sdac_ramdac.h" diff --git a/pcem/vid_svga.cpp b/pcem/vid_svga.cpp index d6494a35..478eaa65 100644 --- a/pcem/vid_svga.cpp +++ b/pcem/vid_svga.cpp @@ -3,6 +3,7 @@ #include #include "ibm.h" #include "mem.h" +#include "device.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -57,7 +58,9 @@ void svga_out(uint16_t addr, uint8_t val, void *p) svga_t *svga = (svga_t *)p; int c; uint8_t o; -// printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,pc); + uint8_t index; + +// printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,pc); switch (addr) { case 0x3C0: @@ -100,9 +103,9 @@ void svga_out(uint16_t addr, uint8_t val, void *p) case 0x3C2: svga->miscout = val; svga->vidclock = val & 4;// printf("3C2 write %02X\n",val); - io_removehandlerx(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + io_removehandlerx(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->priv); if (!(val & 1)) - io_sethandlerx(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + io_sethandlerx(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->priv); svga_recalctimings(svga); break; case 0x3C4: @@ -145,40 +148,42 @@ void svga_out(uint16_t addr, uint8_t val, void *p) svga->dac_mask = val; break; case 0x3C7: - svga->dac_read = val; - svga->dac_pos = 0; - break; case 0x3C8: - svga->dac_write = val; - svga->dac_read = val - 1; - svga->dac_pos = 0; + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = (val + (addr & 0x01)) & 0xff; break; case 0x3C9: svga->dac_status = 0; - svga->fullchange = changeframecount; - switch (svga->dac_pos) - { - case 0: + if (svga->adv_flags & FLAG_RAMDAC_SHIFT) + val <<= 2; + svga->fullchange = svga->monitor->mon_changeframecount; + switch (svga->dac_pos) { + case 0: svga->dac_r = val; - svga->dac_pos++; + svga->dac_pos++; break; - case 1: + case 1: svga->dac_g = val; - svga->dac_pos++; + svga->dac_pos++; break; - case 2: - svga->vgapal[svga->dac_write].r = svga->dac_r; - svga->vgapal[svga->dac_write].g = svga->dac_g; - svga->vgapal[svga->dac_write].b = val; - //pclog("%d: %02x %02x %02x\n", svga->dac_write, svga->dac_r, svga->dac_g, val); + case 2: + index = svga->dac_addr & 0xff; + svga->dac_b = val; + svga->vgapal[index].r = svga->dac_r; + svga->vgapal[index].g = svga->dac_g; + svga->vgapal[index].b = svga->dac_b; + //if (index < 16) + // pclog("%d: %02x %02x %02x\n", index, svga->dac_r, svga->dac_g, svga->dac_b); if (svga->ramdac_type == RAMDAC_8BIT) - svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); + svga->pallook[index] = makecol32(svga->vgapal[index].r, svga->vgapal[index].g, svga->vgapal[index].b); else - svga->pallook[svga->dac_write] = makecol32((svga->vgapal[svga->dac_write].r & 0x3f) * 4, (svga->vgapal[svga->dac_write].g & 0x3f) * 4, (svga->vgapal[svga->dac_write].b & 0x3f) * 4); - if (svga->swaprb) - svga->pallook[svga->dac_write] = ((svga->pallook[svga->dac_write] >> 16) & 0xff) | ((svga->pallook[svga->dac_write] & 0xff) << 16) | (svga->pallook[svga->dac_write] & 0x00ff00); - svga->dac_pos = 0; - svga->dac_write = (svga->dac_write + 1) & 255; + svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f], video_6to8[svga->vgapal[index].g & 0x3f], video_6to8[svga->vgapal[index].b & 0x3f]); + svga->dac_pos = 0; + svga->dac_addr = (svga->dac_addr + 1) & 0xff; + break; + + default: break; } break; @@ -237,6 +242,9 @@ uint8_t svga_in(uint16_t addr, void *p) { svga_t *svga = (svga_t *)p; uint8_t temp; + uint8_t index; + uint8_t ret = 0xff; + // if (addr!=0x3da) pclog("Read port %04X\n",addr); switch (addr) { @@ -256,28 +264,38 @@ uint8_t svga_in(uint16_t addr, void *p) return svga->seqregs[svga->seqaddr & 0xF]; case 0x3c6: return svga->dac_mask; case 0x3c7: return svga->dac_status; - case 0x3c8: return svga->dac_write; + case 0x3c8: return svga->dac_addr; case 0x3c9: - svga->dac_status = 3; - switch (svga->dac_pos) - { - case 0: - svga->dac_pos++; + index = (svga->dac_addr - 1) & 0xff; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; if (svga->ramdac_type == RAMDAC_8BIT) - return svga->vgapal[svga->dac_read].r; - return svga->vgapal[svga->dac_read].r & 0x3f; - case 1: - svga->dac_pos++; + ret = svga->vgapal[index].r; + else + ret = svga->vgapal[index].r & 0x3f; + break; + case 1: + svga->dac_pos++; if (svga->ramdac_type == RAMDAC_8BIT) - return svga->vgapal[svga->dac_read].g; - return svga->vgapal[svga->dac_read].g & 0x3f; - case 2: - svga->dac_pos=0; - svga->dac_read = (svga->dac_read + 1) & 255; + ret = svga->vgapal[index].g; + else + ret = svga->vgapal[index].g & 0x3f; + break; + case 2: + svga->dac_pos = 0; + svga->dac_addr = (svga->dac_addr + 1) & 0xff; if (svga->ramdac_type == RAMDAC_8BIT) - return svga->vgapal[(svga->dac_read - 1) & 255].b; - return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + ret = svga->vgapal[index].b; + else + ret = svga->vgapal[index].b & 0x3f; + break; + + default: + break; } + if (svga->adv_flags & FLAG_RAMDAC_SHIFT) + ret >>= 2; break; case 0x3CC: return svga->miscout; @@ -295,7 +313,7 @@ uint8_t svga_in(uint16_t addr, void *p) return svga->cgastat; } // printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc); - return 0xFF; + return ret; } void svga_set_ramdac_type(svga_t *svga, int type) @@ -313,7 +331,7 @@ void svga_set_ramdac_type(svga_t *svga, int type) else svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, (svga->vgapal[c].g & 0x3f) * 4, (svga->vgapal[c].b & 0x3f) * 4); if (svga->swaprb) - svga->pallook[svga->dac_write] = ((svga->pallook[svga->dac_write] >> 16) & 0xff) | ((svga->pallook[svga->dac_write] & 0xff) << 16) | (svga->pallook[svga->dac_write] & 0x00ff00); + svga->pallook[svga->dac_addr] = ((svga->pallook[c] >> 16) & 0xff) | ((svga->pallook[c] & 0xff) << 16) | (svga->pallook[c] & 0x00ff00); } } } @@ -549,7 +567,7 @@ int svga_poll(void *p) // if (!(vc & 15)) pclog("VC %i %i\n", vc, GetTickCount()); if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { - svga->hwcursor_on = svga->hwcursor.ysize - svga->hwcursor_latch.yoff; + svga->hwcursor_on = svga->hwcursor.cur_ysize - svga->hwcursor_latch.yoff; if (svga->hwcursor_on < 0) svga->hwcursor_on = 0; svga->hwcursor_oddeven = 0; @@ -557,30 +575,30 @@ int svga_poll(void *p) if (svga->displine == svga->hwcursor_latch.y+1 && svga->hwcursor_latch.ena && svga->interlace) { - svga->hwcursor_on = svga->hwcursor.ysize - svga->hwcursor_latch.yoff; + svga->hwcursor_on = svga->hwcursor.cur_ysize - svga->hwcursor_latch.yoff; if (svga->hwcursor_on < 0) svga->hwcursor_on = 0; svga->hwcursor_oddeven = 1; } if (svga->displine == ((svga->dac_hwcursor_latch.y < 0) ? 0 : svga->dac_hwcursor_latch.y) && svga->dac_hwcursor_latch.ena) { - svga->dac_hwcursor_on = svga->dac_hwcursor_latch.ysize - svga->dac_hwcursor_latch.yoff; + svga->dac_hwcursor_on = svga->dac_hwcursor_latch.cur_ysize - svga->dac_hwcursor_latch.yoff; svga->dac_hwcursor_oddeven = 0; } if (svga->displine == (((svga->dac_hwcursor_latch.y < 0) ? 0 : svga->dac_hwcursor_latch.y) + 1) && svga->dac_hwcursor_latch.ena && svga->interlace) { - svga->dac_hwcursor_on = svga->dac_hwcursor_latch.ysize - (svga->dac_hwcursor_latch.yoff + 1); + svga->dac_hwcursor_on = svga->dac_hwcursor_latch.cur_ysize - (svga->dac_hwcursor_latch.yoff + 1); svga->dac_hwcursor_oddeven = 1; } if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { - svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_on = svga->overlay_latch.cur_ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 0; } if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) { - svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_on = svga->overlay_latch.cur_ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 1; } #ifndef UAE @@ -833,6 +851,7 @@ int svga_poll(void *p) } svga->scrollcache_src = 0; svga->scrollcache_dst_reset = svga->scrollcache_dst; + svga->x_add = svga->scrollcache_dst; if (svga->adjust_panning) { svga->adjust_panning(svga); @@ -888,7 +907,7 @@ void svga_setvram(void *p, uint8_t *vram) svga->vram = vram; } -int svga_init(svga_t *svga, void *p, int memsize, +int svga_init(const device_t *info, svga_t *svga, void *priv, int memsize, void (*recalctimings_ex)(struct svga_t *svga), uint8_t (*video_in) (uint16_t addr, void *p), void (*video_out)(uint16_t addr, uint8_t val, void *p), @@ -897,7 +916,9 @@ int svga_init(svga_t *svga, void *p, int memsize, { int c, d, e; - svga->p = p; + svga->priv = priv; + svga->monitor_index = monitor_index_global; + svga->monitor = &monitors[svga->monitor_index]; for (c = 0; c < 256; c++) { @@ -910,6 +931,9 @@ int svga_init(svga_t *svga, void *p, int memsize, } svga->readmode = 0; + svga->x_add = 8; + svga->y_add = 16; + svga->crtcreg_mask = 0x3f; svga->crtc[0] = 63; svga->crtc[6] = 255; @@ -932,7 +956,7 @@ int svga_init(svga_t *svga, void *p, int memsize, svga->video_out = video_out; svga->hwcursor_draw = hwcursor_draw; svga->overlay_draw = overlay_draw; - svga->hwcursor.ysize = 64; + svga->hwcursor.cur_ysize = 64; svga->ksc5601_english_font_type = 0; svga_recalctimings(svga); diff --git a/pcem/vid_svga.h b/pcem/vid_svga.h index a444a828..5ca4a6b9 100644 --- a/pcem/vid_svga.h +++ b/pcem/vid_svga.h @@ -10,8 +10,12 @@ # define FLAG_S3_911_16BIT 256 # define FLAG_512K_MASK 512 +struct monitor_t; + typedef struct svga_t { + void *priv; + mem_mapping_t mapping; uint8_t crtcreg, crtcreg_mask; @@ -43,7 +47,7 @@ typedef struct svga_t uint8_t la, lb, lc, ld; uint8_t dac_mask, dac_status; - int dac_read, dac_write, dac_pos; + int dac_pos; int dac_r, dac_g, dac_b; int dac_addr; @@ -115,7 +119,7 @@ typedef struct svga_t int ena; int x, y; int xoff, yoff; - int xsize, ysize; + int cur_xsize, cur_ysize; uint32_t addr; uint32_t pitch; int v_acc, h_acc; @@ -135,10 +139,14 @@ typedef struct svga_t void (*video_out)(uint16_t addr, uint8_t val, void *p); uint8_t (*video_in) (uint16_t addr, void *p); + float (*getclock)(int clock, void *priv); + void (*hwcursor_draw)(struct svga_t *svga, int displine); void (*dac_hwcursor_draw)(struct svga_t *svga, int displine); void (*overlay_draw)(struct svga_t *svga, int displine); + + void (*vblank_start)(struct svga_t *svga); void (*adjust_panning)(struct svga_t *svga); @@ -153,7 +161,6 @@ typedef struct svga_t /*If set then another device is driving the monitor output and the SVGA card should not attempt to display anything */ int override; - void *p; uint8_t ksc5601_sbyte_mask; uint8_t ksc5601_udc_area_msb[2]; @@ -170,6 +177,11 @@ typedef struct svga_t addresses are shifted to match*/ int packed_chain4; + /*Disable 8bpp blink mode - some cards support it, some don't, it's a weird mode + If mode 13h appears in a reddish-brown background (0x88) with dark green text (0x8F), + you should set this flag when entering that mode*/ + int disable_blink; + /*Force CRTC to dword mode, regardless of CR14/CR17. Required for S3 enhanced mode*/ int force_dword_mode; @@ -179,6 +191,7 @@ typedef struct svga_t uint32_t overscan_color; int ati_4color; void *ramdac; + void *clock_gen; uint32_t adv_flags; int hblankstart; int hblankend; @@ -193,11 +206,23 @@ typedef struct svga_t int x_add; int y_add; uint8_t ext_overscan; + uint8_t dpms; + uint8_t lut_map; + + int swaprb; + + /* Return a 32 bpp color from a 15/16 bpp color. */ + uint32_t(*conv_16to32)(struct svga_t *svga, uint16_t color, uint8_t bpp); + + /* Monitor Index */ + uint8_t monitor_index; + + /* Pointer to monitor */ + monitor_t *monitor; - bool swaprb; } svga_t; -extern int svga_init(svga_t *svga, void *p, int memsize, +extern int svga_init(const device_t *info, svga_t *svga, void *p, int memsize, void (*recalctimings_ex)(struct svga_t *svga), uint8_t (*video_in) (uint16_t addr, void *p), void (*video_out)(uint16_t addr, uint8_t val, void *p), @@ -232,9 +257,21 @@ void svga_set_override(svga_t *svga, int val); #define RAMDAC_6BIT 0 #define RAMDAC_8BIT 1 + +uint32_t svga_lookup_lut_ram(svga_t *svga, uint32_t val); + void svga_set_ramdac_type(svga_t *svga, int type); void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); extern void sc1502x_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga); extern uint8_t sc1502x_ramdac_in(uint16_t addr, void *priv, svga_t *svga); + +extern void tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *priv, svga_t *svga); +extern uint8_t tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *priv, svga_t *svga); +extern uint32_t tvp3026_conv_16to32(svga_t *svga, uint16_t color, uint8_t bpp); +extern void tvp3026_recalctimings(void *priv, svga_t *svga); +extern void tvp3026_hwcursor_draw(svga_t *svga, int displine); +extern float tvp3026_getclock(int clock, void *priv); +extern void tvp3026_gpio(uint8_t(*read)(uint8_t cntl, void *priv), void (*write)(uint8_t cntl, uint8_t data, void *priv), void *cb_priv, void *priv); +extern const device_t tvp3026_ramdac_device; diff --git a/pcem/vid_svga_render.cpp b/pcem/vid_svga_render.cpp index 06d41df0..da2c369f 100644 --- a/pcem/vid_svga_render.cpp +++ b/pcem/vid_svga_render.cpp @@ -1,10 +1,28 @@ + +#include #include "ibm.h" #include "mem.h" +#include "device.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_svga_render_remap.h" + +uint32_t +svga_lookup_lut_ram(svga_t *svga, uint32_t val) +{ + if (!svga->lut_map) + return val; + + uint8_t r = getcolr(svga->pallook[getcolr(val)]); + uint8_t g = getcolg(svga->pallook[getcolg(val)]); + uint8_t b = getcolb(svga->pallook[getcolb(val)]); + return makecol32(r, g, b) | (val & 0xFF000000); +} + +#define lookup_lut(val) svga_lookup_lut_ram(svga, val) + void svga_render_null(svga_t *svga) { if (svga->firstline_draw == 4000) @@ -1128,7 +1146,7 @@ void svga_render_32bpp_highres_swaprb(svga_t *svga) for (x = 0; x <= svga->hdisp; x++) { uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + shift + (x << 2)) & svga->vram_display_mask]); - dat = ((dat & 0xff0000) >> 16) | ((dat & 0x0000ff) << 16) | ((dat & 0x00ff00)); + dat = _byteswap_ulong(dat); *p++ = dat & 0xffffff; } svga->ma += x * 4; @@ -1139,7 +1157,7 @@ void svga_render_32bpp_highres_swaprb(svga_t *svga) { uint32_t addr = svga->remap_func(svga, svga->ma + shift); uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); - dat = ((dat & 0xff0000) >> 16) | ((dat & 0x0000ff) << 16) | ((dat & 0x00ff00)); + dat = _byteswap_ulong(dat); *p++ = dat & 0xffffff; svga->ma += 4; } diff --git a/pcem/vid_tvp3026_ramdac.cpp b/pcem/vid_tvp3026_ramdac.cpp new file mode 100644 index 00000000..66113ec5 --- /dev/null +++ b/pcem/vid_tvp3026_ramdac.cpp @@ -0,0 +1,756 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the Texas Instruments TVP3026 true colour RAMDAC + * family. + * + * + * TODO: Clock and other parts. + * + * Authors: TheCollector1995, + * + * Copyright 2021 TheCollector1995. + */ +#include +#include +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" + +typedef struct tvp3026_ramdac_t { + PALETTE extpal; + uint32_t extpallook[256]; + uint8_t cursor64_data[1024]; + int hwc_y; + int hwc_x; + uint8_t ind_idx; + uint8_t dcc; + uint8_t dc_init; + uint8_t ccr; + uint8_t true_color; + uint8_t latch_cntl; + uint8_t mcr; + uint8_t ppr; + uint8_t general_cntl; + uint8_t mclk; + uint8_t misc; + uint8_t type; + uint8_t mode; + uint8_t pll_addr; + uint8_t clock_sel; + struct { + uint8_t m; + uint8_t n; + uint8_t p; + } pix, mem, loop; + uint8_t gpio_cntl; + uint8_t gpio_data; + uint8_t (*gpio_read)(uint8_t cntl, void *priv); + void (*gpio_write)(uint8_t cntl, uint8_t val, void *priv); + void *gpio_priv; +} tvp3026_ramdac_t; + +static void +tvp3026_set_bpp(tvp3026_ramdac_t *ramdac, svga_t *svga) +{ + svga->swaprb = 0; + if (ramdac->true_color & 0x80) { + if (ramdac->mcr & 0x08) + svga->bpp = 8; + else + svga->bpp = 4; + } else { + switch (ramdac->true_color & 0x0f) { + case 0x01: + svga->bpp = 16; + break; + case 0x03: + svga->bpp = 16; + break; + case 0x05: + svga->bpp = 16; + break; + case 0x04: + svga->bpp = 15; + break; + case 0x06: + if (ramdac->true_color & 0x10) + svga->bpp = 24; + else + svga->bpp = 32; + break; + case 0x07: + if (ramdac->true_color & 0x10) { + svga->bpp = 24; + svga->swaprb = 1; + } else { + svga->bpp = 32; + svga->swaprb = 1; + } + break; + case 0x0e: + svga->bpp = 24; + break; + case 0x0f: + svga->bpp = 24; + svga->swaprb = 1; + break; + + default: + break; + } + } + void pcemvideorbswap(bool swapped); + pcemvideorbswap(svga->swaprb); + svga_recalctimings(svga); +} + +void +tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *priv, svga_t *svga) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv; + uint32_t o32; + uint8_t *cd; + uint16_t index; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x03ff; + rs |= (!!rs2 << 2); + rs |= (!!rs3 << 3); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + ramdac->ind_idx = val; + //fallthrough; + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + case 0x03: + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = val; + if (svga->dac_status) + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + svga_out(addr, val, svga); + break; + case 0x05: /* Ext Palette Data Register (RS value = 0101) */ + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + index = svga->dac_addr & 3; + ramdac->extpal[index].r = svga->dac_r; + ramdac->extpal[index].g = svga->dac_g; + ramdac->extpal[index].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + ramdac->extpallook[index] = makecol32(ramdac->extpal[index].r, ramdac->extpal[index].g, ramdac->extpal[index].b); + else + ramdac->extpallook[index] = makecol32(video_6to8[ramdac->extpal[index].r & 0x3f], video_6to8[ramdac->extpal[index].g & 0x3f], video_6to8[ramdac->extpal[index].b & 0x3f]); + + if (svga->ext_overscan && !index) { + o32 = svga->overscan_color; + svga->overscan_color = ramdac->extpallook[0]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + svga->dac_addr = (svga->dac_addr + 1) & 0xff; + svga->dac_pos = 0; + break; + + default: + break; + } + break; + case 0x09: /* Direct Cursor Control (RS value = 1001) */ + ramdac->dcc = val; + if (ramdac->ccr & 0x80) { + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; + svga->dac_hwcursor.ena = !!(val & 0x03); + ramdac->mode = val & 0x03; + } + break; + case 0x0a: /* Indexed Data (RS value = 1010) */ + switch (ramdac->ind_idx) { + case 0x06: /* Indirect Cursor Control */ + ramdac->ccr = val; + if (!(ramdac->ccr & 0x80)) { + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; + svga->dac_hwcursor.ena = !!(val & 0x03); + ramdac->mode = val & 0x03; + } else { + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; + svga->dac_hwcursor.ena = !!(ramdac->dcc & 0x03); + ramdac->mode = ramdac->dcc & 0x03; + } + break; + case 0x0f: /* Latch Control */ + ramdac->latch_cntl = val; + break; + case 0x18: /* True Color Control */ + ramdac->true_color = val; + tvp3026_set_bpp(ramdac, svga); + break; + case 0x19: /* Multiplex Control */ + ramdac->mcr = val; + tvp3026_set_bpp(ramdac, svga); + break; + case 0x1a: /* Clock Selection */ + ramdac->clock_sel = val; + break; + case 0x1c: /* Palette-Page Register */ + ramdac->ppr = val; + break; + case 0x1d: /* General Control Register */ + ramdac->general_cntl = val; + break; + case 0x1e: /* Miscellaneous Control */ + ramdac->misc = val; + svga->ramdac_type = (val & 0x08) ? RAMDAC_8BIT : RAMDAC_6BIT; + break; + case 0x2a: /* General-Purpose I/O Control */ + ramdac->gpio_cntl = val; + if (ramdac->gpio_write) + ramdac->gpio_write(ramdac->gpio_cntl, ramdac->gpio_data, ramdac->gpio_priv); + break; + case 0x2b: /* General-Purpose I/O Data */ + ramdac->gpio_data = val; + if (ramdac->gpio_write) + ramdac->gpio_write(ramdac->gpio_cntl, ramdac->gpio_data, ramdac->gpio_priv); + break; + case 0x2c: /* PLL Address */ + ramdac->pll_addr = val; + break; + case 0x2d: /* Pixel clock PLL data */ + switch (ramdac->pll_addr & 3) { + case 0: + ramdac->pix.n = val; + break; + case 1: + ramdac->pix.m = val; + break; + case 2: + ramdac->pix.p = val; + break; + + default: + break; + } + ramdac->pll_addr = ((ramdac->pll_addr + 1) & 3) | (ramdac->pll_addr & 0xfc); + break; + case 0x2e: /* Memory Clock PLL Data */ + switch ((ramdac->pll_addr >> 2) & 3) { + case 0: + ramdac->mem.n = val; + break; + case 1: + ramdac->mem.m = val; + break; + case 2: + ramdac->mem.p = val; + break; + + default: + break; + } + ramdac->pll_addr = ((ramdac->pll_addr + 4) & 0x0c) | (ramdac->pll_addr & 0xf3); + break; + case 0x2f: /* Loop Clock PLL Data */ + switch ((ramdac->pll_addr >> 4) & 3) { + case 0: + ramdac->loop.n = val; + break; + case 1: + ramdac->loop.m = val; + break; + case 2: + ramdac->loop.p = val; + break; + + default: + break; + } + ramdac->pll_addr = ((ramdac->pll_addr + 0x10) & 0x30) | (ramdac->pll_addr & 0xcf); + break; + case 0x39: /* MCLK/Loop Clock Control */ + ramdac->mclk = val; + break; + + default: + break; + } + break; + case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ + index = (svga->dac_addr & da_mask) | ((ramdac->ccr & 0x0c) << 6); + cd = (uint8_t *) ramdac->cursor64_data; + cd[index] = val; + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x0c: /* Cursor X Low Register (RS value = 1100) */ + ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + break; + case 0x0d: /* Cursor X High Register (RS value = 1101) */ + ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + break; + case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ + ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; + break; + case 0x0f: /* Cursor Y High Register (RS value = 1111) */ + ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; + break; + + default: + break; + } + + return; +} + +uint8_t +tvp3026_ramdac_in(uint16_t addr, int rs2, int rs3, void *priv, svga_t *svga) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv; + uint8_t temp = 0xff; + const uint8_t *cd; + uint16_t index; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x03ff; + rs |= (!!rs2 << 2); + rs |= (!!rs3 << 3); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + temp = svga_in(addr, svga); + break; + case 0x03: /* Palette Read Index Register (RS value = 0011) */ + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + temp = svga->dac_addr & 0xff; + break; + case 0x05: /* Ext Palette Data Register (RS value = 0101) */ + index = (svga->dac_addr - 1) & 3; + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].r; + else + temp = ramdac->extpal[index].r & 0x3f; + break; + case 1: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].g; + else + temp = ramdac->extpal[index].g & 0x3f; + break; + case 2: + svga->dac_pos = 0; + svga->dac_addr = svga->dac_addr + 1; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].b; + else + temp = ramdac->extpal[index].b & 0x3f; + break; + + default: + break; + } + break; + case 0x09: /* Direct Cursor Control (RS value = 1001) */ + temp = ramdac->dcc; + break; + case 0x0a: /* Indexed Data (RS value = 1010) */ + switch (ramdac->ind_idx) { + case 0x01: /* Silicon Revision */ + temp = 0x00; + break; + case 0x06: /* Indirect Cursor Control */ + temp = ramdac->ccr; + break; + case 0x0f: /* Latch Control */ + temp = ramdac->latch_cntl; + break; + case 0x18: /* True Color Control */ + temp = ramdac->true_color; + break; + case 0x19: /* Multiplex Control */ + temp = ramdac->mcr; + break; + case 0x1a: /* Clock Selection */ + temp = ramdac->clock_sel; + break; + case 0x1c: /* Palette-Page Register */ + temp = ramdac->ppr; + break; + case 0x1d: /* General Control Register */ + temp = ramdac->general_cntl; + break; + case 0x1e: /* Miscellaneous Control */ + temp = ramdac->misc; + break; + case 0x2a: /* General-Purpose I/O Control */ + temp = ramdac->gpio_cntl; + break; + case 0x2b: /* General-Purpose I/O Data */ + if (ramdac->gpio_read) { + temp = 0xe0 | (ramdac->gpio_cntl & 0x1f); /* keep upper bits untouched */ + ramdac->gpio_data = (ramdac->gpio_data & temp) | (ramdac->gpio_read(ramdac->gpio_cntl, ramdac->gpio_priv) & ~temp); + } + temp = ramdac->gpio_data; + break; + case 0x2c: /* PLL Address */ + temp = ramdac->pll_addr; + break; + case 0x2d: /* Pixel clock PLL data */ + switch (ramdac->pll_addr & 3) { + case 0: + temp = ramdac->pix.n; + break; + case 1: + temp = ramdac->pix.m; + break; + case 2: + temp = ramdac->pix.p; + break; + case 3: + temp = 0x40; /*PLL locked to frequency*/ + break; + + default: + break; + } + break; + case 0x2e: /* Memory Clock PLL Data */ + switch ((ramdac->pll_addr >> 2) & 3) { + case 0: + temp = ramdac->mem.n; + break; + case 1: + temp = ramdac->mem.m; + break; + case 2: + temp = ramdac->mem.p; + break; + case 3: + temp = 0x40; /*PLL locked to frequency*/ + break; + + default: + break; + } + break; + case 0x2f: /* Loop Clock PLL Data */ + switch ((ramdac->pll_addr >> 4) & 3) { + case 0: + temp = ramdac->loop.n; + break; + case 1: + temp = ramdac->loop.m; + break; + case 2: + temp = ramdac->loop.p; + break; + + default: + break; + } + break; + case 0x39: /* MCLK/Loop Clock Control */ + temp = ramdac->mclk; + break; + case 0x3f: /* ID */ + temp = 0x26; + break; + + default: + break; + } + break; + case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ + index = ((svga->dac_addr - 1) & da_mask) | ((ramdac->ccr & 0x0c) << 6); + cd = (uint8_t *) ramdac->cursor64_data; + temp = cd[index]; + + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x0c: /* Cursor X Low Register (RS value = 1100) */ + temp = ramdac->hwc_x & 0xff; + break; + case 0x0d: /* Cursor X High Register (RS value = 1101) */ + temp = (ramdac->hwc_x >> 8) & 0xff; + break; + case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ + temp = ramdac->hwc_y & 0xff; + break; + case 0x0f: /* Cursor Y High Register (RS value = 1111) */ + temp = (ramdac->hwc_y >> 8) & 0xff; + break; + + default: + break; + } + + return temp; +} + +void +tvp3026_recalctimings(void *priv, svga_t *svga) +{ + const tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv; + + svga->interlace = !!(ramdac->ccr & 0x40); + /* TODO: Figure out gamma correction for 15/16 bpp color. */ + svga->lut_map = !!((svga->bpp >= 15 && (svga->bpp != 24)) && (ramdac->true_color & 0xf0) != 0x00); + + if (!(ramdac->clock_sel & 0x70)) { + if (ramdac->mcr != 0x98) { + svga->hdisp <<= 1; + svga->dots_per_clock <<= 1; + } + } +} + +uint32_t +tvp3026_conv_16to32(svga_t* svga, uint16_t color, uint8_t bpp) +{ + uint32_t ret = 0x00000000; + + if (svga->lut_map) { + if (bpp == 15) { + uint8_t b = getcolr(svga->pallook[(color & 0x1f) << 3]); + uint8_t g = getcolg(svga->pallook[(color & 0x3e0) >> 2]); + uint8_t r = getcolb(svga->pallook[(color & 0x7c00) >> 7]); + ret = (video_15to32[color] & 0xFF000000) | makecol(r, g, b); + } else { + uint8_t b = getcolr(svga->pallook[(color & 0x1f) << 3]); + uint8_t g = getcolg(svga->pallook[(color & 0x7e0) >> 3]); + uint8_t r = getcolb(svga->pallook[(color & 0xf800) >> 8]); + ret = (video_16to32[color] & 0xFF000000) | makecol(r, g, b); + } + } else + ret = (bpp == 15) ? video_15to32[color] : video_16to32[color]; + + return ret; +} + +void +tvp3026_hwcursor_draw(svga_t *svga, int displine) +{ + int comb; + int b0; + int b1; + uint16_t dat[2]; + int offset = svga->dac_hwcursor_latch.x + svga->dac_hwcursor_latch.xoff; + int pitch; + int bppl; + int mode; + int x_pos; + int y_pos; + uint32_t clr1; + uint32_t clr2; + uint32_t clr3; + uint32_t *p; + const uint8_t *cd; + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) svga->ramdac; + + clr1 = ramdac->extpallook[1]; + clr2 = ramdac->extpallook[2]; + clr3 = ramdac->extpallook[3]; + + /* The planes come in two parts, and each plane is 1bpp, + so a 32x32 cursor has 4 bytes per line, and a 64x64 + cursor has 8 bytes per line. */ + pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */ + /* A 32x32 cursor has 128 bytes per line, and a 64x64 + cursor has 512 bytes per line. */ + bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */ + mode = ramdac->mode; + + if (svga->interlace && svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; + + cd = (uint8_t *) ramdac->cursor64_data; + + for (int x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += 16) { + dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | cd[svga->dac_hwcursor_latch.addr + 1]; + dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | cd[svga->dac_hwcursor_latch.addr + bppl + 1]; + + for (uint8_t xx = 0; xx < 16; xx++) { + b0 = (dat[0] >> (15 - xx)) & 1; + b1 = (dat[1] >> (15 - xx)) & 1; + comb = (b0 | (b1 << 1)); + + y_pos = displine; + x_pos = (offset + svga->x_add) & 2047; + p = svga->monitor->target_buffer->line[y_pos]; + + if (offset >= svga->dac_hwcursor_latch.x) { + switch (mode) { + case 1: /* Three Color */ + switch (comb) { + case 1: + p[x_pos] = clr1; + break; + case 2: + p[x_pos] = clr2; + break; + case 3: + p[x_pos] = clr3; + break; + + default: + break; + } + break; + case 2: /* XGA */ + switch (comb) { + case 0: + p[x_pos] = clr1; + break; + case 1: + p[x_pos] = clr2; + break; + case 3: + p[x_pos] ^= 0xffffff; + break; + + default: + break; + } + break; + case 3: /* X-Windows */ + switch (comb) { + case 2: + p[x_pos] = clr1; + break; + case 3: + p[x_pos] = clr2; + break; + + default: + break; + } + break; + + default: + break; + } + } + offset++; + } + svga->dac_hwcursor_latch.addr += 2; + } + + if (svga->interlace && !svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; +} + +float +tvp3026_getclock(int clock, void *priv) +{ + const tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv; + int n; + int m; + int pl; + float f_vco; + float f_pll; + + if (clock == 0) + return 25175000.0; + if (clock == 1) + return 28322000.0; + + /*Fvco = 8 x Fref x (65 - M) / (65 - N)*/ + /*Fpll = Fvco / 2^P*/ + n = ramdac->pix.n & 0x3f; + m = ramdac->pix.m & 0x3f; + pl = ramdac->pix.p & 0x03; + f_vco = 8.0f * 14318184 * (float) (65 - m) / (float) (65 - n); + f_pll = f_vco / (float) (1 << pl); + + return f_pll; +} + +void +tvp3026_gpio(uint8_t (*read)(uint8_t cntl, void *priv), + void (*write)(uint8_t cntl, uint8_t val, void *priv), + void *cb_priv, void *priv) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv; + + ramdac->gpio_read = read; + ramdac->gpio_write = write; + ramdac->gpio_priv = cb_priv; +} + +void * +tvp3026_ramdac_init(const device_t *info) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) malloc(sizeof(tvp3026_ramdac_t)); + memset(ramdac, 0, sizeof(tvp3026_ramdac_t)); + + ramdac->type = info->local; + + ramdac->latch_cntl = 0x06; + ramdac->true_color = 0x80; + ramdac->mcr = 0x98; + ramdac->clock_sel = 0x07; + ramdac->mclk = 0x18; + + return ramdac; +} + +static void +tvp3026_ramdac_close(void *priv) +{ + tvp3026_ramdac_t *ramdac = (tvp3026_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + +const device_t tvp3026_ramdac_device = { + .name = "TI TVP3026 RAMDAC", + .internal_name = "tvp3026_ramdac", + .flags = 0, + .local = 0, + .init = tvp3026_ramdac_init, + .close = tvp3026_ramdac_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/pcem/vid_voodoo.cpp b/pcem/vid_voodoo.cpp index 37260741..7868bd6c 100644 --- a/pcem/vid_voodoo.cpp +++ b/pcem/vid_voodoo.cpp @@ -416,9 +416,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) case SST_swapbufferCMD: voodoo->cmd_written++; - thread_lock_mutex(voodoo->swap_mutex); + thread_wait_mutex(voodoo->swap_mutex); voodoo->swap_count++; - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); @@ -499,9 +499,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) if ((voodoo->fbiInit1 & FBIINIT1_VIDEO_RESET) && !(val & FBIINIT1_VIDEO_RESET)) { voodoo->line = 0; - thread_lock_mutex(voodoo->swap_mutex); + thread_wait_mutex(voodoo->swap_mutex); voodoo->swap_count = 0; - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); voodoo->retrace_count = 0; } voodoo->fbiInit1 = (val & ~5) | (voodoo->fbiInit1 & 5); @@ -1212,7 +1212,7 @@ void *voodoo_2d3d_card_init(int type) return voodoo; } -void *voodoo_init() +void *voodoo_init(const device_t *info) { voodoo_set_t *voodoo_set = (voodoo_set_t*)malloc(sizeof(voodoo_set_t)); uint32_t tmuConfig = 1; @@ -1470,13 +1470,12 @@ static device_config_t voodoo_config[] = device_t voodoo_device = { - "3DFX Voodoo Graphics", - DEVICE_PCI, + "3DFX Voodoo Graphics", NULL, + DEVICE_PCI, 0, voodoo_init, voodoo_close, NULL, - voodoo_speed_changed, NULL, - voodoo_add_status_info, - voodoo_config + voodoo_speed_changed, + NULL }; diff --git a/pcem/vid_voodoo_banshee.cpp b/pcem/vid_voodoo_banshee.cpp index 60411f9d..a1f0b04c 100644 --- a/pcem/vid_voodoo_banshee.cpp +++ b/pcem/vid_voodoo_banshee.cpp @@ -222,15 +222,15 @@ static int banshee_vga_vsync_enabled(banshee_t *banshee) static void banshee_update_irqs(banshee_t *banshee) { if (banshee->vblank_irq > 0 && banshee_vga_vsync_enabled(banshee)) { - pci_set_irq(NULL, PCI_INTA); + pci_set_irq(NULL, PCI_INTA, NULL); } else { - pci_clear_irq(NULL, PCI_INTA); + pci_clear_irq(NULL, PCI_INTA, NULL); } } static void banshee_vblank_start(svga_t* svga) { - banshee_t *banshee = (banshee_t*)svga->p; + banshee_t *banshee = (banshee_t*)svga->priv; if (banshee->vblank_irq >= 0) { banshee->vblank_irq = 1; banshee_update_irqs(banshee); @@ -365,7 +365,7 @@ static void banshee_updatemapping(banshee_t *banshee) static void banshee_render_16bpp_tiled(svga_t *svga) { - banshee_t *banshee = (banshee_t *)svga->p; + banshee_t *banshee = (banshee_t *)svga->priv; int x; int offset = 32; uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; @@ -408,7 +408,7 @@ static void banshee_render_16bpp_tiled(svga_t *svga) static void banshee_recalctimings(svga_t *svga) { - banshee_t *banshee = (banshee_t *)svga->p; + banshee_t *banshee = (banshee_t *)svga->priv; voodoo_t *voodoo = banshee->voodoo; /*7 R/W Horizontal Retrace End bit 5. - @@ -496,12 +496,12 @@ static void banshee_recalctimings(svga_t *svga) svga->overlay.x = voodoo->overlay.start_x; svga->overlay.y = voodoo->overlay.start_y; - svga->overlay.xsize = voodoo->overlay.size_x; - svga->overlay.ysize = voodoo->overlay.size_y; + svga->overlay.cur_xsize = voodoo->overlay.size_x; + svga->overlay.cur_ysize = voodoo->overlay.size_y; svga->overlay.pitch = (banshee->vidDesktopOverlayStride & VID_STRIDE_OVERLAY_MASK) >> VID_STRIDE_OVERLAY_SHIFT; if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) svga->overlay.pitch *= 128*32; - if (svga->overlay.xsize <= 0 || svga->overlay.ysize <= 0) + if (svga->overlay.cur_xsize <= 0 || svga->overlay.cur_ysize <= 0) svga->overlay.ena = 0; if (svga->overlay.ena) { @@ -696,8 +696,8 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) else svga->hwcursor.yoff = 0; svga->hwcursor.addr = (banshee->hwCurPatAddr & 0xfffff0) + (svga->hwcursor.yoff * 16); - svga->hwcursor.xsize = 64; - svga->hwcursor.ysize = 64; + svga->hwcursor.cur_xsize = 64; + svga->hwcursor.cur_ysize = 64; // pclog("hwCurLoc %08x %i\n", val, svga->hwcursor.y); break; case Video_hwCurC0: @@ -1380,9 +1380,9 @@ static void banshee_reg_writel(uint32_t addr, uint32_t val, void *p) break; case SST_swapPending: - thread_lock_mutex(voodoo->swap_mutex); + thread_wait_mutex(voodoo->swap_mutex); voodoo->swap_count++; - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); // voodoo->cmd_written++; break; @@ -1710,7 +1710,7 @@ static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p) void banshee_hwcursor_draw(svga_t *svga, int displine) { - banshee_t *banshee = (banshee_t *)svga->p; + banshee_t *banshee = (banshee_t *)svga->priv; int x, c; int x_off; uint32_t col0 = banshee->hwCurC0; @@ -2075,7 +2075,7 @@ void voodoo_generate_vb_filters(voodoo_t *voodoo, int fcr, int fcg) static void banshee_overlay_draw(svga_t *svga, int displine) { - banshee_t *banshee = (banshee_t *)svga->p; + banshee_t *banshee = (banshee_t *)svga->priv; voodoo_t *voodoo = banshee->voodoo; uint32_t *p; int x; @@ -2133,7 +2133,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) OVERLAY_SAMPLE(banshee->overlay_buffer[1]); if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { unsigned int x_coeff = (src_x & 0xfffff) >> 4; unsigned int coeffs[4] = { @@ -2165,7 +2165,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20]; uint32_t samp1 = banshee->overlay_buffer[1][src_x >> 20]; @@ -2191,7 +2191,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* leilei HACK - don't know of real 4x1 hscaled behavior yet, double for now */ { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { fil[x*3] = ((banshee->overlay_buffer[0][src_x >> 20])); fil[x*3+1] = ((banshee->overlay_buffer[0][src_x >> 20] >> 8)); @@ -2204,7 +2204,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { fil[x*3] = ((banshee->overlay_buffer[0][x])); fil[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); @@ -2216,7 +2216,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } if (y % 2 == 0) { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { fil[x*3] = banshee->voodoo->purpleline[fil[x*3+0]][0]; fil[x*3+1] = banshee->voodoo->purpleline[fil[x*3+1]][1]; @@ -2224,25 +2224,25 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } } - for (x=1; xoverlay_latch.xsize;x++) + for (x=1; xoverlay_latch.cur_xsize;x++) { fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; } - for (x=1; xoverlay_latch.xsize;x++) + for (x=1; xoverlay_latch.cur_xsize;x++) { fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x-1) *3]]; fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x-1) *3+1]]; fil[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil3[(x-1) *3+2]]; } - for (x=1; xoverlay_latch.xsize;x++) + for (x=1; xoverlay_latch.cur_xsize;x++) { fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; } - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x+1) *3]]; fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x+1) *3+1]]; @@ -2254,7 +2254,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) { if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { p[x] = banshee->overlay_buffer[0][src_x >> 20]; src_x += voodoo->overlay.vidOverlayDudx; @@ -2262,7 +2262,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) p[x] = banshee->overlay_buffer[0][x]; } } @@ -2290,7 +2290,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) src = &svga->vram[src_addr2 & svga->vram_mask]; OVERLAY_SAMPLE(banshee->overlay_buffer[1]); - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { samp1[x*3] = ((banshee->overlay_buffer[0][x])); samp1[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); @@ -2327,7 +2327,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* 2x2 on a scaled low res */ { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { p[x] = (fil[(src_x >> 20)*3+2] << 16) | (fil[(src_x >> 20)*3+1] << 8) | fil[(src_x >> 20)*3]; src_x += voodoo->overlay.vidOverlayDudx; @@ -2335,7 +2335,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { p[x] = (fil[x*3+2] << 16) | (fil[x*3+1] << 8) | fil[x*3]; } @@ -2345,7 +2345,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) { if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { p[x] = banshee->overlay_buffer[0][src_x >> 20]; @@ -2354,7 +2354,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) p[x] = banshee->overlay_buffer[0][x]; } } @@ -2364,7 +2364,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) default: if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { p[x] = banshee->overlay_buffer[0][src_x >> 20]; @@ -2373,7 +2373,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) p[x] = banshee->overlay_buffer[0][x]; } break; @@ -2398,17 +2398,17 @@ void banshee_set_overlay_addr(void *p, uint32_t addr) static void banshee_vsync_callback(svga_t *svga) { - banshee_t *banshee = (banshee_t *)svga->p; + banshee_t *banshee = (banshee_t *)svga->priv; voodoo_t *voodoo = banshee->voodoo; voodoo->retrace_count++; - thread_lock_mutex(voodoo->swap_mutex); + thread_wait_mutex(voodoo->swap_mutex); if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) { if (voodoo->swap_count > 0) voodoo->swap_count--; voodoo->swap_pending = 0; - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); voodoo->retrace_count = 0; @@ -2417,7 +2417,7 @@ static void banshee_vsync_callback(svga_t *svga) voodoo->frame_count++; } else - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); voodoo->overlay.src_y = 0; banshee->desktop_addr = banshee->vidDesktopStartAddr; @@ -2747,7 +2747,7 @@ static void *banshee_init_common(char *fn, int has_sgram, int type, int voodoo_t else mem_size = 16; /*SDRAM Banshee only supports 16 MB*/ - svga_init(&banshee->svga, banshee, mem_size << 20, + svga_init(NULL, &banshee->svga, banshee, mem_size << 20, banshee_recalctimings, banshee_in, banshee_out, banshee_hwcursor_draw, @@ -2852,19 +2852,19 @@ static void *banshee_init_common(char *fn, int has_sgram, int type, int voodoo_t return banshee; } -static void *banshee_init() +static void *banshee_init(const device_t *info) { return banshee_init_common("pci_sg.rom", 1, TYPE_BANSHEE, VOODOO_BANSHEE); } -static void *creative_banshee_init() +static void *creative_banshee_init(const device_t *info) { return banshee_init_common("blasterpci.rom", 0, TYPE_BANSHEE, VOODOO_BANSHEE); } -static void *v3_2000_init() +static void *v3_2000_init(const device_t *info) { return banshee_init_common("voodoo3_2000/2k11sd.rom", 0, TYPE_V3_2000, VOODOO_3); } -static void *v3_3000_init() +static void *v3_3000_init(const device_t *info) { return banshee_init_common("voodoo3_3000/3k12sd.rom", 0, TYPE_V3_3000, VOODOO_3); } @@ -3002,52 +3002,48 @@ static void banshee_add_status_info(char *s, int max_len, void *p) device_t voodoo_banshee_device = { - "Voodoo Banshee PCI (reference)", - DEVICE_PCI, + "Voodoo Banshee PCI (reference)", NULL, + DEVICE_PCI, 0, banshee_init, banshee_close, + NULL, banshee_available, banshee_speed_changed, - banshee_force_redraw, - banshee_add_status_info, - banshee_sgram_config + banshee_force_redraw }; device_t creative_voodoo_banshee_device = { - "Creative Labs 3D Blaster Banshee PCI", - DEVICE_PCI, + "Creative Labs 3D Blaster Banshee PCI", NULL, + DEVICE_PCI, 0, creative_banshee_init, banshee_close, + NULL, creative_banshee_available, banshee_speed_changed, - banshee_force_redraw, - banshee_add_status_info, - banshee_sdram_config + banshee_force_redraw }; device_t voodoo_3_2000_device = { - "Voodoo 3 2000 PCI", - DEVICE_PCI, + "Voodoo 3 2000 PCI", NULL, + DEVICE_PCI, 0, v3_2000_init, banshee_close, + NULL, v3_2000_available, banshee_speed_changed, - banshee_force_redraw, - banshee_add_status_info, - banshee_sdram_config + banshee_force_redraw }; device_t voodoo_3_3000_device = { - "Voodoo 3 3000 PCI", - DEVICE_PCI, + "Voodoo 3 3000 PCI", NULL, + DEVICE_PCI, 0, v3_3000_init, banshee_close, + NULL, v3_3000_available, banshee_speed_changed, - banshee_force_redraw, - banshee_add_status_info, - banshee_sdram_config + banshee_force_redraw }; diff --git a/pcem/vid_voodoo_display.cpp b/pcem/vid_voodoo_display.cpp index 34d7e13c..70c289ad 100644 --- a/pcem/vid_voodoo_display.cpp +++ b/pcem/vid_voodoo_display.cpp @@ -531,7 +531,7 @@ skip_draw: { voodoo_t *voodoo_1 = voodoo->set->voodoos[1]; - thread_lock_mutex(voodoo->swap_mutex); + thread_wait_mutex(voodoo->swap_mutex); /*Only swap if both Voodoos are waiting for buffer swap*/ if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval) && voodoo_1->swap_pending && (voodoo_1->retrace_count > voodoo_1->swap_interval)) @@ -549,7 +549,7 @@ skip_draw: if (voodoo_1->swap_count > 0) voodoo_1->swap_count--; voodoo_1->swap_pending = 0; - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); thread_set_event(voodoo->wake_fifo_thread); thread_set_event(voodoo_1->wake_fifo_thread); @@ -558,19 +558,19 @@ skip_draw: voodoo_1->frame_count++; } else - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); } } else { - thread_lock_mutex(voodoo->swap_mutex); + thread_wait_mutex(voodoo->swap_mutex); if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) { voodoo->front_offset = voodoo->swap_offset; if (voodoo->swap_count > 0) voodoo->swap_count--; voodoo->swap_pending = 0; - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); memset(voodoo->dirty_line, 1, 1024); voodoo->retrace_count = 0; @@ -578,7 +578,7 @@ skip_draw: voodoo->frame_count++; } else - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); } voodoo->v_retrace = 1; } diff --git a/pcem/vid_voodoo_fifo.cpp b/pcem/vid_voodoo_fifo.cpp index 1c873162..5a1c2b03 100644 --- a/pcem/vid_voodoo_fifo.cpp +++ b/pcem/vid_voodoo_fifo.cpp @@ -91,7 +91,7 @@ void voodoo_wait_for_swap_complete(voodoo_t *voodoo) thread_wait_event(voodoo->wake_fifo_thread, -1); thread_reset_event(voodoo->wake_fifo_thread); - thread_lock_mutex(voodoo->swap_mutex); + thread_wait_mutex(voodoo->swap_mutex); if ((voodoo->swap_pending && voodoo->flush) || FIFO_FULL) { /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ @@ -100,11 +100,11 @@ void voodoo_wait_for_swap_complete(voodoo_t *voodoo) if (voodoo->swap_count > 0) voodoo->swap_count--; voodoo->swap_pending = 0; - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); break; } else - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); } } diff --git a/pcem/vid_voodoo_reg.cpp b/pcem/vid_voodoo_reg.cpp index 63e590b5..d443bc90 100644 --- a/pcem/vid_voodoo_reg.cpp +++ b/pcem/vid_voodoo_reg.cpp @@ -56,10 +56,10 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) if (!(val & 1)) { banshee_set_overlay_addr(voodoo->p, voodoo->leftOverlayBuf); - thread_lock_mutex(voodoo->swap_mutex); + thread_wait_mutex(voodoo->swap_mutex); if (voodoo->swap_count > 0) voodoo->swap_count--; - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); voodoo->frame_count++; } else if (TRIPLE_BUFFER) @@ -104,10 +104,10 @@ void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) { memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); voodoo->front_offset = voodoo->params.front_offset; - thread_lock_mutex(voodoo->swap_mutex); + thread_wait_mutex(voodoo->swap_mutex); if (voodoo->swap_count > 0) voodoo->swap_count--; - thread_unlock_mutex(voodoo->swap_mutex); + thread_release_mutex(voodoo->swap_mutex); } else if (TRIPLE_BUFFER) { diff --git a/pcem/video.h b/pcem/video.h index e8a97e50..fd37eeb5 100644 --- a/pcem/video.h +++ b/pcem/video.h @@ -1,4 +1,10 @@ +#define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) +#define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) +#define getcolr(color) (((color) >> 16) & 0xFF) +#define getcolg(color) (((color) >> 8) & 0xFF) +#define getcolb(color) ((color) & 0xFF) + typedef struct { int w, h; @@ -24,7 +30,7 @@ extern PCBITMAP *buffer32; int video_card_available(int card); char *video_card_getname(int card); -struct device_t *video_card_getdevice(int card, int romset); +device_t *video_card_getdevice(int card, int romset); int video_card_has_config(int card, int romset); int video_card_getid(char *s); int video_old_to_new(int card); @@ -58,6 +64,7 @@ extern uint8_t fontdatksc5601[16384][32]; extern uint8_t fontdatksc5601_user[192][32]; extern uint32_t *video_15to32, *video_16to32; +extern uint32_t *video_6to8; extern int xsize,ysize; @@ -104,6 +111,7 @@ void video_init(); void closevideo(); void video_updatetiming(); +void video_force_resize_set_monitor(uint8_t res, int monitor_index); void hline(PCBITMAP *b, int x1, int y, int x2, int col); @@ -119,3 +127,86 @@ extern uint32_t cgapal[16]; #define DISPLAY_WHITE 5 void cgapal_rebuild(int display_type, int contrast); + +typedef struct video_timings_t { + int type; + int write_b; + int write_w; + int write_l; + int read_b; + int read_w; + int read_l; +} video_timings_t; + +typedef struct bitmap_t { + int w; + int h; + uint32_t *dat; + uint32_t *line[2112 * 2]; +} bitmap_t; + +typedef struct monitor_t { + char name[512]; + int mon_xsize; + int mon_ysize; + int mon_scrnsz_x; + int mon_scrnsz_y; + int mon_efscrnsz_y; + int mon_unscaled_size_x; + int mon_unscaled_size_y; + double mon_res_x; + double mon_res_y; + int mon_bpp; + bitmap_t *target_buffer; + int mon_video_timing_read_b; + int mon_video_timing_read_w; + int mon_video_timing_read_l; + int mon_video_timing_write_b; + int mon_video_timing_write_w; + int mon_video_timing_write_l; + int mon_overscan_x; + int mon_overscan_y; + int mon_force_resize; + int mon_fullchange; + int mon_changeframecount; + //atomic_int mon_screenshots; + uint32_t *mon_pal_lookup; + int *mon_cga_palette; + int mon_pal_lookup_static; /* Whether it should not be freed by the API. */ + int mon_cga_palette_static; /* Whether it should not be freed by the API. */ + const video_timings_t *mon_vid_timings; + int mon_vid_type; + //struct blit_data_struct *mon_blit_data_ptr; +} monitor_t; + +typedef struct monitor_settings_t { + int mon_window_x; /* (C) window size and position info. */ + int mon_window_y; + int mon_window_w; + int mon_window_h; + int mon_window_maximized; +} monitor_settings_t; + +extern int monitor_index_global; + +#define MONITORS_NUM 2 +extern monitor_t monitors[MONITORS_NUM]; + +enum { + VIDEO_ISA = 0, + VIDEO_MCA, + VIDEO_BUS, + VIDEO_PCI, + VIDEO_AGP +}; + +#define VIDEO_FLAG_TYPE_CGA 0 +#define VIDEO_FLAG_TYPE_MDA 1 +#define VIDEO_FLAG_TYPE_SPECIAL 2 +#define VIDEO_FLAG_TYPE_8514 3 +#define VIDEO_FLAG_TYPE_XGA 4 +#define VIDEO_FLAG_TYPE_NONE 5 +#define VIDEO_FLAG_TYPE_MASK 7 + +void video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index); +#define video_inform(type, video_timings_ptr) video_inform_monitor(type, video_timings_ptr, monitor_index_global) diff --git a/x86.cpp b/x86.cpp index 68cc6ddb..d92fd77f 100644 --- a/x86.cpp +++ b/x86.cpp @@ -48,6 +48,7 @@ #include "audio.h" #include "pcem/ibm.h" +#include "pcem/device.h" #include "pcem/pic.h" #include "pcem/pit.h" #include "pcem/timer.h" @@ -3554,7 +3555,7 @@ void *sb_2_init(); void *sb_pro_v1_init(); void *sb_pro_v2_init(); void *sb_16_init(); -void *cms_init(); +void *cms_init(const device_t*); static int x86_global_settings; @@ -3629,15 +3630,15 @@ static void set_sb_emu(struct x86_bridge *xb) switch (model) { case 0: - c = cms_init(); + c = cms_init(NULL); p = sb_1_init(); break; case 1: - c = cms_init(); + c = cms_init(NULL); p = sb_15_init(); break; case 2: - c = cms_init(); + c = cms_init(NULL); p = sb_2_init(); break; case 3: @@ -4004,7 +4005,7 @@ bool x86_bridge_init(struct autoconfig_info *aci, uae_u32 romtype, int type) if (xb->type >= TYPE_2286) { AT = 1; - nvr_device.init(); + nvr_device.init(&nvr_device); TCHAR path[MAX_DPATH]; cfgfile_resolve_path_out_load(currprefs.flashfile, path, MAX_DPATH, PATH_ROM); xb->cmossize = xb->type == TYPE_2386 ? 192 : 64; -- 2.47.3