1. Finally add the ATI 8514/A Ultra add-on BIOS in both ISA and MCA variants (despite the ROM page failure on POST). 2. Fixed a mode switch bug in the Mach8 (both add-on and vga combo) when exiting the Win3.x GUI using the native drivers. 3. Corrected (best possible) the eeprom load of the Mach8 products. 4. Partial implementation of the FIFO on the 8514/A compatible products including Mach8/32 and plain IBM 8514/A.
260 lines
8.7 KiB
C
260 lines
8.7 KiB
C
/*
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
* running old operating systems and software designed for IBM
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
* system designs based on the PCI bus.
|
|
*
|
|
* This file is part of the 86Box distribution.
|
|
*
|
|
* Emulation of the EEPROM on select ATI cards.
|
|
*
|
|
*
|
|
*
|
|
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
*
|
|
* Copyright 2008-2020 Sarah Walker.
|
|
* Copyright 2016-2020 Miran Grca.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
#include <86box/86box.h>
|
|
#include <86box/device.h>
|
|
#include <86box/mem.h>
|
|
#include <86box/timer.h>
|
|
#include <86box/nvr.h>
|
|
#include <86box/vid_ati_eeprom.h>
|
|
#include <86box/plat_fallthrough.h>
|
|
|
|
void
|
|
ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type)
|
|
{
|
|
FILE *fp;
|
|
int size;
|
|
eeprom->type = type;
|
|
strncpy(eeprom->fn, fn, sizeof(eeprom->fn) - 1);
|
|
fp = nvr_fopen(eeprom->fn, "rb");
|
|
size = eeprom->type ? 512 : 128;
|
|
if (!fp) {
|
|
memset(eeprom->data, 0xff, size);
|
|
return;
|
|
}
|
|
if (fread(eeprom->data, 1, size, fp) != size)
|
|
memset(eeprom->data, 0, size);
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
void
|
|
ati_eeprom_load_mach8(ati_eeprom_t *eeprom, char *fn, int mca)
|
|
{
|
|
FILE *fp;
|
|
int size;
|
|
eeprom->type = 0;
|
|
strncpy(eeprom->fn, fn, sizeof(eeprom->fn) - 1);
|
|
fp = nvr_fopen(eeprom->fn, "rb");
|
|
size = 128;
|
|
if (!fp) {
|
|
if (mca) {
|
|
(void) fseek(fp, 2L, SEEK_SET);
|
|
memset(eeprom->data + 2, 0xff, size - 2);
|
|
fp = nvr_fopen(eeprom->fn, "wb");
|
|
fwrite(eeprom->data, 1, size, fp);
|
|
fclose(fp);
|
|
} else
|
|
memset(eeprom->data, 0xff, size);
|
|
return;
|
|
}
|
|
if (fread(eeprom->data, 1, size, fp) != size)
|
|
memset(eeprom->data, 0, size);
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
void
|
|
ati_eeprom_load_mach8_vga(ati_eeprom_t *eeprom, char *fn)
|
|
{
|
|
FILE *fp;
|
|
int size;
|
|
eeprom->type = 0;
|
|
strncpy(eeprom->fn, fn, sizeof(eeprom->fn) - 1);
|
|
fp = nvr_fopen(eeprom->fn, "rb");
|
|
size = 128;
|
|
if (!fp) { /*The ATI Graphics Ultra bios expects a fresh nvram zero'ed at boot time otherwise
|
|
it would hang the machine.*/
|
|
memset(eeprom->data, 0, size);
|
|
fp = nvr_fopen(eeprom->fn, "wb");
|
|
fwrite(eeprom->data, 1, size, fp);
|
|
fclose(fp);
|
|
return;
|
|
}
|
|
if (fread(eeprom->data, 1, size, fp) != size)
|
|
memset(eeprom->data, 0, size);
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
void
|
|
ati_eeprom_save(ati_eeprom_t *eeprom)
|
|
{
|
|
FILE *fp = nvr_fopen(eeprom->fn, "wb");
|
|
if (!fp)
|
|
return;
|
|
fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, fp);
|
|
fclose(fp);
|
|
}
|
|
|
|
void
|
|
ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat)
|
|
{
|
|
if (!ena)
|
|
eeprom->out = 1;
|
|
|
|
if (clk && !eeprom->oldclk) {
|
|
if (ena && !eeprom->oldena) {
|
|
eeprom->state = EEPROM_WAIT;
|
|
eeprom->opcode = 0;
|
|
eeprom->count = 3;
|
|
eeprom->out = 1;
|
|
} else if (ena) {
|
|
switch (eeprom->state) {
|
|
case EEPROM_WAIT:
|
|
if (!dat)
|
|
break;
|
|
eeprom->state = EEPROM_OPCODE;
|
|
fallthrough;
|
|
case EEPROM_OPCODE:
|
|
eeprom->opcode = (eeprom->opcode << 1) | (dat ? 1 : 0);
|
|
eeprom->count--;
|
|
if (!eeprom->count) {
|
|
switch (eeprom->opcode) {
|
|
case EEPROM_OP_WRITE:
|
|
eeprom->count = eeprom->type ? 24 : 22;
|
|
eeprom->state = EEPROM_INPUT;
|
|
eeprom->dat = 0;
|
|
break;
|
|
case EEPROM_OP_READ:
|
|
eeprom->count = eeprom->type ? 8 : 6;
|
|
eeprom->state = EEPROM_INPUT;
|
|
eeprom->dat = 0;
|
|
break;
|
|
case EEPROM_OP_EW:
|
|
eeprom->count = 2;
|
|
eeprom->state = EEPROM_INPUT;
|
|
eeprom->dat = 0;
|
|
break;
|
|
case EEPROM_OP_ERASE:
|
|
eeprom->count = eeprom->type ? 8 : 6;
|
|
eeprom->state = EEPROM_INPUT;
|
|
eeprom->dat = 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EEPROM_INPUT:
|
|
eeprom->dat = (eeprom->dat << 1) | (dat ? 1 : 0);
|
|
eeprom->count--;
|
|
if (!eeprom->count) {
|
|
switch (eeprom->opcode) {
|
|
case EEPROM_OP_WRITE:
|
|
if (!eeprom->wp) {
|
|
eeprom->data[(eeprom->dat >> 16) & (eeprom->type ? 255 : 63)] = eeprom->dat & 0xffff;
|
|
ati_eeprom_save(eeprom);
|
|
}
|
|
eeprom->state = EEPROM_IDLE;
|
|
eeprom->out = 1;
|
|
break;
|
|
|
|
case EEPROM_OP_READ:
|
|
eeprom->count = 17;
|
|
eeprom->state = EEPROM_OUTPUT;
|
|
eeprom->dat = eeprom->data[eeprom->dat];
|
|
break;
|
|
case EEPROM_OP_EW:
|
|
switch (eeprom->dat) {
|
|
case EEPROM_OP_EWDS:
|
|
eeprom->wp = 1;
|
|
break;
|
|
case EEPROM_OP_WRAL:
|
|
eeprom->opcode = EEPROM_OP_WRALMAIN;
|
|
eeprom->count = 20;
|
|
break;
|
|
case EEPROM_OP_ERAL:
|
|
if (!eeprom->wp) {
|
|
memset(eeprom->data, 0xff, 128);
|
|
ati_eeprom_save(eeprom);
|
|
}
|
|
break;
|
|
case EEPROM_OP_EWEN:
|
|
eeprom->wp = 0;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
eeprom->state = EEPROM_IDLE;
|
|
eeprom->out = 1;
|
|
break;
|
|
|
|
case EEPROM_OP_ERASE:
|
|
if (!eeprom->wp) {
|
|
eeprom->data[eeprom->dat] = 0xffff;
|
|
ati_eeprom_save(eeprom);
|
|
}
|
|
eeprom->state = EEPROM_IDLE;
|
|
eeprom->out = 1;
|
|
break;
|
|
|
|
case EEPROM_OP_WRALMAIN:
|
|
if (!eeprom->wp) {
|
|
for (uint16_t c = 0; c < 256; c++)
|
|
eeprom->data[c] = eeprom->dat;
|
|
ati_eeprom_save(eeprom);
|
|
}
|
|
eeprom->state = EEPROM_IDLE;
|
|
eeprom->out = 1;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
eeprom->oldena = ena;
|
|
} else if (!clk && eeprom->oldclk) {
|
|
if (ena) {
|
|
switch (eeprom->state) {
|
|
case EEPROM_OUTPUT:
|
|
eeprom->out = (eeprom->dat & 0x10000) ? 1 : 0;
|
|
eeprom->dat <<= 1;
|
|
eeprom->count--;
|
|
if (!eeprom->count) {
|
|
eeprom->state = EEPROM_IDLE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
eeprom->oldclk = clk;
|
|
}
|
|
|
|
int
|
|
ati_eeprom_read(ati_eeprom_t *eeprom)
|
|
{
|
|
return eeprom->out;
|
|
}
|