mirror of
https://github.com/86Box/86Box.git
synced 2026-02-22 01:25:33 -07:00
Merge pull request #6751 from disean/nmc93cxx_rewrite
nmc93cxx: Rewrite the nmc93cxx emulation
This commit is contained in:
@@ -1,25 +1,72 @@
|
||||
#include <86box/vid_ati_eeprom.h>
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Header of the emulation of the National Semiconductors NMC93Cxx EEPROMs
|
||||
* (16 bits or 8 bits).
|
||||
*
|
||||
* Authors: Cacodemon345
|
||||
*
|
||||
* Copyright 2023 Cacodemon345
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
typedef struct nmc93cxx_eeprom_t {
|
||||
ati_eeprom_t dev;
|
||||
uint8_t addrbits;
|
||||
uint16_t size;
|
||||
char filename[1024];
|
||||
} nmc93cxx_eeprom_t;
|
||||
/* Forward declaration to hide internal device state from users. */
|
||||
typedef struct nmc93cxx_eeprom_t nmc93cxx_eeprom_t;
|
||||
|
||||
/* EEPROM device type used to specify the size of data array. */
|
||||
typedef enum nmc93cxx_eeprom_type {
|
||||
/*
|
||||
* Standard 93CX6 class of 16-bit EEPROMs.
|
||||
*
|
||||
* Type / Bits per cell / Number of cells
|
||||
*/
|
||||
NMC_93C06_x16_16,
|
||||
NMC_93C46_x16_64,
|
||||
NMC_93C56_x16_128,
|
||||
NMC_93C57_x16_128,
|
||||
NMC_93C66_x16_256,
|
||||
NMC_93C76_x16_512,
|
||||
NMC_93C86_x16_1024,
|
||||
|
||||
/*
|
||||
* Some manufacturers use pin 6 as an "ORG" pin which,
|
||||
* when pulled low, configures memory for 8-bit accesses.
|
||||
*
|
||||
* Type / Bits per cell / Number of cells
|
||||
*/
|
||||
NMC_93C46_x8_128,
|
||||
NMC_93C56_x8_256,
|
||||
NMC_93C57_x8_256,
|
||||
NMC_93C66_x8_512,
|
||||
NMC_93C76_x8_1024,
|
||||
NMC_93C86_x8_2048,
|
||||
} nmc93cxx_eeprom_type;
|
||||
|
||||
/* EEPROM device parameters. */
|
||||
typedef struct nmc93cxx_eeprom_params_t {
|
||||
uint16_t nwords;
|
||||
char *filename;
|
||||
uint16_t *default_content;
|
||||
/* Device type */
|
||||
nmc93cxx_eeprom_type type;
|
||||
/* Name of EEPROM image file */
|
||||
const char *filename;
|
||||
/*
|
||||
* Optional pointer to the default data buffer.
|
||||
* The buffer size should match the size of EEPROM data array specified by nmc93cxx_eeprom_type.
|
||||
*/
|
||||
const void *default_content;
|
||||
} nmc93cxx_eeprom_params_t;
|
||||
|
||||
/* Read from the EEPROM. */
|
||||
uint16_t nmc93cxx_eeprom_read(nmc93cxx_eeprom_t *eeprom);
|
||||
/* Read the state of the data output (DO) line. */
|
||||
bool nmc93cxx_eeprom_read(nmc93cxx_eeprom_t *dev);
|
||||
|
||||
/* Write to the EEPROM. */
|
||||
void nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi);
|
||||
/* Set the state of the input lines. */
|
||||
void nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *dev, bool eecs, bool eesk, bool eedi);
|
||||
|
||||
/* Get EEPROM data array. */
|
||||
uint16_t *nmc93cxx_eeprom_data(nmc93cxx_eeprom_t *eeprom);
|
||||
/* Returns pointer to the current EEPROM data array. */
|
||||
const uint16_t *nmc93cxx_eeprom_data(nmc93cxx_eeprom_t *dev);
|
||||
|
||||
extern const device_t nmc93cxx_device;
|
||||
|
||||
@@ -6,267 +6,676 @@
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Emulation of National Semiconductors NMC93Cxx EEPROMs.
|
||||
* Emulation of National Semiconductors NMC93Cxx EEPROMs (16 bits or 8 bits).
|
||||
*
|
||||
* Authors: Cacodemon345
|
||||
*
|
||||
* Copyright 2023 Cacodemon345
|
||||
*/
|
||||
|
||||
/* Ported over from QEMU */
|
||||
/* Ported over from the MAME eepromser.cpp implementation. Copyright 2013 Aaron Giles */
|
||||
|
||||
#ifdef ENABLE_NMC93CXX_EEPROM_LOG
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <wchar.h>
|
||||
#include <time.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <assert.h>
|
||||
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/nvr.h>
|
||||
#include <86box/log.h>
|
||||
#include <86box/nmc93cxx.h>
|
||||
#include <86box/plat_unused.h>
|
||||
|
||||
#define WRITE_TIME_US 1750
|
||||
#define WRITE_ALL_TIME_US 8000
|
||||
#define ERASE_TIME_US 1000
|
||||
#define ERASE_ALL_TIME_US 8000
|
||||
|
||||
typedef enum EepromCommand {
|
||||
COMMAND_INVALID,
|
||||
COMMAND_READ,
|
||||
COMMAND_WRITE,
|
||||
COMMAND_ERASE,
|
||||
COMMAND_LOCK,
|
||||
COMMAND_UNLOCK,
|
||||
COMMAND_WRITEALL,
|
||||
COMMAND_ERASEALL,
|
||||
COMMAND_COPY_EEPROM_TO_RAM,
|
||||
COMMAND_COPY_RAM_TO_EEPROM
|
||||
} EepromCommand;
|
||||
|
||||
typedef enum EepromState {
|
||||
STATE_IN_RESET,
|
||||
STATE_WAIT_FOR_START_BIT,
|
||||
STATE_WAIT_FOR_COMMAND,
|
||||
STATE_READING_DATA,
|
||||
STATE_WAIT_FOR_DATA,
|
||||
STATE_WAIT_FOR_COMPLETION
|
||||
} EepromState;
|
||||
|
||||
typedef enum EepromEvent {
|
||||
EVENT_CS_RISING_EDGE = 1 << 0,
|
||||
EVENT_CS_FALLING_EDGE = 1 << 1,
|
||||
EVENT_CLK_RISING_EDGE = 1 << 2,
|
||||
EVENT_CLK_FALLING_EDGE = 1 << 3
|
||||
} EepromEvent;
|
||||
|
||||
struct nmc93cxx_eeprom_t {
|
||||
/* Command completion timer */
|
||||
pc_timer_t cmd_complete_timer;
|
||||
/* Write tick */
|
||||
uint32_t write_tick;
|
||||
/* State of the CS line */
|
||||
bool cs_state;
|
||||
/* State of the CLK line */
|
||||
bool clk_state;
|
||||
/* State of the DI line */
|
||||
bool di_state;
|
||||
/* READY/BUSY status during a programming operation */
|
||||
bool is_busy;
|
||||
/* Internal device state */
|
||||
EepromState state;
|
||||
/* Accumulator of command+address bits */
|
||||
uint32_t command_address_accum;
|
||||
/* Current address extracted from command */
|
||||
uint32_t address;
|
||||
/* Holds data coming in/going out */
|
||||
uint32_t shift_register;
|
||||
/* Number of bits accumulated */
|
||||
uint32_t bits_accum;
|
||||
/* Current command */
|
||||
EepromCommand command;
|
||||
/* Number of memory cells */
|
||||
uint16_t cells;
|
||||
/* Number of bits per cell */
|
||||
uint16_t data_bits;
|
||||
/* Number of address bits in a command */
|
||||
uint8_t command_address_bits;
|
||||
/* Number of address bits in an address */
|
||||
uint8_t address_bits;
|
||||
/* Are we locked against writes? */
|
||||
bool is_locked;
|
||||
/* Tick of the last CS rising edge */
|
||||
uint32_t last_cs_rising_edge_tick;
|
||||
/* Device logging */
|
||||
void *log;
|
||||
/* Name of EEPROM image file */
|
||||
char filename[1024];
|
||||
|
||||
/* EEPROM image words, must be the last structure member */
|
||||
uint16_t array_data[];
|
||||
};
|
||||
|
||||
#ifdef ENABLE_NMC93CXX_EEPROM_LOG
|
||||
int nmc93cxx_eeprom_do_log = ENABLE_NMC93CXX_EEPROM_LOG;
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_log(int lvl, const char *fmt, ...)
|
||||
nmc93cxx_eeprom_log(nmc93cxx_eeprom_t *dev, int lvl, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (nmc93cxx_eeprom_do_log >= lvl) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
log_out(dev->log, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define nmc93cxx_eeprom_log(lvl, fmt, ...)
|
||||
# define nmc93cxx_eeprom_log(dev, lvl, fmt, ...)
|
||||
#endif
|
||||
|
||||
#define MAKE_CASE(x) case x: return #x;
|
||||
static char*
|
||||
nmc93cxx_eeprom_state_to_name(EepromState state)
|
||||
{
|
||||
switch (state) {
|
||||
MAKE_CASE(STATE_IN_RESET);
|
||||
MAKE_CASE(STATE_WAIT_FOR_START_BIT);
|
||||
MAKE_CASE(STATE_WAIT_FOR_COMMAND);
|
||||
MAKE_CASE(STATE_READING_DATA);
|
||||
MAKE_CASE(STATE_WAIT_FOR_DATA);
|
||||
MAKE_CASE(STATE_WAIT_FOR_COMPLETION);
|
||||
default: return "<UNK>";
|
||||
}
|
||||
}
|
||||
|
||||
static char*
|
||||
nmc93cxx_eeprom_cmd_to_name(EepromCommand command)
|
||||
{
|
||||
switch (command) {
|
||||
MAKE_CASE(COMMAND_INVALID);
|
||||
MAKE_CASE(COMMAND_READ);
|
||||
MAKE_CASE(COMMAND_WRITE);
|
||||
MAKE_CASE(COMMAND_ERASE);
|
||||
MAKE_CASE(COMMAND_LOCK);
|
||||
MAKE_CASE(COMMAND_UNLOCK);
|
||||
MAKE_CASE(COMMAND_WRITEALL);
|
||||
MAKE_CASE(COMMAND_ERASEALL);
|
||||
MAKE_CASE(COMMAND_COPY_EEPROM_TO_RAM);
|
||||
MAKE_CASE(COMMAND_COPY_RAM_TO_EEPROM);
|
||||
default: return "<UNK>";
|
||||
}
|
||||
}
|
||||
#undef MAKE_CASE
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_set_state(nmc93cxx_eeprom_t *dev, EepromState state)
|
||||
{
|
||||
if (dev->state != state) {
|
||||
nmc93cxx_eeprom_log(dev, 2, "EEPROM: New state %s\n", nmc93cxx_eeprom_state_to_name(state));
|
||||
}
|
||||
dev->state = state;
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_cmd_complete_timer_callback(void *priv)
|
||||
{
|
||||
nmc93cxx_eeprom_t *dev = priv;
|
||||
|
||||
dev->is_busy = false;
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_start_cmd_timer(nmc93cxx_eeprom_t *dev, double period)
|
||||
{
|
||||
dev->is_busy = true;
|
||||
timer_on_auto(&dev->cmd_complete_timer, period);
|
||||
}
|
||||
|
||||
static void *
|
||||
nmc93cxx_eeprom_init(const device_t *info)
|
||||
{
|
||||
uint16_t nwords = 64;
|
||||
uint8_t addrbits = 6;
|
||||
uint8_t filldefault = 1;
|
||||
nmc93cxx_eeprom_params_t *params_details = (nmc93cxx_eeprom_params_t *) info->local;
|
||||
nmc93cxx_eeprom_t *eeprom = NULL;
|
||||
if (info->local == 0)
|
||||
return NULL;
|
||||
nmc93cxx_eeprom_t *dev;
|
||||
bool fill_default = true;
|
||||
uint16_t cells, nwords, data_bits;
|
||||
uint8_t addrbits;
|
||||
|
||||
nwords = params_details->nwords;
|
||||
/* Check for mandatory parameters */
|
||||
assert(params_details != NULL);
|
||||
assert(params_details->filename != NULL);
|
||||
|
||||
switch (nwords) {
|
||||
case 16:
|
||||
case 64:
|
||||
switch (params_details->type) {
|
||||
/* 16-bit EEPROMs */
|
||||
case NMC_93C06_x16_16:
|
||||
cells = 16;
|
||||
addrbits = 6;
|
||||
data_bits = 16;
|
||||
break;
|
||||
case 128:
|
||||
case 256:
|
||||
case NMC_93C46_x16_64:
|
||||
cells = 64;
|
||||
addrbits = 6;
|
||||
data_bits = 16;
|
||||
break;
|
||||
case NMC_93C56_x16_128:
|
||||
cells = 128;
|
||||
addrbits = 8;
|
||||
data_bits = 16;
|
||||
break;
|
||||
case NMC_93C57_x16_128:
|
||||
cells = 128;
|
||||
addrbits = 7;
|
||||
data_bits = 16;
|
||||
break;
|
||||
case NMC_93C66_x16_256:
|
||||
cells = 256;
|
||||
addrbits = 8;
|
||||
data_bits = 16;
|
||||
break;
|
||||
case NMC_93C76_x16_512:
|
||||
cells = 512;
|
||||
addrbits = 10;
|
||||
data_bits = 16;
|
||||
break;
|
||||
case NMC_93C86_x16_1024:
|
||||
cells = 1024;
|
||||
addrbits = 10;
|
||||
data_bits = 16;
|
||||
break;
|
||||
|
||||
/* 8-bit EEPROMs */
|
||||
case NMC_93C46_x8_128:
|
||||
cells = 128;
|
||||
addrbits = 7;
|
||||
data_bits = 8;
|
||||
break;
|
||||
case NMC_93C56_x8_256:
|
||||
cells = 256;
|
||||
addrbits = 9;
|
||||
data_bits = 8;
|
||||
break;
|
||||
case NMC_93C57_x8_256:
|
||||
cells = 256;
|
||||
addrbits = 8;
|
||||
data_bits = 8;
|
||||
break;
|
||||
case NMC_93C66_x8_512:
|
||||
cells = 512;
|
||||
addrbits = 9;
|
||||
data_bits = 8;
|
||||
break;
|
||||
case NMC_93C76_x8_1024:
|
||||
cells = 1024;
|
||||
addrbits = 11;
|
||||
data_bits = 8;
|
||||
break;
|
||||
case NMC_93C86_x8_2048:
|
||||
cells = 1024;
|
||||
addrbits = 11;
|
||||
data_bits = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
nwords = 64;
|
||||
addrbits = 6;
|
||||
/* Invalid parameter passed to the device */
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
eeprom = calloc(1, sizeof(nmc93cxx_eeprom_t) + ((nwords + 1) * 2));
|
||||
if (!eeprom)
|
||||
|
||||
/* The "ORG" pin can select the x8 or x16 memory organization */
|
||||
if (data_bits == 16) {
|
||||
nwords = cells;
|
||||
} else {
|
||||
nwords = cells / 2;
|
||||
|
||||
assert(data_bits == 8);
|
||||
}
|
||||
|
||||
dev = calloc(1, offsetof(nmc93cxx_eeprom_t, array_data[nwords]));
|
||||
if (!dev)
|
||||
return NULL;
|
||||
eeprom->size = nwords;
|
||||
eeprom->addrbits = addrbits;
|
||||
/* Output DO is tristate, read results in 1. */
|
||||
eeprom->dev.out = 1;
|
||||
dev->cells = cells;
|
||||
dev->command_address_bits = addrbits;
|
||||
dev->data_bits = data_bits;
|
||||
dev->is_locked = true;
|
||||
dev->command = COMMAND_INVALID;
|
||||
dev->log = log_open("nmc93cxx");
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
|
||||
if (params_details->filename) {
|
||||
FILE *fp = nvr_fopen(params_details->filename, "rb");
|
||||
strncpy(eeprom->filename, params_details->filename, sizeof(eeprom->filename) - 1);
|
||||
if (fp) {
|
||||
filldefault = !fread(eeprom->dev.data, sizeof(uint16_t), nwords, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
/* Load the EEPROM image */
|
||||
snprintf(dev->filename, sizeof(dev->filename), "%s", params_details->filename);
|
||||
FILE *fp = nvr_fopen(dev->filename, "rb");
|
||||
if (fp) {
|
||||
fill_default = !fread(dev->array_data, dev->data_bits / 8, dev->cells, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
if (fill_default && params_details->default_content) {
|
||||
memcpy(dev->array_data, params_details->default_content, dev->cells * (dev->data_bits / 8));
|
||||
}
|
||||
|
||||
if (filldefault) {
|
||||
memcpy(eeprom->dev.data, params_details->default_content, nwords * sizeof(uint16_t));
|
||||
/* Compute address bits */
|
||||
uint32_t count = dev->cells - 1;
|
||||
dev->address_bits = 0;
|
||||
while (count != 0) {
|
||||
count >>= 1;
|
||||
dev->address_bits++;
|
||||
}
|
||||
|
||||
return eeprom;
|
||||
timer_add(&dev->cmd_complete_timer, nmc93cxx_eeprom_cmd_complete_timer_callback, dev, 0);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
nmc93cxx_eeprom_cell_read(nmc93cxx_eeprom_t *dev, uint32_t address)
|
||||
{
|
||||
if (dev->data_bits == 16) {
|
||||
return dev->array_data[address];
|
||||
} else {
|
||||
return *((uint8_t *)dev->array_data + address);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_save(nmc93cxx_eeprom_t *eeprom)
|
||||
nmc93cxx_eeprom_cell_write(nmc93cxx_eeprom_t *dev, uint32_t address, uint32_t data)
|
||||
{
|
||||
FILE *fp = nvr_fopen(eeprom->filename, "wb");
|
||||
if (!fp)
|
||||
return;
|
||||
fwrite(eeprom->dev.data, 2, eeprom->size, fp);
|
||||
fclose(fp);
|
||||
if (dev->data_bits == 16) {
|
||||
dev->array_data[address] = data;
|
||||
} else {
|
||||
*((uint8_t *)dev->array_data + address) = data;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_handle_cmd_write(nmc93cxx_eeprom_t *dev, uint32_t address, uint32_t data)
|
||||
{
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: WR %08lX <-- %X\n", address, data);
|
||||
|
||||
nmc93cxx_eeprom_cell_write(dev, address, data);
|
||||
nmc93cxx_eeprom_start_cmd_timer(dev, WRITE_TIME_US);
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_handle_cmd_write_all(nmc93cxx_eeprom_t *dev, uint32_t data)
|
||||
{
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Write all operation %X\n", data);
|
||||
|
||||
for (uint32_t address = 0; address < (1 << dev->address_bits); ++address) {
|
||||
nmc93cxx_eeprom_cell_write(dev, address, nmc93cxx_eeprom_cell_read(dev, address) & data);
|
||||
}
|
||||
|
||||
nmc93cxx_eeprom_start_cmd_timer(dev, WRITE_ALL_TIME_US);
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_handle_cmd_erase(nmc93cxx_eeprom_t *dev, uint32_t address)
|
||||
{
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Erase data at %08lx\n", address);
|
||||
|
||||
nmc93cxx_eeprom_cell_write(dev, address, ~0);
|
||||
nmc93cxx_eeprom_start_cmd_timer(dev, ERASE_TIME_US);
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_handle_cmd_erase_all(nmc93cxx_eeprom_t *dev)
|
||||
{
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Erase all operation\n");
|
||||
|
||||
for (uint32_t address = 0; address < (1 << dev->address_bits); ++address) {
|
||||
nmc93cxx_eeprom_cell_write(dev, address, ~0);
|
||||
}
|
||||
|
||||
nmc93cxx_eeprom_start_cmd_timer(dev, ERASE_ALL_TIME_US);
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_parse_command_and_address(nmc93cxx_eeprom_t *dev)
|
||||
{
|
||||
dev->address = dev->command_address_accum & ((1 << dev->command_address_bits) - 1);
|
||||
|
||||
/* Extract the command portion and handle it */
|
||||
switch (dev->command_address_accum >> dev->command_address_bits) {
|
||||
/* Opcode 0 needs two more bits to decode the operation */
|
||||
case 0:
|
||||
switch (dev->address >> (dev->command_address_bits - 2)) {
|
||||
case 0: dev->command = COMMAND_LOCK; break;
|
||||
case 1: dev->command = COMMAND_WRITEALL; break;
|
||||
case 2: dev->command = COMMAND_ERASEALL; break;
|
||||
case 3: dev->command = COMMAND_UNLOCK; break;
|
||||
}
|
||||
dev->address = 0;
|
||||
break;
|
||||
|
||||
case 1: dev->command = COMMAND_WRITE; break;
|
||||
case 2: dev->command = COMMAND_READ; break;
|
||||
case 3: dev->command = COMMAND_ERASE; break;
|
||||
|
||||
default:
|
||||
dev->command = COMMAND_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev->address >= (1 << dev->address_bits)) {
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: out-of-range address 0x%X provided (maximum should be 0x%X)\n", dev->address, (1 << dev->address_bits) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_execute_command(nmc93cxx_eeprom_t *dev)
|
||||
{
|
||||
/* Parse into a generic command and reset the accumulator count */
|
||||
nmc93cxx_eeprom_parse_command_and_address(dev);
|
||||
dev->bits_accum = 0;
|
||||
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Execute command %s\n", nmc93cxx_eeprom_cmd_to_name(dev->command));
|
||||
switch (dev->command) {
|
||||
/*
|
||||
* Advance to the READING_DATA state; data is fetched after first CLK
|
||||
* reset the shift register to 0 to simulate the dummy 0 bit that happens prior
|
||||
* to the first clock
|
||||
*/
|
||||
case COMMAND_READ:
|
||||
dev->shift_register = 0;
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_READING_DATA);
|
||||
break;
|
||||
|
||||
/* Reset the shift register and wait for enough data to be clocked through */
|
||||
case COMMAND_WRITE:
|
||||
case COMMAND_WRITEALL:
|
||||
dev->shift_register = 0;
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_WAIT_FOR_DATA);
|
||||
break;
|
||||
|
||||
/* Erase the parsed address (unless locked) and wait for it to complete */
|
||||
case COMMAND_ERASE:
|
||||
if (dev->is_locked) {
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Attempt to erase while locked\n");
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
break;
|
||||
}
|
||||
nmc93cxx_eeprom_handle_cmd_erase(dev, dev->address);
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_WAIT_FOR_COMPLETION);
|
||||
break;
|
||||
|
||||
/* Lock the chip; return to IN_RESET state */
|
||||
case COMMAND_LOCK:
|
||||
dev->is_locked = true;
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
break;
|
||||
|
||||
/* Unlock the chip; return to IN_RESET state */
|
||||
case COMMAND_UNLOCK:
|
||||
dev->is_locked = false;
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
break;
|
||||
|
||||
/* Erase the entire chip (unless locked) and wait for it to complete */
|
||||
case COMMAND_ERASEALL:
|
||||
if (dev->is_locked) {
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Attempt to erase all while locked\n");
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
break;
|
||||
}
|
||||
nmc93cxx_eeprom_handle_cmd_erase_all(dev);
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_WAIT_FOR_COMPLETION);
|
||||
break;
|
||||
|
||||
default:
|
||||
nmc93cxx_eeprom_log(dev, 1, "execute_command called with invalid command %d\n", dev->command);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_execute_write_command(nmc93cxx_eeprom_t *dev)
|
||||
{
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Execute write command %s\n", nmc93cxx_eeprom_cmd_to_name(dev->command));
|
||||
|
||||
switch (dev->command) {
|
||||
/* Reset the shift register and wait for enough data to be clocked through */
|
||||
case COMMAND_WRITE:
|
||||
if (dev->is_locked) {
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Attempt to write to address 0x%X while locked\n", dev->address);
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
break;
|
||||
}
|
||||
nmc93cxx_eeprom_handle_cmd_write(dev, dev->address, dev->shift_register);
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_WAIT_FOR_COMPLETION);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Write the entire EEPROM with the same data; ERASEALL is required before so we
|
||||
* AND against the already-present data
|
||||
*/
|
||||
case COMMAND_WRITEALL:
|
||||
if (dev->is_locked) {
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Attempt to write all while locked\n");
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
break;
|
||||
}
|
||||
nmc93cxx_eeprom_handle_cmd_write_all(dev, dev->shift_register);
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_WAIT_FOR_COMPLETION);
|
||||
break;
|
||||
|
||||
default:
|
||||
nmc93cxx_eeprom_log(dev, 1, "execute_command called with invalid command %d\n", dev->command);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_handle_event(nmc93cxx_eeprom_t *dev, EepromEvent event)
|
||||
{
|
||||
switch (dev->state) {
|
||||
/* CS is not asserted; wait for a rising CS to move us forward, ignoring all clocks */
|
||||
case STATE_IN_RESET:
|
||||
if (event == EVENT_CS_RISING_EDGE)
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_WAIT_FOR_START_BIT);
|
||||
break;
|
||||
|
||||
/*
|
||||
* CS is asserted; wait for rising clock with a 1 start bit; falling CS will reset us
|
||||
* note that because each bit is written independently, it is possible for us to receive
|
||||
* a false rising CLK edge at the exact same time as a rising CS edge; it appears we
|
||||
* should ignore these edges (makes sense really)
|
||||
*/
|
||||
case STATE_WAIT_FOR_START_BIT:
|
||||
if ((event == EVENT_CLK_RISING_EDGE) && dev->di_state && !dev->is_busy && (dev->write_tick != dev->last_cs_rising_edge_tick)) {
|
||||
dev->command_address_accum = 0;
|
||||
dev->bits_accum = 0;
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_WAIT_FOR_COMMAND);
|
||||
} else if (event == EVENT_CS_FALLING_EDGE)
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
break;
|
||||
|
||||
/* CS is asserted; wait for a command to come through; falling CS will reset us */
|
||||
case STATE_WAIT_FOR_COMMAND:
|
||||
if (event == EVENT_CLK_RISING_EDGE) {
|
||||
/* If we have enough bits for a command + address, check it out */
|
||||
dev->command_address_accum = (dev->command_address_accum << 1) | dev->di_state;
|
||||
if (++dev->bits_accum == 2 + dev->command_address_bits)
|
||||
nmc93cxx_eeprom_execute_command(dev);
|
||||
} else if (event == EVENT_CS_FALLING_EDGE)
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
break;
|
||||
|
||||
/* CS is asserted; reading data, clock the shift register; falling CS will reset us */
|
||||
case STATE_READING_DATA:
|
||||
if (event == EVENT_CLK_RISING_EDGE) {
|
||||
uint32_t bit_index = dev->bits_accum++;
|
||||
|
||||
/* Wrapping the address on multi-read */
|
||||
if (((bit_index % dev->data_bits) == 0) && (bit_index == 0))
|
||||
{
|
||||
uint32_t addr = (dev->address + dev->bits_accum / dev->data_bits) & ((1 << dev->address_bits) - 1);
|
||||
uint32_t data = nmc93cxx_eeprom_cell_read(dev, addr);
|
||||
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: RD %08lX --> %X\n", addr, data);
|
||||
|
||||
dev->shift_register = data << (32 - dev->data_bits);
|
||||
} else {
|
||||
dev->shift_register = (dev->shift_register << 1) | 1;
|
||||
}
|
||||
} else if (event == EVENT_CS_FALLING_EDGE) {
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
|
||||
if (dev->bits_accum > (dev->data_bits + 1))
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: Overclocked read by %d bits\n", dev->bits_accum - dev->data_bits);
|
||||
else if (dev->bits_accum < dev->data_bits)
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: CS deasserted in READING_DATA after %d bits\n", dev->bits_accum);
|
||||
}
|
||||
break;
|
||||
|
||||
/* CS is asserted; waiting for data; clock data through until we accumulate enough; falling CS will reset us */
|
||||
case STATE_WAIT_FOR_DATA:
|
||||
if (event == EVENT_CLK_RISING_EDGE) {
|
||||
dev->shift_register = (dev->shift_register << 1) | dev->di_state;
|
||||
if (++dev->bits_accum == dev->data_bits)
|
||||
nmc93cxx_eeprom_execute_write_command(dev);
|
||||
} else if (event == EVENT_CS_FALLING_EDGE) {
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
nmc93cxx_eeprom_log(dev, 1, "EEPROM: CS deasserted in STATE_WAIT_FOR_DATA after %d bits\n", dev->bits_accum);
|
||||
}
|
||||
break;
|
||||
|
||||
/* CS is asserted; waiting for completion; watch for CS falling */
|
||||
case STATE_WAIT_FOR_COMPLETION:
|
||||
if (event == EVENT_CS_FALLING_EDGE)
|
||||
nmc93cxx_eeprom_set_state(dev, STATE_IN_RESET);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi)
|
||||
nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *dev, bool eecs, bool eesk, bool eedi)
|
||||
{
|
||||
uint8_t tick = eeprom->dev.count;
|
||||
uint8_t eedo = eeprom->dev.out;
|
||||
uint16_t address = eeprom->dev.address;
|
||||
uint8_t command = eeprom->dev.opcode;
|
||||
assert(dev != NULL);
|
||||
|
||||
nmc93cxx_eeprom_log(1, "CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
|
||||
eecs, eesk, eedi, eedo, tick);
|
||||
dev->write_tick++;
|
||||
|
||||
if (!eeprom->dev.oldena && eecs) {
|
||||
/* Start chip select cycle. */
|
||||
nmc93cxx_eeprom_log(1, "Cycle start, waiting for 1st start bit (0)\n");
|
||||
tick = 0;
|
||||
command = 0x0;
|
||||
address = 0x0;
|
||||
} else if (eeprom->dev.oldena && !eecs) {
|
||||
/* End chip select cycle. This triggers write / erase. */
|
||||
if (!eeprom->dev.wp) {
|
||||
uint8_t subcommand = address >> (eeprom->addrbits - 2);
|
||||
if (command == 0 && subcommand == 2) {
|
||||
/* Erase all. */
|
||||
for (address = 0; address < eeprom->size; address++)
|
||||
eeprom->dev.data[address] = 0xffff;
|
||||
nmc93cxx_eeprom_log(dev, 3, "EEPROM: CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
|
||||
eecs, eesk, eedi, nmc93cxx_eeprom_read(dev), dev->write_tick);
|
||||
|
||||
nmc93cxx_eeprom_save(eeprom);
|
||||
} else if (command == 3) {
|
||||
/* Erase word. */
|
||||
eeprom->dev.data[address] = 0xffff;
|
||||
nmc93cxx_eeprom_save(eeprom);
|
||||
} else if (tick >= (2 + 2 + eeprom->addrbits + 16)) {
|
||||
if (command == 1) {
|
||||
/* Write word. */
|
||||
eeprom->dev.data[address] &= eeprom->dev.dat;
|
||||
nmc93cxx_eeprom_save(eeprom);
|
||||
} else if (command == 0 && subcommand == 1) {
|
||||
/* Write all. */
|
||||
for (address = 0; address < eeprom->size; address++)
|
||||
eeprom->dev.data[address] &= eeprom->dev.dat;
|
||||
if (dev->cs_state != eecs) {
|
||||
dev->cs_state = eecs;
|
||||
|
||||
nmc93cxx_eeprom_save(eeprom);
|
||||
}
|
||||
}
|
||||
/* Remember the rising edge tick so we don't process CLK signals at the same time */
|
||||
if (eecs) {
|
||||
dev->last_cs_rising_edge_tick = dev->write_tick;
|
||||
}
|
||||
/* Output DO is tristate, read results in 1. */
|
||||
eedo = 1;
|
||||
} else if (eecs && !eeprom->dev.oldclk && eesk) {
|
||||
/* Raising edge of clock shifts data in. */
|
||||
if (tick == 0) {
|
||||
/* Wait for 1st start bit. */
|
||||
if (eedi == 0) {
|
||||
nmc93cxx_eeprom_log(1, "Got correct 1st start bit, waiting for 2nd start bit (1)\n");
|
||||
tick++;
|
||||
} else {
|
||||
nmc93cxx_eeprom_log(1, "wrong 1st start bit (is 1, should be 0)\n");
|
||||
tick = 2;
|
||||
#if 0
|
||||
~ assert(!"wrong start bit");
|
||||
#endif
|
||||
}
|
||||
} else if (tick == 1) {
|
||||
/* Wait for 2nd start bit. */
|
||||
if (eedi != 0) {
|
||||
nmc93cxx_eeprom_log(1, "Got correct 2nd start bit, getting command + address\n");
|
||||
tick++;
|
||||
} else {
|
||||
nmc93cxx_eeprom_log(1, "1st start bit is longer than needed\n");
|
||||
}
|
||||
} else if (tick < 2 + 2) {
|
||||
/* Got 2 start bits, transfer 2 opcode bits. */
|
||||
tick++;
|
||||
command <<= 1;
|
||||
if (eedi) {
|
||||
command += 1;
|
||||
}
|
||||
} else if (tick < 2 + 2 + eeprom->addrbits) {
|
||||
/* Got 2 start bits and 2 opcode bits, transfer all address bits. */
|
||||
tick++;
|
||||
address = ((address << 1) | eedi);
|
||||
if (tick == 2 + 2 + eeprom->addrbits) {
|
||||
nmc93cxx_eeprom_log(1, "Address = 0x%02x (value 0x%04x)\n",
|
||||
address, eeprom->dev.data[address]);
|
||||
if (command == 2) {
|
||||
eedo = 0;
|
||||
}
|
||||
address = address % eeprom->size;
|
||||
if (command == 0) {
|
||||
/* Command code in upper 2 bits of address. */
|
||||
switch (address >> (eeprom->addrbits - 2)) {
|
||||
case 0:
|
||||
nmc93cxx_eeprom_log(1, "write disable command\n");
|
||||
eeprom->dev.wp = 1;
|
||||
break;
|
||||
case 1:
|
||||
nmc93cxx_eeprom_log(1, "write all command\n");
|
||||
break;
|
||||
case 2:
|
||||
nmc93cxx_eeprom_log(1, "erase all command\n");
|
||||
break;
|
||||
case 3:
|
||||
nmc93cxx_eeprom_log(1, "write enable command\n");
|
||||
eeprom->dev.wp = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Read, write or erase word. */
|
||||
eeprom->dev.dat = eeprom->dev.data[address];
|
||||
}
|
||||
}
|
||||
} else if (tick < 2 + 2 + eeprom->addrbits + 16) {
|
||||
/* Transfer 16 data bits. */
|
||||
tick++;
|
||||
if (command == 2) {
|
||||
/* Read word. */
|
||||
eedo = ((eeprom->dev.dat & 0x8000) != 0);
|
||||
}
|
||||
eeprom->dev.dat <<= 1;
|
||||
eeprom->dev.dat += eedi;
|
||||
} else {
|
||||
nmc93cxx_eeprom_log(1, "additional unneeded tick, not processed\n");
|
||||
}
|
||||
nmc93cxx_eeprom_handle_event(dev, eecs ? EVENT_CS_RISING_EDGE : EVENT_CS_FALLING_EDGE);
|
||||
}
|
||||
|
||||
dev->di_state = eedi;
|
||||
|
||||
if (dev->clk_state != eesk) {
|
||||
dev->clk_state = eesk;
|
||||
nmc93cxx_eeprom_handle_event(dev, eesk ? EVENT_CLK_RISING_EDGE : EVENT_CLK_FALLING_EDGE);
|
||||
}
|
||||
/* Save status of EEPROM. */
|
||||
eeprom->dev.count = tick;
|
||||
eeprom->dev.oldena = eecs;
|
||||
eeprom->dev.oldclk = eesk;
|
||||
eeprom->dev.out = eedo;
|
||||
eeprom->dev.address = address;
|
||||
eeprom->dev.opcode = command;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
nmc93cxx_eeprom_read(nmc93cxx_eeprom_t *eeprom)
|
||||
bool
|
||||
nmc93cxx_eeprom_read(nmc93cxx_eeprom_t *dev)
|
||||
{
|
||||
/* Return status of pin DO (0 or 1). */
|
||||
return eeprom->dev.out;
|
||||
assert(dev != NULL);
|
||||
|
||||
if (dev->state == STATE_WAIT_FOR_START_BIT) {
|
||||
/* Read the state of the READY/BUSY line */
|
||||
return !dev->is_busy;
|
||||
} else if (dev->state == STATE_READING_DATA) {
|
||||
/* Read the current output bit */
|
||||
return ((dev->shift_register & 0x80000000) != 0);
|
||||
}
|
||||
|
||||
/* The DO pin is tristated */
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_close(void *priv)
|
||||
{
|
||||
nmc93cxx_eeprom_t *eeprom = (nmc93cxx_eeprom_t *) priv;
|
||||
FILE *fp = nvr_fopen(eeprom->filename, "wb");
|
||||
nmc93cxx_eeprom_t *dev = priv;
|
||||
FILE *fp = nvr_fopen(dev->filename, "wb");
|
||||
if (fp) {
|
||||
fwrite(eeprom->dev.data, 2, eeprom->size, fp);
|
||||
fwrite(dev->array_data, dev->data_bits / 8, dev->cells, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
free(priv);
|
||||
log_close(dev->log);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
uint16_t *
|
||||
nmc93cxx_eeprom_data(nmc93cxx_eeprom_t *eeprom)
|
||||
const uint16_t *
|
||||
nmc93cxx_eeprom_data(nmc93cxx_eeprom_t *dev)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
/* Get EEPROM data array. */
|
||||
return &eeprom->dev.data[0];
|
||||
return &dev->array_data[0];
|
||||
}
|
||||
|
||||
const device_t nmc93cxx_device = {
|
||||
|
||||
@@ -182,7 +182,7 @@ nic_config_reset(void *priv)
|
||||
{
|
||||
nic_t *dev = (nic_t *) priv;
|
||||
|
||||
uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom);
|
||||
const uint8_t *data = (const uint8_t *) nmc93cxx_eeprom_data(dev->eeprom);
|
||||
|
||||
dev->config1 = (data[0x00] & 0x7f) | 0x80;
|
||||
dev->config2 = (data[0x01] & 0xdf);
|
||||
@@ -425,7 +425,7 @@ page3_read(nic_t *dev, uint32_t off, UNUSED(unsigned int len))
|
||||
|
||||
case 0xd: /* CONFIG4 */
|
||||
if (dev->board == NE2K_RTL8019AS_PNP) {
|
||||
uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom);
|
||||
const uint8_t *data = (const uint8_t *) nmc93cxx_eeprom_data(dev->eeprom);
|
||||
ret = data[0x03];
|
||||
}
|
||||
break;
|
||||
@@ -464,7 +464,7 @@ page3_write(nic_t *dev, uint32_t off, uint32_t val, UNUSED(unsigned len))
|
||||
if ((val & 0xc0) == 0x80)
|
||||
nmc93cxx_eeprom_write(dev->eeprom, !!(val & 0x08), !!(val & 0x04), !!(val & 0x02));
|
||||
else if ((val & 0xc0) == 0x40) {
|
||||
uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom);
|
||||
const uint8_t *data = (const uint8_t *) nmc93cxx_eeprom_data(dev->eeprom);
|
||||
|
||||
dev->config1 = (data[0x00] & 0x7f) | 0x80;
|
||||
dev->config2 = (data[0x01] & 0xdf);
|
||||
@@ -1391,18 +1391,15 @@ nic_init(const device_t *info)
|
||||
nmc93cxx_eeprom_params_t params;
|
||||
char filename[1024] = { 0 };
|
||||
|
||||
params.nwords = 64;
|
||||
params.default_content = (uint16_t *) dev->eeprom_data;
|
||||
params.type = NMC_93C46_x16_64;
|
||||
params.default_content = dev->eeprom_data;
|
||||
params.filename = filename;
|
||||
int inst = device_get_instance();
|
||||
snprintf(filename, sizeof(filename), "nmc93cxx_eeprom_%s_%d.nvr", info->internal_name, inst);
|
||||
dev->eeprom = device_add_inst_params(&nmc93cxx_device, inst, ¶ms);
|
||||
if (dev->eeprom == NULL) {
|
||||
free(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info->local == NE2K_RTL8019AS_PNP) {
|
||||
uint8_t *data = (uint8_t *) nmc93cxx_eeprom_data(dev->eeprom);
|
||||
const uint8_t *data = (const uint8_t *) nmc93cxx_eeprom_data(dev->eeprom);
|
||||
|
||||
dev->config1 = (data[0x00] & 0x7f) | 0x80;
|
||||
dev->config2 = (data[0x01] & 0xdf);
|
||||
|
||||
@@ -3286,15 +3286,11 @@ nic_init(const device_t *info)
|
||||
for (uint32_t i = 0; i < 6; i++)
|
||||
s->phys[MAC0 + i] = mac_bytes[i];
|
||||
|
||||
params.nwords = 64;
|
||||
params.default_content = (uint16_t *) s->eeprom_data;
|
||||
params.type = NMC_93C46_x16_64;
|
||||
params.default_content = s->eeprom_data;
|
||||
params.filename = filename;
|
||||
snprintf(filename, sizeof(filename), "nmc93cxx_eeprom_%s_%d.nvr", info->internal_name, s->inst);
|
||||
s->eeprom = device_add_inst_params(&nmc93cxx_device, s->inst, ¶ms);
|
||||
if (s->eeprom == NULL) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->nic = network_attach(s, (uint8_t *) &s->phys[MAC0], rtl8139_do_receive, rtl8139_set_link_status);
|
||||
timer_add(&s->timer, rtl8139_timer, s, 0);
|
||||
|
||||
@@ -1642,16 +1642,12 @@ nic_init(const device_t *info)
|
||||
}
|
||||
|
||||
if (info->local != 3) {
|
||||
params.nwords = 64;
|
||||
params.default_content = (uint16_t *) s->eeprom_data;
|
||||
params.type = NMC_93C46_x16_64;
|
||||
params.default_content = s->eeprom_data;
|
||||
params.filename = filename;
|
||||
int inst = device_get_instance();
|
||||
snprintf(filename, sizeof(filename), "nmc93cxx_eeprom_%s_%d.nvr", info->internal_name, inst);
|
||||
s->eeprom = device_add_inst_params(&nmc93cxx_device, inst, ¶ms);
|
||||
if (s->eeprom == NULL) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
s->tulip_pci_bar[0].addr_regs[0] = 1;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
@@ -2091,19 +2092,17 @@ esp_pci_write(UNUSED(int func), int addr, UNUSED(int len), uint8_t val, void *pr
|
||||
{
|
||||
esp_t *dev = (esp_t *) priv;
|
||||
uint8_t valxor;
|
||||
int eesk;
|
||||
int eedi;
|
||||
|
||||
esp_log("%04X:%08X: ESP PCI: Write value %02X to register %02X\n", CS, cpu_state.pc, val, addr);
|
||||
|
||||
if (!dev->local) {
|
||||
if ((addr >= 0x80) && (addr <= 0xFF)) {
|
||||
if (addr == 0x80) {
|
||||
eesk = val & 0x80 ? 1 : 0;
|
||||
eedi = val & 0x40 ? 1 : 0;
|
||||
nmc93cxx_eeprom_write(dev->eeprom, 1, eesk, eedi);
|
||||
bool eesk = !!(val & 0x80);
|
||||
bool eedi = !!(val & 0x40);
|
||||
nmc93cxx_eeprom_write(dev->eeprom, true, eesk, eedi);
|
||||
} else if (addr == 0xc0)
|
||||
nmc93cxx_eeprom_write(dev->eeprom, 0, 0, 0);
|
||||
nmc93cxx_eeprom_write(dev->eeprom, false, false, false);
|
||||
// esp_log("ESP PCI: Write value %02X to register %02X\n", val, addr);
|
||||
return;
|
||||
}
|
||||
@@ -2300,8 +2299,8 @@ dc390_init(const device_t *info)
|
||||
dev->eeprom_data[EE_CHKSUM1] = checksum & 0xff;
|
||||
dev->eeprom_data[EE_CHKSUM2] = checksum >> 8;
|
||||
|
||||
params.nwords = 64;
|
||||
params.default_content = (uint16_t *) dev->eeprom_data;
|
||||
params.type = NMC_93C46_x16_64;
|
||||
params.default_content = dev->eeprom_data;
|
||||
params.filename = filename;
|
||||
snprintf(filename, sizeof(filename), "nmc93cxx_eeprom_%s_%d.nvr", info->internal_name, dev->eeprom_inst);
|
||||
dev->eeprom = device_add_inst_params(&nmc93cxx_device, dev->eeprom_inst, ¶ms);
|
||||
|
||||
@@ -12237,15 +12237,11 @@ s3_init(const device_t *info)
|
||||
checksum = s3_calc_crc16(64, s3->eeprom_data);
|
||||
|
||||
s3->eeprom_data[0x00] = checksum;
|
||||
params.nwords = 64;
|
||||
params.type = NMC_93C46_x16_64;
|
||||
params.default_content = s3->eeprom_data;
|
||||
params.filename = filename;
|
||||
snprintf(filename, sizeof(filename), "nmc93cxx_eeprom_%s_%d.nvr", info->internal_name, s3->eeprom_inst);
|
||||
s3->eeprom = device_add_inst_params(&nmc93cxx_device, s3->eeprom_inst, ¶ms);
|
||||
if (s3->eeprom == NULL) {
|
||||
free(s3);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
s3->accel.multifunc[0xd] = 0xd000;
|
||||
|
||||
Reference in New Issue
Block a user