diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 14883f315..5d3d99bd3 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -217,6 +217,11 @@ extern uint8_t bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, void *p, svga_t extern void bt48x_recalctimings(void *p, svga_t *svga); extern void bt48x_hwcursor_draw(svga_t *svga, int displine); +extern void ibm_rgb525_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga); +extern uint8_t ibm_rgb525_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga); +extern void ibm_rgb525_recalctimings(void *p, svga_t *svga); +extern void ibm_rgb525_hwcursor_draw(svga_t *svga, int displine); + extern void icd2061_write(void *p, int val); extern float icd2061_getclock(int clock, void *p); @@ -259,6 +264,7 @@ extern const device_t bt485_ramdac_device; extern const device_t att20c505_ramdac_device; extern const device_t bt485a_ramdac_device; extern const device_t gendac_ramdac_device; +extern const device_t ibm_rgb525_ramdac_device; extern const device_t ics2494an_305_device; extern const device_t ics2595_device; extern const device_t icd2061_device; diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 8b1917ae5..2079265c2 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -328,6 +328,10 @@ extern const device_t s3_diamond_stealth64_pci_device; extern const device_t s3_diamond_stealth64_vlb_device; extern const device_t s3_diamond_stealth64_964_pci_device; extern const device_t s3_diamond_stealth64_964_vlb_device; +extern const device_t s3_elsa_winner2000_pro_x_964_pci_device; +extern const device_t s3_elsa_winner2000_pro_x_964_vlb_device; +extern const device_t s3_elsa_winner2000_pro_x_pci_device; +extern const device_t s3_elsa_winner2000_pro_x_vlb_device; extern const device_t s3_trio64v2_dx_pci_device; /* S3 ViRGE */ diff --git a/src/video/vid_ibm_rgb525_ramdac.c b/src/video/vid_ibm_rgb525_ramdac.c new file mode 100644 index 000000000..e6ba89e77 --- /dev/null +++ b/src/video/vid_ibm_rgb525_ramdac.c @@ -0,0 +1,978 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the IBM RGB 525 true colour RAMDAC. + * + * + * + * Authors: Miran Grca, + * + * Copyright 2020 Miran Grca. + */ +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/timer.h> +#include <86box/video.h> +#include <86box/vid_svga.h> + + +typedef union { + uint8_t pixel; + struct { + uint8_t b :2, g :3, r :2; + }; +} ibm_rgb525_pixel8_t; + +typedef union { + uint16_t pixel; + struct { + uint16_t b_ :5, g_ :6, r_ :5; + }; + struct { + uint16_t b :5, g :5, r :5, c :1; + }; +} ibm_rgb525_pixel16_t; + +typedef union { + uint32_t pixel; + struct { + uint8_t b, g, r, a; + }; +} ibm_rgb525_pixel32_t; + +typedef struct +{ + PALETTE extpal; + uint32_t extpallook[256]; + uint8_t indexed_data[2048]; + uint8_t cursor32_data[256]; + uint8_t cursor64_data[1024]; + uint8_t palettes[3][256]; + ibm_rgb525_pixel32_t extra_pal[4]; + int hwc_y, hwc_x; + uint16_t index, smlc_part; + uint8_t cmd_r0; + uint8_t cmd_r1; + uint8_t cmd_r2; + uint8_t cmd_r3; + uint8_t cmd_r4; + uint8_t status, indx_cntl; + uint8_t cursor_array; +} ibm_rgb525_ramdac_t; + + +void +ibm_rgb525_render_4bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb525_pixel32_t dat_out; + uint8_t dat; + uint32_t dat32 = 0x00000000; + uint64_t dat64 = 0x0000000000000000ULL; + uint64_t dat642 = 0x0000000000000000ULL; + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) svga->ramdac; + uint8_t b8_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6; + uint8_t partition = (ramdac->indexed_data[0x07] & 0x0f) << 4; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t swap_nib = ramdac->indexed_data[0x72] & 0x21; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x03; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->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++) { + if (svga->crtc[0x17] & 0x80) { + if (vram_size == 3) { + if (!(x & 31)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + dat642 = *(uint64_t *)(&svga->vram[svga->ma + 8]); + if (swap_word) { + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL); + } + } + if (swap_nib) + dat = (((x & 16) ? dat642 : dat64) >> ((x & 15) << 2)) & 0xf; + else + dat = (((x & 16) ? dat642 : dat64) >> (((x & 15) << 2) ^ 4)) & 0xf; + } else if (vram_size == 1) { + if (!(x & 15)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + if (swap_word) + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + } + if (swap_nib) + dat = (dat64 >> ((x & 15) << 2)) & 0xf; + else + dat = (dat64 >> (((x & 15) << 2) ^ 4)) & 0xf; + } else { + if (!(x & 7)) + dat32 = *(uint32_t *)(&svga->vram[svga->ma]); + if (swap_nib) + dat = (dat32 >> ((x & 7) << 2)) & 0xf; + else + dat = (dat32 >> (((x & 7) << 2) ^ 4)) & 0xf; + } + } else + dat = 0x00000000; + if (b8_dcol == 0x00) { + dat_out.a = 0x00; + dat_out.r = ramdac->palettes[0][partition | dat]; + dat_out.g = ramdac->palettes[1][partition | dat]; + dat_out.b = ramdac->palettes[2][partition | dat]; + } else + dat_out.pixel = video_8togs[dat]; + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_out.pixel & 0xffffff; + } else + p[x] = dat_out.pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 31) == 31)) + svga->ma = (svga->ma + 16) & svga->vram_display_mask; + if ((vram_size == 1) && ((x & 15) == 15)) + svga->ma = (svga->ma + 8) & svga->vram_display_mask; + else if ((!vram_size) && ((x & 7) == 7)) + svga->ma = (svga->ma + 4) & svga->vram_display_mask; + } + } +} + + +void +ibm_rgb525_render_8bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb525_pixel32_t dat_out; + uint8_t dat; + uint32_t dat32 = 0x00000000; + uint64_t dat64 = 0x0000000000000000ULL; + uint64_t dat642 = 0x0000000000000000ULL; + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) svga->ramdac; + uint8_t b8_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x03; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->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++) { + if (svga->crtc[0x17] & 0x80) { + if (vram_size == 3) { + if (!(x & 15)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + dat642 = *(uint64_t *)(&svga->vram[svga->ma + 8]); + if (swap_word) { + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL); + } + } + dat = (((x & 8) ? dat642 : dat64) >> ((x & 7) << 3)) & 0xff; + } else if (vram_size == 1) { + if (!(x & 7)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + if (swap_word) + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + } + dat = (dat64 >> ((x & 7) << 3)) & 0xff; + } else { + if (!(x & 3)) + dat32 = *(uint32_t *)(&svga->vram[svga->ma]); + dat = (dat32 >> ((x & 3) << 3)) & 0xff; + } + } else + dat = 0x00000000; + if (b8_dcol == 0x00) { + dat_out.a = 0x00; + dat_out.r = ramdac->palettes[0][dat]; + dat_out.g = ramdac->palettes[1][dat]; + dat_out.b = ramdac->palettes[2][dat]; + } else + dat_out.pixel = video_8togs[dat]; + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_out.pixel & 0xffffff; + } else + p[x] = dat_out.pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 15) == 15)) + svga->ma = (svga->ma + 16) & svga->vram_display_mask; + else if ((vram_size == 1) && ((x & 7) == 7)) + svga->ma = (svga->ma + 8) & svga->vram_display_mask; + else if ((!vram_size) && ((x & 3) == 3)) + svga->ma = (svga->ma + 4) & svga->vram_display_mask; + } + } +} + + +void +ibm_rgb525_render_15_16bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb525_pixel16_t *dat_ex; + ibm_rgb525_pixel32_t dat_out; + uint16_t dat; + uint32_t dat32 = 0x00000000; + uint64_t dat64 = 0x0000000000000000ULL; + uint64_t dat642 = 0x0000000000000000ULL; + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) svga->ramdac; + uint8_t b16_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6; + uint8_t by16_pol = ramdac->indexed_data[0x0c] & 0x20; + uint8_t b555_565 = ramdac->indexed_data[0x0c] & 0x02; + uint8_t bspr_cnt = ramdac->indexed_data[0x0c] & 0x01; + uint8_t partition = (ramdac->indexed_data[0x07] & 0x0e) << 4; + uint8_t b6bit_lin = ramdac->indexed_data[0x07] & 0x80; + uint8_t swaprb = ramdac->indexed_data[0x72] & 0x80; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x01, temp; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (b555_565 && (b16_dcol != 0x01)) + partition &= 0xc0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->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++) { + if (svga->crtc[0x17] & 0x80) { + if (vram_size == 2) { + if (!(x & 7)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + dat642 = *(uint64_t *)(&svga->vram[svga->ma + 8]); + if (swap_word) { + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + dat642 = (dat64 << 32ULL) | (dat642 >> 32ULL); + } + } + dat = (((x & 4) ? dat642 : dat64) >> ((x & 3) << 4)) & 0xffff; + } else if (vram_size == 1) { + if (!(x & 3)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + if (swap_word) + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + } + dat = (dat64 >> ((x & 3) << 4)) & 0xffff; + } else { + if (!(x & 1)) + dat32 = *(uint32_t *)(&svga->vram[svga->ma]); + dat = (dat32 >> ((x & 1) << 4)) & 0xffff; + } + } else + dat = 0x00000000; + dat_ex = (ibm_rgb525_pixel16_t *) &dat; + if (b555_565 && (b16_dcol != 0x01)) { + if (swaprb) { + temp = dat_ex->r_; + dat_ex->r_ = dat_ex->b_; + dat_ex->b_ = temp; + } + if (b16_dcol == 0x00) { + dat_out.a = 0x00; + if (bspr_cnt) { + dat_out.r = ramdac->palettes[0][partition | dat_ex->r_]; + dat_out.g = ramdac->palettes[1][partition | dat_ex->g_]; + dat_out.b = ramdac->palettes[2][partition | dat_ex->b_]; + } else { + dat_out.r = ramdac->palettes[0][dat_ex->r_ << 3]; + dat_out.g = ramdac->palettes[1][dat_ex->g_ << 2]; + dat_out.b = ramdac->palettes[2][dat_ex->b_ << 3]; + } + if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) { + dat_out.r |= ((dat_out.r & 0xc0) >> 6); + dat_out.g |= ((dat_out.g & 0xc0) >> 6); + dat_out.b |= ((dat_out.b & 0xc0) >> 6); + } + } else + dat_out.pixel = video_16to32[dat_ex->pixel]; + } else { + if (swaprb) { + temp = dat_ex->r; + dat_ex->r = dat_ex->b; + dat_ex->b = temp; + } + if (by16_pol) + dat ^= 0x8000; + if ((b16_dcol == 0x00) || ((b16_dcol == 0x01) && !(dat & 0x8000))) { + dat_out.a = 0x00; + if (bspr_cnt) { + dat_out.r = ramdac->palettes[0][partition | dat_ex->r]; + dat_out.g = ramdac->palettes[1][partition | dat_ex->g]; + dat_out.b = ramdac->palettes[2][partition | dat_ex->b]; + } else { + dat_out.r = ramdac->palettes[0][dat_ex->r << 3]; + dat_out.g = ramdac->palettes[1][dat_ex->g << 3]; + dat_out.b = ramdac->palettes[2][dat_ex->b << 3]; + } + if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) { + dat_out.r |= ((dat_out.r & 0xc0) >> 6); + dat_out.g |= ((dat_out.g & 0xc0) >> 6); + dat_out.b |= ((dat_out.b & 0xc0) >> 6); + } + } else + dat_out.pixel = video_15to32[dat_ex->pixel & 0x7fff]; + } + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_out.pixel & 0xffffff; + } else + p[x] = dat_out.pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 7) == 7)) + svga->ma = (svga->ma + 16) & svga->vram_display_mask; + else if ((vram_size == 1) && ((x & 3) == 3)) + svga->ma = (svga->ma + 8) & svga->vram_display_mask; + else if (!vram_size && ((x & 1) == 1)) + svga->ma = (svga->ma + 4) & svga->vram_display_mask; + } + } +} + + +void +ibm_rgb525_render_24bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb525_pixel32_t *dat_ex; + uint32_t dat; + uint64_t dat64[6]; + uint8_t *dat8 = (uint8_t *) dat64; + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) svga->ramdac; + uint8_t b24_dcol = ramdac->indexed_data[0x0d] & 0x01; + uint8_t swaprb = ramdac->indexed_data[0x72] & 0x80; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x01; + uint8_t b6bit_lin = ramdac->indexed_data[0x07] & 0x80, temp; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->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++) { + dat_ex = (ibm_rgb525_pixel32_t *) &dat; + if (svga->crtc[0x17] & 0x80) { + if (vram_size == 3) { + if ((x & 15) == 0) { + dat64[0] = *(uint64_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + dat64[1] = *(uint64_t *)(&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + dat64[2] = *(uint64_t *)(&svga->vram[(svga->ma + 16) & svga->vram_display_mask]); + dat64[3] = *(uint64_t *)(&svga->vram[(svga->ma + 24) & svga->vram_display_mask]); + dat64[4] = *(uint64_t *)(&svga->vram[(svga->ma + 32) & svga->vram_display_mask]); + dat64[5] = *(uint64_t *)(&svga->vram[(svga->ma + 40) & svga->vram_display_mask]); + if (swap_word) { + dat64[0] = (dat64[0] << 32ULL) | (dat64[0] >> 32ULL); + dat64[1] = (dat64[1] << 32ULL) | (dat64[1] >> 32ULL); + dat64[2] = (dat64[2] << 32ULL) | (dat64[2] >> 32ULL); + dat64[3] = (dat64[3] << 32ULL) | (dat64[3] >> 32ULL); + dat64[4] = (dat64[4] << 32ULL) | (dat64[4] >> 32ULL); + dat64[5] = (dat64[5] << 32ULL) | (dat64[5] >> 32ULL); + } + } + dat_ex = (ibm_rgb525_pixel32_t *) &(dat8[((x & 15) * 3)]); + } else if (vram_size == 1) { + if ((x & 7) == 0) { + dat64[0] = *(uint64_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + dat64[1] = *(uint64_t *)(&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + dat64[2] = *(uint64_t *)(&svga->vram[(svga->ma + 16) & svga->vram_display_mask]); + if (swap_word) { + dat64[0] = (dat64[0] << 32ULL) | (dat64[0] >> 32ULL); + dat64[1] = (dat64[1] << 32ULL) | (dat64[1] >> 32ULL); + dat64[2] = (dat64[2] << 32ULL) | (dat64[2] >> 32ULL); + } + } + dat_ex = (ibm_rgb525_pixel32_t *) &(dat8[((x & 7) * 3)]); + } else + dat = 0x00000000; + } else + dat = 0x00000000; + if (swaprb) { + temp = dat_ex->r; + dat_ex->r = dat_ex->b; + dat_ex->b = temp; + } + if (b24_dcol == 0x00) { + dat_ex->a = 0x00; + dat_ex->r = ramdac->palettes[0][dat_ex->r]; + dat_ex->g = ramdac->palettes[1][dat_ex->g]; + dat_ex->g = ramdac->palettes[2][dat_ex->b]; + if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) { + dat_ex->r |= ((dat_ex->r & 0xc0) >> 6); + dat_ex->g |= ((dat_ex->g & 0xc0) >> 6); + dat_ex->b |= ((dat_ex->b & 0xc0) >> 6); + } + } + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_ex->pixel & 0xffffff; + } else + p[x] = dat_ex->pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 15) == 15)) + svga->ma = (svga->ma + 48) & svga->vram_display_mask; + else if ((vram_size == 1) && ((x & 7) == 7)) + svga->ma = (svga->ma + 24) & svga->vram_display_mask; + } + } +} + + +void +ibm_rgb525_render_32bpp(svga_t *svga) +{ + int x; + uint32_t *p; + ibm_rgb525_pixel32_t *dat_ex; + uint32_t dat = 0x00000000; + uint64_t dat64 = 0x0000000000000000ULL; + uint64_t dat642 = 0x0000000000000000ULL; + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) svga->ramdac; + uint8_t b32_dcol = ramdac->indexed_data[0x0e] & 0x03; + uint8_t by32_pol = ramdac->indexed_data[0x0e] & 0x04; + uint8_t swaprb = ramdac->indexed_data[0x72] & 0x80; + uint8_t swap_word = ramdac->indexed_data[0x72] & 0x10; + uint8_t vram_size = ramdac->indexed_data[0x70] & 0x01; + uint8_t b6bit_lin = ramdac->indexed_data[0x07] & 0x80, temp; + + if ((svga->displine + svga->y_add) < 0) + return; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + p = &buffer32->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++) { + if (svga->crtc[0x17] & 0x80) { + if (vram_size == 3) { + if (!(x & 3)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + dat642 = *(uint64_t *)(&svga->vram[svga->ma + 8]); + if (swap_word) { + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL); + } + } + dat = (((x & 2) ? dat642 : dat64) >> ((x & 1ULL) << 5ULL)) & 0xffffffff; + } else if (vram_size == 1) { + if (!(x & 1)) { + dat64 = *(uint64_t *)(&svga->vram[svga->ma]); + if (swap_word) + dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); + } + dat = (dat64 >> ((x & 1ULL) << 5ULL)) & 0xffffffff; + } else + dat = *(uint32_t *)(&svga->vram[svga->ma]); + } else + dat = 0x00000000; + dat_ex = (ibm_rgb525_pixel32_t *) &dat; + if (swaprb) { + temp = dat_ex->r; + dat_ex->r = dat_ex->b; + dat_ex->b = temp; + } + if ((b32_dcol < 0x03) && (by32_pol)) + dat ^= 0x01000000; + if ((b32_dcol == 0x00) || ((b32_dcol == 0x01) && !(dat & 0x01000000))) { + dat_ex->a = 0x00; + dat_ex->r = ramdac->palettes[0][dat_ex->r]; + dat_ex->g = ramdac->palettes[1][dat_ex->g]; + dat_ex->g = ramdac->palettes[2][dat_ex->b]; + if ((svga->ramdac_type != RAMDAC_8BIT) && !b6bit_lin) { + dat_ex->r |= ((dat_ex->r & 0xc0) >> 6); + dat_ex->g |= ((dat_ex->g & 0xc0) >> 6); + dat_ex->b |= ((dat_ex->b & 0xc0) >> 6); + } + } + if (svga->lowres) { + p[x << 1] = p[(x << 1) + 1] = dat_ex->pixel & 0xffffff; + } else + p[x] = dat_ex->pixel & 0xffffff; + + if ((vram_size == 3) && ((x & 3) == 3)) + svga->ma = (svga->ma + 16) & svga->vram_display_mask; + else if ((vram_size == 1) && ((x & 1) == 1)) + svga->ma = (svga->ma + 8) & svga->vram_display_mask; + else if (!vram_size) + svga->ma = (svga->ma + 4) & svga->vram_display_mask; + } + } +} + + +static void +ibm_rgb525_set_bpp(ibm_rgb525_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t b16_dcol = (ramdac->indexed_data[0x0c] & 0xc0) >> 6; + uint8_t b555_565 = ramdac->indexed_data[0x0c] & 0x02; + + if (ramdac->indexed_data[0x071] & 0x01) + switch (ramdac->indexed_data[0x00a] & 0x07) { + case 0x02: + svga->bpp = 4; + break; + case 0x03: + default: + svga->bpp = 8; + break; + case 0x04: + if (b555_565 && (b16_dcol != 0x01)) + svga->bpp = 16; + else + svga->bpp = 15; + break; + case 0x05: + svga->bpp = 24; + break; + case 0x06: + svga->bpp = 32; + break; + } else + svga->bpp = 8; + + // pclog("svga->bpp = %i\n", svga->bpp); + + svga_recalctimings(svga); +} + + +void +ibm_rgb525_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga) +{ + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) p; + uint16_t index; + uint8_t rs = (addr & 0x03); + uint16_t da_mask = 0x03ff; + uint8_t updt_cntl = (ramdac->indexed_data[0x30] & 0x08); + rs |= (!!rs2 << 2); + + // pclog("[%04X:%08X] [W] RS%01X = %02X\n", CS, cpu_state.pc, rs, val); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x03: + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = val; + if (svga->dac_status) + svga->dac_addr = (svga->dac_addr + 1) & da_mask; + break; + case 0x01: /* Palette Data Register (RS value = 0001) */ + index = svga->dac_addr & 255; + if (svga->ramdac_type == RAMDAC_8BIT) + ramdac->palettes[svga->dac_pos][index] = val; + else + ramdac->palettes[svga->dac_pos][index] = (val & 0x3f) << 2; + svga_out(addr, val, svga); + break; + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + svga_out(addr, val, svga); + break; + case 0x04: + // pclog("Index low: %02X\n", val); + ramdac->index = (ramdac->index & 0x0700) | val; + if ((ramdac->index >= 0x0100) && (ramdac->index <= 0x04ff)) + ramdac->cursor_array = 1; + break; + case 0x05: + // pclog("Index high: %02X\n", val); + ramdac->index = (ramdac->index & 0x00ff) | ((val & 0x07) << 0x08); + if ((ramdac->index >= 0x0100) && (ramdac->index <= 0x04ff)) + ramdac->cursor_array = 1; + break; + case 0x06: + // pclog("Indexed data [%03X]: %02X\n", ramdac->index, val); + if ((ramdac->index < 0x0100) || (ramdac->index > 0x04ff) || ramdac->cursor_array) + ramdac->indexed_data[ramdac->index] = val; + switch (ramdac->index) { + case 0x00a: case 0x00c: + ibm_rgb525_set_bpp(ramdac, svga); + break; + case 0x030: + switch (val & 0xc0) { + case 0x00: + ramdac->smlc_part = 0x0100; + break; + case 0x40: + ramdac->smlc_part = 0x0200; + break; + case 0x80: + ramdac->smlc_part = 0x0300; + break; + case 0xc0: + ramdac->smlc_part = 0x0400; + break; + } + svga->dac_hwcursor.addr = ramdac->smlc_part; + svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = (val & 0x04) ? 64 : 32; + svga->dac_hwcursor.ena = ((val & 0x03) != 0x00); + /* pclog("%ix%i cursor %sabled at DAC buffer address %02X\n", svga->dac_hwcursor.xsize, + svga->dac_hwcursor.ysize, svga->dac_hwcursor.ena ? "en" : "dis", + svga->dac_hwcursor.addr); + pclog("Pixel order %i, mode %i, update %s\n", !!(ramdac->indexed_data[0x30] & 0x20), + ramdac->indexed_data[0x30] & 0x03, (ramdac->indexed_data[0x30] & 0x08) ? "now" : "later"); */ + break; + case 0x031: + if (!updt_cntl) + break; + svga->dac_hwcursor.x = (svga->dac_hwcursor.x & 0xff00) | val; + // pclog("Cursor X = %i\n", svga->dac_hwcursor.x); + break; + case 0x032: + /* Sign-extend the sign bit (7) to the remaining bits (6-4). */ + val &= 0x8f; + if (val & 0x80) + val |= 0x70; + ramdac->indexed_data[ramdac->index] = val; + if (!updt_cntl) + break; + svga->dac_hwcursor.x = (svga->dac_hwcursor.x & 0x00ff) | (val << 8); + // pclog("Cursor X = %i\n", svga->dac_hwcursor.x); + break; + case 0x033: + if (!updt_cntl) + break; + svga->dac_hwcursor.y = (svga->dac_hwcursor.y & 0xff00) | val; + // pclog("Cursor Y = %i\n", svga->dac_hwcursor.y); + break; + case 0x034: + /* Sign-extend the sign bit (7) to the remaining bits (6-4). */ + val &= 0x8f; + if (val & 0x80) + val |= 0x70; + ramdac->indexed_data[ramdac->index] = val; + if (updt_cntl) { + svga->dac_hwcursor.y = (svga->dac_hwcursor.y & 0x00ff) | (val << 8); + // pclog("Cursor Y = %i\n", svga->dac_hwcursor.x); + } else { + svga->dac_hwcursor.x = ramdac->indexed_data[0x031]; + svga->dac_hwcursor.x |= (ramdac->indexed_data[0x032] << 8); + // pclog("Cursor X = %i\n", svga->dac_hwcursor.x); + svga->dac_hwcursor.y = ramdac->indexed_data[0x033]; + svga->dac_hwcursor.y |= (val << 8); + // pclog("Cursor Y = %i\n", svga->dac_hwcursor.y); + } + break; + case 0x035: + if (svga->dac_hwcursor.xsize == 64) + svga->dac_hwcursor.xoff = (val & 0x1f); + else + svga->dac_hwcursor.xoff = (val & 0x3f); + // pclog("Cursor X offset = %i\n", (int) svga->dac_hwcursor.xoff); + break; + case 0x036: + if (svga->dac_hwcursor.xsize == 64) + svga->dac_hwcursor.yoff = (val & 0x1f); + else + svga->dac_hwcursor.yoff = (val & 0x3f); + // pclog("Cursor Y offset = %i\n", (int) svga->dac_hwcursor.yoff); + break; + case 0x040: case 0x043: case 0x046: + ramdac->extra_pal[(ramdac->index - 0x40) / 3].r = val; + break; + case 0x041: case 0x044: case 0x047: + ramdac->extra_pal[(ramdac->index - 0x41) / 3].g = val; + break; + case 0x042: case 0x045: case 0x048: + ramdac->extra_pal[(ramdac->index - 0x42) / 3].b = val; + break; + case 0x060: + ramdac->extra_pal[3].r = val; + break; + case 0x061: + ramdac->extra_pal[3].g = val; + break; + case 0x062: + ramdac->extra_pal[3].b = val; + break; + case 0x071: + svga->ramdac_type = (val & 0x04) ? RAMDAC_8BIT : RAMDAC_6BIT; + ibm_rgb525_set_bpp(ramdac, svga); + break; + default: + break; + } + if (ramdac->indx_cntl) { + if (ramdac->index == 0x00ff) + ramdac->cursor_array = 0; + ramdac->index = (ramdac->index + 1) & 0x07ff; + // pclog("Index now: %03X\n", ramdac->index); + } + break; + case 0x07: + ramdac->indx_cntl = val & 0x01; + break; + } + + return; +} + + +uint8_t +ibm_rgb525_ramdac_in(uint16_t addr, int rs2, void *p, svga_t *svga) +{ + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) p; + uint8_t temp = 0xff; + uint8_t rs = (addr & 0x03); + uint8_t loc_read = (ramdac->indexed_data[0x30] & 0x10); + rs |= (!!rs2 << 2); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + temp = svga_in(addr, svga); + break; + case 0x03: /* Palette Read Index Register (RS value = 0011) */ + temp = svga->dac_addr & 0xff; + if (ramdac->indexed_data[0x070] & 0x20) + temp = (temp & 0xfc) | svga->dac_status; + break; + case 0x04: + temp = ramdac->index & 0xff; + break; + case 0x05: + temp = ramdac->index >> 8; + break; + case 0x06: + temp = ramdac->indexed_data[ramdac->index]; + switch (ramdac->index) { + case 0x0000: /* Revision */ + temp = 0xe0; + break; + case 0x0001: /* ID */ + temp = 0x02; + break; + case 0x0031: + if (loc_read) + temp = svga->dac_hwcursor.x & 0xff; + break; + case 0x0032: + if (loc_read) + temp = svga->dac_hwcursor.x >> 8; + break; + case 0x0033: + if (loc_read) + temp = svga->dac_hwcursor.y & 0xff; + break; + case 0x0034: + if (loc_read) + temp = svga->dac_hwcursor.y >> 8; + break; + default: + temp = ramdac->indexed_data[ramdac->index]; + break; + } + if (ramdac->indx_cntl) { + if (ramdac->index == 0x00ff) + ramdac->cursor_array = 0; + ramdac->index = (ramdac->index + 1) & 0x07ff; + } + break; + case 0x07: + temp = ramdac->indx_cntl; + break; + } + + // pclog("[%04X:%08X] [R] RS%01X = %02X\n", CS, cpu_state.pc, rs, temp); + + return temp; +} + + +void +ibm_rgb525_recalctimings(void *p, svga_t *svga) +{ + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) p; + + svga->interlace = ramdac->indexed_data[0x071] & 0x20; + + if (svga->scrblank || !svga->attr_palette_enable) { + if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { + if (((svga->gdcreg[5] & 0x60) == 0x40) || ((svga->gdcreg[5] & 0x60) == 0x60)) { + if (ramdac->indexed_data[0x071] & 0x01) { + switch (svga->bpp) { + case 4: + svga->render = ibm_rgb525_render_4bpp; + break; + case 8: + svga->render = ibm_rgb525_render_8bpp; + break; + case 15: case 16: + svga->render = ibm_rgb525_render_15_16bpp; + break; + case 24: + svga->render = ibm_rgb525_render_24bpp; + break; + case 32: + svga->render = ibm_rgb525_render_32bpp; + break; + } + } + } + } + } +} + + +void +ibm_rgb525_hwcursor_draw(svga_t *svga, int displine) +{ + uint8_t dat, four_pixels = 0x00; + int x, pitch, x_pos, y_pos, offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff; + uint32_t *p; + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) svga->ramdac; + uint8_t pix_ordr = ramdac->indexed_data[0x30] & 0x20; + uint8_t cursor_mode = ramdac->indexed_data[0x30] & 0x03; + + /* The planes come in one part, and each plane is 2bpp, + so a 32x32 cursor has 8 bytes per line, and a 64x64 + cursor has 16 bytes per line. */ + pitch = (svga->dac_hwcursor_latch.xsize >> 2); /* Bytes per line. */ + + if ((ramdac->indexed_data[0x071] & 0x20) && svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; + + y_pos = displine; + x_pos = offset + svga->x_add; + p = buffer32->line[y_pos]; + + for (x = 0; x < svga->dac_hwcursor_latch.xsize; x ++) { + if (!(x & 3)) { + four_pixels = ramdac->indexed_data[svga->dac_hwcursor_latch.addr]; + // pclog("Pixels %i to %i: %02X at %08X\n", x, x + 3, four_pixels, svga->dac_hwcursor_latch.addr); + } + if (pix_ordr) + dat = (four_pixels >> (((3 - x) & 3) << 1)) & 0x03; + else + dat = (four_pixels >> ((x & 3) << 1)) & 0x03; + + x_pos = offset + svga->x_add + x; + + switch (cursor_mode) { + case 0x01: + switch (dat) { + case 0x01: + /* Cursor Color 1 */ + p[x_pos] = ramdac->extra_pal[0].pixel; + break; + case 0x02: + /* Cursor Color 2 */ + p[x_pos] = ramdac->extra_pal[1].pixel; + break; + case 0x03: + /* Cursor Color 3 */ + p[x_pos] = ramdac->extra_pal[2].pixel; + break; + } + break; + case 0x02: + switch (dat) { + case 0x00: + /* Cursor Color 1 */ + p[x_pos] = ramdac->extra_pal[0].pixel; + break; + case 0x01: + /* Cursor Color 2 */ + p[x_pos] = ramdac->extra_pal[1].pixel; + break; + case 0x03: + /* Complement */ + p[x_pos] ^= 0xffffff; + break; + } + break; + case 0x03: + switch (dat) { + case 0x02: + /* Cursor Color 1 */ + p[x_pos] = ramdac->extra_pal[0].pixel; + break; + case 0x03: + /* Cursor Color 2 */ + p[x_pos] = ramdac->extra_pal[1].pixel; + break; + } + break; + } + + if ((x & 3) == 3) + svga->dac_hwcursor_latch.addr++; + } + + if ((ramdac->indexed_data[0x071] & 0x20) && !svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; +} + + +void * +ibm_rgb525_ramdac_init(const device_t *info) +{ + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) malloc(sizeof(ibm_rgb525_ramdac_t)); + memset(ramdac, 0, sizeof(ibm_rgb525_ramdac_t)); + + ramdac->smlc_part = 0x0100; + + ramdac->indexed_data[0x0008] = 0x0001; + ramdac->indexed_data[0x0015] = 0x0008; + ramdac->indexed_data[0x0016] = 0x0041; + + return ramdac; +} + + +static void +ibm_rgb525_ramdac_close(void *priv) +{ + ibm_rgb525_ramdac_t *ramdac = (ibm_rgb525_ramdac_t *) priv; + + if (ramdac) + free(ramdac); +} + + +const device_t ibm_rgb525_ramdac_device = +{ + "IBM RGB525 RAMDAC", + 0, 0, + ibm_rgb525_ramdac_init, ibm_rgb525_ramdac_close, + NULL, { NULL }, NULL, NULL, NULL +}; diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 4d61f9424..dafd25ebc 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -52,6 +52,8 @@ #define ROM_TRIO64V2_DX_VBE20 L"roms/video/s3/86c775_2.bin" #define ROM_PHOENIX_TRIO64VPLUS L"roms/video/s3/64V1506.ROM" #define ROM_DIAMOND_STEALTH_SE L"roms/video/s3/DiamondStealthSE.VBI" +#define ROM_ELSAWIN2KPROX_964 L"roms/video/s3/elsaw20004m.BIN" +#define ROM_ELSAWIN2KPROX L"roms/video/s3/elsaw20008m.BIN" enum { @@ -72,7 +74,9 @@ enum S3_PHOENIX_TRIO64VPLUS, S3_PHOENIX_TRIO64VPLUS_ONBOARD, S3_DIAMOND_STEALTH_SE, - S3_DIAMOND_STEALTH_VRAM + S3_DIAMOND_STEALTH_VRAM, + S3_ELSAWIN2KPROX_964, + S3_ELSAWIN2KPROX }; @@ -84,11 +88,12 @@ enum S3_86C801 = 0x06, S3_86C805 = 0x07, S3_VISION964 = 0x08, - S3_VISION864 = 0x10, - S3_TRIO32 = 0x18, - S3_TRIO64 = 0x20, - S3_TRIO64V = 0x28, - S3_TRIO64V2 = 0x30 + S3_VISION968 = 0x10, + S3_VISION864 = 0x18, + S3_TRIO32 = 0x20, + S3_TRIO64 = 0x28, + S3_TRIO64V = 0x30, + S3_TRIO64V2 = 0x38 }; @@ -101,6 +106,8 @@ static video_timings_t timing_s3_vision864_vlb = {VIDEO_BUS, 4, 4, 5, 20, 20, static video_timings_t timing_s3_vision864_pci = {VIDEO_PCI, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_vision964_vlb = {VIDEO_BUS, 2, 2, 4, 20, 20, 35}; static video_timings_t timing_s3_vision964_pci = {VIDEO_PCI, 2, 2, 4, 20, 20, 35}; +static video_timings_t timing_s3_vision968_vlb = {VIDEO_BUS, 2, 2, 4, 20, 20, 35}; +static video_timings_t timing_s3_vision968_pci = {VIDEO_PCI, 2, 2, 4, 20, 20, 35}; static video_timings_t timing_s3_trio32_vlb = {VIDEO_BUS, 4, 3, 5, 26, 26, 42}; static video_timings_t timing_s3_trio32_pci = {VIDEO_PCI, 4, 3, 5, 26, 26, 42}; static video_timings_t timing_s3_trio64_vlb = {VIDEO_BUS, 3, 2, 4, 25, 25, 40}; @@ -176,6 +183,8 @@ typedef struct s3_t uint32_t vram_mask; uint8_t data_available; + int card_type; + struct { uint16_t subsys_cntl; @@ -183,13 +192,15 @@ typedef struct s3_t uint8_t advfunc_cntl; uint16_t cur_y, cur_y2; uint16_t cur_x, cur_x2; - uint16_t x2; + uint16_t x2, ropmix; + uint16_t pat_x, pat_y; int16_t desty_axstp, desty_axstp2; int16_t destx_distp; int16_t err_term, err_term2; int16_t maj_axis_pcnt, maj_axis_pcnt2; - uint16_t cmd; + uint16_t cmd, cmd2; uint16_t short_stroke; + uint32_t pat_bg_color, pat_fg_color; uint32_t bkgd_color; uint32_t frgd_color; uint32_t wrt_mask; @@ -202,12 +213,14 @@ typedef struct s3_t uint8_t pix_trans[4]; int cx, cy; + int px, py; int sx, sy; int dx, dy; uint32_t src, dest, pattern; int poly_cx, poly_cx2; int poly_cy, poly_cy2; + int poly_line_cx; int point_1_updated, point_2_updated; int poly_dx1, poly_dx2; int poly_x; @@ -300,6 +313,9 @@ static void s3_accel_out(uint16_t port, uint8_t val, void *p); static void s3_accel_out_w(uint16_t port, uint16_t val, void *p); static void s3_accel_out_l(uint16_t port, uint32_t val, void *p); static uint8_t s3_accel_in(uint16_t port, void *p); +static uint8_t s3_pci_read(int func, int addr, void *p); +static void s3_pci_write(int func, int addr, uint8_t val, void *p); + static __inline void wake_fifo_thread(s3_t *s3) @@ -322,10 +338,11 @@ s3_update_irqs(s3_t *s3) if (!s3->pci) return; - if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) + if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) { pci_set_irq(s3->card, PCI_INTA); - else + } else { pci_clear_irq(s3->card, PCI_INTA); + } } void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3); @@ -403,26 +420,24 @@ s3_data_len(s3_t *s3) static void s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) { - svga_t *svga = &s3->svga; - if (s3->accel.cmd & 0x100) { if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); - if ((s3->accel.cmd & 0x600) == 0x600 && (s3->chip == S3_TRIO32 || s3->chip >= S3_TRIO64V)) { + if ((s3->accel.cmd & 0x600) == 0x600 && (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip >= S3_TRIO64V)) { s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); s3_accel_start(8, 1, val & 0xff, 0, s3); } else if ((s3->accel.cmd & 0x600) == 0x000) { s3_accel_start(8, 1, val | (val << 16), 0, s3); - } else if ((s3->accel.cmd & 0x400) && (svga->crtc[0x53] & 0x08)) + } else if (s3->accel.cmd & 0x400) s3_accel_start(32, 1, val | (val << 16), 0, s3); else s3_accel_start(16, 1, val | (val << 16), 0, s3); } else { if ((s3->accel.cmd & 0x600) == 0x000) s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); - else if ((s3->accel.cmd & 0x400) && (svga->crtc[0x53] & 0x08)) + else if (s3->accel.cmd & 0x400) s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3); else s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); @@ -432,18 +447,18 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) static void s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val) -{ +{ if (s3->accel.cmd & 0x100) { if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40))) { - if ((s3->accel.cmd & 0x600) == 0x600 && (s3->chip == S3_TRIO32 || s3->chip >= S3_TRIO64V)) { + if ((s3->accel.cmd & 0x600) == 0x600 && (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip >= S3_TRIO64V)) { if (s3->accel.cmd & 0x1000) val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); s3_accel_start(8, 1, val & 0xff, 0, s3); - } else if (s3->accel.cmd & 0x400) { + } else if (s3->accel.cmd & 0x400) { if (s3->accel.cmd & 0x1000) val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); s3_accel_start(32, 1, val, 0, s3); @@ -459,9 +474,9 @@ s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val) s3_accel_start(8, 1, val >> 16, 0, s3); } } else { - if (s3->accel.cmd & 0x400) - s3_accel_start(4, 1, 0xffffffff, val, s3); - else if ((s3->accel.cmd & 0x600) == 0x200) { + if (s3->accel.cmd & 0x400) { + s3_accel_start(4, 1, 0xffffffff, val, s3); + } else if ((s3->accel.cmd & 0x600) == 0x200) { s3_accel_start(2, 1, 0xffffffff, val, s3); s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); } else { @@ -474,9 +489,7 @@ s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val) static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) -{ - svga_t *svga = &s3->svga; - +{ switch (port) { case 0x8148: case 0x82e8: s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; @@ -594,11 +607,18 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.b2e8_pix = 0; break; case 0x9949: case 0x9ae9: - s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); + s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); s3_accel_start(-1, 0, 0xffffffff, 0, s3); s3->accel.multifunc[0xe] &= ~0x10; /*hack*/ break; + case 0x994a: case 0x9aea: + s3->accel.cmd2 = (s3->accel.cmd2 & 0xff00) | val; + break; + case 0x994b: case 0x9aeb: + s3->accel.cmd2 = (s3->accel.cmd2 & 0xff) | (val << 8); + break; + case 0x9d48: case 0x9ee8: s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; break; @@ -802,6 +822,95 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; break; + case 0xd148: case 0xd2e8: + s3->accel.ropmix = (s3->accel.ropmix & 0xff00) | val; + break; + case 0xd149: case 0xd2e9: + s3->accel.ropmix = (s3->accel.ropmix & 0x00ff) | (val << 8); + break; + case 0xe548: case 0xe6e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x00ff0000) | (val << 16); + else + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x000000ff) | val; + break; + case 0xe549: case 0xe6e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0xff000000) | (val << 24); + else + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xe54a: case 0xe6ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x00ff0000) | (val << 16); + else + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x000000ff) | val; + } + break; + case 0xe54b: case 0xe6eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0xff000000) | (val << 24); + else + s3->accel.pat_bg_color = (s3->accel.pat_bg_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + case 0xe948: case 0xeae8: + s3->accel.pat_y = (s3->accel.pat_y & 0xf00) | val; + break; + case 0xe949: case 0xeae9: + s3->accel.pat_y = (s3->accel.pat_y & 0xff) | ((val & 0x1f) << 8); + break; + case 0xe94a: case 0xeaea: + s3->accel.pat_x = (s3->accel.pat_x & 0xf00) | val; + break; + case 0xe94b: case 0xeaeb: + s3->accel.pat_x = (s3->accel.pat_x & 0xff) | ((val & 0x1f) << 8); + break; + case 0xed48: case 0xeee8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x00ff0000) | (val << 16); + else + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x000000ff) | val; + break; + case 0xed49: case 0xeee9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0xff000000) | (val << 24); + else + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xed4a: case 0xeeea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x00ff0000) | (val << 16); + else + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x000000ff) | val; + } + break; + case 0xed4b: case 0xeeeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0xff000000) | (val << 24); + else + s3->accel.pat_fg_color = (s3->accel.pat_fg_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + case 0xe148: case 0xe2e8: s3->accel.b2e8_pix = 0; if (s3_cpu_dest(s3)) @@ -831,11 +940,10 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); break; case 0x400: - if (svga->crtc[0x53] & 0x08) - s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); break; case 0x600: - if (s3->chip == S3_TRIO32 || s3->chip >= S3_TRIO64V) { + if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip >= S3_TRIO64V) { s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); } @@ -855,8 +963,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); break; case 0x400: - if (svga->crtc[0x53] & 0x08) - s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); break; } } @@ -887,7 +994,7 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); break; case 0x600: - if (s3->chip == S3_TRIO32 || s3->chip >= S3_TRIO64V) { + if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip >= S3_TRIO64V) { s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3); s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3); s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); @@ -940,10 +1047,17 @@ static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) { svga_t *svga = &s3->svga; - + if (s3->packed_mmio) { int addr_lo = addr & 1; - switch (addr & 0xfffe) { + if (svga->crtc[0x53] & 0x08) { + if ((addr >= 0x08000) && (addr <= 0x0803f)) + s3_pci_write(0, addr & 0xff, val, s3); + else if ((addr >= 0x083b0) && (addr <= 0x083df)) + s3_out(addr & 0xfff, val, s3); + } + + switch (addr & 0x1fffe) { case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ case 0x8102: addr = 0x86e8; break; @@ -1019,12 +1133,25 @@ s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) case 0x814a: addr = 0x96e8; break; case 0x814c: addr = 0x96ea; break; + case 0x8150: addr = 0xd2e8; break; + + case 0x8154: addr = 0x8ee8; break; + case 0x8156: addr = 0x96e8; break; + + case 0x8164: case 0x8166: + WRITE8(addr, s3->accel.pat_bg_color, val); + return; + case 0x8168: addr = 0xeae8; break; case 0x816a: addr = 0xeaea; break; + + case 0x816c: case 0x816e: + WRITE8(addr, s3->accel.pat_fg_color, val); + return; } addr |= addr_lo; } - + if (svga->crtc[0x53] & 0x08) { if ((addr & 0xffff) < 0x8000) { if (s3->accel.cmd & 0x100) { @@ -1088,7 +1215,7 @@ static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) { svga_t *svga = &s3->svga; - + if (svga->crtc[0x53] & 0x08) { if ((addr & 0xfffe) < 0x8000) { s3_accel_out_pixtrans_w(s3, val); @@ -1123,7 +1250,7 @@ s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) if ((addr & 0xfffc) < 0x8000) { s3_accel_out_pixtrans_l(s3, val); } else { - switch (addr & 0xfffc) { + switch (addr & 0xfffc) { case 0x8180: s3->streams.pri_ctrl = val; svga_recalctimings(svga); @@ -1254,13 +1381,16 @@ s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) s3_accel_write_fifo(s3, addr, val); break; + case 0x18080: + break; + default: s3_accel_write_fifo(s3, addr, val); s3_accel_write_fifo(s3, addr + 1, val >> 8); s3_accel_write_fifo(s3, addr + 2, val >> 16); s3_accel_write_fifo(s3, addr + 3, val >> 24); break; - } + } } } else { if (addr & 0x8000) { @@ -1732,7 +1862,7 @@ s3_io_remove_alt(s3_t *s3) io_removehandler(0x8d48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x9148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x9548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x9d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -1745,7 +1875,11 @@ s3_io_remove_alt(s3_t *s3) io_removehandler(0xb548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xb948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xbd48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xe148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_removehandler(0xd148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xed48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); } static void @@ -1775,7 +1909,11 @@ s3_io_remove(s3_t *s3) io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xd2e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + io_removehandler(0xe6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xeae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xeee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); s3_io_remove_alt(s3); } @@ -1783,13 +1921,18 @@ s3_io_remove(s3_t *s3) static void s3_io_set_alt(s3_t *s3) { + svga_t *svga = &s3->svga; + if (!s3->translate) return; + if ((s3->chip == S3_VISION968) && (svga->seqregs[0x90] & 0x80)) + return; + io_sethandler(0x4148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x4548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x4948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - if (s3->chip == S3_TRIO64 || s3->chip >= S3_TRIO64V) + if (s3->chip == S3_TRIO64 || s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968) { io_sethandler(0x8148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x8548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -1807,7 +1950,10 @@ s3_io_set_alt(s3_t *s3) io_sethandler(0x9148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x9548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); } - io_sethandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_VISION968) + io_sethandler(0x9948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + else + io_sethandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x9d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -1821,19 +1967,30 @@ s3_io_set_alt(s3_t *s3) io_sethandler(0xb948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xbd48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xe148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + if (s3->chip == S3_VISION968) { + io_sethandler(0xd148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xed48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } } static void s3_io_set(s3_t *s3) { + svga_t *svga = &s3->svga; + s3_io_remove(s3); io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + if ((s3->chip == S3_VISION968) && (svga->seqregs[0x90] & 0x80)) + return; + io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - if (s3->chip == S3_TRIO64 || s3->chip >= S3_TRIO64V) + if (s3->chip == S3_TRIO64 || s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968) { io_sethandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -1851,7 +2008,10 @@ s3_io_set(s3_t *s3) io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); } - io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_VISION968) + io_sethandler(0x9ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + else + io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -1865,6 +2025,12 @@ s3_io_set(s3_t *s3) io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + if (s3->chip == S3_VISION968) { + io_sethandler(0xd2e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xeae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xeee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } s3_io_set_alt(s3); } @@ -1883,7 +2049,7 @@ s3_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3c2: - if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) { + if ((s3->chip == S3_VISION964) || (s3->chip == S3_VISION968) || (s3->chip == S3_86C928)) { if (((val >> 2) & 3) != 3) icd2061_write(svga->clock_gen, (val >> 2) & 3); } @@ -1906,6 +2072,13 @@ s3_out(uint16_t addr, uint8_t val, void *p) svga->write_bank = svga->read_bank = s3->bank << 16; else svga->write_bank = svga->read_bank = s3->bank << 14; + } else if (svga->seqaddr == 9) { + svga->seqregs[svga->seqaddr] = val & 0x80; + s3_io_set(s3); + return; + } else if (svga->seqaddr == 0xa) { + svga->seqregs[svga->seqaddr] = val & 0x80; + return; } break; @@ -1916,13 +2089,15 @@ s3_out(uint16_t addr, uint8_t val, void *p) rs2 = (svga->crtc[0x55] & 0x01); if (s3->chip >= S3_TRIO32) svga_out(addr, val, svga); - else if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) { + else if ((s3->chip == S3_VISION964 && s3->card_type != S3_ELSAWIN2KPROX_964) || (s3->chip == S3_86C928)) { if (!(svga->crtc[0x45] & 0x20) || (s3->chip == S3_86C928)) rs3 = !!(svga->crtc[0x55] & 0x02); else rs3 = 0; bt48x_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); - } else if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) + } else if ((s3->chip == S3_VISION964 && s3->card_type == S3_ELSAWIN2KPROX_964) || s3->chip == S3_VISION968) + ibm_rgb525_ramdac_out(addr, rs2, val, svga->ramdac, svga); + else if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) att49x_ramdac_out(addr, val, svga->ramdac, svga); else if (s3->chip < S3_86C928) sc1148x_ramdac_out(addr, val, svga->ramdac, svga); @@ -1972,7 +2147,7 @@ s3_out(uint16_t addr, uint8_t val, void *p) case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; case 0x01: s3->width = 1152; break; case 0x40: s3->width = 640; break; - case 0x80: s3->width = 800; break; + case 0x80: s3->width = ((s3->chip > S3_86C805) && (s3->accel.advfunc_cntl & 4)) ? 1600 : 800; break; case 0x81: s3->width = 1600; break; case 0xc0: s3->width = 1280; break; } @@ -2020,13 +2195,13 @@ s3_out(uint16_t addr, uint8_t val, void *p) break; case 0x45: - if (s3->chip == S3_VISION964) + if (s3->chip == S3_VISION964 || s3->chip == S3_VISION968) break; svga->hwcursor.ena = val & 1; break; case 0x46: case 0x47: case 0x48: case 0x49: case 0x4c: case 0x4d: case 0x4e: case 0x4f: - if (s3->chip == S3_VISION964) + if (s3->chip == S3_VISION964 || s3->chip == S3_VISION968) break; svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; if (svga->bpp == 32) svga->hwcursor.x >>= 1; @@ -2073,6 +2248,9 @@ s3_out(uint16_t addr, uint8_t val, void *p) case 0x53: case 0x58: case 0x59: case 0x5a: + if (svga->crtcreg == 0x59) + pclog("0x59 write val = %02x\n", val); + s3_updatemapping(s3); break; @@ -2088,8 +2266,13 @@ s3_out(uint16_t addr, uint8_t val, void *p) } break; + case 0x5c: + if ((val & 0xa0) == 0x80) + i2c_gpio_set(s3->i2c, !!(val & 0x40), !!(val & 0x10)); + break; + case 0x42: - if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) { + if ((s3->chip == S3_VISION964) || (s3->chip == S3_VISION968) || (s3->chip == S3_86C928)) { if (((svga->miscout >> 2) & 3) == 3) icd2061_write(svga->clock_gen, svga->crtc[0x42] & 0x0f); } @@ -2161,10 +2344,12 @@ s3_in(uint16_t addr, void *p) rs2 = (svga->crtc[0x55] & 0x01) || !!(svga->crtc[0x43] & 2); if (s3->chip >= S3_TRIO32) return svga_in(addr, svga); - else if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) { + else if ((s3->chip == S3_VISION964 && s3->card_type != S3_ELSAWIN2KPROX_964) || (s3->chip == S3_86C928)) { rs3 = !!(svga->crtc[0x55] & 0x02); return bt48x_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); - } else if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) + } else if ((s3->chip == S3_VISION964 && s3->card_type == S3_ELSAWIN2KPROX_964) || s3->chip == S3_VISION968) + return ibm_rgb525_ramdac_in(addr, rs2, svga->ramdac, svga); + else if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) return att49x_ramdac_in(addr, svga->ramdac, svga); else if (s3->chip <= S3_86C924) return sc1148x_ramdac_in(addr, svga->ramdac, svga); @@ -2186,18 +2371,24 @@ s3_in(uint16_t addr, void *p) case 0x45: s3->hwc_col_stack_pos = 0; break; case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3); case 0x5c: /* General Output Port Register */ - temp = svga->crtc[svga->crtcreg] & 0xf0; - if (((svga->miscout >> 2) & 3) == 3) + temp = svga->crtc[svga->crtcreg] & 0xa0; + if (((svga->miscout >> 2) & 3) == 3) temp |= svga->crtc[0x42] & 0x0f; - else + else temp |= ((svga->miscout >> 2) & 3); - return temp; + if ((temp & 0xa0) == 0xa0) { + if ((svga->crtc[0x5c] & 0x40) && i2c_gpio_get_scl(s3->i2c)) + temp |= 0x40; + if ((svga->crtc[0x5c] & 0x10) && i2c_gpio_get_sda(s3->i2c)) + temp |= 0x10; + } + return temp; case 0x69: return s3->ma_ext; case 0x6a: return s3->bank; /* Phoenix S3 video BIOS'es seem to expect CRTC registers 6B and 6C to be mirrors of 59 and 5A. */ - case 0x6b: return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : svga->crtc[0x59]; - case 0x6c: return (s3->chip >= S3_TRIO64V) ? 0 : (svga->crtc[0x5a] & 0x80); + case 0x6b: return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : ((s3->chip == S3_VISION968) ? (svga->crtc[0x59] & 0xfe) : svga->crtc[0x59]); + case 0x6c: return (s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968) ? 0 : (svga->crtc[0x5a] & 0x80); } return svga->crtc[svga->crtcreg]; } @@ -2226,8 +2417,13 @@ static void s3_recalctimings(svga_t *svga) else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; if (!svga->rowoffset) svga->rowoffset = 256; - if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) - bt48x_recalctimings(svga->ramdac, svga); + if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) { + if (s3->card_type == S3_ELSAWIN2KPROX_964) + ibm_rgb525_recalctimings(svga->ramdac, svga); + else + bt48x_recalctimings(svga->ramdac, svga); + } else if (s3->chip == S3_VISION968) + ibm_rgb525_recalctimings(svga->ramdac, svga); else svga->interlace = svga->crtc[0x42] & 0x20; @@ -2247,36 +2443,45 @@ static void s3_recalctimings(svga_t *svga) switch (svga->bpp) { case 8: svga->render = svga_render_8bpp_highres; + if (s3->width == 1280) + svga->hdisp *= 2; break; case 15: svga->render = svga_render_15bpp_highres; if ((s3->chip != S3_VISION964) && (s3->chip != S3_86C801)) { if (s3->chip == S3_86C928) svga->hdisp *= 2; - else + else if (s3->chip != S3_VISION968) svga->hdisp /= 2; } + if (s3->width == 1280) + svga->hdisp *= 2; break; case 16: svga->render = svga_render_16bpp_highres; if ((s3->chip != S3_VISION964) && (s3->chip != S3_86C801)) { if (s3->chip == S3_86C928) svga->hdisp *= 2; - else + else if (s3->chip != S3_VISION968) svga->hdisp /= 2; } + if (s3->width == 1280) + svga->hdisp *= 2; break; case 24: svga->render = svga_render_24bpp_highres; - if (s3->chip != S3_86C928 && s3->chip != S3_86C801 && s3->chip != S3_86C805) + if (s3->chip != S3_86C928 && s3->chip != S3_86C801 && s3->chip != S3_86C805 && s3->chip != S3_VISION968) svga->hdisp /= 3; else svga->hdisp = (svga->hdisp * 2) / 3; break; case 32: svga->render = svga_render_32bpp_highres; - if ((s3->chip < S3_TRIO32) && (s3->chip != S3_VISION964) && (s3->chip != S3_86C928)) + if ((s3->chip < S3_TRIO32) && (s3->chip != S3_VISION964) && + (s3->chip != S3_VISION968) && (s3->chip != S3_86C928)) svga->hdisp /= 4; + if (s3->width == 1280 || s3->width == 1600) + svga->hdisp *= 2; break; } } @@ -2467,16 +2672,23 @@ s3_updatemapping(s3_t *s3) mem_mapping_disable(&s3->linear_mapping); if (!(svga->crtc[0x53] & 0x10)) { + pclog("Linear mapping enabled at 0xa0000\n"); mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); svga->banked_mask = 0xffff; } } else { + if (s3->chip >= S3_TRIO64V) + s3->linear_base &= 0xfc000000; + else + s3->linear_base &= 0xfe000000; + pclog("Linear mapping enabled at %08x, size = %08x\n", s3->linear_base, s3->linear_size); mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); } } else { + pclog("Linear mapping disabled\n"); mem_mapping_disable(&s3->linear_mapping); } - + /* Memory mapped I/O. */ if ((svga->crtc[0x53] & 0x10) || (s3->accel.advfunc_cntl & 0x20)) { mem_mapping_disable(&svga->mapping); @@ -2486,17 +2698,22 @@ s3_updatemapping(s3_t *s3) else mem_mapping_set_addr(&s3->mmio_mapping, 0xa0000, 0x10000); } else { + pclog("Standard MMIO enabled at 0xa0000\n"); mem_mapping_enable(&s3->mmio_mapping); } } else { + pclog("Standard MMIO disabled\n"); mem_mapping_disable(&s3->mmio_mapping); } /* New MMIO. */ if (svga->crtc[0x53] & 0x08) { + pclog("New MMIO enabled at %08x, CRTC59 = %02x\n", s3->linear_base + 0x1000000, svga->crtc[0x59]); mem_mapping_set_addr(&s3->new_mmio_mapping, s3->linear_base + 0x1000000, 0x10000); - } else - mem_mapping_disable(&s3->new_mmio_mapping); + } else { + pclog("New MMIO disabled\n", s3->linear_base); + mem_mapping_disable(&s3->new_mmio_mapping); + } } } @@ -2524,7 +2741,8 @@ s3_enable_fifo(s3_t *s3) if ((s3->chip == S3_TRIO32) || (s3->chip == S3_TRIO64) || (s3->chip == S3_TRIO64V) || (s3->chip == S3_TRIO64V2) || - (s3->chip == S3_VISION864) || (s3->chip == S3_VISION964)) + (s3->chip == S3_VISION864) || (s3->chip == S3_VISION964) || + (s3->chip == S3_VISION968)) return 1; /* FIFO always enabled on these chips. */ return !!((svga->crtc[0x40] & 0x08) || (s3->accel.advfunc_cntl & 0x40)); @@ -2535,6 +2753,7 @@ static void s3_accel_out(uint16_t port, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; if (!s3->enable_8514) return; @@ -2564,6 +2783,11 @@ s3_accel_out(uint16_t port, uint8_t val, void *p) break; case 0x4948: case 0x4ae8: s3->accel.advfunc_cntl = val; + if ((s3->chip > S3_86C805) && ((svga->crtc[0x50] & 0xc1) == 0x80)) { + s3->width = (val & 4) ? 1600 : 800; + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } s3_updatemapping(s3); break; } @@ -2871,6 +3095,48 @@ s3_accel_in(uint16_t port, void *p) } break; + case 0xd148: case 0xd2e8: + return s3->accel.ropmix & 0xff; + + case 0xd149: case 0xd2e9: + return s3->accel.ropmix >> 8; + + case 0xe548: case 0xe6e8: + return s3->accel.pat_bg_color & 0xff; + + case 0xe549: case 0xe6e9: + return s3->accel.pat_bg_color >> 8; + + case 0xe54a: case 0xe6ea: + return s3->accel.pat_bg_color >> 16; + + case 0xe54b: case 0xe6eb: + return s3->accel.pat_bg_color >> 24; + + case 0xe948: case 0xeae8: + return s3->accel.pat_y & 0xff; + + case 0xe949: case 0xeae9: + return s3->accel.pat_y >> 8; + + case 0xe94a: case 0xeaea: + return s3->accel.pat_x & 0xff; + + case 0xe94b: case 0xeaeb: + return s3->accel.pat_x >> 8; + + case 0xed48: case 0xeee8: + return s3->accel.pat_fg_color & 0xff; + + case 0xed49: case 0xeee9: + return s3->accel.pat_fg_color >> 8; + + case 0xed4a: case 0xeeea: + return s3->accel.pat_fg_color >> 16; + + case 0xed4b: case 0xeeeb: + return s3->accel.pat_fg_color >> 24; + case 0xe148: case 0xe2e8: if (!s3_cpu_dest(s3)) break; @@ -2984,11 +3250,17 @@ s3_accel_read(uint32_t addr, void *p) svga_t *svga = &s3->svga; uint8_t temp = 0x00; - if (!s3->enable_8514) + if (!s3->enable_8514) { return 0xff; + } - if (svga->crtc[0x53] & 0x08) { - switch (addr & 0xffff) { + if (((svga->crtc[0x53] & 0x08) && s3->chip >= S3_TRIO64V) || ((svga->crtc[0x53] & 0x18) && (s3->chip == S3_VISION968))) { + if ((addr >= 0x08000) && (addr <= 0x0803f)) + return s3_pci_read(0, addr & 0xff, s3); + else if ((addr >= 0x083b0) && (addr <= 0x083df)) + return s3_in(addr & 0xfff, s3); + + switch (addr & 0x1ffff) { case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: @@ -3006,6 +3278,9 @@ s3_accel_read(uint32_t addr, void *p) return s3->subsys_stat; case 0x8505: return s3->subsys_cntl; + /* Video engine status - currently a dummy. */ + case 0x1809c: case 0x1809d: case 0x1809e: case 0x1809f: + return 0x00; default: return s3_accel_in(addr & 0xffff, p); } @@ -3038,8 +3313,8 @@ s3_accel_read_w(uint32_t addr, void *p) if (!s3->enable_8514) return 0xffff; - if (svga->crtc[0x53] & 0x08) { - switch (addr & 0xfffe) { + if (((svga->crtc[0x53] & 0x08) && s3->chip >= S3_TRIO64V) || ((svga->crtc[0x53] & 0x18) && (s3->chip == S3_VISION968))) { + switch (addr & 0x001fffe) { default: return s3_accel_read(addr, p) | s3_accel_read(addr + 1, p) << 8; @@ -3084,8 +3359,8 @@ s3_accel_read_l(uint32_t addr, void *p) if (!s3->enable_8514) return 0xffffffff; - if (svga->crtc[0x53] & 0x08) { - switch (addr & 0xfffc) { + if (((svga->crtc[0x53] & 0x08) && s3->chip >= S3_TRIO64V) || ((svga->crtc[0x53] & 0x18) && (s3->chip == S3_VISION968))) { + switch (addr & 0x001fffc) { case 0x8180: temp = s3->streams.pri_ctrl; break; @@ -3241,6 +3516,7 @@ polygon_setup(s3_t *s3) } } + #define READ(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; @@ -3276,6 +3552,277 @@ polygon_setup(s3_t *s3) } + +#define ROPMIX_READ(D, P, S) \ + { \ + switch (rop) { \ + case 0x00: out = 0; break; \ + case 0x01: out = ~(D | (P | S)); break; \ + case 0x02: out = D & ~(P | S); break; \ + case 0x03: out = ~(P | S); break; \ + case 0x04: out = S & ~(D | P); break; \ + case 0x05: out = ~(D | P); break; \ + case 0x06: out = ~(P | ~(D ^ S)); break; \ + case 0x07: out = ~(P | (D & S)); break; \ + case 0x08: out = S & (D & ~P); break; \ + case 0x09: out = ~(P | (D ^ S)); break; \ + case 0x0a: out = D & ~P; break; \ + case 0x0b: out = ~(P | (S & ~D)); break; \ + case 0x0c: out = S & ~P; break; \ + case 0x0d: out = ~(P | (D & ~S)); break; \ + case 0x0e: out = ~(P | ~(D | S)); break; \ + case 0x0f: out = ~P; break; \ + case 0x10: out = P & ~(D | S); break; \ + case 0x11: out = ~(D | S); break; \ + case 0x12: out = ~(S | ~(D ^ P)); break; \ + case 0x13: out = ~(S | (D & P)); break; \ + case 0x14: out = ~(D | ~(P ^ S)); break; \ + case 0x15: out = ~(D | (P & S)); break; \ + case 0x16: out = P ^ (S ^ (D & ~(P & S))); break; \ + case 0x17: out = ~(S ^ ((S ^ P) & (D ^ S))); break; \ + case 0x18: out = (S ^ P) & (P ^ D); break; \ + case 0x19: out = ~(S ^ (D & ~(P & S))); break; \ + case 0x1a: out = P ^ (D | (S & P)); break; \ + case 0x1b: out = ~(S ^ (D & (P ^ S))); break; \ + case 0x1c: out = P ^ (S | (D & P)); break; \ + case 0x1d: out = ~(D ^ (S & (P ^ D))); break; \ + case 0x1e: out = P ^ (D | S); break; \ + case 0x1f: out = ~(P & (D | S)); break; \ + case 0x20: out = D & (P & ~S); break; \ + case 0x21: out = ~(S | (D ^ P)); break; \ + case 0x22: out = D & ~S; break; \ + case 0x23: out = ~(S | (P & ~D)); break; \ + case 0x24: out = (S ^ P) & (D ^ S); break; \ + case 0x25: out = ~(P ^ (D & ~(S & P))); break; \ + case 0x26: out = S ^ (D | (P & S)); break; \ + case 0x27: out = S ^ (D | ~(P ^ S)); break; \ + case 0x28: out = D & (P ^ S); break; \ + case 0x29: out = ~(P ^ (S ^ (D | (P & S)))); break; \ + case 0x2a: out = D & ~(P & S); break; \ + case 0x2b: out = ~(S ^ ((S ^ P) & (P ^ D))); break; \ + case 0x2c: out = S ^ (P & (D | S)); break; \ + case 0x2d: out = P ^ (S | ~D); break; \ + case 0x2e: out = P ^ (S | (D ^ P)); break; \ + case 0x2f: out = ~(P & (S | ~D)); break; \ + case 0x30: out = P & ~S; break; \ + case 0x31: out = ~(S | (D & ~P)); break; \ + case 0x32: out = S ^ (D | (P | S)); break; \ + case 0x33: out = ~S; break; \ + case 0x34: out = S ^ (P | (D & S)); break; \ + case 0x35: out = S ^ (P | ~(D ^ S)); break; \ + case 0x36: out = S ^ (D | P); break; \ + case 0x37: out = ~(S & (D | P)); break; \ + case 0x38: out = P ^ (S & (D | P)); break; \ + case 0x39: out = S ^ (P | ~D); break; \ + case 0x3a: out = S ^ (P | (D ^ S)); break; \ + case 0x3b: out = ~(S & (P | ~D)); break; \ + case 0x3c: out = P ^ S; break; \ + case 0x3d: out = S ^ (P | ~(D | S)); break; \ + case 0x3e: out = S ^ (P | (D & ~S)); break; \ + case 0x3f: out = ~(P & S); break; \ + case 0x40: out = P & (S & ~D); break; \ + case 0x41: out = ~(D | (P ^ S)); break; \ + case 0x42: out = (S ^ D) & (P ^ D); break; \ + case 0x43: out = ~(S ^ (P & ~(D & S))); break; \ + case 0x44: out = S & ~D; break; \ + case 0x45: out = ~(D | (P & ~S)); break; \ + case 0x46: out = D ^ (S | (P & D)); break; \ + case 0x47: out = ~(P ^ (S & (D ^ P))); break; \ + case 0x48: out = S & (D ^ P); break; \ + case 0x49: out = ~(P ^ (D ^ (S | (P & D)))); break; \ + case 0x4a: out = D ^ (P & (S | D)); break; \ + case 0x4b: out = P ^ (D | ~S); break; \ + case 0x4c: out = S & ~(D & P); break; \ + case 0x4d: out = ~(S ^ ((S ^ P) | (D ^ S))); break; \ + case 0x4e: out = P ^ (D | (S ^ P)); break; \ + case 0x4f: out = ~(P & (D | ~S)); break; \ + case 0x50: out = P & ~D; break; \ + case 0x51: out = ~(D | (S & ~P)); break; \ + case 0x52: out = D ^ (P | (S & D)); break; \ + case 0x53: out = ~(S ^ (P & (D ^ S))); break; \ + case 0x54: out = ~(D | ~(P | S)); break; \ + case 0x55: out = ~D; break; \ + case 0x56: out = D ^ (P | S); break; \ + case 0x57: out = ~(D & (P | S)); break; \ + case 0x58: out = P ^ (D & (S | P)); break; \ + case 0x59: out = D ^ (P | ~S); break; \ + case 0x5a: out = D ^ P; break; \ + case 0x5b: out = D ^ (P | ~(S | D)); break; \ + case 0x5c: out = D ^ (P | (S ^ D)); break; \ + case 0x5d: out = ~(D & (P | ~S)); break; \ + case 0x5e: out = D ^ (P | (S & ~D)); break; \ + case 0x5f: out = ~(D & P); break; \ + case 0x60: out = P & (D ^ S); break; \ + case 0x61: out = ~(D ^ (S ^ (P | (D & S)))); break; \ + case 0x62: out = D ^ (S & (P | D)); break; \ + case 0x63: out = S ^ (D | ~P); break; \ + case 0x64: out = S ^ (D & (P | S)); break; \ + case 0x65: out = D ^ (S | ~P); break; \ + case 0x66: out = D ^ S; break; \ + case 0x67: out = S ^ (D | ~(P | S)); break; \ + case 0x68: out = ~(D ^ (S ^ (P | ~(D | S)))); break; \ + case 0x69: out = ~(P ^ (D ^ S)); break; \ + case 0x6a: out = D ^ (P & S); break; \ + case 0x6b: out = ~(P ^ (S ^ (D & (P | S)))); break; \ + case 0x6c: out = S ^ (D & P); break; \ + case 0x6d: out = ~(P ^ (D ^ (S & (P | D)))); break; \ + case 0x6e: out = S ^ (D & (P | ~S)); break; \ + case 0x6f: out = ~(P & ~(D ^ S)); break; \ + case 0x70: out = P & ~(D & S); break; \ + case 0x71: out = ~(S ^ ((S ^ D) & (P ^ D))); break; \ + case 0x72: out = S ^ (D | (P ^ S)); break; \ + case 0x73: out = ~(S & (D | ~P)); break; \ + case 0x74: out = D ^ (S | (P ^ D)); break; \ + case 0x75: out = ~(D & (S | ~P)); break; \ + case 0x76: out = S ^ (D | (P & ~S)); break; \ + case 0x77: out = ~(D & S); break; \ + case 0x78: out = P ^ (D & S); break; \ + case 0x79: out = ~(D ^ (S ^ (P & (D | S)))); break; \ + case 0x7a: out = D ^ (P & (S | ~D)); break; \ + case 0x7b: out = ~(S & ~(D ^ P)); break; \ + case 0x7c: out = S ^ (P & (D | ~S)); break; \ + case 0x7d: out = ~(D & ~(P ^ S)); break; \ + case 0x7e: out = (S ^ P) | (D ^ S); break; \ + case 0x7f: out = ~(D & (P & S)); break; \ + case 0x80: out = D & (P & S); break; \ + case 0x81: out = ~((S ^ P) | (D ^ S)); break; \ + case 0x82: out = D & ~(P ^ S); break; \ + case 0x83: out = ~(S ^ (P & (D | ~S))); break; \ + case 0x84: out = S & ~(D ^ P); break; \ + case 0x85: out = ~(P ^ (D & (S | ~P))); break; \ + case 0x86: out = D ^ (S ^ (P & (D | S))); break; \ + case 0x87: out = ~(P ^ (D & S)); break; \ + case 0x88: out = D & S; break; \ + case 0x89: out = ~(S ^ (D | (P & ~S))); break; \ + case 0x8a: out = D & (S | ~P); break; \ + case 0x8b: out = ~(D ^ (S | (P ^ D))); break; \ + case 0x8c: out = S & (D | ~P); break; \ + case 0x8d: out = ~(S ^ (D | (P ^ S))); break; \ + case 0x8e: out = S ^ ((S ^ D) & (P ^ D)); break; \ + case 0x8f: out = ~(P & ~(D & S)); break; \ + case 0x90: out = P & ~(D ^ S); break; \ + case 0x91: out = ~(S ^ (D & (P | ~S))); break; \ + case 0x92: out = D ^ (P ^ (S & (D | P))); break; \ + case 0x93: out = ~(S ^ (P & D)); break; \ + case 0x94: out = P ^ (S ^ (D & (P | S))); break; \ + case 0x95: out = ~(D ^ (P & S)); break; \ + case 0x96: out = D ^ (P ^ S); break; \ + case 0x97: out = P ^ (S ^ (D | ~(P | S))); break; \ + case 0x98: out = ~(S ^ (D | ~(P | S))); break; \ + case 0x99: out = ~(D ^ S); break; \ + case 0x9a: out = D ^ (P & ~S); break; \ + case 0x9b: out = ~(S ^ (D & (P | S))); break; \ + case 0x9c: out = S ^ (P & ~D); break; \ + case 0x9d: out = ~(D ^ (S & (P | D))); break; \ + case 0x9e: out = D ^ (S ^ (P | (D & S))); break; \ + case 0x9f: out = ~(P & (D ^ S)); break; \ + case 0xa0: out = D & P; break; \ + case 0xa1: out = ~(P ^ (D | (S & ~P))); break; \ + case 0xa2: out = D & (P | ~S); break; \ + case 0xa3: out = ~(D ^ (P | (S ^ D))); break; \ + case 0xa4: out = ~(P ^ (D | ~(S | P))); break; \ + case 0xa5: out = ~(P ^ D); break; \ + case 0xa6: out = D ^ (S & ~P); break; \ + case 0xa7: out = ~(P ^ (D & (S | P))); break; \ + case 0xa8: out = D & (P | S); break; \ + case 0xa9: out = ~(D ^ (P | S)); break; \ + case 0xaa: out = D; break; \ + case 0xab: out = D | ~(P | S); break; \ + case 0xac: out = S ^ (P & (D ^ S)); break; \ + case 0xad: out = ~(D ^ (P | (S & D))); break; \ + case 0xae: out = D | (S & ~P); break; \ + case 0xaf: out = D | ~P; break; \ + case 0xb0: out = P & (D | ~S); break; \ + case 0xb1: out = ~(P ^ (D | (S ^ P))); break; \ + case 0xb2: out = S ^ ((S ^ P) | (D ^ S)); break; \ + case 0xb3: out = ~(S & ~(D & P)); break; \ + case 0xb4: out = P ^ (S & ~D); break; \ + case 0xb5: out = ~(D ^ (P & (S | D))); break; \ + case 0xb6: out = D ^ (P ^ (S | (D & P))); break; \ + case 0xb7: out = ~(S & (D ^ P)); break; \ + case 0xb8: out = P ^ (S & (D ^ P)); break; \ + case 0xb9: out = ~(D ^ (S | (P & D))); break; \ + case 0xba: out = D | (P & ~S); break; \ + case 0xbb: out = D | ~S; break; \ + case 0xbc: out = S ^ (P & ~(D & S)); break; \ + case 0xbd: out = ~((S ^ D) & (P ^ D)); break; \ + case 0xbe: out = D | (P ^ S); break; \ + case 0xbf: out = D | ~(P & S); break; \ + case 0xc0: out = P & S; break; \ + case 0xc1: out = ~(S ^ (P | (D & ~S))); break; \ + case 0xc2: out = ~(S ^ (P | ~(D | S))); break; \ + case 0xc3: out = ~(P ^ S); break; \ + case 0xc4: out = S & (P | ~D); break; \ + case 0xc5: out = ~(S ^ (P | (D ^ S))); break; \ + case 0xc6: out = S ^ (D & ~P); break; \ + case 0xc7: out = ~(P ^ (S & (D | P))); break; \ + case 0xc8: out = S & (D | P); break; \ + case 0xc9: out = ~(S ^ (P | D)); break; \ + case 0xca: out = D ^ (P & (S ^ D)); break; \ + case 0xcb: out = ~(S ^ (P | (D & S))); break; \ + case 0xcc: out = S; break; \ + case 0xcd: out = S | ~(D | P); break; \ + case 0xce: out = S | (D & ~P); break; \ + case 0xcf: out = S | ~P; break; \ + case 0xd0: out = P & (S | ~D); break; \ + case 0xd1: out = ~(P ^ (S | (D ^ P))); break; \ + case 0xd2: out = P ^ (D & ~S); break; \ + case 0xd3: out = ~(S ^ (P & (D | S))); break; \ + case 0xd4: out = S ^ ((S ^ P) & (P ^ D)); break; \ + case 0xd5: out = ~(D & ~(P & S)); break; \ + case 0xd6: out = P ^ (S ^ (D | (P & S))); break; \ + case 0xd7: out = ~(D & (P ^ S)); break; \ + case 0xd8: out = P ^ (D & (S ^ P)); break; \ + case 0xd9: out = ~(S ^ (D | (P & S))); break; \ + case 0xda: out = D ^ (P & ~(S & D)); break; \ + case 0xdb: out = ~((S ^ P) & (D ^ S)); break; \ + case 0xdc: out = S | (P & ~D); break; \ + case 0xdd: out = S | ~D; break; \ + case 0xde: out = S | (D ^ P); break; \ + case 0xdf: out = S | ~(D & P); break; \ + case 0xe0: out = P & (D | S); break; \ + case 0xe1: out = ~(P ^ (D | S)); break; \ + case 0xe2: out = D ^ (S & (P ^ D)); break; \ + case 0xe3: out = ~(P ^ (S | (D & P))); break; \ + case 0xe4: out = S ^ (D & (P ^ S)); break; \ + case 0xe5: out = ~(P ^ (D | (S & P))); break; \ + case 0xe6: out = S ^ (D & ~(P & S)); break; \ + case 0xe7: out = ~((S ^ P) & (P ^ D)); break; \ + case 0xe8: out = S ^ ((S ^ P) & (D ^ S)); break; \ + case 0xe9: out = ~(D ^ (S ^ (P & ~(D & S)))); break; \ + case 0xea: out = D | (P & S); break; \ + case 0xeb: out = D | ~(P ^ S); break; \ + case 0xec: out = S | (D & P); break; \ + case 0xed: out = S | ~(D ^ P); break; \ + case 0xee: out = D | S; break; \ + case 0xef: out = S | (D | ~P); break; \ + case 0xf0: out = P; break; \ + case 0xf1: out = P | ~(D | S); break; \ + case 0xf2: out = P | (D & ~S); break; \ + case 0xf3: out = P | ~S; break; \ + case 0xf4: out = P | (S & ~D); break; \ + case 0xf5: out = P | ~D; break; \ + case 0xf6: out = P | (D ^ S); break; \ + case 0xf7: out = P | ~(D & S); break; \ + case 0xf8: out = P | (D & S); break; \ + case 0xf9: out = P | ~(D ^ S); break; \ + case 0xfa: out = D | P; break; \ + case 0xfb: out = D | (P | ~S); break; \ + case 0xfc: out = P | S; break; \ + case 0xfd: out = P | (S | ~D); break; \ + case 0xfe: out = D | (P | S); break; \ + case 0xff: out = ~0; break; \ + } \ + } + + +#define ROPMIX { \ + old_dest_dat = dest_dat; \ + ROPMIX_READ(dest_dat, pat_dat, src_dat); \ + out = (out & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask); \ + } + + #define WRITE(addr, dat) if (s3->bpp == 0) \ { \ svga->vram[(addr) & s3->vram_mask] = dat; \ @@ -3298,6 +3845,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ { svga_t *svga = &s3->svga; uint32_t src_dat = 0, dest_dat, old_dest_dat; + uint32_t out, pat_dat = 0; int frgd_mix, bkgd_mix; int clip_t = s3->accel.multifunc[1] & 0xfff; int clip_l = s3->accel.multifunc[2] & 0xfff; @@ -3308,6 +3856,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ uint16_t *vram_w = (uint16_t *)svga->vram; uint32_t *vram_l = (uint32_t *)svga->vram; uint32_t compare = s3->accel.color_cmp; + uint8_t rop = s3->accel.ropmix & 0xff; int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; uint32_t rd_mask = s3->accel.rd_mask; int cmd = s3->accel.cmd >> 13; @@ -3321,8 +3870,9 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ } } - if ((s3->chip >= S3_TRIO64) && (s3->accel.cmd & (1 << 11))) + if ((s3->chip >= S3_TRIO64 || s3->chip == S3_VISION968) && (s3->accel.cmd & (1 << 11))) { cmd |= 8; + } // SRC-BASE/DST-BASE if ((s3->accel.multifunc[0xd] >> 4) & 7) { @@ -3349,7 +3899,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ if (!cpu_input) s3->accel.dat_count = 0; - + if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) { if (s3->bpp == 3 && count == 2) { if (s3->accel.dat_count) { @@ -3377,7 +3927,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ case 0x000: mix_mask = 0x80; break; case 0x200: mix_mask = 0x8000; break; case 0x400: mix_mask = 0x80000000; break; - case 0x600: mix_mask = (s3->chip == S3_TRIO32 || s3->chip >= S3_TRIO64V) ? 0x80 : 0x80000000; break; + case 0x600: mix_mask = (s3->chip == S3_TRIO32 || s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968) ? 0x80 : 0x80000000; break; } if (s3->bpp == 0) compare &= 0xff; @@ -3695,6 +4245,82 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ } break; + + case 3: /*Polygon Fill Solid (Vision868/968 and Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64 && s3->chip != S3_VISION968) + break; + + polygon_setup(s3); + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.dest = dstbase + y * s3->width; + + while (x_count-- && count--) + { + if ((s3->accel.poly_x & 0xfff) >= clip_l && (s3->accel.poly_x & 0xfff) <= clip_r && + (s3->accel.poly_cy & 0xfff) >= clip_t && (s3->accel.poly_cy & 0xfff) <= clip_b) + { + switch (frgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; /*Not supported?*/ break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.poly_x, dest_dat); + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; + + case 6: /*BitBlt*/ if (!cpu_input) /*!cpu_input is trigger to start operation*/ { @@ -3725,7 +4351,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7) { - while (1) + while (count-- && s3->accel.sy >= 0) { if ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) @@ -3971,86 +4597,112 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ } } break; - - case 3: /*Polygon Fill Solid (Trio64 only)*/ - { - int end_y1, end_y2; + + case 9: /*Polyline/2-Point Line (Vision868/968 and Trio64 only)*/ + { + int error; - if (s3->chip != S3_TRIO64) + if (s3->chip != S3_TRIO64 && s3->chip != S3_VISION968) break; - polygon_setup(s3); + if (!cpu_input) { + s3->accel.dx = ABS(s3->accel.destx_distp - s3->accel.cur_x); + if (s3->accel.destx_distp & 0x1000) + s3->accel.dx |= ~0xfff; + s3->accel.dy = ABS(s3->accel.desty_axstp - s3->accel.cur_y); + if (s3->accel.desty_axstp & 0x1000) + s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) + s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) + s3->accel.cy |= ~0xfff; + } if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ - end_y1 = s3->accel.desty_axstp; - end_y2 = s3->accel.desty_axstp2; - - frgd_mix = (s3->accel.frgd_mix >> 5) & 3; - - while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) - { - int y = s3->accel.poly_cy; - int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; - - s3->accel.dest = dstbase + y * s3->width; - - while (x_count-- && count--) - { - if ((s3->accel.poly_x & 0xfff) >= clip_l && (s3->accel.poly_x & 0xfff) <= clip_r && - (s3->accel.poly_cy & 0xfff) >= clip_t && (s3->accel.poly_cy & 0xfff) <= clip_b) + if (s3->accel.dx > s3->accel.dy) { + error = s3->accel.dx / 2; + while (s3->accel.cx != s3->accel.destx_distp && count--) { + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { - switch (frgd_mix) - { - case 0: src_dat = s3->accel.bkgd_color; break; - case 1: src_dat = s3->accel.frgd_color; break; - case 2: src_dat = cpu_dat; break; - case 3: src_dat = 0; /*Not supported?*/ break; - } + src_dat = s3->accel.frgd_color; if ((compare_mode == 2 && src_dat != compare) || (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ(s3->accel.dest + s3->accel.poly_x, dest_dat); - + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + MIX - WRITE(s3->accel.dest + s3->accel.poly_x, dest_dat); + WRITE((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); } } - if (s3->bpp == 0) cpu_dat >>= 8; - else cpu_dat >>= 16; - if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) - s3->accel.poly_x++; + error -= s3->accel.dy; + if (error < 0) { + error += s3->accel.dx; + if (s3->accel.desty_axstp > s3->accel.cur_y) + s3->accel.cy++; + else + s3->accel.cy--; + } + + if (s3->accel.destx_distp > s3->accel.cur_x) + s3->accel.cx++; else - s3->accel.poly_x--; + s3->accel.cx--; } - - s3->accel.poly_cx += s3->accel.poly_dx1; - s3->accel.poly_cx2 += s3->accel.poly_dx2; - s3->accel.poly_x = s3->accel.poly_cx >> 20; - - s3->accel.poly_cy++; - s3->accel.poly_cy2++; - - if (!count) - break; - } - - s3->accel.cur_x = s3->accel.poly_cx & 0xfff; - s3->accel.cur_y = s3->accel.poly_cy & 0xfff; - s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; - s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; - } - break; + } else { + error = s3->accel.dy / 2; + while (s3->accel.cy != s3->accel.desty_axstp && count--) { + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) + { + src_dat = s3->accel.frgd_color; - case 11: /*Polygon Fill Pattern (Trio64 only)*/ + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + } + } + + error -= s3->accel.dx; + if (error < 0) { + error += s3->accel.dy; + if (s3->accel.destx_distp > s3->accel.cur_x) + s3->accel.cx++; + else + s3->accel.cx--; + } + if (s3->accel.desty_axstp > s3->accel.cur_y) + s3->accel.cy++; + else + s3->accel.cy--; + + } + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + break; + + + case 11: /*Polygon Fill Pattern (Vision868/968 and Trio64 only)*/ { int end_y1, end_y2; - if (s3->chip != S3_TRIO64) + if (s3->chip != S3_TRIO64 && s3->chip != S3_VISION968) break; polygon_setup(s3); @@ -4133,6 +4785,144 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; } break; + + case 14: /*ROPBlt (Vision868/968 only)*/ + if (s3->chip != S3_VISION968) + break; + + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.px = s3->accel.pat_x & 0xfff; + if (s3->accel.pat_x & 0x1000) s3->accel.px |= ~0xfff; + s3->accel.py = s3->accel.pat_y & 0xfff; + if (s3->accel.pat_y & 0x1000) s3->accel.py |= ~0xfff; + + s3->accel.dest = dstbase + (s3->accel.dy * s3->width); + s3->accel.src = srcbase + (s3->accel.cy * s3->width); + s3->accel.pattern = (s3->accel.py * s3->width); + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if (s3->accel.ropmix & 0x100) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: pat_dat = s3->accel.pat_bg_color; break; + case 1: pat_dat = s3->accel.pat_fg_color; break; + case 2: pat_dat = cpu_dat; break; + case 3: READ(s3->accel.pattern + s3->accel.px, pat_dat); break; + } + } else { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: pat_dat = s3->accel.bkgd_color; break; + case 1: pat_dat = s3->accel.frgd_color; break; + case 2: pat_dat = cpu_dat; break; + case 3: READ(s3->accel.pattern + s3->accel.px, pat_dat); break; + } + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3->accel.dest + s3->accel.dx, dest_dat); + + ROPMIX + + WRITE(s3->accel.dest + s3->accel.dx, out); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx++; + s3->accel.dx++; + s3->accel.px++; + } + else + { + s3->accel.cx--; + s3->accel.dx--; + s3->accel.px--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.px -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.px += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy++; + s3->accel.dy++; + s3->accel.py++; + } + else + { + s3->accel.cy--; + s3->accel.dy--; + s3->accel.py--; + } + + s3->accel.src = srcbase + (s3->accel.cy * s3->width); + s3->accel.dest = dstbase + (s3->accel.dy * s3->width); + s3->accel.pattern = (s3->accel.py * s3->width); + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) { + return; + } + } + } + break; } } @@ -4150,7 +4940,11 @@ s3_pci_read(int func, int addr, void *p) case 0x03: return (s3->chip == S3_TRIO64V2) ? 0x89 : 0x88; case PCI_REG_COMMAND: - return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + if (s3->chip == S3_VISION968) + return s3->pci_regs[PCI_REG_COMMAND] | 0x80; /*Respond to IO and memory accesses*/ + else + return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + break; case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ @@ -4158,13 +4952,13 @@ s3_pci_read(int func, int addr, void *p) case 0x09: return 0; /*Programming interface*/ case 0x0a: - if (s3->chip >= S3_TRIO32) + if (s3->chip >= S3_TRIO32 || s3->chip == S3_VISION968) return 0x00; /*Supports VGA interface*/ else return 0x01; break; case 0x0b: - if (s3->chip >= S3_TRIO32) + if (s3->chip >= S3_TRIO32 || s3->chip == S3_VISION968) return 0x03; else return 0x00; @@ -4172,8 +4966,8 @@ s3_pci_read(int func, int addr, void *p) case 0x10: return 0x00; /*Linear frame buffer address*/ case 0x11: return 0x00; - case 0x12: return (s3->chip >= S3_TRIO64V) ? 0 : (svga->crtc[0x5a] & 0x80); - case 0x13: return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : svga->crtc[0x59]; + case 0x12: return (s3->chip >= S3_TRIO64V || s3->chip == S3_VISION968) ? 0 : (svga->crtc[0x5a] & 0x80); + case 0x13: return (s3->chip >= S3_TRIO64V) ? (svga->crtc[0x59] & 0xfc) : ((s3->chip == S3_VISION968) ? (svga->crtc[0x59] & 0xfe) : svga->crtc[0x59]); case 0x30: return s3->has_bios ? (s3->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ case 0x31: return 0x00; @@ -4203,14 +4997,14 @@ s3_pci_write(int func, int addr, uint8_t val, void *p) break; case 0x12: - if (s3->chip != S3_TRIO64V && s3->chip != S3_TRIO64V2) { + if (s3->chip != S3_TRIO64V && s3->chip != S3_TRIO64V2 && s3->chip != S3_VISION968) { svga->crtc[0x5a] = (svga->crtc[0x5a] & 0x7f) | (val & 0x80); s3_updatemapping(s3); } break; case 0x13: - svga->crtc[0x59] = (s3->chip >= S3_TRIO64V) ? (val & 0xfc) : val; + svga->crtc[0x59] = (s3->chip >= S3_TRIO64V) ? (val & 0xfc) : ((s3->chip == S3_VISION968) ? (val & 0xfe) : val); s3_updatemapping(s3); break; @@ -4316,6 +5110,22 @@ static void *s3_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision964_vlb); break; + case S3_ELSAWIN2KPROX_964: + bios_fn = ROM_ELSAWIN2KPROX_964; + chip = S3_VISION964; + if (info->flags & DEVICE_PCI) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision964_pci); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision964_vlb); + break; + case S3_ELSAWIN2KPROX: + bios_fn = ROM_ELSAWIN2KPROX; + chip = S3_VISION968; + if (info->flags & DEVICE_PCI) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision968_pci); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_vision968_vlb); + break; case S3_PHOENIX_TRIO32: bios_fn = ROM_PHOENIX_TRIO32; chip = S3_TRIO32; @@ -4432,7 +5242,7 @@ static void *s3_init(const device_t *info) mem_mapping_disable(&s3->mmio_mapping); mem_mapping_disable(&s3->new_mmio_mapping); - if (chip == S3_VISION964) + if (chip == S3_VISION964 || chip == S3_VISION968) svga_init(info, &s3->svga, s3, vram_size, s3_recalctimings, s3_in, s3_out, @@ -4456,8 +5266,10 @@ static void *s3_init(const device_t *info) svga->hwcursor.ysize = 64; - if (chip == S3_VISION964) + if (chip == S3_VISION964 && info->local != S3_ELSAWIN2KPROX_964) svga->dac_hwcursor_draw = bt48x_hwcursor_draw; + else if ((chip == S3_VISION964 && info->local == S3_ELSAWIN2KPROX_964) || chip == S3_VISION968) + svga->dac_hwcursor_draw = ibm_rgb525_hwcursor_draw; if (chip >= S3_VISION964) { switch (vram) { @@ -4489,13 +5301,20 @@ static void *s3_init(const device_t *info) break; } } - - if (s3->pci) - svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4); - else if (s3->vlb) - svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4); - else - svga->crtc[0x36] = 3 | (3 << 2) | (1 << 4); + + if (chip == S3_VISION968) { + if (s3->pci) + svga->crtc[0x36] = 2 | (0 << 2) | (1 << 4); + else + svga->crtc[0x36] = 1 | (0 << 2) | (1 << 4); + } else { + if (s3->pci) + svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4); + else if (s3->vlb) + svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4); + else + svga->crtc[0x36] = 3 | (3 << 2) | (1 << 4); + } if (chip >= S3_86C928) svga->crtc[0x36] |= (vram_sizes[vram] << 5); @@ -4524,8 +5343,10 @@ static void *s3_init(const device_t *info) s3->fifo_thread = thread_create(fifo_thread, s3); s3->int_line = 0; + + s3->card_type = info->local; - switch(info->local) { + switch(s3->card_type) { case S3_ORCHID_86C911: case S3_DIAMOND_STEALTH_VRAM: svga->decode_mask = (1 << 20) - 1; @@ -4614,6 +5435,7 @@ static void *s3_init(const device_t *info) break; case S3_DIAMOND_STEALTH64_964: + case S3_ELSAWIN2KPROX_964: svga->decode_mask = (8 << 20) - 1; stepping = 0xd0; /*Vision964*/ s3->id = stepping; @@ -4621,10 +5443,33 @@ static void *s3_init(const device_t *info) s3->packed_mmio = 1; svga->crtc[0x5a] = 0x0a; - svga->ramdac = device_add(&bt485_ramdac_device); + svga->ramdac = (info->local == S3_ELSAWIN2KPROX_964) ? device_add(&ibm_rgb525_ramdac_device) : device_add(&bt485_ramdac_device); svga->clock_gen = device_add(&icd2061_device); svga->getclock = icd2061_getclock; - break; + break; + + case S3_ELSAWIN2KPROX: + svga->decode_mask = (8 << 20) - 1; + s3->id = 0xe1; /*Vision968*/ + s3->id_ext = 0xb0; + s3->id_ext_pci = 0xf0; + s3->packed_mmio = 1; + if (s3->pci) { + svga->crtc[0x53] = 0x18; + svga->crtc[0x58] = 0x10; + svga->crtc[0x59] = 0x70; + svga->crtc[0x5a] = 0x00; + svga->crtc[0x6c] = 1; + } else { + svga->crtc[0x53] = 0x00; + svga->crtc[0x59] = 0x00; + svga->crtc[0x5a] = 0x0a; + } + + svga->ramdac = device_add(&ibm_rgb525_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + break; case S3_PHOENIX_TRIO32: case S3_DIAMOND_STEALTH_SE: @@ -4723,6 +5568,16 @@ static int s3_diamond_stealth64_964_available(void) return rom_present(ROM_DIAMOND_STEALTH64_964); } +static int s3_elsa_winner2000_pro_x_964_available(void) +{ + return rom_present(ROM_ELSAWIN2KPROX_964); +} + +static int s3_elsa_winner2000_pro_x_available(void) +{ + return rom_present(ROM_ELSAWIN2KPROX); +} + static int s3_phoenix_trio32_available(void) { return rom_present(ROM_PHOENIX_TRIO32); @@ -4855,7 +5710,7 @@ static const device_config_t s3_phoenix_trio32_config[] = } }; -static const device_config_t s3_phoenix_trio64_onboard_config[] = +static const device_config_t s3_standard_config[] = { { "memory", "Video memory size", CONFIG_SELECTION, "", 4, "", { 0 }, @@ -4879,7 +5734,7 @@ static const device_config_t s3_phoenix_trio64_onboard_config[] = } }; -static const device_config_t s3_config[] = +static const device_config_t s3_968_config[] = { { "memory", "Memory size", CONFIG_SELECTION, "", 4, "", { 0 }, @@ -4987,7 +5842,7 @@ const device_t s3_metheus_86c928_isa_device = { s3_metheus_86c928_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_metheus_86c928_vlb_device = @@ -5001,7 +5856,7 @@ const device_t s3_metheus_86c928_vlb_device = { s3_metheus_86c928_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_metheus_86c928_pci_device = @@ -5015,7 +5870,7 @@ const device_t s3_metheus_86c928_pci_device = { s3_metheus_86c928_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_bahamas64_vlb_device = @@ -5057,7 +5912,7 @@ const device_t s3_diamond_stealth64_964_vlb_device = { s3_diamond_stealth64_964_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_diamond_stealth64_964_pci_device = @@ -5071,7 +5926,7 @@ const device_t s3_diamond_stealth64_964_pci_device = { s3_diamond_stealth64_964_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_9fx_vlb_device = @@ -5170,7 +6025,7 @@ const device_t s3_phoenix_trio64_vlb_device = { s3_phoenix_trio64_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_phoenix_trio64_onboard_pci_device = @@ -5184,7 +6039,7 @@ const device_t s3_phoenix_trio64_onboard_pci_device = { NULL }, s3_speed_changed, s3_force_redraw, - s3_phoenix_trio64_onboard_config + s3_standard_config }; const device_t s3_phoenix_trio64_pci_device = @@ -5198,7 +6053,7 @@ const device_t s3_phoenix_trio64_pci_device = { s3_phoenix_trio64_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_phoenix_trio64vplus_vlb_device = @@ -5212,7 +6067,7 @@ const device_t s3_phoenix_trio64vplus_vlb_device = { s3_phoenix_trio64vplus_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_phoenix_trio64vplus_onboard_pci_device = @@ -5226,7 +6081,7 @@ const device_t s3_phoenix_trio64vplus_onboard_pci_device = { NULL }, s3_speed_changed, s3_force_redraw, - s3_phoenix_trio64_onboard_config + s3_standard_config }; const device_t s3_phoenix_trio64vplus_pci_device = @@ -5240,7 +6095,7 @@ const device_t s3_phoenix_trio64vplus_pci_device = { s3_phoenix_trio64vplus_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_phoenix_vision864_vlb_device = @@ -5254,7 +6109,7 @@ const device_t s3_phoenix_vision864_vlb_device = { s3_phoenix_vision864_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_phoenix_vision864_pci_device = @@ -5268,7 +6123,7 @@ const device_t s3_phoenix_vision864_pci_device = { s3_phoenix_vision864_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; const device_t s3_diamond_stealth64_vlb_device = @@ -5299,6 +6154,63 @@ const device_t s3_diamond_stealth64_pci_device = s3_9fx_config }; +const device_t s3_elsa_winner2000_pro_x_964_pci_device = +{ + "S3 Vision964 (ELSA Winner 2000 Pro/X) PCI", + DEVICE_PCI, + S3_ELSAWIN2KPROX_964, + s3_init, + s3_close, + NULL, + { s3_elsa_winner2000_pro_x_964_available }, + s3_speed_changed, + s3_force_redraw, + s3_968_config +}; + +const device_t s3_elsa_winner2000_pro_x_964_vlb_device = +{ + "S3 Vision964 (ELSA Winner 2000 Pro/X) VLB", + DEVICE_VLB, + S3_ELSAWIN2KPROX_964, + s3_init, + s3_close, + NULL, + { s3_elsa_winner2000_pro_x_964_available }, + s3_speed_changed, + s3_force_redraw, + s3_968_config +}; + +const device_t s3_elsa_winner2000_pro_x_pci_device = +{ + "S3 Vision968 (ELSA Winner 2000 Pro/X) PCI", + DEVICE_PCI, + S3_ELSAWIN2KPROX, + s3_init, + s3_close, + NULL, + { s3_elsa_winner2000_pro_x_available }, + s3_speed_changed, + s3_force_redraw, + s3_968_config +}; + +const device_t s3_elsa_winner2000_pro_x_vlb_device = +{ + "S3 Vision968 (ELSA Winner 2000 Pro/X) VLB", + DEVICE_VLB, + S3_ELSAWIN2KPROX, + s3_init, + s3_close, + NULL, + { s3_elsa_winner2000_pro_x_available }, + s3_speed_changed, + s3_force_redraw, + s3_968_config +}; + + const device_t s3_trio64v2_dx_pci_device = { "S3 Trio64V2/DX PCI", @@ -5310,5 +6222,6 @@ const device_t s3_trio64v2_dx_pci_device = { s3_trio64v2_dx_available }, s3_speed_changed, s3_force_redraw, - s3_config + s3_standard_config }; + diff --git a/src/video/vid_table.c b/src/video/vid_table.c index d675ab322..88304b797 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -129,6 +129,8 @@ video_cards[] = { { "stealth3d_3000_pci", &s3_virge_988_pci_device }, { "stealth64d_pci", &s3_diamond_stealth64_pci_device }, { "stealth64v_pci", &s3_diamond_stealth64_964_pci_device }, + { "elsawin2kprox_964_pci", &s3_elsa_winner2000_pro_x_964_pci_device }, + { "elsawin2kprox_pci", &s3_elsa_winner2000_pro_x_pci_device }, { "stealthse_pci", &s3_diamond_stealth_se_pci_device }, #if defined(DEV_BRANCH) && defined(USE_MGA) { "mystique", &mystique_device }, @@ -165,6 +167,8 @@ video_cards[] = { { "stealth3d_3000_vlb", &s3_virge_988_vlb_device }, { "stealth64d_vlb", &s3_diamond_stealth64_vlb_device }, { "stealth64v_vlb", &s3_diamond_stealth64_964_vlb_device }, + { "elsawin2kprox_964_vlb", &s3_elsa_winner2000_pro_x_964_vlb_device }, + { "elsawin2kprox_vlb", &s3_elsa_winner2000_pro_x_vlb_device }, { "stealthse_vlb", &s3_diamond_stealth_se_vlb_device }, { "metheus928_vlb", &s3_metheus_86c928_vlb_device }, { "n9_9fx_vlb", &s3_9fx_vlb_device }, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index c7cba0b80..9cf52250d 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -742,7 +742,7 @@ VIDOBJ := video.o \ vid_tgui9440.o vid_tkd8001_ramdac.o \ vid_att20c49x_ramdac.o \ vid_s3.o vid_s3_virge.o \ - vid_sdac_ramdac.o \ + vid_ibm_rgb525_ramdac.o vid_sdac_ramdac.o \ vid_voodoo.o vid_voodoo_banshee.o \ vid_voodoo_banshee_blitter.o \ vid_voodoo_blitter.o \