I2C overhaul part 3: "we finally figured out NCR NVRAM" edition

This commit is contained in:
RichardG867
2020-11-21 01:36:33 -03:00
parent cf2dba5838
commit d5867928d6
8 changed files with 214 additions and 235 deletions

View File

@@ -43,6 +43,7 @@
#include <86box/device.h>
#include <86box/nvr.h>
#include <86box/plat.h>
#include <86box/i2c.h>
#include <86box/scsi.h>
#include <86box/scsi_device.h>
#include <86box/scsi_ncr53c8xx.h>
@@ -225,14 +226,8 @@ typedef struct {
int msg_action;
int msg_len;
uint8_t msg[NCR_MAX_MSGIN_LEN];
#ifdef USE_NVRAM
uint16_t nvram;
uint8_t nvram_t;
uint8_t nvram_op;
uint8_t nvram_param;
uint8_t nvram_start;
uint8_t nvram_index;
#endif
uint8_t nvram[2048]; /* 24C16 EEPROM (16 kbit) */
void *i2c, *eeprom;
uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */
/* 0 if SCRIPTS are running or stopped.
* 1 if a Wait Reselect instruction has been issued.
@@ -434,10 +429,7 @@ ncr53c8xx_soft_reset(ncr53c8xx_t *dev)
dev->gpreg = 0;
dev->slpar = 0;
dev->sstop = 1;
dev->gpcntl = 0x0f;
#ifdef USE_NVRAM
dev->nvram_t = dev->nvram_index = 0;
#endif
dev->gpcntl = 0x03;
if (dev->chip >= CHIP_825) {
/* This *IS* a wide SCSI controller, so reset all SCSI
@@ -474,7 +466,7 @@ ncr53c8xx_read(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len)
buf[i] = inb((uint16_t) (addr + i));
} else {
ncr53c8xx_log("NCR 810: Reading from memory address %08X\n", addr);
dma_bm_read(addr, buf, len, 4);
dma_bm_read(addr, buf, len, 4);
}
}
@@ -492,7 +484,7 @@ ncr53c8xx_write(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len)
outb((uint16_t) (addr + i), buf[i]);
} else {
ncr53c8xx_log("NCR 810: Writing to memory address %08X\n", addr);
dma_bm_write(addr, buf, len, 4);
dma_bm_write(addr, buf, len, 4);
}
}
@@ -511,10 +503,10 @@ static
void do_irq(ncr53c8xx_t *dev, int level)
{
if (level) {
pci_set_irq(dev->pci_slot, PCI_INTA);
pci_set_irq(dev->pci_slot, PCI_INTA);
ncr53c8xx_log("Raising IRQ...\n");
} else {
pci_clear_irq(dev->pci_slot, PCI_INTA);
pci_clear_irq(dev->pci_slot, PCI_INTA);
ncr53c8xx_log("Lowering IRQ...\n");
}
}
@@ -852,8 +844,8 @@ ncr53c8xx_do_msgin(ncr53c8xx_t *dev)
switch to PHASE_MO. */
switch (dev->msg_action) {
case 0:
ncr53c8xx_set_phase(dev, PHASE_CMD);
break;
ncr53c8xx_set_phase(dev, PHASE_CMD);
break;
case 1:
ncr53c8xx_disconnect(dev);
break;
@@ -1444,7 +1436,7 @@ ncr53c8xx_callback(void *p)
if (dev->waiting)
timer_on_auto(&dev->timer, 40.0);
else
ncr53c8xx_process_script(dev);
ncr53c8xx_process_script(dev);
}
if (dev->sstop)
@@ -1452,146 +1444,22 @@ ncr53c8xx_callback(void *p)
}
#ifdef USE_NVRAM
static void
ncr53c8xx_eeprom(ncr53c8xx_t *dev, int save)
ncr53c8xx_eeprom(ncr53c8xx_t *dev, uint8_t save)
{
FILE *f;
if (save)
f = nvr_fopen(dev->nvr_path, L"wb");
else
f = nvr_fopen(dev->nvr_path, L"rb");
if (f)
{
if (save) {
fwrite((uint8_t *) &dev->nvram, 1, 1, f);
fwrite(((uint8_t *) &dev->nvram) + 1, 1, 1, f);
} else {
fread((uint8_t *) &dev->nvram, 1, 1, f);
fread(((uint8_t *) &dev->nvram) + 1, 1, 1, f);
}
f = nvr_fopen(dev->nvr_path, save ? L"wb": L"rb");
if (f) {
if (save)
fwrite(&dev->nvram, sizeof(dev->nvram), 1, f);
else
fread(&dev->nvram, sizeof(dev->nvram), 1, f);
fclose(f);
f = NULL;
}
}
#define ADDRESS_LENGTH 9
#define ADDRESS_END (ADDRESS_LENGTH + 2)
#define ADDRESS_SHIFT (ADDRESS_LENGTH - 2)
#define ADDRESS_MASK 0x3f
#define DATA_LENGTH 8
#define DATA_START (ADDRESS_END + 1)
#define DATA_END (ADDRESS_END + DATA_LENGTH)
static void
ncr53c8xx_serial_eeprom_write(ncr53c8xx_t *dev, uint8_t val)
{
uint8_t temp, old = dev->nvram_t;
dev->nvram_t = val & 0x03;
if (val & 0x02) {
if (!dev->nvram_index) {
/* First signal clocked in after clock is high, start bit. */
dev->nvram_start = 1;
ncr53c8xx_log("[W] Serial EEPROM: Start bit\n");
dev->nvram_op = 0;
} else if ((dev->nvram_index == 1) || (dev->nvram_index == 2)) {
if (!dev->nvram_start)
return;
dev->nvram_op = (val & 0x01) << (dev->nvram_index - 1);
if (dev->nvram_index == 2) {
// ncr53c8xx_log("[W] Serial EEPROM: Opcode: %01X\n", dev->nvram_op);
dev->nvram_param = 0;
}
} else if ((dev->nvram_index >= 3) && (dev->nvram_index <= ADDRESS_END)) {
if (!dev->nvram_start)
return;
dev->nvram_param = (val & 0x01) << (dev->nvram_index - 3);
if (dev->nvram_index < ADDRESS_END) {
dev->nvram_index++;
return;
}
switch (dev->nvram_op) {
case 0x00:
temp = dev->nvram_param >> ADDRESS_SHIFT;
switch(temp) {
case 0x00:
ncr53c8xx_log("[W] Serial EEPROM: EWDS\n");
break;
case 0x01:
ncr53c8xx_log("[W] Serial EEPROM: WRAL\n");
break;
case 0x02:
ncr53c8xx_log("[W] Serial EEPROM: ERAL\n");
break;
case 0x03:
ncr53c8xx_log("[W] Serial EEPROM: EWEN\n");
break;
default:
ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN 00\n");
break;
}
dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0;
return;
case 0x01:
ncr53c8xx_log("[W] Serial EEPROM: WRITE\n");
break;
case 0x02:
ncr53c8xx_log("[W] Serial EEPROM: READ\n");
break;
case 0x03:
ncr53c8xx_log("[W] Serial EEPROM: ERASE\n");
break;
default:
ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN\n");
break;
}
} else if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) {
if (!dev->nvram_start)
return;
if (dev->nvram_index == DATA_END) {
ncr53c8xx_log("[W] Serial EEPROM: Data end\n");
dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0;
return;
}
}
dev->nvram_index++;
}
}
static uint8_t
ncr53c8xx_serial_eeprom_read(ncr53c8xx_t *dev)
{
uint8_t temp = 0;
if (dev->gpreg & 0x02) {
if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) {
if (!dev->nvram_start)
return temp;
dev->nvram_index++;
if (dev->nvram_index == DATA_END) {
ncr53c8xx_log("[R] Serial EEPROM: Data end\n");
dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0;
return temp;
}
}
}
return temp;
}
#endif
static void
ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val)
{
@@ -1659,12 +1527,8 @@ ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val)
break;
case 0x07: /* GPREG */
ncr53c8xx_log("NCR 810: GPREG write %02X\n", val);
tmp = dev->gpreg;
dev->gpreg = val & 0xfe;
#ifdef USE_NVRAM
if ((dev->gpcntl & 0xc3) == 0x00)
ncr53c8xx_serial_eeprom_write(dev, val & 0x03);
#endif
dev->gpreg = val;
i2c_gpio_set(dev->i2c, !!(dev->gpreg & 0x02), !!(dev->gpreg & 0x01));
break;
case 0x08: /* SFBR */
/* The CPU is not allowed to write to this register. However the
@@ -1893,13 +1757,18 @@ ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset)
ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid);
return dev->sdid;
case 0x07: /* GPREG */
#ifdef USE_NVRAM
tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e;
if ((dev->gpcntl & 0xc3) == 0x01)
tmp |= ncr53c8xx_serial_eeprom_read(dev);
#else
tmp = ((dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e) | 0x01;
#endif
tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1f;
if ((dev->gpcntl & 0x41) == 0x01) {
tmp &= 0xfe;
if (i2c_gpio_get_sda(dev->i2c))
tmp |= 0x01;
}
if ((dev->gpcntl & 0x82) == 0x02) {
tmp &= 0xfd;
if (i2c_gpio_get_scl(dev->i2c))
tmp |= 0x02;
}
ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp);
return tmp;
case 0x08: /* Revision ID */
@@ -2677,8 +2546,8 @@ ncr53c8xx_init(const device_t *info)
dev->chip_rev = 0x26;
dev->nvr_path = L"ncr53c825a.nvr";
}
ncr53c8xx_pci_bar[2].addr_regs[0] = 0;
ncr53c8xx_pci_bar[3].addr = 0xffff0000;
ncr53c8xx_pci_bar[2].addr_regs[0] = 0;
ncr53c8xx_pci_bar[3].addr = 0xffff0000;
/* Need to make it align on a 16k boundary as that's this emulator's
memory mapping granularity. */
ncr53c8xx_ram_init(dev, 0x0fffc000);
@@ -2695,10 +2564,11 @@ ncr53c8xx_init(const device_t *info)
dev->nvr_path = L"ncr53c810.nvr";
}
#ifdef USE_NVRAM
dev->i2c = i2c_gpio_init("nvr_ncr53c8xx");
dev->eeprom = i2c_eeprom_init(i2c_gpio_get_bus(dev->i2c), 0x50, dev->nvram, sizeof(dev->nvram), 1);
/* Load the serial EEPROM. */
ncr53c8xx_eeprom(dev, 0);
#endif
ncr53c8xx_soft_reset(dev);
@@ -2714,6 +2584,15 @@ ncr53c8xx_close(void *priv)
ncr53c8xx_t *dev = (ncr53c8xx_t *)priv;
if (dev) {
/* Save the serial EEPROM. */
ncr53c8xx_eeprom(dev, 1);
if (dev->eeprom)
i2c_eeprom_close(dev->eeprom);
if (dev->i2c)
i2c_gpio_close(dev->i2c);
free(dev);
dev = NULL;
}