Merge pull request #3959 from Cacodemon345/mga-millennium-ii

MGA: Add Matrox Millennium II video adapter
This commit is contained in:
Miran Grča
2023-12-29 10:55:10 +01:00
committed by GitHub
3 changed files with 399 additions and 82 deletions

View File

@@ -438,6 +438,7 @@ extern const device_t pgc_device;
extern const device_t millennium_device;
extern const device_t mystique_device;
extern const device_t mystique_220_device;
extern const device_t millennium_ii_device;
/* Oak OTI-0x7 */
extern const device_t oti037c_device;

View File

@@ -15,6 +15,7 @@
* Copyright 2008-2020 Sarah Walker.
*/
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
@@ -36,9 +37,10 @@
#include <86box/vid_svga.h>
#include <86box/vid_svga_render.h>
#define ROM_MILLENNIUM "roms/video/matrox/matrox2064wr2.BIN"
#define ROM_MYSTIQUE "roms/video/matrox/MYSTIQUE.VBI"
#define ROM_MYSTIQUE_220 "roms/video/matrox/Myst220_66-99mhz.vbi"
#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 FIFO_SIZE 65536
#define FIFO_MASK (FIFO_SIZE - 1)
@@ -111,6 +113,13 @@
#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_FIFOSTATUS 0x1e10
#define REG_STATUS 0x1e14
#define REG_ICLEAR 0x1e18
@@ -309,6 +318,7 @@
#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_TLUTLOAD (1 << 29)
#define MACCESS_NODITHER (1 << 30)
#define MACCESS_DIT555 (1 << 31)
@@ -383,6 +393,7 @@ enum {
MGA_2064W, /*Millennium*/
MGA_1064SG, /*Mystique*/
MGA_1164SG, /*Mystique 220*/
MGA_2164W, /*Millennium II*/
};
enum {
@@ -488,6 +499,8 @@ typedef struct mystique_t {
uint32_t src[4], ar[7],
dr[16], tmr[9];
uint64_t extended_dr[4];
struct
{
int sdydxl, scanleft, sdxl, sdy,
@@ -675,7 +688,7 @@ mystique_out(uint16_t addr, uint8_t val, void *priv)
case 0x3c6:
case 0x3c7:
case 0x3c9:
if (mystique->type == MGA_2064W) {
if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) {
tvp3026_ramdac_out(addr, 0, 0, val, svga->ramdac, svga);
return;
}
@@ -723,22 +736,57 @@ mystique_out(uint16_t addr, uint8_t val, void *priv)
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);
svga->rowoffset <<= 1;
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)) {
if ((mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8)) && !(mystique->type >= MGA_2164W)) {
svga->rowoffset <<= 1;
svga->ma_latch <<= 1;
}
svga->ma_latch <<= 1;
if (!(mystique->type >= MGA_2164W))
svga->ma_latch <<= 1;
if (mystique->type == MGA_2164W)
{
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;
if (svga->dispend >= 1024)
svga->rowoffset <<= 1;
break;
case 24:
svga->render = svga_render_24bpp_highres;
if (svga->hdisp >= 1024)
svga->rowoffset <<= 1;
break;
case 32:
svga->render = svga_render_32bpp_highres;
svga->rowoffset <<= 1;
if (svga->hdisp >= 1024) {
svga->ma_latch <<= 1;
}
break;
}
}
if (svga->ma_latch != mystique->ma_latch_old) {
if (svga->interlace && svga->oddeven)
svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) +
@@ -753,12 +801,22 @@ mystique_out(uint16_t addr, uint8_t val, void *priv)
if (mystique->crtcext_idx == 4) {
if (svga->gdcreg[6] & 0xc) {
/*64k banks*/
svga->read_bank = (val & 0x7f) << 16;
svga->write_bank = (val & 0x7f) << 16;
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*/
svga->read_bank = (val & 0x7e) << 16;
svga->write_bank = (val & 0x7e) << 16;
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;
}
}
}
break;
@@ -792,7 +850,7 @@ mystique_in(uint16_t addr, void *priv)
case 0x3c7:
case 0x3c8:
case 0x3c9:
if (mystique->type == MGA_2064W)
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);
@@ -906,7 +964,7 @@ mystique_recalctimings(svga_t *svga)
if (mystique->crtcext_regs[2] & CRTCX_R2_LINECOMP10)
svga->split |= 0x400;
if (mystique->type == MGA_2064W) {
if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) {
tvp3026_recalctimings(svga->ramdac, svga);
svga->interlace |= !!(mystique->crtcext_regs[0] & 0x80);
} else
@@ -922,7 +980,7 @@ mystique_recalctimings(svga_t *svga)
if (mystique->type >= MGA_1064SG)
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)) {
if ((mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8)) && !(mystique->type >= MGA_2164W)) {
svga->rowoffset <<= 1;
if (mystique->type >= MGA_1064SG)
svga->ma_latch <<= 1;
@@ -931,7 +989,8 @@ mystique_recalctimings(svga_t *svga)
if (mystique->type >= MGA_1064SG) {
/*Mystique, unlike most SVGA cards, allows display start to take
effect mid-screen*/
svga->ma_latch <<= 1;
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) {
@@ -944,34 +1003,63 @@ mystique_recalctimings(svga_t *svga)
mystique->ma_latch_old = svga->ma_latch;
}
svga->rowoffset <<= 1;
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;
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;
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;
if (svga->dispend >= 1024)
svga->rowoffset <<= 1;
break;
case 24:
svga->render = svga_render_24bpp_highres;
if (svga->hdisp >= 1024)
svga->rowoffset <<= 1;
break;
case 32:
svga->render = svga_render_32bpp_highres;
svga->rowoffset <<= 1;
if (svga->hdisp >= 1024) {
svga->ma_latch <<= 1;
}
break;
}
}
} else {
switch (svga->bpp) {
@@ -1037,7 +1125,7 @@ mystique_recalc_mapping(mystique_t *mystique)
mem_mapping_disable(&mystique->ctrl_mapping);
if (mystique->lfb_base)
mem_mapping_set_addr(&mystique->lfb_mapping, mystique->lfb_base, 0x800000);
mem_mapping_set_addr(&mystique->lfb_mapping, mystique->lfb_base, (mystique->type >= MGA_2164W) ? 0x1000000 : 0x800000);
else
mem_mapping_disable(&mystique->lfb_mapping);
@@ -1441,7 +1529,7 @@ mystique_ctrl_read_b(uint32_t addr, void *priv)
int rs2 = 0;
int rs3 = 0;
if ((mystique->type == MGA_2064W) && (addr & 0x3e00) == 0x3c00) {
if ((mystique->type == MGA_2064W || mystique->type == MGA_2164W) && (addr & 0x3e00) == 0x3c00) {
/*RAMDAC*/
addr_0x0f = addr & 0x0f;
@@ -1675,6 +1763,7 @@ mystique_accel_ctrl_write_b(uint32_t addr, uint8_t val, void *priv)
case REG_MACCESS + 3:
WRITE8(addr, mystique->maccess, val);
mystique->dwgreg.dither = mystique->maccess >> 30;
mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * ((mystique->maccess & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg;
break;
case REG_MCTLWTST:
@@ -1811,7 +1900,7 @@ mystique_accel_ctrl_write_b(uint32_t addr, uint8_t val, void *priv)
case REG_YDSTORG + 2:
case REG_YDSTORG + 3:
WRITE8(addr, mystique->dwgreg.ydstorg, val);
mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * 2 + mystique->dwgreg.zorg;
mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * ((mystique->maccess & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg;
break;
case REG_YTOP:
case REG_YTOP + 1:
@@ -2007,7 +2096,7 @@ mystique_ctrl_write_b(uint32_t addr, uint8_t val, void *priv)
int rs2 = 0;
int rs3 = 0;
if ((mystique->type == MGA_2064W) && (addr & 0x3e00) == 0x3c00) {
if ((mystique->type == MGA_2064W || mystique->type == MGA_2164W) && (addr & 0x3e00) == 0x3c00) {
/*RAMDAC*/
addr_0x0f = addr & 0x0f;
@@ -2290,7 +2379,7 @@ mystique_accel_ctrl_write_l(uint32_t addr, uint32_t val, void *priv)
case REG_ZORG:
mystique->dwgreg.zorg = val;
mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * 2 + mystique->dwgreg.zorg;
mystique->dwgreg.z_base = mystique->dwgreg.ydstorg * ((mystique->maccess & MACCESS_ZWIDTH) ? 4 : 2) + mystique->dwgreg.zorg;
break;
case REG_PLNWT:
@@ -2417,14 +2506,47 @@ mystique_accel_ctrl_write_l(uint32_t addr, uint32_t val, void *priv)
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;
@@ -2503,6 +2625,7 @@ mystique_ctrl_write_l(uint32_t addr, uint32_t val, void *priv)
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;
@@ -4113,6 +4236,29 @@ z_check(uint16_t z, uint16_t old_z, uint32_t z_mode) // mystique->dwgreg.dwgctrl
}
}
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)
{
@@ -4216,18 +4362,30 @@ blit_line(mystique_t *mystique, int closed)
x = mystique->dwgreg.xdst;
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) {
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];
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(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK)) {
if (z_check_pass) {
int r = 0;
int g = 0;
int b = 0;
if (z_write)
z_p[x] = z;
switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) {
case MACCESS_PWIDTH_16:
if (!(mystique->dwgreg.dr[4] & (1 << 23)))
@@ -4253,7 +4411,13 @@ blit_line(mystique_t *mystique, int closed)
else
mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK));
mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2];
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];
@@ -4266,7 +4430,13 @@ blit_line(mystique_t *mystique, int closed)
else
x += (mystique->dwgreg.sgn.sdxl ? -1 : 1);
mystique->dwgreg.dr[0] += mystique->dwgreg.dr[3];
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];
@@ -4326,6 +4496,7 @@ 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;
@@ -4491,12 +4662,14 @@ blit_trap(mystique_t *mystique)
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 * 2 + mystique->dwgreg.zorg) & mystique->vram_mask];
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];
@@ -4504,10 +4677,18 @@ blit_trap(mystique_t *mystique)
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]) {
uint16_t z = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15);
uint16_t old_z = z_p[x_l];
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(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;
@@ -4521,8 +4702,13 @@ blit_trap(mystique_t *mystique)
if (!(mystique->dwgreg.dr[12] & (1 << 23)))
b = (mystique->dwgreg.dr[12] >> 15) & 0xff;
if (z_write)
z_p[x_l] = z;
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:
@@ -4553,7 +4739,13 @@ blit_trap(mystique_t *mystique)
}
}
mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2];
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];
@@ -4566,7 +4758,13 @@ blit_trap(mystique_t *mystique)
mystique->pixel_count++;
}
mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3];
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];
@@ -4584,7 +4782,13 @@ blit_trap(mystique_t *mystique)
mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5];
dx = (int16_t) ((mystique->dwgreg.fxleft - old_x_l) & 0xffff);
mystique->dwgreg.dr[0] += dx * mystique->dwgreg.dr[2];
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];
@@ -4715,12 +4919,14 @@ blit_texture_trap(mystique_t *mystique)
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 * 2 + mystique->dwgreg.zorg) & mystique->vram_mask];
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];
@@ -4731,10 +4937,18 @@ blit_texture_trap(mystique_t *mystique)
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]) {
uint16_t z = ((int32_t) mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15);
uint16_t old_z = z_p[x_l];
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(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;
@@ -4808,8 +5022,13 @@ blit_texture_trap(mystique_t *mystique)
((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)
z_p[x_l] = z;
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:
@@ -4820,7 +5039,13 @@ skip_pixel:
mystique->pixel_count++;
mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2];
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];
@@ -4829,7 +5054,13 @@ skip_pixel:
mystique->dwgreg.tmr[8] += mystique->dwgreg.tmr[4];
}
mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3];
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];
@@ -4850,7 +5081,13 @@ skip_pixel:
mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5];
dx = (int16_t) ((mystique->dwgreg.fxleft - old_x_l) & 0xffff);
mystique->dwgreg.dr[0] += dx * mystique->dwgreg.dr[2];
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];
@@ -4888,6 +5125,7 @@ blit_bitblt(mystique_t *mystique)
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++) {
@@ -4896,7 +5134,7 @@ blit_bitblt(mystique_t *mystique)
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 = src_addr & 7;
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) {
@@ -4994,6 +5232,7 @@ blit_bitblt(mystique_t *mystique)
case DWGCTRL_ATYPE_RSTR:
switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) {
case DWGCTRL_BLTMOD_BMONOLEF:
case DWGCTRL_BLTMOD_BMONOWF:
if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN)
fatal("BITBLT RPL/RSTR BMONOLEF with pattern\n");
@@ -5005,7 +5244,7 @@ blit_bitblt(mystique_t *mystique)
while (1) {
uint32_t byte_addr = (src_addr >> 3) & mystique->vram_mask;
int bit_offset = src_addr & 7;
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;
@@ -5474,6 +5713,15 @@ mystique_pci_read(UNUSED(int func), int addr, void *priv)
mystique_t *mystique = (mystique_t *) priv;
uint8_t ret = 0x00;
if (mystique->type >= MGA_2164W)
{
/* Millennium II and later Matrox cards swap MGABASE1 and 2. */
if (addr >= 0x10 && addr <= 0x13)
addr += 0x4;
else if (addr >= 0x14 && addr <= 0x17)
addr -= 0x4;
}
if ((addr >= 0x30) && (addr <= 0x33) && !(mystique->pci_regs[0x43] & 0x40))
ret = 0x00;
else
@@ -5486,7 +5734,7 @@ mystique_pci_read(UNUSED(int func), int addr, void *priv)
break;
case 0x02:
ret = (mystique->type == MGA_2064W) ? 0x19 : 0x1a;
ret = (mystique->type == MGA_2164W) ? 0x1b : ((mystique->type == MGA_2064W) ? 0x19 : 0x1a);
break; /*MGA*/
case 0x03:
ret = 0x05;
@@ -5537,7 +5785,7 @@ mystique_pci_read(UNUSED(int func), int addr, void *priv)
ret = 0x00;
break; /*Linear frame buffer*/
case 0x16:
ret = (mystique->lfb_base >> 16) & 0x80;
ret = (mystique->type >= MGA_2164W) ? 0x00 : ((mystique->lfb_base >> 16) & 0x80);
break;
case 0x17:
ret = mystique->lfb_base >> 24;
@@ -5626,6 +5874,15 @@ mystique_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv)
{
mystique_t *mystique = (mystique_t *) priv;
if (mystique->type >= MGA_2164W)
{
/* Millennium II and later Matrox cards swap MGABASE1 and 2. */
if (addr >= 0x10 && addr <= 0x13)
addr += 0x4;
else if (addr >= 0x14 && addr <= 0x17)
addr -= 0x4;
}
switch (addr) {
case PCI_REG_COMMAND:
mystique->pci_regs[PCI_REG_COMMAND] = (val & 0x27) | 0x80;
@@ -5654,11 +5911,13 @@ mystique_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv)
break;
case 0x16:
if (mystique->type >= MGA_2164W)
break;
mystique->lfb_base = (mystique->lfb_base & 0xff000000) | ((val & 0x80) << 16);
mystique_recalc_mapping(mystique);
break;
case 0x17:
mystique->lfb_base = (mystique->lfb_base & 0x00800000) | (val << 24);
mystique->lfb_base = (mystique->lfb_base & ((mystique->type >= MGA_2164W) ? 0x00000000 : 0x00800000)) | (val << 24);
mystique_recalc_mapping(mystique);
break;
@@ -5785,6 +6044,8 @@ mystique_init(const device_t *info)
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
@@ -5800,8 +6061,8 @@ mystique_init(const device_t *info)
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique);
if (mystique->type == MGA_2064W) {
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_millennium);
if (mystique->type == MGA_2064W || mystique->type == MGA_2164W) {
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,
@@ -5811,6 +6072,8 @@ mystique_init(const device_t *info)
mystique->svga.ramdac = device_add(&tvp3026_ramdac_device);
mystique->svga.clock_gen = mystique->svga.ramdac;
mystique->svga.getclock = tvp3026_getclock;
if (mystique->vram_size >= 16)
mystique->svga.decode_mask = mystique->svga.vram_mask;
tvp3026_gpio(mystique_tvp3026_gpio_read, mystique_tvp3026_gpio_write, mystique, mystique->svga.ramdac);
} else {
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_matrox_mystique);
@@ -5945,6 +6208,12 @@ mystique_220_available(void)
return rom_present(ROM_MYSTIQUE_220);
}
static int
millennium_ii_available(void)
{
return rom_present(ROM_MILLENNIUM_II);
}
static void
mystique_speed_changed(void *priv)
{
@@ -5993,6 +6262,38 @@ static const device_config_t mystique_config[] = {
// 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
};
const device_t millennium_device = {
.name = "Matrox Millennium",
.internal_name = "millennium",
@@ -6034,3 +6335,17 @@ const device_t mystique_220_device = {
.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
};

View File

@@ -205,6 +205,7 @@ video_cards[] = {
{ &s3_diamond_stealth_4000_pci_device },
{ &s3_trio3d2x_pci_device },
{ &millennium_device },
{ &millennium_ii_device },
{ &mystique_device },
{ &mystique_220_device },
{ &tgui9440_pci_device },