diff --git a/SEL32/sel32_chan.c b/SEL32/sel32_chan.c
index 7fcdc1c..c5fceda 100644
--- a/SEL32/sel32_chan.c
+++ b/SEL32/sel32_chan.c
@@ -600,7 +600,6 @@ loop:
chp->chan_caw, chan, chp->chan_status, chp->ccw_count);
/* see if bad status */
-// if (chp->chan_status & (STATUS_ATTN|STATUS_CHECK|STATUS_EXPT)) {
if (chp->chan_status & (STATUS_ATTN|STATUS_ERROR)) {
chp->chan_status |= STATUS_CEND; /* channel end status */
chp->ccw_flags = 0; /* no flags */
@@ -1070,7 +1069,6 @@ nothere:
sim_debug(DEBUG_EXP, &cpu_dev,
"checkxio chsa %04x flags UNIT_ATTABLE %1x UNIT_ATT %1x\n",
chsa, (uptr->flags & UNIT_ATTABLE)?1:0, (uptr->flags & UNIT_ATT)?1:0);
-#ifndef TEST_ETHERNET
/* check for the device being defined and attached in simh */
if ((uptr->flags & UNIT_ATTABLE) && ((uptr->flags & UNIT_ATT) == 0)) {
sim_debug(DEBUG_EXP, &cpu_dev,
@@ -1078,7 +1076,6 @@ nothere:
*status = CC3BIT; /* not attached, so error CC3 */
return SCPE_OK; /* not found, CC3 */
}
-#endif
inta = find_int_lev(chsa&0x7f00); /* Interrupt Level for channel */
chan_icb = find_int_icb(chsa&0x7f00); /* Interrupt level context block address */
@@ -1151,7 +1148,8 @@ t_stat startxio(uint16 chsa, uint32 *status) {
}
uptr = chp->unitptr; /* get the unit ptr */
- if ((uptr->flags & UNIT_ATTABLE) && ((uptr->flags & UNIT_ATT) == 0)) { /* is unit attached? */
+ if ((uptr->flags & UNIT_ATTABLE) && ((uptr->flags & UNIT_ATT) == 0) &&
+ (uptr->flags & UNIT_SUBCHAN) == 0) { /* is unit attached? */
sim_debug(DEBUG_EXP, &cpu_dev,
"startxio chsa %04x device not present, CC3 returned flags %08x\n", chsa, uptr->flags);
*status = CC3BIT; /* not attached, so error CC3 */
@@ -2086,7 +2084,7 @@ t_stat chan_set_devs() {
chp->ccw_cmd = 0; /* read command */
chp->chan_inch_addr = 0; /* clear address of stat dw in memory */
- if ((uptr->flags & UNIT_DIS) == 0) { /* is unit marked disabled? */
+ if ((uptr->flags & UNIT_DIS) == 0 || (uptr->flags & UNIT_SUBCHAN) != 0) { /* is unit marked disabled? */
/* see if this is unit zero */
if ((chsa & 0xff) == 0) {
/* we have channel mux or dev 0 of units */
@@ -2173,13 +2171,11 @@ t_stat set_dev_addr(UNIT *uptr, int32 val, CONST char *cptr, void *desc) {
return SCPE_IERR; /* no, arg error */
dptr = get_dev(uptr); /* find the device from unit pointer */
if (dptr == NULL) { /* device not found, so error */
- fprintf(stderr, "Set dev no DEVICE ptr %s\r\n", cptr);
return SCPE_IERR; /* error */
}
dibp = (DIB *)dptr->ctxt; /* get dib pointer from device struct */
if (dibp == NULL) { /* we need a DIB */
- fprintf(stderr, "Set dev no DIB ptr %s\r\n", GET_UADDR(tuptr->u3), chsa);
return SCPE_IERR; /* no DIB, so error */
}
diff --git a/SEL32/sel32_defs.h b/SEL32/sel32_defs.h
index 8b80592..688e0cc 100644
--- a/SEL32/sel32_defs.h
+++ b/SEL32/sel32_defs.h
@@ -128,6 +128,8 @@
#define NUM_UNITS_RTOM 1 /* 1 IOP RTOM device (clock & interval timer) */
#define NUM_DEVS_LPR 1 /* 1 IOP Line printer */
#define NUM_UNITS_LPR 1 /* 1 IOP Line printer device */
+#define NUM_DEVS_ETHER 1 /* 1 Ethernet controller */
+#define NUM_UNITS_ETHER 1 /* 1 Ethernet controller */
extern DEVICE cpu_dev; /* cpu device */
extern UNIT cpu_unit; /* the cpu unit */
@@ -181,6 +183,9 @@ extern DEVICE com_dev;
#ifdef NUM_DEVS_LPR
extern DEVICE lpr_dev;
#endif
+#ifdef NUM_DEVS_ETHER
+extern DEVICE ec_dev;
+#endif
/* Memory */
@@ -249,6 +254,7 @@ extern DIB *dib_chan[MAX_CHAN]; /* Pointer to channel mux dib */
#endif
/* allow 255 type disks */
+#define UNIT_SUBCHAN (1 << (UNIT_V_UF_31))
#define UNIT_V_TYPE (UNIT_V_UF + 0)
#define UNIT_TYPE (0xff << UNIT_V_TYPE)
/* get & set disk types */
diff --git a/SEL32/sel32_ec.c b/SEL32/sel32_ec.c
new file mode 100644
index 0000000..4c6c643
--- /dev/null
+++ b/SEL32/sel32_ec.c
@@ -0,0 +1,968 @@
+/* sel32_ec.c: SEL-32 8516 Ethernet controller.
+
+ Copyright (c) 2020, Richard Cornwell
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ RICHARD CORNWELL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "sel32_defs.h"
+
+#if NUM_DEVS_ETHER > 0
+#include "sim_ether.h"
+
+/* allow 3 modes */
+#define UNIT_V_MODE (UNIT_V_UF + 1)
+#define UNIT_MODE (0x3 << UNIT_V_MODE)
+/* get & set disk types */
+#define GET_MODE(x) ((UNIT_MODE & (x)) >> UNIT_V_MODE)
+#define SET_MODE(x) (UNIT_MODE & ((x) << UNIT_V_MODE))
+
+
+#define CMD u3
+/* u3 */
+/* in u3 is device command code and status */
+#define EC_CMDMSK 0x0ff /* Command being run */
+/* commands */
+#define EC_INCH 0x00 /* Initialize channel */
+#define EC_WRITE 0x01 /* Write frame */
+#define EC_READ 0x02 /* Read frame*/
+#define EC_NOP 0x03 /* No operation */
+#define EC_SNS 0x04 /* Sense */
+#define EC_LIA 0x07 /* Load individual address */
+#define EC_TIC 0x08 /* Transfer in channel */
+#define EC_CGA 0x0B /* Disable multicast address */
+#define EC_LGA 0x0F /* Load Multicast address */
+#define EC_LCC 0x10 /* Configure LCC */
+#define EC_STATS 0x14 /* Read Statistics */
+#define EC_CSTATS 0x15 /* Clear software counters */
+#define EC_BUSY 0x100 /* Mark Device as Busy */
+
+#define SNS u5
+/* u5 */
+/* Sense byte 0 */
+#define SNS_CMDREJ 0x80000000 /* Command reject */
+#define SNS_SPARE0 0x40000000 /* Spare */
+#define SNS_SPARE1 0x20000000 /* Spare */
+#define SNS_EQUCHK 0x10000000 /* Equipment check */
+#define SNS_SPARE2 0x08000000 /* Spare */
+#define SNS_SPARE3 0x04000000 /* Spare */
+#define SNS_MODE_M 0x03000000 /* Mode Mask */
+
+/* Sense byte 1 */
+#define SNS_RCV_RDY 0x00800000 /* Receive unit ready */
+#define SNS_TMT_DEF 0x00400000 /* Transmission deferred */
+#define SNS_COL_RTY 0x00300000 /* Collision retry */
+#define SNS_HRT_TST 0x00080000 /* Heartbeat test failure */
+#define SNS_DMA_UND 0x00040000 /* DMA under run */
+#define SNS_LST_CTS 0x00020000 /* Lost Clear to send */
+#define SNS_NO_CAR 0x00010000 /* No carrier. */
+
+/* Sense byte 2 & 3 */
+#define SNS_XFR_MASK 0x0000FFFF /* Previous frame count */
+
+typedef uint32 in_addr_T;
+
+#define ETHTYPE_ARP 0x0806
+#define ETHTYPE_IP 0x0800
+
+#define STAT_FR_ALIGN 0 /* Frame alignment errors */
+#define STAT_FR_CRC 1 /* Frame CRC errors */
+#define STAT_LCL_AVAIL 2 /* Local bus available errors */
+#define STAT_LCL_OVER 3 /* Local bus overflow */
+#define STAT_TX_COLL 4 /* Transmission collisions */
+#define STAT_RX_LEN 5 /* Receive length errors */
+#define STAT_TX_SUCC 6 /* Transmitt success after 2-15 collisions */
+#define STAT_TX_DEF 7 /* Transmitt deferred */
+#define STAT_TX_UNSUCC 8 /* Transmitt unsuccessful */
+#define STAT_TX_SUCC1 9 /* Transmitt success after 1 collision */
+#define STAT_LEN 10 /* Number of half word stats */
+
+PACKED_BEGIN
+struct ec_eth_hdr {
+ ETH_MAC dest;
+ ETH_MAC src;
+ uint16 type;
+} PACKED_END;
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+PACKED_BEGIN
+struct ip {
+ uint8 ip_v_hl; /* version,header length */
+ uint8 ip_tos; /* type of service */
+ uint16 ip_len; /* total length */
+ uint16 ip_id; /* identification */
+ uint16 ip_off; /* fragment offset field */
+#define IP_DF 0x4000 /* don't fragment flag */
+#define IP_MF 0x2000 /* more fragments flag */
+#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
+ uint8 ip_ttl; /* time to live */
+ uint8 ip_p; /* protocol */
+ uint16 ip_sum; /* checksum */
+ in_addr_T ip_src;
+ in_addr_T ip_dst; /* source and dest address */
+} PACKED_END;
+
+#define TCP_PROTO 6
+PACKED_BEGIN
+struct tcp {
+ uint16 tcp_sport; /* Source port */
+ uint16 tcp_dport; /* Destination port */
+ uint32 seq; /* Sequence number */
+ uint32 ack; /* Ack number */
+ uint16 flags; /* Flags */
+#define TCP_FL_FIN 0x01
+#define TCP_FL_SYN 0x02
+#define TCP_FL_RST 0x04
+#define TCP_FL_PSH 0x08
+#define TCP_FL_ACK 0x10
+#define TCP_FL_URG 0x20
+ uint16 window; /* Window size */
+ uint16 chksum; /* packet checksum */
+ uint16 urgent; /* Urgent pointer */
+} PACKED_END;
+
+#define UDP_PROTO 17
+PACKED_BEGIN
+struct udp {
+ uint16 udp_sport; /* Source port */
+ uint16 udp_dport; /* Destination port */
+ uint16 len; /* Length */
+ uint16 chksum; /* packet checksum */
+} PACKED_END;
+
+PACKED_BEGIN
+struct udp_hdr {
+ in_addr_T ip_src;
+ in_addr_T ip_dst; /* source and dest address */
+ uint8 zero;
+ uint8 proto; /* Protocol */
+ uint16 hlen; /* Length of header and data */
+} PACKED_END;
+
+#define ICMP_PROTO 1
+PACKED_BEGIN
+struct icmp {
+ uint8 type; /* Type of packet */
+ uint8 code; /* Code */
+ uint16 chksum; /* packet checksum */
+} PACKED_END;
+
+PACKED_BEGIN
+struct ip_hdr {
+ struct ec_eth_hdr ethhdr;
+ struct ip iphdr;
+} PACKED_END;
+
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+#define ARP_HWTYPE_ETH 1
+
+PACKED_BEGIN
+struct arp_hdr {
+ struct ec_eth_hdr ethhdr;
+ uint16 hwtype;
+ int16 protocol;
+ uint8 hwlen;
+ uint8 protolen;
+ uint16 opcode;
+ ETH_MAC shwaddr;
+ in_addr_T sipaddr;
+ ETH_MAC dhwaddr;
+ in_addr_T dipaddr;
+ uint8 padding[18];
+} PACKED_END;
+
+struct ec_device {
+ ETH_PCALLBACK rcallback; /* read callback routine */
+ ETH_PCALLBACK wcallback; /* write callback routine */
+ ETH_MAC mac; /* Hardware MAC addresses */
+ ETH_DEV etherface;
+ ETH_QUE ReadQ;
+ ETH_PACK rec_buff; /* Buffer for recieved packet */
+ ETH_PACK snd_buff; /* Buffer for sending packet */
+ int macs_n; /* Number of multi-cast addresses */
+ ETH_MAC macs[67]; /* Watched Multi-cast addresses */
+ int amc; /* Recieve all multicast packets */
+ uint32 rx_count; /* Packets received */
+ uint32 tx_count; /* Packets sent */
+ int r_pkt; /* Packet pending */
+ int poll; /* Need to poll receiver */
+} ec_data;
+
+
+extern int32 tmxr_poll;
+
+static CONST ETH_MAC broadcast_ethaddr = {0xff,0xff,0xff,0xff,0xff,0xff};
+
+/* channel program information */
+CHANP ec_chp[8] = {0};
+
+uint16 ec_startcmd(UNIT *uptr, uint16 chan, uint8 cmd) ;
+t_stat ec_srv(UNIT *uptr);
+void ec_packet_debug(struct ec_device *ec, const char *action, ETH_PACK *packet);
+t_stat ec_reset (DEVICE *dptr);
+void ec_ini(UNIT *, t_bool);
+t_stat ec_show_mac (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
+t_stat ec_set_mac (UNIT* uptr, int32 val, CONST char* cptr, void* desc);
+t_stat ec_show_mode (FILE* st, UNIT* uptr, int32 val, CONST void* desc);
+t_stat ec_set_mode (UNIT* uptr, int32 val, CONST char* cptr, void* desc);
+t_stat ec_attach (UNIT * uptr, CONST char * cptr);
+t_stat ec_detach (UNIT * uptr);
+t_stat ec_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, CONST char *cptr);
+const char *ec_description (DEVICE *dptr);
+
+#define ec_master_uptr (&ec_unit[0]) /* Unit doing receive digestion */
+
+UNIT ec_unit[] = {
+ {UDATA(ec_srv, UNIT_IDLE|UNIT_ATTABLE, 0), 0, UNIT_ADDR(0xE00)}, /* 0 */
+ {UDATA(ec_srv, UNIT_IDLE|UNIT_DIS|UNIT_SUBCHAN, 0), 0, UNIT_ADDR(0xE01)}, /* 1 */
+ {UDATA(ec_srv, UNIT_IDLE|UNIT_DIS|UNIT_SUBCHAN, 0), 0, UNIT_ADDR(0xE02)}, /* 2 */
+ {UDATA(ec_srv, UNIT_IDLE|UNIT_DIS|UNIT_SUBCHAN, 0), 0, UNIT_ADDR(0xE03)}, /* 3 */
+ {UDATA(ec_srv, UNIT_IDLE|UNIT_DIS|UNIT_SUBCHAN, 0), 0, UNIT_ADDR(0xE04)}, /* 4 */
+ {UDATA(ec_srv, UNIT_IDLE|UNIT_DIS|UNIT_SUBCHAN, 0), 0, UNIT_ADDR(0xE05)}, /* 5 */
+ {UDATA(ec_srv, UNIT_IDLE|UNIT_DIS|UNIT_SUBCHAN, 0), 0, UNIT_ADDR(0xE06)}, /* 6 */
+ {UDATA(ec_srv, UNIT_IDLE|UNIT_DIS|UNIT_SUBCHAN, 0), 0, UNIT_ADDR(0xE07)}, /* 7 */
+};
+
+
+
+DIB ec_dib = {
+ NULL, /* Pre start I/O */
+ ec_startcmd, /* Start a command */
+ NULL, /* Stop I/O */
+ NULL, /* Test I/O */
+ NULL, /* Post I/O */
+ ec_ini, /* init function */
+ ec_unit, /* Pointer to units structure */
+ ec_chp, /* Pointer to chan_prg structure */
+ 8, /* number of units defined */
+ 0x0F, /* device mask */
+ 0x0E00, /* parent channel address */
+ 0, /* fifo input index */
+ 0, /* fifo output index */
+ {0}, /* interrupt status fifo for channel */
+};
+
+
+MTAB ec_mod[] = {
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, "MODE", "MODE=#",
+ &ec_set_mode, &ec_show_mode, NULL, "Ethernet mode" },
+ { MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx",
+ &ec_set_mac, &ec_show_mac, NULL, "MAC address" },
+ { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "ETH", NULL, NULL,
+ ð_show, NULL, "Display attachedable devices" },
+ {MTAB_XTD | MTAB_VUN | MTAB_VALR, 0, "DEV", "DEV",
+ &set_dev_addr, &show_dev_addr, NULL, "Device channel address"},
+ { 0 }
+ };
+
+/* Simulator debug controls */
+DEBTAB ec_debug[] = {
+ {"CMD", DEBUG_CMD, "Show command execution to devices"},
+ {"DATA", DEBUG_DATA, "Show data transfers"},
+ {"DETAIL", DEBUG_DETAIL, "Show details about device"},
+ {"EXP", DEBUG_EXP, "Show exception information"},
+ {"IRQ", DEBUG_IRQ, "Show IRQ requests"},
+#define DEBUG_ARP (DEBUG_IRQ<<1)
+ {"ARP", DEBUG_ARP, "Show ARP activities"},
+#define DEBUG_TCP (DEBUG_ARP<<1)
+ {"TCP", DEBUG_TCP, "Show TCP packet activities"},
+#define DEBUG_UDP (DEBUG_TCP<<1)
+ {"UDP", DEBUG_UDP, "Show UDP packet activities"},
+#define DEBUG_ICMP (DEBUG_UDP<<1)
+ {"ICMP", DEBUG_ICMP, "Show ICMP packet activities"},
+#define DEBUG_ETHER (DEBUG_ICMP<<1)
+ {"ETHER", DEBUG_ETHER, "Show ETHER activities"},
+ {0, 0}
+};
+
+DEVICE ec_dev = {
+ "EC", ec_unit, NULL, ec_mod,
+ 8, 16, 24, 4, 16, 32,
+ NULL, NULL, &ec_reset, NULL, &ec_attach, &ec_detach,
+ &ec_dib, DEV_DISABLE | DEV_DEBUG | DEV_ETHER, 0, ec_debug,
+ NULL, NULL, &ec_help, NULL, NULL, &ec_description
+};
+
+
+/* Start ethernet command */
+uint16 ec_startcmd(UNIT *uptr, uint16 chan, uint8 cmd)
+{
+ DEVICE *dptr = get_dev(uptr);
+ uint16 chsa = GET_UADDR(uptr->CMD);
+ CHANP *chp = find_chanp_ptr(chsa); /* find the chanp pointer */
+
+ sim_debug(DEBUG_CMD, dptr,
+ "ec_startcmd chsa %04x unit %d cmd %02x CMD %08x\n",
+ chsa, (int)(uptr - ec_unit), cmd, uptr->CMD);
+ if ((uptr->CMD & 0xff) != 0) { /* if any status info, we are busy */
+ sim_debug(DEBUG_CMD, dptr, "ec_startcmd busy\n");
+ return SNS_BSY;
+ }
+
+ /* Unit is online, so process a command */
+ switch (cmd) {
+ case EC_WRITE: /* Write command 0x01 */
+ case EC_READ: /* Read command 0x02 */
+ case EC_TIC: /* Transfer in channel */
+ case EC_CGA: /* Disable multicast address */
+ case EC_LCC: /* Configure LCC */
+ case EC_STATS: /* Read Statistics */
+ case EC_CSTATS: /* Clear software counters */
+ case EC_NOP: /* NOP 0x03 */
+ case EC_INCH: /* INCH cmd 0x0 */
+ case EC_LIA: /* Load individual address */
+ case EC_LGA: /* Load Multicast address */
+ uptr->SNS &= 0xff0000;
+ /* Fall through */
+ case EC_SNS: /* Sense 0x04 */
+ uptr->CMD |= cmd|EC_BUSY; /* save cmd */
+ sim_activate(uptr, 300); /* start things off */
+ return 0;
+ }
+
+ uptr->SNS |= SNS_CMDREJ;
+ sim_debug(DEBUG_CMD, dptr, "ec_startcmd illegal with ec_startcmd %02x SNS %08x\n",
+ cmd, uptr->SNS);
+ return SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK;
+}
+
+/* Handle processing of disk requests. */
+t_stat ec_srv(UNIT *uptr)
+{
+ uint16 chsa = GET_UADDR(uptr->CMD);
+ DEVICE *dptr = get_dev(uptr);
+ DIB *dibp = (DIB *)dptr->ctxt; /* get DIB address */
+ CHANP *chp = (CHANP *)dibp->chan_prg; /* get pointer to channel program */
+ int cmd = uptr->CMD & EC_CMDMSK;
+ uint32 mema;
+ int i;
+ int n;
+ uint8 ch;
+ uint8 buf[256];
+ uint8 *pck;
+ struct ec_eth_hdr *hdr;
+
+ sim_debug(DEBUG_CMD, dptr,
+ "ec_srv cmd=%02x chsa %04x count %04x\n", cmd, chsa, chp->ccw_count);
+
+ switch (cmd) {
+ case EC_INCH: /* INCH cmd 0x0 */
+ sim_debug(DEBUG_CMD, dptr,
+ "ec_srv starting INCH %06x cmd, chsa %04x MemBuf %06x cnt %04x\n",
+ uptr->u4, chsa, chp->ccw_addr, chp->ccw_count);
+ mema = chp->ccw_addr; /* get inch or buffer addr */
+
+ uptr->CMD &= LMASK; /* remove old status bits & */
+
+ /* now call set_inch() function to write and test inch buffer addresses */
+ i = set_inch(uptr, mema); /* new address */
+ if ((i == SCPE_MEM) || (i == SCPE_ARG)) { /* any error */
+ /* we have error, bail out */
+ uptr->SNS |= SNS_CMDREJ|SNS_EQUCHK;
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
+ break;
+ }
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+ case EC_LIA: /* Load individual address */
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ for(i = 0; i < sizeof (ETH_MAC); i++) {
+ if (chan_read_byte(chsa, &buf[i])) {
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
+ return SCPE_OK;
+
+ }
+ }
+ memcpy(&ec_data.mac, &buf[0], sizeof (ETH_MAC));
+ eth_mac_fmt(&ec_data.mac, (char *)&buf[0]);
+ sim_debug(DEBUG_CMD, dptr, "ec_srv setting mac %s\n", buf);
+ n = ec_data.macs_n + 2;
+ memcpy(&ec_data.macs[0], &ec_data.mac, sizeof (ETH_MAC));
+ memcpy(&ec_data.macs[1], &broadcast_ethaddr, sizeof (ETH_MAC));
+ if (ec_master_uptr->flags & UNIT_ATT)
+ eth_filter (&ec_data.etherface, n, ec_data.macs, ec_data.amc, 0);
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+ case EC_CGA: /* Disable multicast address */
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ ec_data.macs_n = 0;
+ if (ec_master_uptr->flags & UNIT_ATT)
+ eth_filter (&ec_data.etherface, 1, ec_data.macs, ec_data.amc, 0);
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+ case EC_LGA: /* Load Multicast address */
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ ec_data.macs_n = 0;
+ for(n = 2; n < (int)(sizeof(ec_data.macs_n) / sizeof (ETH_MAC)); n++) {
+ for(i = 0; i < sizeof (ETH_MAC); i++) {
+ if (chan_read_byte(chsa, &buf[i])) {
+ break;
+ }
+ }
+ if (i != sizeof (ETH_MAC))
+ break;
+ memcpy(&ec_data.macs[n], &buf[0], sizeof (ETH_MAC));
+ }
+ ec_data.macs_n = n - 2;
+
+ for(i = 0; i< n; i++) {
+ eth_mac_fmt(&ec_data.macs[i], (char *)&buf[0]);
+ sim_debug(DEBUG_DETAIL, &ec_dev, "ec_srv load mcast%d: %s\n\r",i,buf);
+ }
+
+ if (ec_master_uptr->flags & UNIT_ATT)
+ eth_filter (&ec_data.etherface, n, ec_data.macs, ec_data.amc, 0);
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+ case EC_WRITE: /* Write command 0x01 */
+ ec_data.tx_count++;
+ hdr = (struct ec_eth_hdr *)(&ec_data.snd_buff.msg[0]);
+ pck = (uint8 *)(&ec_data.snd_buff.msg[0]);
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ switch (GET_MODE(ec_master_uptr->flags)) {
+ case 0:
+ for(i = 0; i < sizeof (struct ec_eth_hdr); i++) {
+ if (chan_read_byte(chsa, &pck[i])) {
+ goto runt;
+ }
+ }
+ break;
+ case 1:
+ case 2:
+ for(i = 0; i < sizeof (ETH_MAC); i++) {
+ if (chan_read_byte(chsa, &pck[i])) {
+ goto runt;
+ }
+ }
+ memcpy(&hdr->src, ec_data.mac, sizeof (ETH_MAC));
+ for(i += 6; i < sizeof(struct ec_eth_hdr); i++) {
+ if (chan_read_byte(chsa, &pck[i])) {
+ goto runt;
+ }
+ }
+ break;
+ case 3:
+ for(i = 0; i < sizeof (ETH_MAC); i++) {
+ if (chan_read_byte(chsa, &pck[i])) {
+ goto runt;
+ }
+ }
+ memcpy(&hdr->src, ec_data.mac, sizeof (ETH_MAC));
+ hdr->type = htons(ETHTYPE_IP);
+ break;
+ }
+ pck = (uint8 *)(&ec_data.snd_buff.msg[sizeof(struct ec_eth_hdr)]);
+ for(i = 0; i < (ETH_FRAME_SIZE - sizeof(struct ec_eth_hdr)); i++) {
+ if (chan_read_byte(chsa, &pck[i])) {
+ break;
+ }
+ }
+ ec_data.snd_buff.len = i + sizeof(struct ec_eth_hdr);
+ ec_packet_debug(&ec_data, "send", &ec_data.snd_buff);
+ if (eth_write(&ec_data.etherface, &ec_data.snd_buff, NULL) != SCPE_OK) {
+runt:
+ sim_debug(DEBUG_DETAIL, &ec_dev, "ec_srv short packet %d\n\r",i);
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITEXP);
+ break;
+ }
+ sim_debug(DEBUG_DETAIL, &ec_dev, "ec_srv sent packet %d bytes\n\r",i);
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+ case EC_READ: /* Read command 0x02 */
+ ec_master_uptr->SNS |= SNS_RCV_RDY;
+ if (eth_read(&ec_data.etherface, &ec_data.rec_buff, NULL) <= 0) {
+ sim_clock_coschedule(uptr, 1000); /* continue poll */
+ return SCPE_OK;
+ }
+ ec_packet_debug(&ec_data, "recv", &ec_data.rec_buff);
+ ec_data.rx_count++;
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ hdr = (struct ec_eth_hdr *)(&ec_data.rec_buff.msg[0]);
+ pck = (uint8 *)(&ec_data.rec_buff.msg[0]);
+ switch (GET_MODE(ec_master_uptr->flags)) {
+ case 0:
+ for(i = 0; i < sizeof (struct ec_eth_hdr); i++) {
+ if (chan_write_byte(chsa, &pck[i])) {
+ goto runt;
+ }
+ }
+ break;
+ case 1:
+ case 2:
+ case 3:
+ for(i = 0; i < sizeof (ETH_MAC); i++) {
+ if (chan_write_byte(chsa, &pck[i])) {
+ goto runt;
+ }
+ }
+ ch = (ec_data.rec_buff.len >> 8) & 0xff;
+ if (chan_write_byte(chsa, &ch)) {
+ goto runt;
+ }
+ ch = ec_data.rec_buff.len & 0xff;
+ if (chan_write_byte(chsa, &ch)) {
+ goto runt;
+ }
+ for(; i < sizeof(struct ec_eth_hdr); i++) {
+ if (chan_write_byte(chsa, &pck[i])) {
+ goto runt;
+ }
+ }
+ break;
+ }
+ pck = (uint8 *)(&ec_data.rec_buff.msg[sizeof(struct ec_eth_hdr)]);
+ for(i = 0; i < (int)(ec_data.rec_buff.len - sizeof(struct ec_eth_hdr)); i++) {
+ if (chan_write_byte(chsa, &pck[i])) {
+ break;
+ }
+ }
+ sim_debug(DEBUG_DETAIL, &ec_dev, "ec_srv received bytes %d\n\r",i);
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+ case EC_LCC: /* Configure LCC */
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ /* Read up to 12 bytes */
+ for (i = 0; i < 12; i++) {
+ if (chan_read_byte(chsa, &ch)) {
+ break;
+ }
+ }
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+ case EC_STATS: /* Read Statistics */
+ ch = 0;
+ /* First 5 words are always zero since these errors are not supported */
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ for (i = 0; i < STAT_LEN * 2; i++) {
+ if (chan_write_byte(chsa, &ch)) {
+ break;
+ }
+ }
+ sim_debug(DEBUG_DETAIL, dptr, "ec_srv stats rx_count %08x\n", ec_data.rx_count);
+ ch = (ec_data.rx_count >> 24) & 0xff;
+ chan_write_byte(chsa, &ch);
+ ch = (ec_data.rx_count >> 16) & 0xff;
+ chan_write_byte(chsa, &ch);
+ ch = (ec_data.rx_count >> 8) & 0xff;
+ chan_write_byte(chsa, &ch);
+ ch = ec_data.rx_count & 0xff;
+ chan_write_byte(chsa, &ch);
+ sim_debug(DEBUG_DETAIL, dptr, "ec_srv stats tx_count %08x\n", ec_data.tx_count);
+ ch = (ec_data.tx_count >> 24) & 0xff;
+ chan_write_byte(chsa, &ch);
+ ch = (ec_data.tx_count >> 16) & 0xff;
+ chan_write_byte(chsa, &ch);
+ ch = (ec_data.tx_count >> 8) & 0xff;
+ chan_write_byte(chsa, &ch);
+ ch = ec_data.tx_count & 0xff;
+ chan_write_byte(chsa, &ch);
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+ case EC_CSTATS: /* Clear software counters */
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ ec_data.rx_count = ec_data.tx_count = 0;
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+ case EC_NOP: /* NOP 0x03 */
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ sim_debug(DEBUG_CMD, dptr,
+ "ec_srv cmd NOP chsa %04x count %04x completed\n",
+ chsa, chp->ccw_count);
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND); /* return OK */
+ break;
+
+ case EC_SNS: /* 0x4 */
+ sim_debug(DEBUG_CMD, dptr, "ec_startcmd CMD sense\n");
+
+ ch = (uptr->SNS >> 24) & 0xfc;
+ ch |= GET_MODE(ec_master_uptr->flags);
+ sim_debug(DEBUG_DETAIL, dptr, "ec_srv sense CHS b0 1 %02x\n", ch);
+ chan_write_byte(chsa, &ch);
+ ch = (ec_master_uptr->SNS >> 16) & 0xff;
+ sim_debug(DEBUG_DETAIL, dptr, "ec_srv sense CHS b1 2 %02x\n", ch);
+ chan_write_byte(chsa, &ch);
+ ch = (ec_data.rec_buff.len >> 8) & 0xff;
+ sim_debug(DEBUG_DETAIL, dptr, "ec_srv sense CHS b2 3 %02x\n", ch);
+ chan_write_byte(chsa, &ch);
+ ch = ec_data.rec_buff.len & 0xff;
+ sim_debug(DEBUG_DETAIL, dptr, "ec_srv sense CHS b3 4 %02x\n", ch);
+ chan_write_byte(chsa, &ch);
+
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND);
+ break;
+
+
+ default:
+ sim_debug(DEBUG_CMD, dptr, "invalid command %02x\n", cmd);
+ uptr->SNS |= SNS_CMDREJ;
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ chan_end(chsa, SNS_CHNEND|SNS_DEVEND|SNS_UNITCHK);
+ }
+ sim_debug(DEBUG_DETAIL, dptr,
+ "ec_srv done cmd=%02x chsa %04x count %04x\n", cmd, chsa, chp->ccw_count);
+ return SCPE_OK;
+}
+
+/* initialize the disk */
+void ec_ini(UNIT *uptr, t_bool f)
+{
+ DEVICE *dptr = get_dev(uptr);
+
+ /* start out at sector 0 */
+ uptr->CMD &= LMASK; /* remove old status bits & cmd */
+ uptr->SNS = 0; /* save mode value */
+
+ sim_debug(DEBUG_EXP, &dda_dev, "EC init device %s on unit EC%.1x cap %x %d\n",
+ dptr->name, GET_UADDR(uptr->CMD), uptr->capac, uptr->capac);
+}
+
+static char *
+ipv4_inet_ntoa(struct in_addr ip)
+{
+ static char str[20];
+
+ if (sim_end)
+ sprintf (str, "%d.%d.%d.%d", ip.s_addr & 0xFF,
+ (ip.s_addr >> 8) & 0xFF,
+ (ip.s_addr >> 16) & 0xFF,
+ (ip.s_addr >> 24) & 0xFF);
+ else
+ sprintf (str, "%d.%d.%d.%d", (ip.s_addr >> 24) & 0xFF,
+ (ip.s_addr >> 16) & 0xFF,
+ (ip.s_addr >> 8) & 0xFF,
+ ip.s_addr & 0xFF);
+ return str;
+}
+
+/*
+ * Pretty print a packet for debugging.
+ */
+void ec_packet_debug(struct ec_device *ec, const char *action,
+ ETH_PACK *packet) {
+ struct ec_eth_hdr *eth = (struct ec_eth_hdr *)&packet->msg[0];
+ struct arp_hdr *arp = (struct arp_hdr *)eth;
+ struct ip *ip = (struct ip *)&packet->msg[sizeof(struct ec_eth_hdr)];
+ struct udp *udp;
+ struct tcp *tcp;
+ struct icmp *icmp;
+ uint8 *payload;
+ struct in_addr ipaddr;
+ size_t len;
+ int flag;
+ char src_ip[20];
+ char dst_ip[20];
+ char src_port[8];
+ char dst_port[8];
+ char flags[64];
+ static struct tcp_flag_bits {
+ const char *name;
+ uint16 bitmask;
+ } bits[] = {
+ {"FIN", TCP_FL_FIN},
+ {"SYN", TCP_FL_SYN},
+ {"RST", TCP_FL_RST},
+ {"PSH", TCP_FL_PSH},
+ {"ACK", TCP_FL_ACK},
+ {"URG", TCP_FL_URG},
+ {NULL, 0}
+ };
+ static const char *icmp_types[] = {
+ "Echo Reply", // Type 0
+ "Type 1 - Unassigned",
+ "Type 2 - Unassigned",
+ "Destination Unreachable", // Type 3
+ "Source Quench (Deprecated)", // Type 4
+ "Redirect", // Type 5
+ "Type 6 - Alternate Host Address (Deprecated)",
+ "Type 7 - Unassigned",
+ "Echo Request", // Type 8
+ "Router Advertisement", // Type 9
+ "Router Selection", // Type 10
+ "Time Exceeded", // Type 11
+ "Type 12 - Parameter Problem",
+ "Type 13 - Timestamp",
+ "Type 14 - Timestamp Reply",
+ "Type 15 - Information Request (Deprecated)",
+ "Type 16 - Information Reply (Deprecated)",
+ "Type 17 - Address Mask Request (Deprecated)",
+ "Type 18 - Address Mask Reply (Deprecated)",
+ "Type 19 - Reserved (for Security)",
+ "Type 20 - Reserved (for Robustness Experiment)",
+ "Type 21 - Reserved (for Robustness Experiment)",
+ "Type 22 - Reserved (for Robustness Experiment)",
+ "Type 23 - Reserved (for Robustness Experiment)",
+ "Type 24 - Reserved (for Robustness Experiment)",
+ "Type 25 - Reserved (for Robustness Experiment)",
+ "Type 26 - Reserved (for Robustness Experiment)",
+ "Type 27 - Reserved (for Robustness Experiment)",
+ "Type 28 - Reserved (for Robustness Experiment)",
+ "Type 29 - Reserved (for Robustness Experiment)",
+ "Type 30 - Traceroute (Deprecated)",
+ "Type 31 - Datagram Conversion Error (Deprecated)",
+ "Type 32 - Mobile Host Redirect (Deprecated)",
+ "Type 33 - IPv6 Where-Are-You (Deprecated)",
+ "Type 34 - IPv6 I-Am-Here (Deprecated)",
+ "Type 35 - Mobile Registration Request (Deprecated)",
+ "Type 36 - Mobile Registration Reply (Deprecated)",
+ "Type 37 - Domain Name Request (Deprecated)",
+ "Type 38 - Domain Name Reply (Deprecated)",
+ "Type 39 - SKIP (Deprecated)",
+ "Type 40 - Photuris",
+ "Type 41 - ICMP messages utilized by experimental mobility protocols such as Seamoby",
+ "Type 42 - Extended Echo Request",
+ "Type 43 - Extended Echo Reply"
+ };
+
+ if (ntohs(eth->type) == ETHTYPE_ARP) {
+ struct in_addr in_addr;
+ const char *arp_op = (ARP_REQUEST == ntohs(arp->opcode)) ? "REQUEST" :
+ ((ARP_REPLY == ntohs(arp->opcode)) ? "REPLY" : "Unknown");
+ char eth_src[20], eth_dst[20];
+ char arp_shwaddr[20], arp_dhwaddr[20];
+ char arp_sipaddr[20], arp_dipaddr[20];
+
+ if (!(ec_dev.dctrl & DEBUG_ARP))
+ return;
+ eth_mac_fmt(&arp->ethhdr.src, eth_src);
+ eth_mac_fmt(&arp->ethhdr.dest, eth_dst);
+ eth_mac_fmt(&arp->shwaddr, arp_shwaddr);
+ memcpy(&in_addr, &arp->sipaddr, sizeof(in_addr));
+ strlcpy(arp_sipaddr, ipv4_inet_ntoa(in_addr), sizeof(arp_sipaddr));
+ eth_mac_fmt(&arp->dhwaddr, arp_dhwaddr);
+ memcpy(&in_addr, &arp->dipaddr, sizeof(in_addr));
+ strlcpy(arp_dipaddr, ipv4_inet_ntoa(in_addr), sizeof(arp_dipaddr));
+ sim_debug(DEBUG_ARP, &ec_dev,
+ "%s %s EthDst=%s EthSrc=%s shwaddr=%s sipaddr=%s dhwaddr=%s dipaddr=%s\n",
+ action, arp_op, eth_dst, eth_src, arp_shwaddr, arp_sipaddr, arp_dhwaddr, arp_dipaddr);
+ return;
+ }
+ if (ntohs(eth->type) != ETHTYPE_IP) {
+ payload = (uint8 *)&packet->msg[sizeof(struct ec_eth_hdr)];
+ len = packet->len - sizeof(struct ec_eth_hdr);
+ sim_data_trace(&ec_dev, ec_unit, payload, "", len, "", DEBUG_DATA);
+ return;
+ }
+ if (!(ec_dev.dctrl & (DEBUG_TCP|DEBUG_UDP|DEBUG_ICMP)))
+ return;
+ memcpy(&ipaddr, &ip->ip_src, sizeof(ipaddr));
+ strlcpy(src_ip, ipv4_inet_ntoa(ipaddr), sizeof(src_ip));
+ memcpy(&ipaddr, &ip->ip_dst, sizeof(ipaddr));
+ strlcpy(dst_ip, ipv4_inet_ntoa(ipaddr), sizeof(dst_ip));
+ payload = (uint8 *)&packet->msg[sizeof(struct ec_eth_hdr) + (ip->ip_v_hl & 0xf) * 4];
+ switch (ip->ip_p) {
+ case UDP_PROTO:
+ udp = (struct udp *)payload;
+ snprintf(src_port, sizeof(src_port), "%d", ntohs(udp->udp_sport));
+ snprintf(dst_port, sizeof(dst_port), "%d", ntohs(udp->udp_dport));
+ sim_debug(DEBUG_UDP, &ec_dev, "%s %d byte packet from %s:%s to %s:%s\n", action,
+ ntohs(udp->len), src_ip, src_port, dst_ip, dst_port);
+ if (udp->len && (ec_dev.dctrl & DEBUG_UDP))
+ sim_data_trace(&ec_dev, ec_unit, payload + sizeof(struct udp), "",
+ ntohs(udp->len), "", DEBUG_DATA);
+ break;
+ case TCP_PROTO:
+ tcp = (struct tcp *)payload;
+ snprintf(src_port, sizeof(src_port), "%d", ntohs(tcp->tcp_sport));
+ snprintf(dst_port, sizeof(dst_port), "%d", ntohs(tcp->tcp_dport));
+ strlcpy(flags, "", sizeof(flags));
+ for (flag=0; bits[flag].name; flag++) {
+ if (ntohs(tcp->flags) & bits[flag].bitmask) {
+ if (*flags)
+ strlcat(flags, ",", sizeof(flags));
+ strlcat(flags, bits[flag].name, sizeof(flags));
+ }
+
+ }
+ len = ntohs(ip->ip_len) - ((ip->ip_v_hl & 0xf) * 4 + (ntohs(tcp->flags) >> 12) * 4);
+ sim_debug(DEBUG_TCP, &ec_dev, "%s %s%s %d byte packet from %s:%s to %s:%s\n", action,
+ flags, *flags ? ":" : "", (int)len, src_ip, src_port, dst_ip, dst_port);
+ if (len && (ec_dev.dctrl & DEBUG_TCP))
+ sim_data_trace(&ec_dev, ec_unit, payload + 4 * (ntohs(tcp->flags) >> 12), "", len, "", DEBUG_DATA);
+ break;
+ case ICMP_PROTO:
+ icmp = (struct icmp *)payload;
+ len = ntohs(ip->ip_len) - (ip->ip_v_hl & 0xf) * 4;
+ sim_debug(DEBUG_ICMP, &ec_dev, "%s %s %d byte packet from %s to %s\n", action,
+ (icmp->type < sizeof(icmp_types)/sizeof(icmp_types[0])) ? icmp_types[icmp->type] : "", (int)len, src_ip, dst_ip);
+ if (len && (ec_dev.dctrl & DEBUG_ICMP))
+ sim_data_trace(&ec_dev, ec_unit, payload + sizeof(struct icmp), "", len, "", DEBUG_DATA);
+ break;
+ }
+}
+
+
+
+t_stat ec_show_mode (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
+{
+ fprintf(st, "MODE=%d", GET_MODE(uptr->flags));
+ return SCPE_OK;
+}
+
+t_stat ec_set_mode (UNIT* uptr, int32 val, CONST char* cptr, void* desc)
+{
+ t_stat r;
+ int newmode;
+
+ if (!cptr) return SCPE_IERR;
+
+ newmode = get_uint (cptr, 10, 4, &r);
+
+ if (r != SCPE_OK)
+ return r;
+
+ if (newmode > 3)
+ return SCPE_ARG;
+
+ uptr->flags &= ~UNIT_MODE;
+ uptr->flags |= SET_MODE(newmode);
+ return SCPE_OK;
+}
+
+
+t_stat ec_show_mac (FILE* st, UNIT* uptr, int32 val, CONST void* desc)
+{
+ char buffer[20];
+ eth_mac_fmt(&ec_data.mac, buffer);
+ fprintf(st, "MAC=%s", buffer);
+ return SCPE_OK;
+}
+
+t_stat ec_set_mac (UNIT* uptr, int32 val, CONST char* cptr, void* desc)
+{
+ t_stat status;
+
+ if (!cptr) return SCPE_IERR;
+ if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
+
+ status = eth_mac_scan_ex(&ec_data.mac, cptr, uptr);
+ if (status != SCPE_OK)
+ return status;
+
+ return SCPE_OK;
+}
+
+t_stat ec_reset (DEVICE *dptr)
+{
+ int i;
+
+ for (i = 0; i < sizeof(ETH_MAC); i++) {
+ if (ec_data.mac[i] != 0)
+ break;
+ }
+ if (i == 6) { /* First call to reset? */
+ /* Set a default MAC address in a BBN assigned OID range no longer in use */
+ ec_set_mac (dptr->units, 0, "00:00:02:00:00:00/24", NULL);
+ }
+ return SCPE_OK;
+}
+
+/* attach device: */
+t_stat ec_attach(UNIT* uptr, CONST char* cptr)
+{
+ t_stat status;
+ char* tptr;
+ char buf[32];
+
+ tptr = (char *) malloc(strlen(cptr) + 1);
+ if (tptr == NULL) return SCPE_MEM;
+ strcpy(tptr, cptr);
+
+ memcpy(&ec_data.macs[0], &ec_data.mac, sizeof (ETH_MAC));
+ memcpy(&ec_data.macs[1], &broadcast_ethaddr, sizeof (ETH_MAC));
+ status = eth_open(&ec_data.etherface, cptr, &ec_dev, DEBUG_ETHER);
+ if (status != SCPE_OK) {
+ free(tptr);
+ return status;
+ }
+ eth_mac_fmt(&ec_data.mac, buf); /* format ethernet mac address */
+ if (SCPE_OK != eth_check_address_conflict (&ec_data.etherface,
+ &ec_data.mac)) {
+ eth_close(&ec_data.etherface);
+ free(tptr);
+ return sim_messagef (SCPE_NOATT,
+ "%s: MAC Address Conflict on LAN for address %s\n",
+ ec_dev.name, buf);
+ }
+ if (SCPE_OK != eth_filter(&ec_data.etherface, 2, ec_data.macs, 0, 0)) {
+ eth_close(&ec_data.etherface);
+ free(tptr);
+ return sim_messagef (SCPE_NOATT,
+ "%s: Can't set packet filter for MAC Address %s\n",
+ ec_dev.name, buf);
+ }
+
+ uptr->filename = tptr;
+ uptr->flags |= UNIT_ATT;
+ eth_setcrc(&ec_data.etherface, 1); /* Enable CRC */
+
+ /* init read queue (first time only) */
+ status = ethq_init(&ec_data.ReadQ, 8);
+ if (status != SCPE_OK) {
+ eth_close(&ec_data.etherface);
+ uptr->filename = NULL;
+ free(tptr);
+ return sim_messagef (status, "%s: Can't initialize receive queue\n",
+ ec_dev.name);
+ }
+
+ return SCPE_OK;
+}
+
+/* detach device: */
+
+t_stat ec_detach(UNIT* uptr)
+{
+
+ if (uptr->flags & UNIT_ATT && (uptr->flags & UNIT_DIS) == 0) {
+ eth_close (&ec_data.etherface);
+ free(uptr->filename);
+ uptr->filename = NULL;
+ uptr->flags &= ~UNIT_ATT;
+ }
+ return SCPE_OK;
+}
+
+t_stat ec_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr)
+{
+fprintf (st, "Ethernet interface\n\n");
+fprintf (st, "The ethernet interfaces to the network. Setting MAC defines default MAC address\n");
+fprint_set_help (st, dptr);
+fprint_show_help (st, dptr);
+eth_attach_help(st, dptr, uptr, flag, cptr);
+return SCPE_OK;
+}
+
+const char *ec_description (DEVICE *dptr)
+{
+ return "SEL32 8516 Ethernet interface";
+}
+
+#endif
diff --git a/SEL32/sel32_sys.c b/SEL32/sel32_sys.c
index eadf3d6..e104b24 100644
--- a/SEL32/sel32_sys.c
+++ b/SEL32/sel32_sys.c
@@ -111,6 +111,9 @@ DEVICE *sim_devices[] = {
&sbb_dev,
#endif
#endif
+#ifdef NUM_DEVS_ETHER
+ &ec_dev,
+#endif
#ifdef NUM_DEVS_COM
&coml_dev,
&com_dev,
diff --git a/Visual Studio Projects/SEL32.vcproj b/Visual Studio Projects/SEL32.vcproj
index ab743e9..6ef9ece 100644
--- a/Visual Studio Projects/SEL32.vcproj
+++ b/Visual Studio Projects/SEL32.vcproj
@@ -220,6 +220,10 @@
RelativePath="..\SEL32\sel32_disk.c"
>
+
+
diff --git a/makefile b/makefile
index fee9353..e628cf8 100644
--- a/makefile
+++ b/makefile
@@ -121,6 +121,10 @@ endif
ifneq (,$(or $(findstring pdp10-ka,${MAKECMDGOALS}),$(findstring pdp10-ki,${MAKECMDGOALS},$(findstring pdp10-kl,${MAKECMDGOALS}))))
NETWORK_USEFUL = true
endif
+# building the SEL32 networking can be ussed
+ifneq (,$(findstring sel32,${MAKECMDGOALS}))
+ NETWORK_USEFUL = true
+endif
# building the PDP-7 needs video support
ifneq (,$(findstring pdp7,${MAKECMDGOALS}))
VIDEO_USEFUL = true
@@ -1973,8 +1977,9 @@ SEL32 = ${SEL32D}/sel32_cpu.c ${SEL32D}/sel32_sys.c ${SEL32D}/sel32_chan.c \
${SEL32D}/sel32_iop.c ${SEL32D}/sel32_com.c ${SEL32D}/sel32_con.c \
${SEL32D}/sel32_clk.c ${SEL32D}/sel32_mt.c ${SEL32D}/sel32_lpr.c \
${SEL32D}/sel32_scfi.c ${SEL32D}/sel32_fltpt.c ${SEL32D}/sel32_disk.c \
- ${SEL32D}/sel32_hsdp.c ${SEL32D}/sel32_mfp.c ${SEL32D}/sel32_scsi.c
-SEL32_OPT = -I $(SEL32D) -DSEL32
+ ${SEL32D}/sel32_hsdp.c ${SEL32D}/sel32_mfp.c ${SEL32D}/sel32_scsi.c \
+ ${SEL32D}/sel32_ec.c
+SEL32_OPT = -I $(SEL32D) -DSEL32 ${NETWORK_OPT}
#SEL32_OPT = -I $(SEL32D) -DUSE_INT64 -DSEL32
ICL1900D = ${SIMHD}/ICL1900