diff options
author | Emmanouil Theofanis Chourdakis | 2020-03-22 18:15:02 +0200 |
---|---|---|
committer | Emmanouil Theofanis Chourdakis | 2020-03-22 18:15:02 +0200 |
commit | bb8496b5a0475712835ec396ea9d4a4a7cba3861 (patch) | |
tree | 4fd3499142842bf90e6539af908c214cccad51f4 | |
download | aur-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-- | .SRCINFO | 36 | ||||
-rw-r--r-- | PKGBUILD | 67 | ||||
-rw-r--r-- | dosbox-128.png | bin | 0 -> 35632 bytes | |||
-rw-r--r-- | dosbox-16.png | bin | 0 -> 1018 bytes | |||
-rw-r--r-- | dosbox-48.png | bin | 0 -> 5537 bytes | |||
-rw-r--r-- | dosbox-svn-ne2000.desktop | 10 | ||||
-rw-r--r-- | ne2000.patch | 2061 |
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 Binary files differnew file mode 100644 index 000000000000..5beb624002be --- /dev/null +++ b/dosbox-128.png diff --git a/dosbox-16.png b/dosbox-16.png Binary files differnew file mode 100644 index 000000000000..2f27d70c85a3 --- /dev/null +++ b/dosbox-16.png diff --git a/dosbox-48.png b/dosbox-48.png Binary files differnew file mode 100644 index 000000000000..3b8e06a54126 --- /dev/null +++ b/dosbox-48.png 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> |