3c505: replace hle (nw)

For review/comment especially by @rb6502 and Hans Ostermeyer because it's:
* a rewrite/replacement of prior work, and proposes taking over the copyright as well; and
* untested on Apollo at the moment because the driver is crashing while trying to install Domain/OS (unrelated to this device).
Testing with the 3c505.exe diagnostic program on MS-DOS passes the Group 1 & 2 tests successfully when using 16-bit DMA channel. It intermittently fails the Group 2 transmit test when using an 8-bit channel.
This commit is contained in:
Patrick Mackinlay 2019-04-05 19:04:52 +07:00
parent f0d27bc603
commit cf64b0fed3
4 changed files with 228 additions and 2082 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Hans Ostermeyer,R. Belmont
/*
* threecom3c505.h - 3COM 3C505 ethernet controller
*
* Created on: August 27, 2010
* Author: Hans Ostermeyer
*
*/
// copyright-holders:Patrick Mackinlay
#ifndef MAME_BUS_ISA_3C505_H
#define MAME_BUS_ISA_3C505_H
@ -19,267 +12,6 @@
#include "bus/isa/isa.h"
// ======================> PCB data structure
#pragma pack(1)
struct Memconf
{
uint16_t cmd_q, rcv_q, mcast, frame, rcv_b, progs;
};
struct Rcv_pkt
{
uint16_t buf_ofs, buf_seg, buf_len, timeout;
};
struct Xmit_pkt
{
uint16_t buf_ofs, buf_seg, pkt_len;
};
struct Rcv_resp
{
uint16_t buf_ofs, buf_seg, buf_len, pkt_len, timeout, status;
uint32_t timetag;
};
struct Xmit_resp
{
uint16_t buf_ofs, buf_seg, c_stat, status;
};
struct Netstat
{
uint32_t tot_recv, tot_xmit;
uint16_t err_CRC, err_align, err_res, err_ovrrun;
};
struct Selftest
{
uint16_t error;
union
{
uint16_t ROM_cksum;
struct
{
uint16_t ofs, seg;
} RAM;
uint16_t i82586;
} failure;
};
struct Info
{
uint8_t minor_vers, major_vers;
uint16_t ROM_cksum, RAM_sz, free_ofs, free_seg;
};
struct Memdump
{
uint16_t size, off, seg;
};
/*
Primary Command Block. The most important data structure. All communication
between the host and the adapter is done with these. (Except for the actual
Ethernet data, which has different packaging.)
*/
struct pcb_struct
{
uint8_t command;
uint8_t length;
union
{
struct Memconf memconf;
uint16_t configure;
struct Rcv_pkt rcv_pkt;
struct Xmit_pkt xmit_pkt;
uint8_t multicast[10][6];
uint8_t eth_addr[6];
int16_t failed;
struct Rcv_resp rcv_resp;
struct Xmit_resp xmit_resp;
struct Netstat netstat;
struct Selftest selftest;
struct Info info;
struct Memdump memdump;
uint8_t raw[62];
} data;
};
#pragma pack()
// ======================> threecom3c505_device
class threecom3c505_device: public device_t,
public device_network_interface,
public device_isa16_card_interface
{
public:
// construction/destruction
threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// device register I/O
virtual DECLARE_READ16_MEMBER(read);
virtual DECLARE_WRITE16_MEMBER(write);
static void set_verbose(int on_off);
virtual void recv_cb(uint8_t *data, int length) override;
protected:
static constexpr unsigned CMD_BUFFER_SIZE = 100;
static constexpr unsigned ETH_BUFFER_SIZE = 2048;
static constexpr unsigned PGM_BUFFER_SIZE = 0x2000;
static constexpr unsigned ETHERNET_ADDR_SIZE = 6;
static constexpr unsigned RX_FIFO_SIZE = 32;
threecom3c505_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
virtual int tx_data(device_t *, const uint8_t *, int);
virtual int setfilter(device_t *, int);
std::string cpu_context() const;
template <typename Format, typename... Params> void logerror(Format &&fmt, Params &&... args) const;
// device-level overrides
virtual void device_start() override;
virtual const tiny_rom_entry *device_rom_region() const override;
required_ioport m_iobase;
required_ioport m_irqdrq;
required_ioport m_romopts;
private:
// device-level overrides
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual ioport_constructor device_input_ports() const override;
class data_buffer_fifo;
/* data buffer */
class data_buffer
{
friend class data_buffer_fifo;
public:
data_buffer();
void start(threecom3c505_device *device, int32_t size);
void reset();
int append(uint8_t data);
uint8_t get(int i) { return m_data[i]; };
uint16_t get_word(int i) { return (m_data[i*2+1] << 8) + m_data[i*2]; };
int is_empty() {return m_length == 0; };
int is_full() {return m_length >= m_data.size(); };
uint16_t get_length() { return m_length; };
uint16_t get_size() { return m_data.size(); };
uint8_t *get_data() { return &m_data[0]; };
void copy(data_buffer *db) const;
void log(const char *title) const;
private:
std::string cpu_context() const { return m_device->cpu_context(); }
threecom3c505_device *m_device; // pointer back to our device
uint16_t m_length;
std::vector<uint8_t> m_data;
};
/* data_buffer fifo (used to buffer the received data) */
class data_buffer_fifo
{
public:
data_buffer_fifo();
~data_buffer_fifo();
void start(threecom3c505_device *device, int32_t size, int32_t db_size);
void reset();
int put(const uint8_t data[], const int length);
int get(data_buffer *db);
int is_empty () { return m_get_index == m_put_index; }
int is_full () { return ((m_put_index + 1) % m_size) == m_get_index; }
private:
std::string cpu_context() const { return m_device->cpu_context(); }
threecom3c505_device *m_device; // pointer back to our device
uint16_t m_size;
uint16_t m_count;
uint16_t m_get_index;
uint16_t m_put_index;
data_buffer *m_db[RX_FIFO_SIZE];
};
void set_filter_list();
void set_interrupt(enum line_state state);
void log_command();
void log_response();
void do_receive_command();
void set_command_pending(int onoff);
int ethernet_packet_is_for_me(const uint8_t mac_address[]);
void write_command_port( uint8_t data);
uint8_t read_command_port();
void write_data_port( uint8_t data);
uint8_t read_data_port();
void write_control_port( uint8_t data);
uint8_t read_status_port();
void do_command();
uint8_t m_reg[16];
uint8_t m_status;
uint8_t m_control;
uint8_t m_command_buffer[CMD_BUFFER_SIZE];
int m_command_index;
int m_command_pending;
int m_wait_for_ack;
int m_wait_for_nak;
data_buffer_fifo m_rx_fifo;
data_buffer m_rx_data_buffer; // the ethernet receive buffer
int m_rx_data_index;
int m_rx_pending;
data_buffer m_tx_data_buffer; // the ethernet transmit buffer
int m_tx_data_length;
data_buffer m_program_buffer; // the program data buffer
int m_program_length;
pcb_struct m_response;
int m_response_length;
int m_response_index;
pcb_struct m_rcv_response;
uint16_t m_microcode_version;
uint16_t m_microcode_running;
uint16_t m_i82586_config;
struct Netstat m_netstat;
uint8_t m_station_address[ETHERNET_ADDR_SIZE];
uint8_t m_multicast_list[ETHERNET_ADDR_SIZE*2];
uint8_t m_filter_list[ETHERNET_ADDR_SIZE*4];
enum line_state irq_state;
emu_timer * m_do_command_timer; // timer to delay command execution
bool m_installed;
int m_irq, m_drq;
};
class isa16_3c505_device
: public device_t
, public device_isa16_card_interface
@ -287,9 +19,6 @@ class isa16_3c505_device
public:
isa16_3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
DECLARE_READ16_MEMBER(host_r);
DECLARE_WRITE16_MEMBER(host_w);
protected:
// device_t overrides
virtual const tiny_rom_entry *device_rom_region() const override;
@ -300,6 +29,7 @@ protected:
void map_main(address_map &map);
void map_io(address_map &map);
void map_isa(address_map &map);
enum acr_mask : u8
{
@ -369,14 +99,27 @@ protected:
// host register helpers
u8 hcmd_r();
u16 hdata_r();
u8 hsr_r() { return m_hsr; }
u16 hdata_r(offs_t offset, u16 mem_mask = 0xffff);
u8 hcr_r() { return m_hcr; }
void hcmd_w(u8 data);
void hdr_w(u8 data) { m_hdr = data & HDR_BRST; }
void hdata_w(offs_t offset, u16 data, u16 mem_mask = 0xffff);
void hcr_w(u8 data);
void hdata_w(u16 data);
void update_irq(int state);
void update_cpu_drq(int state);
void update_cpu_irq(int state);
void update_isa_drq(int state);
void update_isa_irq(int state);
void update_rdy(u8 const acr, u8 const hcr);
// dma helpers
virtual u8 dack_r(int line) override { return hdata_r(0, 0x00ff); }
virtual void dack_w(int line, u8 data) override { hdata_w(0, data, 0x00ff); }
virtual void eop_w(int state) override;
virtual u16 dack16_r(int line) override { return hdata_r(0); }
virtual void dack16_w(int line, u16 data) override { hdata_w(0, data); }
private:
required_device<i80186_cpu_device> m_cpu;
required_device<i82586_device> m_net;
@ -398,18 +141,20 @@ private:
u8 m_hsr; // host status register
u8 m_hdr; // host aux dma register
util::fifo<u16, 10> m_data;
static constexpr unsigned FIFO_SIZE = 20;
util::fifo<u8, FIFO_SIZE> m_data;
bool m_installed;
unsigned m_isa_irq;
unsigned m_isa_drq;
bool m_cpu_drq_asserted;
bool m_cpu_irq_asserted;
bool m_isa_drq_asserted;
bool m_isa_irq_asserted;
bool m_installed;
};
// device type definition
DECLARE_DEVICE_TYPE(ISA16_3C505, threecom3c505_device)
DECLARE_DEVICE_TYPE(ISA16_3C505_LLE, isa16_3c505_device)
DECLARE_DEVICE_TYPE(ISA16_3C505, isa16_3c505_device)
#endif // MAME_BUS_ISA_3C505_H

View File

@ -176,7 +176,6 @@ void pc_isa16_cards(device_slot_interface &device)
device.option_add("gfxultrap", ISA16_SVGA_GFXULTRAPRO);
device.option_add("tgui9680",ISA16_SVGA_TGUI9680);
device.option_add("3c505", ISA16_3C505);
device.option_add("3c505_lle", ISA16_3C505_LLE);
device.option_add("mach64", ISA16_SVGA_MACH64);
device.option_add("sb16_lle", ISA16_SB16);
device.option_add("mcd", ISA16_MCD);

View File

@ -1040,11 +1040,20 @@ void apollo_ni::set_node_id_from_disk()
#undef VERBOSE
#define VERBOSE 0
DEVICE_INPUT_DEFAULTS_START(3c505)
DEVICE_INPUT_DEFAULTS("IO_BASE", 0x3f0, 0x300) // I/O address 0x300
DEVICE_INPUT_DEFAULTS("IRQ_DRQ", 0x0f, 0x0a) // IRQ 10
DEVICE_INPUT_DEFAULTS("IRQ_DRQ", 0x70, 0x60) // DRQ 6
DEVICE_INPUT_DEFAULTS("ROM_OPTS", 0x01, 0x01) // host ROM enabled
DEVICE_INPUT_DEFAULTS("ROM_OPTS", 0xfe, 0x00) // host ROM address 0x00000
DEVICE_INPUT_DEFAULTS_END
static void apollo_isa_cards(device_slot_interface &device)
{
device.option_add("wdc", ISA16_OMTI8621_APOLLO); // Combo ESDI/AT floppy controller
device.option_add("ctape", ISA8_SC499); // Archive SC499 cartridge tape
device.option_add("3c505", ISA16_3C505); // 3Com 3C505 Ethernet card
device.option_add("3c505", ISA16_3C505).default_bios("apollo"); // 3Com 3C505 Ethernet card
device.set_option_device_input_defaults("3c505", DEVICE_INPUT_DEFAULTS_NAME(3c505));
}
void apollo_state::common(machine_config &config)