This commit is contained in:
OBattler
2025-06-19 01:52:31 +02:00
27 changed files with 583 additions and 211 deletions

View File

@@ -137,6 +137,7 @@ typedef struct mach_t {
int16_t dx_end; int16_t dx_end;
int16_t dy; int16_t dy;
int16_t dy_end; int16_t dy_end;
int16_t dx_first_row_start;
int16_t dx_start; int16_t dx_start;
int16_t dy_start; int16_t dy_start;
int16_t cy; int16_t cy;

View File

@@ -61,42 +61,63 @@ typedef enum mda_crtc_registers_e
typedef enum mda_mode_flags_e typedef enum mda_mode_flags_e
{ {
MDA_MODE_HIGHRES = 1 << 0, // MUST be enabled for sane operation MDA_MODE_HIGHRES = 1 << 0, // MUST be enabled for sane operation
MDA_MODE_BLACKANDWHITE = 1 << 1, // UNUSED in most cases. Not present on Hercules MDA_MODE_BW = 1 << 1, // UNUSED in most cases. Not present on Hercules
MDA_MODE_VIDEO_ENABLE = 1 << 3, MDA_MODE_VIDEO_ENABLE = 1 << 3,
MDA_MODE_BLINK = 1 << 5, MDA_MODE_BLINK = 1 << 5,
} mda_mode_flags; } mda_mode_flags;
typedef enum mda_colors_e
{
MDA_COLOR_BLACK = 0,
MDA_COLOR_BLUE = 1,
MDA_COLOR_GREEN = 2,
MDA_COLOR_CYAN = 3,
MDA_COLOR_RED = 4,
MDA_COLOR_MAGENTA = 5,
MDA_COLOR_BROWN = 6,
MDA_COLOR_WHITE = 7,
MDA_COLOR_GREY = 8,
MDA_COLOR_BRIGHT_BLUE = 9,
MDA_COLOR_BRIGHT_GREEN = 10,
MDA_COLOR_BRIGHT_CYAN = 11,
MDA_COLOR_BRIGHT_RED = 12,
MDA_COLOR_BRIGHT_MAGENTA = 13,
MDA_COLOR_BRIGHT_YELLOW = 14,
MDA_COLOR_BRIGHT_WHITE = 15,
} mda_colors;
typedef struct mda_t { typedef struct mda_t {
mem_mapping_t mapping; mem_mapping_t mapping;
uint8_t crtc[MDA_CRTC_NUM_REGISTERS]; uint8_t crtc[MDA_CRTC_NUM_REGISTERS];
int crtcreg; int32_t crtcreg;
uint8_t mode; uint8_t mode;
uint8_t status; uint8_t status;
uint64_t dispontime; uint64_t dispontime;
uint64_t dispofftime; uint64_t dispofftime;
pc_timer_t timer; pc_timer_t timer;
int firstline; int32_t firstline;
int lastline; int32_t lastline;
int fontbase; int32_t fontbase;
int linepos; int32_t linepos;
int displine; int32_t displine;
int vc; int32_t vc;
int scanline; int32_t scanline;
uint16_t memaddr; uint16_t memaddr;
uint16_t memaddr_backup; uint16_t memaddr_backup;
int cursorvisible; int32_t cursorvisible;
int cursoron; int32_t cursoron;
int dispon; int32_t dispon;
int blink; int32_t blink;
int vsynctime; int32_t vsynctime;
int vadj; int32_t vadj;
int monitor_index; int32_t monitor_index;
int prev_monitor_index; int32_t prev_monitor_index;
int32_t monitor_type; // Used for MDA Colour support (REV0 u64)
uint8_t *vram; uint8_t *vram;
} mda_t; } mda_t;

View File

@@ -188,6 +188,10 @@ extern bitmap_t *buffer32;
#define efscrnsz_y (monitors[monitor_index_global].mon_efscrnsz_y) #define efscrnsz_y (monitors[monitor_index_global].mon_efscrnsz_y)
#define unscaled_size_x (monitors[monitor_index_global].mon_unscaled_size_x) #define unscaled_size_x (monitors[monitor_index_global].mon_unscaled_size_x)
#define unscaled_size_y (monitors[monitor_index_global].mon_unscaled_size_y) #define unscaled_size_y (monitors[monitor_index_global].mon_unscaled_size_y)
#define CGAPAL_CGA_START 16 // Where the 16-color cga text/composite starts
extern PALETTE cgapal; extern PALETTE cgapal;
extern PALETTE cgapal_mono[6]; extern PALETTE cgapal_mono[6];
#if 0 #if 0

View File

@@ -15,10 +15,39 @@
# #
add_library(vid OBJECT add_library(vid OBJECT
# Video Core
agpgart.c agpgart.c
video.c video.c
vid_table.c vid_table.c
# CGA
# RAMDAC (Should this be its own library?)
ramdac/vid_ramdac_ati68860.c
ramdac/vid_ramdac_ati68875.c
ramdac/vid_ramdac_att20c49x.c
ramdac/vid_ramdac_att2xc498.c
ramdac/vid_ramdac_bt48x.c
ramdac/vid_ramdac_bt481.c
ramdac/vid_ramdac_ibm_rgb528.c
ramdac/vid_ramdac_sc1148x.c
ramdac/vid_ramdac_sc1502x.c
ramdac/vid_ramdac_sdac.c
ramdac/vid_ramdac_stg1702.c
ramdac/vid_ramdac_tkd8001.c
ramdac/vid_ramdac_tvp3026.c
# Clock generator chips
clockgen/vid_clockgen_av9194.c
clockgen/vid_clockgen_icd2061.c
clockgen/vid_clockgen_ics2494.c
clockgen/vid_clockgen_ics2595.c
# DDC / monitor identification stuff
vid_ddc.c
# CARDS start here
# CGA / Super CGA
vid_cga.c vid_cga.c
vid_cga_comp.c vid_cga_comp.c
vid_cga_compaq.c vid_cga_compaq.c
@@ -32,64 +61,84 @@ add_library(vid OBJECT
# PCJr/Tandy # PCJr/Tandy
vid_pcjr.c vid_pcjr.c
vid_tandy.c vid_tandy.c
vid_mda.c vid_mda.c
# Hercules
vid_hercules.c vid_hercules.c
vid_hercules_plus.c vid_hercules_plus.c
vid_hercules_incolor.c vid_hercules_incolor.c
# Other early CGA-era cards
vid_genius.c vid_genius.c
vid_sigma.c
# PGC / IM1024 / WY700 high-resolution
vid_pgc.c vid_pgc.c
vid_im1024.c vid_im1024.c
vid_sigma.c
vid_wy700.c vid_wy700.c
# EGA
vid_ega.c vid_ega.c
vid_ega_render.c vid_ega_render.c
vid_svga.c vid_jega.c
vid_8514a.c
vid_svga_render.c # (Real IBM) VGA
vid_ddc.c
vid_vga.c vid_vga.c
# Super VGA core
vid_svga.c
vid_svga_render.c
# 8514/A, XGA and derivatives
vid_8514a.c
vid_xga.c
vid_ps55da2.c
# ATI Technologies
vid_ati_eeprom.c vid_ati_eeprom.c
vid_ati18800.c vid_ati18800.c
vid_ati28800.c vid_ati28800.c
vid_ati_mach8.c vid_ati_mach8.c
vid_ati_mach64.c vid_ati_mach64.c
vid_ati68875_ramdac.c
vid_ati68860_ramdac.c # Chips & Technologies
vid_bt481_ramdac.c
vid_bt48x_ramdac.c
vid_chips_69000.c vid_chips_69000.c
vid_av9194.c
vid_icd2061.c # Cirrus Logic
vid_ics2494.c
vid_ics2595.c
vid_cl54xx.c vid_cl54xx.c
# Tseng Labs
vid_et3000.c vid_et3000.c
vid_et4000.c vid_et4000.c
vid_sc1148x_ramdac.c
vid_sc1502x_ramdac.c
vid_et4000w32.c vid_et4000w32.c
vid_stg_ramdac.c
# Headland
vid_ht216.c vid_ht216.c
vid_oak_oti.c vid_oak_oti.c
# Paradise
vid_paradise.c vid_paradise.c
vid_rtg310x.c vid_rtg310x.c
vid_f82c425.c vid_f82c425.c
vid_ti_cf62011.c vid_ti_cf62011.c
vid_tvga.c vid_tgui9440.c
vid_tkd8001_ramdac.c # Trident
vid_att20c49x_ramdac.c vid_tvga.c
vid_s3.c vid_s3_virge.c vid_tgui9440.c
vid_ibm_rgb528_ramdac.c
vid_sdac_ramdac.c # S3 Graphics
vid_s3.c
vid_s3_virge.c
# Matrox
vid_mga.c vid_mga.c
vid_tvp3026_ramdac.c
vid_att2xc498_ramdac.c # NVidia (pending)
vid_xga.c
vid_bochs_vbe.c
vid_ps55da2.c
vid_jega.c
nv/nv_rivatimer.c nv/nv_rivatimer.c
# Generic
vid_bochs_vbe.c
) )
if(G100) if(G100)
@@ -100,6 +149,7 @@ if(XL24)
target_compile_definitions(vid PRIVATE USE_XL24) target_compile_definitions(vid PRIVATE USE_XL24)
endif() endif()
# 3Dfx Voodoo
add_library(voodoo OBJECT add_library(voodoo OBJECT
vid_voodoo.c vid_voodoo.c
vid_voodoo_banshee.c vid_voodoo_banshee.c

View File

@@ -261,38 +261,57 @@ void
ati68860_hwcursor_draw(svga_t *svga, int displine) ati68860_hwcursor_draw(svga_t *svga, int displine)
{ {
const ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) svga->ramdac; const ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) svga->ramdac;
int comb;
int offset; int offset;
uint8_t dat; int x_pos;
int y_pos;
int shift = 0;
uint16_t dat;
uint32_t col0 = ramdac->pallook[0]; uint32_t col0 = ramdac->pallook[0];
uint32_t col1 = ramdac->pallook[1]; uint32_t col1 = ramdac->pallook[1];
uint32_t *p;
offset = svga->dac_hwcursor_latch.xoff; offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff;
for (uint32_t x = 0; x < 64 - svga->dac_hwcursor_latch.xoff; x += 4) { if (svga->packed_4bpp)
dat = svga->vram[svga->dac_hwcursor_latch.addr + (offset >> 2)]; shift = 1;
if (!(dat & 2))
buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add] = (dat & 1) ? col1 : col0; for (int x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += (8 >> shift)) {
else if ((dat & 3) == 3) if (shift) {
buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add] ^= 0xFFFFFF; dat = svga->vram[(svga->dac_hwcursor_latch.addr) & svga->vram_mask] & 0x0f;
dat >>= 2; dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 1) & svga->vram_mask] << 4);
if (!(dat & 2)) dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 2) & svga->vram_mask] << 8);
buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 1] = (dat & 1) ? col1 : col0; dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 3) & svga->vram_mask] << 12);
else if ((dat & 3) == 3) } else {
buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 1] ^= 0xFFFFFF; dat = svga->vram[svga->dac_hwcursor_latch.addr & svga->vram_mask];
dat >>= 2; dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 1) & svga->vram_mask] << 8);
if (!(dat & 2)) }
buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 2] = (dat & 1) ? col1 : col0; for (int xx = 0; xx < (8 >> shift); xx++) {
else if ((dat & 3) == 3) comb = (dat >> (xx << 1)) & 0x03;
buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 2] ^= 0xFFFFFF;
dat >>= 2; y_pos = displine;
if (!(dat & 2)) x_pos = offset + svga->x_add;
buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 3] = (dat & 1) ? col1 : col0; p = buffer32->line[y_pos];
else if ((dat & 3) == 3)
buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 3] ^= 0xFFFFFF; if (offset >= svga->dac_hwcursor_latch.x) {
dat >>= 2; switch (comb) {
offset += 4; case 0:
p[x_pos] = col0;
break;
case 1:
p[x_pos] = col1;
break;
case 3:
p[x_pos] ^= 0xffffff;
break;
default:
break;
}
}
offset++;
}
svga->dac_hwcursor_latch.addr += 2;
} }
svga->dac_hwcursor_latch.addr += 16;
} }
static void static void

View File

@@ -524,14 +524,18 @@ mach64_recalctimings(svga_t *svga)
svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1; svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1;
svga->rowoffset = (mach64->crtc_off_pitch >> 22); svga->rowoffset = (mach64->crtc_off_pitch >> 22);
svga->clock = (cpuclock * (double) (1ULL << 32)) / ics2595_getclock(svga->clock_gen); svga->clock = (cpuclock * (double) (1ULL << 32)) / ics2595_getclock(svga->clock_gen);
svga->memaddr_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; svga->memaddr_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2;
svga->linedbl = svga->rowcount = 0; svga->linedbl = svga->rowcount = 0;
svga->split = 0xffffff; svga->split = 0xffffff;
svga->vblankstart = svga->dispend; svga->vblankstart = svga->dispend;
svga->rowcount = mach64->crtc_gen_cntl & 1; svga->rowcount = mach64->crtc_gen_cntl & 1;
svga->rowoffset <<= 1; svga->rowoffset <<= 1;
if (mach64->type == MACH64_GX) if (mach64->type == MACH64_GX)
ati68860_ramdac_set_render(svga->ramdac, svga); ati68860_ramdac_set_render(svga->ramdac, svga);
svga->packed_4bpp = !!(((mach64->crtc_gen_cntl >> 8) & 7) == BPP_4);
switch ((mach64->crtc_gen_cntl >> 8) & 7) { switch ((mach64->crtc_gen_cntl >> 8) & 7) {
case BPP_4: case BPP_4:
if (mach64->type != MACH64_GX) if (mach64->type != MACH64_GX)
@@ -572,8 +576,9 @@ mach64_recalctimings(svga_t *svga)
} }
svga->vram_display_mask = mach64->vram_mask; svga->vram_display_mask = mach64->vram_mask;
} else } else {
svga->vram_display_mask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff; svga->vram_display_mask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff;
}
} }
void void
@@ -2310,6 +2315,7 @@ uint8_t
mach64_ext_readb(uint32_t addr, void *priv) mach64_ext_readb(uint32_t addr, void *priv)
{ {
mach64_t *mach64 = (mach64_t *) priv; mach64_t *mach64 = (mach64_t *) priv;
svga_t *svga = &mach64->svga;
uint8_t ret = 0xff; uint8_t ret = 0xff;
if (!(addr & 0x400)) { if (!(addr & 0x400)) {
@@ -2524,8 +2530,22 @@ mach64_ext_readb(uint32_t addr, void *priv)
case 0xc3: case 0xc3:
if (mach64->type == MACH64_GX) if (mach64->type == MACH64_GX)
ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), mach64->svga.ramdac, &mach64->svga); ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), mach64->svga.ramdac, &mach64->svga);
else else {
ret = ati68860_ramdac_in(addr & 3, mach64->svga.ramdac, &mach64->svga); switch (addr & 3) {
case 0:
ret = svga_in(0x3c8, svga);
break;
case 1:
ret = svga_in(0x3c9, svga);
break;
case 2:
ret = svga_in(0x3c6, svga);
break;
case 3:
ret = svga_in(0x3c7, svga);
break;
}
}
break; break;
case 0xc4: case 0xc4:
case 0xc5: case 0xc5:
@@ -2962,7 +2982,7 @@ mach64_ext_readl(uint32_t addr, void *priv)
uint32_t ret; uint32_t ret;
if (!(addr & 0x400)) { if (!(addr & 0x400)) {
mach64_log("nmach64_ext_readl: addr=%04x\n", addr); mach64_log("mach64_ext_readl: addr=%04x\n", addr);
ret = 0xffffffff; ret = 0xffffffff;
} else } else
switch (addr & 0x3ff) { switch (addr & 0x3ff) {
@@ -3101,6 +3121,7 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv)
} else if (addr & 0x300) { } else if (addr & 0x300) {
mach64_queue(mach64, addr & 0x3ff, val, FIFO_WRITE_BYTE); mach64_queue(mach64, addr & 0x3ff, val, FIFO_WRITE_BYTE);
} else { } else {
mach64_log("mach64_ext_writeb: addr=%04x val=%02x\n", addr & 0x3ff, val);
switch (addr & 0x3ff) { switch (addr & 0x3ff) {
case 0x00: case 0x00:
case 0x01: case 0x01:
@@ -3189,39 +3210,48 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv)
case 0x62: case 0x62:
case 0x63: case 0x63:
WRITE8(addr, mach64->cur_clr0, val); WRITE8(addr, mach64->cur_clr0, val);
if (mach64->type == MACH64_VT2)
ati68860_ramdac_set_pallook(mach64->svga.ramdac, 0, makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff));
break; break;
case 0x64: case 0x64:
case 0x65: case 0x65:
case 0x66: case 0x66:
case 0x67: case 0x67:
WRITE8(addr, mach64->cur_clr1, val); WRITE8(addr, mach64->cur_clr1, val);
if (mach64->type == MACH64_VT2)
ati68860_ramdac_set_pallook(mach64->svga.ramdac, 1, makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff));
break; break;
case 0x68: case 0x68:
case 0x69: case 0x69:
case 0x6a: case 0x6a:
case 0x6b: case 0x6b:
WRITE8(addr, mach64->cur_offset, val); WRITE8(addr, mach64->cur_offset, val);
svga->dac_hwcursor.addr = (mach64->cur_offset & 0xfffff) * 8; if (mach64->type == MACH64_GX)
svga->dac_hwcursor.addr = (mach64->cur_offset & 0xfffff) << 3;
else
svga->hwcursor.addr = (mach64->cur_offset & 0xfffff) << 3;
break; break;
case 0x6c: case 0x6c:
case 0x6d: case 0x6d:
case 0x6e: case 0x6e:
case 0x6f: case 0x6f:
WRITE8(addr, mach64->cur_horz_vert_posn, val); WRITE8(addr, mach64->cur_horz_vert_posn, val);
svga->dac_hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff; if (mach64->type == MACH64_GX) {
svga->dac_hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff; svga->dac_hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff;
svga->dac_hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff;
} else {
svga->hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff;
svga->hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff;
}
break; break;
case 0x70: case 0x70:
case 0x71: case 0x71:
case 0x72: case 0x72:
case 0x73: case 0x73:
WRITE8(addr, mach64->cur_horz_vert_off, val); WRITE8(addr, mach64->cur_horz_vert_off, val);
svga->dac_hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f; if (mach64->type == MACH64_GX) {
svga->dac_hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f; svga->dac_hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f;
svga->dac_hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f;
} else {
svga->hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f;
svga->hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f;
}
break; break;
case 0x80: case 0x80:
@@ -3283,8 +3313,22 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv)
case 0xc3: case 0xc3:
if (mach64->type == MACH64_GX) if (mach64->type == MACH64_GX)
ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, svga->ramdac, svga); ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, svga->ramdac, svga);
else else {
ati68860_ramdac_out(addr & 3, val, svga->ramdac, svga); switch (addr & 3) {
case 0:
svga_out(0x3c8, val, svga);
break;
case 1:
svga_out(0x3c9, val, svga);
break;
case 2:
svga_out(0x3c6, val, svga);
break;
case 3:
svga_out(0x3c7, val, svga);
break;
}
}
break; break;
case 0xc4: case 0xc4:
case 0xc5: case 0xc5:
@@ -3294,7 +3338,8 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv)
mach64_log("Ext RAMDAC TYPE write=%x, bit set=%03x.\n", addr & 0x3ff, mach64->dac_cntl & 0x100); mach64_log("Ext RAMDAC TYPE write=%x, bit set=%03x.\n", addr & 0x3ff, mach64->dac_cntl & 0x100);
if ((addr & 3) >= 1) { if ((addr & 3) >= 1) {
svga_set_ramdac_type(svga, !!(mach64->dac_cntl & 0x100)); svga_set_ramdac_type(svga, !!(mach64->dac_cntl & 0x100));
ati68860_set_ramdac_type(svga->ramdac, !!(mach64->dac_cntl & 0x100)); if (mach64->type == MACH64_GX)
ati68860_set_ramdac_type(svga->ramdac, !!(mach64->dac_cntl & 0x100));
} }
i2c_gpio_set(mach64->i2c, !(mach64->dac_cntl & 0x20000000) || (mach64->dac_cntl & 0x04000000), !(mach64->dac_cntl & 0x10000000) || (mach64->dac_cntl & 0x02000000)); i2c_gpio_set(mach64->i2c, !(mach64->dac_cntl & 0x20000000) || (mach64->dac_cntl & 0x04000000), !(mach64->dac_cntl & 0x10000000) || (mach64->dac_cntl & 0x02000000));
break; break;
@@ -3306,7 +3351,10 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv)
WRITE8(addr, mach64->gen_test_cntl, val); WRITE8(addr, mach64->gen_test_cntl, val);
ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1); ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1);
mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0); mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0);
svga->dac_hwcursor.ena = mach64->gen_test_cntl & 0x80; if (mach64->type == MACH64_GX)
svga->dac_hwcursor.ena = !!(mach64->gen_test_cntl & 0x80);
else
svga->hwcursor.ena = !!(mach64->gen_test_cntl & 0x80);
break; break;
case 0xdc: case 0xdc:
@@ -3371,6 +3419,7 @@ uint8_t
mach64_ext_inb(uint16_t port, void *priv) mach64_ext_inb(uint16_t port, void *priv)
{ {
mach64_t *mach64 = (mach64_t *) priv; mach64_t *mach64 = (mach64_t *) priv;
svga_t *svga = &mach64->svga;
uint8_t ret = 0xff; uint8_t ret = 0xff;
switch (port) { switch (port) {
@@ -3384,6 +3433,12 @@ mach64_ext_inb(uint16_t port, void *priv)
case 0x7eef: case 0x7eef:
ret = mach64_ext_readb(0x400 | 0x00 | (port & 3), priv); ret = mach64_ext_readb(0x400 | 0x00 | (port & 3), priv);
break; break;
case 0x06ec:
case 0x06ed:
case 0x06ee:
case 0x06ef:
ret = mach64_ext_readb(0x400 | 0x04 | (port & 3), priv);
break;
case 0x0aec: case 0x0aec:
case 0x0aed: case 0x0aed:
case 0x0aee: case 0x0aee:
@@ -3519,8 +3574,22 @@ mach64_ext_inb(uint16_t port, void *priv)
case 0x5eef: case 0x5eef:
if (mach64->type == MACH64_GX) if (mach64->type == MACH64_GX)
ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), mach64->svga.ramdac, &mach64->svga); ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), mach64->svga.ramdac, &mach64->svga);
else else {
ret = ati68860_ramdac_in(port & 3, mach64->svga.ramdac, &mach64->svga); switch (port & 3) {
case 0:
ret = svga_in(0x3c8, svga);
break;
case 1:
ret = svga_in(0x3c9, svga);
break;
case 2:
ret = svga_in(0x3c6, svga);
break;
case 3:
ret = svga_in(0x3c7, svga);
break;
}
}
break; break;
case 0x62ec: case 0x62ec:
@@ -3617,6 +3686,12 @@ mach64_ext_outb(uint16_t port, uint8_t val, void *priv)
case 0x7eef: case 0x7eef:
mach64_ext_writeb(0x400 | 0x00 | (port & 3), val, priv); mach64_ext_writeb(0x400 | 0x00 | (port & 3), val, priv);
break; break;
case 0x06ec:
case 0x06ed:
case 0x06ee:
case 0x06ef:
mach64_ext_writeb(0x400 | 0x04 | (port & 3), val, priv);
break;
case 0x0aec: case 0x0aec:
case 0x0aed: case 0x0aed:
case 0x0aee: case 0x0aee:
@@ -3745,8 +3820,22 @@ mach64_ext_outb(uint16_t port, uint8_t val, void *priv)
case 0x5eef: case 0x5eef:
if (mach64->type == MACH64_GX) if (mach64->type == MACH64_GX)
ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, svga->ramdac, svga); ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, svga->ramdac, svga);
else else {
ati68860_ramdac_out(port & 3, val, svga->ramdac, svga); switch (port & 3) {
case 0:
svga_out(0x3c8, val, svga);
break;
case 1:
svga_out(0x3c9, val, svga);
break;
case 2:
svga_out(0x3c6, val, svga);
break;
case 3:
svga_out(0x3c7, val, svga);
break;
}
}
break; break;
case 0x62ec: case 0x62ec:
@@ -3905,6 +3994,63 @@ mach64_readl(uint32_t addr, void *priv)
return ret; return ret;
} }
void
mach64_int_hwcursor_draw(svga_t *svga, int displine)
{
const mach64_t *mach64 = (mach64_t *) svga->priv;
int comb;
int offset;
int x_pos;
int y_pos;
int shift = 0;
uint16_t dat;
uint32_t col0 = makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff);
uint32_t col1 = makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff);
uint32_t *p;
offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff;
if (svga->packed_4bpp)
shift = 1;
for (int x = 0; x < svga->hwcursor_latch.cur_xsize; x += (8 >> shift)) {
if (shift) {
dat = svga->vram[(svga->hwcursor_latch.addr) & svga->vram_mask] & 0x0f;
dat |= (svga->vram[(svga->hwcursor_latch.addr + 1) & svga->vram_mask] << 4);
dat |= (svga->vram[(svga->hwcursor_latch.addr + 2) & svga->vram_mask] << 8);
dat |= (svga->vram[(svga->hwcursor_latch.addr + 3) & svga->vram_mask] << 12);
} else {
dat = svga->vram[svga->hwcursor_latch.addr & svga->vram_mask];
dat |= (svga->vram[(svga->hwcursor_latch.addr + 1) & svga->vram_mask] << 8);
}
for (int xx = 0; xx < (8 >> shift); xx++) {
comb = (dat >> (xx << 1)) & 0x03;
y_pos = displine;
x_pos = offset + svga->x_add;
p = buffer32->line[y_pos];
if (offset >= svga->hwcursor_latch.x) {
switch (comb) {
case 0:
p[x_pos] = col0;
break;
case 1:
p[x_pos] = col1;
break;
case 3:
p[x_pos] ^= 0xffffff;
break;
default:
break;
}
}
offset++;
}
svga->hwcursor_latch.addr += 2;
}
}
#define CLAMP(x) \ #define CLAMP(x) \
do { \ do { \
if ((x) & ~0xff) \ if ((x) & ~0xff) \
@@ -4550,15 +4696,22 @@ mach64_common_init(const device_t *info)
svga = &mach64->svga; svga = &mach64->svga;
mach64->type = info->local & 0xff;
mach64->vram_size = device_get_config_int("memory"); mach64->vram_size = device_get_config_int("memory");
mach64->vram_mask = (mach64->vram_size << 20) - 1; mach64->vram_mask = (mach64->vram_size << 20) - 1;
svga_init(info, svga, mach64, mach64->vram_size << 20, if (mach64->type > MACH64_GX)
mach64_recalctimings, svga_init(info, svga, mach64, mach64->vram_size << 20,
mach64_in, mach64_out, mach64_recalctimings,
NULL, mach64_in, mach64_out,
mach64_overlay_draw); mach64_int_hwcursor_draw,
svga->dac_hwcursor.cur_ysize = 64; mach64_overlay_draw);
else
svga_init(info, svga, mach64, mach64->vram_size << 20,
mach64_recalctimings,
mach64_in, mach64_out,
NULL,
mach64_overlay_draw);
mem_mapping_add(&mach64->linear_mapping, 0, 0, mach64_read_linear, mach64_readw_linear, mach64_readl_linear, mach64_write_linear, mach64_writew_linear, mach64_writel_linear, NULL, MEM_MAPPING_EXTERNAL, svga); mem_mapping_add(&mach64->linear_mapping, 0, 0, mach64_read_linear, mach64_readw_linear, mach64_readl_linear, mach64_write_linear, mach64_writew_linear, mach64_writel_linear, NULL, MEM_MAPPING_EXTERNAL, svga);
mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64);
@@ -4576,9 +4729,6 @@ mach64_common_init(const device_t *info)
mach64->pci_regs[0x32] = 0x0c; mach64->pci_regs[0x32] = 0x0c;
mach64->pci_regs[0x33] = 0x00; mach64->pci_regs[0x33] = 0x00;
svga->ramdac = device_add(&ati68860_ramdac_device);
svga->dac_hwcursor_draw = ati68860_hwcursor_draw;
svga->clock_gen = device_add(&ics2595_device); svga->clock_gen = device_add(&ics2595_device);
mach64->dst_cntl = 3; mach64->dst_cntl = 3;
@@ -4598,6 +4748,13 @@ static void *
mach64gx_init(const device_t *info) mach64gx_init(const device_t *info)
{ {
mach64_t *mach64 = mach64_common_init(info); mach64_t *mach64 = mach64_common_init(info);
svga_t *svga = &mach64->svga;
svga->ramdac = device_add(&ati68860_ramdac_device);
svga->dac_hwcursor_draw = ati68860_hwcursor_draw;
svga->dac_hwcursor.cur_ysize = 64;
svga->dac_hwcursor.cur_xsize = 64;
if (info->flags & DEVICE_ISA16) if (info->flags & DEVICE_ISA16)
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_isa); video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_isa);
@@ -4606,12 +4763,11 @@ mach64gx_init(const device_t *info)
else else
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_vlb); video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_vlb);
mach64->type = MACH64_GX;
mach64->pci = !!(info->flags & DEVICE_PCI); mach64->pci = !!(info->flags & DEVICE_PCI);
mach64->pci_id = 'X' | ('G' << 8); mach64->pci_id = 'X' | ('G' << 8);
mach64->config_chip_id = 0x000000d7; mach64->config_chip_id = 0x000000d7;
mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/
mach64->config_stat0 = (5 << 9) | (3 << 3); /*ATI-68860, 256Kx16 DRAM*/ mach64->config_stat0 = (5 << 9) | (3 << 3); /*ATI 68860, 256Kx16 DRAM*/
if (info->flags & DEVICE_PCI) { if (info->flags & DEVICE_PCI) {
mach64->config_stat0 |= 7; /*PCI, 256Kx16 DRAM*/ mach64->config_stat0 |= 7; /*PCI, 256Kx16 DRAM*/
ati_eeprom_load(&mach64->eeprom, "mach64_pci.nvr", 1); ati_eeprom_load(&mach64->eeprom, "mach64_pci.nvr", 1);
@@ -4635,9 +4791,13 @@ mach64vt2_init(const device_t *info)
mach64_t *mach64 = mach64_common_init(info); mach64_t *mach64 = mach64_common_init(info);
svga_t *svga = &mach64->svga; svga_t *svga = &mach64->svga;
svga->dac_hwcursor_draw = NULL;
svga->hwcursor.cur_ysize = 64;
svga->hwcursor.cur_xsize = 64;
video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_pci); video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_pci);
mach64->type = MACH64_VT2;
mach64->pci = 1; mach64->pci = 1;
mach64->pci_id = 0x5654; mach64->pci_id = 0x5654;
mach64->config_chip_id = 0x40005654; mach64->config_chip_id = 0x40005654;
@@ -4757,7 +4917,7 @@ const device_t mach64gx_isa_device = {
.name = "ATI Mach64GX ISA", .name = "ATI Mach64GX ISA",
.internal_name = "mach64gx_isa", .internal_name = "mach64gx_isa",
.flags = DEVICE_ISA16, .flags = DEVICE_ISA16,
.local = 0, .local = MACH64_GX,
.init = mach64gx_init, .init = mach64gx_init,
.close = mach64_close, .close = mach64_close,
.reset = NULL, .reset = NULL,
@@ -4771,7 +4931,7 @@ const device_t mach64gx_vlb_device = {
.name = "ATI Mach64GX VLB", .name = "ATI Mach64GX VLB",
.internal_name = "mach64gx_vlb", .internal_name = "mach64gx_vlb",
.flags = DEVICE_VLB, .flags = DEVICE_VLB,
.local = 0, .local = MACH64_GX,
.init = mach64gx_init, .init = mach64gx_init,
.close = mach64_close, .close = mach64_close,
.reset = NULL, .reset = NULL,
@@ -4785,7 +4945,7 @@ const device_t mach64gx_pci_device = {
.name = "ATI Mach64GX PCI", .name = "ATI Mach64GX PCI",
.internal_name = "mach64gx_pci", .internal_name = "mach64gx_pci",
.flags = DEVICE_PCI, .flags = DEVICE_PCI,
.local = 0, .local = MACH64_GX,
.init = mach64gx_init, .init = mach64gx_init,
.close = mach64_close, .close = mach64_close,
.reset = NULL, .reset = NULL,
@@ -4799,7 +4959,7 @@ const device_t mach64vt2_device = {
.name = "ATI Mach64VT2", .name = "ATI Mach64VT2",
.internal_name = "mach64vt2", .internal_name = "mach64vt2",
.flags = DEVICE_PCI, .flags = DEVICE_PCI,
.local = 0, .local = MACH64_VT2,
.init = mach64vt2_init, .init = mach64vt2_init,
.close = mach64_close, .close = mach64_close,
.reset = NULL, .reset = NULL,

View File

@@ -817,6 +817,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3
dev->accel.dy |= ~0x5ff; dev->accel.dy |= ~0x5ff;
/*Destination Width*/ /*Destination Width*/
mach->accel.dx_first_row_start = dev->accel.cur_x;
if (dev->accel.cur_x >= 0x600)
mach->accel.dx_first_row_start |= ~0x5ff;
mach->accel.dx_start = mach->accel.dest_x_start; mach->accel.dx_start = mach->accel.dest_x_start;
if (mach->accel.dest_x_start >= 0x600) if (mach->accel.dest_x_start >= 0x600)
mach->accel.dx_start |= ~0x5ff; mach->accel.dx_start |= ~0x5ff;
@@ -831,16 +835,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3
} else if (mach->accel.dx_end < mach->accel.dx_start) { } else if (mach->accel.dx_end < mach->accel.dx_start) {
mach->accel.width = (mach->accel.dx_start - mach->accel.dx_end); mach->accel.width = (mach->accel.dx_start - mach->accel.dx_end);
mach->accel.stepx = -1; mach->accel.stepx = -1;
if (dev->accel.dx > 0)
dev->accel.dx--;
mach_log("BitBLT: Dst Negative X, dxstart = %d, end = %d, width = %d, dx = %d, dpconfig = %04x.\n",
mach->accel.dest_x_start, mach->accel.dest_x_end, mach->accel.width, dev->accel.dx,
mach->accel.dp_config);
} else { } else {
mach->accel.stepx = 1; mach->accel.stepx = 1;
mach->accel.width = 0; mach->accel.width = 0;
mach_log("BitBLT: Dst Indeterminate X, dpconfig = %04x, destxend = %d, destxstart = %d.\n",
mach->accel.dp_config, mach->accel.dest_x_end, mach->accel.dest_x_start);
} }
dev->accel.sx = 0; dev->accel.sx = 0;
@@ -869,6 +866,24 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3
if (mach->accel.dp_config == 0x4011) if (mach->accel.dp_config == 0x4011)
mach->accel.height++; mach->accel.height++;
if (mach->accel.height == 1) {
if (mach->accel.dx_end > mach->accel.dx_first_row_start) {
mach->accel.width = (mach->accel.dx_end - mach->accel.dx_first_row_start);
mach->accel.stepx = 1;
} else if (mach->accel.dx_end < mach->accel.dx_first_row_start) {
mach->accel.width = (mach->accel.dx_first_row_start - mach->accel.dx_end);
mach->accel.stepx = -1;
} else {
mach->accel.stepx = 1;
mach->accel.width = 0;
}
}
if (mach->accel.stepx == -1) {
if (dev->accel.dx > 0)
dev->accel.dx--;
}
dev->accel.sy = 0; dev->accel.sy = 0;
dev->accel.dest = mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch); dev->accel.dest = mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch);
@@ -6475,6 +6490,7 @@ ati8514_io_set(svga_t *svga)
io_sethandler(0xeeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xeeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
io_sethandler(0xf2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xf2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
io_sethandler(0xf6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xf6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
io_sethandler(0xfaee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
io_sethandler(0xfeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xfeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga);
} }

View File

@@ -6,7 +6,7 @@
* *
* This file is part of the 86Box distribution. * This file is part of the 86Box distribution.
* *
* MDA emulation. * IBM Monochrome Display and Printer Adapter emulation.
* *
* *
* *
@@ -18,6 +18,7 @@
* Copyright 2016-2025 Miran Grca. * Copyright 2016-2025 Miran Grca.
* Copyright 2025 starfrost / Connor Hyde * Copyright 2025 starfrost / Connor Hyde
*/ */
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@@ -35,6 +36,16 @@
#include <86box/vid_mda.h> #include <86box/vid_mda.h>
#include <86box/plat_unused.h> #include <86box/plat_unused.h>
// Enumerates MDA monitor types
enum mda_monitor_type_e {
MDA_MONITOR_TYPE_DEFAULT = 0, // Default MDA monitor type.
MDA_MONITOR_TYPE_GREEN = 1, // Green phosphor
MDA_MONITOR_TYPE_AMBER = 2, // Amber phosphor
MDA_MONITOR_TYPE_GRAY = 3, // Gray phosphor
MDA_MONITOR_TYPE_RGBI = 4, // RGBI colour monitor with modified rev1 or rev0 MDA card for colour support
} mda_monitor_type;
// [attr][blink][fg]
static int mda_attr_to_color_table[256][2][2]; static int mda_attr_to_color_table[256][2][2];
static video_timings_t timing_mda = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; static video_timings_t timing_mda = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 };
@@ -46,12 +57,11 @@ mda_out(uint16_t addr, uint8_t val, void *priv)
{ {
mda_t *mda = (mda_t *) priv; mda_t *mda = (mda_t *) priv;
if (addr < MDA_REGISTER_START if (addr < MDA_REGISTER_START
|| addr > MDA_REGISTER_CRT_STATUS) // Maintain old behaviour for printer registers, just in case || addr > MDA_REGISTER_CRT_STATUS) // Maintain old behaviour for printer registers, just in case
return; return;
switch (addr) switch (addr) {
{
case MDA_REGISTER_MODE_CONTROL: case MDA_REGISTER_MODE_CONTROL:
mda->mode = val; mda->mode = val;
return; return;
@@ -61,20 +71,17 @@ mda_out(uint16_t addr, uint8_t val, void *priv)
// addr & 1 == 1 = MDA_REGISTER_CRTC_DATA // addr & 1 == 1 = MDA_REGISTER_CRTC_DATA
// otherwise MDA_REGISTER_CRTC_INDEX // otherwise MDA_REGISTER_CRTC_INDEX
if (addr & 1) if (addr & 1) {
{
mda->crtc[mda->crtcreg] = val; mda->crtc[mda->crtcreg] = val;
if (mda->crtc[MDA_CRTC_CURSOR_START] == 6 if (mda->crtc[MDA_CRTC_CURSOR_START] == 6
&& mda->crtc[MDA_CRTC_CURSOR_END] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ && mda->crtc[MDA_CRTC_CURSOR_END] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/
{ {
mda->crtc[MDA_CRTC_CURSOR_START] = 0xb; mda->crtc[MDA_CRTC_CURSOR_START] = 0xb;
mda->crtc[MDA_CRTC_CURSOR_END] = 0xc; mda->crtc[MDA_CRTC_CURSOR_END] = 0xc;
} }
mda_recalctimings(mda); mda_recalctimings(mda);
} } else
else
mda->crtcreg = val & 31; mda->crtcreg = val & 31;
} }
uint8_t uint8_t
@@ -82,19 +89,18 @@ mda_in(uint16_t addr, void *priv)
{ {
const mda_t *mda = (mda_t *) priv; const mda_t *mda = (mda_t *) priv;
switch (addr) switch (addr) {
{
case MDA_REGISTER_CRT_STATUS: case MDA_REGISTER_CRT_STATUS:
return mda->status | 0xF0; return mda->status | 0xF0;
default: default:
if (addr < MDA_REGISTER_START if (addr < MDA_REGISTER_START
|| addr > MDA_REGISTER_CRT_STATUS) // Maintain old behaviour for printer registers, just in case || addr > MDA_REGISTER_CRT_STATUS) // Maintain old behaviour for printer registers, just in case
return 0xFF; return 0xFF;
// MDA_REGISTER_CRTC_DATA // MDA_REGISTER_CRTC_DATA
if (addr & 1) if (addr & 1)
return mda->crtc[mda->crtcreg]; return mda->crtc[mda->crtcreg];
else else
return mda->crtcreg; return mda->crtcreg;
break; break;
@@ -136,51 +142,133 @@ mda_recalctimings(mda_t *mda)
void void
mda_poll(void *priv) mda_poll(void *priv)
{ {
mda_t *mda = (mda_t *) priv; mda_t *mda = (mda_t *) priv;
uint16_t cursoraddr = (mda->crtc[MDA_CRTC_CURSOR_ADDR_LOW] | (mda->crtc[MDA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; uint16_t cursoraddr = (mda->crtc[MDA_CRTC_CURSOR_ADDR_LOW] | (mda->crtc[MDA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff;
int drawcursor; bool drawcursor;
int x; int32_t oldvc;
int c;
int oldvc;
uint8_t chr; uint8_t chr;
uint8_t attr; uint8_t attr;
int scanline_old; int32_t scanline_old;
int blink; int32_t blink;
VIDEO_MONITOR_PROLOGUE() VIDEO_MONITOR_PROLOGUE()
if (!mda->linepos) { if (!mda->linepos) {
timer_advance_u64(&mda->timer, mda->dispofftime); timer_advance_u64(&mda->timer, mda->dispofftime);
mda->status |= 1; mda->status |= 1;
mda->linepos = 1; mda->linepos = 1;
scanline_old = mda->scanline; scanline_old = mda->scanline;
if ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3) if ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3)
mda->scanline = (mda->scanline << 1) & 7; mda->scanline = (mda->scanline << 1) & 7;
if (mda->dispon) { if (mda->dispon) {
if (mda->displine < mda->firstline) { if (mda->displine < mda->firstline) {
mda->firstline = mda->displine; mda->firstline = mda->displine;
video_wait_for_buffer(); video_wait_for_buffer();
} }
mda->lastline = mda->displine; mda->lastline = mda->displine;
for (x = 0; x < mda->crtc[MDA_CRTC_HDISP]; x++) {
for (uint32_t x = 0; x < mda->crtc[MDA_CRTC_HDISP]; x++) {
chr = mda->vram[(mda->memaddr << 1) & 0xfff]; chr = mda->vram[(mda->memaddr << 1) & 0xfff];
attr = mda->vram[((mda->memaddr << 1) + 1) & 0xfff]; attr = mda->vram[((mda->memaddr << 1) + 1) & 0xfff];
drawcursor = ((mda->memaddr == cursoraddr) && mda->cursorvisible && mda->cursoron); drawcursor = ((mda->memaddr == cursoraddr) && mda->cursorvisible && mda->cursoron);
blink = ((mda->blink & 16) && (mda->mode & MDA_MODE_BLINK) && (attr & 0x80) && !drawcursor); blink = ((mda->blink & 16) && (mda->mode & MDA_MODE_BLINK) && (attr & 0x80) && !drawcursor);
if (mda->scanline == 12 && ((attr & 7) == 1)) {
for (c = 0; c < 9; c++) // Colours that will be used
buffer32->line[mda->displine][(x * 9) + c] = mda_attr_to_color_table[attr][blink][1]; int32_t color_bg = 0, color_fg = 0;
} else {
for (c = 0; c < 8; c++) // If we are using an RGBI monitor allow colour
buffer32->line[mda->displine][(x * 9) + c] = mda_attr_to_color_table[attr][blink][(fontdatm[chr + mda->fontbase][mda->scanline] & (1 << (c ^ 7))) ? 1 : 0]; if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI
if ((chr & ~0x1f) == 0xc0) && !(mda->mode & MDA_MODE_BW)) {
buffer32->line[mda->displine][(x * 9) + 8] = mda_attr_to_color_table[attr][blink][fontdatm[chr + mda->fontbase][mda->scanline] & 1]; color_bg = (attr >> 4) & 0x0F;
else color_fg = (attr & 0x0F);
buffer32->line[mda->displine][(x * 9) + 8] = mda_attr_to_color_table[attr][blink][0];
// turn off bright bg colours in blink mode
if ((mda->mode & MDA_MODE_BLINK)
&& (color_bg & 0x8))
color_bg & ~(0x8);
// black-on-non black or white colours forced to white
// grey-on-colours forced to bright white
bool special_treatment = (color_bg != 0 && color_bg != 7);
if (color_fg == MDA_COLOR_GREY
&& special_treatment)
color_fg = MDA_COLOR_BRIGHT_WHITE;
if (color_fg == 0
&& special_treatment)
color_fg = MDA_COLOR_GREY;
// gray is black
if (color_fg == MDA_COLOR_GREY
&& (color_bg == MDA_COLOR_GREY || color_bg == MDA_COLOR_BLACK))
color_fg = MDA_COLOR_BLACK;
} }
if (mda->scanline == 12
&& ((attr & 7) == 1)) { // underline
for (uint32_t column = 0; column < 9; column++) {
if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI
&& !(mda->mode & MDA_MODE_BW)) {
buffer32->line[mda->displine][(x * 9) + column] = CGAPAL_CGA_START + color_fg;
} else
buffer32->line[mda->displine][(x * 9) + column] = mda_attr_to_color_table[attr][blink][1];
}
} else { // character
for (uint32_t column = 0; column < 8; column++) {
// bg=0, fg=1
bool is_fg = (fontdatm[chr + mda->fontbase][mda->scanline] & (1 << (column ^ 7))) ? 1 : 0;
uint32_t font_char = mda_attr_to_color_table[attr][blink][is_fg];
if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI
&& !(mda->mode & MDA_MODE_BW)) {
if (!is_fg)
font_char = CGAPAL_CGA_START + color_bg;
else
font_char = CGAPAL_CGA_START + color_fg;
}
buffer32->line[mda->displine][(x * 9) + column] = font_char;
}
// these characters (C0-DF) have their background extended to their 9th column
if ((chr & ~0x1f) == 0xc0) {
bool is_fg = fontdatm[chr + mda->fontbase][mda->scanline] & 1;
uint32_t final_result = mda_attr_to_color_table[attr][blink][is_fg];
if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI
&& !(mda->mode & MDA_MODE_BW)) {
if (!is_fg)
final_result = CGAPAL_CGA_START + color_bg;
else
final_result = CGAPAL_CGA_START + color_fg;
}
buffer32->line[mda->displine][(x * 9) + 8] = final_result;
} else {
if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI
&& !(mda->mode & MDA_MODE_BW)) {
buffer32->line[mda->displine][(x * 9) + 8] = CGAPAL_CGA_START + color_bg;
} else
buffer32->line[mda->displine][(x * 9) + 8] = mda_attr_to_color_table[attr][blink][0];
}
}
mda->memaddr++; mda->memaddr++;
if (drawcursor) { if (drawcursor) {
for (c = 0; c < 9; c++) for (uint32_t column = 0; column < 9; column++) {
buffer32->line[mda->displine][(x * 9) + c] ^= mda_attr_to_color_table[attr][0][1]; if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI
&& !(mda->mode & MDA_MODE_BW)) {
buffer32->line[mda->displine][(x * 9) + column] ^= CGAPAL_CGA_START + color_fg;
} else
buffer32->line[mda->displine][(x * 9) + column] ^= mda_attr_to_color_table[attr][0][1];
}
} }
} }
@@ -198,33 +286,35 @@ mda_poll(void *priv)
if (mda->dispon) if (mda->dispon)
mda->status &= ~1; mda->status &= ~1;
mda->linepos = 0; mda->linepos = 0;
if (mda->vsynctime) { if (mda->vsynctime) {
mda->vsynctime--; mda->vsynctime--;
if (!mda->vsynctime) { if (!mda->vsynctime) {
mda->status &= ~8; mda->status &= ~8;
} }
} }
if (mda->scanline == (mda->crtc[MDA_CRTC_CURSOR_END] & 31) if (mda->scanline == (mda->crtc[MDA_CRTC_CURSOR_END] & 31)
|| ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3 || ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3
&& mda->scanline == ((mda->crtc[MDA_CRTC_CURSOR_END] & 31) >> 1))) { && mda->scanline == ((mda->crtc[MDA_CRTC_CURSOR_END] & 31) >> 1))) {
mda->cursorvisible = 0; mda->cursorvisible = 0;
} }
if (mda->vadj) { if (mda->vadj) {
mda->scanline++; mda->scanline++;
mda->scanline &= 31; mda->scanline &= 31;
mda->memaddr = mda->memaddr_backup; mda->memaddr = mda->memaddr_backup;
mda->vadj--; mda->vadj--;
if (!mda->vadj) { if (!mda->vadj) {
mda->dispon = 1; mda->dispon = 1;
mda->memaddr = mda->memaddr_backup = (mda->crtc[MDA_CRTC_START_ADDR_LOW] | (mda->crtc[MDA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; mda->memaddr = mda->memaddr_backup = (mda->crtc[MDA_CRTC_START_ADDR_LOW] | (mda->crtc[MDA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff;
mda->scanline = 0; mda->scanline = 0;
} }
} else if (mda->scanline == mda->crtc[MDA_CRTC_MAX_SCANLINE_ADDR] } else if (mda->scanline == mda->crtc[MDA_CRTC_MAX_SCANLINE_ADDR]
|| ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3 || ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3
&& mda->scanline == (mda->crtc[MDA_CRTC_MAX_SCANLINE_ADDR] >> 1))) { && mda->scanline == (mda->crtc[MDA_CRTC_MAX_SCANLINE_ADDR] >> 1))) {
mda->memaddr_backup = mda->memaddr; mda->memaddr_backup = mda->memaddr;
mda->scanline = 0; mda->scanline = 0;
oldvc = mda->vc; oldvc = mda->vc;
mda->vc++; mda->vc++;
mda->vc &= 127; mda->vc &= 127;
if (mda->vc == mda->crtc[MDA_CRTC_VDISP]) if (mda->vc == mda->crtc[MDA_CRTC_VDISP])
@@ -247,7 +337,7 @@ mda_poll(void *priv)
mda->displine = 0; mda->displine = 0;
mda->vsynctime = 16; mda->vsynctime = 16;
if (mda->crtc[MDA_CRTC_VSYNC]) { if (mda->crtc[MDA_CRTC_VSYNC]) {
x = mda->crtc[MDA_CRTC_HDISP] * 9; uint32_t x = mda->crtc[MDA_CRTC_HDISP] * 9;
mda->lastline++; mda->lastline++;
if ((x != xsize) || ((mda->lastline - mda->firstline) != ysize) || video_force_resize_get()) { if ((x != xsize) || ((mda->lastline - mda->firstline) != ysize) || video_force_resize_get()) {
xsize = x; xsize = x;
@@ -277,9 +367,9 @@ mda_poll(void *priv)
mda->memaddr = mda->memaddr_backup; mda->memaddr = mda->memaddr_backup;
} }
if (mda->scanline == (mda->crtc[MDA_CRTC_CURSOR_START] & 31) if (mda->scanline == (mda->crtc[MDA_CRTC_CURSOR_START] & 31)
|| ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3 || ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3
&& mda->scanline == ((mda->crtc[MDA_CRTC_CURSOR_START] & 31) >> 1))) { && mda->scanline == ((mda->crtc[MDA_CRTC_CURSOR_START] & 31) >> 1))) {
mda->cursorvisible = 1; mda->cursorvisible = 1;
} }
} }
@@ -289,21 +379,22 @@ mda_poll(void *priv)
void void
mda_init(mda_t *mda) mda_init(mda_t *mda)
{ {
for (uint16_t c = 0; c < 256; c++) {
mda_attr_to_color_table[c][0][0] = mda_attr_to_color_table[c][1][0] = mda_attr_to_color_table[c][1][1] = 16; for (uint16_t attr = 0; attr < 256; attr++) {
if (c & 8) mda_attr_to_color_table[attr][0][0] = mda_attr_to_color_table[attr][1][0] = mda_attr_to_color_table[attr][1][1] = 16;
mda_attr_to_color_table[c][0][1] = 15 + 16; if (attr & 8)
mda_attr_to_color_table[attr][0][1] = 15 + 16;
else else
mda_attr_to_color_table[c][0][1] = 7 + 16; mda_attr_to_color_table[attr][0][1] = 7 + 16;
} }
mda_attr_to_color_table[0x70][0][1] = 16; mda_attr_to_color_table[0x70][0][1] = 16;
mda_attr_to_color_table[0x70][0][0] = mda_attr_to_color_table[0x70][1][0] = mda_attr_to_color_table[0x70][1][1] = 16 + 15; mda_attr_to_color_table[0x70][0][0] = mda_attr_to_color_table[0x70][1][0] = mda_attr_to_color_table[0x70][1][1] = CGAPAL_CGA_START + 15;
mda_attr_to_color_table[0xF0][0][1] = 16; mda_attr_to_color_table[0xF0][0][1] = 16;
mda_attr_to_color_table[0xF0][0][0] = mda_attr_to_color_table[0xF0][1][0] = mda_attr_to_color_table[0xF0][1][1] = 16 + 15; mda_attr_to_color_table[0xF0][0][0] = mda_attr_to_color_table[0xF0][1][0] = mda_attr_to_color_table[0xF0][1][1] = CGAPAL_CGA_START + 15;
mda_attr_to_color_table[0x78][0][1] = 16 + 7; mda_attr_to_color_table[0x78][0][1] = CGAPAL_CGA_START + 7;
mda_attr_to_color_table[0x78][0][0] = mda_attr_to_color_table[0x78][1][0] = mda_attr_to_color_table[0x78][1][1] = 16 + 15; mda_attr_to_color_table[0x78][0][0] = mda_attr_to_color_table[0x78][1][0] = mda_attr_to_color_table[0x78][1][1] = CGAPAL_CGA_START + 15;
mda_attr_to_color_table[0xF8][0][1] = 16 + 7; mda_attr_to_color_table[0xF8][0][1] = CGAPAL_CGA_START + 7;
mda_attr_to_color_table[0xF8][0][0] = mda_attr_to_color_table[0xF8][1][0] = mda_attr_to_color_table[0xF8][1][1] = 16 + 15; mda_attr_to_color_table[0xF8][0][0] = mda_attr_to_color_table[0xF8][1][0] = mda_attr_to_color_table[0xF8][1][1] = CGAPAL_CGA_START + 15;
mda_attr_to_color_table[0x00][0][1] = mda_attr_to_color_table[0x00][1][1] = 16; mda_attr_to_color_table[0x00][0][1] = mda_attr_to_color_table[0x00][1][1] = 16;
mda_attr_to_color_table[0x08][0][1] = mda_attr_to_color_table[0x08][1][1] = 16; mda_attr_to_color_table[0x08][0][1] = mda_attr_to_color_table[0x08][1][1] = 16;
mda_attr_to_color_table[0x80][0][1] = mda_attr_to_color_table[0x80][1][1] = 16; mda_attr_to_color_table[0x80][0][1] = mda_attr_to_color_table[0x80][1][1] = 16;
@@ -312,7 +403,8 @@ mda_init(mda_t *mda)
overscan_x = overscan_y = 0; overscan_x = overscan_y = 0;
mda->monitor_index = monitor_index_global; mda->monitor_index = monitor_index_global;
cga_palette = device_get_config_int("rgb_type") << 1; mda->monitor_type = device_get_config_int("rgb_type");
cga_palette = mda->monitor_type << 1;
if (cga_palette > 6) { if (cga_palette > 6) {
cga_palette = 0; cga_palette = 0;
} }
@@ -330,7 +422,7 @@ mda_standalone_init(UNUSED(const device_t *info))
mda->vram = malloc(0x1000); mda->vram = malloc(0x1000);
switch(device_get_config_int("font")) { switch (device_get_config_int("font")) {
case 0: case 0:
loadfont(FONT_IBM_MDA_437_PATH, 0); loadfont(FONT_IBM_MDA_437_PATH, 0);
break; break;
@@ -369,7 +461,7 @@ mda_standalone_init(UNUSED(const device_t *info))
void void
mda_setcol(int chr, int blink, int fg, uint8_t cga_ink) mda_setcol(int chr, int blink, int fg, uint8_t cga_ink)
{ {
mda_attr_to_color_table[chr][blink][fg] = 16 + cga_ink; mda_attr_to_color_table[chr][blink][fg] = CGAPAL_CGA_START + cga_ink;
} }
void void
@@ -390,7 +482,7 @@ mda_speed_changed(void *priv)
} }
static const device_config_t mda_config[] = { static const device_config_t mda_config[] = {
// clang-format off // clang-format off
{ {
.name = "rgb_type", .name = "rgb_type",
.description = "Display type", .description = "Display type",
@@ -399,12 +491,14 @@ static const device_config_t mda_config[] = {
.default_int = 0, .default_int = 0,
.file_filter = NULL, .file_filter = NULL,
.spinner = { 0 }, .spinner = { 0 },
.selection = { .selection =
{ .description = "Default", .value = 0 }, {
{ .description = "Green", .value = 1 }, { .description = "Default", .value = MDA_MONITOR_TYPE_DEFAULT },
{ .description = "Amber", .value = 2 }, { .description = "Green", .value = MDA_MONITOR_TYPE_GREEN },
{ .description = "Gray", .value = 3 }, { .description = "Amber", .value = MDA_MONITOR_TYPE_AMBER },
{ .description = "" } { .description = "Gray", .value = MDA_MONITOR_TYPE_GRAY },
{ .description = "Generic RGBI color monitor", .value = MDA_MONITOR_TYPE_RGBI },
{ .description = "" }
}, },
.bios = { { 0 } } .bios = { { 0 } }
}, },
@@ -416,18 +510,19 @@ static const device_config_t mda_config[] = {
.default_int = 0, .default_int = 0,
.file_filter = NULL, .file_filter = NULL,
.spinner = { 0 }, .spinner = { 0 },
.selection = { .selection =
{ .description = "US (CP 437)", .value = 0 }, {
{ .description = "US (CP 437)", .value = 0 },
{ .description = "IBM Nordic (CP 437-Nordic)", .value = 1 }, { .description = "IBM Nordic (CP 437-Nordic)", .value = 1 },
{ .description = "Czech Kamenicky (CP 895) #1", .value = 2 }, { .description = "Czech Kamenicky (CP 895) #1", .value = 2 },
{ .description = "Czech Kamenicky (CP 895) #2", .value = 3 }, { .description = "Czech Kamenicky (CP 895) #2", .value = 3 },
{ .description = "Tulip DGA", .value = 4 }, { .description = "Tulip DGA", .value = 4 },
{ .description = "" } { .description = "" }
}, },
.bios = { { 0 } } .bios = { { 0 } }
}, },
{ .name = "", .description = "", .type = CONFIG_END } { .name = "", .description = "", .type = CONFIG_END }
// clang-format on // clang-format on
}; };
const device_t mda_device = { const device_t mda_device = {
@@ -443,3 +538,4 @@ const device_t mda_device = {
.force_redraw = NULL, .force_redraw = NULL,
.config = mda_config .config = mda_config
}; };

View File

@@ -917,7 +917,7 @@ svga_recalctimings(svga_t *svga)
if (vblankend <= svga->vblankstart) if (vblankend <= svga->vblankstart)
vblankend += 0x00000080; vblankend += 0x00000080;
if (svga->hoverride) { if (svga->hoverride || svga->override) {
if (svga->hdisp >= 2048) if (svga->hdisp >= 2048)
svga->monitor->mon_overscan_x = 0; svga->monitor->mon_overscan_x = 0;
@@ -958,14 +958,18 @@ svga_recalctimings(svga_t *svga)
svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock);
svga->left_overscan = svga->x_add = (svga->htotal - adj_dot - 1) * svga->dots_per_clock; svga->left_overscan = svga->x_add = (svga->htotal - adj_dot - 1) * svga->dots_per_clock;
svga->monitor->mon_overscan_x = svga->x_add + (svga->hblankstart * svga->dots_per_clock) - hd; svga->monitor->mon_overscan_x = svga->x_add + (svga->hblankstart * svga->dots_per_clock) - hd + svga->dots_per_clock;
/* Compensate for the HDISP code above. */
if (svga->crtc[1] & 1)
svga->monitor->mon_overscan_x++;
if ((svga->hdisp >= 2048) || (svga->left_overscan < 0)) { if ((svga->hdisp >= 2048) || (svga->left_overscan < 0)) {
svga->left_overscan = svga->x_add = 0; svga->left_overscan = svga->x_add = 0;
svga->monitor->mon_overscan_x = 0; svga->monitor->mon_overscan_x = 0;
} }
svga->y_add = svga->vtotal - vblankend + 1; /* - 1 because + 1 but also - 2 to compensate for the + 2 added to vtotal above. */
svga->y_add = svga->vtotal - vblankend - 1;
svga->monitor->mon_overscan_y = svga->y_add + abs(svga->vblankstart - svga->dispend); svga->monitor->mon_overscan_y = svga->y_add + abs(svga->vblankstart - svga->dispend);
if ((svga->dispend >= 2048) || (svga->y_add < 0)) { if ((svga->dispend >= 2048) || (svga->y_add < 0)) {

View File

@@ -483,7 +483,7 @@ vid_poll(void *priv)
vid->memaddr++; vid->memaddr++;
if (vid->scanline & 8) { if (vid->scanline & 8) {
for (c = 0; c < 8; c++) for (c = 0; c < 8; c++)
buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = cols[0]; buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[0];
} else { } else {
for (c = 0; c < 8; c++) { for (c = 0; c < 8; c++) {
if (vid->scanline == 8) { if (vid->scanline == 8) {
@@ -824,4 +824,4 @@ const device_t tandy_1000sl_video_device = {
.speed_changed = tandy_vid_speed_changed, .speed_changed = tandy_vid_speed_changed,
.force_redraw = NULL, .force_redraw = NULL,
.config = NULL .config = NULL
}; };

View File

@@ -530,6 +530,7 @@ voodoo_writel(uint32_t addr, uint32_t val, void *priv)
voodoo_recalc(voodoo); voodoo_recalc(voodoo);
voodoo->front_offset = voodoo->params.front_offset; voodoo->front_offset = voodoo->params.front_offset;
} }
svga_recalctimings(voodoo->svga);
} }
break; break;
case SST_fbiInit1: case SST_fbiInit1: