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

@@ -103,13 +103,16 @@ gl518sm_i2c_read(void *bus, uint8_t addr, void *priv)
uint16_t read = gl518sm_read(dev, dev->addr_register);
uint8_t ret = 0;
if (dev->i2c_state == 0)
dev->i2c_state = 1;
if ((dev->i2c_state == 1) && (dev->addr_register >= 0x07) && (dev->addr_register <= 0x0c)) { /* two-byte registers: read MSB first */
dev->i2c_state = 2;
ret = read >> 8;
} else
} else {
ret = read;
dev->addr_register++;
dev->addr_register++;
}
return ret;
}
@@ -178,6 +181,7 @@ gl518sm_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
break;
default:
dev->i2c_state = 3;
return 0;
}

View File

@@ -35,7 +35,7 @@ static uint8_t lm75_i2c_read(void *bus, uint8_t addr, void *priv);
static uint8_t lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv);
static void lm75_reset(lm75_t *dev);
#define ENABLE_LM75_LOG 1
#ifdef ENABLE_LM75_LOG
int lm75_do_log = ENABLE_LM75_LOG;
@@ -86,23 +86,39 @@ lm75_i2c_read(void *bus, uint8_t addr, void *priv)
lm75_t *dev = (lm75_t *) priv;
uint8_t ret = 0;
switch (dev->addr_register & 0x3) {
case 0x0: /* temperature */
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x1 : 0x0);
break;
if (dev->i2c_state == 0)
dev->i2c_state = 1;
case 0x1: /* configuration */
ret = lm75_read(dev, 0x2);
break;
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register);
ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
} else {
switch (dev->addr_register & 0x3) {
case 0x0: /* temperature */
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x0 : 0x1);
break;
case 0x2: /* Thyst */
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x4 : 0x3);
break;
case 0x3: /* Tos */
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x6 : 0x5);
break;
case 0x1: /* configuration */
ret = lm75_read(dev, 0x2);
break;
case 0x2: /* Thyst */
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x3 : 0x4);
break;
case 0x3: /* Tos */
ret = lm75_read(dev, (dev->i2c_state == 1) ? 0x5 : 0x6);
break;
}
}
if (++dev->i2c_state > 2)
dev->i2c_state = 2;
return ret;
}
@@ -112,15 +128,7 @@ lm75_read(lm75_t *dev, uint8_t reg)
{
uint8_t ret;
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg);
ret = i2c_read(i2c_smbus, dev->as99127f_i2c_addr);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
} else if ((reg & 0x7) == 0x0) /* temperature high byte */
if ((reg & 0x7) == 0x0) /* temperature high byte */
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]) >> 8;
else if ((reg & 0x7) == 0x1) /* temperature low byte */
ret = LM75_TEMP_TO_REG(dev->values->temperatures[dev->local >> 8]);
@@ -145,23 +153,37 @@ lm75_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
return 1;
}
switch (dev->addr_register & 0x3) {
case 0x0: /* temperature */
lm75_write(dev, (dev->i2c_state == 1) ? 0x1 : 0x0, data);
break;
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((dev->addr_register > 0x7) && ((dev->addr_register & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, dev->addr_register);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, data);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
return 1;
} else {
switch (dev->addr_register & 0x3) {
case 0x0: /* temperature */
lm75_write(dev, (dev->i2c_state == 1) ? 0x0 : 0x1, data);
break;
case 0x1: /* configuration */
lm75_write(dev, 0x2, data);
break;
case 0x1: /* configuration */
lm75_write(dev, 0x2, data);
break;
case 0x2: /* Thyst */
lm75_write(dev, (dev->i2c_state == 1) ? 0x4 : 0x3, data);
break;
case 0x3: /* Tos */
lm75_write(dev, (dev->i2c_state == 1) ? 0x6 : 0x5, data);
break;
case 0x2: /* Thyst */
lm75_write(dev, (dev->i2c_state == 1) ? 0x3 : 0x4, data);
break;
case 0x3: /* Tos */
lm75_write(dev, (dev->i2c_state == 1) ? 0x5 : 0x6, data);
break;
}
}
if (++dev->i2c_state > 2)
dev->i2c_state = 2;
return 1;
}
@@ -171,17 +193,6 @@ lm75_write(lm75_t *dev, uint8_t reg, uint8_t val)
{
lm75_log("LM75: write(%02X, %02X)\n", reg, val);
/* The AS99127F hardware monitor uses the addresses of its LM75 devices
to access some of its proprietary registers. Pass this operation on to
the main monitor address through an internal I2C call, if necessary. */
if ((reg > 0x7) && ((reg & 0xf8) != 0x50) && (dev->as99127f_i2c_addr < 0x80)) {
i2c_start(i2c_smbus, dev->as99127f_i2c_addr);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, reg);
i2c_write(i2c_smbus, dev->as99127f_i2c_addr, val);
i2c_stop(i2c_smbus, dev->as99127f_i2c_addr);
return 1;
}
uint8_t reg_idx = (reg & 0x7);
if ((reg_idx <= 0x1) || (reg_idx == 0x7))

View File

@@ -69,7 +69,7 @@ static uint8_t lm78_i2c_write(void *bus, uint8_t addr, uint8_t data, void *priv)
static uint8_t lm78_write(lm78_t *dev, uint8_t reg, uint8_t val, uint8_t bank);
static void lm78_reset(lm78_t *dev, uint8_t initialization);
#define ENABLE_LM78_LOG 1
#ifdef ENABLE_LM78_LOG
int lm78_do_log = ENABLE_LM78_LOG;

View File

@@ -194,6 +194,8 @@ i2c_has_device(void *bus_handle, uint8_t addr)
if (!bus)
return 0;
i2c_log("I2C: has_device(%s, %02X) = %d\n", bus->name, addr, !!bus->devices[addr]);
return(!!bus->devices[addr]);
}

View File

@@ -6,7 +6,7 @@
*
* This file is part of the 86Box distribution.
*
* Emulation of the AT24Cxx series of I2C EEPROMs.
* Emulation of the 24Cxx series of I2C EEPROMs.
*
*
*
@@ -27,22 +27,42 @@
typedef struct {
void *i2c;
uint8_t addr;
uint8_t *data;
uint8_t writable;
uint8_t addr, *data, writable;
uint16_t addr_mask;
uint8_t addr_register;
uint16_t addr_mask, addr_register;
uint8_t i2c_state;
} i2c_eeprom_t;
#define ENABLE_I2C_EEPROM_LOG 1
#ifdef ENABLE_I2C_EEPROM_LOG
int i2c_eeprom_do_log = ENABLE_I2C_EEPROM_LOG;
static void
i2c_eeprom_log(const char *fmt, ...)
{
va_list ap;
if (i2c_eeprom_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define i2c_eeprom_log(fmt, ...)
#endif
void
i2c_eeprom_start(void *bus, uint8_t addr, void *priv)
{
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
i2c_eeprom_log("I2C EEPROM: start()\n");
dev->i2c_state = 0;
dev->addr_register = (addr << 8) & dev->addr_mask;
}
@@ -50,8 +70,13 @@ uint8_t
i2c_eeprom_read(void *bus, uint8_t addr, void *priv)
{
i2c_eeprom_t *dev = (i2c_eeprom_t *) priv;
uint8_t ret = dev->data[dev->addr_register];
return dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask];
i2c_eeprom_log("I2C EEPROM: read(%04X) = %02X\n", dev->addr_register, ret);
if (++dev->addr_register > dev->addr_mask) /* roll-over */
dev->addr_register = 0;
return ret;
}
@@ -62,11 +87,16 @@ i2c_eeprom_write(void *bus, uint8_t addr, uint8_t data, void *priv)
if (dev->i2c_state == 0) {
dev->i2c_state = 1;
dev->addr_register = data;
} else if (dev->writable)
dev->data[((addr << 8) | dev->addr_register++) & dev->addr_mask] = data;
else
return 0;
dev->addr_register = ((addr << 8) | data) & dev->addr_mask;
i2c_eeprom_log("I2C EEPROM: write(address, %04X)\n", dev->addr_register);
} else {
i2c_eeprom_log("I2C EEPROM: write(%04X, %02X) = %s\n", dev->addr_register, data, dev->writable ? "accepted" : "blocked");
if (dev->writable)
dev->data[dev->addr_register] = data;
if (++dev->addr_register > dev->addr_mask) /* roll-over */
dev->addr_register = 0;
return dev->writable;
}
return 1;
}
@@ -78,6 +108,8 @@ i2c_eeprom_init(void *i2c, uint8_t addr, uint8_t *data, uint16_t size, uint8_t w
i2c_eeprom_t *dev = (i2c_eeprom_t *) malloc(sizeof(i2c_eeprom_t));
memset(dev, 0, sizeof(i2c_eeprom_t));
i2c_eeprom_log("I2C EEPROM: init(%02X, %d, %d)\n", addr, size, writable);
dev->i2c = i2c;
dev->addr = addr;
dev->data = data;
@@ -96,6 +128,8 @@ i2c_eeprom_close(void *dev_handle)
{
i2c_eeprom_t *dev = (i2c_eeprom_t *) dev_handle;
i2c_eeprom_log("I2C EEPROM: close()\n");
i2c_removehandler(dev->i2c, dev->addr & ~(dev->addr_mask >> 8), (dev->addr_mask >> 8) + 1, i2c_eeprom_start, i2c_eeprom_read, i2c_eeprom_write, NULL, dev);
free(dev);

View File

@@ -52,19 +52,43 @@ enum {
};
typedef struct {
char *bus_name;
void *i2c;
uint8_t scl, sda, state, slave_state, slave_addr,
slave_rw, last_sda, pos, transmit, byte;
} i2c_gpio_t;
#ifdef ENABLE_I2C_GPIO_LOG
int i2c_gpio_do_log = ENABLE_I2C_GPIO_LOG;
static void
i2c_gpio_log(int level, const char *fmt, ...)
{
va_list ap;
if (i2c_gpio_do_log >= level) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define i2c_gpio_log(fmt, ...)
#endif
void *
i2c_gpio_init(char *bus_name)
{
i2c_gpio_t *dev = (i2c_gpio_t *) malloc(sizeof(i2c_gpio_t));
memset(dev, 0, sizeof(i2c_gpio_t));
dev->i2c = i2c_addbus(bus_name);
i2c_gpio_log(1, "I2C GPIO %s: init()\n", bus_name);
dev->bus_name = bus_name;
dev->i2c = i2c_addbus(dev->bus_name);
dev->scl = dev->sda = 1;
dev->slave_addr = 0xff;
@@ -77,6 +101,8 @@ i2c_gpio_close(void *dev_handle)
{
i2c_gpio_t *dev = (i2c_gpio_t *) dev_handle;
i2c_gpio_log(1, "I2C GPIO %s: close()\n", dev->bus_name);
i2c_removebus(dev->i2c);
free(dev);
@@ -87,6 +113,7 @@ void
i2c_gpio_next_byte(i2c_gpio_t *dev)
{
dev->byte = i2c_read(dev->i2c, dev->slave_addr);
i2c_gpio_log(1, "I2C GPIO %s: next_byte() = %02X\n", dev->bus_name, dev->byte);
}
@@ -101,6 +128,8 @@ i2c_gpio_write(i2c_gpio_t *dev)
dev->slave_addr = dev->byte >> 1;
dev->slave_rw = dev->byte & 1;
i2c_gpio_log(1, "I2C GPIO %s: Initiating transfer to address %02X rw %d\n", dev->bus_name, dev->slave_addr, dev->slave_rw);
if (!i2c_has_device(dev->i2c, dev->slave_addr)) {
dev->slave_state = SLAVE_INVALID;
break;
@@ -120,11 +149,13 @@ i2c_gpio_write(i2c_gpio_t *dev)
break;
case SLAVE_RECEIVEADDR:
i2c_gpio_log(1, "I2C GPIO %s: Receiving address %02X\n", dev->bus_name, dev->byte);
i2c_write(dev->i2c, dev->slave_addr, dev->byte);
dev->slave_state = dev->slave_rw ? SLAVE_SENDDATA : SLAVE_RECEIVEDATA;
break;
case SLAVE_RECEIVEDATA:
i2c_gpio_log(1, "I2C GPIO %s: Receiving data %02X\n", dev->bus_name, dev->byte);
i2c_write(dev->i2c, dev->slave_addr, dev->byte);
break;
}
@@ -134,7 +165,10 @@ i2c_gpio_write(i2c_gpio_t *dev)
void
i2c_gpio_stop(i2c_gpio_t *dev)
{
i2c_stop(dev->i2c, dev->slave_addr);
i2c_gpio_log(1, "I2C GPIO %s: Stopping transfer\n", dev->bus_name);
if (dev->slave_addr != 0xff)
i2c_stop(dev->i2c, dev->slave_addr);
dev->slave_addr = 0xff;
dev->slave_state = SLAVE_IDLE;
@@ -149,7 +183,9 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
switch (dev->state) {
case I2C_IDLE:
if (dev->scl && scl && dev->last_sda && !sda) { /* start bit */
/* !dev->scl check breaks NCR SDMS. */
if (/*!dev->scl &&*/ scl && dev->last_sda && !sda) { /* start bit */
i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from IDLE)\n", dev->bus_name);
dev->state = I2C_RECEIVE;
dev->pos = 0;
}
@@ -173,9 +209,11 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
}
} else if (dev->scl && scl) {
if (sda && !dev->last_sda) { /* stop bit */
i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from RECEIVE)\n", dev->bus_name);
dev->state = I2C_IDLE;
i2c_gpio_stop(dev);
} else if (!sda && dev->last_sda) { /* start bit */
i2c_gpio_log(2, "I2C GPIO %s: Start bit received (from RECEIVE)\n", dev->bus_name);
dev->pos = 0;
dev->slave_state = SLAVE_IDLE;
}
@@ -184,6 +222,7 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
case I2C_ACKNOWLEDGE:
if (!dev->scl && scl) {
i2c_gpio_log(2, "I2C GPIO %s: Acknowledging transfer\n", dev->bus_name);
sda = 0;
dev->pos = 0;
dev->state = (dev->transmit == TRANSMITTER_MASTER) ? I2C_RECEIVE_WAIT : I2C_TRANSMIT;
@@ -193,12 +232,14 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
case I2C_TRANSACKNOWLEDGE:
if (!dev->scl && scl) {
if (sda) { /* not acknowledged; must be end of transfer */
i2c_gpio_log(2, "I2C GPIO %s: End of transfer\n", dev->bus_name);
dev->state = I2C_IDLE;
i2c_gpio_stop(dev);
} else { /* next byte to transfer */
dev->state = I2C_TRANSMIT_START;
i2c_gpio_next_byte(dev);
dev->pos = 0;
i2c_gpio_log(2, "I2C GPIO %s: Next byte = %02X\n", dev->bus_name, dev->byte);
}
}
break;
@@ -208,8 +249,10 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
if (dev->last_sda && !sda) { /* start bit */
i2c_gpio_next_byte(dev);
dev->pos = 0;
i2c_gpio_log(2, "I2C GPIO %s: Next byte = %02X\n", dev->bus_name, dev->byte);
}
if (!dev->last_sda && sda) { /* stop bit */
i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_WAIT)\n", dev->bus_name);
dev->state = I2C_IDLE;
i2c_gpio_stop(dev);
}
@@ -220,6 +263,7 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
if (!dev->scl && scl)
dev->state = I2C_TRANSMIT;
if (dev->scl && scl && !dev->last_sda && sda) { /* stop bit */
i2c_gpio_log(2, "I2C GPIO %s: Stop bit received (from TRANSMIT_START)\n", dev->bus_name);
dev->state = I2C_IDLE;
i2c_gpio_stop(dev);
}
@@ -228,13 +272,18 @@ i2c_gpio_set(void *dev_handle, uint8_t scl, uint8_t sda)
case I2C_TRANSMIT:
if (!dev->scl && scl) {
dev->scl = scl;
if (!dev->pos)
i2c_gpio_log(2, "I2C GPIO %s: Transmit byte %02X\n", dev->bus_name, dev->byte);
dev->sda = sda = dev->byte & 0x80;
i2c_gpio_log(2, "I2C GPIO %s: Transmit bit %02X %d\n", dev->bus_name, dev->byte, dev->pos);
dev->byte <<= 1;
dev->pos++;
return;
}
if (dev->scl && !scl && (dev->pos == 8))
if (dev->scl && !scl && (dev->pos == 8)) {
dev->state = I2C_TRANSACKNOWLEDGE;
i2c_gpio_log(2, "I2C GPIO %s: Acknowledge mode\n", dev->bus_name);
}
break;
}

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;
}

View File

@@ -38,7 +38,7 @@ static uint8_t edid_data[128] = {
0x08, /* Analog input, separate sync */
34, 0, /* Landscape, 4:3 */
0, /* Gamma */
0x08, /* RGB colour */
0x08, /* RGB color */
0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /* Chromaticity */
0xff, 0xff, 0xff, /* Established timing bitmap */