ATI EGA Wonder 800+ fixes.
1. Reverted the migration from ATI 18800 as the EGA code had the proper palette. 2. Add support for the 800x600 resolution required by said card.
This commit is contained in:
@@ -109,6 +109,8 @@ typedef struct ega_t {
|
||||
int bpp;
|
||||
int index;
|
||||
int remap_required;
|
||||
int actual_type;
|
||||
int chipset;
|
||||
|
||||
uint32_t charseta;
|
||||
uint32_t charsetb;
|
||||
@@ -132,6 +134,8 @@ typedef struct ega_t {
|
||||
|
||||
double dot_clock;
|
||||
|
||||
void * eeprom;
|
||||
|
||||
uint32_t (*remap_func)(struct ega_t *ega, uint32_t in_addr);
|
||||
void (*render)(struct ega_t *svga);
|
||||
} ega_t;
|
||||
@@ -141,6 +145,7 @@ typedef struct ega_t {
|
||||
extern const device_t ega_device;
|
||||
extern const device_t cpqega_device;
|
||||
extern const device_t sega_device;
|
||||
extern const device_t atiega800p_device;
|
||||
extern const device_t iskra_ega_device;
|
||||
extern const device_t et2000_device;
|
||||
#endif
|
||||
|
@@ -322,7 +322,6 @@ extern const device_t ati18800_wonder_device;
|
||||
# endif
|
||||
extern const device_t ati18800_vga88_device;
|
||||
extern const device_t ati18800_device;
|
||||
extern const device_t ati18800_egawonder800plus_device;
|
||||
|
||||
/* ATi 28800 */
|
||||
extern const device_t ati28800_device;
|
||||
|
@@ -37,18 +37,15 @@
|
||||
#endif
|
||||
#define BIOS_ROM_PATH_VGA88 "roms/video/ati18800/vga88.bin"
|
||||
#define BIOS_ROM_PATH_EDGE16 "roms/video/ati18800/vgaedge16.vbi"
|
||||
#define BIOS_ROM_PATH_ATIEGAPLUS "roms/video/ati18800/ATI EGA Wonder 800+ N1.00.BIN"
|
||||
|
||||
enum {
|
||||
#if defined(DEV_BRANCH) && defined(USE_VGAWONDER)
|
||||
ATI18800_WONDER = 0,
|
||||
ATI18800_VGA88,
|
||||
ATI18800_EDGE16,
|
||||
ATI18800_EGAWONDER800PLUS
|
||||
ATI18800_EDGE16
|
||||
#else
|
||||
ATI18800_VGA88 = 0,
|
||||
ATI18800_EDGE16,
|
||||
ATI18800_EGAWONDER800PLUS
|
||||
ATI18800_EDGE16
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -71,6 +68,7 @@ ati18800_out(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
ati18800_t *ati18800 = (ati18800_t *) priv;
|
||||
svga_t *svga = &ati18800->svga;
|
||||
uint8_t o;
|
||||
uint8_t old;
|
||||
|
||||
if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1))
|
||||
@@ -182,40 +180,6 @@ ati18800_recalctimings(svga_t *svga)
|
||||
|
||||
clock_sel = ((svga->miscout >> 2) & 3) | ((ati18800->regs[0xbe] & 0x10) >> 1) | ((ati18800->regs[0xb9] & 2) << 1);
|
||||
|
||||
if (ati18800->type == ATI18800_EGAWONDER800PLUS) {
|
||||
svga->crtc[5] &= ~0x60; /*Not supported by the EGA Wonder 800+*/
|
||||
svga->crtc[0x0b] &= ~0x60; /*Not supported by the EGA Wonder 800+*/
|
||||
|
||||
svga->hdisp_time = svga->hdisp;
|
||||
|
||||
svga->hdisp = svga->crtc[1];
|
||||
svga->hdisp++;
|
||||
|
||||
svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]);
|
||||
|
||||
svga->hdisp_time = svga->hdisp;
|
||||
svga->render = svga_render_blank;
|
||||
|
||||
if (!svga->scrblank && (svga->crtc[0x17] & 0x80) && svga->attr_palette_enable) {
|
||||
if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/
|
||||
if (svga->seqregs[1] & 8) { /*40 column*/
|
||||
svga->render = svga_render_text_40;
|
||||
svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18;
|
||||
/* Character clock is off by 1 now in 40-line modes, on all cards. */
|
||||
svga->ma_latch--;
|
||||
svga->hdisp += (svga->seqregs[1] & 1) ? 16 : 18;
|
||||
} else {
|
||||
svga->render = svga_render_text_80;
|
||||
svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9;
|
||||
}
|
||||
svga->hdisp_old = svga->hdisp;
|
||||
} else {
|
||||
svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8;
|
||||
svga->hdisp_old = svga->hdisp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ati18800->regs[0xb6] & 0x10) {
|
||||
svga->hdisp <<= 1;
|
||||
svga->htotal <<= 1;
|
||||
@@ -291,10 +255,6 @@ ati18800_init(const device_t *info)
|
||||
rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_EDGE16, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
ati18800->memory = 512;
|
||||
break;
|
||||
case ATI18800_EGAWONDER800PLUS:
|
||||
rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_ATIEGAPLUS, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
ati18800->memory = 256;
|
||||
break;
|
||||
}
|
||||
|
||||
svga_init(info, &ati18800->svga, ati18800, ati18800->memory << 10,
|
||||
@@ -311,10 +271,7 @@ ati18800_init(const device_t *info)
|
||||
ati18800->svga.miscout = 1;
|
||||
ati18800->svga.bpp = 8;
|
||||
|
||||
if (info->local == ATI18800_EGAWONDER800PLUS)
|
||||
ati_eeprom_load(&ati18800->eeprom, "egawonder800.nvr", 0);
|
||||
else
|
||||
ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0);
|
||||
ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0);
|
||||
|
||||
return ati18800;
|
||||
}
|
||||
@@ -339,12 +296,6 @@ ati18800_available(void)
|
||||
return rom_present(BIOS_ROM_PATH_EDGE16);
|
||||
}
|
||||
|
||||
static int
|
||||
ati18800_egawonder800plus_available(void)
|
||||
{
|
||||
return rom_present(BIOS_ROM_PATH_ATIEGAPLUS);
|
||||
}
|
||||
|
||||
static void
|
||||
ati18800_close(void *priv)
|
||||
{
|
||||
@@ -414,17 +365,3 @@ const device_t ati18800_device = {
|
||||
.force_redraw = ati18800_force_redraw,
|
||||
.config = NULL
|
||||
};
|
||||
|
||||
const device_t ati18800_egawonder800plus_device = {
|
||||
.name = "ATI EGA Wonder 800+",
|
||||
.internal_name = "egawonder800",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = ATI18800_EGAWONDER800PLUS,
|
||||
.init = ati18800_init,
|
||||
.close = ati18800_close,
|
||||
.reset = NULL,
|
||||
{ .available = ati18800_egawonder800plus_available },
|
||||
.speed_changed = ati18800_speed_changed,
|
||||
.force_redraw = ati18800_force_redraw,
|
||||
.config = NULL
|
||||
};
|
||||
|
@@ -41,6 +41,7 @@ void ega_doblit(int wx, int wy, ega_t *ega);
|
||||
#define BIOS_IBM_PATH "roms/video/ega/ibm_6277356_ega_card_u44_27128.bin"
|
||||
#define BIOS_CPQ_PATH "roms/video/ega/108281-001.bin"
|
||||
#define BIOS_SEGA_PATH "roms/video/ega/lega.vbi"
|
||||
#define BIOS_ATIEGA800P_PATH "roms/video/ega/ATI EGA Wonder 800+ N1.00.BIN"
|
||||
#define BIOS_ISKRA_PATH "roms/video/ega/143-02.bin", "roms/video/ega/143-03.bin"
|
||||
#define BIOS_TSENG_PATH "roms/video/ega/EGA ET2000.BIN"
|
||||
|
||||
@@ -48,6 +49,7 @@ enum {
|
||||
EGA_IBM = 0,
|
||||
EGA_COMPAQ,
|
||||
EGA_SUPEREGA,
|
||||
EGA_ATI800P,
|
||||
EGA_ISKRA,
|
||||
EGA_TSENG
|
||||
};
|
||||
@@ -78,6 +80,24 @@ ega_out(uint16_t addr, uint8_t val, void *priv)
|
||||
addr ^= 0x60;
|
||||
|
||||
switch (addr) {
|
||||
case 0x1ce:
|
||||
ega->index = val;
|
||||
break;
|
||||
case 0x1cf:
|
||||
ega->regs[ega->index] = val;
|
||||
switch (ega->index) {
|
||||
case 0xb0:
|
||||
ega_recalctimings(ega);
|
||||
break;
|
||||
case 0xb3:
|
||||
ati_eeprom_write((ati_eeprom_t *) ega->eeprom, val & 8, val & 2, val & 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3c0:
|
||||
case 0x3c1:
|
||||
if (!ega->attrff) {
|
||||
@@ -126,8 +146,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv)
|
||||
io_removehandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega);
|
||||
if (!(val & 1))
|
||||
io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega);
|
||||
if ((o ^ val) & 0x80)
|
||||
ega_recalctimings(ega);
|
||||
ega_recalctimings(ega);
|
||||
break;
|
||||
case 0x3c4:
|
||||
ega->seqaddr = val;
|
||||
@@ -208,14 +227,24 @@ ega_out(uint16_t addr, uint8_t val, void *priv)
|
||||
break;
|
||||
case 0x3d0:
|
||||
case 0x3d4:
|
||||
ega->crtcreg = val & 31;
|
||||
if (ega->chipset)
|
||||
ega->crtcreg = val & 0x3f;
|
||||
else
|
||||
ega->crtcreg = val & 0x1f;
|
||||
return;
|
||||
case 0x3d1:
|
||||
case 0x3d5:
|
||||
if ((ega->crtcreg < 7) && (ega->crtc[0x11] & 0x80))
|
||||
return;
|
||||
if ((ega->crtcreg == 7) && (ega->crtc[0x11] & 0x80))
|
||||
val = (ega->crtc[7] & ~0x10) | (val & 0x10);
|
||||
if (ega->chipset) {
|
||||
if ((ega->crtcreg < 7) && (ega->crtc[0x11] & 0x80) && !(ega->regs[0xb4] & 0x80))
|
||||
return;
|
||||
if ((ega->crtcreg == 7) && (ega->crtc[0x11] & 0x80) && !(ega->regs[0xb4] & 0x80))
|
||||
val = (ega->crtc[7] & ~0x10) | (val & 0x10);
|
||||
} else {
|
||||
if ((ega->crtcreg < 7) && (ega->crtc[0x11] & 0x80))
|
||||
return;
|
||||
if ((ega->crtcreg == 7) && (ega->crtc[0x11] & 0x80))
|
||||
val = (ega->crtc[7] & ~0x10) | (val & 0x10);
|
||||
}
|
||||
old = ega->crtc[ega->crtcreg];
|
||||
ega->crtc[ega->crtcreg] = val;
|
||||
if (old != val) {
|
||||
@@ -246,6 +275,23 @@ ega_in(uint16_t addr, void *priv)
|
||||
addr ^= 0x60;
|
||||
|
||||
switch (addr) {
|
||||
case 0x1ce:
|
||||
ret = ega->index;
|
||||
break;
|
||||
case 0x1cf:
|
||||
switch (ega->index) {
|
||||
case 0xb7:
|
||||
ret = ega->regs[ega->index] & ~8;
|
||||
if (ati_eeprom_read((ati_eeprom_t *) ega->eeprom))
|
||||
ret |= 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = ega->regs[ega->index];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3c0:
|
||||
if (ega_type)
|
||||
ret = ega->attraddr | ega->attr_palette_enable;
|
||||
@@ -255,8 +301,8 @@ ega_in(uint16_t addr, void *priv)
|
||||
ret = ega->attrregs[ega->attraddr];
|
||||
break;
|
||||
case 0x3c2:
|
||||
ret = (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00;
|
||||
break;
|
||||
ret = (egaswitches & (8 >> egaswitchread)) ? 0x10 : 0x00;
|
||||
break;
|
||||
case 0x3c4:
|
||||
if (ega_type)
|
||||
ret = ega->seqaddr;
|
||||
@@ -310,6 +356,7 @@ ega_in(uint16_t addr, void *priv)
|
||||
default:
|
||||
if (ega_type)
|
||||
ret = ega->crtc[ega->crtcreg];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x3da:
|
||||
@@ -429,6 +476,31 @@ ega_recalctimings(ega_t *ega)
|
||||
crtcconst *= 9.0;
|
||||
else
|
||||
crtcconst *= 8.0;
|
||||
} else if (ega->eeprom) {
|
||||
clksel = ((ega->miscout & 0xc) >> 2) | ((ega->regs[0xbe] & 0x10) ? 4 : 0);
|
||||
|
||||
switch (clksel) {
|
||||
case 0:
|
||||
crtcconst = (cpuclock / 25175000.0 * (double) (1ULL << 32));
|
||||
break;
|
||||
case 1:
|
||||
crtcconst = (cpuclock / 28322000.0 * (double) (1ULL << 32));
|
||||
break;
|
||||
case 4:
|
||||
crtcconst = (cpuclock / 14318181.0 * (double) (1ULL << 32));
|
||||
break;
|
||||
case 5:
|
||||
crtcconst = (cpuclock / 16257000.0 * (double) (1ULL << 32));
|
||||
break;
|
||||
case 7:
|
||||
default:
|
||||
crtcconst = (cpuclock / 36000000.0 * (double) (1ULL << 32));
|
||||
break;
|
||||
}
|
||||
if (!(ega->seqregs[1] & 1))
|
||||
crtcconst *= 9.0;
|
||||
else
|
||||
crtcconst *= 8.0;
|
||||
} else {
|
||||
if (ega->vidclock)
|
||||
crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0));
|
||||
@@ -460,6 +532,15 @@ ega_recalctimings(ega_t *ega)
|
||||
}
|
||||
}
|
||||
|
||||
if (ega->chipset) {
|
||||
if (ega->hdisp > 640) {
|
||||
ega->dispend <<= 1;
|
||||
ega->vtotal <<= 1;
|
||||
ega->split <<= 1;
|
||||
ega->vsyncstart <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (enable_overscan) {
|
||||
overscan_y = (ega->rowcount + 1) << 1;
|
||||
|
||||
@@ -663,8 +744,18 @@ ega_poll(void *priv)
|
||||
if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines)
|
||||
ega->stat &= ~8;
|
||||
ega->vslines++;
|
||||
if (ega->displine > 500)
|
||||
ega->displine = 0;
|
||||
if (ega->chipset) {
|
||||
if (ega->hdisp > 640) {
|
||||
if (ega->displine > 2000)
|
||||
ega->displine = 0;
|
||||
} else {
|
||||
if (ega->displine > 500)
|
||||
ega->displine = 0;
|
||||
}
|
||||
} else {
|
||||
if (ega->displine > 500)
|
||||
ega->displine = 0;
|
||||
}
|
||||
} else {
|
||||
timer_advance_u64(&ega->timer, ega->dispontime);
|
||||
|
||||
@@ -700,7 +791,13 @@ ega_poll(void *priv)
|
||||
}
|
||||
}
|
||||
ega->vc++;
|
||||
ega->vc &= 511;
|
||||
if (ega->chipset) {
|
||||
if (ega->hdisp > 640)
|
||||
ega->vc &= 1023;
|
||||
else
|
||||
ega->vc &= 511;
|
||||
} else
|
||||
ega->vc &= 511;
|
||||
if (ega->vc == ega->split) {
|
||||
// TODO: Implement the hardware bug where the first scanline is drawn twice when the split happens
|
||||
if (ega->interlace && ega->oddeven)
|
||||
@@ -1327,6 +1424,9 @@ ega_standalone_init(const device_t *info)
|
||||
else
|
||||
ega_type = 1;
|
||||
|
||||
ega->actual_type = info->local;
|
||||
ega->chipset = 0;
|
||||
|
||||
switch (info->local) {
|
||||
default:
|
||||
case EGA_IBM:
|
||||
@@ -1342,6 +1442,11 @@ ega_standalone_init(const device_t *info)
|
||||
rom_init(&ega->bios_rom, BIOS_SEGA_PATH,
|
||||
0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
break;
|
||||
case EGA_ATI800P:
|
||||
rom_init(&ega->bios_rom, BIOS_ATIEGA800P_PATH,
|
||||
0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
ega->chipset = 1;
|
||||
break;
|
||||
case EGA_ISKRA:
|
||||
rom_init_interleaved(&ega->bios_rom, BIOS_ISKRA_PATH,
|
||||
0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
@@ -1369,7 +1474,12 @@ ega_standalone_init(const device_t *info)
|
||||
mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega);
|
||||
io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega);
|
||||
|
||||
if (info->local == EGA_COMPAQ) {
|
||||
if (ega->chipset) {
|
||||
io_sethandler(0x01ce, 0x0002, ega_in, NULL, NULL, ega_out, NULL, NULL, ega);
|
||||
ega->eeprom = malloc(sizeof(ati_eeprom_t));
|
||||
memset(ega->eeprom, 0, sizeof(ati_eeprom_t));
|
||||
ati_eeprom_load((ati_eeprom_t *) ega->eeprom, "egawonder800p.nvr", 0);
|
||||
} else if (info->local == EGA_COMPAQ) {
|
||||
io_sethandler(0x0084, 0x0001, ega_in, NULL, NULL, ega_out, NULL, NULL, ega);
|
||||
io_sethandler(0x07c6, 0x0001, ega_in, NULL, NULL, ega_out, NULL, NULL, ega);
|
||||
io_sethandler(0x0bc6, 0x0001, ega_in, NULL, NULL, ega_out, NULL, NULL, ega);
|
||||
@@ -1397,6 +1507,12 @@ sega_standalone_available(void)
|
||||
return rom_present(BIOS_SEGA_PATH);
|
||||
}
|
||||
|
||||
static int
|
||||
atiega800p_standalone_available(void)
|
||||
{
|
||||
return rom_present(BIOS_ATIEGA800P_PATH);
|
||||
}
|
||||
|
||||
static int
|
||||
iskra_ega_standalone_available(void)
|
||||
{
|
||||
@@ -1414,6 +1530,8 @@ ega_close(void *priv)
|
||||
{
|
||||
ega_t *ega = (ega_t *) priv;
|
||||
|
||||
if (ega->eeprom)
|
||||
free(ega->eeprom);
|
||||
free(ega->vram);
|
||||
free(ega);
|
||||
}
|
||||
@@ -1551,6 +1669,20 @@ const device_t sega_device = {
|
||||
.config = ega_config
|
||||
};
|
||||
|
||||
const device_t atiega800p_device = {
|
||||
.name = "ATI EGA Wonder 800+",
|
||||
.internal_name = "egawonder800p",
|
||||
.flags = DEVICE_ISA,
|
||||
.local = EGA_ATI800P,
|
||||
.init = ega_standalone_init,
|
||||
.close = ega_close,
|
||||
.reset = NULL,
|
||||
{ .available = atiega800p_standalone_available },
|
||||
.speed_changed = ega_speed_changed,
|
||||
.force_redraw = NULL,
|
||||
.config = ega_config
|
||||
};
|
||||
|
||||
const device_t iskra_ega_device = {
|
||||
.name = "Iskra EGA (Cyrillic ROM)",
|
||||
.internal_name = "iskra_ega",
|
||||
|
@@ -79,7 +79,7 @@ video_cards[] = {
|
||||
// clang-format off
|
||||
{ &vid_none_device },
|
||||
{ &vid_internal_device },
|
||||
{ &ati18800_egawonder800plus_device },
|
||||
{ &atiega800p_device },
|
||||
{ &mach8_isa_device, VIDEO_FLAG_TYPE_8514 },
|
||||
{ &mach32_isa_device, VIDEO_FLAG_TYPE_8514 },
|
||||
{ &mach64gx_isa_device },
|
||||
|
Reference in New Issue
Block a user