[not subscribed, please Cc, thanks.]

6.5 update of the previous patch, w/ additional 'ne2000' flavour.

 'dyncore': re-enable the dynamic core (possibly insecure)
 'ne2000': add third-party ne(4) emulation
 'nosplash': disable spam piccy upon invocation

Tested only in the most limited of fashions (on 6.5), but expected to
work fine. As always, {bug,test} reports are very welcome.

Enjoy!

        --zeurkous.

--- ports/emulators/dosbox/Makefile.orig        Tue Jan 22 04:31:41 2019
+++ ports/emulators/dosbox/Makefile     Fri May 31 19:34:00 2019
@@ -6,6 +6,7 @@
 
 VERSION=       0.74-2
 DISTNAME=      dosbox-${VERSION}
+REVISION=      0
 PKGNAME=       dosbox-${VERSION:S/-/./}
 CATEGORIES=    games x11 emulators
 MASTER_SITES=  ${MASTER_SITE_SOURCEFORGE:=dosbox/}
@@ -37,8 +38,26 @@
 CONFIGURE_ENV+=LDFLAGS="-L${LOCALBASE}/lib -L${X11BASE}/lib"
 CONFIGURE_ARGS+=       --disable-alsatest
 
+PATCH_LIST=    patch-*
+
+FLAVORS=       dyncore ne2000 nosplash
+FLAVOR?=
+
+.if ${FLAVOR:L:Mne2000}
+PATCH_LIST+=   ne2000
+WANT_LIB+=pcap
+.endif
+
+.if ${FLAVOR:L:Mnosplash}
+PATCH_LIST+=   nosplash
+.endif
+
+.if ${FLAVOR:L:Mdyncore}
+PATCH_LIST+=   wxneeded
+.else
 # needs W+X memory
 CONFIGURE_ARGS+=       --disable-dynamic-core
+.endif
 
 pre-configure:
        cp ${FILESDIR}/midi_sndio.h ${WRKSRC}/src/gui

--- /dev/null   Fri May 31 19:56:39 2019
+++ ports/emulators/dosbox/patches/ne2000       Fri May 31 19:45:02 2019
@@ -0,0 +1,2047 @@
+--- visualc_net/dosbox.vcproj.orig     Thu Jul  5 13:24:23 2018
++++ visualc_net/dosbox.vcproj  Fri May 31 18:19:21 2019
+@@ -480,6 +480,9 @@
+                               <File
+                                       
RelativePath="..\src\hardware\mixer.cpp">
+                               </File>
++                              <File
++                                      
RelativePath="..\src\hardware\ne2000.cpp">
++                              </File>
+                               <File
+                                       RelativePath="..\src\hardware\pic.cpp">
+                               </File>
+@@ -827,6 +830,9 @@
+                       </File>
+                       <File
+                               RelativePath="..\include\mouse.h">
++                      </File>
++                      <File
++                              RelativePath="..\include\ne2000.h">
+                       </File>
+                       <File
+                               RelativePath="..\include\paging.h">
+
+--- src/platform/visualc/config.h.orig Mon Aug 27 14:55:55 2018
++++ src/platform/visualc/config.h      Fri May 31 18:19:21 2019
+@@ -12,6 +12,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
+ 
+
+--- src/hardware/ne2000.cpp.orig       Fri May 31 18:19:21 2019
++++ src/hardware/ne2000.cpp    Fri May 31 18:28:13 2019
+@@ -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 (gre...@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 0 
++#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
+
+--- src/hardware/Makefile.am.orig      Mon Aug 27 10:34:03 2018
++++ src/hardware/Makefile.am   Fri May 31 18:19:22 2019
+@@ -10,6 +10,6 @@
+                         memory.cpp mixer.cpp pcspeaker.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
+ 
+ 
+
+--- src/dosbox.cpp.orig        Mon Aug 27 16:41:22 2018
++++ src/dosbox.cpp     Fri May 31 18:19:22 2019
+@@ -43,6 +43,11 @@
+ #include "ints/int10.h"
+ #include "render.h"
+ 
++#ifdef C_NE2000
++//#include "ne2000.h"
++void NE2K_Init(Section* sec);
++#endif
++
+ Config * control;
+ MachineType machine;
+ SVGACards svgaCard;
+@@ -751,6 +756,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 ?
+
+--- include/ne2000.h.orig      Fri May 31 18:19:22 2019
++++ include/ne2000.h   Fri May 31 18:19:22 2019
+@@ -0,0 +1,251 @@
++/////////////////////////////////////////////////////////////////////////
++// $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 (gre...@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
++
++
++};
++
+
+--- configure.ac.orig  Fri May 31 18:19:20 2019
++++ configure.ac       Fri May 31 18:19:22 2019
+@@ -413,6 +413,16 @@
+   AC_MSG_WARN([Can't find libpng, screenshot support disabled])
+ 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_MODEM,[Define to 1 to enable internal modem support, requires 
SDL_net])
+ AH_TEMPLATE(C_IPX,[Define to 1 to enable IPX over Internet networking, 
requires SDL_net])
+ AC_CHECK_HEADER(SDL_net.h,have_sdl_net_h=yes,)

--- /dev/null   Fri May 31 19:56:41 2019
+++ ports/emulators/dosbox/patches/nosplash     Fri May 31 19:33:47 2019
@@ -0,0 +1,44 @@
+--- src/gui/..ar/0/sdlmain.cpp Thu Aug 30 10:52:30 2018
++++ src/gui/sdlmain.cpp        Fri May 31 19:33:29 2019
+@@ -1077,7 +1077,9 @@
+       }
+ }
+ 
++#ifdef TOTAL_WANKER
+ #include "dosbox_splash.h"
++#endif
+ 
+ //extern void UI_Run(bool);
+ static void GUI_StartUp(Section * sec) {
+@@ -1279,6 +1281,7 @@
+     Bit32u bmask = 0x00ff0000;
+ //#endif
+ 
++#ifdef TOTAL_WANKER
+ /* Please leave the Splash screen stuff in working order in DOSBox. We spend 
a lot of time making DOSBox. */
+       SDL_Surface* splash_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 
400, 32, rmask, gmask, bmask, 0);
+       if (splash_surf) {
+@@ -1339,6 +1342,7 @@
+               delete [] tmpbufp;
+ 
+       }
++#endif
+ 
+       /* Get some Event handlers */
+       MAPPER_AddHandler(KillSwitch,MK_f9,MMOD1,"shutdown","ShutDown");
+@@ -1687,6 +1691,7 @@
+       Bit32u gmask = 0x0000ff00;                    
+       Bit32u bmask = 0x00ff0000;
+ #endif
++#ifdef TOTAL_WANKER
+       SDL_Surface* splash_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 
400, 32, rmask, gmask, bmask, 0);
+       if (!splash_surf) return;
+ 
+@@ -1707,6 +1712,7 @@
+       SDL_BlitSurface(splash_surf, NULL, sdl.surface, NULL);
+       SDL_Flip(sdl.surface);
+       SDL_Delay(12000);
++#endif
+ }
+    
+ static void launcheditor() {

--- /dev/null   Fri May 31 19:56:41 2019
+++ ports/emulators/dosbox/patches/wxneeded     Fri May 31 19:13:07 2019
@@ -0,0 +1,10 @@
+--- src/..ar/0/Makefile.am     Fri May 31 19:12:02 2019
++++ src/Makefile.am    Fri May 31 19:12:31 2019
+@@ -15,6 +15,7 @@
+ dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a  
hardware/libhardware.a gui/libgui.a \
+                ints/libints.a misc/libmisc.a shell/libshell.a 
hardware/mame/libmame.a \
+                hardware/serialport/libserial.a libs/gui_tk/libgui_tk.a
++dosbox_LDFLAGS = -z notext -z wxneeded
+ 
+ EXTRA_DIST = winres.rc dosbox.ico
+

-- 
Friggin' Machines!

Reply via email to