Files
86Box/src/video/vid_ati_eeprom.c
2023-08-09 20:09:36 -04:00

230 lines
8.0 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)
{
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 an immediate write to nvram if none is present 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);
}
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;
}