summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmmanouil Theofanis Chourdakis2020-03-22 18:15:02 +0200
committerEmmanouil Theofanis Chourdakis2020-03-22 18:15:02 +0200
commitbb8496b5a0475712835ec396ea9d4a4a7cba3861 (patch)
tree4fd3499142842bf90e6539af908c214cccad51f4
downloadaur-bb8496b5a0475712835ec396ea9d4a4a7cba3861.tar.gz
Initial commit
The same as the dosbox-svn PKGBUILD with the inclusion of the NE2000 ethernet network card for easy use of tcp/ip from within dosbox
-rw-r--r--.SRCINFO36
-rw-r--r--PKGBUILD67
-rw-r--r--dosbox-128.pngbin0 -> 35632 bytes
-rw-r--r--dosbox-16.pngbin0 -> 1018 bytes
-rw-r--r--dosbox-48.pngbin0 -> 5537 bytes
-rw-r--r--dosbox-svn-ne2000.desktop10
-rw-r--r--ne2000.patch2061
7 files changed, 2174 insertions, 0 deletions
diff --git a/.SRCINFO b/.SRCINFO
new file mode 100644
index 000000000000..c990aa0585b8
--- /dev/null
+++ b/.SRCINFO
@@ -0,0 +1,36 @@
+pkgbase = dosbox-svn-ne2000
+ pkgdesc = An emulator with builtin DOS for running DOS Games - Includes patches for NE2000 network card
+ pkgver = 0.74.2.4335M
+ pkgrel = 1
+ epoch = 1
+ url = http://dosbox.sourceforge.net/
+ arch = i686
+ arch = x86_64
+ license = GPL2
+ makedepends = subversion
+ makedepends = desktop-file-utils
+ depends = alsa-lib
+ depends = hicolor-icon-theme
+ depends = libgl
+ depends = libpng
+ depends = libpcap
+ depends = mesa
+ depends = sdl_net
+ depends = sdl_sound
+ provides = dosbox
+ conflicts = dosbox
+ source = dosbox-svn-ne2000::svn+https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk
+ source = dosbox-svn-ne2000.desktop
+ source = dosbox-16.png
+ source = dosbox-48.png
+ source = dosbox-128.png
+ source = ne2000.patch
+ sha256sums = SKIP
+ sha256sums = 7c8db8a5a475f54283748b539b50fa49b59a87c5ff80e94e82520530b996f871
+ sha256sums = e657254e56dd7d66cb1cefbf37f0f360e13a221bc60b1638c00dcda508f7fd56
+ sha256sums = e71a3984170b3bf7af7d9cfbec0752187d70be76602721a1227b60980d7c380a
+ sha256sums = 228593e97732eaa31e0202b7d46da9d7529672369c17312db3f97784601b5d81
+ sha256sums = 839e20fab07cc29bb80e34fce2199dea91eacd090c6bce89c4d276564ac519cb
+
+pkgname = dosbox-svn-ne2000
+
diff --git a/PKGBUILD b/PKGBUILD
new file mode 100644
index 000000000000..7d6e3d726909
--- /dev/null
+++ b/PKGBUILD
@@ -0,0 +1,67 @@
+# Maintainer: mmxgn <eruyome@gmail.com>
+# Based on dosbox-svn AUR PKGBUILD from: https://aur.archlinux.org/packages/dosbox-svn/
+# Includes patches from: James Kelly Jr, James-F (https://sourceforge.net/p/dosbox/patches/238/)
+
+pkgname=dosbox-svn-ne2000
+pkgver=0.74.2.4335M
+pkgrel=1
+epoch=1
+pkgdesc="An emulator with builtin DOS for running DOS Games - Includes patches for NE2000 network card"
+arch=('i686' 'x86_64')
+url='http://dosbox.sourceforge.net/'
+license=('GPL2')
+depends=('alsa-lib' 'hicolor-icon-theme' 'libgl' 'libpng' 'libpcap' 'mesa' 'sdl_net' 'sdl_sound')
+makedepends=('subversion' 'desktop-file-utils')
+provides=('dosbox')
+conflicts=('dosbox')
+source=($pkgname::svn+https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk
+ $pkgname.desktop
+ dosbox-16.png
+ dosbox-48.png
+ dosbox-128.png
+ ne2000.patch
+)
+
+prepare(){
+ cd $pkgname
+ #patch -N --forward --strip=1 --silent < ../ne2000.patch
+ patch -Np1 -i ../ne2000.patch
+}
+
+pkgver(){
+ echo $(cat $pkgname/VERSION).$(svnversion $pkgname) | sed 's/-/./'
+}
+
+build() {
+ cd $pkgname
+ sh autogen.sh
+ ./configure --prefix=/usr --sysconfdir=/etc/dosbox
+ make
+}
+
+package() {
+ make -C $pkgname DESTDIR="$pkgdir" install
+
+ # Fix invalid permissions FS#10732
+ chmod 755 "$pkgdir"/usr/share/man/man1
+
+ for i in 16 48 128; do
+ install -Dm644 dosbox-$i.png "$pkgdir"/usr/share/icons/hicolor/${i}x$i/apps/dosbox.png
+ done
+ desktop-file-install $pkgname.desktop --dir "$pkgdir"/usr/share/applications/
+ echo ""
+ echo ""
+ echo "Please make sure to edit ~/.dosbox/dosbox-SVN.conf and set the desired"
+ echo "interface to use. Note: you have to have permissions to capture from it"
+ echo "see e.g.:"
+ echo " https://askubuntu.com/questions/530920/tcpdump-permissions-problem#632189"
+ echo ""
+ echo ""
+}
+
+sha256sums=('SKIP'
+ '7c8db8a5a475f54283748b539b50fa49b59a87c5ff80e94e82520530b996f871'
+ 'e657254e56dd7d66cb1cefbf37f0f360e13a221bc60b1638c00dcda508f7fd56'
+ 'e71a3984170b3bf7af7d9cfbec0752187d70be76602721a1227b60980d7c380a'
+ '228593e97732eaa31e0202b7d46da9d7529672369c17312db3f97784601b5d81'
+ '839e20fab07cc29bb80e34fce2199dea91eacd090c6bce89c4d276564ac519cb')
diff --git a/dosbox-128.png b/dosbox-128.png
new file mode 100644
index 000000000000..5beb624002be
--- /dev/null
+++ b/dosbox-128.png
Binary files differ
diff --git a/dosbox-16.png b/dosbox-16.png
new file mode 100644
index 000000000000..2f27d70c85a3
--- /dev/null
+++ b/dosbox-16.png
Binary files differ
diff --git a/dosbox-48.png b/dosbox-48.png
new file mode 100644
index 000000000000..3b8e06a54126
--- /dev/null
+++ b/dosbox-48.png
Binary files differ
diff --git a/dosbox-svn-ne2000.desktop b/dosbox-svn-ne2000.desktop
new file mode 100644
index 000000000000..8dc7fa77d1de
--- /dev/null
+++ b/dosbox-svn-ne2000.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Type=Application
+Name=DOSBox
+Comment=DOS Emulator
+Comment[es]=Emulador de DOS
+Comment[fr]=Emulateur DOS
+Exec=dosbox
+Icon=dosbox
+Terminal=false
+Categories=System;Emulator;Game;
diff --git a/ne2000.patch b/ne2000.patch
new file mode 100644
index 000000000000..c7f04fcef5cc
--- /dev/null
+++ b/ne2000.patch
@@ -0,0 +1,2061 @@
+diff --unified --recursive --new-file --text dosbox-svn-orig/configure.ac dosbox-svn-new/configure.ac
+--- dosbox-svn-orig/configure.ac 2020-03-22 15:14:51.275002066 +0200
++++ dosbox-svn-new/configure.ac 2020-03-22 15:26:35.906325030 +0200
+@@ -455,6 +455,18 @@
+ AC_MSG_RESULT([no])
+ fi
+
++AH_TEMPLATE(C_NE2000,[Define to 1 to enable NE2000 ethernet passthrough, requires libpcap])
++AC_CHECK_HEADER(pcap.h,have_pcap_h=yes,)
++AC_CHECK_LIB(pcap, pcap_open_live, have_pcap_lib=yes, ,-lz)
++if test x$have_pcap_lib = xyes -a x$have_pcap_h = xyes ; then
++ LIBS="$LIBS -lpcap";
++ AC_DEFINE(C_NE2000,1)
++else
++ AC_MSG_WARN([Can't find libpcap, NE2000 ethernet passthrough disabled])
++fi
++
++
++
+ AH_TEMPLATE(C_SRECORD,[Define to 1 to enable movie recording, requires zlib built without Z_SOLO])
+ AC_ARG_ENABLE(recording,AC_HELP_STRING([--disable-recording],[Disable movie recording]),,enable_recording=yes)
+ AC_CHECK_HEADER(zlib.h,have_zlib_h=yes)
+diff --unified --recursive --new-file --text dosbox-svn-orig/include/Makefile.am dosbox-svn-new/include/Makefile.am
+--- dosbox-svn-orig/include/Makefile.am 2020-03-22 15:14:51.295001817 +0200
++++ dosbox-svn-new/include/Makefile.am 2020-03-22 15:26:01.186750010 +0200
+@@ -36,5 +36,6 @@
+ support.h \
+ timer.h \
+ vga.h \
+-video.h
++video.h \
++ne2000.h
+
+diff --unified --recursive --new-file --text dosbox-svn-orig/include/ne2000.h dosbox-svn-new/include/ne2000.h
+--- dosbox-svn-orig/include/ne2000.h 1970-01-01 02:00:00.000000000 +0200
++++ dosbox-svn-new/include/ne2000.h 2020-03-22 15:25:46.206933434 +0200
+@@ -0,0 +1,250 @@
++/////////////////////////////////////////////////////////////////////////
++// $Id: ne2k.h,v 1.11.2.3 2003/04/06 17:29:49 bdenney Exp $
++/////////////////////////////////////////////////////////////////////////
++//
++// Copyright (C) 2001 MandrakeSoft S.A.
++//
++// MandrakeSoft S.A.
++// 43, rue d'Aboukir
++// 75002 Paris - France
++// http://www.linux-mandrake.com/
++// http://www.mandrakesoft.com/
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++
++// Peter Grehan (grehan@iprg.nokia.com) coded all of this
++// NE2000/ether stuff.
++
++//
++// An implementation of an ne2000 ISA ethernet adapter. This part uses
++// a National Semiconductor DS-8390 ethernet MAC chip, with some h/w
++// to provide a windowed memory region for the chip and a MAC address.
++//
++
++#include "dosbox.h"
++
++#define bx_bool int
++#define bx_param_c Bit8u
++
++
++# define BX_NE2K_SMF
++# define BX_NE2K_THIS_PTR
++# define BX_NE2K_THIS
++#define BX_INFO
++//LOG_MSG
++#define BX_DEBUG
++//LOG_MSG
++
++#define BX_NE2K_MEMSIZ (32*1024)
++#define BX_NE2K_MEMSTART (16*1024)
++#define BX_NE2K_MEMEND (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ)
++
++typedef struct {
++ //
++ // ne2k register state
++
++ //
++ // Page 0
++ //
++ // Command Register - 00h read/write
++ struct CR_t {
++ bx_bool stop; // STP - Software Reset command
++ bx_bool start; // START - start the NIC
++ bx_bool tx_packet; // TXP - initiate packet transmission
++ Bit8u rdma_cmd; // RD0,RD1,RD2 - Remote DMA command
++ Bit8u pgsel; // PS0,PS1 - Page select
++ } CR;
++ // Interrupt Status Register - 07h read/write
++ struct ISR_t {
++ bx_bool pkt_rx; // PRX - packet received with no errors
++ bx_bool pkt_tx; // PTX - packet transmitted with no errors
++ bx_bool rx_err; // RXE - packet received with 1 or more errors
++ bx_bool tx_err; // TXE - packet tx'd " " " " "
++ bx_bool overwrite; // OVW - rx buffer resources exhausted
++ bx_bool cnt_oflow; // CNT - network tally counter MSB's set
++ bx_bool rdma_done; // RDC - remote DMA complete
++ bx_bool reset; // RST - reset status
++ } ISR;
++ // Interrupt Mask Register - 0fh write
++ struct IMR_t {
++ bx_bool rx_inte; // PRXE - packet rx interrupt enable
++ bx_bool tx_inte; // PTXE - packet tx interrput enable
++ bx_bool rxerr_inte; // RXEE - rx error interrupt enable
++ bx_bool txerr_inte; // TXEE - tx error interrupt enable
++ bx_bool overw_inte; // OVWE - overwrite warn int enable
++ bx_bool cofl_inte; // CNTE - counter o'flow int enable
++ bx_bool rdma_inte; // RDCE - remote DMA complete int enable
++ bx_bool reserved; // D7 - reserved
++ } IMR;
++ // Data Configuration Register - 0eh write
++ struct DCR_t {
++ bx_bool wdsize; // WTS - 8/16-bit select
++ bx_bool endian; // BOS - byte-order select
++ bx_bool longaddr; // LAS - long-address select
++ bx_bool loop; // LS - loopback select
++ bx_bool auto_rx; // AR - auto-remove rx packets with remote DMA
++ Bit8u fifo_size; // FT0,FT1 - fifo threshold
++ } DCR;
++ // Transmit Configuration Register - 0dh write
++ struct TCR_t {
++ bx_bool crc_disable; // CRC - inhibit tx CRC
++ Bit8u loop_cntl; // LB0,LB1 - loopback control
++ bx_bool ext_stoptx; // ATD - allow tx disable by external mcast
++ bx_bool coll_prio; // OFST - backoff algorithm select
++ Bit8u reserved; // D5,D6,D7 - reserved
++ } TCR;
++ // Transmit Status Register - 04h read
++ struct TSR_t {
++ bx_bool tx_ok; // PTX - tx complete without error
++ bx_bool reserved; // D1 - reserved
++ bx_bool collided; // COL - tx collided >= 1 times
++ bx_bool aborted; // ABT - aborted due to excessive collisions
++ bx_bool no_carrier; // CRS - carrier-sense lost
++ bx_bool fifo_ur; // FU - FIFO underrun
++ bx_bool cd_hbeat; // CDH - no tx cd-heartbeat from transceiver
++ bx_bool ow_coll; // OWC - out-of-window collision
++ } TSR;
++ // Receive Configuration Register - 0ch write
++ struct RCR_t {
++ bx_bool errors_ok; // SEP - accept pkts with rx errors
++ bx_bool runts_ok; // AR - accept < 64-byte runts
++ bx_bool broadcast; // AB - accept eth broadcast address
++ bx_bool multicast; // AM - check mcast hash array
++ bx_bool promisc; // PRO - accept all packets
++ bx_bool monitor; // MON - check pkts, but don't rx
++ Bit8u reserved; // D6,D7 - reserved
++ } RCR;
++ // Receive Status Register - 0ch read
++ struct RSR_t {
++ bx_bool rx_ok; // PRX - rx complete without error
++ bx_bool bad_crc; // CRC - Bad CRC detected
++ bx_bool bad_falign; // FAE - frame alignment error
++ bx_bool fifo_or; // FO - FIFO overrun
++ bx_bool rx_missed; // MPA - missed packet error
++ bx_bool rx_mbit; // PHY - unicast or mcast/bcast address match
++ bx_bool rx_disabled; // DIS - set when in monitor mode
++ bx_bool deferred; // DFR - collision active
++ } RSR;
++
++ Bit16u local_dma; // 01,02h read ; current local DMA addr
++ Bit8u page_start; // 01h write ; page start register
++ Bit8u page_stop; // 02h write ; page stop register
++ Bit8u bound_ptr; // 03h read/write ; boundary pointer
++ Bit8u tx_page_start; // 04h write ; transmit page start register
++ Bit8u num_coll; // 05h read ; number-of-collisions register
++ Bit16u tx_bytes; // 05,06h write ; transmit byte-count register
++ Bit8u fifo; // 06h read ; FIFO
++ Bit16u remote_dma; // 08,09h read ; current remote DMA addr
++ Bit16u remote_start; // 08,09h write ; remote start address register
++ Bit16u remote_bytes; // 0a,0bh write ; remote byte-count register
++ Bit8u tallycnt_0; // 0dh read ; tally counter 0 (frame align errors)
++ Bit8u tallycnt_1; // 0eh read ; tally counter 1 (CRC errors)
++ Bit8u tallycnt_2; // 0fh read ; tally counter 2 (missed pkt errors)
++
++ //
++ // Page 1
++ //
++ // Command Register 00h (repeated)
++ //
++ Bit8u physaddr[6]; // 01-06h read/write ; MAC address
++ Bit8u curr_page; // 07h read/write ; current page register
++ Bit8u mchash[8]; // 08-0fh read/write ; multicast hash array
++
++ //
++ // Page 2 - diagnostic use only
++ //
++ // Command Register 00h (repeated)
++ //
++ // Page Start Register 01h read (repeated)
++ // Page Stop Register 02h read (repeated)
++ // Current Local DMA Address 01,02h write (repeated)
++ // Transmit Page start address 04h read (repeated)
++ // Receive Configuration Register 0ch read (repeated)
++ // Transmit Configuration Register 0dh read (repeated)
++ // Data Configuration Register 0eh read (repeated)
++ // Interrupt Mask Register 0fh read (repeated)
++ //
++ Bit8u rempkt_ptr; // 03h read/write ; remote next-packet pointer
++ Bit8u localpkt_ptr; // 05h read/write ; local next-packet pointer
++ Bit16u address_cnt; // 06,07h read/write ; address counter
++
++ //
++ // Page 3 - should never be modified.
++ //
++
++ // Novell ASIC state
++ Bit8u macaddr[32]; // ASIC ROM'd MAC address, even bytes
++ Bit8u mem[BX_NE2K_MEMSIZ]; // on-chip packet memory
++
++ // ne2k internal state
++ Bit32u base_address;
++ int base_irq;
++ int tx_timer_index;
++ int tx_timer_active;
++
++ void register_state(bx_param_c *list_p);
++
++} bx_ne2k_t;
++
++
++
++class bx_ne2k_c {
++public:
++ bx_ne2k_c(void);
++ ~bx_ne2k_c(void);
++ virtual void init(void);
++ virtual void reset(unsigned type);
++
++public:
++ bx_ne2k_t s;
++
++ /* TODO: Setup SDL */
++ //eth_pktmover_c *ethdev;
++
++ BX_NE2K_SMF Bit32u read_cr(void);
++ BX_NE2K_SMF void write_cr(Bit32u value);
++
++ BX_NE2K_SMF Bit32u chipmem_read(Bit32u address, unsigned io_len);
++ BX_NE2K_SMF Bit32u asic_read(Bit32u offset, unsigned io_len);
++ BX_NE2K_SMF Bit32u page0_read(Bit32u offset, unsigned io_len);
++ BX_NE2K_SMF Bit32u page1_read(Bit32u offset, unsigned io_len);
++ BX_NE2K_SMF Bit32u page2_read(Bit32u offset, unsigned io_len);
++ BX_NE2K_SMF Bit32u page3_read(Bit32u offset, unsigned io_len);
++
++ BX_NE2K_SMF void chipmem_write(Bit32u address, Bit32u value, unsigned io_len);
++ BX_NE2K_SMF void asic_write(Bit32u address, Bit32u value, unsigned io_len);
++ BX_NE2K_SMF void page0_write(Bit32u address, Bit32u value, unsigned io_len);
++ BX_NE2K_SMF void page1_write(Bit32u address, Bit32u value, unsigned io_len);
++ BX_NE2K_SMF void page2_write(Bit32u address, Bit32u value, unsigned io_len);
++ BX_NE2K_SMF void page3_write(Bit32u address, Bit32u value, unsigned io_len);
++
++public:
++ static void tx_timer_handler(void *);
++ BX_NE2K_SMF void tx_timer(void);
++
++ static void rx_handler(void *arg, const void *buf, unsigned len);
++ BX_NE2K_SMF unsigned mcast_index(const void *dst);
++ BX_NE2K_SMF void rx_frame(const void *buf, unsigned io_len);
++
++
++ static Bit32u read_handler(void *this_ptr, Bit32u address, unsigned io_len);
++ static void write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len);
++#if !BX_USE_NE2K_SMF
++ Bit32u read(Bit32u address, unsigned io_len);
++ void write(Bit32u address, Bit32u value, unsigned io_len);
++#endif
++
++
++};
+diff --unified --recursive --new-file --text dosbox-svn-orig/src/dosbox.cpp dosbox-svn-new/src/dosbox.cpp
+--- dosbox-svn-orig/src/dosbox.cpp 2020-03-22 15:14:51.288335232 +0200
++++ dosbox-svn-new/src/dosbox.cpp 2020-03-22 15:24:59.187509372 +0200
+@@ -43,6 +43,12 @@
+ #include "render.h"
+ #include "pci_bus.h"
+
++#ifdef C_NE2000
++//#include "ne2000.h"
++void NE2K_Init(Section* sec);
++#endif
++
++
+ Config * control;
+ MachineType machine;
+ SVGACards svgaCard;
+@@ -784,6 +790,46 @@
+ Pbool = secprop->Add_bool("ipx",Property::Changeable::WhenIdle, false);
+ Pbool->Set_help("Enable ipx over UDP/IP emulation.");
+ #endif
++
++#ifdef C_NE2000
++ secprop=control->AddSection_prop("ne2000",&NE2K_Init,true);
++ MSG_Add("NE2000_CONFIGFILE_HELP",
++ "macaddr -- The physical address the emulator will use on your network.\n"
++ " If you have multiple DOSBoxes running on your network,\n"
++ " this has to be changed. Modify the last three number blocks.\n"
++ " I.e. AC:DE:48:88:99:AB.\n"
++ "realnic -- Specifies which of your network interfaces is used.\n"
++ " Write \'list\' here to see the list of devices in the\n"
++ " Status Window. Then make your choice and put either the\n"
++ " interface number (2 or something) or a part of your adapters\n"
++ " name, e.g. VIA here.\n"
++
++ );
++
++ Pbool = secprop->Add_bool("ne2000", Property::Changeable::WhenIdle, true);
++ Pbool->Set_help("Enable Ethernet passthrough. Requires [Win]Pcap.");
++
++ Phex = secprop->Add_hex("nicbase", Property::Changeable::WhenIdle, 0x300);
++ Phex->Set_help("The base address of the NE2000 board.");
++
++ Pint = secprop->Add_int("nicirq", Property::Changeable::WhenIdle, 3);
++ Pint->Set_help("The interrupt it uses. Note serial2 uses IRQ3 as default.");
++
++ Pstring = secprop->Add_string("macaddr", Property::Changeable::WhenIdle,"AC:DE:48:88:99:AA");
++ Pstring->Set_help("The physical address the emulator will use on your network.\n"
++ "If you have multiple DOSBoxes running on your network,\n"
++ "this has to be changed for each. AC:DE:48 is an address range reserved for\n"
++ "private use, so modify the last three number blocks.\n"
++ "I.e. AC:DE:48:88:99:AB.");
++
++ Pstring = secprop->Add_string("realnic", Property::Changeable::WhenIdle,"list");
++ Pstring->Set_help("Specifies which of your network interfaces is used.\n"
++ "Write \'list\' here to see the list of devices in the\n"
++ "Status Window. Then make your choice and put either the\n"
++ "interface number (2 or something) or a part of your adapters\n"
++ "name, e.g. VIA here.");
++#endif // C_NE2000
++
+ // secprop->AddInitFunction(&CREDITS_Init);
+
+ //TODO ?
+diff --unified --recursive --new-file --text dosbox-svn-orig/src/hardware/Makefile.am dosbox-svn-new/src/hardware/Makefile.am
+--- dosbox-svn-orig/src/hardware/Makefile.am 2020-03-22 15:14:51.291668525 +0200
++++ dosbox-svn-new/src/hardware/Makefile.am 2020-03-22 15:22:57.492334872 +0200
+@@ -10,6 +10,6 @@
+ memory.cpp mixer.cpp pcspeaker.cpp pci_bus.cpp pic.cpp sblaster.cpp tandy_sound.cpp timer.cpp \
+ vga.cpp vga_attr.cpp vga_crtc.cpp vga_dac.cpp vga_draw.cpp vga_gfx.cpp vga_other.cpp \
+ vga_memory.cpp vga_misc.cpp vga_seq.cpp vga_xga.cpp vga_s3.cpp vga_tseng.cpp vga_paradise.cpp \
+- cmos.cpp disney.cpp gus.cpp mpu401.cpp ipx.cpp ipxserver.cpp dbopl.cpp
++ cmos.cpp disney.cpp gus.cpp mpu401.cpp ipx.cpp ipxserver.cpp dbopl.cpp ne2000.cpp
+
+
+diff --unified --recursive --new-file --text dosbox-svn-orig/src/hardware/ne2000.cpp dosbox-svn-new/src/hardware/ne2000.cpp
+--- dosbox-svn-orig/src/hardware/ne2000.cpp 1970-01-01 02:00:00.000000000 +0200
++++ dosbox-svn-new/src/hardware/ne2000.cpp 2020-03-22 15:22:37.089251983 +0200
+@@ -0,0 +1,1660 @@
++#include "config.h"
++
++#ifdef C_NE2000
++
++
++#include "dosbox.h"
++#include <string.h>
++#include <stdio.h>
++#include "support.h"
++#include "inout.h"
++#include "setup.h"
++#include "callback.h"
++#include "timer.h"
++#include "pic.h"
++#include "cpu.h"
++
++/* Couldn't find a real spec for the NE2000 out there, hence this is adapted heavily from Bochs */
++
++
++/////////////////////////////////////////////////////////////////////////
++// $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $
++/////////////////////////////////////////////////////////////////////////
++//
++// Copyright (C) 2002 MandrakeSoft S.A.
++//
++// MandrakeSoft S.A.
++// 43, rue d'Aboukir
++// 75002 Paris - France
++// http://www.linux-mandrake.com/
++// http://www.mandrakesoft.com/
++//
++// This library is free software; you can redistribute it and/or
++// modify it under the terms of the GNU Lesser General Public
++// License as published by the Free Software Foundation; either
++// version 2 of the License, or (at your option) any later version.
++//
++// This library is distributed in the hope that it will be useful,
++// but WITHOUT ANY WARRANTY; without even the implied warranty of
++// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++// Lesser General Public License for more details.
++//
++// You should have received a copy of the GNU Lesser General Public
++// License along with this library; if not, write to the Free Software
++// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++
++// Peter Grehan (grehan@iprg.nokia.com) coded all of this
++// NE2000/ether stuff.
++
++#include "ne2000.h"
++
++#define HAVE_REMOTE
++
++#include "pcap.h"
++// Handle to WinPCap device
++pcap_t *adhandle = 0;
++static void NE2000_TX_Event(Bitu val);
++
++#ifdef WIN32
++// DLL loading
++#define pcap_sendpacket(A,B,C) PacketSendPacket(A,B,C)
++#define pcap_close(A) PacketClose(A)
++#define pcap_freealldevs(A) PacketFreealldevs(A)
++#define pcap_open(A,B,C,D,E,F) PacketOpen(A,B,C,D,E,F)
++#define pcap_next_ex(A,B,C) PacketNextEx(A,B,C)
++#define pcap_findalldevs_ex(A,B,C,D) PacketFindALlDevsEx(A,B,C,D)
++
++int (*PacketSendPacket)(pcap_t *, const u_char *, int) = 0;
++void (*PacketClose)(pcap_t *) = 0;
++void (*PacketFreealldevs)(pcap_if_t *) = 0;
++pcap_t* (*PacketOpen)(char const *,int,int,int,struct pcap_rmtauth *,char *) = 0;
++int (*PacketNextEx)(pcap_t *, struct pcap_pkthdr **, const u_char **) = 0;
++int (*PacketFindALlDevsEx)(char *, struct pcap_rmtauth *, pcap_if_t **, char *) = 0;
++
++#endif
++
++//Never completely fill the ne2k ring so that we never
++// hit the unclear completely full buffer condition.
++#define BX_NE2K_NEVER_FULL_RING (1)
++
++#define LOG_THIS theNE2kDevice->
++//#define BX_DEBUG
++//#define BX_INFO
++#define BX_NULL_TIMER_HANDLE NULL
++#define BX_PANIC
++#define BX_ERROR
++#define BX_RESET_HARDWARE 0
++#define BX_RESET_SOFTWARE 1
++
++bx_ne2k_c* theNE2kDevice = NULL;
++
++
++bx_ne2k_c::bx_ne2k_c(void)
++{
++ s.tx_timer_index = BX_NULL_TIMER_HANDLE;
++}
++
++
++bx_ne2k_c::~bx_ne2k_c(void)
++{
++ // nothing for now
++}
++
++//
++// reset - restore state to power-up, cancelling all i/o
++//
++void
++bx_ne2k_c::reset(unsigned type)
++{
++ BX_DEBUG ("reset");
++ // Zero out registers and memory
++ memset( & BX_NE2K_THIS s.CR, 0, sizeof(BX_NE2K_THIS s.CR) );
++ memset( & BX_NE2K_THIS s.ISR, 0, sizeof(BX_NE2K_THIS s.ISR));
++ memset( & BX_NE2K_THIS s.IMR, 0, sizeof(BX_NE2K_THIS s.IMR));
++ memset( & BX_NE2K_THIS s.DCR, 0, sizeof(BX_NE2K_THIS s.DCR));
++ memset( & BX_NE2K_THIS s.TCR, 0, sizeof(BX_NE2K_THIS s.TCR));
++ memset( & BX_NE2K_THIS s.TSR, 0, sizeof(BX_NE2K_THIS s.TSR));
++ //memset( & BX_NE2K_THIS s.RCR, 0, sizeof(BX_NE2K_THIS s.RCR));
++ memset( & BX_NE2K_THIS s.RSR, 0, sizeof(BX_NE2K_THIS s.RSR));
++ BX_NE2K_THIS s.tx_timer_active = 0;
++ BX_NE2K_THIS s.local_dma = 0;
++ BX_NE2K_THIS s.page_start = 0;
++ BX_NE2K_THIS s.page_stop = 0;
++ BX_NE2K_THIS s.bound_ptr = 0;
++ BX_NE2K_THIS s.tx_page_start = 0;
++ BX_NE2K_THIS s.num_coll = 0;
++ BX_NE2K_THIS s.tx_bytes = 0;
++ BX_NE2K_THIS s.fifo = 0;
++ BX_NE2K_THIS s.remote_dma = 0;
++ BX_NE2K_THIS s.remote_start = 0;
++ BX_NE2K_THIS s.remote_bytes = 0;
++ BX_NE2K_THIS s.tallycnt_0 = 0;
++ BX_NE2K_THIS s.tallycnt_1 = 0;
++ BX_NE2K_THIS s.tallycnt_2 = 0;
++
++ //memset( & BX_NE2K_THIS s.physaddr, 0, sizeof(BX_NE2K_THIS s.physaddr));
++ //memset( & BX_NE2K_THIS s.mchash, 0, sizeof(BX_NE2K_THIS s.mchash));
++ BX_NE2K_THIS s.curr_page = 0;
++
++ BX_NE2K_THIS s.rempkt_ptr = 0;
++ BX_NE2K_THIS s.localpkt_ptr = 0;
++ BX_NE2K_THIS s.address_cnt = 0;
++
++ memset( & BX_NE2K_THIS s.mem, 0, sizeof(BX_NE2K_THIS s.mem));
++
++ // Set power-up conditions
++ BX_NE2K_THIS s.CR.stop = 1;
++ BX_NE2K_THIS s.CR.rdma_cmd = 4;
++ BX_NE2K_THIS s.ISR.reset = 1;
++ BX_NE2K_THIS s.DCR.longaddr = 1;
++ PIC_DeActivateIRQ(s.base_irq);
++ //DEV_pic_lower_irq(BX_NE2K_THIS s.base_irq);
++}
++
++//
++// read_cr/write_cr - utility routines for handling reads/writes to
++// the Command Register
++//
++Bit32u
++bx_ne2k_c::read_cr(void)
++{
++ Bit32u val =
++ (((BX_NE2K_THIS s.CR.pgsel & 0x03) << 6) |
++ ((BX_NE2K_THIS s.CR.rdma_cmd & 0x07) << 3) |
++ (BX_NE2K_THIS s.CR.tx_packet << 2) |
++ (BX_NE2K_THIS s.CR.start << 1) |
++ (BX_NE2K_THIS s.CR.stop));
++ BX_DEBUG("read CR returns 0x%08x", val);
++ return val;
++}
++
++void
++bx_ne2k_c::write_cr(Bit32u value)
++{
++ BX_DEBUG ("wrote 0x%02x to CR", value);
++
++ // Validate remote-DMA
++ if ((value & 0x38) == 0x00) {
++ BX_DEBUG("CR write - invalid rDMA value 0");
++ value |= 0x20; /* dma_cmd == 4 is a safe default */
++ //value = 0x22; /* dma_cmd == 4 is a safe default */
++ }
++
++ // Check for s/w reset
++ if (value & 0x01) {
++ BX_NE2K_THIS s.ISR.reset = 1;
++ BX_NE2K_THIS s.CR.stop = 1;
++ } else {
++ BX_NE2K_THIS s.CR.stop = 0;
++ }
++
++ BX_NE2K_THIS s.CR.rdma_cmd = (value & 0x38) >> 3;
++
++ // If start command issued, the RST bit in the ISR
++ // must be cleared
++ if ((value & 0x02) && !BX_NE2K_THIS s.CR.start) {
++ BX_NE2K_THIS s.ISR.reset = 0;
++ }
++
++ BX_NE2K_THIS s.CR.start = ((value & 0x02) == 0x02);
++ BX_NE2K_THIS s.CR.pgsel = (value & 0xc0) >> 6;
++
++ // Check for send-packet command
++ if (BX_NE2K_THIS s.CR.rdma_cmd == 3) {
++ // Set up DMA read from receive ring
++ BX_NE2K_THIS s.remote_start = BX_NE2K_THIS s.remote_dma =
++ BX_NE2K_THIS s.bound_ptr * 256;
++ BX_NE2K_THIS s.remote_bytes = *((Bit16u*) &
++ BX_NE2K_THIS s.mem[BX_NE2K_THIS s.bound_ptr * 256 + 2 - BX_NE2K_MEMSTART]);
++ BX_INFO("Sending buffer #x%x length %d",
++ BX_NE2K_THIS s.remote_start,
++ BX_NE2K_THIS s.remote_bytes);
++ }
++
++ // Check for start-tx
++ if ((value & 0x04) && BX_NE2K_THIS s.TCR.loop_cntl) {
++ // loopback mode
++ if (BX_NE2K_THIS s.TCR.loop_cntl != 1) {
++ BX_INFO("Loop mode %d not supported.", BX_NE2K_THIS s.TCR.loop_cntl);
++ } else {
++ rx_frame (& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 -
++ BX_NE2K_MEMSTART],
++ BX_NE2K_THIS s.tx_bytes);
++
++ // do a TX interrupt
++ // Generate an interrupt if not masked and not one in progress
++ if (BX_NE2K_THIS s.IMR.tx_inte && !BX_NE2K_THIS s.ISR.pkt_tx) {
++ //LOG_MSG("tx complete interrupt");
++ PIC_ActivateIRQ(s.base_irq);
++ }
++ BX_NE2K_THIS s.ISR.pkt_tx = 1;
++ }
++ } else if (value & 0x04) {
++ // start-tx and no loopback
++ if (BX_NE2K_THIS s.CR.stop || !BX_NE2K_THIS s.CR.start)
++ BX_PANIC(("CR write - tx start, dev in reset"));
++
++ if (BX_NE2K_THIS s.tx_bytes == 0)
++ BX_PANIC(("CR write - tx start, tx bytes == 0"));
++
++#ifdef notdef
++ // XXX debug stuff
++ printf("packet tx (%d bytes):\t", BX_NE2K_THIS s.tx_bytes);
++ for (int i = 0; i < BX_NE2K_THIS s.tx_bytes; i++) {
++ printf("%02x ", BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 -
++ BX_NE2K_MEMSTART + i]);
++ if (i && (((i+1) % 16) == 0))
++ printf("\t");
++ }
++ printf("");
++#endif
++
++ // Send the packet to the system driver
++ /* TODO: Transmit packet */
++ //BX_NE2K_THIS ethdev->sendpkt(& BX_NE2K_THIS s.mem[BX_NE2K_THIS s.tx_page_start*256 - BX_NE2K_MEMSTART], BX_NE2K_THIS s.tx_bytes);
++ pcap_sendpacket(adhandle,&s.mem[s.tx_page_start*256 - BX_NE2K_MEMSTART], s.tx_bytes);
++ // some more debug
++ if (BX_NE2K_THIS s.tx_timer_active) {
++ BX_PANIC(("CR write, tx timer still active"));
++ PIC_RemoveEvents(NE2000_TX_Event);
++ }
++ //LOG_MSG("send packet command");
++ //s.tx_timer_index = (64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10;
++ s.tx_timer_active = 1;
++ PIC_AddEvent(NE2000_TX_Event,(float)((64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10000.0),0);
++ // Schedule a timer to trigger a tx-complete interrupt
++ // The number of microseconds is the bit-time / 10.
++ // The bit-time is the preamble+sfd (64 bits), the
++ // inter-frame gap (96 bits), the CRC (4 bytes), and the
++ // the number of bits in the frame (s.tx_bytes * 8).
++ //
++
++ /* TODO: Code transmit timer */
++ /*
++ bx_pc_system.activate_timer(BX_NE2K_THIS s.tx_timer_index,
++ (64 + 96 + 4*8 + BX_NE2K_THIS s.tx_bytes*8)/10,
++ 0); // not continuous
++ */
++ } // end transmit-start branch
++
++ // Linux probes for an interrupt by setting up a remote-DMA read
++ // of 0 bytes with remote-DMA completion interrupts enabled.
++ // Detect this here
++ if (BX_NE2K_THIS s.CR.rdma_cmd == 0x01 &&
++ BX_NE2K_THIS s.CR.start &&
++ BX_NE2K_THIS s.remote_bytes == 0) {
++ BX_NE2K_THIS s.ISR.rdma_done = 1;
++ if (BX_NE2K_THIS s.IMR.rdma_inte) {
++ PIC_ActivateIRQ(s.base_irq);
++ //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
++ }
++ }
++}
++
++//
++// chipmem_read/chipmem_write - access the 64K private RAM.
++// The ne2000 memory is accessed through the data port of
++// the asic (offset 0) after setting up a remote-DMA transfer.
++// Both byte and word accesses are allowed.
++// The first 16 bytes contains the MAC address at even locations,
++// and there is 16K of buffer memory starting at 16K
++//
++Bit32u bx_ne2k_c::chipmem_read(Bit32u address, unsigned int io_len)
++{
++ Bit32u retval = 0;
++
++ if ((io_len == 2) && (address & 0x1))
++ BX_PANIC(("unaligned chipmem word read"));
++
++ // ROM'd MAC address
++ if ((address >=0) && (address <= 31)) {
++ retval = BX_NE2K_THIS s.macaddr[address];
++ if ((io_len == 2) || (io_len == 4)) {
++ retval |= (BX_NE2K_THIS s.macaddr[address + 1] << 8);
++ if (io_len == 4) {
++ retval |= (BX_NE2K_THIS s.macaddr[address + 2] << 16);
++ retval |= (BX_NE2K_THIS s.macaddr[address + 3] << 24);
++ }
++ }
++ return (retval);
++ }
++
++ if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) {
++ retval = BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART];
++ if ((io_len == 2) || (io_len == 4)) {
++ retval |= (BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 1] << 8);
++ }
++ if (io_len == 4) {
++ retval |= (BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 2] << 16);
++ retval |= (BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 3] << 24);
++ }
++ return (retval);
++ }
++
++ BX_DEBUG("out-of-bounds chipmem read, %04X", address);
++
++ return (0xff);
++}
++
++void
++bx_ne2k_c::chipmem_write(Bit32u address, Bit32u value, unsigned io_len)
++{
++ if ((io_len == 2) && (address & 0x1))
++ BX_PANIC(("unaligned chipmem word write"));
++
++ if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) {
++ BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART] = value & 0xff;
++ if (io_len == 2)
++ BX_NE2K_THIS s.mem[address - BX_NE2K_MEMSTART + 1] = value >> 8;
++ } else
++ BX_DEBUG("out-of-bounds chipmem write, %04X", address);
++}
++
++//
++// asic_read/asic_write - This is the high 16 bytes of i/o space
++// (the lower 16 bytes is for the DS8390). Only two locations
++// are used: offset 0, which is used for data transfer, and
++// offset 0xf, which is used to reset the device.
++// The data transfer port is used to as 'external' DMA to the
++// DS8390. The chip has to have the DMA registers set up, and
++// after that, insw/outsw instructions can be used to move
++// the appropriate number of bytes to/from the device.
++//
++Bit32u
++bx_ne2k_c::asic_read(Bit32u offset, unsigned int io_len)
++{
++ Bit32u retval = 0;
++
++ switch (offset) {
++ case 0x0: // Data register
++ //
++ // A read remote-DMA command must have been issued,
++ // and the source-address and length registers must
++ // have been initialised.
++ //
++ if (io_len > BX_NE2K_THIS s.remote_bytes)
++ {
++ BX_ERROR("ne2K: dma read underrun iolen=%d remote_bytes=%d",io_len,BX_NE2K_THIS s.remote_bytes);
++ //return 0;
++ }
++
++ //BX_INFO(("ne2k read DMA: addr=%4x remote_bytes=%d",BX_NE2K_THIS s.remote_dma,BX_NE2K_THIS s.remote_bytes));
++ retval = chipmem_read(BX_NE2K_THIS s.remote_dma, io_len);
++ //
++ // The 8390 bumps the address and decreases the byte count
++ // by the selected word size after every access, not by
++ // the amount of data requested by the host (io_len).
++ //
++ BX_NE2K_THIS s.remote_dma += (BX_NE2K_THIS s.DCR.wdsize + 1);
++ if (BX_NE2K_THIS s.remote_dma == BX_NE2K_THIS s.page_stop << 8) {
++ BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.page_start << 8;
++ }
++ // keep s.remote_bytes from underflowing
++ if (BX_NE2K_THIS s.remote_bytes > 1)
++ BX_NE2K_THIS s.remote_bytes -= (BX_NE2K_THIS s.DCR.wdsize + 1);
++ else
++ BX_NE2K_THIS s.remote_bytes = 0;
++
++ // If all bytes have been written, signal remote-DMA complete
++ if (BX_NE2K_THIS s.remote_bytes == 0) {
++ BX_NE2K_THIS s.ISR.rdma_done = 1;
++ if (BX_NE2K_THIS s.IMR.rdma_inte) {
++ PIC_ActivateIRQ(s.base_irq);
++ //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
++ }
++ }
++ break;
++
++ case 0xf: // Reset register
++ theNE2kDevice->reset(BX_RESET_SOFTWARE);
++ //retval=0x1;
++ break;
++
++ default:
++ BX_INFO("asic read invalid address %04x", (unsigned) offset);
++ break;
++ }
++
++ return (retval);
++}
++
++void
++bx_ne2k_c::asic_write(Bit32u offset, Bit32u value, unsigned io_len)
++{
++ BX_DEBUG("asic write addr=0x%02x, value=0x%04x", (unsigned) offset, (unsigned) value);
++ switch (offset) {
++ case 0x0: // Data register - see asic_read for a description
++
++ if ((io_len == 2) && (BX_NE2K_THIS s.DCR.wdsize == 0)) {
++ BX_PANIC(("dma write length 2 on byte mode operation"));
++ break;
++ }
++
++ if (BX_NE2K_THIS s.remote_bytes == 0)
++ BX_PANIC(("ne2K: dma write, byte count 0"));
++
++ chipmem_write(BX_NE2K_THIS s.remote_dma, value, io_len);
++ // is this right ??? asic_read uses DCR.wordsize
++ BX_NE2K_THIS s.remote_dma += io_len;
++ if (BX_NE2K_THIS s.remote_dma == BX_NE2K_THIS s.page_stop << 8) {
++ BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.page_start << 8;
++ }
++
++ BX_NE2K_THIS s.remote_bytes -= io_len;
++ if (BX_NE2K_THIS s.remote_bytes > BX_NE2K_MEMSIZ)
++ BX_NE2K_THIS s.remote_bytes = 0;
++
++ // If all bytes have been written, signal remote-DMA complete
++ if (BX_NE2K_THIS s.remote_bytes == 0) {
++ BX_NE2K_THIS s.ISR.rdma_done = 1;
++ if (BX_NE2K_THIS s.IMR.rdma_inte) {
++ PIC_ActivateIRQ(s.base_irq);
++ //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
++ }
++ }
++ break;
++
++ case 0xf: // Reset register
++ theNE2kDevice->reset(BX_RESET_SOFTWARE);
++ break;
++
++ default: // this is invalid, but happens under win95 device detection
++ BX_INFO("asic write invalid address %04x, ignoring", (unsigned) offset);
++ break ;
++ }
++}
++
++//
++// page0_read/page0_write - These routines handle reads/writes to
++// the 'zeroth' page of the DS8390 register file
++//
++Bit32u
++bx_ne2k_c::page0_read(Bit32u offset, unsigned int io_len)
++{
++ BX_DEBUG("page 0 read from port %04x, len=%u", (unsigned) offset,
++ (unsigned) io_len);
++ if (io_len > 1) {
++ BX_ERROR("bad length! page 0 read from port %04x, len=%u", (unsigned) offset,
++ (unsigned) io_len); /* encountered with win98 hardware probe */
++ return 0;
++ }
++
++
++ switch (offset) {
++ case 0x1: // CLDA0
++ return (BX_NE2K_THIS s.local_dma & 0xff);
++ break;
++
++ case 0x2: // CLDA1
++ return (BX_NE2K_THIS s.local_dma >> 8);
++ break;
++
++ case 0x3: // BNRY
++ return (BX_NE2K_THIS s.bound_ptr);
++ break;
++
++ case 0x4: // TSR
++ return ((BX_NE2K_THIS s.TSR.ow_coll << 7) |
++ (BX_NE2K_THIS s.TSR.cd_hbeat << 6) |
++ (BX_NE2K_THIS s.TSR.fifo_ur << 5) |
++ (BX_NE2K_THIS s.TSR.no_carrier << 4) |
++ (BX_NE2K_THIS s.TSR.aborted << 3) |
++ (BX_NE2K_THIS s.TSR.collided << 2) |
++ (BX_NE2K_THIS s.TSR.tx_ok));
++ break;
++
++ case 0x5: // NCR
++ return (BX_NE2K_THIS s.num_coll);
++ break;
++
++ case 0x6: // FIFO
++ // reading FIFO is only valid in loopback mode
++ BX_ERROR(("reading FIFO not supported yet"));
++ return (BX_NE2K_THIS s.fifo);
++ break;
++
++ case 0x7: // ISR
++ return ((BX_NE2K_THIS s.ISR.reset << 7) |
++ (BX_NE2K_THIS s.ISR.rdma_done << 6) |
++ (BX_NE2K_THIS s.ISR.cnt_oflow << 5) |
++ (BX_NE2K_THIS s.ISR.overwrite << 4) |
++ (BX_NE2K_THIS s.ISR.tx_err << 3) |
++ (BX_NE2K_THIS s.ISR.rx_err << 2) |
++ (BX_NE2K_THIS s.ISR.pkt_tx << 1) |
++ (BX_NE2K_THIS s.ISR.pkt_rx));
++ break;
++
++ case 0x8: // CRDA0
++ return (BX_NE2K_THIS s.remote_dma & 0xff);
++ break;
++
++ case 0x9: // CRDA1
++ return (BX_NE2K_THIS s.remote_dma >> 8);
++ break;
++
++ case 0xa: // reserved
++ BX_INFO(("reserved read - page 0, 0xa"));
++ return (0xff);
++ break;
++
++ case 0xb: // reserved
++ BX_INFO(("reserved read - page 0, 0xb"));
++ return (0xff);
++ break;
++
++ case 0xc: // RSR
++ return ((BX_NE2K_THIS s.RSR.deferred << 7) |
++ (BX_NE2K_THIS s.RSR.rx_disabled << 6) |
++ (BX_NE2K_THIS s.RSR.rx_mbit << 5) |
++ (BX_NE2K_THIS s.RSR.rx_missed << 4) |
++ (BX_NE2K_THIS s.RSR.fifo_or << 3) |
++ (BX_NE2K_THIS s.RSR.bad_falign << 2) |
++ (BX_NE2K_THIS s.RSR.bad_crc << 1) |
++ (BX_NE2K_THIS s.RSR.rx_ok));
++ break;
++
++ case 0xd: // CNTR0
++ return (BX_NE2K_THIS s.tallycnt_0);
++ break;
++
++ case 0xe: // CNTR1
++ return (BX_NE2K_THIS s.tallycnt_1);
++ break;
++
++ case 0xf: // CNTR2
++ return (BX_NE2K_THIS s.tallycnt_2);
++ break;
++
++ default:
++ BX_PANIC("page 0 offset %04x out of range", (unsigned) offset);
++ }
++
++ return(0);
++}
++
++void
++bx_ne2k_c::page0_write(Bit32u offset, Bit32u value, unsigned io_len)
++{
++ BX_DEBUG("page 0 write to port %04x, len=%u", (unsigned) offset,
++ (unsigned) io_len);
++
++ // It appears to be a common practice to use outw on page0 regs...
++
++ // break up outw into two outb's
++ if (io_len == 2) {
++ page0_write(offset, (value & 0xff), 1);
++ page0_write(offset + 1, ((value >> 8) & 0xff), 1);
++ return;
++ }
++
++ switch (offset) {
++ case 0x1: // PSTART
++ BX_NE2K_THIS s.page_start = value;
++ break;
++
++ case 0x2: // PSTOP
++ // BX_INFO(("Writing to PSTOP: %02x", value));
++ BX_NE2K_THIS s.page_stop = value;
++ break;
++
++ case 0x3: // BNRY
++ BX_NE2K_THIS s.bound_ptr = value;
++ break;
++
++ case 0x4: // TPSR
++ BX_NE2K_THIS s.tx_page_start = value;
++ break;
++
++ case 0x5: // TBCR0
++ // Clear out low byte and re-insert
++ BX_NE2K_THIS s.tx_bytes &= 0xff00;
++ BX_NE2K_THIS s.tx_bytes |= (value & 0xff);
++ break;
++
++ case 0x6: // TBCR1
++ // Clear out high byte and re-insert
++ BX_NE2K_THIS s.tx_bytes &= 0x00ff;
++ BX_NE2K_THIS s.tx_bytes |= ((value & 0xff) << 8);
++ break;
++
++ case 0x7: // ISR
++ value &= 0x7f; // clear RST bit - status-only bit
++ // All other values are cleared iff the ISR bit is 1
++ BX_NE2K_THIS s.ISR.pkt_rx &= ~((bx_bool)((value & 0x01) == 0x01));
++ BX_NE2K_THIS s.ISR.pkt_tx &= ~((bx_bool)((value & 0x02) == 0x02));
++ BX_NE2K_THIS s.ISR.rx_err &= ~((bx_bool)((value & 0x04) == 0x04));
++ BX_NE2K_THIS s.ISR.tx_err &= ~((bx_bool)((value & 0x08) == 0x08));
++ BX_NE2K_THIS s.ISR.overwrite &= ~((bx_bool)((value & 0x10) == 0x10));
++ BX_NE2K_THIS s.ISR.cnt_oflow &= ~((bx_bool)((value & 0x20) == 0x20));
++ BX_NE2K_THIS s.ISR.rdma_done &= ~((bx_bool)((value & 0x40) == 0x40));
++ value = ((BX_NE2K_THIS s.ISR.rdma_done << 6) |
++ (BX_NE2K_THIS s.ISR.cnt_oflow << 5) |
++ (BX_NE2K_THIS s.ISR.overwrite << 4) |
++ (BX_NE2K_THIS s.ISR.tx_err << 3) |
++ (BX_NE2K_THIS s.ISR.rx_err << 2) |
++ (BX_NE2K_THIS s.ISR.pkt_tx << 1) |
++ (BX_NE2K_THIS s.ISR.pkt_rx));
++ value &= ((BX_NE2K_THIS s.IMR.rdma_inte << 6) |
++ (BX_NE2K_THIS s.IMR.cofl_inte << 5) |
++ (BX_NE2K_THIS s.IMR.overw_inte << 4) |
++ (BX_NE2K_THIS s.IMR.txerr_inte << 3) |
++ (BX_NE2K_THIS s.IMR.rxerr_inte << 2) |
++ (BX_NE2K_THIS s.IMR.tx_inte << 1) |
++ (BX_NE2K_THIS s.IMR.rx_inte));
++ if (value == 0)
++ PIC_DeActivateIRQ(s.base_irq);
++ //DEV_pic_lower_irq(BX_NE2K_THIS s.base_irq);
++ break;
++
++ case 0x8: // RSAR0
++ // Clear out low byte and re-insert
++ BX_NE2K_THIS s.remote_start &= 0xff00;
++ BX_NE2K_THIS s.remote_start |= (value & 0xff);
++ BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.remote_start;
++ break;
++
++ case 0x9: // RSAR1
++ // Clear out high byte and re-insert
++ BX_NE2K_THIS s.remote_start &= 0x00ff;
++ BX_NE2K_THIS s.remote_start |= ((value & 0xff) << 8);
++ BX_NE2K_THIS s.remote_dma = BX_NE2K_THIS s.remote_start;
++ break;
++
++ case 0xa: // RBCR0
++ // Clear out low byte and re-insert
++ BX_NE2K_THIS s.remote_bytes &= 0xff00;
++ BX_NE2K_THIS s.remote_bytes |= (value & 0xff);
++ break;
++
++ case 0xb: // RBCR1
++ // Clear out high byte and re-insert
++ BX_NE2K_THIS s.remote_bytes &= 0x00ff;
++ BX_NE2K_THIS s.remote_bytes |= ((value & 0xff) << 8);
++ break;
++
++ case 0xc: // RCR
++ // Check if the reserved bits are set
++ if (value & 0xc0)
++ BX_INFO(("RCR write, reserved bits set"));
++
++ // Set all other bit-fields
++ BX_NE2K_THIS s.RCR.errors_ok = ((value & 0x01) == 0x01);
++ BX_NE2K_THIS s.RCR.runts_ok = ((value & 0x02) == 0x02);
++ BX_NE2K_THIS s.RCR.broadcast = ((value & 0x04) == 0x04);
++ BX_NE2K_THIS s.RCR.multicast = ((value & 0x08) == 0x08);
++ BX_NE2K_THIS s.RCR.promisc = ((value & 0x10) == 0x10);
++ BX_NE2K_THIS s.RCR.monitor = ((value & 0x20) == 0x20);
++
++ // Monitor bit is a little suspicious...
++ if (value & 0x20)
++ BX_INFO(("RCR write, monitor bit set!"));
++ break;
++
++ case 0xd: // TCR
++ // Check reserved bits
++ if (value & 0xe0)
++ BX_ERROR(("TCR write, reserved bits set"));
++
++ // Test loop mode (not supported)
++ if (value & 0x06) {
++ BX_NE2K_THIS s.TCR.loop_cntl = (value & 0x6) >> 1;
++ BX_INFO("TCR write, loop mode %d not supported", BX_NE2K_THIS s.TCR.loop_cntl);
++ } else {
++ BX_NE2K_THIS s.TCR.loop_cntl = 0;
++ }
++
++ // Inhibit-CRC not supported.
++ if (value & 0x01)
++ BX_PANIC(("TCR write, inhibit-CRC not supported"));
++
++ // Auto-transmit disable very suspicious
++ if (value & 0x08)
++ BX_PANIC(("TCR write, auto transmit disable not supported"));
++
++ // Allow collision-offset to be set, although not used
++ BX_NE2K_THIS s.TCR.coll_prio = ((value & 0x08) == 0x08);
++ break;
++
++ case 0xe: // DCR
++ // the loopback mode is not suppported yet
++ if (!(value & 0x08)) {
++ BX_ERROR(("DCR write, loopback mode selected"));
++ }
++ // It is questionable to set longaddr and auto_rx, since they
++ // aren't supported on the ne2000. Print a warning and continue
++ if (value & 0x04)
++ BX_INFO(("DCR write - LAS set ???"));
++ if (value & 0x10)
++ BX_INFO(("DCR write - AR set ???"));
++
++ // Set other values.
++ BX_NE2K_THIS s.DCR.wdsize = ((value & 0x01) == 0x01);
++ BX_NE2K_THIS s.DCR.endian = ((value & 0x02) == 0x02);
++ BX_NE2K_THIS s.DCR.longaddr = ((value & 0x04) == 0x04); // illegal ?
++ BX_NE2K_THIS s.DCR.loop = ((value & 0x08) == 0x08);
++ BX_NE2K_THIS s.DCR.auto_rx = ((value & 0x10) == 0x10); // also illegal ?
++ BX_NE2K_THIS s.DCR.fifo_size = (value & 0x50) >> 5;
++ break;
++
++ case 0xf: // IMR
++ // Check for reserved bit
++ if (value & 0x80)
++ BX_PANIC(("IMR write, reserved bit set"));
++
++ // Set other values
++ BX_NE2K_THIS s.IMR.rx_inte = ((value & 0x01) == 0x01);
++ BX_NE2K_THIS s.IMR.tx_inte = ((value & 0x02) == 0x02);
++ BX_NE2K_THIS s.IMR.rxerr_inte = ((value & 0x04) == 0x04);
++ BX_NE2K_THIS s.IMR.txerr_inte = ((value & 0x08) == 0x08);
++ BX_NE2K_THIS s.IMR.overw_inte = ((value & 0x10) == 0x10);
++ BX_NE2K_THIS s.IMR.cofl_inte = ((value & 0x20) == 0x20);
++ BX_NE2K_THIS s.IMR.rdma_inte = ((value & 0x40) == 0x40);
++ if(BX_NE2K_THIS s.ISR.pkt_tx && BX_NE2K_THIS s.IMR.tx_inte) {
++ LOG_MSG("tx irq retrigger");
++ PIC_ActivateIRQ(s.base_irq);
++ }
++ break;
++ default:
++ BX_PANIC("page 0 write, bad offset %0x", offset);
++ }
++}
++
++
++//
++// page1_read/page1_write - These routines handle reads/writes to
++// the first page of the DS8390 register file
++//
++Bit32u
++bx_ne2k_c::page1_read(Bit32u offset, unsigned int io_len)
++{
++ BX_DEBUG("page 1 read from port %04x, len=%u", (unsigned) offset,
++ (unsigned) io_len);
++ if (io_len > 1)
++ BX_PANIC("bad length! page 1 read from port %04x, len=%u", (unsigned) offset,
++ (unsigned) io_len);
++
++ switch (offset) {
++ case 0x1: // PAR0-5
++ case 0x2:
++ case 0x3:
++ case 0x4:
++ case 0x5:
++ case 0x6:
++ return (BX_NE2K_THIS s.physaddr[offset - 1]);
++ break;
++
++ case 0x7: // CURR
++ BX_DEBUG("returning current page: %02x", (BX_NE2K_THIS s.curr_page));
++ return (BX_NE2K_THIS s.curr_page);
++
++ case 0x8: // MAR0-7
++ case 0x9:
++ case 0xa:
++ case 0xb:
++ case 0xc:
++ case 0xd:
++ case 0xe:
++ case 0xf:
++ return (BX_NE2K_THIS s.mchash[offset - 8]);
++ break;
++
++ default:
++ BX_PANIC("page 1 r offset %04x out of range", (unsigned) offset);
++ }
++
++ return (0);
++}
++
++void
++bx_ne2k_c::page1_write(Bit32u offset, Bit32u value, unsigned io_len)
++{
++ BX_DEBUG("page 1 w offset %04x", (unsigned) offset);
++ switch (offset) {
++ case 0x1: // PAR0-5
++ case 0x2:
++ case 0x3:
++ case 0x4:
++ case 0x5:
++ case 0x6:
++ BX_NE2K_THIS s.physaddr[offset - 1] = value;
++ break;
++
++ case 0x7: // CURR
++ BX_NE2K_THIS s.curr_page = value;
++ break;
++
++ case 0x8: // MAR0-7
++ case 0x9:
++ case 0xa:
++ case 0xb:
++ case 0xc:
++ case 0xd:
++ case 0xe:
++ case 0xf:
++ BX_NE2K_THIS s.mchash[offset - 8] = value;
++ break;
++
++ default:
++ BX_PANIC("page 1 w offset %04x out of range", (unsigned) offset);
++ }
++}
++
++
++//
++// page2_read/page2_write - These routines handle reads/writes to
++// the second page of the DS8390 register file
++//
++Bit32u
++bx_ne2k_c::page2_read(Bit32u offset, unsigned int io_len)
++{
++ BX_DEBUG("page 2 read from port %04x, len=%u", (unsigned) offset, (unsigned) io_len);
++
++ if (io_len > 1)
++ BX_PANIC("bad length! page 2 read from port %04x, len=%u", (unsigned) offset, (unsigned) io_len);
++
++ switch (offset) {
++ case 0x1: // PSTART
++ return (BX_NE2K_THIS s.page_start);
++ break;
++
++ case 0x2: // PSTOP
++ return (BX_NE2K_THIS s.page_stop);
++ break;
++
++ case 0x3: // Remote Next-packet pointer
++ return (BX_NE2K_THIS s.rempkt_ptr);
++ break;
++
++ case 0x4: // TPSR
++ return (BX_NE2K_THIS s.tx_page_start);
++ break;
++
++ case 0x5: // Local Next-packet pointer
++ return (BX_NE2K_THIS s.localpkt_ptr);
++ break;
++
++ case 0x6: // Address counter (upper)
++ return (BX_NE2K_THIS s.address_cnt >> 8);
++ break;
++
++ case 0x7: // Address counter (lower)
++ return (BX_NE2K_THIS s.address_cnt & 0xff);
++ break;
++
++ case 0x8: // Reserved
++ case 0x9:
++ case 0xa:
++ case 0xb:
++ BX_ERROR("reserved read - page 2, 0x%02x", (unsigned) offset);
++ return (0xff);
++ break;
++
++ case 0xc: // RCR
++ return ((BX_NE2K_THIS s.RCR.monitor << 5) |
++ (BX_NE2K_THIS s.RCR.promisc << 4) |
++ (BX_NE2K_THIS s.RCR.multicast << 3) |
++ (BX_NE2K_THIS s.RCR.broadcast << 2) |
++ (BX_NE2K_THIS s.RCR.runts_ok << 1) |
++ (BX_NE2K_THIS s.RCR.errors_ok));
++ break;
++
++ case 0xd: // TCR
++ return ((BX_NE2K_THIS s.TCR.coll_prio << 4) |
++ (BX_NE2K_THIS s.TCR.ext_stoptx << 3) |
++ ((BX_NE2K_THIS s.TCR.loop_cntl & 0x3) << 1) |
++ (BX_NE2K_THIS s.TCR.crc_disable));
++ break;
++
++ case 0xe: // DCR
++ return (((BX_NE2K_THIS s.DCR.fifo_size & 0x3) << 5) |
++ (BX_NE2K_THIS s.DCR.auto_rx << 4) |
++ (BX_NE2K_THIS s.DCR.loop << 3) |
++ (BX_NE2K_THIS s.DCR.longaddr << 2) |
++ (BX_NE2K_THIS s.DCR.endian << 1) |
++ (BX_NE2K_THIS s.DCR.wdsize));
++ break;
++
++ case 0xf: // IMR
++ return ((BX_NE2K_THIS s.IMR.rdma_inte << 6) |
++ (BX_NE2K_THIS s.IMR.cofl_inte << 5) |
++ (BX_NE2K_THIS s.IMR.overw_inte << 4) |
++ (BX_NE2K_THIS s.IMR.txerr_inte << 3) |
++ (BX_NE2K_THIS s.IMR.rxerr_inte << 2) |
++ (BX_NE2K_THIS s.IMR.tx_inte << 1) |
++ (BX_NE2K_THIS s.IMR.rx_inte));
++ break;
++
++ default:
++ BX_PANIC("page 2 offset %04x out of range", (unsigned) offset);
++ }
++
++ return (0);
++};
++
++void
++bx_ne2k_c::page2_write(Bit32u offset, Bit32u value, unsigned io_len)
++{
++ // Maybe all writes here should be BX_PANIC()'d, since they
++ // affect internal operation, but let them through for now
++ // and print a warning.
++ if (offset != 0)
++ BX_ERROR(("page 2 write ?"));
++
++ switch (offset) {
++ case 0x1: // CLDA0
++ // Clear out low byte and re-insert
++ BX_NE2K_THIS s.local_dma &= 0xff00;
++ BX_NE2K_THIS s.local_dma |= (value & 0xff);
++ break;
++
++ case 0x2: // CLDA1
++ // Clear out high byte and re-insert
++ BX_NE2K_THIS s.local_dma &= 0x00ff;
++ BX_NE2K_THIS s.local_dma |= ((value & 0xff) << 8);
++ break;
++
++ case 0x3: // Remote Next-pkt pointer
++ BX_NE2K_THIS s.rempkt_ptr = value;
++ break;
++
++ case 0x4:
++ BX_PANIC(("page 2 write to reserved offset 4"));
++ break;
++
++ case 0x5: // Local Next-packet pointer
++ BX_NE2K_THIS s.localpkt_ptr = value;
++ break;
++
++ case 0x6: // Address counter (upper)
++ // Clear out high byte and re-insert
++ BX_NE2K_THIS s.address_cnt &= 0x00ff;
++ BX_NE2K_THIS s.address_cnt |= ((value & 0xff) << 8);
++ break;
++
++ case 0x7: // Address counter (lower)
++ // Clear out low byte and re-insert
++ BX_NE2K_THIS s.address_cnt &= 0xff00;
++ BX_NE2K_THIS s.address_cnt |= (value & 0xff);
++ break;
++
++ case 0x8:
++ case 0x9:
++ case 0xa:
++ case 0xb:
++ case 0xc:
++ case 0xd:
++ case 0xe:
++ case 0xf:
++ BX_PANIC("page 2 write to reserved offset %0x", offset);
++ break;
++
++ default:
++ BX_PANIC("page 2 write, illegal offset %0x", offset);
++ break;
++ }
++}
++
++//
++// page3_read/page3_write - writes to this page are illegal
++//
++Bit32u
++bx_ne2k_c::page3_read(Bit32u offset, unsigned int io_len)
++{
++ BX_PANIC(("page 3 read attempted"));
++ return (0);
++}
++
++void
++bx_ne2k_c::page3_write(Bit32u offset, Bit32u value, unsigned io_len)
++{
++ BX_PANIC(("page 3 write attempted"));
++}
++
++//
++// tx_timer_handler/tx_timer
++//
++void
++bx_ne2k_c::tx_timer_handler(void *this_ptr)
++{
++ bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
++
++ class_ptr->tx_timer();
++}
++
++void
++bx_ne2k_c::tx_timer(void)
++{
++ BX_DEBUG(("tx_timer"));
++ BX_NE2K_THIS s.TSR.tx_ok = 1;
++ // Generate an interrupt if not masked and not one in progress
++ if (BX_NE2K_THIS s.IMR.tx_inte && !BX_NE2K_THIS s.ISR.pkt_tx) {
++ //LOG_MSG("tx complete interrupt");
++ PIC_ActivateIRQ(s.base_irq);
++ //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
++ } //else LOG_MSG("no tx complete interrupt");
++ BX_NE2K_THIS s.ISR.pkt_tx = 1;
++ BX_NE2K_THIS s.tx_timer_active = 0;
++}
++
++
++//
++// read_handler/read - i/o 'catcher' function called from BOCHS
++// mainline when the CPU attempts a read in the i/o space registered
++// by this ne2000 instance
++//
++Bit32u bx_ne2k_c::read_handler(void *this_ptr, Bit32u address, unsigned io_len)
++{
++#if !BX_USE_NE2K_SMF
++ bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
++
++ return( class_ptr->read(address, io_len) );
++}
++
++Bit32u bx_ne2k_c::read(Bit32u address, unsigned io_len)
++{
++#else
++ UNUSED(this_ptr);
++#endif // !BX_USE_NE2K_SMF
++ BX_DEBUG("read addr %x, len %d", address, io_len);
++ Bit32u retval = 0;
++ int offset = address - BX_NE2K_THIS s.base_address;
++
++ if (offset >= 0x10) {
++ retval = asic_read(offset - 0x10, io_len);
++ } else if (offset == 0x00) {
++ retval = read_cr();
++ } else {
++ switch (BX_NE2K_THIS s.CR.pgsel) {
++ case 0x00:
++ retval = page0_read(offset, io_len);
++ break;
++
++ case 0x01:
++ retval = page1_read(offset, io_len);
++ break;
++
++ case 0x02:
++ retval = page2_read(offset, io_len);
++ break;
++
++ case 0x03:
++ retval = page3_read(offset, io_len);
++ break;
++
++ default:
++ BX_PANIC("ne2K: unknown value of pgsel in read - %d",
++ BX_NE2K_THIS s.CR.pgsel);
++ }
++ }
++
++ return (retval);
++}
++
++//
++// write_handler/write - i/o 'catcher' function called from BOCHS
++// mainline when the CPU attempts a write in the i/o space registered
++// by this ne2000 instance
++//
++void
++bx_ne2k_c::write_handler(void *this_ptr, Bit32u address, Bit32u value,
++ unsigned io_len)
++{
++#if !BX_USE_NE2K_SMF
++ bx_ne2k_c *class_ptr = (bx_ne2k_c *) this_ptr;
++
++ class_ptr->write(address, value, io_len);
++}
++
++void
++bx_ne2k_c::write(Bit32u address, Bit32u value, unsigned io_len)
++{
++#else
++ UNUSED(this_ptr);
++#endif // !BX_USE_NE2K_SMF
++ BX_DEBUG("write with length %d", io_len);
++ int offset = address - BX_NE2K_THIS s.base_address;
++
++ //
++ // The high 16 bytes of i/o space are for the ne2000 asic -
++ // the low 16 bytes are for the DS8390, with the current
++ // page being selected by the PS0,PS1 registers in the
++ // command register
++ //
++ if (offset >= 0x10) {
++ asic_write(offset - 0x10, value, io_len);
++ } else if (offset == 0x00) {
++ write_cr(value);
++ } else {
++ switch (BX_NE2K_THIS s.CR.pgsel) {
++ case 0x00:
++ page0_write(offset, value, io_len);
++ break;
++
++ case 0x01:
++ page1_write(offset, value, io_len);
++ break;
++
++ case 0x02:
++ page2_write(offset, value, io_len);
++ break;
++
++ case 0x03:
++ page3_write(offset, value, io_len);
++ break;
++
++ default:
++ BX_PANIC("ne2K: unknown value of pgsel in write - %d",
++ BX_NE2K_THIS s.CR.pgsel);
++ }
++ }
++}
++
++
++/*
++ * mcast_index() - return the 6-bit index into the multicast
++ * table. Stolen unashamedly from FreeBSD's if_ed.c
++ */
++unsigned
++bx_ne2k_c::mcast_index(const void *dst)
++{
++#define POLYNOMIAL 0x04c11db6
++ Bit32u crc = 0xffffffffL;
++ int carry, i, j;
++ unsigned char b;
++ unsigned char *ep = (unsigned char *) dst;
++
++ for (i = 6; --i >= 0;) {
++ b = *ep++;
++ for (j = 8; --j >= 0;) {
++ carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
++ crc <<= 1;
++ b >>= 1;
++ if (carry)
++ crc = ((crc ^ POLYNOMIAL) | carry);
++ }
++ }
++ return (crc >> 26);
++#undef POLYNOMIAL
++}
++
++/*
++ * Callback from the eth system driver when a frame has arrived
++ */
++/*
++void
++bx_ne2k_c::rx_handler(void *arg, const void *buf, unsigned len)
++{
++ // BX_DEBUG(("rx_handler with length %d", len));
++ bx_ne2k_c *class_ptr = (bx_ne2k_c *) arg;
++ if(
++ class_ptr->rx_frame(buf, len);
++}
++*/
++/*
++ * rx_frame() - called by the platform-specific code when an
++ * ethernet frame has been received. The destination address
++ * is tested to see if it should be accepted, and if the
++ * rx ring has enough room, it is copied into it and
++ * the receive process is updated
++ */
++void
++bx_ne2k_c::rx_frame(const void *buf, unsigned io_len)
++{
++ int pages;
++ int avail;
++ unsigned idx;
++ int wrapped;
++ int nextpage;
++ unsigned char pkthdr[4];
++ unsigned char *pktbuf = (unsigned char *) buf;
++ unsigned char *startptr;
++ static unsigned char bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
++
++ if(io_len != 60) {
++ BX_DEBUG("rx_frame with length %d", io_len);
++ }
++
++ //LOG_MSG("stop=%d, pagestart=%x, dcr_loop=%x, tcr_loopcntl=%x",
++ // BX_NE2K_THIS s.CR.stop, BX_NE2K_THIS s.page_start,
++ // BX_NE2K_THIS s.DCR.loop, BX_NE2K_THIS s.TCR.loop_cntl);
++ if ((BX_NE2K_THIS s.CR.stop != 0) ||
++ (BX_NE2K_THIS s.page_start == 0) /*||
++ ((BX_NE2K_THIS s.DCR.loop == 0) &&
++ (BX_NE2K_THIS s.TCR.loop_cntl != 0))*/) {
++ return;
++ }
++
++ // Add the pkt header + CRC to the length, and work
++ // out how many 256-byte pages the frame would occupy
++ pages = (io_len + 4 + 4 + 255)/256;
++
++ if (BX_NE2K_THIS s.curr_page < BX_NE2K_THIS s.bound_ptr) {
++ avail = BX_NE2K_THIS s.bound_ptr - BX_NE2K_THIS s.curr_page;
++ } else {
++ avail = (BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.page_start) -
++ (BX_NE2K_THIS s.curr_page - BX_NE2K_THIS s.bound_ptr);
++ wrapped = 1;
++ }
++
++ // Avoid getting into a buffer overflow condition by not attempting
++ // to do partial receives. The emulation to handle this condition
++ // seems particularly painful.
++ if ((avail < pages)
++#if BX_NE2K_NEVER_FULL_RING
++ || (avail == pages)
++#endif
++ ) {
++ BX_DEBUG("no space");
++ return;
++ }
++
++ if ((io_len < 40/*60*/) && !BX_NE2K_THIS s.RCR.runts_ok) {
++ BX_DEBUG("rejected small packet, length %d", io_len);
++ return;
++ }
++ // some computers don't care...
++ if (io_len < 60) io_len=60;
++
++ // Do address filtering if not in promiscuous mode
++ if (! BX_NE2K_THIS s.RCR.promisc) {
++ if (!memcmp(buf, bcast_addr, 6)) {
++ if (!BX_NE2K_THIS s.RCR.broadcast) {
++ return;
++ }
++ } else if (pktbuf[0] & 0x01) {
++ if (! BX_NE2K_THIS s.RCR.multicast) {
++ return;
++ }
++ idx = mcast_index(buf);
++ if (!(BX_NE2K_THIS s.mchash[idx >> 3] & (1 << (idx & 0x7)))) {
++ return;
++ }
++ } else if (0 != memcmp(buf, BX_NE2K_THIS s.physaddr, 6)) {
++ return;
++ }
++ } else {
++ BX_DEBUG(("rx_frame promiscuous receive"));
++ }
++
++ BX_INFO("rx_frame %d to %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x",
++ io_len,
++ pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3], pktbuf[4], pktbuf[5],
++ pktbuf[6], pktbuf[7], pktbuf[8], pktbuf[9], pktbuf[10], pktbuf[11]);
++
++ nextpage = BX_NE2K_THIS s.curr_page + pages;
++ if (nextpage >= BX_NE2K_THIS s.page_stop) {
++ nextpage -= BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.page_start;
++ }
++
++ // Setup packet header
++ pkthdr[0] = 0; // rx status - old behavior
++ pkthdr[0] = 1; // Probably better to set it all the time
++ // rather than set it to 0, which is clearly wrong.
++ if (pktbuf[0] & 0x01) {
++ pkthdr[0] |= 0x20; // rx status += multicast packet
++ }
++ pkthdr[1] = nextpage; // ptr to next packet
++ pkthdr[2] = (io_len + 4) & 0xff; // length-low
++ pkthdr[3] = (io_len + 4) >> 8; // length-hi
++
++ // copy into buffer, update curpage, and signal interrupt if config'd
++ startptr = & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.curr_page * 256 -
++ BX_NE2K_MEMSTART];
++ if ((nextpage > BX_NE2K_THIS s.curr_page) ||
++ ((BX_NE2K_THIS s.curr_page + pages) == BX_NE2K_THIS s.page_stop)) {
++ memcpy(startptr, pkthdr, 4);
++ memcpy(startptr + 4, buf, io_len);
++ BX_NE2K_THIS s.curr_page = nextpage;
++ } else {
++ int endbytes = (BX_NE2K_THIS s.page_stop - BX_NE2K_THIS s.curr_page)
++ * 256;
++ memcpy(startptr, pkthdr, 4);
++ memcpy(startptr + 4, buf, endbytes - 4);
++ startptr = & BX_NE2K_THIS s.mem[BX_NE2K_THIS s.page_start * 256 -
++ BX_NE2K_MEMSTART];
++ memcpy(startptr, (void *)(pktbuf + endbytes - 4),
++ io_len - endbytes + 8);
++ BX_NE2K_THIS s.curr_page = nextpage;
++ }
++
++ BX_NE2K_THIS s.RSR.rx_ok = 1;
++ if (pktbuf[0] & 0x80) {
++ BX_NE2K_THIS s.RSR.rx_mbit = 1;
++ }
++
++ BX_NE2K_THIS s.ISR.pkt_rx = 1;
++
++ if (BX_NE2K_THIS s.IMR.rx_inte) {
++ //LOG_MSG("packet rx interrupt");
++ PIC_ActivateIRQ(s.base_irq);
++ //DEV_pic_raise_irq(BX_NE2K_THIS s.base_irq);
++ } //else LOG_MSG("no packet rx interrupt");
++
++}
++
++//Bit8u macaddr[6] = { 0xAC, 0xDE, 0x48, 0x8E, 0x89, 0x19 };
++
++Bitu dosbox_read(Bitu port, Bitu len) {
++ Bitu retval = theNE2kDevice->read(port,len);
++ //LOG_MSG("ne2k rd port %x val %4x len %d page %d, CS:IP %8x:%8x",
++ // port, retval, len, theNE2kDevice->s.CR.pgsel,SegValue(cs),reg_eip);
++ return retval;
++}
++void dosbox_write(Bitu port, Bitu val, Bitu len) {
++ //LOG_MSG("ne2k wr port %x val %4x len %d page %d, CS:IP %8x:%8x",
++ // port, val, len,theNE2kDevice->s.CR.pgsel,SegValue(cs),reg_eip);
++ theNE2kDevice->write(port, val, len);
++}
++
++void bx_ne2k_c::init()
++{
++ //BX_DEBUG(("Init $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $"));
++
++ // Read in values from config file
++ //BX_NE2K_THIS s.base_address = 0x300;
++ //BX_NE2K_THIS s.base_irq = 3;
++ /*
++ if (BX_NE2K_THIS s.tx_timer_index == BX_NULL_TIMER_HANDLE) {
++ BX_NE2K_THIS s.tx_timer_index =
++ bx_pc_system.register_timer(this, tx_timer_handler, 0,
++ 0,0, "ne2k"); // one-shot, inactive
++ }*/
++ // Register the IRQ and i/o port addresses
++ //DEV_register_irq(BX_NE2K_THIS s.base_irq, "NE2000 ethernet NIC");
++
++ //DEV_register_ioread_handler(this, read_handler, addr, "ne2000 NIC", 3);
++ //DEV_register_iowrite_handler(this, write_handler, addr, "ne2000 NIC", 3);
++
++
++ BX_INFO("port 0x%x/32 irq %d mac %02x:%02x:%02x:%02x:%02x:%02x",
++ BX_NE2K_THIS s.base_address,
++ BX_NE2K_THIS s.base_irq,
++ BX_NE2K_THIS s.physaddr[0],
++ BX_NE2K_THIS s.physaddr[1],
++ BX_NE2K_THIS s.physaddr[2],
++ BX_NE2K_THIS s.physaddr[3],
++ BX_NE2K_THIS s.physaddr[4],
++ BX_NE2K_THIS s.physaddr[5]);
++
++ // Initialise the mac address area by doubling the physical address
++ BX_NE2K_THIS s.macaddr[0] = BX_NE2K_THIS s.physaddr[0];
++ BX_NE2K_THIS s.macaddr[1] = BX_NE2K_THIS s.physaddr[0];
++ BX_NE2K_THIS s.macaddr[2] = BX_NE2K_THIS s.physaddr[1];
++ BX_NE2K_THIS s.macaddr[3] = BX_NE2K_THIS s.physaddr[1];
++ BX_NE2K_THIS s.macaddr[4] = BX_NE2K_THIS s.physaddr[2];
++ BX_NE2K_THIS s.macaddr[5] = BX_NE2K_THIS s.physaddr[2];
++ BX_NE2K_THIS s.macaddr[6] = BX_NE2K_THIS s.physaddr[3];
++ BX_NE2K_THIS s.macaddr[7] = BX_NE2K_THIS s.physaddr[3];
++ BX_NE2K_THIS s.macaddr[8] = BX_NE2K_THIS s.physaddr[4];
++ BX_NE2K_THIS s.macaddr[9] = BX_NE2K_THIS s.physaddr[4];
++ BX_NE2K_THIS s.macaddr[10] = BX_NE2K_THIS s.physaddr[5];
++ BX_NE2K_THIS s.macaddr[11] = BX_NE2K_THIS s.physaddr[5];
++
++ // ne2k signature
++ for (Bitu i = 12; i < 32; i++)
++ BX_NE2K_THIS s.macaddr[i] = 0x57;
++
++ // Bring the register state into power-up state
++ reset(BX_RESET_HARDWARE);
++}
++
++static void NE2000_TX_Event(Bitu val) {
++ theNE2kDevice->tx_timer();
++}
++
++static void NE2000_Poller(void) {
++ int res;
++ struct pcap_pkthdr *header;
++ u_char *pkt_data;
++//#if 0
++ while((res = pcap_next_ex( adhandle, &header, (const u_char **)&pkt_data)) > 0) {
++ //LOG_MSG("NE2000: Received %d bytes", header->len);
++
++ // don't receive in loopback modes
++ if((theNE2kDevice->s.DCR.loop == 0) || (theNE2kDevice->s.TCR.loop_cntl != 0))
++ return;
++ theNE2kDevice->rx_frame(pkt_data, header->len);
++ }
++//#endif
++}
++#ifdef WIN32
++#include <windows.h>
++#endif
++
++class NE2K: public Module_base {
++private:
++ // Data
++ IO_ReadHandleObject ReadHandler8[0x20];
++ IO_WriteHandleObject WriteHandler8[0x20];
++ IO_ReadHandleObject ReadHandler16[0x10];
++ IO_WriteHandleObject WriteHandler16[0x10];
++
++public:
++ bool load_success;
++ NE2K(Section* configuration):Module_base(configuration) {
++ Section_prop * section=static_cast<Section_prop *>(configuration);
++
++ load_success = true;
++ // enabled?
++
++ if(!section->Get_bool("ne2000")) {
++ load_success = false;
++ return;
++ }
++
++#ifdef WIN32
++/*
++ int (*PacketSendPacket)(pcap_t *, const u_char *, int);
++ void (*PacketClose)(pcap_t *);
++ void (*PacketFreealldevs)(pcap_if_t *);
++ pcap_t* (*PacketOpen)(char const *,int,int,int,struct pcap_rmtauth *,char *);
++ int (*PacketNextEx)(pcap_t *, struct pcap_pkthdr **, const u_char **);
++ int (*PacketFindALlDevsEx)(char *, struct pcap_rmtauth *, pcap_if_t **, char *);
++*/
++ // init the library
++ HINSTANCE pcapinst;
++ pcapinst = LoadLibrary("WPCAP.DLL");
++ if(pcapinst==NULL) {
++ LOG_MSG("WinPcap has to be installed for the NE2000 to work.");
++ load_success = false;
++ return;
++ }
++ FARPROC psp;
++
++ psp = GetProcAddress(pcapinst,"pcap_sendpacket");
++ if(!PacketSendPacket) PacketSendPacket =
++ (int (__cdecl *)(pcap_t *,const u_char *,int))psp;
++
++ psp = GetProcAddress(pcapinst,"pcap_close");
++ if(!PacketClose) PacketClose =
++ (void (__cdecl *)(pcap_t *)) psp;
++
++ psp = GetProcAddress(pcapinst,"pcap_freealldevs");
++ if(!PacketFreealldevs) PacketFreealldevs =
++ (void (__cdecl *)(pcap_if_t *)) psp;
++
++ psp = GetProcAddress(pcapinst,"pcap_open");
++ if(!PacketOpen) PacketOpen =
++ (pcap_t* (__cdecl *)(char const *,int,int,int,struct pcap_rmtauth *,char *)) psp;
++
++ psp = GetProcAddress(pcapinst,"pcap_next_ex");
++ if(!PacketNextEx) PacketNextEx =
++ (int (__cdecl *)(pcap_t *, struct pcap_pkthdr **, const u_char **)) psp;
++
++ psp = GetProcAddress(pcapinst,"pcap_findalldevs_ex");
++ if(!PacketFindALlDevsEx) PacketFindALlDevsEx =
++ (int (__cdecl *)(char *, struct pcap_rmtauth *, pcap_if_t **, char *)) psp;
++
++ if(PacketFindALlDevsEx==0 || PacketNextEx==0 || PacketOpen==0 ||
++ PacketFreealldevs==0 || PacketClose==0 || PacketSendPacket==0) {
++ LOG_MSG("Wrong WinPcap version or something");
++ load_success = false;
++ return;
++ }
++
++#endif
++
++ // get irq and base
++ Bitu irq = section->Get_int("nicirq");
++ if(!(irq==3 || irq==4 || irq==5 || irq==6 ||irq==7 ||
++ irq==9 || irq==10 || irq==11 || irq==12 ||irq==14 ||irq==15)) {
++ irq=3;
++ }
++ Bitu base = section->Get_hex("nicbase");
++ if(!(base==0x260||base==0x280||base==0x300||base==0x320||base==0x340||base==0x380)) {
++ base=0x300;
++ }
++
++ // mac address
++ const char* macstring=section->Get_string("macaddr");
++ Bitu macint[6];
++ Bit8u mac[6];
++ if(sscanf(macstring,"%02x:%02x:%02x:%02x:%02x:%02x",
++ &macint[0],&macint[1],&macint[2],&macint[3],&macint[4],&macint[5]) != 6) {
++ mac[0]=0xac;mac[1]=0xde;mac[2]=0x48;
++ mac[3]=0x88;mac[4]=0xbb;mac[5]=0xaa;
++ } else {
++ mac[0]=macint[0]; mac[1]=macint[1];
++ mac[2]=macint[2]; mac[3]=macint[3];
++ mac[4]=macint[4]; mac[5]=macint[5];
++ }
++
++ // find out which pcap device to use
++ const char* realnicstring=section->Get_string("realnic");
++ pcap_if_t *alldevs;
++ pcap_if_t *currentdev = NULL;
++ char errbuf[PCAP_ERRBUF_SIZE];
++ Bitu userdev;
++#ifdef WIN32
++ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
++#else
++ if (pcap_findalldevs(&alldevs, errbuf) == -1)
++#endif
++ {
++ LOG_MSG("Cannot enumerate network interfaces: %s\n", errbuf);
++ load_success = false;
++ return;
++ }
++ if (!strcasecmp(realnicstring,"list")) {
++ // print list and quit
++ Bitu i = 0;
++ LOG_MSG("\nNetwork Interface List \n-----------------------------------");
++ for(currentdev=alldevs; currentdev!=NULL; currentdev=currentdev->next) {
++ const char* desc = "no description";
++ if(currentdev->description) desc=currentdev->description;
++ i++;
++ LOG_MSG("%2d. %s\n (%s)\n",i,currentdev->name,desc);
++ }
++ pcap_freealldevs(alldevs);
++ load_success = false;
++ return;
++ } else if(1==sscanf(realnicstring,"%u",&userdev)) {
++ // user passed us a number
++ Bitu i = 0;
++ currentdev=alldevs;
++ while(currentdev!=NULL) {
++ i++;
++ if(i==userdev) break;
++ else currentdev=currentdev->next;
++ }
++ } else {
++ // user might have passed a piece of name
++ for(currentdev=alldevs; currentdev!=NULL; currentdev=currentdev->next) {
++ if(strstr(currentdev->name,realnicstring)) {
++ break;
++ }else if(currentdev->description!=NULL &&
++ strstr(currentdev->description,realnicstring)) {
++ break;
++ }
++ }
++ }
++
++ if(currentdev==NULL) {
++ LOG_MSG("Unable to find network interface - check realnic parameter\n");
++ load_success = false;
++ pcap_freealldevs(alldevs);
++ return;
++ }
++ // print out which interface we are going to use
++ const char* desc = "no description";
++ if(currentdev->description) desc=currentdev->description;
++ LOG_MSG("Using Network interface:\n%s\n(%s)\n",currentdev->name,desc);
++
++ // attempt to open it
++#ifdef WIN32
++ if ( (adhandle= pcap_open(
++ currentdev->name, // name of the device
++ 65536, // portion of the packet to capture
++ // 65536 = whole packet
++ PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
++ -1, // read timeout
++ NULL, // authentication on the remote machine
++ errbuf // error buffer
++ ) ) == NULL)
++#else
++ /*pcap_t *pcap_open_live(const char *device, int snaplen,
++ int promisc, int to_ms, char *errbuf)*/
++ if ( (adhandle= pcap_open_live(
++ currentdev->name, // name of the device
++ 65536, // portion of the packet to capture
++ // 65536 = whole packet
++ true, // promiscuous mode
++ -1, // read timeout
++ errbuf // error buffer
++ ) ) == NULL)
++
++#endif
++ {
++ LOG_MSG("\nUnable to open the interface: %s.", errbuf);
++ pcap_freealldevs(alldevs);
++ load_success = false;
++ return;
++ }
++ pcap_freealldevs(alldevs);
++#ifndef WIN32
++ pcap_setnonblock(adhandle,1,errbuf);
++#endif
++ // create the bochs NIC class
++ theNE2kDevice = new bx_ne2k_c ();
++ memcpy(theNE2kDevice->s.physaddr, mac, 6);
++ theNE2kDevice->init();
++
++ theNE2kDevice->s.base_address=base;
++ theNE2kDevice->s.base_irq=irq;
++
++ // install I/O-handlers and timer
++ for(Bitu i = 0; i < 0x20; i++) {
++ ReadHandler8[i].Install((i+theNE2kDevice->s.base_address),
++ dosbox_read,IO_MB|IO_MW);
++ WriteHandler8[i].Install((i+theNE2kDevice->s.base_address),
++ dosbox_write,IO_MB|IO_MW);
++ }
++ TIMER_AddTickHandler(NE2000_Poller);
++ }
++
++ ~NE2K() {
++ if(adhandle) pcap_close(adhandle);
++ adhandle=0;
++ if(theNE2kDevice != 0) delete theNE2kDevice;
++ theNE2kDevice=0;
++ TIMER_DelTickHandler(NE2000_Poller);
++ PIC_RemoveEvents(NE2000_TX_Event);
++ }
++};
++
++static NE2K* test;
++void NE2K_ShutDown(Section* sec) {
++ if(test) delete test;
++ test=0;
++}
++
++void NE2K_Init(Section* sec) {
++ test = new NE2K(sec);
++ sec->AddDestroyFunction(&NE2K_ShutDown,true);
++ if(!test->load_success) {
++ delete test;
++ test=0;
++ }
++}
++
++#endif // C_NE2000
+diff --unified --recursive --new-file --text dosbox-svn-orig/src/platform/visualc/config.h dosbox-svn-new/src/platform/visualc/config.h
+--- dosbox-svn-orig/src/platform/visualc/config.h 2020-03-22 15:14:51.295001817 +0200
++++ dosbox-svn-new/src/platform/visualc/config.h 2020-03-22 15:20:05.687780067 +0200
+@@ -17,6 +17,9 @@
+ /* Define to 1 to enable internal modem support, requires SDL_net */
+ #define C_MODEM 1
+
++/* Define to 1 to enable NE2000 ethernet passthrough, requires libpcap */
++#define C_NE2000 1
++
+ /* Define to 1 to enable IPX networking support, requires SDL_net */
+ #define C_IPX 1
+
+diff --unified --recursive --new-file --text dosbox-svn-orig/visualc_net/dosbox.vcproj dosbox-svn-new/visualc_net/dosbox.vcproj
+--- dosbox-svn-orig/visualc_net/dosbox.vcproj 2020-03-22 15:14:51.295001817 +0200
++++ dosbox-svn-new/visualc_net/dosbox.vcproj 2020-03-22 15:19:19.815011915 +0200
+@@ -483,6 +483,9 @@
+ <File
+ RelativePath="..\src\hardware\mixer.cpp">
+ </File>
++ <File
++ RelativePath="..\src\hardware\ne2000.cpp">
++ </File>
+ <File
+ RelativePath="..\src\hardware\pci_bus.cpp">
+ </File>
+@@ -871,6 +874,9 @@
+ <File
+ RelativePath="..\include\mouse.h">
+ </File>
++ <File
++ RelativePath="..\include\ne2000.h">
++ </File>
+ <File
+ RelativePath="..\include\paging.h">
+ </File>