From 1f5d00fe55aab2349733c726065082c41b80ee40 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 10:26:13 +1300 Subject: [PATCH 01/30] Generate CGA-to-EGA tables in video.c; Remove redundant table generation in vid_ega.c --- src/include/86box/vid_svga_render.h | 1 + src/video/vid_ega.c | 28 ---------------------------- src/video/video.c | 13 +++++++++++++ 3 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 0c48303c9..3ad9e401c 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -34,6 +34,7 @@ extern int cgablink; extern int scrollcache; extern uint8_t edatlookup[4][4]; +extern uint8_t egaremap2bpp[256]; void svga_recalc_remap_func(svga_t *svga); diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 957a81304..d4abebb39 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -61,8 +61,6 @@ static uint32_t pallook64[256]; static int ega_type = 0; static int old_overscan_color = 0; -uint8_t egaremap2bpp[256]; - /* 3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour): 7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines). */ int egaswitchread; @@ -1282,32 +1280,6 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) } } - for (c = 0; c < 4; c++) { - for (d = 0; d < 4; d++) { - edatlookup[c][d] = 0; - if (c & 1) - edatlookup[c][d] |= 1; - if (d & 1) - edatlookup[c][d] |= 2; - if (c & 2) - edatlookup[c][d] |= 0x10; - if (d & 2) - edatlookup[c][d] |= 0x20; - } - } - - for (c = 0; c < 256; c++) { - egaremap2bpp[c] = 0; - if (c & 0x01) - egaremap2bpp[c] |= 0x01; - if (c & 0x04) - egaremap2bpp[c] |= 0x02; - if (c & 0x10) - egaremap2bpp[c] |= 0x04; - if (c & 0x40) - egaremap2bpp[c] |= 0x08; - } - if (is_mono) { for (c = 0; c < 256; c++) { if (((c >> 3) & 3) == 0) diff --git a/src/video/video.c b/src/video/video.c index 34e602e39..4c561e229 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -78,6 +78,7 @@ volatile int screenshots = 0; uint8_t edatlookup[4][4]; +uint8_t egaremap2bpp[256]; uint8_t fontdat[2048][8]; /* IBM CGA font */ uint8_t fontdatm[2048][16]; /* IBM MDA font */ uint8_t fontdat2[2048][8]; /* IBM CGA 2nd instance font */ @@ -915,6 +916,18 @@ video_init(void) } } + for (uint16_t c = 0; c < 256; c++) { + egaremap2bpp[c] = 0; + if (c & 0x01) + egaremap2bpp[c] |= 0x01; + if (c & 0x04) + egaremap2bpp[c] |= 0x02; + if (c & 0x10) + egaremap2bpp[c] |= 0x04; + if (c & 0x40) + egaremap2bpp[c] |= 0x08; + } + video_6to8 = malloc(4 * 256); for (uint16_t c = 0; c < 256; c++) video_6to8[c] = calc_6to8(c); From 9703ccec45d914f598c9f3d467bec20a38749367 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 11:31:47 +1300 Subject: [PATCH 02/30] Initial merge of VGA 2bpp/4bpp lo/hi res renderers About half of it was taken from the EGA renderer. Also, the "force_old_addr" hack is kept here for now. --- src/video/vid_svga_render.c | 493 +++++++----------------------------- 1 file changed, 88 insertions(+), 405 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index c9369f09c..cee321347 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -16,6 +16,7 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. */ +#include #include #include #include @@ -392,202 +393,6 @@ svga_render_text_80_ksc5601(svga_t *svga) } } -void -svga_render_2bpp_lowres(svga_t *svga) -{ - int changed_offset; - int x; - uint8_t dat[2]; - uint32_t addr; - uint32_t *p; - uint32_t changed_addr; - - if ((svga->displine + svga->y_add) < 0) - return; - - if (svga->force_old_addr) { - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->ma; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; - svga->ma &= svga->vram_mask; - p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; - p += 16; - } - } - } else { - changed_addr = svga->remap_func(svga, svga->ma); - - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->remap_func(svga, svga->ma); - - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; - - svga->ma &= svga->vram_mask; - - p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; - - p += 16; - } - } - } -} - -void -svga_render_2bpp_highres(svga_t *svga) -{ - int changed_offset; - int x; - uint8_t dat[2]; - uint32_t addr; - uint32_t *p; - uint32_t changed_addr; - - if ((svga->displine + svga->y_add) < 0) - return; - - if (svga->force_old_addr) { - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->ma; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; - svga->ma &= svga->vram_mask; - p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; - p += 8; - } - } - } else { - changed_addr = svga->remap_func(svga, svga->ma); - - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->remap_func(svga, svga->ma); - - dat[0] = svga->vram[addr]; - dat[1] = svga->vram[addr | 0x1]; - if (svga->seqregs[1] & 4) - svga->ma += 2; - else - svga->ma += 4; - - svga->ma &= svga->vram_mask; - - p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; - p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; - p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; - p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; - p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; - p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; - p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; - p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; - - p += 8; - } - } - } -} - void svga_render_2bpp_headland_highres(svga_t *svga) { @@ -644,7 +449,7 @@ svga_render_2bpp_headland_highres(svga_t *svga) } void -svga_render_4bpp_lowres(svga_t *svga) +svga_render_4bpp(svga_t *svga, bool highres, bool cga2bpp) { int x; int oddeven; @@ -652,234 +457,112 @@ svga_render_4bpp_lowres(svga_t *svga) uint32_t *p; uint8_t edat[4]; uint8_t dat; - uint32_t changed_addr; + uint32_t changed_offset; - if ((svga->displine + svga->y_add) < 0) - return; - - if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->ma; - oddeven = 0; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - - if (svga->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; - - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - if (svga->seqregs[1] & 4) { - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); - svga->ma += 4; - } - svga->ma &= svga->vram_mask; - - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - - p += 16; - } - } - } else { - changed_addr = svga->remap_func(svga, svga->ma); - - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->remap_func(svga, svga->ma); - oddeven = 0; - - if (svga->seqregs[1] & 4) { - oddeven = (addr & 4) ? 1 : 0; - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); - svga->ma += 4; - } - svga->ma &= svga->vram_mask; - - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - - p += 16; - } - } - } -} - -void -svga_render_4bpp_highres(svga_t *svga) -{ - int changed_offset; - int x; - int oddeven; - uint32_t addr; - uint32_t *p; - uint8_t edat[4]; - uint8_t dat; - uint32_t changed_addr; + const bool blinked = svga->blink & 0x10; + const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); + const bool wordmode = ((svga->crtc[0x17] & 0x40) == 0); + const int dwshift = highres ? 0 : 1; + const int dotwidth = 1 << dwshift; + const int charwidth = dotwidth * 8; + const uint8_t blinkmask = (attrblink && blinked ? 0x8 : 0x0); if ((svga->displine + svga->y_add) < 0) return; if (svga->force_old_addr) { changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; - - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->ma; - oddeven = 0; - - if (!(svga->crtc[0x17] & 0x40)) { - addr = (addr << 1) & svga->vram_mask; - - if (svga->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; - - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; - } - - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - - if (svga->seqregs[1] & 4) { - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); - svga->ma += 4; - } - svga->ma &= svga->vram_mask; - - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - - p += 8; - } - } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_offset = svga->remap_func(svga, svga->ma) >> 12; + } - if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { - p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; + if (!(svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange)) { + return; + } + p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; - if (svga->firstline_draw == 2000) - svga->firstline_draw = svga->displine; - svga->lastline_draw = svga->displine; + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; - for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->remap_func(svga, svga->ma); - oddeven = 0; + for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += charwidth) { + oddeven = 0; - if (svga->seqregs[1] & 4) { + if (svga->force_old_addr) { + addr = svga->ma; + + if (wordmode) { + addr = (addr << 1) & svga->vram_mask; + + if (svga->seqregs[1] & 4) oddeven = (addr & 4) ? 1 : 0; - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); - svga->ma += 4; - } - svga->ma &= svga->vram_mask; - dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; - dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; - p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + addr &= ~7; - p += 8; + if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + addr |= 4; + if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + addr |= 4; } + + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + } else { + addr = svga->remap_func(svga, svga->ma); } + + if (svga->seqregs[1] & 4) { + if (!svga->force_old_addr) { + oddeven = (addr & 4) ? 1 : 0; + } + edat[0] = svga->vram[addr | oddeven]; + edat[2] = svga->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + svga->ma += 2; + } else { + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); + svga->ma += 4; + } + svga->ma &= svga->vram_mask; + + if (cga2bpp) { + // Remap CGA 2bpp-chunky data into fully planar data + uint8_t dat0 = egaremap2bpp[edat[1]] | (egaremap2bpp[edat[0]] << 4); + uint8_t dat1 = egaremap2bpp[edat[1] >> 1] | (egaremap2bpp[edat[0] >> 1] << 4); + uint8_t dat2 = egaremap2bpp[edat[3]] | (egaremap2bpp[edat[2]] << 4); + uint8_t dat3 = egaremap2bpp[edat[3] >> 1] | (egaremap2bpp[edat[2] >> 1] << 4); + edat[0] = dat0; + edat[1] = dat1; + edat[2] = dat2; + edat[3] = dat3; + } + + for (int i = 0; i < 8; i += 2) { + const int outoffs = i << dwshift; + const int inshift = 6 - i; + uint8_t dat = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) + | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); + // FIXME: Confirm blink behaviour is actually XOR on real hardware + uint32_t p0 = svga->pallook[svga->egapal[((dat >> 4) & svga->plane_mask) ^ blinkmask]]; + uint32_t p1 = svga->pallook[svga->egapal[(dat & svga->plane_mask) ^ blinkmask]]; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx] = p0; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx + dotwidth] = p1; + } + + p += charwidth; } } +// Remap these to the 4bpp renderer +void svga_render_2bpp_lowres(svga_t *svga) { svga_render_4bpp(svga, false, true); } +void svga_render_2bpp_highres(svga_t *svga) { svga_render_4bpp(svga, true, true); } +void svga_render_4bpp_lowres(svga_t *svga) { svga_render_4bpp(svga, false, false); } +void svga_render_4bpp_highres(svga_t *svga) { svga_render_4bpp(svga, true, false); } + void svga_render_8bpp_lowres(svga_t *svga) { From cfda3e1cce830b45245a5437e4c6c2a5b079306e Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 15:40:44 +1300 Subject: [PATCH 03/30] Add 8bpp support to the 4bpp renderer (breaks S3 Trio) It appears that the S3 Trio does something weird with its 8bpp modes. Specifically, it seems to ignore some of the flags needed for dword mode. I will keep looking into that and see if I can find a good solution. --- src/video/vid_svga_render.c | 184 ++++++++++++++++++++++++------------ 1 file changed, 124 insertions(+), 60 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index cee321347..79ca2418e 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -449,10 +449,9 @@ svga_render_2bpp_headland_highres(svga_t *svga) } void -svga_render_4bpp(svga_t *svga, bool highres, bool cga2bpp) +svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) { int x; - int oddeven; uint32_t addr; uint32_t *p; uint8_t edat[4]; @@ -461,16 +460,34 @@ svga_render_4bpp(svga_t *svga, bool highres, bool cga2bpp) const bool blinked = svga->blink & 0x10; const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); - const bool wordmode = ((svga->crtc[0x17] & 0x40) == 0); + + // FIXME: + // The following is likely how it works on an IBM VGA - that is, it works with its BIOS. + // But on an S3 Trio, mode 13h is broken - seemingly accepting the address shift but ignoring the increment. + const bool is_s3 = true; + const bool dwordload = ((svga->seqregs[0x01] & 0x10) != 0); + const bool wordload = ((svga->seqregs[0x01] & 0x04) != 0) && !dwordload; + const bool wordincr = ((svga->crtc[0x17] & 0x08) != 0); + const bool dwordincr = ((svga->crtc[0x14] & 0x20) != 0) && !wordincr; + const bool dwordshift = ((svga->crtc[0x14] & 0x40) != 0); + const bool wordshift = ((svga->crtc[0x17] & 0x40) == 0) && !dwordshift; + const uint32_t incbypow2 = (dwordshift ? 2 : wordshift ? 1 : 0); + const uint32_t incevery = (dwordincr ? 4 : wordincr ? 2 : 1); + const uint32_t loadevery = (dwordload ? 4 : wordload ? 2 : 1); + + const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ); + const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ); + const int dwshift = highres ? 0 : 1; const int dotwidth = 1 << dwshift; - const int charwidth = dotwidth * 8; + const int charwidth = dotwidth * (combine8bits ? 4 : 8); const uint8_t blinkmask = (attrblink && blinked ? 0x8 : 0x0); if ((svga->displine + svga->y_add) < 0) return; - if (svga->force_old_addr) { + // FIXME look into SVGA remap func to see what we actually need to do here --GM + if (true || svga->force_old_addr) { changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; } else { changed_offset = svga->remap_func(svga, svga->ma) >> 12; @@ -485,84 +502,129 @@ svga_render_4bpp(svga_t *svga, bool highres, bool cga2bpp) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; + uint32_t incr_counter = 0; + uint32_t load_counter = 0; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += charwidth) { - oddeven = 0; + if (load_counter == 0) { + // Find our address + if (true || svga->force_old_addr) { + addr = ((svga->ma & ~0x3) << incbypow2) & svga->vram_display_mask; - if (svga->force_old_addr) { - addr = svga->ma; + if (incbypow2 == 2) { + // Mapping is from the 82C451 datasheet, minus the chip-specific extensions. + // if (svga->ma & (4<<13)) addr |= 0x8; + // if (svga->ma & (4<<12)) addr |= 0x4; + } else if (incbypow2 == 1) { + if ((svga->crtc[0x17] & 0x20)) { + if (svga->ma & (4<<15)) addr |= 0x4; + } else { + if (svga->ma & (4<<13)) addr |= 0x4; + } + } else { + // Nothing + } - if (wordmode) { - addr = (addr << 1) & svga->vram_mask; - - if (svga->seqregs[1] & 4) - oddeven = (addr & 4) ? 1 : 0; - - addr &= ~7; - - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) - addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) - addr |= 4; + if (!(svga->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + if (!(svga->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + } else { + addr = svga->remap_func(svga, svga->ma); } - if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); - if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + // Load VRAM + *(uint32_t *)&edat[0] = *(uint32_t *)&svga->vram[addr]; + + if (shift4bit) { + // Remap VGA 4bpp-chunky data into fully planar data + // Plane 3 LSbit is aligned with MSbit + uint8_t tmpdat[4] = {0, 0, 0, 0}; + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 8; i++) { + tmpdat[j] <<= 1; + tmpdat[j] |= (edat[i>>1] >> (((0x1&~i)<<2)+j)) & 0x1; + } + } + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&tmpdat[0]); + } + + if (shift2bit) { + // Remap CGA 2bpp-chunky data into fully planar data + uint8_t dat0 = egaremap2bpp[edat[1]] | (egaremap2bpp[edat[0]] << 4); + uint8_t dat1 = egaremap2bpp[edat[1] >> 1] | (egaremap2bpp[edat[0] >> 1] << 4); + uint8_t dat2 = egaremap2bpp[edat[3]] | (egaremap2bpp[edat[2]] << 4); + uint8_t dat3 = egaremap2bpp[edat[3] >> 1] | (egaremap2bpp[edat[2] >> 1] << 4); + edat[0] = dat0; + edat[1] = dat1; + edat[2] = dat2; + edat[3] = dat3; + } } else { - addr = svga->remap_func(svga, svga->ma); + // According to the 82C451 VGA clone chipset datasheet, all 4 planes chain in a ring. + // So, rotate them all around. + *(uint32_t *)&edat[0] + = ((*(uint32_t *)&edat[0]) >> 8) + | ((*(uint32_t *)&edat[0]) << 24); + } + load_counter += 1; + if (load_counter >= loadevery) { + load_counter = 0; } - if (svga->seqregs[1] & 4) { - if (!svga->force_old_addr) { - oddeven = (addr & 4) ? 1 : 0; - } - edat[0] = svga->vram[addr | oddeven]; - edat[2] = svga->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - svga->ma += 2; - } else { - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); + if (incr_counter == 0) { svga->ma += 4; + // DISCREPANCY TODO FIXME 2/4bpp used vram_mask, 8bpp used vram_display_mask --GM + svga->ma &= svga->vram_display_mask; } - svga->ma &= svga->vram_mask; - - if (cga2bpp) { - // Remap CGA 2bpp-chunky data into fully planar data - uint8_t dat0 = egaremap2bpp[edat[1]] | (egaremap2bpp[edat[0]] << 4); - uint8_t dat1 = egaremap2bpp[edat[1] >> 1] | (egaremap2bpp[edat[0] >> 1] << 4); - uint8_t dat2 = egaremap2bpp[edat[3]] | (egaremap2bpp[edat[2]] << 4); - uint8_t dat3 = egaremap2bpp[edat[3] >> 1] | (egaremap2bpp[edat[2] >> 1] << 4); - edat[0] = dat0; - edat[1] = dat1; - edat[2] = dat2; - edat[3] = dat3; + incr_counter += 1; + if (incr_counter >= incevery) { + incr_counter = 0; } + // + // Now that we've converted it all to planar, convert it (back?) to chunky! + // for (int i = 0; i < 8; i += 2) { - const int outoffs = i << dwshift; const int inshift = 6 - i; - uint8_t dat = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) + uint8_t dat + = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); + // FIXME: Confirm blink behaviour is actually XOR on real hardware - uint32_t p0 = svga->pallook[svga->egapal[((dat >> 4) & svga->plane_mask) ^ blinkmask]]; - uint32_t p1 = svga->pallook[svga->egapal[(dat & svga->plane_mask) ^ blinkmask]]; - for (int subx = 0; subx < dotwidth; subx++) - p[outoffs + subx] = p0; - for (int subx = 0; subx < dotwidth; subx++) - p[outoffs + subx + dotwidth] = p1; + uint32_t c0 = ((dat >> 4) & svga->plane_mask) ^ blinkmask; + uint32_t c1 = (dat & svga->plane_mask) ^ blinkmask; + if (combine8bits) { + uint32_t ccombined = (c0 << 4) | c1; + uint32_t p0 = svga->map8[ccombined]; + const int outoffs = (i >> 1) << dwshift; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx] = p0; + } else { + uint32_t p0 = svga->pallook[svga->egapal[c0]]; + uint32_t p1 = svga->pallook[svga->egapal[c1]]; + const int outoffs = i << dwshift; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx] = p0; + for (int subx = 0; subx < dotwidth; subx++) + p[outoffs + subx + dotwidth] = p1; + } } p += charwidth; } } -// Remap these to the 4bpp renderer -void svga_render_2bpp_lowres(svga_t *svga) { svga_render_4bpp(svga, false, true); } -void svga_render_2bpp_highres(svga_t *svga) { svga_render_4bpp(svga, true, true); } -void svga_render_4bpp_lowres(svga_t *svga) { svga_render_4bpp(svga, false, false); } -void svga_render_4bpp_highres(svga_t *svga) { svga_render_4bpp(svga, true, false); } +// Remap these to the paletted renderer +// (*, highres, combine8bits) +void svga_render_2bpp_lowres(svga_t *svga) { svga_render_indexed_gfx(svga, false, false); } +void svga_render_2bpp_highres(svga_t *svga) { svga_render_indexed_gfx(svga, true, false); } +void svga_render_4bpp_lowres(svga_t *svga) { svga_render_indexed_gfx(svga, false, false); } +void svga_render_4bpp_highres(svga_t *svga) { svga_render_indexed_gfx(svga, true, false); } +void svga_render_8bpp_lowres(svga_t *svga) { svga_render_indexed_gfx(svga, false, true); } +void svga_render_8bpp_highres(svga_t *svga) { svga_render_indexed_gfx(svga, true, true); } +// TODO: Integrate more of this into the generic paletted renderer --GM +#if 0 void svga_render_8bpp_lowres(svga_t *svga) { @@ -717,6 +779,8 @@ svga_render_8bpp_highres(svga_t *svga) } } } +#endif + void svga_render_8bpp_tseng_lowres(svga_t *svga) From 2166ae0fb7b6f02d7a2aaccd65d60a7fb8f9099a Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 16:54:45 +1300 Subject: [PATCH 04/30] Get S3 Trio working in mode 13h + Mode-X again Outside of that, we're now using the remappers properly. --- src/include/86box/vid_svga_render.h | 2 ++ src/video/vid_svga_render.c | 23 ++++++++++------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 3ad9e401c..8a93b4089 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -53,6 +53,8 @@ void svga_render_4bpp_lowres(svga_t *svga); void svga_render_4bpp_highres(svga_t *svga); void svga_render_8bpp_lowres(svga_t *svga); void svga_render_8bpp_highres(svga_t *svga); +void svga_render_8bpp_s3_lowres(svga_t *svga); +void svga_render_8bpp_s3_highres(svga_t *svga); void svga_render_8bpp_tseng_lowres(svga_t *svga); void svga_render_8bpp_tseng_highres(svga_t *svga); void svga_render_8bpp_gs_lowres(svga_t *svga); diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 79ca2418e..afeddef85 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -461,19 +461,18 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) const bool blinked = svga->blink & 0x10; const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); - // FIXME: // The following is likely how it works on an IBM VGA - that is, it works with its BIOS. // But on an S3 Trio, mode 13h is broken - seemingly accepting the address shift but ignoring the increment. - const bool is_s3 = true; + // Forcing it to use incbypow2=0, incevery=1, loadevery=1 makes it behave. const bool dwordload = ((svga->seqregs[0x01] & 0x10) != 0); const bool wordload = ((svga->seqregs[0x01] & 0x04) != 0) && !dwordload; const bool wordincr = ((svga->crtc[0x17] & 0x08) != 0); const bool dwordincr = ((svga->crtc[0x14] & 0x20) != 0) && !wordincr; const bool dwordshift = ((svga->crtc[0x14] & 0x40) != 0); const bool wordshift = ((svga->crtc[0x17] & 0x40) == 0) && !dwordshift; - const uint32_t incbypow2 = (dwordshift ? 2 : wordshift ? 1 : 0); - const uint32_t incevery = (dwordincr ? 4 : wordincr ? 2 : 1); - const uint32_t loadevery = (dwordload ? 4 : wordload ? 2 : 1); + const uint32_t incbypow2 = combine8bits && svga->force_old_addr ? 0 : (dwordshift ? 2 : wordshift ? 1 : 0); + const uint32_t incevery = combine8bits && svga->force_old_addr ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); + const uint32_t loadevery = combine8bits && svga->force_old_addr ? 1 : (dwordload ? 4 : wordload ? 2 : 1); const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ); const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ); @@ -486,8 +485,7 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) if ((svga->displine + svga->y_add) < 0) return; - // FIXME look into SVGA remap func to see what we actually need to do here --GM - if (true || svga->force_old_addr) { + if (svga->force_old_addr) { changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; } else { changed_offset = svga->remap_func(svga, svga->ma) >> 12; @@ -507,13 +505,12 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += charwidth) { if (load_counter == 0) { // Find our address - if (true || svga->force_old_addr) { - addr = ((svga->ma & ~0x3) << incbypow2) & svga->vram_display_mask; + if (svga->force_old_addr) { + addr = ((svga->ma & ~0x3) << incbypow2); if (incbypow2 == 2) { - // Mapping is from the 82C451 datasheet, minus the chip-specific extensions. - // if (svga->ma & (4<<13)) addr |= 0x8; - // if (svga->ma & (4<<12)) addr |= 0x4; + if (svga->ma & (4<<15)) addr |= 0x8; + if (svga->ma & (4<<14)) addr |= 0x4; } else if (incbypow2 == 1) { if ((svga->crtc[0x17] & 0x20)) { if (svga->ma & (4<<15)) addr |= 0x4; @@ -531,6 +528,7 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) } else { addr = svga->remap_func(svga, svga->ma); } + addr &= svga->vram_display_mask; // Load VRAM *(uint32_t *)&edat[0] = *(uint32_t *)&svga->vram[addr]; @@ -781,7 +779,6 @@ svga_render_8bpp_highres(svga_t *svga) } #endif - void svga_render_8bpp_tseng_lowres(svga_t *svga) { From 81b8150a6bc2c427d85481d869a789c2781571cb Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 19:25:26 +1300 Subject: [PATCH 05/30] (S)VGA: Increment CRTC address just before it needs to be used This gives more likely behaviour when one loads more often than the address is incremented. The behaviour matches an Intel GMA 4500MHD (2008) which is the earliest hardware I'm able to test right now. --- src/video/vid_svga_render.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index afeddef85..b9330f4c0 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -569,14 +569,12 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) load_counter = 0; } - if (incr_counter == 0) { - svga->ma += 4; - // DISCREPANCY TODO FIXME 2/4bpp used vram_mask, 8bpp used vram_display_mask --GM - svga->ma &= svga->vram_display_mask; - } incr_counter += 1; if (incr_counter >= incevery) { incr_counter = 0; + svga->ma += 4; + // DISCREPANCY TODO FIXME 2/4bpp used vram_mask, 8bpp used vram_display_mask --GM + svga->ma &= svga->vram_display_mask; } // From 220d5fa237a49f9fbc3226bb1d23900e26c6dda1 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 19:32:43 +1300 Subject: [PATCH 06/30] (S)VGA: Do redraws if blink is enabled in graphics mode too Easy test case in QBASIC: SCREEN 10 PSET (2,0),2 There should be a blinking pixel in the top-left. --- src/video/vid_svga.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index c48baeb6e..b2347f87c 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -1001,7 +1001,7 @@ svga_poll(void *priv) else svga->cursoron = svga->blink & (16 + (16 * blink_delay)); - if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) + if (!(svga->blink & 15)) svga->fullchange = 2; svga->blink = (svga->blink + 1) & 0x7f; From 9903e12e69b76080e962f2c21e63110d4531ae60 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 19:39:30 +1300 Subject: [PATCH 07/30] (S)VGA: Update graphics mode blink behaviour to match something more feasible --- src/video/vid_svga_render.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index b9330f4c0..0a6be44fa 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -480,7 +480,8 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) const int dwshift = highres ? 0 : 1; const int dotwidth = 1 << dwshift; const int charwidth = dotwidth * (combine8bits ? 4 : 8); - const uint8_t blinkmask = (attrblink && blinked ? 0x8 : 0x0); + const uint8_t blinkmask = (attrblink ? 0x7 : 0xF); + const uint8_t blinkval = (attrblink && blinked ? 0x8 : 0x0); if ((svga->displine + svga->y_add) < 0) return; @@ -586,9 +587,13 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); - // FIXME: Confirm blink behaviour is actually XOR on real hardware - uint32_t c0 = ((dat >> 4) & svga->plane_mask) ^ blinkmask; - uint32_t c1 = (dat & svga->plane_mask) ^ blinkmask; + // FIXME: Confirm blink behaviour on real hardware + // This is how it behaves on an Intel GMA 4500MHD (2008). + // That includes 8bpp modes. + // However, an AMD Stoney Ridge (2016) seems to ignore blink in 8bpp modes. + + uint32_t c0 = ((dat >> 4) & svga->plane_mask & blinkmask) | blinkval; + uint32_t c1 = (dat & svga->plane_mask & blinkmask) | blinkval; if (combine8bits) { uint32_t ccombined = (c0 << 4) | c1; uint32_t p0 = svga->map8[ccombined]; From 35eb025c50333a612f15d7e4bc0837e3e741c3f9 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Tue, 21 Nov 2023 19:40:15 +1300 Subject: [PATCH 08/30] Remove some nonexistent function prototypes I was going to use the existing 8bpp renderers as-is for the S3 stuff but then found out how to make it work on the new generic renderer. --- src/include/86box/vid_svga_render.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 8a93b4089..3ad9e401c 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -53,8 +53,6 @@ void svga_render_4bpp_lowres(svga_t *svga); void svga_render_4bpp_highres(svga_t *svga); void svga_render_8bpp_lowres(svga_t *svga); void svga_render_8bpp_highres(svga_t *svga); -void svga_render_8bpp_s3_lowres(svga_t *svga); -void svga_render_8bpp_s3_highres(svga_t *svga); void svga_render_8bpp_tseng_lowres(svga_t *svga); void svga_render_8bpp_tseng_highres(svga_t *svga); void svga_render_8bpp_gs_lowres(svga_t *svga); From a3fa181b01a584b8cd880c933d537e29d12f7e1b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Tue, 21 Nov 2023 20:06:12 +0100 Subject: [PATCH 09/30] 8-bit renderer fix about the Tseng cards: Seems the Tseng cards are as incompatible as the S3 cards in terms of pure IBM VGA emulation, especially the chain4 stuff, so accomodate the fix to the renderer. Fixes 8bpp rendering on Tseng cards when invoked. --- src/video/vid_svga_render.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 0a6be44fa..fea4490d5 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -470,9 +470,9 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) const bool dwordincr = ((svga->crtc[0x14] & 0x20) != 0) && !wordincr; const bool dwordshift = ((svga->crtc[0x14] & 0x40) != 0); const bool wordshift = ((svga->crtc[0x17] & 0x40) == 0) && !dwordshift; - const uint32_t incbypow2 = combine8bits && svga->force_old_addr ? 0 : (dwordshift ? 2 : wordshift ? 1 : 0); - const uint32_t incevery = combine8bits && svga->force_old_addr ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); - const uint32_t loadevery = combine8bits && svga->force_old_addr ? 1 : (dwordload ? 4 : wordload ? 2 : 1); + const uint32_t incbypow2 = (combine8bits && (svga->force_old_addr || svga->packed_chain4)) ? 0 : (dwordshift ? 2 : wordshift ? 1 : 0); + const uint32_t incevery = (combine8bits && (svga->force_old_addr || svga->packed_chain4)) ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); + const uint32_t loadevery = (combine8bits && (svga->force_old_addr || svga->packed_chain4)) ? 1 : (dwordload ? 4 : wordload ? 2 : 1); const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ); const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ); From aeb44f1c5c0d71b832e965b733dad17a195f00a5 Mon Sep 17 00:00:00 2001 From: "Joakim L. Gilje" Date: Tue, 21 Nov 2023 23:37:50 +0100 Subject: [PATCH 10/30] update WM_CLASS instance name from vm_name --- src/qt/CMakeLists.txt | 2 ++ src/qt/qt_mainwindow.cpp | 19 +++++++++++++++++++ src/qt/x11_util.c | 22 ++++++++++++++++++++++ src/qt/x11_util.h | 9 +++++++++ 4 files changed, 52 insertions(+) create mode 100644 src/qt/x11_util.c create mode 100644 src/qt/x11_util.h diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 7ef93b4c0..fb96de1ea 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -371,6 +371,8 @@ if (APPLE AND CMAKE_MACOSX_BUNDLE) endif() if (UNIX AND NOT APPLE AND NOT HAIKU) + target_sources(ui PRIVATE x11_util.c) + find_package(X11 REQUIRED) target_link_libraries(ui PRIVATE X11::X11 X11::Xi) target_sources(ui PRIVATE evdev_keyboard.cpp xinput2_mouse.cpp) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index a372dbfb8..ee2311120 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -117,6 +117,11 @@ extern int qt_nvr_save(void); # undef KeyRelease #endif +#if defined Q_OS_UNIX && !defined Q_OS_HAIKU && !defined Q_OS_MACOS +#include +#include "x11_util.h" +#endif + #ifdef Q_OS_MACOS # include "cocoa_keyboard.hpp" // The namespace is required to avoid clashing typedefs; we only use this @@ -712,6 +717,20 @@ MainWindow::MainWindow(QWidget *parent) # endif {} #endif + +#if !defined Q_OS_MACOS && !defined Q_OS_HAIKU + if (QApplication::platformName().contains("xcb")) { + QTimer::singleShot(0, this, [this] { + auto whandle = windowHandle(); + if (! whandle) { + qWarning() << "No window handle"; + } else { + QPlatformWindow *window = whandle->handle(); + set_wm_class(window->winId(), vm_name); + } + }); + } +#endif } void diff --git a/src/qt/x11_util.c b/src/qt/x11_util.c new file mode 100644 index 000000000..e55033172 --- /dev/null +++ b/src/qt/x11_util.c @@ -0,0 +1,22 @@ +#include +#include +#include + +#include "x11_util.h" + +void set_wm_class(unsigned long window, char *res_name) { + Display* display = XOpenDisplay(NULL); + if (display == NULL) { + return; + } + + XClassHint hint; + XGetClassHint(display, window, &hint); + + hint.res_name = res_name; + XSetClassHint(display, window, &hint); + + // During testing, I've had to issue XGetClassHint after XSetClassHint + // to get the window manager to recognize the change. + XGetClassHint(display, window, &hint); +} diff --git a/src/qt/x11_util.h b/src/qt/x11_util.h new file mode 100644 index 000000000..f06db9419 --- /dev/null +++ b/src/qt/x11_util.h @@ -0,0 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + +void set_wm_class(unsigned long window, char *res_name); + +#ifdef __cplusplus +} +#endif From bea98c0e2c282926b473f0e11051a15f8480ade3 Mon Sep 17 00:00:00 2001 From: "Joakim L. Gilje" Date: Wed, 22 Nov 2023 08:22:46 +0100 Subject: [PATCH 11/30] added Q_OS_UNIX to ifdef guard around set_wm_class --- src/qt/qt_mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index ee2311120..f3503caeb 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -718,7 +718,7 @@ MainWindow::MainWindow(QWidget *parent) {} #endif -#if !defined Q_OS_MACOS && !defined Q_OS_HAIKU +#if defined Q_OS_UNIX && !defined Q_OS_MACOS && !defined Q_OS_HAIKU if (QApplication::platformName().contains("xcb")) { QTimer::singleShot(0, this, [this] { auto whandle = windowHandle(); From d19fe700f5e249d8f4b277004edcafe54fcc4106 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Thu, 23 Nov 2023 09:58:00 +1300 Subject: [PATCH 12/30] Use 8bpp renderer when attrregs.0x10.6 is set instead of when gdcreg.0x05.6 is set This allows correct emulation of the 4bpp chunky mode which is supported by many but not all chipsets. See discussion #3840 on GitHub. --- src/video/vid_svga.c | 125 ++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 55 deletions(-) diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index b2347f87c..1b9b3cf7c 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -639,67 +639,82 @@ svga_recalctimings(svga_t *svga) svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; svga->hdisp_old = svga->hdisp; - switch (svga->gdcreg[5] & 0x60) { - case 0x00: + if (svga->bpp <= 8) { + if (svga->attrregs[0x10] & 0x40) { /*8bpp mode*/ + svga->map8 = svga->pallook; + if (svga->lowres) /*Low res (320)*/ + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + } else { if (svga->seqregs[1] & 8) /*Low res (320)*/ svga->render = svga_render_4bpp_lowres; else svga->render = svga_render_4bpp_highres; - break; - case 0x20: /*4 colours*/ - if (svga->seqregs[1] & 8) /*Low res (320)*/ - svga->render = svga_render_2bpp_lowres; - else - svga->render = svga_render_2bpp_highres; - break; - case 0x40: - case 0x60: /*256+ colours*/ - switch (svga->bpp) { - case 8: - svga->map8 = svga->pallook; - if (svga->lowres) - svga->render = svga_render_8bpp_lowres; - else - svga->render = svga_render_8bpp_highres; - break; - case 15: - if (svga->lowres) - svga->render = svga_render_15bpp_lowres; - else - svga->render = svga_render_15bpp_highres; - break; - case 16: - if (svga->lowres) - svga->render = svga_render_16bpp_lowres; - else - svga->render = svga_render_16bpp_highres; - break; - case 17: - if (svga->lowres) - svga->render = svga_render_15bpp_mix_lowres; - else - svga->render = svga_render_15bpp_mix_highres; - break; - case 24: - if (svga->lowres) - svga->render = svga_render_24bpp_lowres; - else - svga->render = svga_render_24bpp_highres; - break; - case 32: - if (svga->lowres) - svga->render = svga_render_32bpp_lowres; - else - svga->render = svga_render_32bpp_highres; - break; + } + } else { + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: + case 0x60: /*256+ colours*/ + switch (svga->bpp) { + case 8: + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 17: + if (svga->lowres) + svga->render = svga_render_15bpp_mix_lowres; + else + svga->render = svga_render_15bpp_mix_highres; + break; + case 24: + if (svga->lowres) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; - default: - break; - } - break; + default: + break; + } + break; - default: - break; + default: + break; + } } } } From 81d285b883651588bbe9e28a889687afff7284cd Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Thu, 23 Nov 2023 10:04:04 +1300 Subject: [PATCH 13/30] Force 8bpp highres SVGA modes to "bypass" the shifter entirely The current implementation still uses the shifter forced to Shift 256 mode to keep things generic, but we can always opt for a separate scanline renderer. --- src/video/vid_svga_render.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index fea4490d5..b1ce6a88d 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -462,20 +462,27 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); // The following is likely how it works on an IBM VGA - that is, it works with its BIOS. - // But on an S3 Trio, mode 13h is broken - seemingly accepting the address shift but ignoring the increment. - // Forcing it to use incbypow2=0, incevery=1, loadevery=1 makes it behave. + // But on some cards, certain modes are broken. + // - S3 Trio: mode 13h (320x200x8), incbypow2 given as 2 treated as 0 + // - ET4000/W32i: mode 2Eh (640x480x8), incevery given as 2 treated as 1 + const bool forcepacked = combine8bits && (svga->force_old_addr || svga->packed_chain4); + + // SVGA cards with a high-resolution 8bpp mode may actually bypass the VGA shifter logic. + // - HT-216 (+ other Video7 chipsets?) has 0x3C4.0xC8 bit 4 which, when set to 1, loads bytes directly, bypassing the shifters. + const bool highres8bpp = combine8bits && highres; + const bool dwordload = ((svga->seqregs[0x01] & 0x10) != 0); const bool wordload = ((svga->seqregs[0x01] & 0x04) != 0) && !dwordload; const bool wordincr = ((svga->crtc[0x17] & 0x08) != 0); const bool dwordincr = ((svga->crtc[0x14] & 0x20) != 0) && !wordincr; const bool dwordshift = ((svga->crtc[0x14] & 0x40) != 0); const bool wordshift = ((svga->crtc[0x17] & 0x40) == 0) && !dwordshift; - const uint32_t incbypow2 = (combine8bits && (svga->force_old_addr || svga->packed_chain4)) ? 0 : (dwordshift ? 2 : wordshift ? 1 : 0); - const uint32_t incevery = (combine8bits && (svga->force_old_addr || svga->packed_chain4)) ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); - const uint32_t loadevery = (combine8bits && (svga->force_old_addr || svga->packed_chain4)) ? 1 : (dwordload ? 4 : wordload ? 2 : 1); + const uint32_t incbypow2 = forcepacked ? 0 : (dwordshift ? 2 : wordshift ? 1 : 0); + const uint32_t incevery = forcepacked ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); + const uint32_t loadevery = forcepacked ? 1 : (dwordload ? 4 : wordload ? 2 : 1); - const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ); - const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ); + const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ) || highres8bpp; + const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ) && !shift4bit; const int dwshift = highres ? 0 : 1; const int dotwidth = 1 << dwshift; From 7de7ea3fe1ccce660ec9101aadbab4b5a8bfd476 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Thu, 23 Nov 2023 10:08:52 +1300 Subject: [PATCH 14/30] Clean up unused variable --- src/video/vid_svga_render.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index b1ce6a88d..9f3474418 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -455,7 +455,6 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) uint32_t addr; uint32_t *p; uint8_t edat[4]; - uint8_t dat; uint32_t changed_offset; const bool blinked = svga->blink & 0x10; From a25a17bc62fb00b5b6cb72fb1dad9fd088f60768 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 22 Nov 2023 23:01:11 +0100 Subject: [PATCH 15/30] Default PIT to slow on 286 and 386. --- src/machine/machine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine.c b/src/machine/machine.c index c4ace6b4f..1684f312a 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -168,7 +168,7 @@ pit_irq0_timer(int new_out, int old_out) void machine_common_init(UNUSED(const machine_t *model)) { - uint8_t cpu_requires_fast_pit = is486 || (is8086 && (cpu_s->rspeed >= 8000000)); + uint8_t cpu_requires_fast_pit = is486 || (!is286 && is8086 && (cpu_s->rspeed >= 8000000)); /* System devices first. */ pic_init(); From c8c9fa2f91c2bf64ab26970234369e68eb37ed1e Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Thu, 23 Nov 2023 13:12:09 +1300 Subject: [PATCH 16/30] Implement 4bpp graphics mode blink properly on VGA Closes #3447 --- src/video/vid_svga_render.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 9f3474418..10303cc5f 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -486,7 +486,7 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) const int dwshift = highres ? 0 : 1; const int dotwidth = 1 << dwshift; const int charwidth = dotwidth * (combine8bits ? 4 : 8); - const uint8_t blinkmask = (attrblink ? 0x7 : 0xF); + const uint8_t blinkmask = (attrblink ? 0x8 : 0x0); const uint8_t blinkval = (attrblink && blinked ? 0x8 : 0x0); if ((svga->displine + svga->y_add) < 0) @@ -594,12 +594,24 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); // FIXME: Confirm blink behaviour on real hardware - // This is how it behaves on an Intel GMA 4500MHD (2008). - // That includes 8bpp modes. - // However, an AMD Stoney Ridge (2016) seems to ignore blink in 8bpp modes. - uint32_t c0 = ((dat >> 4) & svga->plane_mask & blinkmask) | blinkval; - uint32_t c1 = (dat & svga->plane_mask & blinkmask) | blinkval; + // The VGA 4bpp graphics blink logic was a pain to work out. + // + // If plane 3 is enabled in the attribute controller, then: + // - if bit 3 is 0, then we force the output of it to be 1. + // - if bit 3 is 1, then the output blinks. + // This can be tested with Lotus 1-2-3 release 2.3 with the WYSIWYG addon. + // + // If plane 3 is disabled in the attribute controller, then the output blinks. + // This can be tested with QBASIC SCREEN 10 - anything using color #2 should blink and nothing else. + // + // If you can simplify the following and have it still work, give yourself a medal. + // + uint32_t c0 = (dat >> 4) & 0xF; + uint32_t c1 = dat & 0xF; + c0 = ((c0 & svga->plane_mask & ~blinkmask) | ((c0 | ~svga->plane_mask) & blinkmask & blinkval)) ^ blinkmask; + c1 = ((c1 & svga->plane_mask & ~blinkmask) | ((c1 | ~svga->plane_mask) & blinkmask & blinkval)) ^ blinkmask; + if (combine8bits) { uint32_t ccombined = (c0 << 4) | c1; uint32_t p0 = svga->map8[ccombined]; From 97bdf1bdc0232594e67b68d819d6a37d2bbc8f32 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 24 Nov 2023 21:17:15 +0100 Subject: [PATCH 17/30] DEC/Tulip/Intel 21140/21143 fixes: Corrected serial ROM defaults, fixes NT 3.x's driver of the NIC while keeping compatibility with the other guests. --- src/network/net_eeprom_nmc93cxx.c | 95 ++-- src/network/net_tulip.c | 802 ++++++++++++++++-------------- 2 files changed, 483 insertions(+), 414 deletions(-) diff --git a/src/network/net_eeprom_nmc93cxx.c b/src/network/net_eeprom_nmc93cxx.c index 6e5b9c60c..b2038bdb5 100644 --- a/src/network/net_eeprom_nmc93cxx.c +++ b/src/network/net_eeprom_nmc93cxx.c @@ -16,34 +16,27 @@ /* Ported over from QEMU */ -#include -#include #include +#include #include +#include +#include +#include #include - +#define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/timer.h> #include <86box/nvr.h> +#include <86box/vid_ati_eeprom.h> #include <86box/net_eeprom_nmc93cxx.h> #include <86box/plat_unused.h> struct nmc93cxx_eeprom_t { - uint8_t tick; - uint8_t address; - uint8_t command; - uint8_t writable; - - uint8_t eecs; - uint8_t eesk; - uint8_t eedo; - + ati_eeprom_t dev; uint8_t addrbits; uint16_t size; - uint16_t data; char filename[1024]; - uint16_t contents[]; }; typedef struct nmc93cxx_eeprom_t nmc93cxx_eeprom_t; @@ -66,6 +59,16 @@ nmc93cxx_eeprom_log(int lvl, const char *fmt, ...) # define nmc93cxx_eeprom_log(lvl, fmt, ...) #endif +static void +nmc93cxx_eeprom_save(nmc93cxx_eeprom_t *eeprom) +{ + FILE *fp = nvr_fopen(eeprom->filename, "wb"); + if (fp) { + fwrite(eeprom->dev.data, 2, eeprom->size, fp); + fclose(fp); + } +} + static void * nmc93cxx_eeprom_init_params(UNUSED(const device_t *info), void *params) { @@ -99,19 +102,19 @@ nmc93cxx_eeprom_init_params(UNUSED(const device_t *info), void *params) eeprom->size = nwords; eeprom->addrbits = addrbits; /* Output DO is tristate, read results in 1. */ - eeprom->eedo = 1; + eeprom->dev.out = 1; if (params_details->filename) { FILE *fp = nvr_fopen(params_details->filename, "rb"); strncpy(eeprom->filename, params_details->filename, sizeof(eeprom->filename) - 1); if (fp) { - filldefault = !fread(eeprom->contents, sizeof(uint16_t), nwords, fp); + filldefault = !fread(eeprom->dev.data, sizeof(uint16_t), nwords, fp); fclose(fp); } } if (filldefault) { - memcpy(eeprom->contents, params_details->default_content, nwords * sizeof(uint16_t)); + memcpy(eeprom->dev.data, params_details->default_content, nwords * sizeof(uint16_t)); } return eeprom; @@ -120,47 +123,47 @@ nmc93cxx_eeprom_init_params(UNUSED(const device_t *info), void *params) void nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi) { - uint8_t tick = eeprom->tick; - uint8_t eedo = eeprom->eedo; - uint16_t address = eeprom->address; - uint8_t command = eeprom->command; + uint8_t tick = eeprom->dev.count; + uint8_t eedo = eeprom->dev.out; + uint16_t address = eeprom->dev.address; + uint8_t command = eeprom->dev.opcode; nmc93cxx_eeprom_log(1, "CS=%u SK=%u DI=%u DO=%u, tick = %u\n", eecs, eesk, eedi, eedo, tick); - if (!eeprom->eecs && eecs) { + if (!eeprom->dev.oldena && eecs) { /* Start chip select cycle. */ nmc93cxx_eeprom_log(1, "Cycle start, waiting for 1st start bit (0)\n"); tick = 0; command = 0x0; address = 0x0; - } else if (eeprom->eecs && !eecs) { + } else if (eeprom->dev.oldena && !eecs) { /* End chip select cycle. This triggers write / erase. */ - if (eeprom->writable) { + if (!eeprom->dev.wp) { uint8_t subcommand = address >> (eeprom->addrbits - 2); if (command == 0 && subcommand == 2) { /* Erase all. */ for (address = 0; address < eeprom->size; address++) { - eeprom->contents[address] = 0xffff; + eeprom->dev.data[address] = 0xffff; } } else if (command == 3) { /* Erase word. */ - eeprom->contents[address] = 0xffff; + eeprom->dev.data[address] = 0xffff; } else if (tick >= 2 + 2 + eeprom->addrbits + 16) { if (command == 1) { /* Write word. */ - eeprom->contents[address] &= eeprom->data; + eeprom->dev.data[address] &= eeprom->dev.dat; } else if (command == 0 && subcommand == 1) { /* Write all. */ for (address = 0; address < eeprom->size; address++) { - eeprom->contents[address] &= eeprom->data; + eeprom->dev.data[address] &= eeprom->dev.dat; } } } } /* Output DO is tristate, read results in 1. */ eedo = 1; - } else if (eecs && !eeprom->eesk && eesk) { + } else if (eecs && !eeprom->dev.oldclk && eesk) { /* Raising edge of clock shifts data in. */ if (tick == 0) { /* Wait for 1st start bit. */ @@ -194,8 +197,8 @@ nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi) tick++; address = ((address << 1) | eedi); if (tick == 2 + 2 + eeprom->addrbits) { - nmc93cxx_eeprom_log(1, "%s command, address = 0x%02x (value 0x%04x)\n", - opstring[command], address, eeprom->contents[address]); + nmc93cxx_eeprom_log(1, "Address = 0x%02x (value 0x%04x)\n", + address, eeprom->dev.data[address]); if (command == 2) { eedo = 0; } @@ -205,7 +208,7 @@ nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi) switch (address >> (eeprom->addrbits - 2)) { case 0: nmc93cxx_eeprom_log(1, "write disable command\n"); - eeprom->writable = 0; + eeprom->dev.wp = 1; break; case 1: nmc93cxx_eeprom_log(1, "write all command\n"); @@ -215,7 +218,7 @@ nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi) break; case 3: nmc93cxx_eeprom_log(1, "write enable command\n"); - eeprom->writable = 1; + eeprom->dev.wp = 0; break; default: @@ -223,7 +226,7 @@ nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi) } } else { /* Read, write or erase word. */ - eeprom->data = eeprom->contents[address]; + eeprom->dev.dat = eeprom->dev.data[address]; } } } else if (tick < 2 + 2 + eeprom->addrbits + 16) { @@ -231,28 +234,28 @@ nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi) tick++; if (command == 2) { /* Read word. */ - eedo = ((eeprom->data & 0x8000) != 0); + eedo = ((eeprom->dev.dat & 0x8000) != 0); } - eeprom->data <<= 1; - eeprom->data += eedi; + eeprom->dev.dat <<= 1; + eeprom->dev.dat += eedi; } else { nmc93cxx_eeprom_log(1, "additional unneeded tick, not processed\n"); } } /* Save status of EEPROM. */ - eeprom->tick = tick; - eeprom->eecs = eecs; - eeprom->eesk = eesk; - eeprom->eedo = eedo; - eeprom->address = address; - eeprom->command = command; + eeprom->dev.count = tick; + eeprom->dev.oldena = eecs; + eeprom->dev.oldclk = eesk; + eeprom->dev.out = eedo; + eeprom->dev.address = address; + eeprom->dev.opcode = command; } uint16_t nmc93cxx_eeprom_read(nmc93cxx_eeprom_t *eeprom) { /* Return status of pin DO (0 or 1). */ - return eeprom->eedo; + return eeprom->dev.out; } static void @@ -261,7 +264,7 @@ nmc93cxx_eeprom_close(void *priv) nmc93cxx_eeprom_t *eeprom = (nmc93cxx_eeprom_t *) priv; FILE *fp = nvr_fopen(eeprom->filename, "wb"); if (fp) { - fwrite(eeprom->contents, 2, eeprom->size, fp); + fwrite(eeprom->dev.data, 2, eeprom->size, fp); fclose(fp); } free(priv); @@ -271,7 +274,7 @@ uint16_t * nmc93cxx_eeprom_data(nmc93cxx_eeprom_t *eeprom) { /* Get EEPROM data array. */ - return &eeprom->contents[0]; + return &eeprom->dev.data[0]; } const device_t nmc93cxx_device = { diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index aaa60b4fc..8329e52e4 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -26,6 +26,7 @@ #include <86box/random.h> #include <86box/io.h> #include <86box/mem.h> +#include <86box/rom.h> #include <86box/dma.h> #include <86box/device.h> #include <86box/thread.h> @@ -33,8 +34,11 @@ #include <86box/net_eeprom_nmc93cxx.h> #include <86box/net_tulip.h> #include <86box/bswap.h> +#include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> +#define ROM_PATH_DEC21140 "roms/network/dec21140/BIOS13502.BIN" + #define CSR(_x) ((_x) << 3) #define BIT(x) (1 << x) @@ -288,6 +292,8 @@ #define ETH_ALEN 6 +static bar_t tulip_pci_bar[3]; + struct tulip_descriptor { uint32_t status; uint32_t control; @@ -298,15 +304,19 @@ struct tulip_descriptor { struct TULIPState { uint8_t pci_slot; uint8_t irq_state; + int PCIBase; + int MMIOBase; const device_t *device_info; uint16_t subsys_id; uint16_t subsys_ven_id; mem_mapping_t memory; + rom_t bios_rom; netcard_t *nic; nmc93cxx_eeprom_t *eeprom; uint32_t csr[16]; uint8_t pci_conf[256]; uint16_t mii_regs[32]; + uint8_t eeprom_data[128]; /* state for MII */ uint32_t old_csr9; @@ -323,7 +333,9 @@ struct TULIPState { uint16_t rx_frame_size; uint32_t rx_status; + uint32_t bios_addr; uint8_t filter[16][6]; + int has_bios; }; typedef struct TULIPState TULIPState; @@ -419,7 +431,7 @@ tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) len = s->rx_frame_len; } - dma_bm_write(desc->buf_addr1, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len, 1); + dma_bm_write(desc->buf_addr1, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len, 4); s->rx_frame_len -= len; } @@ -430,7 +442,7 @@ tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) len = s->rx_frame_len; } - dma_bm_write(desc->buf_addr2, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len, 1); + dma_bm_write(desc->buf_addr2, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len, 4); s->rx_frame_len -= len; } } @@ -475,15 +487,17 @@ tulip_receive(void *priv, uint8_t *buf, int size) struct tulip_descriptor desc; TULIPState *s = (TULIPState *) priv; + if (size < 14 || size > sizeof(s->rx_frame) - 4 - || s->rx_frame_len || tulip_rx_stopped(s)) { + || s->rx_frame_len || tulip_rx_stopped(s)) return 0; - } if (!tulip_filter_address(s, buf)) { + //pclog("Not a filter address.\n"); return 1; } + //pclog("Size = %d, FrameLen = %d, Buffer[%02x:%02x:%02x:%02x:%02x:%02x].\n", size, s->rx_frame_len, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); do { tulip_desc_read(s, s->current_rx_desc, &desc); @@ -512,6 +526,7 @@ tulip_receive(void *priv, uint8_t *buf, int size) tulip_desc_write(s, s->current_rx_desc, &desc); tulip_next_rx_descriptor(s, &desc); } while (s->rx_frame_len); + return 1; } @@ -571,6 +586,7 @@ tulip_mii_read(TULIPState *s, int phy, int reg) if (phy == 1) { ret = l80225_mii_readw(s->mii_regs, reg); } + //pclog("MII read phy = %02x, regs = %x, reg = %x, ret = %04x.\n", phy, s->mii_regs, reg, ret); return ret; } @@ -594,36 +610,43 @@ tulip_mii(TULIPState *s) int reg; if (!(changed & CSR9_MDC)) { + //pclog("No Change.\n"); return; } if (!(s->csr[9] & CSR9_MDC)) { + //pclog("No Change to MDC.\n"); return; } s->mii_bitcnt++; s->mii_word <<= 1; - if (s->csr[9] & CSR9_MDO && (s->mii_bitcnt < 16 || !(s->csr[9] & CSR9_MII))) { + if ((s->csr[9] & CSR9_MDO) && (s->mii_bitcnt < 16 || !(s->csr[9] & CSR9_MII))) { /* write op or address bits */ s->mii_word |= 1; + //pclog("WriteOp.\n"); } - if (s->mii_bitcnt >= 16 && (s->csr[9] & CSR9_MII)) { + if ((s->mii_bitcnt >= 16) && (s->csr[9] & CSR9_MII)) { if (s->mii_word & 0x8000) { s->csr[9] |= CSR9_MDI; + //pclog("CSR9 MDI set.\n"); } else { s->csr[9] &= ~CSR9_MDI; + //pclog("CSR9 MDI cleared.\n"); } } if (s->mii_word == 0xffffffff) { s->mii_bitcnt = 0; + //pclog("BitCnt = 0.\n"); } else if (s->mii_bitcnt == 16) { op = (s->mii_word >> 12) & 0x0f; phy = (s->mii_word >> 7) & 0x1f; reg = (s->mii_word >> 2) & 0x1f; + //pclog("BitCnt = 16, op=%d, phy=%x, reg=%x.\n"); if (op == 6) { s->mii_word = tulip_mii_read(s, phy, reg); } @@ -633,6 +656,7 @@ tulip_mii(TULIPState *s) reg = (s->mii_word >> 18) & 0x1f; data = s->mii_word & 0xffff; + //pclog("BitCnt = 32, op=%d, phy=%x, reg=%x.\n"); if (op == 5) { tulip_mii_write(s, phy, reg, data); } @@ -683,17 +707,20 @@ tulip_read(uint32_t addr, void *opaque) data = s->csr[addr >> 3]; break; } + //pclog("[%04X:%08X]: CSR9 read %02x, data = %08x.\n", CS, cpu_state.pc, addr, data); return data; } static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc) { + //pclog("TX FrameLen = %d.\n", s->tx_frame_len); if (s->tx_frame_len) { if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) { /* Internal or external Loopback */ tulip_receive(s, s->tx_frame, s->tx_frame_len); } else if (s->tx_frame_len <= sizeof(s->tx_frame)) { + //pclog("Transmit!.\n"); network_tx(s->nic, s->tx_frame, s->tx_frame_len); } } @@ -715,7 +742,7 @@ tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc) } if (len1) { dma_bm_read(desc->buf_addr1, - s->tx_frame + s->tx_frame_len, len1, 1); + s->tx_frame + s->tx_frame_len, len1, 4); s->tx_frame_len += len1; } @@ -724,7 +751,7 @@ tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc) } if (len2) { dma_bm_read(desc->buf_addr2, - s->tx_frame + s->tx_frame_len, len2, 1); + s->tx_frame + s->tx_frame_len, len2, 4); s->tx_frame_len += len2; } desc->status = (len1 + len2) ? 0 : 0x7fffffff; @@ -755,7 +782,7 @@ tulip_setup_frame(TULIPState *s, int len = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK; if (len == 192) { - dma_bm_read(desc->buf_addr1, buf, len, 1); + dma_bm_read(desc->buf_addr1, buf, len, 4); for (uint8_t i = 0; i < 16; i++) { tulip_setup_filter_addr(s, buf, i); } @@ -847,13 +874,13 @@ tulip_reset(void *priv) s->csr[0] = 0xfe000000; s->csr[1] = 0xffffffff; s->csr[2] = 0xffffffff; - s->csr[5] = 0xf0000000; + s->csr[5] = 0xfc000000; s->csr[6] = 0x32000040; - s->csr[7] = 0xf3fe0000; - s->csr[8] = 0xe0000000; + s->csr[7] = 0xfffe0000; + s->csr[8] = 0x00000000; s->csr[9] = 0xfff483ff; s->csr[11] = 0xfffe0000; - s->csr[12] = 0x000000c6; + s->csr[12] = 0xfffffec6; s->csr[13] = 0xffff0000; s->csr[14] = 0xffffffff; s->csr[15] = 0x8ff00000; @@ -867,6 +894,7 @@ tulip_write(uint32_t addr, uint32_t data, void *opaque) TULIPState *s = opaque; addr &= 127; + //pclog("[%04X:%08X]: Tulip Write >> 3: %02x, val=%08x.\n", CS, cpu_state.pc, addr >> 3, data); switch (addr) { case CSR(0): s->csr[0] = data; @@ -923,7 +951,7 @@ tulip_write(uint32_t addr, uint32_t data, void *opaque) break; case CSR(8): - s->csr[9] = data; + s->csr[8] = data; break; case CSR(9): @@ -969,13 +997,73 @@ tulip_write(uint32_t addr, uint32_t data, void *opaque) } static void -tulip_write_io(uint16_t addr, uint32_t data, void *opaque) +tulip_writeb_io(uint16_t addr, uint8_t data, void *opaque) { return tulip_write(addr, data, opaque); } +static void +tulip_writew_io(uint16_t addr, uint16_t data, void *opaque) +{ + return tulip_write(addr, data, opaque); +} + +static void +tulip_writel_io(uint16_t addr, uint32_t data, void *opaque) +{ + return tulip_write(addr, data, opaque); +} + +static void +tulip_mem_writeb(uint32_t addr, uint8_t data, void *opaque) +{ + return tulip_write(addr, data, opaque); +} + +static void +tulip_mem_writew(uint32_t addr, uint16_t data, void *opaque) +{ + return tulip_write(addr, data, opaque); +} + +static void +tulip_mem_writel(uint32_t addr, uint32_t data, void *opaque) +{ + return tulip_write(addr, data, opaque); +} + +static uint8_t +tulip_mem_readb(uint32_t addr, void *opaque) +{ + return tulip_read(addr, opaque); +} + +static uint16_t +tulip_mem_readw(uint32_t addr, void *opaque) +{ + return tulip_read(addr, opaque); +} + static uint32_t -tulip_read_io(uint16_t addr, void *opaque) +tulip_mem_readl(uint32_t addr, void *opaque) +{ + return tulip_read(addr, opaque); +} + +static uint8_t +tulip_readb_io(uint16_t addr, void *opaque) +{ + return tulip_read(addr, opaque); +} + +static uint16_t +tulip_readw_io(uint16_t addr, void *opaque) +{ + return tulip_read(addr, opaque); +} + +static uint32_t +tulip_readl_io(uint16_t addr, void *opaque) { return tulip_read(addr, opaque); } @@ -1009,7 +1097,7 @@ tulip_idblock_crc(uint16_t *srom) } static uint16_t -tulip_srom_crc(uint8_t *eeprom, size_t len) +tulip_srom_crc(uint8_t *eeprom) { unsigned long crc = 0xffffffff; unsigned long flippedcrc = 0; @@ -1017,7 +1105,7 @@ tulip_srom_crc(uint8_t *eeprom, size_t len) unsigned int msb; unsigned int bit; - for (size_t i = 0; i < len; i++) { + for (size_t i = 0; i < 126; i++) { currentbyte = eeprom[i]; for (bit = 0; bit < 8; bit++) { msb = (crc >> 31) & 1; @@ -1039,320 +1127,114 @@ tulip_srom_crc(uint8_t *eeprom, size_t len) return (flippedcrc ^ 0xffffffff) & 0xffff; } -static const uint8_t eeprom_default[128] = { - 0xf0, - 0x11, - 0x35, - 0x42, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x56, - 0x08, - 0x04, - 0x01, -#ifdef USE_DEC_OID - 0x00, - 0x80, - 0x48, -#else - 0x00, - 0x00, - 0xcb, -#endif - 0xb3, - 0x0e, - 0xa7, - 0x00, - 0x1e, - 0x00, - 0x00, - 0x00, - 0x08, - 0x01, - 0x8d, - 0x03, - 0x00, - 0x00, - 0x00, - 0x00, - 0x78, - 0xe0, - 0x01, - 0x00, - 0x50, - 0x00, - 0x18, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0xe8, - 0x6b, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x80, - 0x48, - 0xb3, - 0x0e, - 0xa7, - 0x40, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, -}; - -/* MAC address at 14h, card-specific at 17h. */ -static const uint8_t eeprom_default_24110[128] = { - 0x46, - 0x26, - 0x00, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x56, - 0x08, - 0x04, - 0x01, - 0x00, /* Obtained from a Linux dump from the real Kingston KNE110TX: 00:C0:F0:16:2A:CB */ - 0xc0, - 0xf0, - 0x16, - 0x2a, - 0xcb, - 0x00, - 0x1e, - 0x00, - 0x00, - 0x00, - 0x08, - 0xff, - 0x01, - 0x8d, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0x78, - 0xe0, - 0x01, - 0x00, - 0x50, - 0x00, - 0x18, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0xe8, - 0x6b, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x80, - 0x48, - 0xb3, - 0x0e, - 0xa7, - 0x40, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, -}; - static uint8_t tulip_pci_read(UNUSED(int func), int addr, void *priv) { const TULIPState *s = (TULIPState *) priv; + uint8_t ret = 0; switch (addr) { - default: - return s->pci_conf[addr & 0xFF]; case 0x00: - return 0x11; + ret = 0x11; + break; case 0x01: - return 0x10; + ret = 0x10; + break; case 0x02: - return s->device_info->local ? 0x09 : 0x19; + if (s->device_info->local) + ret = 0x09; + else + ret = 0x19; + break; case 0x03: - return 0x00; - case 0x07: - return 0x02; + ret = 0x00; + break; + case 0x04: + ret = s->pci_conf[0x04]; + break; + case 0x05: + ret = s->pci_conf[0x05]; + break; case 0x06: - return 0x80; - case 0x5: - return s->pci_conf[addr & 0xFF] & 1; - case 0x8: - return 0x30; - case 0x9: - return 0x0; - case 0xA: - return 0x0; - case 0xB: - return 0x2; + ret = 0x80; + break; + case 0x07: + ret = 0x02; + break; + case 0x08: + ret = 0x20; + break; + case 0x09: + ret = 0x00; + break; + case 0x0A: + ret = 0x00; + break; + case 0x0B: + ret = 0x02; + break; case 0x10: - return (s->pci_conf[addr & 0xFF] & 0x80) | 1; + ret = (tulip_pci_bar[0].addr_regs[0] & 0x80) | 0x01; + break; + case 0x11: + ret = tulip_pci_bar[0].addr_regs[1]; + break; + case 0x12: + ret = tulip_pci_bar[0].addr_regs[2]; + break; + case 0x13: + ret = tulip_pci_bar[0].addr_regs[3]; + break; case 0x14: - return s->pci_conf[addr & 0xFF] & 0x80; + ret = (tulip_pci_bar[1].addr_regs[0] & 0x80); + break; + case 0x15: + ret = tulip_pci_bar[1].addr_regs[1]; + break; + case 0x16: + ret = tulip_pci_bar[1].addr_regs[2]; + break; + case 0x17: + ret = tulip_pci_bar[1].addr_regs[3]; + break; case 0x2C: - return s->subsys_ven_id & 0xFF; + ret = s->subsys_ven_id & 0xFF; + break; case 0x2D: - return s->subsys_ven_id >> 8; + ret = s->subsys_ven_id >> 8; + break; case 0x2E: - return s->subsys_id & 0xFF; + ret = s->subsys_id & 0xFF; + break; case 0x2F: - return s->subsys_id >> 8; + ret = s->subsys_id >> 8; + break; + case 0x30: + ret = (tulip_pci_bar[2].addr_regs[0] & 0x01); + break; + case 0x31: + ret = tulip_pci_bar[2].addr_regs[1]; + break; + case 0x32: + ret = tulip_pci_bar[2].addr_regs[2]; + break; + case 0x33: + ret = tulip_pci_bar[2].addr_regs[3]; + break; + case 0x3C: + ret = s->pci_conf[0x3C]; + break; case 0x3D: - return PCI_INTA; + ret = PCI_INTA; + break; + case 0x3E: + case 0x3F: + ret = s->pci_conf[addr & 0xff]; + break; } + + //pclog("PCI read=%02x, ret=%02x.\n", addr, ret); + return ret; } static void @@ -1360,49 +1242,85 @@ tulip_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) { TULIPState *s = (TULIPState *) priv; + //pclog("PCI write=%02x, ret=%02x.\n", addr, val); switch (addr) { - case 0x4: + case 0x04: + s->pci_conf[0x04] = val & 0x07; + //pclog("PCI write cmd: IOBase=%04x, MMIOBase=%08x, val=%02x.\n", s->PCIBase, s->MMIOBase, s->pci_conf[0x04]); + io_removehandler(s->PCIBase, 128, + tulip_readb_io, tulip_readw_io, tulip_readl_io, + tulip_writeb_io, tulip_writew_io, tulip_writel_io, + priv); + if ((s->PCIBase != 0) && (val & PCI_COMMAND_IO)) + io_sethandler(s->PCIBase, 128, + tulip_readb_io, tulip_readw_io, tulip_readl_io, + tulip_writeb_io, tulip_writew_io, tulip_writel_io, + priv); + //pclog("PCI write cmd: IOBase=%04x, MMIOBase=%08x, val=%02x.\n", s->PCIBase, s->MMIOBase, s->pci_conf[0x04]); mem_mapping_disable(&s->memory); - io_removehandler((s->pci_conf[0x10] & 0x80) | (s->pci_conf[0x11] << 8), 128, - NULL, NULL, tulip_read_io, - NULL, NULL, tulip_write_io, - priv); - s->pci_conf[addr & 0xFF] = val; - if (val & PCI_COMMAND_IO) - io_sethandler((s->pci_conf[0x10] & 0x80) | (s->pci_conf[0x11] << 8), 128, - NULL, NULL, tulip_read_io, - NULL, NULL, tulip_write_io, - priv); - if ((val & PCI_COMMAND_MEM) && s->memory.size) - mem_mapping_enable(&s->memory); + if ((s->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) + mem_mapping_set_addr(&s->memory, s->MMIOBase, 128); break; - case 0x5: - s->pci_conf[addr & 0xFF] = val & 1; + case 0x05: + s->pci_conf[0x05] = val & 1; break; case 0x10: case 0x11: - io_removehandler((s->pci_conf[0x10] & 0x80) | (s->pci_conf[0x11] << 8), 128, - NULL, NULL, tulip_read_io, - NULL, NULL, tulip_write_io, + case 0x12: + case 0x13: + io_removehandler(s->PCIBase, 128, + tulip_readb_io, tulip_readw_io, tulip_readl_io, + tulip_writeb_io, tulip_writew_io, tulip_writel_io, priv); - s->pci_conf[addr & 0xFF] = val; - if (s->pci_conf[0x4] & PCI_COMMAND_IO) - io_sethandler((s->pci_conf[0x10] & 0x80) | (s->pci_conf[0x11] << 8), 128, - NULL, NULL, tulip_read_io, - NULL, NULL, tulip_write_io, - priv); + tulip_pci_bar[0].addr_regs[addr & 3] = val; + tulip_pci_bar[0].addr &= 0xffffff80; + s->PCIBase = tulip_pci_bar[0].addr; + if (s->pci_conf[0x4] & PCI_COMMAND_IO) { + //pclog("PCI write=%02x, base=%04x, io?=%x.\n", addr, s->PCIBase, s->pci_conf[0x4] & PCI_COMMAND_IO); + if (s->PCIBase != 0) + io_sethandler(s->PCIBase, 128, + tulip_readb_io, tulip_readw_io, tulip_readl_io, + tulip_writeb_io, tulip_writew_io, tulip_writel_io, + priv); + } break; case 0x14: case 0x15: case 0x16: case 0x17: - s->pci_conf[addr & 0xFF] = val; - if (s->pci_conf[0x4] & PCI_COMMAND_MEM) - mem_mapping_set_addr(&s->memory, (s->pci_conf[0x14] & 0x80) | (s->pci_conf[0x15] << 8) | (s->pci_conf[0x16] << 16) | (s->pci_conf[0x17] << 24), 128); + mem_mapping_disable(&s->memory); + tulip_pci_bar[1].addr_regs[addr & 3] = val; + tulip_pci_bar[1].addr &= 0xffffff80; + s->MMIOBase = tulip_pci_bar[1].addr; + if (s->pci_conf[0x4] & PCI_COMMAND_MEM) { + //pclog("PCI write=%02x, mmiobase=%08x, mmio?=%x.\n", addr, s->PCIBase, s->pci_conf[0x4] & PCI_COMMAND_MEM); + if (s->MMIOBase != 0) + mem_mapping_set_addr(&s->memory, s->MMIOBase, 128); + } break; + case 0x30: /* PCI_ROMBAR */ + case 0x31: /* PCI_ROMBAR */ + case 0x32: /* PCI_ROMBAR */ + case 0x33: /* PCI_ROMBAR */ + if (!s->has_bios) + return; + + mem_mapping_disable(&s->bios_rom.mapping); + tulip_pci_bar[2].addr_regs[addr & 3] = val; + tulip_pci_bar[2].addr &= 0xffff0001; + s->bios_addr = tulip_pci_bar[2].addr & 0xffff0000; + if (tulip_pci_bar[2].addr_regs[0] & 0x01) { + if (s->bios_addr != 0) + mem_mapping_set_addr(&s->bios_rom.mapping, s->bios_addr, 0x10000); + } + return; case 0x3C: - s->pci_conf[addr & 0xFF] = val; - break; + s->pci_conf[0x3c] = val; + return; + case 0x3E: + case 0x3F: + s->pci_conf[addr & 0xff] = val; + return; } } @@ -1414,18 +1332,69 @@ nic_init(const device_t *info) TULIPState *s = calloc(1, sizeof(TULIPState)); char filename[1024] = { 0 }; uint32_t mac; + uint8_t *eeprom_data; if (!s) return NULL; - + + if (info->local) { + s->bios_addr = 0xD0000; + s->has_bios = device_get_config_int("bios"); + } else { + s->bios_addr = 0; + s->has_bios = 0; + } + + mem_mapping_add(&s->memory, 0x0fffff00, 128, tulip_mem_readb, tulip_mem_readw, tulip_mem_readl, tulip_mem_writeb, tulip_mem_writew, tulip_mem_writel, NULL, MEM_MAPPING_EXTERNAL, s); + mem_mapping_disable(&s->memory); + s->device_info = info; - memcpy(eeprom_default_local, info->local ? eeprom_default_24110 : eeprom_default, - sizeof(eeprom_default)); + + /*Subsystem Vendor ID*/ + s->eeprom_data[0] = info->local ? 0x25 : 0x11; + s->eeprom_data[1] = 0x10; + + /*Subsystem ID*/ + s->eeprom_data[2] = info->local ? 0x10 : 0x0a; + s->eeprom_data[3] = info->local ? 0x03 : 0x50; + + /*Cardbus CIS Pointer low*/ + s->eeprom_data[4] = 0x00; + s->eeprom_data[5] = 0x00; + + /*Cardbus CIS Pointer high*/ + s->eeprom_data[6] = 0x00; + s->eeprom_data[7] = 0x00; + + /*ID Reserved1*/ + for (int i = 0; i < 7; i++) + s->eeprom_data[8 + i] = 0x00; + + /*MiscHwOptions*/ + s->eeprom_data[15] = 0x00; + + /*ID_BLOCK_CRC*/ + tulip_idblock_crc((uint16_t *) s->eeprom_data); + + /*Func0_HwOptions*/ + s->eeprom_data[17] = 0x00; + + /*SROM Format Version 1, compatible with older guests*/ + s->eeprom_data[18] = 0x01; + + /*Controller Count*/ + s->eeprom_data[19] = 0x01; + + /*DEC OID*/ + s->eeprom_data[20] = 0x00; + s->eeprom_data[21] = 0x00; + s->eeprom_data[22] = 0xf8; + if (info->local == 2) { /* Microsoft VPC DEC Tulip. */ - eeprom_default_local[0x14] = 0x00; - eeprom_default_local[0x15] = 0x03; - eeprom_default_local[0x16] = 0x0f; + s->eeprom_data[20] = 0x00; + s->eeprom_data[21] = 0x03; + s->eeprom_data[22] = 0x0f; } /* See if we have a local MAC address configured. */ @@ -1434,24 +1403,88 @@ nic_init(const device_t *info) /* Set up our BIA. */ if (mac & 0xff000000) { /* Generate new local MAC. */ - eeprom_default_local[0x17] = random_generate(); - eeprom_default_local[0x18] = random_generate(); - eeprom_default_local[0x19] = random_generate(); - mac = (((int) eeprom_default_local[0x17]) << 16); - mac |= (((int) eeprom_default_local[0x18]) << 8); - mac |= ((int) eeprom_default_local[0x19]); + s->eeprom_data[23] = random_generate(); + s->eeprom_data[24] = random_generate(); + s->eeprom_data[25] = random_generate(); + mac = (((int) s->eeprom_data[23]) << 16); + mac |= (((int) s->eeprom_data[24]) << 8); + mac |= ((int) s->eeprom_data[25]); device_set_config_mac("mac", mac); } else { - eeprom_default_local[0x17] = (mac >> 16) & 0xff; - eeprom_default_local[0x18] = (mac >> 8) & 0xff; - eeprom_default_local[0x19] = (mac & 0xff); + s->eeprom_data[23] = (mac >> 16) & 0xff; + s->eeprom_data[24] = (mac >> 8) & 0xff; + s->eeprom_data[25] = (mac & 0xff); } - tulip_idblock_crc((uint16_t *) eeprom_default_local); - ((uint16_t *) eeprom_default_local)[63] = (tulip_srom_crc((uint8_t *) eeprom_default_local, 126)); + /*Controller_0 Device_Number*/ + s->eeprom_data[26] = 0x00; + + /*Controller_0 Info Leaf_Offset*/ + s->eeprom_data[27] = 0x1e; + s->eeprom_data[28] = 0x00; + + /*Selected Connection Type, Powerup AutoSense and Dynamic AutoSense if the board supports it*/ + s->eeprom_data[30] = 0x00; + s->eeprom_data[31] = 0x08; + + if (info->local) { + /*General Purpose Control*/ + s->eeprom_data[32] = 0xff; + + /*Block Count*/ + s->eeprom_data[33] = 0x01; + + /*Extended Format (first part)*/ + /*Length (0:6) and Format Indicator (7)*/ + s->eeprom_data[34] = 0x81; + + /*Block Type (first part)*/ + s->eeprom_data[35] = 0x01; + + /*Extended Format (second part) - Block Type 0 for 21140*/ + /*Length (0:6) and Format Indicator (7)*/ + s->eeprom_data[36] = 0x85; + + /*Block Type (second part)*/ + s->eeprom_data[37] = 0x00; + + /*Media Code (0:5), EXT (6), Reserved (7)*/ + s->eeprom_data[38] = 0x01; + + /*General Purpose Data*/ + s->eeprom_data[39] = 0x00; + + /*Command*/ + s->eeprom_data[40] = 0x00; + s->eeprom_data[41] = 0x00; + } else { + /*Block Count*/ + s->eeprom_data[32] = 0x01; + + /*Extended Format - Block Type 2 for 21142/21143*/ + /*Length (0:6) and Format Indicator (7)*/ + s->eeprom_data[33] = 0x86; + + /*Block Type*/ + s->eeprom_data[34] = 0x02; + + /*Media Code (0:5), EXT (6), Reserved (7)*/ + s->eeprom_data[35] = 0x01; + + /*General Purpose Control*/ + s->eeprom_data[36] = 0xff; + s->eeprom_data[37] = 0xff; + + /*General Purpose Data*/ + s->eeprom_data[38] = 0x00; + s->eeprom_data[39] = 0x00; + } + + s->eeprom_data[126] = tulip_srom_crc(s->eeprom_data) & 0xff; + s->eeprom_data[127] = tulip_srom_crc(s->eeprom_data) >> 8; params.nwords = 64; - params.default_content = (uint16_t *) eeprom_default_local; + params.default_content = (uint16_t *) s->eeprom_data; params.filename = filename; snprintf(filename, sizeof(filename), "nmc93cxx_eeprom_%s_%d.nvr", info->internal_name, device_get_instance()); s->eeprom = device_add_parameters(&nmc93cxx_device, ¶ms); @@ -1459,10 +1492,25 @@ nic_init(const device_t *info) free(s); return NULL; } + + tulip_pci_bar[0].addr_regs[0] = 1; + tulip_pci_bar[1].addr_regs[0] = 0; + s->pci_conf[0x04] = 7; + + /* Enable our BIOS space in PCI, if needed. */ + if (s->bios_addr > 0) { + rom_init(&s->bios_rom, ROM_PATH_DEC21140, s->bios_addr, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + tulip_pci_bar[2].addr = 0xffff0000; + } else + tulip_pci_bar[2].addr = 0; + + mem_mapping_disable(&s->bios_rom.mapping); + eeprom_data = (uint8_t *) &nmc93cxx_eeprom_data(s->eeprom)[0]; + + //pclog("EEPROM Data Format=%02x, Count=%02x, MAC=%02x:%02x:%02x:%02x:%02x:%02x.\n", eeprom_data[0x12], eeprom_data[0x13], eeprom_data[0x14], eeprom_data[0x15], eeprom_data[0x16], eeprom_data[0x17], eeprom_data[0x18], eeprom_data[0x19]); memcpy(s->mii_regs, tulip_mdi_default, sizeof(tulip_mdi_default)); - s->nic = network_attach(s, (uint8_t *) &nmc93cxx_eeprom_data(s->eeprom)[10], tulip_receive, NULL); + s->nic = network_attach(s, &eeprom_data[20], tulip_receive, NULL); pci_add_card(PCI_ADD_NORMAL, tulip_pci_read, tulip_pci_write, s, &s->pci_slot); - mem_mapping_add(&s->memory, 0, 0, NULL, NULL, tulip_read, NULL, NULL, tulip_write, NULL, MEM_MAPPING_EXTERNAL, s); tulip_reset(s); return s; } @@ -1474,7 +1522,25 @@ nic_close(void *priv) } // clang-format off -static const device_config_t dec_tulip_config[] = { +static const device_config_t dec_tulip_21143_config[] = { + { + .name = "mac", + .description = "MAC Address", + .type = CONFIG_MAC, + .default_string = "", + .default_int = -1 + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + +static const device_config_t dec_tulip_21140_config[] = { + { + .name = "bios", + .description = "Enable BIOS", + .type = CONFIG_BINARY, + .default_string = "", + .default_int = 0 + }, { .name = "mac", .description = "MAC Address", @@ -1487,7 +1553,7 @@ static const device_config_t dec_tulip_config[] = { // clang-format on const device_t dec_tulip_device = { - .name = "Compu-Shack FASTLine-II UTP 10/100 (DECchip 21143 \"Tulip\")", + .name = "DE500A Fast Ethernet (DECchip 21143 \"Tulip\")", .internal_name = "dec_21143_tulip", .flags = DEVICE_PCI, .local = 0, @@ -1497,11 +1563,11 @@ const device_t dec_tulip_device = { { .available = NULL }, .speed_changed = NULL, .force_redraw = NULL, - .config = dec_tulip_config + .config = dec_tulip_21143_config }; const device_t dec_tulip_21140_device = { - .name = "Kingston KNE100TX (DECchip 21140 \"Tulip FasterNet\")", + .name = "DEC 21140 Fast Ethernet (DECchip 21140 \"Tulip FasterNet\")", .internal_name = "dec_21140_tulip", .flags = DEVICE_PCI, .local = 1, @@ -1511,7 +1577,7 @@ const device_t dec_tulip_21140_device = { { .available = NULL }, .speed_changed = NULL, .force_redraw = NULL, - .config = dec_tulip_config + .config = dec_tulip_21140_config }; const device_t dec_tulip_21140_vpc_device = { @@ -1525,5 +1591,5 @@ const device_t dec_tulip_21140_vpc_device = { { .available = NULL }, .speed_changed = NULL, .force_redraw = NULL, - .config = dec_tulip_config + .config = dec_tulip_21140_config }; From 6f218b6360e994139633e40780dd6ef629410b73 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 24 Nov 2023 21:49:56 +0100 Subject: [PATCH 18/30] Fixed some left-over network warnings. --- src/network/net_eeprom_nmc93cxx.c | 10 ---------- src/network/net_tulip.c | 1 - 2 files changed, 11 deletions(-) diff --git a/src/network/net_eeprom_nmc93cxx.c b/src/network/net_eeprom_nmc93cxx.c index b2038bdb5..1e2fd1645 100644 --- a/src/network/net_eeprom_nmc93cxx.c +++ b/src/network/net_eeprom_nmc93cxx.c @@ -59,16 +59,6 @@ nmc93cxx_eeprom_log(int lvl, const char *fmt, ...) # define nmc93cxx_eeprom_log(lvl, fmt, ...) #endif -static void -nmc93cxx_eeprom_save(nmc93cxx_eeprom_t *eeprom) -{ - FILE *fp = nvr_fopen(eeprom->filename, "wb"); - if (fp) { - fwrite(eeprom->dev.data, 2, eeprom->size, fp); - fclose(fp); - } -} - static void * nmc93cxx_eeprom_init_params(UNUSED(const device_t *info), void *params) { diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index 8329e52e4..b74b345bc 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -1327,7 +1327,6 @@ tulip_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv) static void * nic_init(const device_t *info) { - uint8_t eeprom_default_local[128]; nmc93cxx_eeprom_params_t params; TULIPState *s = calloc(1, sizeof(TULIPState)); char filename[1024] = { 0 }; From d3897b57e846aa29f7dc39fbe9d69346d0dddd33 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Sun, 26 Nov 2023 11:54:01 +1300 Subject: [PATCH 19/30] Handle SVGA 8bit RAMDAC for Voodoo Banshee cards --- src/video/vid_voodoo_banshee.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 37c795b59..d0fad5b95 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -211,6 +211,7 @@ enum { Agp_agpGraphicsStride = 0x10, }; +#define VGAINIT0_RAMDAC_8BIT (1 << 2) #define VGAINIT0_EXTENDED_SHIFT_OUT (1 << 12) #define VIDPROCCFG_VIDPROC_ENABLE (1 << 0) @@ -765,6 +766,7 @@ banshee_ext_outl(uint16_t addr, uint32_t val, void *priv) break; case Init_vgaInit0: banshee->vgaInit0 = val; + svga_set_ramdac_type(svga, (val & VGAINIT0_RAMDAC_8BIT ? RAMDAC_8BIT : RAMDAC_6BIT)); break; case Init_vgaInit1: banshee->vgaInit1 = val; From 8497e33559b30aa48e23d1ce64973cade1e1c2ae Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 25 Nov 2023 22:49:27 -0300 Subject: [PATCH 20/30] Voodoo: Attempt fix for a rare FIFO deadlock on hard reset --- src/video/vid_voodoo_fifo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/vid_voodoo_fifo.c b/src/video/vid_voodoo_fifo.c index 8a84dabe4..f8495edec 100644 --- a/src/video/vid_voodoo_fifo.c +++ b/src/video/vid_voodoo_fifo.c @@ -160,7 +160,7 @@ cmdfifo_get(voodoo_t *voodoo) uint32_t val; if (!voodoo->cmdfifo_in_sub) { - while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr) { + while (voodoo->fifo_thread_run && (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr)) { thread_wait_event(voodoo->wake_fifo_thread, -1); thread_reset_event(voodoo->wake_fifo_thread); } From 3053f15efd0b37cf2cf806e30d9766998c96af18 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 25 Nov 2023 22:54:07 -0300 Subject: [PATCH 21/30] ZIP/MO: Temporary fix for uninitialized IDE channel crashes --- src/disk/mo.c | 9 +++++++-- src/disk/zip.c | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/disk/mo.c b/src/disk/mo.c index 27bf7e5e0..c93f4b055 100644 --- a/src/disk/mo.c +++ b/src/disk/mo.c @@ -343,6 +343,11 @@ mo_load(mo_t *dev, char *fn) uint32_t size = 0; unsigned int found = 0; + if (!dev->drv) { + mo_eject(dev->id); + return 0; + } + is_mdi = image_is_mdi(fn); dev->drv->fp = plat_fopen(fn, dev->drv->read_only ? "rb" : "rb+"); @@ -403,7 +408,7 @@ mo_disk_reload(mo_t *dev) void mo_disk_unload(mo_t *dev) { - if (dev->drv->fp) { + if (dev->drv && dev->drv->fp) { fclose(dev->drv->fp); dev->drv->fp = NULL; } @@ -412,7 +417,7 @@ mo_disk_unload(mo_t *dev) void mo_disk_close(mo_t *dev) { - if (dev->drv->fp) { + if (dev->drv && dev->drv->fp) { mo_disk_unload(dev); memcpy(dev->drv->prev_image_path, dev->drv->image_path, sizeof(dev->drv->prev_image_path)); diff --git a/src/disk/zip.c b/src/disk/zip.c index 887a9c68e..7045b1e41 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -485,6 +485,11 @@ zip_load(zip_t *dev, char *fn) { int size = 0; + if (!dev->drv) { + zip_eject(dev->id); + return 0; + } + dev->drv->fp = plat_fopen(fn, dev->drv->read_only ? "rb" : "rb+"); if (!dev->drv->fp) { if (!dev->drv->read_only) { @@ -548,7 +553,7 @@ zip_disk_reload(zip_t *dev) void zip_disk_unload(zip_t *dev) { - if (dev->drv->fp) { + if (dev->drv && dev->drv->fp) { fclose(dev->drv->fp); dev->drv->fp = NULL; } @@ -557,7 +562,7 @@ zip_disk_unload(zip_t *dev) void zip_disk_close(zip_t *dev) { - if (dev->drv->fp) { + if (dev->drv && dev->drv->fp) { zip_disk_unload(dev); memcpy(dev->drv->prev_image_path, dev->drv->image_path, sizeof(dev->drv->prev_image_path)); From 7b4a6a3388f5af66c329e39ad886e22da25256ba Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 26 Nov 2023 22:15:28 +0100 Subject: [PATCH 22/30] Clean-ups and made the ET4000AX use the old way to check for 8 bpp modes, fixes the Windows 3.0 driver. --- src/include/86box/vid_svga_render.h | 86 ++++++++++----------- src/video/vid_et4000.c | 8 ++ src/video/vid_svga_render.c | 112 ++++++++++++++++------------ 3 files changed, 116 insertions(+), 90 deletions(-) diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index 3ad9e401c..bc6894ca9 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -36,52 +36,52 @@ extern int scrollcache; extern uint8_t edatlookup[4][4]; extern uint8_t egaremap2bpp[256]; -void svga_recalc_remap_func(svga_t *svga); +extern void svga_recalc_remap_func(svga_t *svga); -void svga_render_null(svga_t *svga); -void svga_render_blank(svga_t *svga); -void svga_render_overscan_left(svga_t *svga); -void svga_render_overscan_right(svga_t *svga); -void svga_render_text_40(svga_t *svga); -void svga_render_text_80(svga_t *svga); -void svga_render_text_80_ksc5601(svga_t *svga); +extern void svga_render_null(svga_t *svga); +extern void svga_render_blank(svga_t *svga); +extern void svga_render_overscan_left(svga_t *svga); +extern void svga_render_overscan_right(svga_t *svga); +extern void svga_render_text_40(svga_t *svga); +extern void svga_render_text_80(svga_t *svga); +extern void svga_render_text_80_ksc5601(svga_t *svga); -void svga_render_2bpp_lowres(svga_t *svga); -void svga_render_2bpp_highres(svga_t *svga); -void svga_render_2bpp_headland_highres(svga_t *svga); -void svga_render_4bpp_lowres(svga_t *svga); -void svga_render_4bpp_highres(svga_t *svga); -void svga_render_8bpp_lowres(svga_t *svga); -void svga_render_8bpp_highres(svga_t *svga); -void svga_render_8bpp_tseng_lowres(svga_t *svga); -void svga_render_8bpp_tseng_highres(svga_t *svga); -void svga_render_8bpp_gs_lowres(svga_t *svga); -void svga_render_8bpp_gs_highres(svga_t *svga); -void svga_render_8bpp_rgb_lowres(svga_t *svga); -void svga_render_8bpp_rgb_highres(svga_t *svga); -void svga_render_15bpp_lowres(svga_t *svga); -void svga_render_15bpp_highres(svga_t *svga); -void svga_render_15bpp_mix_lowres(svga_t *svga); -void svga_render_15bpp_mix_highres(svga_t *svga); -void svga_render_16bpp_lowres(svga_t *svga); -void svga_render_16bpp_highres(svga_t *svga); -void svga_render_24bpp_lowres(svga_t *svga); -void svga_render_24bpp_highres(svga_t *svga); -void svga_render_32bpp_lowres(svga_t *svga); -void svga_render_32bpp_highres(svga_t *svga); -void svga_render_ABGR8888_lowres(svga_t *svga); -void svga_render_ABGR8888_highres(svga_t *svga); -void svga_render_RGBA8888_lowres(svga_t *svga); -void svga_render_RGBA8888_highres(svga_t *svga); +extern void svga_render_2bpp_lowres(svga_t *svga); +extern void svga_render_2bpp_highres(svga_t *svga); +extern void svga_render_2bpp_headland_highres(svga_t *svga); +extern void svga_render_4bpp_lowres(svga_t *svga); +extern void svga_render_4bpp_highres(svga_t *svga); +extern void svga_render_8bpp_lowres(svga_t *svga); +extern void svga_render_8bpp_highres(svga_t *svga); +extern void svga_render_8bpp_tseng_lowres(svga_t *svga); +extern void svga_render_8bpp_tseng_highres(svga_t *svga); +extern void svga_render_8bpp_gs_lowres(svga_t *svga); +extern void svga_render_8bpp_gs_highres(svga_t *svga); +extern void svga_render_8bpp_rgb_lowres(svga_t *svga); +extern void svga_render_8bpp_rgb_highres(svga_t *svga); +extern void svga_render_15bpp_lowres(svga_t *svga); +extern void svga_render_15bpp_highres(svga_t *svga); +extern void svga_render_15bpp_mix_lowres(svga_t *svga); +extern void svga_render_15bpp_mix_highres(svga_t *svga); +extern void svga_render_16bpp_lowres(svga_t *svga); +extern void svga_render_16bpp_highres(svga_t *svga); +extern void svga_render_24bpp_lowres(svga_t *svga); +extern void svga_render_24bpp_highres(svga_t *svga); +extern void svga_render_32bpp_lowres(svga_t *svga); +extern void svga_render_32bpp_highres(svga_t *svga); +extern void svga_render_ABGR8888_lowres(svga_t *svga); +extern void svga_render_ABGR8888_highres(svga_t *svga); +extern void svga_render_RGBA8888_lowres(svga_t *svga); +extern void svga_render_RGBA8888_highres(svga_t *svga); -void ibm8514_render_8bpp(svga_t *svga); -void ibm8514_render_15bpp(svga_t *svga); -void ibm8514_render_16bpp(svga_t *svga); -void ibm8514_render_24bpp(svga_t *svga); -void ibm8514_render_BGR(svga_t *svga); -void ibm8514_render_32bpp(svga_t *svga); -void ibm8514_render_ABGR8888(svga_t *svga); -void ibm8514_render_RGBA8888(svga_t *svga); +extern void ibm8514_render_8bpp(svga_t *svga); +extern void ibm8514_render_15bpp(svga_t *svga); +extern void ibm8514_render_16bpp(svga_t *svga); +extern void ibm8514_render_24bpp(svga_t *svga); +extern void ibm8514_render_BGR(svga_t *svga); +extern void ibm8514_render_32bpp(svga_t *svga); +extern void ibm8514_render_ABGR8888(svga_t *svga); +extern void ibm8514_render_RGBA8888(svga_t *svga); extern void (*svga_render)(svga_t *svga); diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 80da770a3..834de7513 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -605,6 +605,14 @@ et4000_recalctimings(svga_t *svga) } } } + + if ((svga->bpp == 8) && ((svga->gdcreg[5] & 0x60) >= 0x40)) { + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + } } static void diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 10303cc5f..b14199f06 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -448,7 +448,7 @@ svga_render_2bpp_headland_highres(svga_t *svga) } } -void +static void svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) { int x; @@ -460,14 +460,19 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) const bool blinked = svga->blink & 0x10; const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); - // The following is likely how it works on an IBM VGA - that is, it works with its BIOS. - // But on some cards, certain modes are broken. - // - S3 Trio: mode 13h (320x200x8), incbypow2 given as 2 treated as 0 - // - ET4000/W32i: mode 2Eh (640x480x8), incevery given as 2 treated as 1 + /* + The following is likely how it works on an IBM VGA - that is, it works with its BIOS. + But on some cards, certain modes are broken. + - S3 Trio: mode 13h (320x200x8), incbypow2 given as 2 treated as 0 + - ET4000/W32i: mode 2Eh (640x480x8), incevery given as 2 treated as 1 + */ const bool forcepacked = combine8bits && (svga->force_old_addr || svga->packed_chain4); - // SVGA cards with a high-resolution 8bpp mode may actually bypass the VGA shifter logic. - // - HT-216 (+ other Video7 chipsets?) has 0x3C4.0xC8 bit 4 which, when set to 1, loads bytes directly, bypassing the shifters. + /* + SVGA cards with a high-resolution 8bpp mode may actually bypass the VGA shifter logic. + - HT-216 (+ other Video7 chipsets?) has 0x3C4.0xC8 bit 4 which, when set to 1, loads + bytes directly, bypassing the shifters. + */ const bool highres8bpp = combine8bits && highres; const bool dwordload = ((svga->seqregs[0x01] & 0x10) != 0); @@ -492,15 +497,14 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) if ((svga->displine + svga->y_add) < 0) return; - if (svga->force_old_addr) { + if (svga->force_old_addr) changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; - } else { + else changed_offset = svga->remap_func(svga, svga->ma) >> 12; - } - if (!(svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange)) { + if (!(svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || + svga->fullchange)) return; - } p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -511,38 +515,46 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) uint32_t load_counter = 0; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += charwidth) { if (load_counter == 0) { - // Find our address + /* Find our address */ if (svga->force_old_addr) { addr = ((svga->ma & ~0x3) << incbypow2); if (incbypow2 == 2) { - if (svga->ma & (4<<15)) addr |= 0x8; - if (svga->ma & (4<<14)) addr |= 0x4; + if (svga->ma & (4 << 15)) + addr |= 0x8; + if (svga->ma & (4 << 14)) + addr |= 0x4; } else if (incbypow2 == 1) { if ((svga->crtc[0x17] & 0x20)) { - if (svga->ma & (4<<15)) addr |= 0x4; + if (svga->ma & (4 << 15)) + addr |= 0x4; } else { - if (svga->ma & (4<<13)) addr |= 0x4; + if (svga->ma & (4<<13)) + addr |= 0x4; } } else { - // Nothing + /* Nothing */ } if (!(svga->crtc[0x17] & 0x01)) addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); if (!(svga->crtc[0x17] & 0x02)) addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); - } else { + } else if (svga->remap_required) addr = svga->remap_func(svga, svga->ma); - } + else + addr = svga->ma; + addr &= svga->vram_display_mask; - // Load VRAM + /* Load VRAM */ *(uint32_t *)&edat[0] = *(uint32_t *)&svga->vram[addr]; if (shift4bit) { - // Remap VGA 4bpp-chunky data into fully planar data - // Plane 3 LSbit is aligned with MSbit + /* + Remap VGA 4bpp-chunky data into fully planar data + Plane 3 LSbit is aligned with MSbit + */ uint8_t tmpdat[4] = {0, 0, 0, 0}; for (int j = 0; j < 4; j++) { for (int i = 0; i < 8; i++) { @@ -565,16 +577,17 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) edat[3] = dat3; } } else { - // According to the 82C451 VGA clone chipset datasheet, all 4 planes chain in a ring. - // So, rotate them all around. + /* + According to the 82C451 VGA clone chipset datasheet, all 4 planes chain in a ring. + So, rotate them all around. + */ *(uint32_t *)&edat[0] = ((*(uint32_t *)&edat[0]) >> 8) | ((*(uint32_t *)&edat[0]) << 24); } load_counter += 1; - if (load_counter >= loadevery) { + if (load_counter >= loadevery) load_counter = 0; - } incr_counter += 1; if (incr_counter >= incevery) { @@ -584,33 +597,36 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) svga->ma &= svga->vram_display_mask; } - // - // Now that we've converted it all to planar, convert it (back?) to chunky! - // + /* + Now that we've converted it all to planar, convert it (back?) to chunky! + */ for (int i = 0; i < 8; i += 2) { const int inshift = 6 - i; uint8_t dat = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); - // FIXME: Confirm blink behaviour on real hardware + /* FIXME: Confirm blink behaviour on real hardware - // The VGA 4bpp graphics blink logic was a pain to work out. - // - // If plane 3 is enabled in the attribute controller, then: - // - if bit 3 is 0, then we force the output of it to be 1. - // - if bit 3 is 1, then the output blinks. - // This can be tested with Lotus 1-2-3 release 2.3 with the WYSIWYG addon. - // - // If plane 3 is disabled in the attribute controller, then the output blinks. - // This can be tested with QBASIC SCREEN 10 - anything using color #2 should blink and nothing else. - // - // If you can simplify the following and have it still work, give yourself a medal. - // + The VGA 4bpp graphics blink logic was a pain to work out. + + If plane 3 is enabled in the attribute controller, then: + - if bit 3 is 0, then we force the output of it to be 1. + - if bit 3 is 1, then the output blinks. + This can be tested with Lotus 1-2-3 release 2.3 with the WYSIWYG addon. + + If plane 3 is disabled in the attribute controller, then the output blinks. + This can be tested with QBASIC SCREEN 10 - anything using color #2 should + blink and nothing else. + + If you can simplify the following and have it still work, give yourself a medal. + */ uint32_t c0 = (dat >> 4) & 0xF; uint32_t c1 = dat & 0xF; - c0 = ((c0 & svga->plane_mask & ~blinkmask) | ((c0 | ~svga->plane_mask) & blinkmask & blinkval)) ^ blinkmask; - c1 = ((c1 & svga->plane_mask & ~blinkmask) | ((c1 | ~svga->plane_mask) & blinkmask & blinkval)) ^ blinkmask; + c0 = ((c0 & svga->plane_mask & ~blinkmask) | + ((c0 | ~svga->plane_mask) & blinkmask & blinkval)) ^ blinkmask; + c1 = ((c1 & svga->plane_mask & ~blinkmask) | + ((c1 | ~svga->plane_mask) & blinkmask & blinkval)) ^ blinkmask; if (combine8bits) { uint32_t ccombined = (c0 << 4) | c1; @@ -633,8 +649,10 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) } } -// Remap these to the paletted renderer -// (*, highres, combine8bits) +/* + Remap these to the paletted renderer + (*, highres, combine8bits) + */ void svga_render_2bpp_lowres(svga_t *svga) { svga_render_indexed_gfx(svga, false, false); } void svga_render_2bpp_highres(svga_t *svga) { svga_render_indexed_gfx(svga, true, false); } void svga_render_4bpp_lowres(svga_t *svga) { svga_render_indexed_gfx(svga, false, false); } From f22dea820960424786fd895498e01165c06cd17a Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 1 Dec 2023 15:06:12 +0100 Subject: [PATCH 23/30] Disabled undocumented Sound Blaster mixer register FFh's for even more cards, fixes #3835. --- src/sound/snd_sb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 5f1aeb261..602c1c2a7 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -945,7 +945,7 @@ sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *priv) break; case 0xff: - if (sb->dsp.sb_type > SBAWE32) { + if ((sb->dsp.sb_type > SBAWE32) && !sb->dsp.sb_16_dma_supported) { /* Bit 5: High DMA channel enabled (0 = yes, 1 = no); Bit 2: ????; From cf36889bd2e9aa31f254ac041b0eb16890051c01 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 3 Dec 2023 14:19:00 +0100 Subject: [PATCH 24/30] Unix SDL fixes, per suggestion by svenska. --- src/unix/unix_sdl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/unix/unix_sdl.c b/src/unix/unix_sdl.c index 19af4b71e..3ba8c1ae0 100644 --- a/src/unix/unix_sdl.c +++ b/src/unix/unix_sdl.c @@ -270,6 +270,11 @@ sdl_close(void) sdl_destroy_texture(); sdl_destroy_window(); + if (pixeldata != NULL) { + free(pixeldata); + pixeldata = NULL; + } + /* Quit. */ SDL_Quit(); sdl_flags = -1; @@ -430,6 +435,8 @@ sdl_init_common(int flags) /* Make sure we get a clean exit. */ atexit(sdl_close); + pixeldata = malloc(2048 * 2048 * 4); + /* Register our renderer! */ video_setblit(sdl_blit_shim); From 44d70ab943e593865d0dc04a9e3c4cebc269e7b2 Mon Sep 17 00:00:00 2001 From: GreaseMonkey Date: Wed, 6 Dec 2023 15:25:17 +1300 Subject: [PATCH 25/30] Rework (S)VGA renderer to be internally chunky + attempt to optimise for speed --- src/video/vid_svga_render.c | 171 +++++++++++++++++++----------------- 1 file changed, 88 insertions(+), 83 deletions(-) diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index b14199f06..7cc0aafc3 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -454,11 +454,10 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) int x; uint32_t addr; uint32_t *p; - uint8_t edat[4]; uint32_t changed_offset; - const bool blinked = svga->blink & 0x10; - const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); + const bool blinked = svga->blink & 0x10; + const bool attrblink = ((svga->attrregs[0x10] & 0x08) != 0); /* The following is likely how it works on an IBM VGA - that is, it works with its BIOS. @@ -466,33 +465,50 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) - S3 Trio: mode 13h (320x200x8), incbypow2 given as 2 treated as 0 - ET4000/W32i: mode 2Eh (640x480x8), incevery given as 2 treated as 1 */ - const bool forcepacked = combine8bits && (svga->force_old_addr || svga->packed_chain4); + const bool forcepacked = combine8bits && (svga->force_old_addr || svga->packed_chain4); /* SVGA cards with a high-resolution 8bpp mode may actually bypass the VGA shifter logic. - HT-216 (+ other Video7 chipsets?) has 0x3C4.0xC8 bit 4 which, when set to 1, loads bytes directly, bypassing the shifters. */ - const bool highres8bpp = combine8bits && highres; + const bool highres8bpp = combine8bits && highres; - const bool dwordload = ((svga->seqregs[0x01] & 0x10) != 0); - const bool wordload = ((svga->seqregs[0x01] & 0x04) != 0) && !dwordload; - const bool wordincr = ((svga->crtc[0x17] & 0x08) != 0); - const bool dwordincr = ((svga->crtc[0x14] & 0x20) != 0) && !wordincr; - const bool dwordshift = ((svga->crtc[0x14] & 0x40) != 0); - const bool wordshift = ((svga->crtc[0x17] & 0x40) == 0) && !dwordshift; + const bool dwordload = ((svga->seqregs[0x01] & 0x10) != 0); + const bool wordload = ((svga->seqregs[0x01] & 0x04) != 0) && !dwordload; + const bool wordincr = ((svga->crtc[0x17] & 0x08) != 0); + const bool dwordincr = ((svga->crtc[0x14] & 0x20) != 0) && !wordincr; + const bool dwordshift = ((svga->crtc[0x14] & 0x40) != 0); + const bool wordshift = ((svga->crtc[0x17] & 0x40) == 0) && !dwordshift; const uint32_t incbypow2 = forcepacked ? 0 : (dwordshift ? 2 : wordshift ? 1 : 0); - const uint32_t incevery = forcepacked ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); - const uint32_t loadevery = forcepacked ? 1 : (dwordload ? 4 : wordload ? 2 : 1); + const uint32_t incevery = forcepacked ? 1 : (dwordincr ? 4 : wordincr ? 2 : 1); + const uint32_t loadevery = forcepacked ? 1 : (dwordload ? 4 : wordload ? 2 : 1); - const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40 ) || highres8bpp; - const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20 ) && !shift4bit; + const bool shift4bit = ((svga->gdcreg[0x05] & 0x40) == 0x40) || highres8bpp; + const bool shift2bit = ((svga->gdcreg[0x05] & 0x60) == 0x20) && !shift4bit; - const int dwshift = highres ? 0 : 1; - const int dotwidth = 1 << dwshift; - const int charwidth = dotwidth * (combine8bits ? 4 : 8); - const uint8_t blinkmask = (attrblink ? 0x8 : 0x0); - const uint8_t blinkval = (attrblink && blinked ? 0x8 : 0x0); + const int dwshift = highres ? 0 : 1; + const int dotwidth = 1 << dwshift; + const int charwidth = dotwidth * (combine8bits ? 4 : 8); + const uint32_t planemask = 0x11111111 * (uint32_t) (svga->plane_mask); + const uint32_t blinkmask = (attrblink ? 0x88888888 : 0x0); + const uint32_t blinkval = (attrblink && blinked ? 0x88888888 : 0x0); + + /* + This is actually a 8x 3-bit lookup table, + preshifted by 2 bits to allow shifting by multiples of 4 bits. + + Anyway, when we perform a planar-to-chunky conversion, + we keep the pixel values in a scrambled order. + This lookup table unscrambles them. + + WARNING: Octal values are used here! + */ + const uint32_t shift_values = (shift4bit + ? ((067452301) << 2) + : shift2bit + ? ((026370415) << 2) + : ((002461357) << 2)); if ((svga->displine + svga->y_add) < 0) return; @@ -502,8 +518,7 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) else changed_offset = svga->remap_func(svga, svga->ma) >> 12; - if (!(svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || - svga->fullchange)) + if (!(svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange)) return; p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -513,6 +528,7 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) uint32_t incr_counter = 0; uint32_t load_counter = 0; + uint32_t edat = 0; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += charwidth) { if (load_counter == 0) { /* Find our address */ @@ -529,7 +545,7 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) if (svga->ma & (4 << 15)) addr |= 0x4; } else { - if (svga->ma & (4<<13)) + if (svga->ma & (4 << 13)) addr |= 0x4; } } else { @@ -548,42 +564,31 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) addr &= svga->vram_display_mask; /* Load VRAM */ - *(uint32_t *)&edat[0] = *(uint32_t *)&svga->vram[addr]; + edat = *(uint32_t *) &svga->vram[addr]; - if (shift4bit) { - /* - Remap VGA 4bpp-chunky data into fully planar data - Plane 3 LSbit is aligned with MSbit - */ - uint8_t tmpdat[4] = {0, 0, 0, 0}; - for (int j = 0; j < 4; j++) { - for (int i = 0; i < 8; i++) { - tmpdat[j] <<= 1; - tmpdat[j] |= (edat[i>>1] >> (((0x1&~i)<<2)+j)) & 0x1; - } + /* + EGA and VGA actually use 4bpp planar as its native format. + But 4bpp chunky is generally easier to deal with on a modern CPU. + shift4bit is the native format for this renderer (4bpp chunky). + */ + if (!shift4bit) { + if (shift2bit) { + /* Group 2x 2bpp values into 4bpp values */ + edat = (edat & 0xCCCC3333) | ((edat << 14) & 0x33330000) | ((edat >> 14) & 0x0000CCCC); + } else { + /* Group 4x 1bpp values into 4bpp values */ + edat = (edat & 0xAA55AA55) | ((edat << 7) & 0x55005500) | ((edat >> 7) & 0x00AA00AA); + edat = (edat & 0xCCCC3333) | ((edat << 14) & 0x33330000) | ((edat >> 14) & 0x0000CCCC); } - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&tmpdat[0]); - } - - if (shift2bit) { - // Remap CGA 2bpp-chunky data into fully planar data - uint8_t dat0 = egaremap2bpp[edat[1]] | (egaremap2bpp[edat[0]] << 4); - uint8_t dat1 = egaremap2bpp[edat[1] >> 1] | (egaremap2bpp[edat[0] >> 1] << 4); - uint8_t dat2 = egaremap2bpp[edat[3]] | (egaremap2bpp[edat[2]] << 4); - uint8_t dat3 = egaremap2bpp[edat[3] >> 1] | (egaremap2bpp[edat[2] >> 1] << 4); - edat[0] = dat0; - edat[1] = dat1; - edat[2] = dat2; - edat[3] = dat3; } } else { /* According to the 82C451 VGA clone chipset datasheet, all 4 planes chain in a ring. So, rotate them all around. + Planar version: edat = (edat >> 8) | (edat << 24); + Here's the chunky version... */ - *(uint32_t *)&edat[0] - = ((*(uint32_t *)&edat[0]) >> 8) - | ((*(uint32_t *)&edat[0]) << 24); + edat = ((edat >> 1) & 0x77777777) | ((edat << 3) & 0x88888888); } load_counter += 1; if (load_counter >= loadevery) @@ -593,50 +598,50 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) if (incr_counter >= incevery) { incr_counter = 0; svga->ma += 4; - // DISCREPANCY TODO FIXME 2/4bpp used vram_mask, 8bpp used vram_display_mask --GM + /* DISCREPANCY TODO FIXME 2/4bpp used vram_mask, 8bpp used vram_display_mask --GM */ svga->ma &= svga->vram_display_mask; } + uint32_t current_shift = shift_values; + uint32_t out_edat = edat; /* - Now that we've converted it all to planar, convert it (back?) to chunky! + Apply blink + FIXME: Confirm blink behaviour on real hardware + + The VGA 4bpp graphics blink logic was a pain to work out. + + If plane 3 is enabled in the attribute controller, then: + - if bit 3 is 0, then we force the output of it to be 1. + - if bit 3 is 1, then the output blinks. + This can be tested with Lotus 1-2-3 release 2.3 with the WYSIWYG addon. + + If plane 3 is disabled in the attribute controller, then the output blinks. + This can be tested with QBASIC SCREEN 10 - anything using color #2 should + blink and nothing else. + + If you can simplify the following and have it still work, give yourself a medal. */ + out_edat = ((out_edat & planemask & ~blinkmask) | ((out_edat | ~planemask) & blinkmask & blinkval)) ^ blinkmask; + for (int i = 0; i < 8; i += 2) { - const int inshift = 6 - i; - uint8_t dat - = (edatlookup[(edat[0] >> inshift) & 3][(edat[1] >> inshift) & 3]) - | (edatlookup[(edat[2] >> inshift) & 3][(edat[3] >> inshift) & 3] << 2); - - /* FIXME: Confirm blink behaviour on real hardware - - The VGA 4bpp graphics blink logic was a pain to work out. - - If plane 3 is enabled in the attribute controller, then: - - if bit 3 is 0, then we force the output of it to be 1. - - if bit 3 is 1, then the output blinks. - This can be tested with Lotus 1-2-3 release 2.3 with the WYSIWYG addon. - - If plane 3 is disabled in the attribute controller, then the output blinks. - This can be tested with QBASIC SCREEN 10 - anything using color #2 should - blink and nothing else. - - If you can simplify the following and have it still work, give yourself a medal. + /* + c0 denotes the first 4bpp pixel shifted, while c1 denotes the second. + For 8bpp modes, the first 4bpp pixel is the upper 4 bits. */ - uint32_t c0 = (dat >> 4) & 0xF; - uint32_t c1 = dat & 0xF; - c0 = ((c0 & svga->plane_mask & ~blinkmask) | - ((c0 | ~svga->plane_mask) & blinkmask & blinkval)) ^ blinkmask; - c1 = ((c1 & svga->plane_mask & ~blinkmask) | - ((c1 | ~svga->plane_mask) & blinkmask & blinkval)) ^ blinkmask; + uint32_t c0 = (out_edat >> (current_shift & 0x1C)) & 0xF; + current_shift >>= 3; + uint32_t c1 = (out_edat >> (current_shift & 0x1C)) & 0xF; + current_shift >>= 3; if (combine8bits) { - uint32_t ccombined = (c0 << 4) | c1; - uint32_t p0 = svga->map8[ccombined]; - const int outoffs = (i >> 1) << dwshift; + uint32_t ccombined = (c0 << 4) | c1; + uint32_t p0 = svga->map8[ccombined]; + const int outoffs = (i >> 1) << dwshift; for (int subx = 0; subx < dotwidth; subx++) p[outoffs + subx] = p0; } else { - uint32_t p0 = svga->pallook[svga->egapal[c0]]; - uint32_t p1 = svga->pallook[svga->egapal[c1]]; + uint32_t p0 = svga->pallook[svga->egapal[c0]]; + uint32_t p1 = svga->pallook[svga->egapal[c1]]; const int outoffs = i << dwshift; for (int subx = 0; subx < dotwidth; subx++) p[outoffs + subx] = p0; From ce0b6e1da14b565655f116e302dc08086a8aadd9 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 6 Dec 2023 15:00:31 +0100 Subject: [PATCH 26/30] Cirrus, ATI Mach8/32 and XGA fixes. 1. Update svga->fast to account for packed chain mode toggles, fixes issues on Descent II for DOS using the Cirrus cards. 2. Re-organized ATI Mach8/32 LFB access as well as 8514/A/ATI mode toggles, should end the video mode issues once and for all. 3. Fixed a small but major pattern issue with IBM OS/2 1.30.1's XGA driver (not .2, which is fine as is). --- src/include/86box/vid_8514a.h | 2 +- src/video/vid_8514a.c | 32 +-- src/video/vid_ati_mach8.c | 391 +++++++++++++++++++++------------- src/video/vid_cl54xx.c | 26 ++- src/video/vid_svga.c | 6 +- src/video/vid_xga.c | 259 +++++++++++----------- 6 files changed, 409 insertions(+), 307 deletions(-) diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index da4e9e700..49b4cb37d 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -137,7 +137,7 @@ typedef struct ibm8514_t { } accel; uint16_t test; - int ibm_mode; + int vendor_mode[2]; int v_total; int dispend; diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 314fee307..955199970 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -2009,7 +2009,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (dev->accel.cur_y >= 0x600) dev->accel.cy |= ~0x5ff; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); else dev->accel.dest = dev->accel.cy * dev->pitch; @@ -2061,7 +2061,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (!(dev->accel.cmd & 0x40) && (frgd_mix == 2) && (bkgd_mix == 2) && (pixcntl == 0) && (cmd == 2)) { if (!(dev->accel.sx & 1)) { dev->accel.output = 1; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.newdest_out = (dev->accel.ge_offset << 2) + ((dev->accel.cy + 1) * dev->pitch); else dev->accel.newdest_out = (dev->accel.cy + 1) * dev->pitch; @@ -2075,7 +2075,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (!(dev->accel.cmd & 2) && (frgd_mix == 2) && (pixcntl == 0) && (cmd == 2)) { if (!(dev->accel.sx & 1)) { dev->accel.input = 1; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.newdest_in = (dev->accel.ge_offset << 2) + ((dev->accel.cy + 1) * dev->pitch); else dev->accel.newdest_in = (dev->accel.cy + 1) * dev->pitch; @@ -2258,7 +2258,7 @@ rect_fill_pix: break; } - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); else dev->accel.dest = dev->accel.cy * dev->pitch; @@ -2343,7 +2343,7 @@ rect_fill_pix: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); else dev->accel.dest = dev->accel.cy * dev->pitch; @@ -2435,7 +2435,7 @@ rect_fill_pix: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); else dev->accel.dest = dev->accel.cy * dev->pitch; @@ -2494,7 +2494,7 @@ rect_fill_pix: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) { + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) { dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); dev->accel.newdest_in = (dev->accel.ge_offset << 2) + ((dev->accel.cy + 1) * dev->pitch); } else { @@ -2519,7 +2519,7 @@ rect_fill_pix: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) { + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) { dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); dev->accel.newdest_in = (dev->accel.ge_offset << 2) + ((dev->accel.cy + 1) * dev->pitch); } else { @@ -2575,7 +2575,7 @@ rect_fill_pix: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) { + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) { dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); dev->accel.newdest_out = (dev->accel.ge_offset << 2) + ((dev->accel.cy + 1) * dev->pitch); } else { @@ -2600,7 +2600,7 @@ rect_fill_pix: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) { + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) { dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); dev->accel.newdest_out = (dev->accel.ge_offset << 2) + ((dev->accel.cy + 1) * dev->pitch); } else { @@ -2690,7 +2690,7 @@ rect_fill_pix: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); else dev->accel.dest = dev->accel.cy * dev->pitch; @@ -2767,7 +2767,7 @@ rect_fill: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); else dev->accel.dest = dev->accel.cy * dev->pitch; @@ -2838,7 +2838,7 @@ rect_fill: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); else dev->accel.dest = dev->accel.cy * dev->pitch; @@ -2923,7 +2923,7 @@ rect_fill: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); else dev->accel.dest = dev->accel.cy * dev->pitch; @@ -2990,7 +2990,7 @@ rect_fill: else dev->accel.cy--; - if ((dev->local >= 2) && dev->accel.ge_offset && (dev->accel_bpp == 24)) + if (((dev->local & 0xff) >= 0x02) && dev->accel.ge_offset && (dev->accel_bpp == 24)) dev->accel.dest = (dev->accel.ge_offset << 2) + (dev->accel.cy * dev->pitch); else dev->accel.dest = dev->accel.cy * dev->pitch; @@ -3685,7 +3685,7 @@ bitblt: } } } else { - if ((dev->accel_bpp == 24) && (dev->local >= 2) && (dev->accel.cmd == 0xc2b5)) { + if ((dev->accel_bpp == 24) && ((dev->local & 0xff) >= 0x02) && (dev->accel.cmd == 0xc2b5)) { int64_t cx; int64_t dx; diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index 90e41d9ba..dea8821e6 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -101,7 +101,6 @@ typedef struct mach_t { uint8_t bank_r; uint16_t shadow_set; int ext_on[2]; - int ati_mode[2]; struct { uint8_t line_idx; @@ -1173,7 +1172,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } break; case 3: - READ(dev->accel.src + ((dev->accel.cx)), mix); + READ(dev->accel.src + dev->accel.cx, mix); mix = (mix & rd_mask) == rd_mask; break; @@ -1296,6 +1295,7 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.cx += mach->accel.src_width; else dev->accel.cx -= mach->accel.src_width; + dev->accel.cy += (mach->accel.src_y_dir ? 1 : -1); if (dev->bpp) dev->accel.src = (mach->accel.ge_offset << 1) + (dev->accel.cy * (dev->pitch)); @@ -2267,7 +2267,7 @@ mach_accel_out_pixtrans(mach_t *mach, ibm8514_t *dev, uint16_t val) case 0x000: /*8-bit size*/ if (mono_src == 2) { if ((frgd_sel != 2) && (bkgd_sel != 2)) { - if ((mach->accel.dp_config & 0x1000) && (dev->local >= 2)) + if ((mach->accel.dp_config & 0x1000) && ((dev->local & 0xff) >= 0x02)) val = (val >> 8) | (val << 8); mach_accel_start(mach->accel.cmd_type, 1, 8, val | (val << 16), 0, mach, dev); } else @@ -2325,7 +2325,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) svga_recalctimings(svga); break; case 0xad: - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { if ((old ^ val) & 0x0c) svga_recalctimings(svga); } @@ -2341,7 +2341,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) if (mach->regs[0xbe] & 0x08) { /* Read/write bank mode */ mach->bank_r = (((mach->regs[0xb2] & 1) << 3) | ((mach->regs[0xb2] & 0xe0) >> 5)); mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { mach->bank_r |= ((mach->regs[0xae] & 0x0c) << 2); mach->bank_w |= ((mach->regs[0xae] & 3) << 4); } @@ -2349,7 +2349,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) mach_log("Separate B2Bank = %02x, AEbank = %02x.\n", mach->regs[0xb2], mach->regs[0xae]); } else { /* Single bank mode */ mach->bank_w = ((mach->regs[0xb2] & 0x1e) >> 1); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { mach->bank_w |= ((mach->regs[0xae] & 3) << 4); } mach->bank_r = mach->bank_w; @@ -2377,7 +2377,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) svga_recalctimings(svga); break; case 0xb8: - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { if ((old ^ val) & 0x40) svga_recalctimings(svga); } else { @@ -2401,7 +2401,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) case 0x2ed: rs2 = !!(mach->accel.ext_ge_config & 0x1000); rs3 = !!(mach->accel.ext_ge_config & 0x2000); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { if (mach->pci_bus && !mach->ramdac_type) ati68860_ramdac_out((addr & 3) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); else @@ -2416,7 +2416,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) case 0x3C9: rs2 = !!(mach->regs[0xa0] & 0x20); rs3 = !!(mach->regs[0xa0] & 0x40); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { if (mach->pci_bus && !mach->ramdac_type) ati68860_ramdac_out((addr & 3) | (rs2 << 2) | (rs3 << 3), val, svga->ramdac, svga); else @@ -2484,7 +2484,7 @@ mach_in(uint16_t addr, void *priv) break; case 0xb0: temp = mach->regs[0xb0] | 0x80; - if (dev->local >= 2) { /*Mach32 VGA 1MB memory*/ + if ((dev->local & 0xff) >= 0x02) { /*Mach32 VGA 1MB memory*/ temp |= 0x08; temp &= ~0x10; } else { /*ATI 28800 VGA 512kB memory*/ @@ -2514,7 +2514,7 @@ mach_in(uint16_t addr, void *priv) case 0x2ed: rs2 = !!(mach->accel.ext_ge_config & 0x1000); rs3 = !!(mach->accel.ext_ge_config & 0x2000); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { if (mach->pci_bus && !mach->ramdac_type) temp = ati68860_ramdac_in((addr & 3) | (rs2 << 2) | (rs3 << 3), svga->ramdac, svga); else @@ -2529,7 +2529,7 @@ mach_in(uint16_t addr, void *priv) case 0x3C9: rs2 = !!(mach->regs[0xa0] & 0x20); rs3 = !!(mach->regs[0xa0] & 0x40); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { if (mach->pci_bus && !mach->ramdac_type) temp = ati68860_ramdac_in((addr & 3) | (rs2 << 2) | (rs3 << 3), svga->ramdac, svga); else @@ -2564,7 +2564,7 @@ mach_recalctimings(svga_t *svga) clock_sel = ((svga->miscout >> 2) & 3) | ((mach->regs[0xbe] & 0x10) >> 1) | ((mach->regs[0xb9] & 2) << 1); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { if (mach->regs[0xad] & 0x04) svga->ma_latch |= 0x40000; @@ -2583,14 +2583,18 @@ mach_recalctimings(svga_t *svga) svga->htotal <<= 1; svga->rowoffset <<= 1; svga->gdcreg[5] &= ~0x40; + svga->attrregs[0x10] &= ~0x40; } - if (mach->regs[0xb0] & 0x20) + if (mach->regs[0xb0] & 0x20) { svga->gdcreg[5] |= 0x40; + svga->attrregs[0x10] |= 0x40; + } + mach_log("ON[0]=%d, ON[1]=%d, exton[0]=%d, exton[1]=%d, vendormode0=%d, vendormode1=%d.\n", dev->on[0], dev->on[1], mach->ext_on[0], mach->ext_on[1], dev->vendor_mode[0], dev->vendor_mode[1]); if (dev->on[0] || dev->on[1]) { mach_log("8514/A ON.\n"); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { dev->h_disp = (dev->hdisp + 1) << 3; dev->h_total = (dev->htotal + 1); dev->v_total = (dev->vtotal + 1); @@ -2639,7 +2643,6 @@ mach_recalctimings(svga_t *svga) dev->v_syncstart >>= 1; dev->v_total >>= 1; } - dev->pitch = dev->ext_pitch; dev->rowoffset = dev->ext_crt_pitch; if ((mach->accel.ext_ge_config & 0x800) || (!(mach->accel.ext_ge_config & 0x8000) && !(mach->accel.ext_ge_config & 0x800))) { @@ -2757,39 +2760,58 @@ mach_recalctimings(svga_t *svga) svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clock_sel, svga->clock_gen); if (mach->regs[0xa7] & 0x80) svga->clock *= 3; - switch (svga->gdcreg[5] & 0x60) { - case 0x00: + if (svga->bpp <= 8) { + if (svga->attrregs[0x10] & 0x40) { /*8bpp mode*/ + svga->map8 = svga->pallook; + if (svga->lowres) /*Low res (320)*/ + svga->render = svga_render_8bpp_lowres; + else { + svga->render = svga_render_8bpp_highres; + svga->ma_latch <<= 1; + svga->rowoffset <<= 1; + } + } else { + mach_log("4bpp.\n"); if (svga->seqregs[1] & 8) /*Low res (320)*/ svga->render = svga_render_4bpp_lowres; else svga->render = svga_render_4bpp_highres; - break; - case 0x20: /*4 colours*/ - if (svga->seqregs[1] & 8) /*Low res (320)*/ - svga->render = svga_render_2bpp_lowres; - else - svga->render = svga_render_2bpp_highres; - break; - case 0x40: - case 0x60: /*256+ colours*/ - switch (svga->bpp) { - default: - case 8: - svga->map8 = svga->pallook; - if (svga->lowres) - svga->render = svga_render_8bpp_lowres; - else { - svga->render = svga_render_8bpp_highres; - svga->ma_latch <<= 1; - svga->rowoffset <<= 1; - } - break; + } + } else { + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: + case 0x60: /*256+ colours*/ + switch (svga->bpp) { + default: + case 8: + svga->map8 = svga->pallook; + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else { + svga->render = svga_render_8bpp_highres; + svga->ma_latch <<= 1; + svga->rowoffset <<= 1; + } + break; - } - break; + } + break; - default: - break; + default: + break; + } } } } @@ -3689,11 +3711,11 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach) WRITE8(port, dev->accel.advfunc_cntl, val); dev->on[port & 1] = (dev->accel.advfunc_cntl & 0x01); - mach_log("%04x: ON=%d.\n", port, dev->on[port & 1]); + mach_log("ATI 8514/A: (0x%04x): ON=%d.\n", port, dev->on[port & 1]); vga_on = !dev->on[port & 1]; mach->ext_on[port & 1] = dev->on[port & 1]; mach32_updatemapping(mach); - mach->ati_mode[port & 1] = 0; + dev->vendor_mode[port & 1] = 0; svga_recalctimings(svga); break; @@ -3770,6 +3792,7 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach) else dev->ext_crt_pitch <<= 1; } + mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val); svga_recalctimings(svga); break; @@ -3814,9 +3837,10 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach) case 0x4aef: WRITE8(port, mach->accel.clock_sel, val); dev->on[port & 1] = mach->accel.clock_sel & 0x01; + mach_log("ATI 8514/A: (0x%04x): ON=%d.\n", port, dev->on[port & 1]); mach->ext_on[port & 1] = dev->on[port & 1]; vga_on = !dev->on[port & 1]; - mach->ati_mode[port & 1] = 1; + dev->vendor_mode[port & 1] = 1; svga_recalctimings(svga); break; @@ -3837,9 +3861,7 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach) case 0x5aee: case 0x5aef: WRITE8(port, mach->shadow_set, val); - if (port & 1) - mach_log("Shadow set = %02x.\n", mach->shadow_set & 0x03); - + mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val); svga_recalctimings(svga); break; @@ -3882,13 +3904,14 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach) case 0x76ef: WRITE8(port, mach->accel.ge_pitch, val); dev->ext_pitch = ((mach->accel.ge_pitch & 0xff) << 3); + mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val); svga_recalctimings(svga); break; case 0x7aee: case 0x7aef: WRITE8(port, mach->accel.ext_ge_config, val); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { if (mach->accel.crt_pitch & 0xff) dev->ext_crt_pitch = mach->accel.crt_pitch & 0xff; switch (mach->accel.ext_ge_config & 0x30) { @@ -3912,9 +3935,10 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach) break; } svga_set_ramdac_type(svga, !!(mach->accel.ext_ge_config & 0x4000)); - mach->ati_mode[port & 1] = 1; + dev->vendor_mode[port & 1] = 1; mach32_updatemapping(mach); } + mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val); svga_recalctimings(svga); break; @@ -3922,7 +3946,7 @@ mach_accel_out(uint16_t port, uint8_t val, mach_t *mach) case 0x7eef: WRITE8(port, mach->accel.eeprom_control, val); ati_eeprom_write(&mach->eeprom, mach->accel.eeprom_control & 4, mach->accel.eeprom_control & 2, mach->accel.eeprom_control & 1); - mach_log("[%04X]: 7EEE+%d VGA ON = %d, Ext = %i, val = %04x, pagesel = %04x.\n", CS, port & 1, vga_on, ibm8514_on, mach->accel.eeprom_control & 0x10ff, (mach->accel.eeprom_control & 0xf0) << 7); + mach_log("ATI 8514/A: (0x%04x) val = %04x.\n", port, val); svga_recalctimings(svga); break; @@ -4274,7 +4298,7 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in case 0xdaee: if (len != 1) { temp = mach->accel.src_x; - if (dev->local >= 2) + if ((dev->local & 0xff) >= 0x02) temp &= 0x7ff; } else temp = mach->accel.src_x & 0xff; @@ -4287,7 +4311,7 @@ mach_accel_in_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, in case 0xdeee: if (len != 1) { temp = mach->accel.src_y; - if (dev->local >= 2) + if ((dev->local & 0xff) >= 0x02) temp &= 0x7ff; } else temp = mach->accel.src_y & 0xff; @@ -4617,10 +4641,47 @@ mach_accel_inl(uint16_t port, void *priv) return temp; } -static void -mach32_write_linear(uint32_t addr, uint8_t val, void *priv) +static uint32_t +mach32_decode_addr(svga_t *svga, uint32_t addr, int write) { - svga_t *svga = (svga_t *) priv; + int memory_map_mode = (svga->gdcreg[6] >> 2) & 3; + + addr &= 0x1ffff; + + switch (memory_map_mode) { + case 0: + break; + case 1: + if (addr >= 0x10000) + return 0xffffffff; + break; + case 2: + addr -= 0x10000; + if (addr >= 0x8000) + return 0xffffffff; + break; + default: + case 3: + addr -= 0x18000; + if (addr >= 0x8000) + return 0xffffffff; + break; + } + + if (memory_map_mode <= 1) { + if (write) + addr = (addr & svga->banked_mask) + svga->write_bank; + else + addr = (addr & svga->banked_mask) + svga->read_bank; + } + + return addr; +} + +static __inline void +mach32_write_common(uint32_t addr, uint8_t val, int linear, mach_t *mach) +{ + svga_t *svga = &mach->svga; ibm8514_t *dev = (ibm8514_t *) svga->dev8514; int writemask2 = svga->writemask; int reset_wm = 0; @@ -4631,6 +4692,12 @@ mach32_write_linear(uint32_t addr, uint8_t val, void *priv) cycles -= svga->monitor->mon_video_timing_write_b; + if (!linear) { + addr = mach32_decode_addr(svga, addr, 1); + if (addr == 0xffffffff) + return; + } + if (!(svga->gdcreg[6] & 1)) svga->fullchange = 2; @@ -4639,6 +4706,9 @@ mach32_write_linear(uint32_t addr, uint8_t val, void *priv) addr &= ~3; } else if (svga->chain4 && (svga->writemode < 4)) { writemask2 = 1 << (addr & 3); + if (!linear) + addr &= ~3; + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); } else if (svga->chain2_write) { writemask2 &= ~0xa; @@ -4750,40 +4820,31 @@ static void mach32_write(uint32_t addr, uint8_t val, void *priv) { mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; - - addr = (addr & svga->banked_mask) + svga->write_bank; - mach32_write_linear(addr, val, svga); + mach32_write_common(addr, val, 0, mach); } static void mach32_writew(uint32_t addr, uint16_t val, void *priv) { mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; - - addr = (addr & svga->banked_mask) + svga->write_bank; - mach32_write_linear(addr, val & 0xff, svga); - mach32_write_linear(addr + 1, val >> 8, svga); + mach32_write_common(addr, val & 0xff, 0, mach); + mach32_write_common(addr + 1, val >> 8, 0, mach); } static void mach32_writel(uint32_t addr, uint32_t val, void *priv) { mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; - - addr = (addr & svga->banked_mask) + svga->write_bank; - mach32_write_linear(addr, val & 0xff, svga); - mach32_write_linear(addr + 1, val >> 8, svga); - mach32_write_linear(addr + 2, val >> 16, svga); - mach32_write_linear(addr + 3, val >> 24, svga); + mach32_write_common(addr, val & 0xff, 0, mach); + mach32_write_common(addr + 1, val >> 8, 0, mach); + mach32_write_common(addr + 2, val >> 16, 0, mach); + mach32_write_common(addr + 3, val >> 24, 0, mach); } -static uint8_t -mach32_read_linear(uint32_t addr, void *priv) +static __inline uint8_t +mach32_read_common(uint32_t addr, int linear, mach_t *mach) { - svga_t *svga = (svga_t *) priv; + svga_t *svga = &mach->svga; const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint32_t latch_addr = 0; int readplane = svga->readplane; @@ -4793,6 +4854,12 @@ mach32_read_linear(uint32_t addr, void *priv) cycles -= svga->monitor->mon_video_timing_read_b; + if (!linear) { + addr = mach32_decode_addr(svga, addr, 0); + if (addr == 0xffffffff) + return 0xff; + } + count = 2; latch_addr = (addr << count) & svga->decode_mask; @@ -4865,11 +4932,9 @@ static uint8_t mach32_read(uint32_t addr, void *priv) { mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; uint8_t ret; - addr = (addr & svga->banked_mask) + svga->read_bank; - ret = mach32_read_linear(addr, svga); + ret = mach32_read_common(addr, 0, mach); return ret; } @@ -4877,12 +4942,10 @@ static uint16_t mach32_readw(uint32_t addr, void *priv) { mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; uint16_t ret; - addr = (addr & svga->banked_mask) + svga->read_bank; - ret = mach32_read_linear(addr, svga); - ret |= (mach32_read_linear(addr + 1, svga) << 8); + ret = mach32_read_common(addr, 0, mach); + ret |= (mach32_read_common(addr + 1, 0, mach) << 8); return ret; } @@ -4890,23 +4953,22 @@ static uint32_t mach32_readl(uint32_t addr, void *priv) { mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; uint32_t ret; - addr = (addr & svga->banked_mask) + svga->read_bank; - ret = mach32_read_linear(addr, svga); - ret |= (mach32_read_linear(addr + 1, svga) << 8); - ret |= (mach32_read_linear(addr + 2, svga) << 16); - ret |= (mach32_read_linear(addr + 3, svga) << 24); + ret = mach32_read_common(addr, 0, mach); + ret |= (mach32_read_common(addr + 1, 0, mach) << 8); + ret |= (mach32_read_common(addr + 2, 0, mach) << 16); + ret |= (mach32_read_common(addr + 3, 0, mach) << 24); return ret; } static void mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) { - mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; - uint8_t port_dword = addr & 0xfc; + mach_t *mach = (mach_t *) priv; + svga_t *svga = &mach->svga; + const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { @@ -4918,17 +4980,21 @@ mach32_ap_writeb(uint32_t addr, uint8_t val, void *priv) mach_accel_outb(0x02e8 + (addr & 1) + (port_dword << 8), val, mach); } } else { - mach_log("Linear WORDB Write=%08x.\n", addr); - mach32_write_linear(addr, val, svga); + mach_log("Linear WORDB Write=%08x, val=%02x.\n", addr, val); + if (dev->on[0] || dev->on[1]) + mach32_write_common(addr, val, 1, mach); + else + svga_write_linear(addr, val, svga); } } static void mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) { - mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; - uint8_t port_dword = addr & 0xfc; + mach_t *mach = (mach_t *) priv; + svga_t *svga = &mach->svga; + const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { @@ -4940,18 +5006,22 @@ mach32_ap_writew(uint32_t addr, uint16_t val, void *priv) mach_accel_outw(0x02e8 + (port_dword << 8), val, mach); } } else { - mach_log("Linear WORDW Write=%08x.\n", addr); - mach32_write_linear(addr, val & 0xff, svga); - mach32_write_linear(addr + 1, val >> 8, svga); + mach_log("Linear WORDW Write=%08x, val=%04x.\n", addr, val); + if (dev->on[0] || dev->on[1]) { + mach32_write_common(addr, val & 0xff, 1, mach); + mach32_write_common(addr + 1, val >> 8, 1, mach); + } else + svga_writew_linear(addr, val, svga); } } static void mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) { - mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; - uint8_t port_dword = addr & 0xfc; + mach_t *mach = (mach_t *) priv; + svga_t *svga = &mach->svga; + const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { @@ -4965,31 +5035,40 @@ mach32_ap_writel(uint32_t addr, uint32_t val, void *priv) mach_accel_outw(0x02e8 + (port_dword << 8) + 4, val >> 16, mach); } } else { - mach_log("Linear WORDL Write=%08x.\n", addr); - mach32_write_linear(addr, val & 0xff, svga); - mach32_write_linear(addr + 1, val >> 8, svga); - mach32_write_linear(addr + 2, val >> 16, svga); - mach32_write_linear(addr + 3, val >> 24, svga); + mach_log("Linear WORDL Write=%08x, val=%08x.\n", addr, val); + if (dev->on[0] || dev->on[1]) { + mach32_write_common(addr, val & 0xff, 1, mach); + mach32_write_common(addr + 1, val >> 8, 1, mach); + mach32_write_common(addr + 2, val >> 16, 1, mach); + mach32_write_common(addr + 3, val >> 24, 1, mach); + } else + svga_writel_linear(addr, val, svga); } } static uint8_t mach32_ap_readb(uint32_t addr, void *priv) { - mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; + mach_t *mach = (mach_t *) priv; + svga_t *svga = &mach->svga; + const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint8_t temp; - uint8_t port_dword = addr & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if (addr & 0x100) { + if (addr & 0x100) temp = mach_accel_inb(0x02ee + (addr & 1) + (port_dword << 8), mach); - } else { + else temp = mach_accel_inb(0x02e8 + (addr & 1) + (port_dword << 8), mach); - } - } else - temp = mach32_read_linear(addr, svga); + } else { + if (dev->on[0] || dev->on[1]) + temp = mach32_read_common(addr, 1, mach); + else + temp = svga_read_linear(addr, svga); + + mach_log("Linear WORDB Read=%08x, ret=%02x, fast=%d.\n", addr, temp, svga->fast); + } return temp; } @@ -4997,21 +5076,26 @@ mach32_ap_readb(uint32_t addr, void *priv) static uint16_t mach32_ap_readw(uint32_t addr, void *priv) { - mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; + mach_t *mach = (mach_t *) priv; + svga_t *svga = &mach->svga; + const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint16_t temp; - uint8_t port_dword = addr & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { - if (addr & 0x100) { + if (addr & 0x100) temp = mach_accel_inw(0x02ee + (port_dword << 8), mach); - } else { + else temp = mach_accel_inw(0x02e8 + (port_dword << 8), mach); - } } else { - temp = mach32_read_linear(addr, svga); - temp |= (mach32_read_linear(addr + 1, svga) << 8); + if (dev->on[0] || dev->on[1]) { + temp = mach32_read_common(addr, 1, mach); + temp |= (mach32_read_common(addr + 1, 1, mach) << 8); + } else + temp = svga_readw_linear(addr, svga); + + mach_log("Linear WORDW Read=%08x, ret=%04x.\n", addr, temp); } return temp; @@ -5020,10 +5104,11 @@ mach32_ap_readw(uint32_t addr, void *priv) static uint32_t mach32_ap_readl(uint32_t addr, void *priv) { - mach_t *mach = (mach_t *) priv; - svga_t *svga = &mach->svga; + mach_t *mach = (mach_t *) priv; + svga_t *svga = &mach->svga; + const ibm8514_t *dev = (ibm8514_t *) svga->dev8514; uint32_t temp; - uint8_t port_dword = addr & 0xfc; + uint8_t port_dword = addr & 0xfc; if (((mach->local_cntl & 0x20) || (mach->pci_cntl_reg & 0x80)) && ((addr >= ((mach->ap_size << 20) - 0x200)) && (addr < (mach->ap_size << 20)))) { @@ -5035,10 +5120,15 @@ mach32_ap_readl(uint32_t addr, void *priv) temp |= (mach_accel_inw(0x02e8 + (port_dword << 8) + 4, mach) << 8); } } else { - temp = mach32_read_linear(addr, svga); - temp |= (mach32_read_linear(addr + 1, svga) << 8); - temp |= (mach32_read_linear(addr + 2, svga) << 16); - temp |= (mach32_read_linear(addr + 3, svga) << 24); + if (dev->on[0] || dev->on[1]) { + temp = mach32_read_common(addr, 1, mach); + temp |= (mach32_read_common(addr + 1, 1, mach) << 8); + temp |= (mach32_read_common(addr + 2, 1, mach) << 16); + temp |= (mach32_read_common(addr + 3, 1, mach) << 24); + } else + temp = svga_readl_linear(addr, svga); + + mach_log("Linear WORDL Read=%08x, ret=%08x, ON0=%d, ON1=%d.\n", addr, temp, dev->on[0], dev->on[1]); } return temp; @@ -5098,7 +5188,7 @@ mach32_updatemapping(mach_t *mach) mach->ap_size = 4; mem_mapping_disable(&mach->mmio_linear_mapping); } - if ((mach->ext_on[0] || mach->ext_on[1]) && (dev->local >= 2) && (mach->ati_mode[0] || mach->ati_mode[1])) { + if (((dev->local & 0xff) >= 0x02) && (dev->on[0] || dev->on[1]) && (mach->ext_on[0] || mach->ext_on[1]) && (dev->vendor_mode[0] || dev->vendor_mode[1])) { mach_log("ExtON.\n"); mem_mapping_set_handler(&svga->mapping, mach32_read, mach32_readw, mach32_readl, mach32_write, mach32_writew, mach32_writel); mem_mapping_set_p(&svga->mapping, mach); @@ -5120,18 +5210,25 @@ mach32_hwcursor_draw(svga_t *svga, int displine) uint32_t color0; uint32_t color1; - if (dev->accel_bpp == 8) { - color0 = dev->pallook[mach->cursor_col_0]; - color1 = dev->pallook[mach->cursor_col_1]; - } else if (dev->accel_bpp == 15) { - color0 = video_15to32[((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0) & 0xffff]; - color1 = video_15to32[((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1) & 0xffff]; - } else if (dev->accel_bpp == 16) { - color0 = video_16to32[((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0) & 0xffff]; - color1 = video_16to32[((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1) & 0xffff]; - } else { - color0 = ((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0); - color1 = ((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1); + switch (dev->accel_bpp) { + case 8: + color0 = dev->pallook[mach->cursor_col_0]; + color1 = dev->pallook[mach->cursor_col_1]; + break; + case 15: + color0 = video_15to32[((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0) & 0xffff]; + color1 = video_15to32[((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1) & 0xffff]; + break; + case 16: + color0 = video_16to32[((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0) & 0xffff]; + color1 = video_16to32[((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1) & 0xffff]; + break; + case 24: + case 32: + default: + color0 = ((mach->ext_cur_col_0_r << 16) | (mach->ext_cur_col_0_g << 8) | mach->cursor_col_0); + color1 = ((mach->ext_cur_col_1_r << 16) | (mach->ext_cur_col_1_g << 8) | mach->cursor_col_1); + break; } if (dev->interlace && dev->hwcursor_oddeven) @@ -5603,7 +5700,7 @@ mach8_init(const device_t *info) mach->memory = device_get_config_int("memory"); mach->ramdac_type = mach->pci_bus ? device_get_config_int("ramdac") : 1; - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { if (mach->pci_bus) { if (mach->has_bios) { rom_init(&mach->bios_rom, @@ -5639,7 +5736,7 @@ mach8_init(const device_t *info) 0, MEM_MAPPING_EXTERNAL); } - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { svga_init(info, svga, mach, mach->memory << 10, /*default: 2MB for Mach32*/ mach_recalctimings, mach_in, mach_out, @@ -5721,7 +5818,7 @@ mach8_init(const device_t *info) io_sethandler(0x02ea, 4, mach_in, NULL, NULL, mach_out, NULL, NULL, mach); mach_io_set(mach); - if (dev->local >= 2) { + if ((dev->local & 0xff) >= 0x02) { svga->decode_mask = (4 << 20) - 1; mach->cursor_col_1 = 0xff; mach->ext_cur_col_1_r = 0xff; diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 83c4f5a63..05e45b7d7 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -650,6 +650,23 @@ gd54xx_is_5434(svga_t *svga) return 0; } +static void +gd54xx_set_svga_fast(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5422) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5424)) + svga->fast = ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && + ((svga->chain4 && svga->packed_chain4) || svga->fb_only) && + !(svga->adv_flags & FLAG_ADDR_BY8); + /* TODO: needs verification on other Cirrus chips */ + else + svga->fast = ((svga->gdcreg[8] == 0xff) && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && ((svga->chain4 && svga->packed_chain4) || + svga->fb_only); +} + static void gd54xx_out(uint16_t addr, uint8_t val, void *priv) { @@ -793,13 +810,14 @@ gd54xx_out(uint16_t addr, uint8_t val, void *priv) break; case 0x07: svga->packed_chain4 = svga->seqregs[7] & 1; - svga_recalctimings(svga); if (gd54xx_is_5422(svga)) gd543x_recalc_mapping(gd54xx); else svga->seqregs[svga->seqaddr] &= 0x0f; if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) svga->set_reset_disabled = svga->seqregs[7] & 1; + gd54xx_set_svga_fast(gd54xx); + svga_recalctimings(svga); break; case 0x17: if (gd54xx_is_5422(svga)) @@ -919,10 +937,8 @@ gd54xx_out(uint16_t addr, uint8_t val, void *priv) break; } - if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5422) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5424)) - svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && ((svga->chain4 && svga->packed_chain4) || svga->fb_only) && !(svga->adv_flags & FLAG_ADDR_BY8); /*TODO: needs verification on other Cirrus chips*/ - else - svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && ((svga->chain4 && svga->packed_chain4) || svga->fb_only); + gd54xx_set_svga_fast(gd54xx); + if (((svga->gdcaddr == 5) && ((val ^ o) & 0x70)) || ((svga->gdcaddr == 6) && ((val ^ o) & 1))) svga_recalctimings(svga); } else { diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 1b9b3cf7c..5f5efcd9e 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -219,7 +219,7 @@ svga_out(uint16_t addr, uint8_t val, void *priv) dev->on[1] = dev->on[0]; } - svga_log("3C3: XGA ON = %d.\n", xga->on); + svga_log("3C3: VGA ON = %d.\n", val & 0x01); vga_on = val & 0x01; break; case 0x3c4: @@ -611,7 +611,7 @@ svga_recalctimings(svga_t *svga) svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; - svga->lowres = svga->attrregs[0x10] & 0x40; + svga->lowres = !!(svga->attrregs[0x10] & 0x40); svga->interlace = 0; @@ -742,7 +742,7 @@ svga_recalctimings(svga_t *svga) } if (ibm8514_active && (svga->dev8514 != NULL)) { - if (!dev->local) + if ((dev->local & 0xff) == 0x00) ibm8514_recalctimings(svga); } diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index f53ba9bb4..17b6dfdb5 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -519,7 +519,6 @@ xga_ext_outb(uint16_t addr, uint8_t val, void *priv) xga_updatemapping(svga); break; case 4: - xga->access_mode &= ~8; if ((xga->disp_cntl_2 & 7) == 4) xga->aperture_cntl = 0; break; @@ -926,16 +925,22 @@ xga_accel_read_pattern_map_pixel(svga_t *svga, int x, int y, int map, uint32_t b addr += (x >> 3); if (!skip) { READ(addr, byte); - } else { + } else byte = mem_readb_phys(addr); - } - if (xga->linear_endian_reverse) { + + if (xga->linear_endian_reverse) bits = 7 - (x & 7); - } else { - if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) - bits = (x & 7); - else { - bits = 7 - (x & 7); + else { + if (xga->accel.px_map_format[xga->accel.dst_map] & 8) { + if ((xga->accel.px_map_format[xga->accel.src_map] & 8) && (xga->accel.px_map_format[map] & 8)) + bits = (x & 7); + else + bits = 7 - (x & 7); + } else { + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) + bits = (x & 7); + else + bits = 7 - (x & 7); } } px = (byte >> bits) & 1; @@ -966,17 +971,16 @@ xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int addr += (x >> 3); if (!skip) { READ(addr, byte); - } else { + } else byte = mem_readb_phys(addr); - } - if (xga->linear_endian_reverse) { + + if (xga->linear_endian_reverse) bits = 7 - (x & 7); - } else { + else { if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) bits = (x & 7); - else { + else bits = 7 - (x & 7); - } } px = (byte >> bits) & 1; return px; @@ -985,9 +989,9 @@ xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int addr += (x >> 1); if (!skip) { READ(addr, byte); - } else { + } else byte = mem_readb_phys(addr); - } + return byte; case 3: /*8-bit*/ addr += (y * width); @@ -1010,9 +1014,8 @@ xga_accel_read_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, int } else { if (!skip) { READW(addr, byte); - } else { + } else byte = mem_readb_phys(addr) | (mem_readb_phys(addr + 1) << 8); - } } return byte; @@ -1045,9 +1048,9 @@ xga_accel_write_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, ui addr += (x >> 3); if (!skip) { READ(addr, byte); - } else { + } else byte = mem_readb_phys(addr); - } + if (xga->linear_endian_reverse) { mask = 1 << (7 - (x & 7)); } else { @@ -1079,14 +1082,13 @@ xga_accel_write_map_pixel(svga_t *svga, int x, int y, int map, uint32_t base, ui } else { byte = mem_readb_phys(addr); } - if (xga->linear_endian_reverse) { + if (xga->linear_endian_reverse) mask = 0x0f << ((1 - (x & 1)) << 2); - } else { - if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) { + else { + if ((xga->accel.px_map_format[map] & 8) && !(xga->access_mode & 8)) mask = 0x0f << ((x & 1) << 2); - } else { + else mask = 0x0f << ((1 - (x & 1)) << 2); - } } byte = (byte & ~mask) | (pixel & mask); if (!skip) { @@ -1136,8 +1138,8 @@ xga_short_stroke(svga_t *svga, uint8_t ssv) uint32_t srcbase = xga->accel.px_map_base[xga->accel.src_map]; int y = ssv & 0x0f; int x = 0; - int dx; - int dy; + int16_t dx; + int16_t dy; int dirx = 0; int diry = 0; @@ -1269,41 +1271,29 @@ xga_line_draw_write(svga_t *svga) int err; int tmpswap; int steep = 1; - int xdir; - int ydir; + int xdir = (xga->accel.octant & 0x04) ? -1 : 1; + int ydir = (xga->accel.octant & 0x02) ? -1 : 1; int y = xga->accel.blt_width; int x = 0; - int dx; - int dy; + int16_t dx; + int16_t dy; int draw_pixel; - dminor = (xga->accel.bres_k1); + dminor = xga->accel.bres_k1; if (xga->accel.bres_k1 & 0x2000) dminor |= ~0x1fff; dminor >>= 1; - destxtmp = (xga->accel.bres_k2); + destxtmp = xga->accel.bres_k2; if (xga->accel.bres_k2 & 0x2000) destxtmp |= ~0x1fff; dmajor = -(destxtmp - (dminor << 1)) >> 1; - err = (xga->accel.bres_err_term); + err = xga->accel.bres_err_term; if (xga->accel.bres_err_term & 0x2000) err |= ~0x1fff; - if (xga->accel.octant & 0x02) { - ydir = -1; - } else { - ydir = 1; - } - - if (xga->accel.octant & 0x04) { - xdir = -1; - } else { - xdir = 1; - } - dx = xga->accel.dst_map_x & 0x1fff; if (xga->accel.dst_map_x >= 0x1800) dx |= ~0x17ff; @@ -1492,26 +1482,14 @@ xga_bitblt(svga_t *svga) uint32_t srcwidth = xga->accel.px_map_width[xga->accel.src_map]; uint32_t patheight = xga->accel.px_map_height[xga->accel.pat_src]; uint32_t srcheight = xga->accel.px_map_height[xga->accel.src_map]; -#if 0 uint32_t dstheight = xga->accel.px_map_height[xga->accel.dst_map]; -#endif uint32_t frgdcol = xga->accel.frgd_color; uint32_t bkgdcol = xga->accel.bkgd_color; + int16_t dx; + int16_t dy; int mix = 0; - int xdir; - int ydir; - - if (xga->accel.octant & 0x02) { - ydir = -1; - } else { - ydir = 1; - } - - if (xga->accel.octant & 0x04) { - xdir = -1; - } else { - xdir = 1; - } + int xdir = (xga->accel.octant & 0x04) ? -1 : 1; + int ydir = (xga->accel.octant & 0x02) ? -1 : 1; xga->accel.x = xga->accel.blt_width & 0xfff; xga->accel.y = xga->accel.blt_height & 0xfff; @@ -1520,12 +1498,13 @@ xga_bitblt(svga_t *svga) xga->accel.sy = xga->accel.src_map_y & 0xfff; xga->accel.px = xga->accel.pat_map_x & 0xfff; xga->accel.py = xga->accel.pat_map_y & 0xfff; - xga->accel.dx = xga->accel.dst_map_x & 0x1fff; + dx = xga->accel.dst_map_x & 0x1fff; + dy = xga->accel.dst_map_y & 0x1fff; if (xga->accel.dst_map_x >= 0x1800) - xga->accel.dx |= ~0x17ff; - xga->accel.dy = xga->accel.dst_map_y & 0x1fff; + dx |= ~0x17ff; if (xga->accel.dst_map_y >= 0x1800) - xga->accel.dy |= ~0x17ff; + dy |= ~0x17ff; + xga_log("D(%d,%d), SWH(%d,%d), BLT(%d,%d), dstwidth=%d.\n", dx, dy, xga->accel.x, xga->accel.y, srcwidth, srcheight, dstwidth); xga->accel.pattern = 0; @@ -1544,44 +1523,46 @@ xga_bitblt(svga_t *svga) xga->accel.pattern = 1; else { if ((dstwidth == (xga->h_disp - 1)) && (srcwidth == 1)) { - if ((xga->accel.dst_map == 1) && (xga->accel.src_map == 2) && xga->linear_endian_reverse) { - if ((xga->accel.px_map_format[xga->accel.dst_map] >= 0x0b) && (xga->accel.px_map_format[xga->accel.src_map] >= 0x0b)) { + if ((xga->accel.dst_map == 1) && (xga->accel.src_map == 2)) { + if ((xga->accel.px_map_format[xga->accel.dst_map] >= 0x0b) && (xga->accel.px_map_format[xga->accel.src_map] >= 0x0b)) xga->accel.pattern = 1; - } } } } + xga_log("PAT8: PatFormat=%x, SrcFormat=%x, DstFormat=%x.\n", xga->accel.px_map_format[xga->accel.pat_src] & 8, (xga->accel.px_map_format[xga->accel.src_map]), (xga->accel.px_map_format[xga->accel.dst_map])); xga_log("Pattern Map = 8: CMD = %08x: SRCBase = %08x, DSTBase = %08x, from/to vram dir = %d, " "cmd dir = %06x\n", xga->accel.command, srcbase, dstbase, xga->from_to_vram, xga->accel.dir_cmd); xga_log("CMD = %08x: Y = %d, X = %d, patsrc = %02x, srcmap = %d, dstmap = %d, py = %d, " "sy = %d, dy = %d, width0 = %d, width1 = %d, width2 = %d, width3 = %d\n", xga->accel.command, xga->accel.y, xga->accel.x, xga->accel.pat_src, xga->accel.src_map, - xga->accel.dst_map, xga->accel.py, xga->accel.sy, xga->accel.dy, + xga->accel.dst_map, xga->accel.py, xga->accel.sy, dy, xga->accel.px_map_width[0], xga->accel.px_map_width[1], xga->accel.px_map_width[2], xga->accel.px_map_width[3]); while (xga->accel.y >= 0) { if (xga->accel.command & 0xc0) { - if ((xga->accel.dx >= xga->accel.mask_map_origin_x_off) && (xga->accel.dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (xga->accel.dy >= xga->accel.mask_map_origin_y_off) && (xga->accel.dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : frgdcol; - dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { old_dest_dat = dest_dat; ROP(1, dest_dat, src_dat); dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); - xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); } } } else { - src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : frgdcol; - dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); - if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { - old_dest_dat = dest_dat; - ROP(1, dest_dat, src_dat); - dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); - xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); + if ((dx >= 0) && (dx <= dstwidth) && (dy >= 0) && (dy <= dstheight)) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : frgdcol; + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); + if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(1, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); + } } } @@ -1589,17 +1570,19 @@ xga_bitblt(svga_t *svga) xga->accel.sx = ((xga->accel.sx + xdir) & srcwidth) | (xga->accel.sx & ~srcwidth); else xga->accel.sx += xdir; - xga->accel.dx += xdir; + + dx += xdir; xga->accel.x--; if (xga->accel.x < 0) { - xga->accel.x = (xga->accel.blt_width & 0xfff); + xga->accel.x = xga->accel.blt_width & 0xfff; - xga->accel.dx = xga->accel.dst_map_x & 0x1fff; + dx = xga->accel.dst_map_x & 0x1fff; if (xga->accel.dst_map_x >= 0x1800) - xga->accel.dx |= ~0x17ff; + dx |= ~0x17ff; xga->accel.sx = xga->accel.src_map_x & 0xfff; - xga->accel.dy += ydir; + dy += ydir; + if (xga->accel.pattern) xga->accel.sy = ((xga->accel.sy + ydir) & srcheight) | (xga->accel.sy & ~srcheight); else @@ -1608,8 +1591,8 @@ xga_bitblt(svga_t *svga) xga->accel.y--; if (xga->accel.y < 0) { - xga->accel.dst_map_x = xga->accel.dx; - xga->accel.dst_map_y = xga->accel.dy; + xga->accel.dst_map_x = dx; + xga->accel.dst_map_y = dy; return; } } @@ -1620,13 +1603,12 @@ xga_bitblt(svga_t *svga) else { if (dstwidth == (xga->h_disp - 1)) { if (srcwidth == (xga->h_disp - 1)) { - if ((xga->accel.src_map == 1) && (xga->accel.dst_map == 1) && (xga->accel.pat_src == 2) && xga->linear_endian_reverse) { - if ((xga->accel.px_map_format[xga->accel.dst_map] >= 0x0b) && (xga->accel.px <= 7) && (xga->accel.py <= 3)) { + if ((xga->accel.src_map == 1) && (xga->accel.dst_map == 1) && (xga->accel.pat_src == 2)) { + if ((xga->accel.px_map_format[xga->accel.dst_map] >= 0x0b) && (xga->accel.px <= 7) && (xga->accel.py <= 3)) xga->accel.pattern = 1; - } } } else { - if (!xga->accel.src_map && (xga->accel.dst_map == 1) && (xga->accel.pat_src == 2) && xga->linear_endian_reverse) { + if (!xga->accel.src_map && (xga->accel.dst_map == 1) && (xga->accel.pat_src == 2)) { if ((xga->accel.px_map_format[xga->accel.dst_map] >= 0x0b) && (xga->accel.px <= 7) && (xga->accel.py <= 3)) { if ((patwidth >= 7) && ((xga->accel.command & 0xc0) == 0x40)) xga->accel.pattern = 0; @@ -1638,6 +1620,7 @@ xga_bitblt(svga_t *svga) } } + xga_log("PAT%d: PatFormat=%x, SrcFormat=%x, DstFormat=%x.\n", xga->accel.pat_src, xga->accel.px_map_format[xga->accel.pat_src] & 8, (xga->accel.px_map_format[xga->accel.src_map]), (xga->accel.px_map_format[xga->accel.dst_map])); xga_log("XGA bitblt linear endian reverse=%d, octanty=%d, src command = %08x, pxsrcmap=%x, " "pxdstmap=%x, srcmap=%d, patmap=%d, dstmap=%d, dstwidth=%d, dstheight=%d, srcwidth=%d, " "srcheight=%d, dstbase=%08x, srcbase=%08x.\n", xga->linear_endian_reverse, ydir, @@ -1661,7 +1644,7 @@ xga_bitblt(svga_t *svga) area_state ^= 1; if (xga->accel.command & 0xc0) { - if ((xga->accel.dx >= xga->accel.mask_map_origin_x_off) && (xga->accel.dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (xga->accel.dy >= xga->accel.mask_map_origin_y_off) && (xga->accel.dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { if (area_state) src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : frgdcol; else @@ -1670,56 +1653,58 @@ xga_bitblt(svga_t *svga) if ((xga->accel.px_map_format[xga->accel.dst_map] & 7) <= 3) src_dat &= 0xff; - dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { old_dest_dat = dest_dat; ROP(area_state, dest_dat, src_dat); dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); xga_log("1SRCDat=%02x, DSTDat=%02x, Old=%02x, MIX=%d.\n", src_dat, dest_dat, old_dest_dat, area_state); - xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); } } } else { - if (area_state) - src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : frgdcol; - else - src_dat = (((xga->accel.command >> 30) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : bkgdcol; + if ((dx >= 0) && (dx <= dstwidth) && (dy >= 0) && (dy <= dstheight)) { + if (area_state) + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : frgdcol; + else + src_dat = (((xga->accel.command >> 30) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : bkgdcol; - if ((xga->accel.px_map_format[xga->accel.dst_map] & 7) <= 3) - src_dat &= 0xff; + if ((xga->accel.px_map_format[xga->accel.dst_map] & 7) <= 3) + src_dat &= 0xff; - dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); - if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { - old_dest_dat = dest_dat; - ROP(area_state, dest_dat, src_dat); - dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); - xga_log("2Fill: NumXY(%d,%d): DXY(%d,%d): SRCDat=%02x, DSTDat=%02x, Old=%02x, frgdcol=%02x, bkgdcol=%02x, MIX=%d, frgdmix=%02x, bkgdmix=%02x, dstmapfmt=%02x, srcmapfmt=%02x, srcmapnum=%d.\n", x, y, xga->accel.dx, xga->accel.dy, src_dat, dest_dat, old_dest_dat, frgdcol, bkgdcol, area_state, xga->accel.frgd_mix & 0x1f, xga->accel.bkgd_mix & 0x1f, xga->accel.px_map_format[xga->accel.dst_map] & 0x0f, xga->accel.px_map_format[xga->accel.src_map] & 0x0f, xga->accel.src_map); - xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); + if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(area_state, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + xga_log("2Fill: NumXY(%d,%d): DXY(%d,%d): SRCDat=%02x, DSTDat=%02x, Old=%02x, frgdcol=%02x, bkgdcol=%02x, MIX=%d, frgdmix=%02x, bkgdmix=%02x, dstmapfmt=%02x, srcmapfmt=%02x, srcmapnum=%d.\n", x, y, dx, dy, src_dat, dest_dat, old_dest_dat, frgdcol, bkgdcol, area_state, xga->accel.frgd_mix & 0x1f, xga->accel.bkgd_mix & 0x1f, xga->accel.px_map_format[xga->accel.dst_map] & 0x0f, xga->accel.px_map_format[xga->accel.src_map] & 0x0f, xga->accel.src_map); + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); + } } } xga->accel.sx = ((xga->accel.sx + 1) & srcwidth) | (xga->accel.sx & ~srcwidth); xga->accel.px = ((xga->accel.px + 1) & patwidth) | (xga->accel.px & ~patwidth); - xga->accel.dx++; + dx++; xga->accel.x--; if (xga->accel.x < 0) { area_state = 0; xga->accel.y--; xga->accel.x = xga->accel.blt_width & 0xfff; - xga->accel.dx = xga->accel.dst_map_x & 0x1fff; + dx = xga->accel.dst_map_x & 0x1fff; if (xga->accel.dst_map_x >= 0x1800) - xga->accel.dx |= ~0x17ff; + dx |= ~0x17ff; xga->accel.sx = xga->accel.src_map_x & 0xfff; xga->accel.px = xga->accel.pat_map_x & 0xfff; xga->accel.sy = ((xga->accel.sy + ydir) & srcheight) | (xga->accel.sy & ~srcheight); xga->accel.py += ydir; - xga->accel.dy += ydir; + dy += ydir; if (xga->accel.y < 0) { - xga->accel.dst_map_x = xga->accel.dx; - xga->accel.dst_map_y = xga->accel.dy; + xga->accel.dst_map_x = dx; + xga->accel.dst_map_y = dy; return; } } @@ -1729,32 +1714,34 @@ xga_bitblt(svga_t *svga) mix = xga_accel_read_pattern_map_pixel(svga, xga->accel.px, xga->accel.py, xga->accel.pat_src, patbase, patwidth + 1); if (xga->accel.command & 0xc0) { - if ((xga->accel.dx >= xga->accel.mask_map_origin_x_off) && (xga->accel.dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (xga->accel.dy >= xga->accel.mask_map_origin_y_off) && (xga->accel.dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { + if ((dx >= xga->accel.mask_map_origin_x_off) && (dx <= ((xga->accel.px_map_width[0] & 0xfff) + xga->accel.mask_map_origin_x_off)) && (dy >= xga->accel.mask_map_origin_y_off) && (dy <= ((xga->accel.px_map_height[0] & 0xfff) + xga->accel.mask_map_origin_y_off))) { if (mix) { src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : frgdcol; } else { src_dat = (((xga->accel.command >> 30) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : bkgdcol; } - dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { old_dest_dat = dest_dat; ROP(mix, dest_dat, src_dat); dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); - xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); } } } else { - if (mix) { - src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : frgdcol; - } else { - src_dat = (((xga->accel.command >> 30) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : bkgdcol; - } - dest_dat = xga_accel_read_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); - if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { - old_dest_dat = dest_dat; - ROP(mix, dest_dat, src_dat); - dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); - xga_accel_write_map_pixel(svga, xga->accel.dx, xga->accel.dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); + if ((dx >= 0) && (dx <= dstwidth) && (dy >= 0) && (dy <= dstheight)) { + if (mix) { + src_dat = (((xga->accel.command >> 28) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : frgdcol; + } else { + src_dat = (((xga->accel.command >> 30) & 3) == 2) ? xga_accel_read_map_pixel(svga, xga->accel.sx, xga->accel.sy, xga->accel.src_map, srcbase, srcwidth + 1, 1) : bkgdcol; + } + dest_dat = xga_accel_read_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dstwidth + 1, 0); + if ((xga->accel.cc_cond == 4) || ((xga->accel.cc_cond == 1) && (dest_dat > color_cmp)) || ((xga->accel.cc_cond == 2) && (dest_dat == color_cmp)) || ((xga->accel.cc_cond == 3) && (dest_dat < color_cmp)) || ((xga->accel.cc_cond == 5) && (dest_dat >= color_cmp)) || ((xga->accel.cc_cond == 6) && (dest_dat != color_cmp)) || ((xga->accel.cc_cond == 7) && (dest_dat <= color_cmp))) { + old_dest_dat = dest_dat; + ROP(mix, dest_dat, src_dat); + dest_dat = (dest_dat & plane_mask) | (old_dest_dat & ~plane_mask); + xga_accel_write_map_pixel(svga, dx, dy, xga->accel.dst_map, dstbase, dest_dat, dstwidth + 1); + } } } @@ -1763,15 +1750,16 @@ xga_bitblt(svga_t *svga) xga->accel.px = ((xga->accel.px + xdir) & patwidth) | (xga->accel.px & ~patwidth); else xga->accel.px += xdir; - xga->accel.dx += xdir; + + dx += xdir; xga->accel.x--; if (xga->accel.x < 0) { xga->accel.y--; - xga->accel.x = (xga->accel.blt_width & 0xfff); + xga->accel.x = xga->accel.blt_width & 0xfff; - xga->accel.dx = xga->accel.dst_map_x & 0x1fff; + dx = xga->accel.dst_map_x & 0x1fff; if (xga->accel.dst_map_x >= 0x1800) - xga->accel.dx |= ~0x17ff; + dx |= ~0x17ff; xga->accel.sx = xga->accel.src_map_x & 0xfff; xga->accel.px = xga->accel.pat_map_x & 0xfff; @@ -1780,11 +1768,12 @@ xga_bitblt(svga_t *svga) xga->accel.py = ((xga->accel.py + ydir) & patheight) | (xga->accel.py & ~patheight); else xga->accel.py += ydir; - xga->accel.dy += ydir; + + dy += ydir; if (xga->accel.y < 0) { - xga->accel.dst_map_x = xga->accel.dx; - xga->accel.dst_map_y = xga->accel.dy; + xga->accel.dst_map_x = dx; + xga->accel.dst_map_y = dy; return; } } From 52470d49100207aac7f422675865827e24d3aa94 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 6 Dec 2023 16:05:43 +0100 Subject: [PATCH 27/30] Fixed an off by 1 error in scsi/scsi_disk.c, fixes NetBSD 7 hang when probing a SCSI hard disk. --- src/scsi/scsi_disk.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 93d29a672..c886ce9a4 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -129,6 +129,7 @@ static void scsi_disk_mode_sense_load(scsi_disk_t *dev); static void scsi_disk_init(scsi_disk_t *dev); +#define ENABLE_SCSI_DISK_LOG 1 #ifdef ENABLE_SCSI_DISK_LOG int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG; @@ -709,7 +710,7 @@ static int scsi_disk_blocks(scsi_disk_t *dev, int32_t *len, UNUSED(int first_batch), int out) { *len = 0; - uint32_t medium_size = hdd_image_get_last_sector(dev->id); + uint32_t medium_size = hdd_image_get_last_sector(dev->id) + 1; if (!dev->sector_len) { scsi_disk_command_complete(dev); From ac63ea66144e9f7677cf690492a88d6abd1545cb Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 6 Dec 2023 16:06:40 +0100 Subject: [PATCH 28/30] Commented out excess logging in scsi/scsi_disk.c. --- src/scsi/scsi_disk.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index c886ce9a4..837800eb0 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -129,7 +129,6 @@ static void scsi_disk_mode_sense_load(scsi_disk_t *dev); static void scsi_disk_init(scsi_disk_t *dev); -#define ENABLE_SCSI_DISK_LOG 1 #ifdef ENABLE_SCSI_DISK_LOG int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG; From 3a0f1ace6062f9c430c95ff420cfb02692106689 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Thu, 7 Dec 2023 23:53:05 -0500 Subject: [PATCH 29/30] Update GHA to macos 12 --- .github/workflows/cmake.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index bde200b6b..4d446fd7a 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -381,10 +381,10 @@ jobs: name: '86Box${{ matrix.ui.slug }}${{ matrix.dynarec.slug }}${{ matrix.build.slug }}-UbuntuJammy-x86_64-gha${{ github.run_number }}' path: build/artifacts/** - macos11: - name: "macOS 11 (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64)" + macos12: + name: "macOS 12 (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64)" - runs-on: macos-11 + runs-on: macos-12 env: BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed From 6c0bd91e4fd1ed77a035ba4742704600f1422d7b Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 10 Dec 2023 01:48:08 -0500 Subject: [PATCH 30/30] Fix codeql runs --- .github/workflows/codeql.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5c23961d5..53dde02ab 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -226,11 +226,11 @@ jobs: with: category: "/language:${{matrix.language}}" - analyze-macos11: + analyze-macos12: - name: "Analyze macOS 11 (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64)" + name: "Analyze macOS 12 (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, x86_64)" - runs-on: macos-11 + runs-on: macos-12 permissions: actions: read