/* * 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, * Miran Grca, * * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. */ #include #include #include #include #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; }