diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 183066911..0fd939908 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -268,6 +268,18 @@ typedef struct s3_t { int ssv_len; uint8_t ssv_dir; uint8_t ssv_draw; + uint8_t dat_buf_16bit; + uint8_t frgd_color_actual[2]; + uint8_t bkgd_color_actual[2]; + uint8_t wrt_mask_actual[2]; + uint8_t rd_mask_actual[2]; + uint8_t *pix_trans_ptr; + int pix_trans_ptr_cnt; + int pix_trans_x_count; + int pix_trans_x_count2; + int color_16bit_check; + int color_16bit_check_rectfill; + uint16_t minus, srcminus; /*For non-threaded FIFO*/ int setup_fifo_slot; @@ -365,6 +377,8 @@ typedef struct s3_t { void *i2c, *ddc; int vram; + + void (*accel_start)(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, void *priv); } s3_t; #define INT_VSY (1 << 0) @@ -475,7 +489,7 @@ s3_update_irqs(s3_t *s3) } } -void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3); +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, void *priv); void s3_short_stroke_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3, uint8_t ssv); static void s3_visionx68_video_engine_op(uint32_t cpu_dat, s3_t *s3); @@ -496,7 +510,7 @@ static void s3_visionx68_video_engine_op(uint32_t cpu_dat, s3_t *s3); } #define READ_PIXTRANS_BYTE_IO(n) \ - s3->accel.pix_trans[n] = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + n)) & s3->vram_mask]; + s3->accel.pix_trans[n] = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + n - s3->accel.minus)) & s3->vram_mask]; #define READ_PIXTRANS_BYTE_MM \ temp = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx)) & s3->vram_mask]; @@ -506,7 +520,7 @@ static void s3_visionx68_video_engine_op(uint32_t cpu_dat, s3_t *s3); temp = svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx)) & s3->vram_mask]; \ temp |= (svga->vram[dword_remap(svga, (s3->accel.dest + s3->accel.cx + 1)) & s3->vram_mask] << 8); \ } else { \ - temp = vram_w[dword_remap_w(svga, (s3->accel.dest + s3->accel.cx)) & (s3->vram_mask >> 1)]; \ + temp = vram_w[dword_remap_w(svga, (s3->accel.dest + s3->accel.cx - s3->accel.minus)) & (s3->vram_mask >> 1)]; \ } #define READ_PIXTRANS_LONG \ @@ -567,20 +581,29 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) const svga_t *svga = &s3->svga; if (s3->accel.cmd & 0x100) { + //pclog("S3 PIXTRANS_W write: cmd=%03x, pixelcntl=%02x, frgdmix=%02x, bkgdmix=%02x, curx=%d, val=%04x.\n", s3->accel.cmd, s3->accel.multifunc[0x0a], s3->accel.frgd_mix, s3->accel.bkgd_mix, s3->accel.cur_x, val); switch (s3->accel.cmd & 0x600) { case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); - s3_accel_start(8, 1, val | (val << 16), 0, s3); + s3->accel_start(8, 1, val | (val << 16), 0, s3); } else - s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + s3->accel_start(1, 1, 0xffffffff, val | (val << 16), s3); } else { - if (s3->color_16bit) - s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); - else - s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + if (s3->accel.color_16bit_check_rectfill) { + if (s3->accel.color_16bit_check) { + if (s3->accel.pix_trans_x_count < s3->accel.pix_trans_ptr_cnt) { + //pclog("Word: CPU data CMD=%04x, byte write=%02x, cnt=%d, check=%d.\n", s3->accel.cmd, val & 0xff, s3->accel.pix_trans_x_count, s3->accel.color_16bit_check); + s3->accel.pix_trans_ptr[s3->accel.pix_trans_x_count] = val & 0xff; + s3->accel.pix_trans_ptr[s3->accel.pix_trans_x_count + 1] = val >> 8; + s3->accel.pix_trans_x_count += 2; + } + } + break; + } + s3->accel_start(1, 1, 0xffffffff, val | (val << 16), s3); } break; case 0x200: @@ -588,11 +611,43 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); - s3_accel_start(16, 1, val | (val << 16), 0, s3); + s3->accel_start(16, 1, val | (val << 16), 0, s3); } else - s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); } else { - s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + if (s3->accel.color_16bit_check_rectfill) { + if (s3->accel.color_16bit_check) { + if (s3->accel.pix_trans_x_count < s3->accel.pix_trans_ptr_cnt) { + //pclog("Word: CPU data CMD=%04x, word write=%04x, cnt=%d, check=%d, totalptrcnt=%d.\n", s3->accel.cmd, val, s3->accel.pix_trans_x_count, s3->accel.color_16bit_check, s3->accel.pix_trans_ptr_cnt); + s3->accel.pix_trans_ptr[s3->accel.pix_trans_x_count] = val & 0xff; + s3->accel.pix_trans_ptr[s3->accel.pix_trans_x_count + 1] = val >> 8; + s3->accel.pix_trans_x_count += 2; + s3->accel.pix_trans_x_count2 = s3->accel.pix_trans_x_count; + } + } else { + if (s3->accel.pix_trans_x_count < s3->accel.pix_trans_ptr_cnt) { + //pclog("Word: CPU data CMD=%04x, word write=%04x, cnt=%d, check=%d, totalptrcnt=%d.\n", s3->accel.cmd, val, s3->accel.pix_trans_x_count, s3->accel.color_16bit_check, s3->accel.pix_trans_ptr_cnt); + s3->accel.pix_trans_ptr[s3->accel.pix_trans_x_count2] = val & 0xff; + s3->accel.pix_trans_ptr[s3->accel.pix_trans_x_count2 + 1] = val >> 8; + s3->accel.pix_trans_x_count += 2; + } + if (s3->accel.pix_trans_x_count2 == s3->accel.pix_trans_ptr_cnt) { + for (int i = 0; i < s3->accel.pix_trans_ptr_cnt; i += 2) { + //pclog("Transferring write count=%d, bytes=%08x.\n", i, s3->accel.pix_trans_ptr[i] | (s3->accel.pix_trans_ptr[i + 1] << 8) | (s3->accel.pix_trans_ptr[i + 2] << 16) | (s3->accel.pix_trans_ptr[i + 3] << 24)); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans_ptr[i] | (s3->accel.pix_trans_ptr[i + 1] << 8), s3); + } + + s3->accel.pix_trans_x_count2 = 0; + s3->accel.color_16bit_check_rectfill = 0; + if (s3->accel.pix_trans_ptr != NULL) { + free(s3->accel.pix_trans_ptr); + s3->accel.pix_trans_ptr = NULL; + } + } + } + break; + } + s3->accel_start(2, 1, 0xffffffff, val | (val << 16), s3); } break; case 0x400: @@ -601,21 +656,21 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); - s3_accel_start(32, 1, val | (val << 16), 0, s3); + s3->accel_start(32, 1, val | (val << 16), 0, s3); } else - s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3); + s3->accel_start(4, 1, 0xffffffff, val | (val << 16), s3); } else - s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3); + s3->accel_start(4, 1, 0xffffffff, val | (val << 16), s3); } else { if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); - s3_accel_start(16, 1, val | (val << 16), 0, s3); + s3->accel_start(16, 1, val | (val << 16), 0, s3); } else - s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3); + s3->accel_start(4, 1, 0xffffffff, val | (val << 16), s3); } else - s3_accel_start(4, 1, 0xffffffff, val | (val << 16), s3); + s3->accel_start(4, 1, 0xffffffff, val | (val << 16), s3); } break; case 0x600: @@ -624,8 +679,8 @@ s3_accel_out_pixtrans_w(s3_t *s3, uint16_t val) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); - s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); - s3_accel_start(8, 1, val & 0xff, 0, s3); + s3->accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3->accel_start(8, 1, val & 0xff, 0, s3); } } } @@ -647,15 +702,15 @@ s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); - s3_accel_start(8, 1, val, 0, s3); - s3_accel_start(8, 1, val >> 16, 0, s3); + s3->accel_start(8, 1, val, 0, s3); + s3->accel_start(8, 1, val >> 16, 0, s3); } else { - s3_accel_start(1, 1, 0xffffffff, val, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + s3->accel_start(1, 1, 0xffffffff, val, s3); + s3->accel_start(1, 1, 0xffffffff, val >> 16, s3); } } else { - s3_accel_start(1, 1, 0xffffffff, val, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + s3->accel_start(1, 1, 0xffffffff, val, s3); + s3->accel_start(1, 1, 0xffffffff, val >> 16, s3); } break; case 0x200: @@ -663,15 +718,15 @@ s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); - s3_accel_start(16, 1, val, 0, s3); - s3_accel_start(16, 1, val >> 16, 0, s3); + s3->accel_start(16, 1, val, 0, s3); + s3->accel_start(16, 1, val >> 16, 0, s3); } else { - s3_accel_start(2, 1, 0xffffffff, val, s3); - s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + s3->accel_start(2, 1, 0xffffffff, val, s3); + s3->accel_start(2, 1, 0xffffffff, val >> 16, s3); } } else { - s3_accel_start(2, 1, 0xffffffff, val, s3); - s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + s3->accel_start(2, 1, 0xffffffff, val, s3); + s3->accel_start(2, 1, 0xffffffff, val >> 16, s3); } break; case 0x400: @@ -679,11 +734,11 @@ s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { 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); + s3->accel_start(32, 1, val, 0, s3); } else - s3_accel_start(4, 1, 0xffffffff, val, s3); + s3->accel_start(4, 1, 0xffffffff, val, s3); } else - s3_accel_start(4, 1, 0xffffffff, val, s3); + s3->accel_start(4, 1, 0xffffffff, val, s3); break; case 0x600: if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868 || s3->chip >= S3_TRIO64V) { @@ -691,10 +746,10 @@ s3_accel_out_pixtrans_l(s3_t *s3, uint32_t val) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { 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); + 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); } } } @@ -854,7 +909,11 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0x9ae9: s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); s3->accel.ssv_state = 0; - s3_accel_start(-1, 0, 0xffffffff, 0, s3); + s3->accel_start(-1, 0, 0xffffffff, 0, s3); + if (s3->bpp == 3) { + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] &= ~0x10; + } break; case 0x994a: @@ -902,6 +961,11 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.bkgd_color = (s3->accel.bkgd_color & 0xffff00ff) | (val << 8); if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; + + if (s3->accel.color_16bit_check) + s3->accel.bkgd_color_actual[1] = s3->accel.bkgd_color & 0xff; + else + s3->accel.bkgd_color_actual[0] = s3->accel.bkgd_color & 0xff; break; case 0xa14a: case 0xa2ea: @@ -935,6 +999,11 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.frgd_color = (s3->accel.frgd_color & 0xffff00ff) | (val << 8); if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; + + if (s3->accel.color_16bit_check) + s3->accel.frgd_color_actual[1] = s3->accel.frgd_color & 0xff; + else + s3->accel.frgd_color_actual[0] = s3->accel.frgd_color & 0xff; break; case 0xa54a: case 0xa6ea: @@ -968,6 +1037,11 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.wrt_mask = (s3->accel.wrt_mask & 0xffff00ff) | (val << 8); if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; + + if (s3->accel.color_16bit_check) + s3->accel.wrt_mask_actual[1] = s3->accel.wrt_mask & 0xff; + else + s3->accel.wrt_mask_actual[0] = s3->accel.wrt_mask & 0xff; break; case 0xa94a: case 0xaaea: @@ -1172,14 +1246,42 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + s3->accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); } else { - if (s3->color_16bit) - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); - else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + if (s3->accel.color_16bit_check_rectfill) { + if (s3->accel.color_16bit_check) { + if (s3->accel.pix_trans_x_count < s3->accel.pix_trans_ptr_cnt) { + //pclog("Byte: CPU data CMD=%04x, byte write=%02x, cnt=%d, check=%d.\n", s3->accel.cmd, val, s3->accel.pix_trans_x_count, s3->accel.color_16bit_check); + s3->accel.pix_trans_ptr[s3->accel.pix_trans_x_count] = val; + s3->accel.pix_trans_x_count++; + s3->accel.pix_trans_x_count2 = s3->accel.pix_trans_x_count; + } + } else { + if (s3->accel.pix_trans_x_count2 < s3->accel.pix_trans_ptr_cnt) { + //pclog("Byte: CPU data CMD=%04x, byte write=%02x, cnt=%d, check=%d.\n", s3->accel.cmd, val, s3->accel.pix_trans_x_count2, s3->accel.color_16bit_check); + s3->accel.pix_trans_ptr[s3->accel.pix_trans_x_count2] = val; + s3->accel.pix_trans_x_count2++; + } + //pclog("WriteCNT=%d, TotalCNT=%d.\n", s3->accel.pix_trans_x_count2, s3->accel.pix_trans_ptr_cnt); + if (s3->accel.pix_trans_x_count2 == s3->accel.pix_trans_ptr_cnt) { + for (int i = 0; i < s3->accel.pix_trans_ptr_cnt; i += 2) { + //pclog("Transferring write count=%d, bytes=%04x.\n", i, s3->accel.pix_trans_ptr[i] | (s3->accel.pix_trans_ptr[i + 1] << 8)); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans_ptr[i] | (s3->accel.pix_trans_ptr[i + 1] << 8), s3); + } + + s3->accel.pix_trans_x_count2 = 0; + s3->accel.color_16bit_check_rectfill = 0; + if (s3->accel.pix_trans_ptr != NULL) { + free(s3->accel.pix_trans_ptr); + s3->accel.pix_trans_ptr = NULL; + } + } + } + break; + } + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); } break; @@ -1195,63 +1297,54 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) break; s3->accel.pix_trans[1] = val; if (s3->accel.cmd & 0x100) { + //pclog("S3 PIXTRANS_B write (E2E9): cmd=%03x, pixelcntl=%02x, frgdmix=%02x, bkgdmix=%02x, curx=%d, val=%04x.\n", s3->accel.cmd, s3->accel.multifunc[0x0a], s3->accel.frgd_mix, s3->accel.bkgd_mix, s3->accel.cur_x, val); switch (s3->accel.cmd & 0x600) { case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + s3->accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); - } else { - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); - } + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } else + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); break; case 0x200: - /*Windows 95's built-in driver expects this to be loaded regardless of the byte swap bit (0xE2E9) in the 86c928 ISA/VLB*/ if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) - s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); + s3->accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); else - s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); - } else { - if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) { - s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8)); - } else { - if (s3->accel.cmd & 0x1000) - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); - else - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); - } - } - } else { - if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) { - s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8)); + s3->accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); } else { if (s3->accel.cmd & 0x1000) - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); else - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); } + } else { + if (s3->accel.cmd & 0x1000) + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else + 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) { if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - 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); else - 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); } else - 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; case 0x600: if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868 || s3->chip >= S3_TRIO64V) { if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { - s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); - s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + s3->accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); + s3->accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); } } } @@ -1279,58 +1372,49 @@ s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 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); + s3->accel_start(8, 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); else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); } else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); break; case 0x200: - /*Windows 95's built-in driver expects the upper 16 bits to be loaded instead of the whole 32-bit one, regardless of the byte swap bit (0xE2EB) in the 86c928 ISA/VLB card*/ if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) - s3_accel_start(16, 1, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), 0, s3); + s3->accel_start(16, 1, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), 0, s3); else - s3_accel_start(16, 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); - } else { - if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) { - s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[2] | (s3->accel.pix_trans[3] << 8)); - } else { - if (s3->accel.cmd & 0x1000) - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), s3); - else - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); - } - } - } else { - if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) { - s3_accel_out_pixtrans_w(s3, s3->accel.pix_trans[2] | (s3->accel.pix_trans[3] << 8)); + s3->accel_start(16, 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); } else { if (s3->accel.cmd & 0x1000) - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), s3); else - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); } + } else { + if (s3->accel.cmd & 0x1000) + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[3] | (s3->accel.pix_trans[2] << 8) | (s3->accel.pix_trans[1] << 16) | (s3->accel.pix_trans[0] << 24), s3); + else + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); } break; case 0x400: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - 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); + 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); else - s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + s3->accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); } else - s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + s3->accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); break; case 0x600: if (s3->chip == S3_TRIO32 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868 || s3->chip >= S3_TRIO64V) { if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { - 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); - s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + 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); + s3->accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); } } } @@ -1377,11 +1461,10 @@ s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) { - if (port == 0xb2e8 || port == 0xb148) { + if (port == 0xb2e8 || port == 0xb148) s3->accel.b2e8_pix = 1; - } else { + else s3->accel.b2e8_pix = 0; - } s3_accel_out_pixtrans_l(s3, val); } @@ -1552,11 +1635,11 @@ s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) if (s3->accel.cmd & 0x100) { if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + s3->accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); else - s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + s3->accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); } else - s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + s3->accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); } } else { switch (addr & 0x1ffff) { @@ -1633,7 +1716,7 @@ s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) } } else { if (addr & 0x8000) { - if ((addr == 0xe2e8) || (addr == 0xe2e9)) { + if ((addr == 0xe2e8) || (addr == 0xe2e9) || (addr == 0xe2ea) || (addr == 0xe2eb)) { if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) goto mmio_byte_write; else @@ -1646,19 +1729,19 @@ mmio_byte_write: if ((s3->accel.cmd & 0x600) == 0x200) { if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(16, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + s3->accel_start(16, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); else - s3_accel_start(2, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + s3->accel_start(2, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); } else - s3_accel_start(2, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + s3->accel_start(2, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); } else { if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + s3->accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); else - s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + s3->accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); } else - s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + s3->accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); } } } @@ -1909,7 +1992,7 @@ s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) } else { if (addr & 0x8000) { if (addr == 0xe2e8) { - if (s3->chip == S3_86C928 || s3->chip == S3_86C928PCI) + if ((s3->chip == S3_86C928) || (s3->chip == S3_86C928PCI)) s3_accel_out_pixtrans_l(s3, val); else { s3_accel_write_fifo(s3, addr, val); @@ -1984,7 +2067,7 @@ s3_hwcursor_draw(svga_t *svga, int displine) fg = video_16to32[s3->hwc_fg_col & 0xffff]; bg = video_16to32[s3->hwc_bg_col & 0xffff]; if (s3->chip >= S3_86C928 && s3->chip <= S3_86C805) { - if (s3->card_type != S3_MIROCRYSTAL10SD_805 && s3->card_type != S3_MIROCRYSTAL8S_805) { + if ((s3->card_type != S3_MIROCRYSTAL10SD_805) && (s3->card_type != S3_MIROCRYSTAL8S_805)) { if (!(svga->crtc[0x45] & 0x04)) { shift = 2; width = 8; @@ -1998,8 +2081,13 @@ s3_hwcursor_draw(svga_t *svga, int displine) break; case 24: - fg = s3->hwc_fg_col; - bg = s3->hwc_bg_col; + if (s3->chip <= S3_86C805) { + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; + } else { + fg = s3->hwc_fg_col; + bg = s3->hwc_bg_col; + } break; case 32: @@ -2519,7 +2607,6 @@ s3_out(uint16_t addr, uint8_t val, void *priv) s3_t *s3 = (s3_t *) priv; svga_t *svga = &s3->svga; uint8_t old; - uint8_t mask; int rs2; int rs3; @@ -2590,9 +2677,10 @@ s3_out(uint16_t addr, uint8_t val, void *priv) else if (s3->chip == S3_VISION968 && (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_MIROVIDEO40SV_ERGO_968)) { rs3 = !!(svga->crtc[0x55] & 0x02); tvp3026_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); - } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) && (s3->card_type != S3_MIROCRYSTAL10SD_805 && s3->card_type != S3_MIROCRYSTAL8S_805)) + } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805) || (s3->chip == S3_86C924)) && + ((s3->card_type != S3_MIROCRYSTAL10SD_805) && (s3->card_type != S3_MIROCRYSTAL8S_805))) att49x_ramdac_out(addr, rs2, val, svga->ramdac, svga); - else if (s3->chip <= S3_86C924) { + else if (s3->chip == S3_86C911) { sc1148x_ramdac_out(addr, rs2, val, svga->ramdac, svga); } else if (s3->card_type == S3_NUMBER9_9FX_531) att498_ramdac_out(addr, rs2, val, svga->ramdac, svga); @@ -2631,6 +2719,8 @@ s3_out(uint16_t addr, uint8_t val, void *priv) break; case 0x32: svga->vram_display_mask = (val & 0x40) ? 0x3ffff : s3->vram_mask; + if (s3->color_16bit) + svga->vram_display_mask = s3->vram_mask; break; case 0x40: @@ -2638,32 +2728,6 @@ s3_out(uint16_t addr, uint8_t val, void *priv) break; case 0x50: - mask = 0xc0; - if (s3->chip != S3_86C801) - mask |= 0x01; - switch (svga->crtc[0x50] & mask) { - 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 = ((s3->chip > S3_86C805) && (s3->accel.advfunc_cntl & 4)) ? 1600 : 800; - break; - case 0x81: - s3->width = 1600; - break; - case 0xc0: - s3->width = 1280; - break; - - default: - break; - } s3->bpp = (svga->crtc[0x50] >> 4) & 3; break; @@ -2747,6 +2811,8 @@ s3_out(uint16_t addr, uint8_t val, void *priv) svga->hwcursor.x >>= 1; } else if ((s3->chip >= S3_86C928 && s3->chip <= S3_86C805) && (svga->bpp == 24)) svga->hwcursor.x /= 3; + else if ((s3->chip <= S3_86C805) && s3->color_16bit) + svga->hwcursor.x >>= 1; break; case 0x4a: @@ -2793,7 +2859,7 @@ s3_out(uint16_t addr, uint8_t val, void *priv) case 0x55: if (s3->chip == S3_86C928) { - if ((val & 0x08) || ((val & 0x20) == 0x20)) { + if (val & 0x28) { svga->hwcursor_draw = NULL; svga->dac_hwcursor_draw = bt48x_hwcursor_draw; } else { @@ -2812,6 +2878,21 @@ s3_out(uint16_t addr, uint8_t val, void *priv) case 0x43: if (s3->chip < S3_VISION964) { + if (s3->chip <= S3_86C805) { + s3->color_16bit = !!(val & 8); + if (s3->color_16bit) { + s3->width = 1024; + } else { + if (s3->chip <= S3_86C924) + s3->width = 1024; + else { + if (s3->accel.advfunc_cntl & 4) + s3->width = 1024; + else + s3->width = 640; + } + } + } s3_io_remove_alt(s3); s3->translate = !!(val & 0x10); s3_io_set_alt(s3); @@ -2912,16 +2993,21 @@ s3_in(uint16_t addr, void *priv) if (s3->chip >= S3_TRIO32) return svga_in(addr, svga); 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); + if (s3->chip == S3_86C928) + rs3 = !!(svga->crtc[0x55] & 0x28) || !!(svga->crtc[0x45] & 0x20) || !!(svga->crtc[0x55] & 0x02); /*Quite insane but Win95's S3 driver wants it set at all costs for 8bpp+ mode*/ + else + rs3 = !!(svga->crtc[0x55] & 0x02); + temp = bt48x_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); + return temp; } else if ((s3->chip == S3_VISION964 && s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->chip == S3_VISION968 && (s3->card_type == S3_ELSAWIN2KPROX || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_NUMBER9_9FX_771))) return ibm_rgb528_ramdac_in(addr, rs2, svga->ramdac, svga); else if (s3->chip == S3_VISION968 && (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_MIROVIDEO40SV_ERGO_968)) { rs3 = !!(svga->crtc[0x55] & 0x02); return tvp3026_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); - } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805)) && (s3->card_type != S3_MIROCRYSTAL10SD_805 && s3->card_type != S3_MIROCRYSTAL8S_805)) + } else if (((s3->chip == S3_86C801) || (s3->chip == S3_86C805) || (s3->chip == S3_86C924)) && + ((s3->card_type != S3_MIROCRYSTAL10SD_805) && (s3->card_type != S3_MIROCRYSTAL8S_805))) return att49x_ramdac_in(addr, rs2, svga->ramdac, svga); - else if (s3->chip <= S3_86C924) + else if (s3->chip == S3_86C911) return sc1148x_ramdac_in(addr, rs2, svga->ramdac, svga); else if (s3->card_type == S3_NUMBER9_9FX_531) return att498_ramdac_in(addr, rs2, svga->ramdac, svga); @@ -2945,7 +3031,8 @@ s3_in(uint16_t addr, void *priv) return 0x16; /*Confirmed on an onboard 64V2/DX*/ default: return 0x00; - } + } + break; case 0x30: return s3->id; /*Chip ID*/ case 0x31: @@ -2954,7 +3041,7 @@ s3_in(uint16_t addr, void *priv) return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); case 0x45: s3->hwc_col_stack_pos = 0; - break; + return svga->crtc[0x45]; case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3); case 0x5c: /* General Output Port Register */ @@ -2985,6 +3072,7 @@ s3_in(uint16_t addr, void *priv) } } else return svga->crtc[0x6b]; + break; case 0x6c: if (s3->chip != S3_TRIO64V2) { if (svga->crtc[0x53] & 0x08) { @@ -2993,6 +3081,7 @@ s3_in(uint16_t addr, void *priv) return (svga->crtc[0x5a] & 0x80); } else return svga->crtc[0x6c]; + break; default: break; @@ -3010,11 +3099,13 @@ s3_recalctimings(svga_t *svga) { s3_t *s3 = (s3_t *) svga->priv; int clk_sel = (svga->miscout >> 2) & 3; + uint8_t mask = 0xc0; if (!svga->scrblank && svga->attr_palette_enable) { if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { if (svga->crtc[0x3a] & 0x10) { /*256+ color register*/ svga->gdcreg[5] |= 0x40; + svga->attrregs[0x10] |= 0x40; } } } @@ -3027,7 +3118,7 @@ s3_recalctimings(svga_t *svga) svga->htotal |= 0x100; if (svga->crtc[0x5d] & 0x02) { svga->hdisp_time |= 0x100; - svga->hdisp |= 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + svga->hdisp |= (0x100 * ((svga->seqregs[1] & 8) ? 16 : 8)); } if (svga->crtc[0x5e] & 0x01) svga->vtotal |= 0x400; @@ -3035,6 +3126,8 @@ s3_recalctimings(svga_t *svga) svga->dispend |= 0x400; if (svga->crtc[0x5e] & 0x04) svga->vblankstart |= 0x400; + else + svga->vblankstart = svga->dispend; if (svga->crtc[0x5e] & 0x10) svga->vsyncstart |= 0x400; if (svga->crtc[0x5e] & 0x40) @@ -3052,17 +3145,19 @@ s3_recalctimings(svga_t *svga) if ((s3->chip == S3_VISION964) || (s3->chip == S3_86C928)) { if (s3->card_type == S3_ELSAWIN2KPROX_964) ibm_rgb528_recalctimings(svga->ramdac, svga); - else + else { bt48x_recalctimings(svga->ramdac, svga); + svga->interlace |= (!!(svga->crtc[0x42] & 0x20)); + } } else if (s3->chip == S3_VISION968) { - if (s3->card_type == S3_SPEA_MERCURY_P64V || s3->card_type == S3_MIROVIDEO40SV_ERGO_968) + if ((s3->card_type == S3_SPEA_MERCURY_P64V) || (s3->card_type == S3_MIROVIDEO40SV_ERGO_968)) tvp3026_recalctimings(svga->ramdac, svga); else ibm_rgb528_recalctimings(svga->ramdac, svga); } else svga->interlace = !!(svga->crtc[0x42] & 0x20); - if ((((svga->miscout >> 2) & 3) == 3) && s3->chip < S3_TRIO32) + if ((((svga->miscout >> 2) & 3) == 3) && (s3->chip < S3_TRIO32)) clk_sel = svga->crtc[0x42] & 0x0f; svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clk_sel, svga->clock_gen); @@ -3080,11 +3175,41 @@ s3_recalctimings(svga_t *svga) svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); + if (s3->chip != S3_86C801) + mask |= 0x01; + switch (svga->crtc[0x50] & mask) { + case 0x00: + if (s3->color_16bit) + s3->width = 1024; + else + 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 = ((s3->chip > S3_86C805) && (s3->accel.advfunc_cntl & 4)) ? 1600 : 800; + break; + case 0x81: + s3->width = 1600; + break; + case 0xc0: + s3->width = 1280; + break; + + default: + break; + } + +#ifdef OLD_CODE_REFERENCE if (s3->card_type == S3_MIROCRYSTAL10SD_805 || s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_MIROCRYSTAL20SV_964 || s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_MIROCRYSTAL8S_805 || s3->card_type == S3_NUMBER9_9FX_531 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI) { if (!(svga->crtc[0x5e] & 0x04)) svga->vblankstart = svga->dispend; if (svga->bpp != 32) { - if (svga->crtc[0x31] & 2) /*This is needed if the pixel width gets set with delays*/ + if (svga->crtc[0x31] & 2) s3->width = 2048; else { if (s3->card_type == S3_MIROCRYSTAL10SD_805) { @@ -3105,24 +3230,96 @@ s3_recalctimings(svga_t *svga) s3->width = 1024; } } - - if ((svga->crtc[0x43] & 0x08) && !s3->color_16bit && (s3->chip <= S3_86C805)) { - s3->color_16bit = 1; - s3->width = 1024; - } else if (!(svga->crtc[0x43] & 0x08) && s3->color_16bit && (s3->chip <= S3_86C805)) { - s3->color_16bit = 0; - if (s3->chip <= S3_86C924) { - if (s3->accel.advfunc_cntl & 4) - s3->width = 1024; - else - s3->width = 640; - } - } +#endif if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) { + //pclog("BPP=%d, pitch=%d, width=%02x, double?=%x, 16bit?=%d, highres?=%d, attr=%02x.\n", svga->bpp, s3->width, svga->crtc[0x50], svga->crtc[0x31] & 0x02, s3->color_16bit, s3->accel.advfunc_cntl & 4, svga->attrregs[0x10] & 0x40); switch (svga->bpp) { case 8: svga->render = svga_render_8bpp_highres; + switch (s3->chip) { + case S3_86C928: + switch (s3->card_type) { + case S3_METHEUS_86C928: + switch (s3->width) { + case 1280: + svga->hdisp <<= 1; + break; + case 2048: /*Account for the 1280x1024 resolution*/ + switch (svga->hdisp) { + case 320: + svga->hdisp <<= 2; + break; + case 640: + svga->hdisp <<= 1; + break; + default: + break; + } + break; + default: + break; + } + break; + + default: + break; + } + break; + case S3_86C928PCI: + switch (s3->card_type) { + case S3_SPEA_MERCURY_LITE_PCI: + switch (s3->width) { + case 640: + svga->hdisp >>= 1; + break; + default: + break; + } + break; + + default: + break; + } + break; + case S3_VISION964: + switch (s3->card_type) { + case S3_ELSAWIN2KPROX_964: + svga->hdisp <<= 1; + break; + + default: + break; + } + break; + case S3_VISION968: + switch (s3->card_type) { + case S3_NUMBER9_9FX_771: + case S3_SPEA_MERCURY_P64V: + case S3_ELSAWIN2KPROX: + case S3_PHOENIX_VISION968: + svga->hdisp <<= 1; + break; + case S3_MIROVIDEO40SV_ERGO_968: + switch (s3->width) { + case 1152: + case 1280: + svga->hdisp <<= 1; + break; + default: + break; + } + break; + + default: + break; + } + break; + + default: + break; + } +#ifdef OLD_CODE_REFERENCE if (s3->chip != S3_VISION868) { if (s3->chip == S3_86C928) { if (s3->width == 2048 || s3->width == 1280 || s3->width == 1600) { @@ -3142,55 +3339,128 @@ s3_recalctimings(svga_t *svga) svga->hdisp <<= 1; } else if (s3->card_type == S3_NUMBER9_9FX_771) svga->hdisp <<= 1; - - if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_MIROCRYSTAL20SD_864 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) { - if (svga->hdisp != 1408) - svga->hdisp = s3->width; - if (s3->card_type == S3_MIROCRYSTAL20SD_864) { - if (s3->width == 2048 || s3->width == 1600 || s3->width == 800) { - switch (svga->dispend) { - case 400: - case 480: - svga->hdisp = 640; - break; - - case 576: - svga->hdisp = 768; - break; - - case 600: - if (s3->width == 1600) - s3->width = 800; - svga->hdisp = 800; - break; - - case 768: - svga->hdisp = 1024; - break; - - case 864: - svga->hdisp = 1152; - break; - - case 1024: - if (svga->vtotal == 1066) - svga->hdisp = 1280; - break; - - default: - break; - } - } - } - } - if (s3->card_type == S3_MIROCRYSTAL10SD_805 || s3->card_type == S3_MIROCRYSTAL8S_805) { - if (svga->rowoffset == 256 && ((svga->crtc[0x51] & 0x30) == 0x00 && !(svga->crtc[0x43] & 0x04))) - svga->rowoffset >>= 1; - } } +#endif break; case 15: svga->render = svga_render_15bpp_highres; + switch (s3->chip) { + case S3_86C911: + case S3_86C924: + svga->hdisp >>= 1; + break; + + case S3_86C801: + switch (s3->card_type) { + case S3_PHOENIX_86C801: + svga->hdisp >>= 1; + break; + + default: + break; + } + break; + case S3_86C805: + switch (s3->card_type) { + case S3_MIROCRYSTAL8S_805: + case S3_MIROCRYSTAL10SD_805: + case S3_PHOENIX_86C805: + case S3_86C805_ONBOARD: + svga->hdisp >>= 1; + break; + + case S3_SPEA_MIRAGE_86C805: + svga->hdisp >>= 1; + switch (s3->width) { + case 800: + case 1024: + if (svga->hdisp == 400) /*SPEA specific drivers + its VBE RAM BIOS...*/ + svga->hdisp <<= 1; + break; + default: + break; + } + break; + + default: + break; + } + break; + case S3_86C928: + switch (s3->card_type) { + case S3_METHEUS_86C928: + if (!s3->color_16bit) + svga->hdisp <<= 1; + switch (svga->hdisp) { /*This might be a driver issue*/ + case 800: + s3->width = 1024; + break; + case 1280: + s3->width = 2048; + break; + default: + break; + } + break; + + default: + break; + } + break; + case S3_86C928PCI: + switch (s3->card_type) { + case S3_SPEA_MERCURY_LITE_PCI: + switch (s3->width) { + case 640: + svga->hdisp >>= 1; + break; + default: + break; + } + break; + + default: + break; + } + break; + case S3_VISION864: + switch (s3->card_type) { + case S3_MIROCRYSTAL20SD_864: + svga->hdisp >>= 1; + break; + + default: + break; + } + break; + case S3_VISION868: + switch (s3->card_type) { + case S3_PHOENIX_VISION868: + case S3_NUMBER9_9FX_531: + svga->hdisp >>= 1; + break; + + default: + break; + } + break; + case S3_VISION968: + switch (s3->card_type) { + case S3_NUMBER9_9FX_771: + case S3_PHOENIX_VISION968: + svga->hdisp <<= 1; + if (svga->hdisp == 832) + svga->hdisp -= 32; + break; + + default: + break; + } + break; + default: + break; + } +#ifdef OLD_CODE_REFERENCE if ((s3->chip != S3_VISION964) && (s3->card_type != S3_SPEA_MIRAGE_86C801) && (s3->card_type != S3_SPEA_MIRAGE_86C805)) { if (s3->chip == S3_86C928) svga->hdisp <<= 1; @@ -3212,9 +3482,127 @@ s3_recalctimings(svga_t *svga) if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI) svga->hdisp = s3->width; +#endif break; case 16: svga->render = svga_render_16bpp_highres; + switch (s3->chip) { + case S3_86C911: + case S3_86C924: + svga->hdisp >>= 1; + break; + + case S3_86C801: + switch (s3->card_type) { + case S3_PHOENIX_86C801: + svga->hdisp >>= 1; + break; + + default: + break; + } + break; + case S3_86C805: + switch (s3->card_type) { + case S3_MIROCRYSTAL8S_805: + case S3_MIROCRYSTAL10SD_805: + case S3_PHOENIX_86C805: + case S3_86C805_ONBOARD: + svga->hdisp >>= 1; + break; + + case S3_SPEA_MIRAGE_86C805: + svga->hdisp >>= 1; + switch (s3->width) { + case 800: + case 1024: + if (svga->hdisp == 400) /*SPEA specific drivers + its VBE RAM BIOS...*/ + svga->hdisp <<= 1; + break; + default: + break; + } + break; + + default: + break; + } + break; + case S3_86C928: + switch (s3->card_type) { + case S3_METHEUS_86C928: + svga->hdisp <<= 1; + switch (svga->hdisp) { /*This might be a driver issue*/ + case 800: + s3->width = 1024; + break; + case 1280: + s3->width = 2048; + break; + default: + break; + } + break; + + default: + break; + } + break; + case S3_86C928PCI: + switch (s3->card_type) { + case S3_SPEA_MERCURY_LITE_PCI: + switch (s3->width) { + case 640: + svga->hdisp >>= 1; + break; + default: + break; + } + break; + + default: + break; + } + break; + case S3_VISION864: + switch (s3->card_type) { + case S3_MIROCRYSTAL20SD_864: + svga->hdisp >>= 1; + break; + + default: + break; + } + break; + case S3_VISION868: + switch (s3->card_type) { + case S3_PHOENIX_VISION868: + case S3_NUMBER9_9FX_531: + svga->hdisp >>= 1; + break; + + default: + break; + } + break; + case S3_VISION968: + switch (s3->card_type) { + case S3_NUMBER9_9FX_771: + case S3_PHOENIX_VISION968: + svga->hdisp <<= 1; + if (svga->hdisp == 832) + svga->hdisp -= 32; + break; + + default: + break; + } + break; + default: + break; + } + +#ifdef OLD_CODE_REFERENCE if ((s3->card_type == S3_ELSAWIN2KPROX_964) || (s3->card_type == S3_ELSAWIN2KPROX)) { if (s3->width == 1280 || s3->width == 1600) svga->hdisp <<= 1; @@ -3233,7 +3621,7 @@ s3_recalctimings(svga_t *svga) svga->hdisp <<= 1; } if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) { - if (svga->hdisp == (1408 * 2)) + if (svga->hdisp == (1408 << 1)) svga->hdisp >>= 1; else svga->hdisp = s3->width; @@ -3241,9 +3629,85 @@ s3_recalctimings(svga_t *svga) if (s3->card_type == S3_SPEA_MIRAGE_86C801 || s3->card_type == S3_SPEA_MIRAGE_86C805 || s3->card_type == S3_SPEA_MERCURY_LITE_PCI) svga->hdisp = s3->width; +#endif break; case 24: svga->render = svga_render_24bpp_highres; + switch (s3->chip) { + case S3_86C924: + switch (s3->card_type) { + case S3_AMI_86C924: + svga->hdisp = (svga->hdisp << 1) / 3; + if (svga->hdisp == 645) + svga->hdisp -= 5; + break; + default: + break; + } + break; + case S3_86C801: + switch (s3->card_type) { + case S3_PHOENIX_86C801: + case S3_SPEA_MIRAGE_86C801: + svga->hdisp = (svga->hdisp << 1) / 3; + break; + default: + break; + } + break; + case S3_86C805: + switch (s3->card_type) { + case S3_MIROCRYSTAL8S_805: + case S3_MIROCRYSTAL10SD_805: + case S3_PHOENIX_86C805: + case S3_SPEA_MIRAGE_86C805: + case S3_86C805_ONBOARD: + svga->hdisp = (svga->hdisp << 1) / 3; + break; + default: + break; + } + break; + case S3_86C928PCI: + switch (s3->card_type) { + case S3_SPEA_MERCURY_LITE_PCI: + svga->hdisp = (svga->hdisp << 1) / 3; + break; + default: + break; + } + break; + case S3_VISION864: + switch (s3->card_type) { + case S3_MIROCRYSTAL20SD_864: + svga->hdisp = (svga->hdisp << 1) / 3; + break; + default: + break; + } + break; + case S3_VISION968: + switch (s3->card_type) { + case S3_MIROVIDEO40SV_ERGO_968: + switch (s3->width) { + case 1280: + svga->hdisp = (svga->hdisp << 1) / 3; + svga->hdisp <<= 1; + break; + default: + break; + } + break; + + default: + break; + } + break; + + default: + break; + } +#ifdef OLD_CODE_REFERENCE if (s3->chip != S3_VISION968) { if (s3->chip != S3_86C928 && s3->chip != S3_86C801 && s3->chip != S3_86C805) svga->hdisp /= 3; @@ -3251,7 +3715,7 @@ s3_recalctimings(svga_t *svga) svga->hdisp = (svga->hdisp * 2) / 3; if (s3->card_type == S3_SPEA_MERCURY_LITE_PCI) { - if (s3->width == 2048) + if (s3->width == 2048) { switch (svga->dispend) { case 480: svga->hdisp = 640; @@ -3260,14 +3724,63 @@ s3_recalctimings(svga_t *svga) default: break; } + } + } else if (s3->chip == S3_86C924) { + if (svga->dispend == 480) + svga->hdisp = 640; } } else { if (s3->card_type == S3_MIROVIDEO40SV_ERGO_968 || s3->card_type == S3_PHOENIX_VISION968 || s3->card_type == S3_SPEA_MERCURY_P64V) svga->hdisp = s3->width; } +#endif break; case 32: svga->render = svga_render_32bpp_highres; + switch (s3->chip) { + case S3_VISION868: + switch (s3->card_type) { + case S3_PHOENIX_VISION868: + case S3_NUMBER9_9FX_531: + svga->hdisp >>= 1; + break; + default: + break; + } + break; + case S3_VISION964: + switch (s3->card_type) { + case S3_MIROCRYSTAL20SV_964: + switch (s3->width) { + case 800: + case 1024: + svga->hdisp >>= 1; + break; + default: + break; + } + break; + default: + break; + } + break; + case S3_VISION968: + switch (s3->card_type) { + case S3_NUMBER9_9FX_771: + case S3_PHOENIX_VISION968: + svga->hdisp <<= 1; + if (svga->hdisp == 832) + svga->hdisp -= 32; + break; + default: + break; + } + break; + + default: + break; + } +#ifdef OLD_CODE_REFERENCE if ((s3->chip < S3_TRIO32) && (s3->chip != S3_VISION964) && (s3->chip != S3_VISION968) && (s3->chip != S3_86C928)) { if (s3->chip == S3_VISION868) svga->hdisp >>= 1; @@ -3308,24 +3821,21 @@ s3_recalctimings(svga_t *svga) } } } +#endif break; default: break; } } else { - if (!svga->scrblank && svga->attr_palette_enable) { + if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) { if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { - if ((svga->crtc[0x31] & 0x08) && ((svga->gdcreg[5] & 0x60) == 0x00)) { + if ((svga->crtc[0x31] & 0x08) && (svga->attrregs[0x10] & 0x40) == 0x00) { if (svga->bpp == 8) { svga->render = svga_render_8bpp_highres; /*Enhanced 4bpp mode, just like the 8bpp mode per spec.*/ - if (svga->hdisp <= 1024) - s3->width = 1024; + svga->rowoffset <<= 1; } } - } else { - if (s3->chip <= S3_86C924) - s3->width = 1024; } } } @@ -3334,13 +3844,15 @@ s3_recalctimings(svga_t *svga) static void s3_trio64v_recalctimings(svga_t *svga) { - const s3_t *s3 = (s3_t *) svga->priv; + s3_t *s3 = (s3_t *) svga->priv; int clk_sel = (svga->miscout >> 2) & 3; if (!svga->scrblank && svga->attr_palette_enable) { if ((svga->gdcreg[6] & 1) || (svga->attrregs[0x10] & 1)) { - if (svga->crtc[0x3a] & 0x10) /*256+ color register*/ + if (svga->crtc[0x3a] & 0x10) { /*256+ color register*/ svga->gdcreg[5] |= 0x40; + svga->attrregs[0x10] |= 0x40; + } } } svga->hdisp = svga->hdisp_old; @@ -3364,6 +3876,30 @@ s3_trio64v_recalctimings(svga_t *svga) svga->clock = (cpuclock * (double) (1ULL << 32)) / svga->getclock(clk_sel, svga->clock_gen); + switch (svga->crtc[0x50] & 0xc1) { + 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 = (s3->accel.advfunc_cntl & 4) ? 1600 : 800; + break; + case 0x81: + s3->width = 1600; + break; + case 0xc0: + s3->width = 1280; + break; + + default: + break; + } + if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ { svga->ma_latch |= (s3->ma_ext << 16); @@ -3542,11 +4078,10 @@ s3_updatemapping(s3_t *s3) svga->banked_mask = 0xffff; } } else { - if (s3->chip >= S3_TRIO64V) { + if (s3->chip >= S3_TRIO64V) s3->linear_base &= 0xfc000000; - } else if (s3->chip == S3_VISION968 || s3->chip == S3_VISION868) { + else if ((s3->chip == S3_VISION968) || (s3->chip == S3_VISION868)) s3->linear_base &= 0xfe000000; - } mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); } @@ -3640,8 +4175,7 @@ s3_accel_out(uint16_t port, uint8_t val, void *priv) svga->fullchange = svga->monitor->mon_changeframecount; svga_recalctimings(svga); } - if (s3->chip > S3_86C924) - s3_updatemapping(s3); + s3_updatemapping(s3); break; default: @@ -3802,6 +4336,7 @@ s3_accel_in(uint16_t port, void *priv) temp |= 0x02; /*Hardware busy*/ else temp |= 0x04; /*FIFO empty*/ + s3->force_busy = 0; if (s3->chip >= S3_VISION964) { @@ -3814,9 +4349,30 @@ s3_accel_in(uint16_t port, void *priv) s3->data_available = 0; } } else { - if (s3->force_busy) { + if (s3->force_busy) temp |= 0x02; /*Hardware busy*/ + else { + switch (s3->accel.cmd >> 13) { /*Some drivers may not set FIFO on but may still turn on FIFO empty bits!*/ + case 0: + if (!s3->accel.ssv_len) + temp |= 0x04; + break; + case 1: + if (!s3->accel.sy) + temp |= 0x04; + break; + case 2: + case 6: + case 7: + if (s3->accel.sy < 0) + temp |= 0x04; + break; + + default: + break; + } } + s3->force_busy = 0; if (s3->data_available) { temp |= 0x01; /*Read Data available*/ @@ -4330,21 +4886,20 @@ s3_accel_in(uint16_t port, void *priv) case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + s3->accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); } else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); break; case 0x200: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(16, 1, s3->accel.pix_trans[0], 0, s3); + s3->accel_start(16, 1, s3->accel.pix_trans[0], 0, s3); else - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); - } else { - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); - } + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + } else + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0], s3); break; default: @@ -4363,30 +4918,30 @@ s3_accel_in(uint16_t port, void *priv) case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + s3->accel_start(8, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); } else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); break; case 0x200: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) - s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); + s3->accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); else - s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + s3->accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); } else { if (s3->accel.cmd & 0x1000) - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); else - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); } } else { if (s3->accel.cmd & 0x1000) - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); else - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); } break; @@ -4413,20 +4968,20 @@ s3_accel_in(uint16_t port, void *priv) case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 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); + s3->accel_start(8, 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); else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); } else - s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + s3->accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); break; case 0x200: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(16, 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); + s3->accel_start(16, 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); else - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); } else - s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + s3->accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); break; default: @@ -4472,28 +5027,22 @@ s3_accel_in_w(uint16_t port, void *priv) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) temp = (temp >> 8) | (temp << 8); - s3_accel_start(8, 1, temp | (temp << 16), 0, s3); - } else { - s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); - } - } else { - if (s3->color_16bit) { - s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); - } else { - s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); - } - } + s3->accel_start(8, 1, temp | (temp << 16), 0, s3); + } else + s3->accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); + } else + s3->accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); break; case 0x200: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) temp = (temp >> 8) | (temp << 8); - s3_accel_start(16, 1, temp | (temp << 16), 0, s3); + s3->accel_start(16, 1, temp | (temp << 16), 0, s3); } else - s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); } else { - s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); } break; @@ -4530,15 +5079,15 @@ s3_accel_in_l(UNUSED(uint16_t port), void *priv) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) temp = ((temp & 0xff00ff00) >> 8) | ((temp & 0x00ff00ff) << 8); - s3_accel_start(8, 1, temp, 0, s3); - s3_accel_start(8, 1, temp >> 16, 0, s3); + s3->accel_start(8, 1, temp, 0, s3); + s3->accel_start(8, 1, temp >> 16, 0, s3); } else { - s3_accel_start(1, 1, 0xffffffff, temp, s3); - s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3); + s3->accel_start(1, 1, 0xffffffff, temp, s3); + s3->accel_start(1, 1, 0xffffffff, temp >> 16, s3); } } else { - s3_accel_start(1, 1, 0xffffffff, temp, s3); - s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3); + s3->accel_start(1, 1, 0xffffffff, temp, s3); + s3->accel_start(1, 1, 0xffffffff, temp >> 16, s3); } break; case 0x200: @@ -4546,15 +5095,15 @@ s3_accel_in_l(UNUSED(uint16_t port), void *priv) if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { if (s3->accel.cmd & 0x1000) temp = ((temp & 0xff00ff00) >> 8) | ((temp & 0x00ff00ff) << 8); - s3_accel_start(16, 1, temp, 0, s3); - s3_accel_start(16, 1, temp >> 16, 0, s3); + s3->accel_start(16, 1, temp, 0, s3); + s3->accel_start(16, 1, temp >> 16, 0, s3); } else { - s3_accel_start(2, 1, 0xffffffff, temp, s3); - s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3); + s3->accel_start(2, 1, 0xffffffff, temp, s3); + s3->accel_start(2, 1, 0xffffffff, temp >> 16, s3); } } else { - s3_accel_start(2, 1, 0xffffffff, temp, s3); - s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3); + s3->accel_start(2, 1, 0xffffffff, temp, s3); + s3->accel_start(2, 1, 0xffffffff, temp >> 16, s3); } break; @@ -4701,20 +5250,20 @@ s3_accel_read(uint32_t addr, void *priv) case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 1, temp | (temp << 8) | (temp << 16) | (temp << 24), 0, s3); + s3->accel_start(8, 1, temp | (temp << 8) | (temp << 16) | (temp << 24), 0, s3); else - s3_accel_start(1, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); + s3->accel_start(1, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); } else - s3_accel_start(1, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); + s3->accel_start(1, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); break; case 0x200: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(16, 1, temp | (temp << 8) | (temp << 16) | (temp << 24), 0, s3); + s3->accel_start(16, 1, temp | (temp << 8) | (temp << 16) | (temp << 24), 0, s3); else - s3_accel_start(2, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); + s3->accel_start(2, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); } else - s3_accel_start(2, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); + s3->accel_start(2, 1, 0xffffffff, temp | (temp << 8) | (temp << 16) | (temp << 24), s3); break; default: @@ -4765,20 +5314,20 @@ s3_accel_read_w(uint32_t addr, void *priv) case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(8, 1, temp | (temp << 16), 0, s3); + s3->accel_start(8, 1, temp | (temp << 16), 0, s3); else - s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); + s3->accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); } else - s3_accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); + s3->accel_start(1, 1, 0xffffffff, temp | (temp << 16), s3); break; case 0x200: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) - s3_accel_start(16, 1, temp | (temp << 16), 0, s3); + s3->accel_start(16, 1, temp | (temp << 16), 0, s3); else - s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); } else - s3_accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); + s3->accel_start(2, 1, 0xffffffff, temp | (temp << 16), s3); break; default: @@ -4939,29 +5488,29 @@ s3_accel_read_l(uint32_t addr, void *priv) case 0x000: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { - s3_accel_start(8, 1, temp, 0, s3); - s3_accel_start(8, 1, temp >> 16, 0, s3); + s3->accel_start(8, 1, temp, 0, s3); + s3->accel_start(8, 1, temp >> 16, 0, s3); } else { - s3_accel_start(1, 1, 0xffffffff, temp, s3); - s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3); + s3->accel_start(1, 1, 0xffffffff, temp, s3); + s3->accel_start(1, 1, 0xffffffff, temp >> 16, s3); } } else { - s3_accel_start(1, 1, 0xffffffff, temp, s3); - s3_accel_start(1, 1, 0xffffffff, temp >> 16, s3); + s3->accel_start(1, 1, 0xffffffff, temp, s3); + s3->accel_start(1, 1, 0xffffffff, temp >> 16, s3); } break; case 0x200: if (((s3->accel.multifunc[0xa] & 0xc0) == 0x80) || (s3->accel.cmd & 2)) { if (((s3->accel.frgd_mix & 0x60) != 0x40) || ((s3->accel.bkgd_mix & 0x60) != 0x40)) { - s3_accel_start(16, 1, temp, 0, s3); - s3_accel_start(16, 1, temp >> 16, 0, s3); + s3->accel_start(16, 1, temp, 0, s3); + s3->accel_start(16, 1, temp >> 16, 0, s3); } else { - s3_accel_start(2, 1, 0xffffffff, temp, s3); - s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3); + s3->accel_start(2, 1, 0xffffffff, temp, s3); + s3->accel_start(2, 1, 0xffffffff, temp >> 16, s3); } } else { - s3_accel_start(2, 1, 0xffffffff, temp, s3); - s3_accel_start(2, 1, 0xffffffff, temp >> 16, s3); + s3->accel_start(2, 1, 0xffffffff, temp, s3); + s3->accel_start(2, 1, 0xffffffff, temp >> 16, s3); } break; @@ -5016,11 +5565,13 @@ polygon_setup(s3_t *s3) #define READ(addr, dat) \ if ((s3->bpp == 0) && !s3->color_16bit) \ dat = svga->vram[dword_remap(svga, addr) & s3->vram_mask]; \ - else if ((s3->bpp == 1) || s3->color_16bit) \ + else if ((s3->bpp == 1) || (s3->color_16bit && (svga->bpp < 24))) \ dat = vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)]; \ - else if (s3->bpp == 2) \ + else if (s3->bpp == 2) \ dat = svga->vram[dword_remap(svga, addr) & s3->vram_mask]; \ - else \ + else if (s3->color_16bit && (svga->bpp == 24)) { \ + dat = vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)]; \ + } else \ dat = vram_l[dword_remap_l(svga, addr) & (s3->vram_mask >> 2)]; #define MIX_READ \ @@ -5081,7 +5632,7 @@ polygon_setup(s3_t *s3) { \ old_dest_dat = dest_dat; \ MIX_READ \ - dest_dat = (dest_dat & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask); \ + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); \ } #define ROPMIX_READ(D, P, S) \ @@ -5869,12 +6420,15 @@ polygon_setup(s3_t *s3) if ((s3->bpp == 0) && !s3->color_16bit) { \ svga->vram[dword_remap(svga, addr) & s3->vram_mask] = dat; \ svga->changedvram[(dword_remap(svga, addr) & s3->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ - } else if ((s3->bpp == 1) || s3->color_16bit) { \ + } else if ((s3->bpp == 1) || (s3->color_16bit && (svga->bpp < 24))) { \ vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)] = dat; \ svga->changedvram[(dword_remap_w(svga, addr) & (s3->vram_mask >> 1)) >> 11] = svga->monitor->mon_changeframecount; \ - } else if (s3->bpp == 2) { \ + } else if (s3->bpp == 2) { \ svga->vram[dword_remap(svga, addr) & s3->vram_mask] = dat; \ svga->changedvram[(dword_remap(svga, addr) & s3->vram_mask) >> 12] = svga->monitor->mon_changeframecount; \ + } else if (s3->color_16bit && (svga->bpp == 24)) { \ + vram_w[dword_remap_w(svga, addr) & (s3->vram_mask >> 1)] = dat; \ + svga->changedvram[(dword_remap_w(svga, addr) & (s3->vram_mask >> 1)) >> 11] = svga->monitor->mon_changeframecount; \ } else { \ vram_l[dword_remap_l(svga, addr) & (s3->vram_mask >> 2)] = dat; \ svga->changedvram[(dword_remap_l(svga, addr) & (s3->vram_mask >> 2)) >> 10] = svga->monitor->mon_changeframecount; \ @@ -6261,6 +6815,782 @@ s3_visionx68_video_engine_op(uint32_t cpu_dat, s3_t *s3) } } +void +s3_911_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, void *priv) +{ + s3_t *s3 = (s3_t *)priv; + svga_t *svga = &s3->svga; + uint32_t src_dat = 0; + uint32_t dest_dat; + uint32_t old_dest_dat; + int frgd_mix; + int bkgd_mix; + int clip_t = s3->accel.multifunc[1] & 0xfff; + int clip_l = s3->accel.multifunc[2] & 0xfff; + int clip_b = s3->accel.multifunc[3] & 0xfff; + int clip_r = s3->accel.multifunc[4] & 0xfff; + int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0; + uint32_t mix_mask = (s3->accel.cmd & 0x200) ? 0x8000 : 0x80; + uint16_t *vram_w = (uint16_t *) svga->vram; + uint32_t *vram_l = (uint32_t *) svga->vram; + uint32_t rd_mask = s3->accel.rd_mask; + uint32_t wrt_mask = s3->accel.wrt_mask; + uint32_t frgd_color = s3->accel.frgd_color; + uint32_t bkgd_color = s3->accel.bkgd_color; + int cmd = s3->accel.cmd >> 13; + + if ((s3->accel.cmd & 0x100) && (s3_cpu_src(s3) || (s3_cpu_dest(s3))) && (!cpu_input || (s3_enable_fifo(s3) == 0))) + s3->force_busy = 1; + + if (cpu_input && (((s3->accel.multifunc[0xa] & 0xc0) != 0x80) || (!(s3->accel.cmd & 2)))) { + if (s3->color_16bit) { + if (count > 1) + count >>= 1; + } + } + + if (s3->color_16bit) + rd_mask &= 0xffff; + else + rd_mask &= 0xff; + + /*Bit 4 of the Command register is the draw yes bit, which enables writing to memory/reading from memory when enabled. + When this bit is disabled, no writing to memory/reading from memory is allowed. (This bit is almost meaningless on + the NOP command)*/ + + switch (cmd) { + case 0: /*NOP (Short Stroke Vectors)*/ + if (s3->accel.ssv_state == 0) + break; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (s3->accel.cmd & 8) { /*Radial*/ + while (count-- && s3->accel.ssv_len >= 0) { + 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 ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; + + default: + break; + } + + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + if (s3->accel.ssv_draw) { + WRITE((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + if (!s3->accel.ssv_len) + break; + + switch (s3->accel.ssv_dir & 0xe0) { + case 0x00: + s3->accel.cx++; + break; + case 0x20: + s3->accel.cx++; + s3->accel.cy--; + break; + case 0x40: + s3->accel.cy--; + break; + case 0x60: + s3->accel.cx--; + s3->accel.cy--; + break; + case 0x80: + s3->accel.cx--; + break; + case 0xa0: + s3->accel.cx--; + s3->accel.cy++; + break; + case 0xc0: + s3->accel.cy++; + break; + case 0xe0: + s3->accel.cx++; + s3->accel.cy++; + break; + + default: + break; + } + + s3->accel.ssv_len--; + s3->accel.cx &= 0xfff; + s3->accel.cy &= 0xfff; + } + + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + break; + + case 1: /*Draw line*/ + if (!cpu_input) { + s3->accel.cx = s3->accel.cur_x & 0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + s3->accel.sy = s3->accel.maj_axis_pcnt & 0x7ff; + + if (s3->color_16bit && (svga->bpp < 24)) { + if (s3->accel.wrt_mask != 0xffff) { + if (s3->accel.cur_x & 0x400) { + s3->accel.color_16bit_check = 0; + s3->accel.minus = 0x400; + } else { + s3->accel.color_16bit_check = 1; + s3->accel.minus = 0; + } + } else { + if (s3->accel.cur_x & 0x400) + s3->accel.color_16bit_check = 1; + else + s3->accel.color_16bit_check = 0; + + s3->accel.minus = 0; + } + } else { + s3->accel.color_16bit_check = 0; + s3->accel.minus = 0; + } + + if (s3_cpu_src(s3)) + return; /*Wait for data from CPU*/ + } + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (s3->accel.cmd & 8) { /*Radial*/ + if (s3->color_16bit && (svga->bpp < 24)) { + if (s3->accel.color_16bit_check) + return; + if (s3->accel.wrt_mask != 0xffff) + wrt_mask = (s3->accel.wrt_mask_actual[0] | (s3->accel.wrt_mask_actual[1] << 8)); + } + + while (count-- && s3->accel.sy >= 0) { + 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 ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + if (s3->color_16bit && (svga->bpp < 24)) + src_dat = s3->accel.bkgd_color_actual[0] | (s3->accel.bkgd_color_actual[1] << 8); + break; + case 1: + src_dat = frgd_color; + if (s3->color_16bit && (svga->bpp < 24)) + src_dat = s3->accel.frgd_color_actual[0] | (s3->accel.frgd_color_actual[1] << 8); + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; + + default: + break; + } + + READ((s3->accel.cy * s3->width) + s3->accel.cx - s3->accel.minus, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx - s3->accel.minus, dest_dat); + } + + mix_dat <<= 1; + mix_dat |= 1; + if ((s3->bpp == 0) && !s3->color_16bit) + cpu_dat >>= 8; + else + cpu_dat >>= 16; + + if (!s3->accel.sy) + break; + + switch (s3->accel.cmd & 0xe0) { + case 0x00: + s3->accel.cx++; + break; + case 0x20: + s3->accel.cx++; + s3->accel.cy--; + break; + case 0x40: + s3->accel.cy--; + break; + case 0x60: + s3->accel.cx--; + s3->accel.cy--; + break; + case 0x80: + s3->accel.cx--; + break; + case 0xa0: + s3->accel.cx--; + s3->accel.cy++; + break; + case 0xc0: + s3->accel.cy++; + break; + case 0xe0: + s3->accel.cx++; + s3->accel.cy++; + break; + + default: + break; + } + s3->accel.sy--; + s3->accel.cx &= 0xfff; + s3->accel.cy &= 0xfff; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } else { /*Bresenham*/ + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && (count == 16)) { /*Stupid undocumented 0xB2E8 on 911/924*/ + count = s3->accel.maj_axis_pcnt + 1; + s3->accel.temp_cnt = 16; + } + + if (s3->color_16bit && (svga->bpp < 24)) { + if (!s3->accel.b2e8_pix) { + if (!s3->accel.color_16bit_check) + wrt_mask = (s3->accel.wrt_mask_actual[0] | (s3->accel.wrt_mask_actual[1] << 8)); + else + return; + } + } + + //pclog("CMD=%04x, curx=%d, lwrtmask=%04x, actual wrtmask=%04x, frgdmix=%d, bkgdmix=%d, input=%d, cnt=%d.\n", s3->accel.cmd, s3->accel.cur_x, wrt_mask, s3->accel.wrt_mask, frgd_mix, bkgd_mix, cpu_input, count); + while (count-- && s3->accel.sy >= 0) { + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && !s3->accel.temp_cnt) { + mix_dat >>= 16; + s3->accel.temp_cnt = 16; + } + + 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 ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + if (s3->color_16bit && (svga->bpp < 24) && !s3->accel.b2e8_pix) { + if (!s3->accel.color_16bit_check) + src_dat = s3->accel.bkgd_color_actual[0] | (s3->accel.bkgd_color_actual[1] << 8); + } + break; + case 1: + src_dat = frgd_color; + if (s3->color_16bit && (svga->bpp < 24) && !s3->accel.b2e8_pix) { + if (!s3->accel.color_16bit_check) + src_dat = s3->accel.frgd_color_actual[0] | (s3->accel.frgd_color_actual[1] << 8); + } + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; + + default: + break; + } + + READ((s3->accel.cy * s3->width) + s3->accel.cx - s3->accel.minus, dest_dat); + + MIX + + if (s3->accel.cmd & 0x10) { + WRITE((s3->accel.cy * s3->width) + s3->accel.cx - s3->accel.minus, dest_dat); + } + } + + if (s3->accel.b2e8_pix && s3_cpu_src(s3)) { + if (s3->accel.temp_cnt > 0) { + s3->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + } + } else { + mix_dat <<= 1; + mix_dat |= 1; + } + + if (s3->color_16bit) + cpu_dat >>= 16; + else + cpu_dat >>= 8; + + if (!s3->accel.sy) + break; + + if (s3->accel.err_term >= s3->accel.maj_axis_pcnt) { + s3->accel.err_term += s3->accel.destx_distp; + /*Step minor axis*/ + switch (s3->accel.cmd & 0xe0) { + case 0x00: + s3->accel.cy--; + break; + case 0x20: + s3->accel.cy--; + break; + case 0x40: + s3->accel.cx--; + break; + case 0x60: + s3->accel.cx++; + break; + case 0x80: + s3->accel.cy++; + break; + case 0xa0: + s3->accel.cy++; + break; + case 0xc0: + s3->accel.cx--; + break; + case 0xe0: + s3->accel.cx++; + break; + + default: + break; + } + } else + s3->accel.err_term += s3->accel.desty_axstp; + + /*Step major axis*/ + switch (s3->accel.cmd & 0xe0) { + case 0x00: + s3->accel.cx--; + break; + case 0x20: + s3->accel.cx++; + break; + case 0x40: + s3->accel.cy--; + break; + case 0x60: + s3->accel.cy--; + break; + case 0x80: + s3->accel.cx--; + break; + case 0xa0: + s3->accel.cx++; + break; + case 0xc0: + s3->accel.cy++; + break; + case 0xe0: + s3->accel.cy++; + break; + + default: + break; + } + s3->accel.sy--; + s3->accel.cx &= 0xfff; + s3->accel.cy &= 0xfff; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + break; + + case 2: /*Rectangle fill*/ + 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.cx = s3->accel.cur_x & 0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + s3->accel.pix_trans_x_count = 0; + + s3->accel.dest = s3->accel.cy * s3->width; + + if (s3->color_16bit && (svga->bpp < 24)) { + if (s3->accel.cur_x & 0x400) { + s3->accel.color_16bit_check = 0; + s3->accel.minus = 0x400; + } else { + s3->accel.color_16bit_check = 1; + s3->accel.minus = 0; + } + + if (s3->accel.color_16bit_check) { + if (((s3->accel.multifunc[0xa] & 0xc0) == 0x00) && !(s3->accel.cmd & 2)) + s3->accel.color_16bit_check_rectfill = !!s3_cpu_src(s3); + else + s3->accel.color_16bit_check_rectfill = 0; + } + + if (s3->accel.color_16bit_check_rectfill) { + if (s3->accel.color_16bit_check) { + s3->accel.pix_trans_ptr = (uint8_t *) calloc(1, (s3->accel.sx + 1) << 1); + s3->accel.pix_trans_ptr_cnt = (s3->accel.sx + 1) << 1; + } + } else + s3->accel.pix_trans_x_count = 0; + } else { + s3->accel.pix_trans_x_count = 0; + s3->accel.color_16bit_check = 0; + s3->accel.color_16bit_check_rectfill = 0; + s3->accel.minus = 0; + } + + if (s3_cpu_src(s3)) { + s3->data_available = 0; + return; /*Wait for data from CPU*/ + } else if (s3_cpu_dest(s3)) { + s3->data_available = 1; + return; + } + } + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && count == 16) { /*Stupid undocumented 0xB2E8 on 911/924*/ + count = s3->accel.maj_axis_pcnt + 1; + s3->accel.temp_cnt = 16; + } + + if (s3->color_16bit && (svga->bpp < 24)) { + if (!s3->accel.b2e8_pix) { + if (!s3->accel.color_16bit_check) { + wrt_mask = (s3->accel.wrt_mask_actual[0] | (s3->accel.wrt_mask_actual[1] << 8)); + } else if (s3->accel.color_16bit_check && (s3->accel.cmd == 0x40f3)) + return; + } + } + + while (count-- && s3->accel.sy >= 0) { + if (s3->accel.b2e8_pix && s3_cpu_src(s3) && !s3->accel.temp_cnt) { + mix_dat >>= 16; + s3->accel.temp_cnt = 16; + } + + 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) { + if (s3_cpu_dest(s3) && ((s3->accel.multifunc[0xa] & 0xc0) == 0x00)) { + mix_dat = mix_mask; /* Mix data = forced to foreground register. */ + } else if (s3_cpu_dest(s3) && vram_mask) { + /* Mix data = current video memory value. */ + READ(s3->accel.dest + s3->accel.cx - s3->accel.minus, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } + + if (s3_cpu_dest(s3)) { + READ(s3->accel.dest + s3->accel.cx - s3->accel.minus, src_dat); + if (vram_mask) + src_dat = ((src_dat & rd_mask) == rd_mask); + } else { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + if (s3->color_16bit && (svga->bpp < 24) && !s3->accel.b2e8_pix && (s3->accel.cmd != 0x41b3)) { + if (!s3->accel.color_16bit_check) + src_dat = s3->accel.bkgd_color_actual[0] | (s3->accel.bkgd_color_actual[1] << 8); + } + break; + case 1: + src_dat = frgd_color; + if (s3->color_16bit && (svga->bpp < 24) && !s3->accel.b2e8_pix && (s3->accel.cmd != 0x41b3)) { + if (!s3->accel.color_16bit_check) + src_dat = s3->accel.frgd_color_actual[0] | (s3->accel.frgd_color_actual[1] << 8); + } + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; + + default: + break; + } + } + + READ(s3->accel.dest + s3->accel.cx - s3->accel.minus, dest_dat); + + if (s3->accel.cmd == 0x41b1 || s3->accel.cmd == 0x41b0) { + uint16_t dest_dat2; + READ(s3->accel.dest + s3->accel.cx, dest_dat2); + //pclog("CMD=%04x, initialdest=%04x, c(%d,%d), cpu=%04x, minus=%d, len=%d.\n", s3->accel.cmd, dest_dat2, s3->accel.cx - s3->accel.minus, s3->accel.cy, cpu_dat & 0xffff, s3->accel.minus, s3->accel.maj_axis_pcnt); + } + + MIX + + if (s3->accel.cmd & 0x10) { + WRITE(s3->accel.dest + s3->accel.cx - s3->accel.minus, dest_dat); + } + } + + if (s3->accel.b2e8_pix && s3_cpu_src(s3)) { + if (s3->accel.temp_cnt > 0) { + s3->accel.temp_cnt--; + mix_dat <<= 1; + mix_dat |= 1; + } + } else { + mix_dat <<= 1; + mix_dat |= 1; + } + + if (s3->color_16bit) + cpu_dat >>= 16; + else + cpu_dat >>= 8; + + if (s3->accel.cmd & 0x20) + s3->accel.cx++; + else + s3->accel.cx--; + + s3->accel.cx &= 0xfff; + s3->accel.sx--; + if (s3->accel.sx < 0) { + if (s3->accel.cmd & 0x20) + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + else + s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + if (s3->accel.cmd & 0x80) + s3->accel.cy++; + else + s3->accel.cy--; + + s3->accel.cy &= 0xfff; + s3->accel.dest = s3->accel.cy * s3->width; + s3->accel.sy--; + + if (cpu_input) { + if (s3->accel.b2e8_pix) { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + return; + } + if (s3->accel.sy < 0) { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + return; + } + } + } + break; + + case 6: /*BitBlt*/ + 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; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + if (s3->color_16bit && (svga->bpp < 24)) { + if (s3->accel.destx_distp & 0x400) { + s3->accel.color_16bit_check = 0; + s3->accel.minus = 0x400; + } else { + s3->accel.color_16bit_check = 1; + s3->accel.minus = 0; + } + s3->accel.srcminus = 0x400; + } else { + s3->accel.color_16bit_check = 0; + s3->accel.minus = 0; + s3->accel.srcminus = 0; + } + } + + 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; + + if (s3->color_16bit && (svga->bpp < 24)) { + if (!s3->accel.color_16bit_check) + wrt_mask = (s3->accel.wrt_mask_actual[0] | (s3->accel.wrt_mask_actual[1] << 8)); + else + return; + } + + if (!cpu_input && (frgd_mix == 3) && !vram_mask && ((s3->accel.cmd & 0xa0) == 0xa0) && ((s3->accel.frgd_mix & 0xf) == 7) && ((s3->accel.bkgd_mix & 0xf) == 7)) { + while (1) { + 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) { + READ(s3->accel.src + s3->accel.cx - s3->accel.srcminus, src_dat); + READ(s3->accel.dest + s3->accel.dx - s3->accel.minus, dest_dat); + + dest_dat = (src_dat & wrt_mask) | (dest_dat & ~wrt_mask); + + WRITE(s3->accel.dest + s3->accel.dx - s3->accel.minus, dest_dat); + } + + s3->accel.cx++; + s3->accel.dx++; + s3->accel.sx--; + s3->accel.dx &= 0xfff; + if (s3->accel.sx < 0) { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + s3->accel.cy++; + s3->accel.dy++; + + s3->accel.dy &= 0xfff; + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (s3->accel.sy < 0) { /*It's evident that this is a clear undocumented difference compared to later chips, per what NT 3.5+ does to DX/DY.*/ + s3->accel.destx_distp = s3->accel.dx; + s3->accel.desty_axstp = s3->accel.dy; + return; + } + } + } + } else { + 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)) { + if (vram_mask && (s3->accel.cmd & 0x10)) { + READ(s3->accel.src + s3->accel.cx - s3->accel.srcminus, mix_dat); + mix_dat = ((mix_dat & rd_mask) == rd_mask); + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + if (s3->color_16bit && (svga->bpp < 24)) { + if (!s3->accel.color_16bit_check) + src_dat = s3->accel.bkgd_color_actual[0] | (s3->accel.bkgd_color_actual[1] << 8); + } + break; + case 1: + src_dat = frgd_color; + if (s3->color_16bit && (svga->bpp < 24)) { + if (!s3->accel.color_16bit_check) + src_dat = s3->accel.frgd_color_actual[0] | (s3->accel.frgd_color_actual[1] << 8); + } + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + READ(s3->accel.src + s3->accel.cx - s3->accel.srcminus, src_dat); + if (vram_mask && (s3->accel.cmd & 0x10)) + src_dat = ((src_dat & rd_mask) == rd_mask); + break; + + default: + break; + } + + READ(s3->accel.dest + s3->accel.dx - s3->accel.minus, dest_dat); + + MIX + + if ((!(s3->accel.cmd & 0x10) && vram_mask) || (s3->accel.cmd & 0x10)) { + WRITE(s3->accel.dest + s3->accel.dx - s3->accel.minus, dest_dat); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + + if (s3->color_16bit) + cpu_dat >>= 16; + else + cpu_dat >>= 8; + + if (s3->accel.cmd & 0x20) { + s3->accel.cx++; + s3->accel.dx++; + } else { + s3->accel.cx--; + s3->accel.dx--; + } + s3->accel.dx &= 0xfff; + 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); + } else { + s3->accel.cx += ((s3->accel.maj_axis_pcnt & 0xfff) + 1); + s3->accel.dx += ((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++; + } else { + s3->accel.cy--; + s3->accel.dy--; + } + s3->accel.dy &= 0xfff; + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input) + return; + + if (s3->accel.sy < 0) { /*It's evident that this is a clear undocumented difference compared to later chips, per what NT 3.5+ does to DX/DY.*/ + s3->accel.destx_distp = s3->accel.dx; + s3->accel.desty_axstp = s3->accel.dy; + return; + } + } + } + } + break; + + default: + break; + } +} + void s3_short_stroke_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3, uint8_t ssv) { @@ -6274,12 +7604,13 @@ s3_short_stroke_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_d } } - s3_accel_start(count, cpu_input, mix_dat, cpu_dat, s3); + s3->accel_start(count, cpu_input, mix_dat, cpu_dat, s3); } void -s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) +s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, void *priv) { + s3_t *s3 = (s3_t *)priv; svga_t *svga = &s3->svga; uint32_t src_dat = 0; uint32_t dest_dat; @@ -6294,16 +7625,23 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ int clip_r = s3->accel.multifunc[4] & 0xfff; int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0; uint32_t mix_mask = 0; + uint8_t *vram = (uint8_t *) svga->vram; 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; + uint32_t wrt_mask = s3->accel.wrt_mask; + uint32_t frgd_color = s3->accel.frgd_color; + uint32_t bkgd_color = s3->accel.bkgd_color; int cmd = s3->accel.cmd >> 13; uint32_t srcbase; uint32_t dstbase; + s3->accel.srcminus = 0; + s3->accel.minus = 0; + if ((s3->chip >= S3_TRIO64 || s3->chip == S3_VISION968 || s3->chip == S3_VISION868) && (s3->accel.cmd & (1 << 11))) cmd |= 8; @@ -6318,7 +7656,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ else dstbase = 0x100000 * ((s3->accel.multifunc[0xe] >> 0) & 3); - if (s3->bpp == 1) { + if ((s3->bpp == 1) || s3->color_16bit) { srcbase >>= 1; dstbase >>= 1; } else if (s3->bpp == 3) { @@ -6354,9 +7692,9 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ else if ((s3->bpp == 1) || s3->color_16bit) rd_mask &= 0xffff; - if ((s3->bpp == 0) && !s3->color_16bit) + if (s3->bpp == 0) compare &= 0xff; - else if ((s3->bpp == 1) || s3->color_16bit) + else if (s3->bpp == 1) compare &= 0xffff; switch (s3->accel.cmd & 0x600) { @@ -6394,10 +7732,10 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ 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 ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: - src_dat = s3->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = s3->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -6423,7 +7761,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ mix_dat <<= 1; mix_dat |= 1; - if (s3->bpp == 0) + if (s3->bpp == 0 && !s3->color_16bit) cpu_dat >>= 8; else cpu_dat >>= 16; @@ -6487,16 +7825,15 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ frgd_mix = (s3->accel.frgd_mix >> 5) & 3; bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - if (s3->accel.cmd & 8) /*Radial*/ - { + if (s3->accel.cmd & 8) { /*Radial*/ while (count-- && s3->accel.sy >= 0) { 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 ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: - src_dat = s3->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = s3->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -6567,8 +7904,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ } s3->accel.cur_x = s3->accel.cx; s3->accel.cur_y = s3->accel.cy; - } else /*Bresenham*/ - { + } else { /*Bresenham*/ if (s3->accel.b2e8_pix && s3_cpu_src(s3) && (count == 16)) { /*Stupid undocumented 0xB2E8 on 911/924*/ count = s3->accel.maj_axis_pcnt + 1; s3->accel.temp_cnt = 16; @@ -6583,10 +7919,10 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ 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 ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: - src_dat = s3->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = s3->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -6618,11 +7954,11 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ mix_dat <<= 1; mix_dat |= 1; } + if (s3->bpp == 0 && !s3->color_16bit) cpu_dat >>= 8; - else { + else cpu_dat >>= 16; - } if (!s3->accel.sy) break; @@ -6659,9 +7995,8 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ default: break; } - } else { + } else s3->accel.err_term += s3->accel.desty_axstp; - } /*Step major axis*/ switch (s3->accel.cmd & 0xe0) { @@ -6749,13 +8084,13 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ READ(s3->accel.dest + s3->accel.cx, src_dat); if (vram_mask) src_dat = ((src_dat & rd_mask) == rd_mask); - } else + } else { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: - src_dat = s3->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = s3->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -6767,6 +8102,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ default: break; } + } if ((compare_mode == 2 && src_dat != compare) || (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { READ(s3->accel.dest + s3->accel.cx, dest_dat); @@ -6790,11 +8126,10 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ mix_dat |= 1; } - if ((s3->bpp == 0) && !s3->color_16bit) + if (s3->bpp == 0 && !s3->color_16bit) cpu_dat >>= 8; - else { + else cpu_dat >>= 16; - } if (s3->accel.cmd & 0x20) s3->accel.cx++; @@ -6808,8 +8143,8 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; - s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; if (s3->accel.cmd & 0x80) s3->accel.cy++; else @@ -6919,17 +8254,12 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ break; case 6: /*BitBlt*/ - if (!cpu_input) /*!cpu_input is trigger to start operation*/ - { + 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 & 0x7ff; - if (s3->accel.destx_distp & 0x800) - s3->accel.dx |= ~0x7ff; - s3->accel.dy = s3->accel.desty_axstp & 0x7ff; - if (s3->accel.desty_axstp & 0x800) - s3->accel.dy |= ~0x7ff; + s3->accel.dx = s3->accel.destx_distp & 0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; s3->accel.cx = s3->accel.cur_x & 0xfff; s3->accel.cy = s3->accel.cur_y & 0xfff; @@ -6951,16 +8281,15 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ READ(s3->accel.src + s3->accel.cx, src_dat); READ(s3->accel.dest + s3->accel.dx, dest_dat); - dest_dat = (src_dat & s3->accel.wrt_mask) | (dest_dat & ~s3->accel.wrt_mask); + dest_dat = (src_dat & wrt_mask) | (dest_dat & ~wrt_mask); - if (s3->accel.cmd & 0x10) { - WRITE(s3->accel.dest + s3->accel.dx, dest_dat); - } + WRITE(s3->accel.dest + s3->accel.dx, dest_dat); } s3->accel.cx++; s3->accel.dx++; s3->accel.sx--; + s3->accel.dx &= 0xfff; if (s3->accel.sx < 0) { s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; @@ -6969,12 +8298,15 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.cy++; s3->accel.dy++; + s3->accel.dy &= 0xfff; s3->accel.src = srcbase + s3->accel.cy * s3->width; s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3->accel.sy--; if (s3->accel.sy < 0) { + s3->accel.destx_distp = s3->accel.dx; + s3->accel.desty_axstp = s3->accel.dy; return; } } @@ -6989,10 +8321,10 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ } switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { case 0: - src_dat = s3->accel.bkgd_color; + src_dat = bkgd_color; break; case 1: - src_dat = s3->accel.frgd_color; + src_dat = frgd_color; break; case 2: src_dat = cpu_dat; @@ -7008,7 +8340,6 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ } 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); MIX @@ -7024,9 +8355,8 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ if (s3->bpp == 0 && !s3->color_16bit) cpu_dat >>= 8; - else { + else cpu_dat >>= 16; - } if (s3->accel.cmd & 0x20) { s3->accel.cx++; @@ -7035,6 +8365,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.cx--; s3->accel.dx--; } + s3->accel.dx &= 0xfff; s3->accel.sx--; if (s3->accel.sx < 0) { if (s3->accel.cmd & 0x20) { @@ -7053,16 +8384,18 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.cy--; s3->accel.dy--; } + s3->accel.dy &= 0xfff; s3->accel.src = srcbase + s3->accel.cy * s3->width; s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3->accel.sy--; - if (cpu_input) { + if (cpu_input) return; - } if (s3->accel.sy < 0) { + s3->accel.destx_distp = s3->accel.dx; + s3->accel.desty_axstp = s3->accel.dy; return; } } @@ -7077,11 +8410,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ 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; s3->accel.cy = s3->accel.cur_y & 0xfff; @@ -7143,7 +8472,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ mix_dat <<= 1; mix_dat |= 1; - if (s3->bpp == 0) + if (s3->bpp == 0 && !s3->color_16bit) cpu_dat >>= 8; else cpu_dat >>= 16; @@ -7155,6 +8484,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7); s3->accel.dx--; } + s3->accel.dx &= 0xfff; s3->accel.sx--; if (s3->accel.sx < 0) { if (s3->accel.cmd & 0x20) { @@ -7174,6 +8504,7 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ s3->accel.dy--; } + s3->accel.dy &= 0xfff; s3->accel.src = srcbase + s3->accel.pattern + (s3->accel.cy * s3->width); s3->accel.dest = dstbase + s3->accel.dy * s3->width; @@ -7183,6 +8514,8 @@ s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_ return; } if (s3->accel.sy < 0) { + s3->accel.destx_distp = s3->accel.dx; + s3->accel.desty_axstp = s3->accel.dy; return; } } @@ -7564,6 +8897,7 @@ s3_pci_read(UNUSED(int func), int addr, void *priv) 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 (s3->chip == S3_TRIO64V2) ? (s3->pci_regs[0x07] & 0x36) : (1 << 1); /*Medium DEVSEL timing*/ @@ -7575,7 +8909,8 @@ s3_pci_read(UNUSED(int func), int addr, void *priv) return 0x16; /*Confirmed on an onboard 64V2/DX*/ default: return 0x00; - } + } + break; case 0x09: return 0; /*Programming interface*/ @@ -7602,6 +8937,7 @@ s3_pci_read(UNUSED(int func), int addr, void *priv) return 0x00; else return (svga->crtc[0x5a] & 0x80); + break; case 0x13: if (svga->crtc[0x53] & 0x08) { @@ -7609,6 +8945,7 @@ s3_pci_read(UNUSED(int func), int addr, void *priv) } else { return svga->crtc[0x59]; } + break; case 0x30: return s3->has_bios ? (s3->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ @@ -7826,6 +9163,11 @@ s3_reset(void *priv) s3->pci_regs[0x32] = 0x0c; s3->pci_regs[0x33] = 0x00; + if (s3->chip <= S3_86C924) + s3->accel_start = s3_911_accel_start; + else + s3->accel_start = s3_accel_start; + switch (s3->card_type) { case S3_MIROCRYSTAL8S_805: case S3_MIROCRYSTAL10SD_805: @@ -7901,9 +9243,7 @@ s3_reset(void *priv) case S3_DIAMOND_STEALTH64_764: case S3_SPEA_MIRAGE_P64: case S3_NUMBER9_9FX: - if ((s3->card_type == S3_CARDEX_TRIO64VPLUS) || - (s3->card_type == S3_PHOENIX_TRIO64VPLUS) || - (s3->card_type == S3_PHOENIX_TRIO64VPLUS_ONBOARD)) + if (s3->chip == S3_TRIO64V) svga->crtc[0x53] = 0x08; break; @@ -8251,12 +9591,34 @@ s3_init(const device_t *info) svga->hwcursor.cur_ysize = 64; - 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 && (info->local == S3_ELSAWIN2KPROX || info->local == S3_PHOENIX_VISION968 || info->local == S3_NUMBER9_9FX_771))) - svga->dac_hwcursor_draw = ibm_rgb528_hwcursor_draw; - else if (chip == S3_VISION968 && (info->local == S3_SPEA_MERCURY_P64V || info->local == S3_MIROVIDEO40SV_ERGO_968)) - svga->dac_hwcursor_draw = tvp3026_hwcursor_draw; + switch (chip) { + case S3_VISION964: + switch (info->local) { + case S3_ELSAWIN2KPROX_964: + svga->dac_hwcursor_draw = ibm_rgb528_hwcursor_draw; + break; + default: + svga->dac_hwcursor_draw = bt48x_hwcursor_draw; + break; + } + break; + + case S3_VISION968: + switch (info->local) { + case S3_ELSAWIN2KPROX: + case S3_PHOENIX_VISION968: + case S3_NUMBER9_9FX_771: + svga->dac_hwcursor_draw = ibm_rgb528_hwcursor_draw; + break; + case S3_SPEA_MERCURY_P64V: + case S3_MIROVIDEO40SV_ERGO_968: + svga->dac_hwcursor_draw = tvp3026_hwcursor_draw; + break; + default: + break; + } + break; + } if (chip >= S3_VISION964) { switch (vram) { @@ -8326,6 +9688,11 @@ s3_init(const device_t *info) svga->force_old_addr = 1; + if (s3->chip <= S3_86C924) + s3->accel_start = s3_911_accel_start; + else + s3->accel_start = s3_accel_start; + switch (s3->card_type) { case S3_ORCHID_86C911: case S3_DIAMOND_STEALTH_VRAM: @@ -8351,7 +9718,7 @@ s3_init(const device_t *info) s3->packed_mmio = 0; s3->width = 1024; - svga->ramdac = device_add(&sc11487_ramdac_device); + svga->ramdac = device_add(&att490_ramdac_device); svga->clock_gen = device_add(&ics2494an_305_device); svga->getclock = ics2494_getclock; break; @@ -8417,7 +9784,7 @@ s3_init(const device_t *info) case S3_METHEUS_86C928: svga->decode_mask = (4 << 20) - 1; - stepping = 0x91; /*86C928*/ + stepping = 0x91; /*86C928D*/ s3->id = stepping; s3->id_ext = stepping; s3->id_ext_pci = 0; @@ -8445,7 +9812,7 @@ s3_init(const device_t *info) case S3_PHOENIX_VISION864: case S3_MIROCRYSTAL20SD_864: /*BIOS 3.xx has a SDAC ramdac.*/ svga->decode_mask = (8 << 20) - 1; - if (info->local == S3_PARADISE_BAHAMAS64 || info->local == S3_MIROCRYSTAL20SD_864) + if (info->local == S3_PARADISE_BAHAMAS64) stepping = 0xc0; /*Vision864*/ else stepping = 0xc1; /*Vision864P*/ @@ -8468,13 +9835,18 @@ s3_init(const device_t *info) s3->packed_mmio = 1; svga->crtc[0x5a] = 0x0a; - if (info->local == S3_ELSAWIN2KPROX_964) - svga->ramdac = device_add(&ibm_rgb528_ramdac_device); - else - svga->ramdac = device_add(&bt485_ramdac_device); - - svga->clock_gen = device_add(&icd2061_device); - svga->getclock = icd2061_getclock; + switch (info->local) { + case S3_ELSAWIN2KPROX_964: + svga->ramdac = device_add(&ibm_rgb528_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + break; + default: + svga->ramdac = device_add(&bt485_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + break; + } break; case S3_ELSAWIN2KPROX: @@ -8498,15 +9870,20 @@ s3_init(const device_t *info) svga->crtc[0x5a] = 0x0a; } - if (info->local == S3_ELSAWIN2KPROX || info->local == S3_PHOENIX_VISION968 || info->local == S3_NUMBER9_9FX_771) { - svga->ramdac = device_add(&ibm_rgb528_ramdac_device); - svga->clock_gen = device_add(&icd2061_device); - svga->getclock = icd2061_getclock; - } else { - svga->ramdac = device_add(&tvp3026_ramdac_device); - svga->clock_gen = svga->ramdac; - svga->getclock = tvp3026_getclock; - svga->conv_16to32 = tvp3026_conv_16to32; + switch (info->local) { + case S3_ELSAWIN2KPROX: + case S3_PHOENIX_VISION968: + case S3_NUMBER9_9FX_771: + svga->ramdac = device_add(&ibm_rgb528_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + break; + default: + svga->ramdac = device_add(&tvp3026_ramdac_device); + svga->clock_gen = svga->ramdac; + svga->getclock = tvp3026_getclock; + svga->conv_16to32 = tvp3026_conv_16to32; + break; } break; @@ -8569,9 +9946,8 @@ s3_init(const device_t *info) s3->id_ext = s3->id_ext_pci = 0x11; s3->packed_mmio = 1; - if (info->local == S3_PHOENIX_TRIO64VPLUS || info->local == S3_PHOENIX_TRIO64VPLUS_ONBOARD) { + if (s3->chip == S3_TRIO64V) svga->crtc[0x53] = 0x08; - } svga->clock_gen = s3; svga->getclock = s3_trio64_getclock; @@ -9112,7 +10488,7 @@ const device_t s3_spea_mercury_lite_86c928_pci_device = { { .available = s3_spea_mercury_lite_pci_available }, .speed_changed = s3_speed_changed, .force_redraw = s3_force_redraw, - .config = s3_standard_config + .config = s3_orchid_86c911_config }; const device_t s3_mirocrystal_20sd_864_vlb_device = { diff --git a/src/video/vid_sc1502x_ramdac.c b/src/video/vid_sc1502x_ramdac.c index 7cbcaf05d..7315c65ad 100644 --- a/src/video/vid_sc1502x_ramdac.c +++ b/src/video/vid_sc1502x_ramdac.c @@ -34,84 +34,126 @@ typedef struct sc1502x_ramdac_t { int state; uint8_t ctrl; + uint8_t idx; + uint8_t regs[256]; + uint32_t pixel_mask; + uint8_t enable_ext; } sc1502x_ramdac_t; -void -sc1502x_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga) +static void +sc1502x_ramdac_bpp(uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga) { - sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) priv; - int oldbpp = 0; - - switch (addr) { - case 0x3C6: - if (ramdac->state == 4) { - ramdac->state = 0; - if (val == 0xFF) + int oldbpp = 0; + if (val == 0xff) + return; + ramdac->ctrl = val; + oldbpp = svga->bpp; + switch ((val & 1) | ((val & 0xc0) >> 5)) { + case 0: + svga->bpp = 8; + break; + case 2: + case 3: + switch (val & 0x20) { + case 0x00: + svga->bpp = 32; + break; + case 0x20: + svga->bpp = 24; break; - ramdac->ctrl = val; - oldbpp = svga->bpp; - switch ((val & 1) | ((val & 0xc0) >> 5)) { - case 0: - svga->bpp = 8; - break; - case 2: - case 3: - switch (val & 0x20) { - case 0x00: - svga->bpp = 32; - break; - case 0x20: - svga->bpp = 24; - break; - default: - break; - } + default: + break; + } + break; + case 4: + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 16; + break; + case 7: + if (val & 4) { + switch (val & 0x20) { + case 0x00: + svga->bpp = 32; break; - case 4: - case 5: - svga->bpp = 15; - break; - case 6: - svga->bpp = 16; - break; - case 7: - if (val & 4) { - switch (val & 0x20) { - case 0x00: - svga->bpp = 32; - break; - case 0x20: - svga->bpp = 24; - break; - - default: - break; - } - } else { - svga->bpp = 16; - } + case 0x20: + svga->bpp = 24; break; default: break; } - if (oldbpp != svga->bpp) - svga_recalctimings(svga); + } else + svga->bpp = 16; + break; + + default: + break; + } + if (oldbpp != svga->bpp) + svga_recalctimings(svga); +} + +void +sc1502x_ramdac_out(uint16_t addr, uint8_t val, void *priv, svga_t *svga) +{ + sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) priv; + + switch (addr) { + case 0x3C6: + if (ramdac->state == 0) + ramdac->enable_ext = (val == 0x10); + + if (ramdac->state == 4) { + ramdac->state = 0; + sc1502x_ramdac_bpp(val, ramdac, svga); return; } ramdac->state = 0; break; case 0x3C7: + if (ramdac->enable_ext) { + ramdac->idx = val; + return; + } + ramdac->state = 0; + break; case 0x3C8: + if (ramdac->enable_ext) { + switch (ramdac->idx) { + case 8: + ramdac->regs[ramdac->idx] = val; + svga_set_ramdac_type(svga, (ramdac->regs[ramdac->idx] & 1) ? RAMDAC_8BIT : RAMDAC_6BIT); + break; + case 0x0d: + ramdac->pixel_mask = val & svga->dac_mask; + break; + case 0x0e: + ramdac->pixel_mask |= ((val & svga->dac_mask) << 8); + break; + case 0x0f: + ramdac->pixel_mask |= ((val & svga->dac_mask) << 16); + break; + default: + ramdac->regs[ramdac->idx] = val; + break; + } + return; + } + ramdac->state = 0; + break; case 0x3C9: + if (ramdac->enable_ext) + return; ramdac->state = 0; break; default: break; } - svga_out(addr, val, svga); } @@ -131,10 +173,45 @@ sc1502x_ramdac_in(uint16_t addr, void *priv, svga_t *svga) ramdac->state++; break; case 0x3C7: - case 0x3C8: - case 0x3C9: ramdac->state = 0; break; + case 0x3C8: + if (ramdac->enable_ext) { + switch (ramdac->idx) { + case 9: + temp = 0x53; + break; + case 0x0a: + temp = 0x3a; + break; + case 0x0b: + temp = 0xb1; + break; + case 0x0c: + temp = 0x41; + break; + case 0x0d: + temp = ramdac->pixel_mask & 0xff; + break; + case 0x0e: + temp = ramdac->pixel_mask >> 8; + break; + case 0x0f: + temp = ramdac->pixel_mask >> 16; + break; + default: + temp = ramdac->regs[ramdac->idx]; + break; + } + } else + ramdac->state = 0; + break; + case 0x3C9: + if (ramdac->enable_ext) + temp = ramdac->idx; + else + ramdac->state = 0; + break; default: break; @@ -149,6 +226,9 @@ sc1502x_ramdac_init(UNUSED(const device_t *info)) sc1502x_ramdac_t *ramdac = (sc1502x_ramdac_t *) malloc(sizeof(sc1502x_ramdac_t)); memset(ramdac, 0, sizeof(sc1502x_ramdac_t)); + ramdac->ctrl = 0; + ramdac->pixel_mask = 0xffffff; + return ramdac; }