This commit is contained in:
OBattler
2025-08-14 00:26:09 +02:00
6 changed files with 82 additions and 23 deletions

View File

@@ -253,6 +253,7 @@ typedef struct ibm8514_t {
int vdisp;
int vdisp2;
int disp_cntl;
int disp_cntl_2;
int interlace;
uint16_t subsys_cntl;
uint8_t subsys_stat;

View File

@@ -109,6 +109,7 @@ typedef struct mach_t {
uint16_t src_y;
int16_t bres_count;
uint16_t clock_sel;
uint16_t clock_sel_mode;
uint16_t crt_pitch;
uint16_t ge_pitch;
uint16_t src_pitch;

View File

@@ -140,6 +140,7 @@ typedef struct svga_t {
int vblankend;
int render_line_offset;
int start_retrace_latch;
int vga_mode;
/*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 :
0MB-1MB - VRAM

View File

@@ -2725,8 +2725,10 @@ mach_set_resolution(mach_t *mach, svga_t *svga)
if (dev->v_syncstart == 1)
dev->v_syncstart = 0x0601;
mach->accel.clock_sel_mode = 0;
mach_log("ATI Mode: set=%02x, dispcntl=%02x, h_total=%d, hdisp=%d, vdisp=%d, v_total=%04x, v_syncstart=%04x, hsync_start=%d, hsync_width=%d, clocksel=%02x, advancedcntl=%02x.\n", mach->shadow_set & 0x03, dev->disp_cntl, dev->h_total, dev->hdisp, dev->vdisp, dev->v_total, dev->v_syncstart, dev->hsync_start, dev->hsync_width, mach->accel.clock_sel & 0xff, dev->accel.advfunc_cntl & 0x05);
if ((dev->disp_cntl >> 5) == 1) { /*Enable the 8514/A subsystem and set modes according to the shadow sets if needed.*/
if ((dev->disp_cntl_2 >> 5) == 1) { /*Enable the 8514/A subsystem and set modes according to the shadow sets if needed.*/
switch (mach->shadow_set & 0x03) {
case 0x01:
if (!(dev->accel.advfunc_cntl & 0x04)) {
@@ -2735,6 +2737,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga)
dev->vdisp = 480;
dev->v_total = 0x0419;
dev->v_syncstart = 0x03d7;
mach->accel.clock_sel_mode = 0x50;
}
break;
case 0x02:
@@ -2744,6 +2747,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga)
dev->vdisp = 768;
dev->v_total = 0x0669;
dev->v_syncstart = 0x0601;
mach->accel.clock_sel_mode = 0x1c;
}
break;
@@ -2751,7 +2755,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga)
break;
}
svga_recalctimings(svga);
} else if ((dev->disp_cntl >> 5) == 2) { /*Reset 8514/A to defaults if needed.*/
} else if ((dev->disp_cntl_2 >> 5) == 2) { /*Reset 8514/A to defaults if needed.*/
if (dev->accel.advfunc_cntl & 0x04) {
if (dev->hdisp == 640) {
dev->h_total = 0x9e;
@@ -2759,6 +2763,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga)
dev->vdisp = 768;
dev->v_total = 0x0669;
dev->v_syncstart = 0x0601;
mach->accel.clock_sel_mode = 0x1c;
svga_recalctimings(svga);
}
} else {
@@ -2768,6 +2773,7 @@ mach_set_resolution(mach_t *mach, svga_t *svga)
dev->vdisp = 480;
dev->v_total = 0x0419;
dev->v_syncstart = 0x03d7;
mach->accel.clock_sel_mode = 0x50;
svga_recalctimings(svga);
}
}
@@ -2780,6 +2786,7 @@ ati8514_recalctimings(svga_t *svga)
{
mach_t *mach = (mach_t *) svga->ext8514;
ibm8514_t *dev = (ibm8514_t *) svga->dev8514;
int _8514_modes = 0;
mach_log("ON=%d, vgahdisp=%d.\n", dev->on, svga->hdisp);
if (dev->on) {
@@ -2790,6 +2797,14 @@ ati8514_recalctimings(svga_t *svga)
dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16)) << 2;
mach->accel.crt_offset = (mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2;
if (mach->accel.clock_sel_mode == 0x1c) {
dev->interlace = 1;
_8514_modes = 1;
} else if (mach->accel.clock_sel_mode == 0x50) {
dev->interlace = 0;
_8514_modes = 2;
}
dev->accel.ge_offset -= mach->accel.crt_offset;
mach_log("HDISP=%d, VDISP=%d, shadowset=%x, 8514/A mode=%x, clocksel=%02x.\n",
@@ -2811,13 +2826,22 @@ ati8514_recalctimings(svga_t *svga)
else if (dev->h_disp == 640)
dev->dispend = 480;
if (dev->accel.advfunc_cntl & 0x04)
svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / 44900000.0;
else
svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / 25175000.0;
dev->h_disp_time = dev->hdisp >> 3;
if (dev->interlace)
if (_8514_modes) {
svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock8514((mach->accel.clock_sel_mode >> 2) & 0x0f, svga->clock_gen8514) / 2;
if (mach->accel.clock_sel_mode & 0x40)
svga->clock_8514 *= 2;
} else {
svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock8514((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen8514) / 2;
if (mach->accel.clock_sel & 0x40)
svga->clock_8514 *= 2;
}
if (dev->interlace) {
dev->dispend >>= 1;
svga->clock_8514 /= 2;
}
mach_log("cntl=%d, hv(%d,%d), pitch=%d, rowoffset=%d, gextconfig=%03x, shadow=%x interlace=%d.\n",
dev->accel.advfunc_cntl & 0x04, dev->h_disp, dev->dispend, dev->pitch, dev->rowoffset,
@@ -2841,6 +2865,7 @@ mach_recalctimings(svga_t *svga)
mach_t *mach = (mach_t *) svga->priv;
ibm8514_t *dev = (ibm8514_t *) svga->dev8514;
int clock_sel;
int _8514_modes = 0;
if (mach->regs[0xad] & 0x08)
svga->hblankstart = ((mach->regs[0x0d] >> 2) << 8) + svga->crtc[2];
@@ -2886,6 +2911,10 @@ mach_recalctimings(svga_t *svga)
svga->ati_4color = 0;
}
svga->interlace = !!(mach->regs[0xbe] & 0x02);
if (svga->interlace)
svga->dispend >>= 1;
mach_log("ON=%d, override=%d, gelo=%04x, gehi=%04x, crtlo=%04x, crthi=%04x, vgahdisp=%d.\n", dev->on, svga->override, mach->accel.ge_offset_lo, mach->accel.ge_offset_hi, mach->accel.crt_offset_lo, mach->accel.crt_offset_hi, svga->hdisp);
if (dev->on) {
dev->memaddr_latch = 0; /*(mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2;*/
@@ -2896,6 +2925,14 @@ mach_recalctimings(svga_t *svga)
dev->accel.ge_offset = (mach->accel.ge_offset_lo | (mach->accel.ge_offset_hi << 16));
mach->accel.crt_offset = (mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16));
if (mach->accel.clock_sel_mode == 0x1c) {
dev->interlace = 1;
_8514_modes = 1;
} else if (mach->accel.clock_sel_mode == 0x50) {
dev->interlace = 0;
_8514_modes = 2;
}
if (dev->bpp) {
dev->accel.ge_offset <<= 1;
mach->accel.crt_offset <<= 1;
@@ -2928,14 +2965,22 @@ mach_recalctimings(svga_t *svga)
dev->h_disp_time = dev->hdisp >> 3;
svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen) / 2;
if (mach->accel.clock_sel & 0x40)
svga->clock_8514 *= 2;
if (_8514_modes) {
svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel_mode >> 2) & 0x0f, svga->clock_gen) / 2;
if (mach->accel.clock_sel_mode & 0x40)
svga->clock_8514 *= 2;
} else {
svga->clock_8514 = (cpuclock * (double) (1ULL << 32)) / svga->getclock((mach->accel.clock_sel >> 2) & 0x0f, svga->clock_gen) / 2;
if (mach->accel.clock_sel & 0x40)
svga->clock_8514 *= 2;
}
mach_log("8514/A clock sel=%x, divide reg ibm=%02x, divide reg vga=%02x.\n", clock_sel, mach->accel.clock_sel & 0x40, mach->regs[0xb8] & 0xc0);
mach_log("8514/A clock sel=%x, divide reg ibm=%02x, divide reg vga=%02x, vgainterlace=%x, interlace=%x.\n", clock_sel, mach->accel.clock_sel & 0x40, mach->regs[0xb8] & 0xc0, svga->interlace, dev->interlace);
if (dev->interlace)
if (dev->interlace) {
dev->dispend >>= 1;
svga->clock_8514 /= 2;
}
if (ATI_MACH32) {
switch ((mach->shadow_set >> 8) & 0x03) {
@@ -3064,6 +3109,9 @@ mach_recalctimings(svga_t *svga)
svga->gdcreg[5] & 0x60, svga->attrregs[0x10] & 0x40, mach->regs[0xb0] & 0x20, dev->on);
svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen);
mach_log("VGA clock sel=%x, divide reg=%02x.\n", clock_sel, mach->regs[0xb8] & 0xc0);
if (svga->interlace)
svga->clock /= 2;
if (ATI_MACH32) {
if (mach->regs[0xb8] & 0x40)
svga->clock *= 2;
@@ -3122,6 +3170,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u
switch (port) {
case 0x2e8:
mach_log("HTOTAL=%04x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01);
if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/
if (!(mach->shadow_cntl & 0x04))
dev->htotal = val;
@@ -3151,7 +3200,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u
if (len == 2) {
mach_log("HDISP and HTOTAL=%04x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01);
if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/
if (!(mach->shadow_cntl & 0x04))
if ((!(mach->shadow_cntl & 0x04)) && ((val >> 8) & 0xff))
dev->htotal = (val >> 8) & 0xff;
if (!(mach->shadow_cntl & 0x08)) {
@@ -3179,7 +3228,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u
if (len == 1) {
mach_log("HDISP and HTOTAL+1=%02x, len=%d, set=%x, ATI mode bit=%x.\n", val, len, mach->shadow_set & 0x03, mach->accel.clock_sel & 0x01);
if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) { /*For 8514/A mode, take the shadow sets into account.*/
if (!(mach->shadow_cntl & 0x04)) {
if (!(mach->shadow_cntl & 0x04) && val) {
dev->htotal = val;
}
}
@@ -3294,11 +3343,16 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u
break;
case 0x22e8:
if ((mach->shadow_cntl & 0x03) == 0x00)
dev->disp_cntl = val;
if ((mach->accel.clock_sel & 0x01) || (!(mach->accel.clock_sel & 0x01) && (mach->shadow_set & 0x03))) {
if ((mach->shadow_cntl & 0x03) == 0x00)
dev->disp_cntl = val;
}
mach_log("ATI 8514/A: DISP_CNTL write %04x=%02x, written=%02x, interlace=%d.\n",
port, val & 0x70, dev->disp_cntl & 0x70, dev->interlace);
if (((mach->shadow_cntl & 0x03) == 0x00) || !dev->local)
dev->disp_cntl_2 = val;
mach_log("ATI 8514/A: DISP_CNTL write %04x=%02x, written=%02x, interlace=%02x, shadowset=%02x, shadowcntl=%02x.\n",
port, val & 0x70, dev->disp_cntl & 0x70, dev->disp_cntl & 0x10, mach->shadow_set & 0x03, mach->shadow_cntl & 0x03);
svga_recalctimings(svga);
break;
@@ -7287,6 +7341,8 @@ ati8514_init(svga_t *svga, void *ext8514, void *dev8514)
dev->accel_out_fifo = ati8514_accel_out_fifo;
dev->vblank_start = ati8514_vblank_start;
svga->clock_gen8514 = device_add(&ati18811_0_device);
svga->getclock8514 = ics2494_getclock;
}
static int

View File

@@ -1102,10 +1102,8 @@ chips_69000_recalctimings(svga_t *svga)
svga->rowoffset |= (svga->crtc[0x41] & 0xF) << 8;
svga->interlace = !!(svga->crtc[0x70] & 0x80);
if (svga->hdisp == 1280 && svga->dispend == 1024) {
svga->interlace = 0;
}
if (svga->interlace)
svga->dispend >>= 1;
switch (chips->ext_regs[0x81] & 0xF) {
default:
@@ -1146,6 +1144,8 @@ chips_69000_recalctimings(svga_t *svga)
if (svga->dispend > (((chips->flat_panel_regs[0x30] | ((chips->flat_panel_regs[0x35] & 0xF) << 8)) + 1))) {
svga->dispend = svga->vsyncstart = svga->vblankstart = ((chips->flat_panel_regs[0x30] | ((chips->flat_panel_regs[0x35] & 0xF) << 8)) + 1);
if (svga->interlace)
svga->dispend >>= 1;
}
//svga->hdisp = ((chips->flat_panel_regs[0x20] | ((chips->flat_panel_regs[0x25] & 0xF) << 8)) + 1) << 3;
//svga->htotal = ((chips->flat_panel_regs[0x23] | ((chips->flat_panel_regs[0x26] & 0xF) << 8)) + 5) << 3;

View File

@@ -1050,7 +1050,7 @@ svga_recalctimings(svga_t *svga)
}
if (xga_active && (svga->xga != NULL)) {
if (xga->on)
crtcconst_xga = svga->clock_xga * svga->char_width;
crtcconst_xga = svga->clock_xga * 8;
}
#ifdef ENABLE_SVGA_LOG