mirror of
https://github.com/86Box/86Box.git
synced 2025-01-22 09:11:50 -05:00
Merge pull request #3504 from Cacodemon345/dec_tulip
Port DECchip 21143 "Tulip" NIC emulation from QEMU
This commit is contained in:
commit
1f963f79bc
6 changed files with 1750 additions and 1 deletions
20
src/include/86box/net_eeprom_nmc93cxx.h
Normal file
20
src/include/86box/net_eeprom_nmc93cxx.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
struct nmc93cxx_eeprom_t;
|
||||
typedef struct nmc93cxx_eeprom_t nmc93cxx_eeprom_t;
|
||||
|
||||
typedef struct nmc93cxx_eeprom_params_t
|
||||
{
|
||||
uint16_t nwords;
|
||||
char* filename;
|
||||
uint16_t* default_content;
|
||||
} nmc93cxx_eeprom_params_t;
|
||||
|
||||
/* Read from the EEPROM. */
|
||||
uint16_t nmc93cxx_eeprom_read(nmc93cxx_eeprom_t *eeprom);
|
||||
|
||||
/* Write to the EEPROM. */
|
||||
void nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi);
|
||||
|
||||
/* Get EEPROM data array. */
|
||||
uint16_t *nmc93cxx_eeprom_data(nmc93cxx_eeprom_t *eeprom);
|
||||
|
||||
extern const device_t nmc93cxx_device;
|
1
src/include/86box/net_tulip.h
Normal file
1
src/include/86box/net_tulip.h
Normal file
|
@ -0,0 +1 @@
|
|||
extern const device_t dec_tulip_device;
|
|
@ -14,7 +14,8 @@
|
|||
#
|
||||
set(net_sources)
|
||||
list(APPEND net_sources network.c net_pcap.c net_slirp.c net_dp8390.c net_3c501.c
|
||||
net_3c503.c net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c net_null.c)
|
||||
net_3c503.c net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c net_null.c
|
||||
net_eeprom_nmc93cxx.c net_tulip.c)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SLIRP REQUIRED IMPORTED_TARGET slirp)
|
||||
|
|
273
src/network/net_eeprom_nmc93cxx.c
Normal file
273
src/network/net_eeprom_nmc93cxx.c
Normal file
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* 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 National Semiconductors NMC93Cxx EEPROMs.
|
||||
*
|
||||
*
|
||||
* Authors: Cacodemon345
|
||||
*
|
||||
* Copyright 2023 Cacodemon345
|
||||
*/
|
||||
|
||||
/* Ported over from QEMU */
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <86box/86box.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/nvr.h>
|
||||
#include <86box/net_eeprom_nmc93cxx.h>
|
||||
|
||||
struct nmc93cxx_eeprom_t {
|
||||
uint8_t tick;
|
||||
uint8_t address;
|
||||
uint8_t command;
|
||||
uint8_t writable;
|
||||
|
||||
uint8_t eecs;
|
||||
uint8_t eesk;
|
||||
uint8_t eedo;
|
||||
|
||||
uint8_t addrbits;
|
||||
uint16_t size;
|
||||
uint16_t data;
|
||||
char filename[1024];
|
||||
uint16_t contents[];
|
||||
};
|
||||
|
||||
typedef struct nmc93cxx_eeprom_t nmc93cxx_eeprom_t;
|
||||
|
||||
#define logout pclog
|
||||
|
||||
static const char *opstring[] = {
|
||||
"extended", "write", "read", "erase"
|
||||
};
|
||||
|
||||
static void *
|
||||
nmc93cxx_eeprom_init_params(const device_t *info, void* params)
|
||||
{
|
||||
uint16_t nwords = 64;
|
||||
uint8_t addrbits = 6;
|
||||
uint8_t filldefault = 1;
|
||||
nmc93cxx_eeprom_params_t* params_details = (nmc93cxx_eeprom_params_t*)params;
|
||||
nmc93cxx_eeprom_t* eeprom = NULL;
|
||||
if (!params)
|
||||
return NULL;
|
||||
|
||||
nwords = params_details->nwords;
|
||||
|
||||
switch (nwords) {
|
||||
case 16:
|
||||
case 64:
|
||||
addrbits = 6;
|
||||
break;
|
||||
case 128:
|
||||
case 256:
|
||||
addrbits = 8;
|
||||
break;
|
||||
default:
|
||||
nwords = 64;
|
||||
addrbits = 6;
|
||||
break;
|
||||
}
|
||||
eeprom = calloc(1, sizeof(nmc93cxx_eeprom_t) + ((nwords + 1) * 2));
|
||||
if (!eeprom)
|
||||
return NULL;
|
||||
eeprom->size = nwords;
|
||||
eeprom->addrbits = addrbits;
|
||||
/* Output DO is tristate, read results in 1. */
|
||||
eeprom->eedo = 1;
|
||||
|
||||
if (params_details->filename)
|
||||
{
|
||||
FILE* file = nvr_fopen(params_details->filename, "rb");
|
||||
strncpy(eeprom->filename, params_details->filename, 1024);
|
||||
if (file) {
|
||||
filldefault = !fread(eeprom->contents, sizeof(uint16_t), nwords, file);
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (filldefault)
|
||||
{
|
||||
memcpy(eeprom->contents, params_details->default_content, nwords * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
return eeprom;
|
||||
}
|
||||
|
||||
void nmc93cxx_eeprom_write(nmc93cxx_eeprom_t *eeprom, int eecs, int eesk, int eedi)
|
||||
{
|
||||
uint8_t tick = eeprom->tick;
|
||||
uint8_t eedo = eeprom->eedo;
|
||||
uint16_t address = eeprom->address;
|
||||
uint8_t command = eeprom->command;
|
||||
|
||||
logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
|
||||
eecs, eesk, eedi, eedo, tick);
|
||||
|
||||
if (!eeprom->eecs && eecs) {
|
||||
/* Start chip select cycle. */
|
||||
logout("Cycle start, waiting for 1st start bit (0)\n");
|
||||
tick = 0;
|
||||
command = 0x0;
|
||||
address = 0x0;
|
||||
} else if (eeprom->eecs && !eecs) {
|
||||
/* End chip select cycle. This triggers write / erase. */
|
||||
if (eeprom->writable) {
|
||||
uint8_t subcommand = address >> (eeprom->addrbits - 2);
|
||||
if (command == 0 && subcommand == 2) {
|
||||
/* Erase all. */
|
||||
for (address = 0; address < eeprom->size; address++) {
|
||||
eeprom->contents[address] = 0xffff;
|
||||
}
|
||||
} else if (command == 3) {
|
||||
/* Erase word. */
|
||||
eeprom->contents[address] = 0xffff;
|
||||
} else if (tick >= 2 + 2 + eeprom->addrbits + 16) {
|
||||
if (command == 1) {
|
||||
/* Write word. */
|
||||
eeprom->contents[address] &= eeprom->data;
|
||||
} else if (command == 0 && subcommand == 1) {
|
||||
/* Write all. */
|
||||
for (address = 0; address < eeprom->size; address++) {
|
||||
eeprom->contents[address] &= eeprom->data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Output DO is tristate, read results in 1. */
|
||||
eedo = 1;
|
||||
} else if (eecs && !eeprom->eesk && eesk) {
|
||||
/* Raising edge of clock shifts data in. */
|
||||
if (tick == 0) {
|
||||
/* Wait for 1st start bit. */
|
||||
if (eedi == 0) {
|
||||
logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n");
|
||||
tick++;
|
||||
} else {
|
||||
logout("wrong 1st start bit (is 1, should be 0)\n");
|
||||
tick = 2;
|
||||
//~ assert(!"wrong start bit");
|
||||
}
|
||||
} else if (tick == 1) {
|
||||
/* Wait for 2nd start bit. */
|
||||
if (eedi != 0) {
|
||||
logout("Got correct 2nd start bit, getting command + address\n");
|
||||
tick++;
|
||||
} else {
|
||||
logout("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) {
|
||||
logout("%s command, address = 0x%02x (value 0x%04x)\n",
|
||||
opstring[command], address, eeprom->contents[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:
|
||||
logout("write disable command\n");
|
||||
eeprom->writable = 0;
|
||||
break;
|
||||
case 1:
|
||||
logout("write all command\n");
|
||||
break;
|
||||
case 2:
|
||||
logout("erase all command\n");
|
||||
break;
|
||||
case 3:
|
||||
logout("write enable command\n");
|
||||
eeprom->writable = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Read, write or erase word. */
|
||||
eeprom->data = eeprom->contents[address];
|
||||
}
|
||||
}
|
||||
} else if (tick < 2 + 2 + eeprom->addrbits + 16) {
|
||||
/* Transfer 16 data bits. */
|
||||
tick++;
|
||||
if (command == 2) {
|
||||
/* Read word. */
|
||||
eedo = ((eeprom->data & 0x8000) != 0);
|
||||
}
|
||||
eeprom->data <<= 1;
|
||||
eeprom->data += eedi;
|
||||
} else {
|
||||
logout("additional unneeded tick, not processed\n");
|
||||
}
|
||||
}
|
||||
/* Save status of EEPROM. */
|
||||
eeprom->tick = tick;
|
||||
eeprom->eecs = eecs;
|
||||
eeprom->eesk = eesk;
|
||||
eeprom->eedo = eedo;
|
||||
eeprom->address = address;
|
||||
eeprom->command = command;
|
||||
}
|
||||
|
||||
uint16_t nmc93cxx_eeprom_read(nmc93cxx_eeprom_t *eeprom)
|
||||
{
|
||||
/* Return status of pin DO (0 or 1). */
|
||||
return eeprom->eedo;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
nmc93cxx_eeprom_close(void *priv)
|
||||
{
|
||||
nmc93cxx_eeprom_t* eeprom = (nmc93cxx_eeprom_t*)priv;
|
||||
FILE* file = nvr_fopen(eeprom->filename, "wb");
|
||||
if (file)
|
||||
{
|
||||
fwrite(eeprom->contents, 2, eeprom->size, file);
|
||||
}
|
||||
fclose(file);
|
||||
free(priv);
|
||||
}
|
||||
|
||||
uint16_t *nmc93cxx_eeprom_data(nmc93cxx_eeprom_t *eeprom)
|
||||
{
|
||||
/* Get EEPROM data array. */
|
||||
return &eeprom->contents[0];
|
||||
}
|
||||
|
||||
const device_t nmc93cxx_device = {
|
||||
.name = "National Semiconductor NMC93Cxx",
|
||||
.internal_name = "nmc93cxx",
|
||||
.flags = DEVICE_EXTPARAMS,
|
||||
.local = 0,
|
||||
.init_ext = nmc93cxx_eeprom_init_params,
|
||||
.close = nmc93cxx_eeprom_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
1452
src/network/net_tulip.c
Normal file
1452
src/network/net_tulip.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -73,6 +73,7 @@
|
|||
#include <86box/net_pcnet.h>
|
||||
#include <86box/net_plip.h>
|
||||
#include <86box/net_wd8003.h>
|
||||
#include <86box/net_tulip.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
|
@ -116,6 +117,7 @@ static const device_t *net_cards[] = {
|
|||
&pcnet_am79c970a_device,
|
||||
&rtl8029as_device,
|
||||
&pcnet_am79c960_vlb_device,
|
||||
&dec_tulip_device,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue