From b1fb809210de70c62034cb6eb21ba9219376280e Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Mon, 10 Feb 2014 17:22:19 -0800 Subject: [PATCH] PDP10, PDP11, VAX: Added the DDCMP corruption troll to the DDCMP layer and removed it from the KDP device. Now all DDCMP capable devices KDP, DUP and DMC/DMR have access to packet corruption generation to simulate real world imperfect data lines for protocol testing. --- PDP11/pdp11_ddcmp.h | 109 ++++++++++++++++--- PDP11/pdp11_dmc.c | 93 ++++++++++++++--- PDP11/pdp11_dup.c | 249 ++++++++++++++++++++++++++++++++++++++------ PDP11/pdp11_kmc.c | 156 --------------------------- sim_tmxr.h | 1 + 5 files changed, 396 insertions(+), 212 deletions(-) diff --git a/PDP11/pdp11_ddcmp.h b/PDP11/pdp11_ddcmp.h index 00a59e71..f66b485b 100644 --- a/PDP11/pdp11_ddcmp.h +++ b/PDP11/pdp11_ddcmp.h @@ -173,6 +173,81 @@ if (sim_deb && dptr && (reason & dptr->dctrl)) { uint16 ddcmp_crc16(uint16 crc, const void* vbuf, size_t len); +/* Data corruption troll, which simulates imperfect links. + */ + +/* Evaluate the corruption troll's appetite. + * + * A message can be eaten (dropped), nibbled (corrupted) or spared. + * + * The probability of a message not being spared is trollHungerLevel, + * expressed in milli-gulps - 0.1%. The troll selects which action + * to taken on selected messages with equal probability. + * + * Nibbled messages' CRCs are changed when possible to simplify + * identifying them when debugging. When it's too much work to + * find the CRC, the first byte of data is changed. The change + * is an XOR to make it possible to reconstruct the original data. + * + * A particularly unfortunate message can be nibbled by both + * the transmitter and receiver; thus the troll applies a direction- + * dependent pattern. + * + * Return TRUE if the troll ate the message. + * Return FALSE if the message was nibbled or spared. + */ +static t_bool ddcmp_feedCorruptionTroll (TMLN *lp, uint8 *msg, t_bool rx, int32 trollHungerLevel) +{ +double r, rmax; +char msgbuf[80]; + +if (trollHungerLevel == 0) + return FALSE; +#if defined(_POSIX_VERSION) || defined (_XOPEN_VERSION) +r = (double)random(); +rmax = (double)0x7fffffff; +#else +r = rand(); +rmax = (double)RAND_MAX; +#endif +if (msg[0] == DDCMP_ENQ) { + int eat = 0 + (int) (2000.0 * (r / rmax)); + + if (eat <= (trollHungerLevel * 2)) { /* Hungry? */ + if (eat <= trollHungerLevel) { /* Eat the packet */ + sprintf (msgbuf, "troll ate a %s control message", rx ? "RCV" : "XMT"); + tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf); + return TRUE; + } + sprintf (msgbuf, "troll bit a %s control message", rx ? "RCV" : "XMT"); + tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf); + msg[6] ^= rx? 0114: 0154; /* Eat the CRC */ + } + } +else { + int eat = 0 + (int) (3000.0 * (r / rmax)); + + if (eat <= (trollHungerLevel * 3)) { /* Hungry? */ + if (eat <= trollHungerLevel) { /* Eat the packet */ + sprintf (msgbuf, "troll ate a %s %s message", rx ? "RCV" : "XMT", (msg[0] == DDCMP_SOH)? "data" : "maintenance"); + tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf); + return TRUE; + } + if (eat <= (trollHungerLevel * 2)) { /* HCRC */ + sprintf (msgbuf, "troll bit a %s %s message", rx ? "RCV" : "XMT", (msg[0] == DDCMP_SOH)? "data" : "maintenance"); + tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf); + msg[6] ^= rx? 0124: 0164; + } + else { /* DCRC */ + sprintf (msgbuf, "troll bit %s %s DCRC\n", (rx? "RCV" : "XMT"), ((msg[0] == DDCMP_SOH)? "data" : "maintenance")); + tmxr_debug_msg (rx ? DDCMP_DBG_PRCV : DDCMP_DBG_PXMT, lp, msgbuf); + msg[8] ^= rx? 0114: 0154; /* Rather than find the CRC, the first data byte will do */ + } + } + } +return FALSE; +} + /* Get packet from specific line Inputs: @@ -190,7 +265,7 @@ uint16 ddcmp_crc16(uint16 crc, const void* vbuf, size_t len); NULL, but success (SCPE_OK) is returned */ -static t_stat ddcmp_tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, uint16 *psize) +static t_stat ddcmp_tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, uint16 *psize, int32 corruptrate) { int32 c; size_t payloadsize; @@ -230,6 +305,8 @@ while (TMXR_VALID & (c = tmxr_getc_ln (lp))) { else strcpy (msg, "<<< RCV Packet"); ddcmp_packet_trace (DDCMP_DBG_PRCV, lp->mp->dptr, msg, lp->rxpb, *psize); + if (ddcmp_feedCorruptionTroll (lp, lp->rxpb, TRUE, corruptrate)) + break; return SCPE_OK; } payloadsize = ((lp->rxpb[2] & 0x3F) << 8)| lp->rxpb[1]; @@ -243,6 +320,8 @@ while (TMXR_VALID & (c = tmxr_getc_ln (lp))) { strcpy (msg, "<<< RCV Packet"); ddcmp_packet_trace (DDCMP_DBG_PRCV, lp->mp->dptr, msg, lp->rxpb, *psize); lp->rxpboffset = 0; + if (ddcmp_feedCorruptionTroll (lp, lp->rxpb, TRUE, corruptrate)) + break; return SCPE_OK; } } @@ -270,7 +349,7 @@ return SCPE_LOST; 2. If prior packet transmission still in progress, SCPE_STALL is returned and no packet data is stored. The caller must retry later. */ -static t_stat ddcmp_tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size) +static t_stat ddcmp_tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size, int32 corruptrate) { t_stat r; char msg[32]; @@ -293,15 +372,17 @@ if (lp->mp->lines > 1) else strcpy (msg, ">>> XMT Packet"); ddcmp_packet_trace (DDCMP_DBG_PXMT, lp->mp->dptr, msg, lp->txpb, lp->txppsize); -++lp->txpcnt; -while ((lp->txppoffset < lp->txppsize) && - (SCPE_OK == (r = tmxr_putc_ln (lp, lp->txpb[lp->txppoffset])))) - ++lp->txppoffset; -tmxr_send_buffered_data (lp); +if (!ddcmp_feedCorruptionTroll (lp, lp->txpb, FALSE, corruptrate)) { + ++lp->txpcnt; + while ((lp->txppoffset < lp->txppsize) && + (SCPE_OK == (r = tmxr_putc_ln (lp, lp->txpb[lp->txppoffset])))) + ++lp->txppoffset; + tmxr_send_buffered_data (lp); + } return lp->conn ? SCPE_OK : SCPE_LOST; } -static t_stat ddcmp_tmxr_put_packet_crc_ln (TMLN *lp, uint8 *buf, size_t size) +static t_stat ddcmp_tmxr_put_packet_crc_ln (TMLN *lp, uint8 *buf, size_t size, int32 corruptrate) { uint16 hdr_crc16 = ddcmp_crc16(0, buf, DDCMP_HEADER_SIZE-DDCMP_CRC_SIZE); @@ -312,7 +393,7 @@ if (size > DDCMP_HEADER_SIZE) { buf[size-DDCMP_CRC_SIZE] = data_crc16 & 0xFF; buf[size-DDCMP_CRC_SIZE+1] = (data_crc16>>8) & 0xFF; } -return ddcmp_tmxr_put_packet_ln (lp, buf, size); +return ddcmp_tmxr_put_packet_ln (lp, buf, size, corruptrate); } static void ddcmp_build_data_packet (uint8 *buf, size_t size, uint8 flags, uint8 sequence, uint8 ack) @@ -338,7 +419,7 @@ buf[5] = 1; static t_stat ddcmp_tmxr_put_data_packet_ln (TMLN *lp, uint8 *buf, size_t size, uint8 flags, uint8 sequence, uint8 ack) { ddcmp_build_data_packet (buf, size, flags, sequence, ack); -return ddcmp_tmxr_put_packet_crc_ln (lp, buf, size); +return ddcmp_tmxr_put_packet_crc_ln (lp, buf, size, 0); } static void ddcmp_build_control_packet (uint8 *buf, uint8 type, uint8 subtype, uint8 flags, uint8 sndr, uint8 rcvr) @@ -355,7 +436,7 @@ buf[5] = 1; /* ADDR */ static t_stat ddcmp_tmxr_put_control_packet_ln (TMLN *lp, uint8 *buf, uint8 type, uint8 subtype, uint8 flags, uint8 sndr, uint8 rcvr) { ddcmp_build_control_packet (buf, type, subtype, flags, sndr, rcvr); -return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE); +return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE, 0); } static void ddcmp_build_ack_packet (uint8 *buf, uint8 ack, uint8 flags) @@ -366,7 +447,7 @@ ddcmp_build_control_packet (buf, DDCMP_CTL_ACK, 0, flags, 0, ack); static t_stat ddcmp_tmxr_put_ack_packet_ln (TMLN *lp, uint8 *buf, uint8 ack, uint8 flags) { ddcmp_build_ack_packet (buf, ack, flags); -return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE); +return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE, 0); } static void ddcmp_build_nak_packet (uint8 *buf, uint8 reason, uint8 nack, uint8 flags) @@ -397,7 +478,7 @@ ddcmp_build_control_packet (buf, DDCMP_CTL_STRT, 0, DDCMP_FLAG_SELECT|DDCMP_FLAG static t_stat ddcmp_tmxr_put_start_packet_ln (TMLN *lp, uint8 *buf) { ddcmp_build_start_packet (buf); -return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE); +return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE, 0); } static void ddcmp_build_start_ack_packet (uint8 *buf) @@ -408,7 +489,7 @@ ddcmp_build_control_packet (buf, DDCMP_CTL_STACK, 0, DDCMP_FLAG_SELECT|DDCMP_FLA static t_stat ddcmp_tmxr_put_start_ack_packet_ln (TMLN *lp, uint8 *buf) { ddcmp_build_start_ack_packet (buf); -return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE); +return ddcmp_tmxr_put_packet_crc_ln (lp, buf, DDCMP_HEADER_SIZE, 0); } #endif /* PDP11_DDCMP_H_ */ diff --git a/PDP11/pdp11_dmc.c b/PDP11/pdp11_dmc.c index 3c912509..0de69ba0 100644 --- a/PDP11/pdp11_dmc.c +++ b/PDP11/pdp11_dmc.c @@ -517,6 +517,7 @@ typedef struct dmc_controller { uint32 *baseaddr; uint16 *basesize; uint8 *modem; + int32 *corruption_factor; uint32 buffers_received_from_net; uint32 buffers_transmitted_to_net; uint32 receive_buffer_output_transfers_completed; @@ -882,6 +883,8 @@ t_stat dmc_setpeer (UNIT* uptr, int32 val, char* cptr, void* desc); t_stat dmc_showpeer (FILE* st, UNIT* uptr, int32 val, void* desc); t_stat dmc_setspeed (UNIT* uptr, int32 val, char* cptr, void* desc); t_stat dmc_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat dmc_setcorrupt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dmc_showcorrupt (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat dmc_set_microdiag (UNIT* uptr, int32 val, char* cptr, void* desc); t_stat dmc_show_microdiag (FILE* st, UNIT* uptr, int32 val, void* desc); t_stat dmc_settype (UNIT* uptr, int32 val, char* cptr, void* desc); @@ -968,6 +971,7 @@ uint32 dmc_baseaddr[DMC_NUMDEVICE]; uint16 dmc_basesize[DMC_NUMDEVICE]; uint8 dmc_modem[DMC_NUMDEVICE]; t_bool dmc_microdiag[DMC_NUMDEVICE]; +int32 dmc_corruption[DMC_NUMDEVICE]; CSRS dmp_csrs[DMP_NUMDEVICE]; uint16 dmp_sel0[DMC_NUMDEVICE]; @@ -982,6 +986,7 @@ char dmp_port[DMP_NUMDEVICE][CBUFSIZE]; uint32 dmp_baseaddr[DMP_NUMDEVICE]; uint16 dmp_basesize[DMP_NUMDEVICE]; uint8 dmp_modem[DMP_NUMDEVICE]; +int32 dmp_corruption[DMC_NUMDEVICE]; TMLN dmc_ldsc[DMC_NUMDEVICE]; /* line descriptors */ TMXR dmc_desc = { 1, NULL, 0, dmc_ldsc }; /* mux descriptor */ @@ -1017,6 +1022,7 @@ REG dmc_reg[] = { { BRDATAD (SEL4, dmc_sel4, DEV_RDX, 16, DMC_NUMDEVICE, "Select 4 CSR") }, { BRDATAD (SEL6, dmc_sel6, DEV_RDX, 16, DMC_NUMDEVICE, "Select 6 CSR") }, { BRDATAD (SPEED, dmc_speed, DEV_RDX, 32, DMC_NUMDEVICE, "line speed") }, + { BRDATAD (CORRUPT, dmc_corruption, DEV_RDX, 32, DMC_NUMDEVICE, "data corruption factor (0.1%)") }, { BRDATAD (DIAG, dmc_microdiag, DEV_RDX, 1, DMC_NUMDEVICE, "Microdiagnostic Enabled") }, { BRDATAD (PEER, dmc_peer, DEV_RDX, 8, DMC_NUMDEVICE*CBUFSIZE, "peer address:port") }, { BRDATAD (PORT, dmc_port, DEV_RDX, 8, DMC_NUMDEVICE*CBUFSIZE, "listen port") }, @@ -1035,6 +1041,7 @@ REG dmp_reg[] = { { BRDATAD (SEL6, dmp_sel6, DEV_RDX, 16, DMC_NUMDEVICE, "Select 6 CSR") }, { BRDATAD (SEL10, dmp_sel10, DEV_RDX, 16, DMP_NUMDEVICE, "Select 10 CSR") }, { BRDATAD (SPEED, dmp_speed, DEV_RDX, 32, DMC_NUMDEVICE, "line speed") }, + { BRDATAD (CORRUPT, dmp_corruption, DEV_RDX, 32, DMC_NUMDEVICE, "data corruption factor (0.1%)") }, { BRDATAD (PEER, dmp_peer, DEV_RDX, 8, DMC_NUMDEVICE*CBUFSIZE, "peer address:port") }, { BRDATAD (PORT, dmp_port, DEV_RDX, 8, DMC_NUMDEVICE*CBUFSIZE, "listen port") }, { BRDATAD (BASEADDR, dmp_baseaddr, DEV_RDX, 32, DMC_NUMDEVICE, "program set base address") }, @@ -1064,6 +1071,8 @@ MTAB dmc_mod[] = { NULL, &dmc_showddcmp, NULL, "Display DDCMP state information" }, { MTAB_XTD|MTAB_VDV, 0, "CONNECTPOLL", "CONNECTPOLL=seconds", &dmc_setconnectpoll, &dmc_showconnectpoll, (void *) &dmc_connect_poll, "Display connection poll interval" }, + { MTAB_XTD|MTAB_VUN|MTAB_VALR|MTAB_NMO, 0, "CORRUPT", "CORRUPTION=factor (0=uncorrupted)" , + &dmc_setcorrupt, &dmc_showcorrupt, NULL, "Display corruption factor (0.1% of packets)" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 020, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL, "Bus address" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, "VECTOR", "VECTOR", @@ -1087,6 +1096,8 @@ MTAB dmp_mod[] = { NULL, &dmc_showddcmp, NULL, "Display DDCMP state information" }, { MTAB_XTD|MTAB_VDV, 0, "CONNECTPOLL", "CONNECTPOLL=seconds", &dmc_setconnectpoll, &dmc_showconnectpoll, (void *) &dmp_connect_poll, "Display connection poll interval" }, + { MTAB_XTD|MTAB_VUN|MTAB_VALR|MTAB_NMO, 0, "CORRUPTION", "CORRUPTION=factor (0=uncorrupted)" , + &dmc_setcorrupt, &dmc_showcorrupt, NULL, "Display corruption factor (0.1% of packets)" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 020, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL, "Bus address" }, { MTAB_XTD|MTAB_VDV|MTAB_VALR, 1, "VECTOR", "VECTOR", @@ -1270,6 +1281,47 @@ fprintf(st, "MicroDiag=%s", dmc_microdiag[dmc] ? "enabled" : "disabled"); return SCPE_OK; } +/* Manage the corruption troll's appetite, in units of milli-gulps. + * + * See ddcmp_feedCorruptionTroll for usage. + */ +t_stat dmc_setcorrupt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DEVICE *dptr = (UNIBUS) ? ((&dmc_dev == find_dev_from_unit(uptr)) ? &dmc_dev : &dmp_dev) : &dmv_dev; +int32 dmc = (int32)(uptr-dptr->units); +int32 *hunger = (dptr == &dmc_dev) ? &dmc_corruption[dmc] : &dmp_corruption[dmc]; +t_stat r; +int32 appetite; + +if ((cptr == NULL) || (*cptr == '\0')) + return SCPE_ARG; + +appetite = (int32) get_uint (cptr, 10, 999, &r); +if (r != SCPE_OK) + return r; + +*hunger = appetite; + +return SCPE_OK; +} + +/* Display the corruption troll's appetite */ + +t_stat dmc_showcorrupt (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr = (UNIBUS) ? ((&dmc_dev == find_dev_from_unit(uptr)) ? &dmc_dev : &dmp_dev) : &dmv_dev; +int32 dmc = (int32)(uptr-dptr->units); +int32 *hunger = (dptr == &dmc_dev) ? &dmc_corruption[dmc] : &dmp_corruption[dmc]; + +if (*hunger) + fprintf(st, "Corruption=%d milligulps (%.1f%% of messages processed)", + *hunger, ((double)*hunger)/10.0); +else + fprintf(st, "No Corruption"); + +return SCPE_OK; +} + t_stat dmc_set_microdiag(UNIT* uptr, int32 val, char* cptr, void* desc) { int32 dmc = (int32)(uptr-dmc_dev.units); @@ -1570,7 +1622,7 @@ const char helpString[] = " simulator. The number of simulated %1s devices or lines can be\n" " specified with command:\n" "\n" - "+sim> SET %U LINES=n\n" + "+sim> SET %D LINES=n\n" "3 Peer\n" " To set the host and port to which data is to be transmitted use the\n" " following command:\n" @@ -1604,7 +1656,18 @@ const char helpString[] = " A SET TYPE command should be entered before the device is attached to a\n" " listening port.\n" #endif + "3 Corruption\n" + " Corruption Troll - the DDCMP emulation includes a process that will\n" + " intentionally drop or corrupt some messages. This emulates the\n" + " less-than-perfect communications lines encountered in the real world,\n" + " and enables network monitoring software to see non-zero error counters.\n" + "\n" + " The troll selects messages with a probablility selected by the SET %U\n" + " CORRUPT command. The units are 0.1%%; that is, a value of 1 means that\n" + " every message has a 1/1000 chance of being selected to be corrupted\n" + " or discarded.\n" /****************************************************************************/ +#define DMC_HLP_ATTACH "Configuration Attach" "2 Attach\n" " The device must be attached to a receive port, use the ATTACH command\n" " specifying the receive port number.\n" @@ -1636,6 +1699,16 @@ const char helpString[] = " The %D device and %U line configuration and state can be displayed with\n" " one of the available show commands.\n" "2 $Show commands\n" + "1 Diagnostics\n" + " Corruption Troll - the DDCMP emulation includes a process that will\n" + " intentionally drop or corrupt some messages. This emulates the\n" + " less-than-perfect communications lines encountered in the real world,\n" + " and enables network monitoring software to see non-zero error counters.\n" + "\n" + " The troll selects messages with a probablility selected by the SET\n" + " CORRUPT command. The units are 0.1%%; that is, a value of 1 means that\n" + " every message has a 1/1000 chance of being selected to be corrupted\n" + " or discarded.\n" "1 Restrictions\n" " Real hardware synchronous connections could operate in Multi-Point mode.\n" " Multi-Point mode was a way of sharing a single wire with multiple\n" @@ -1708,15 +1781,7 @@ return scp_help (st, dptr, uptr, flag, helpString, cptr, devname, devcount, conn t_stat dmc_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { -const char helpString[] = -" The communication line performs input and output through a TCP session\n" -" connected to a user-specified port. The ATTACH command specifies the\n" -" listening port to be used when the incoming connection is established:\n\n" -"+sim> ATTACH %U {interface:}port{,UDP} set up listening port\n\n" -" where port is a decimal number between 1 and 65535 that is not being\n" -" used for other TCP/IP activities.\n\n"; -return scp_help (st, dptr, uptr, flag, helpString, cptr); -return SCPE_OK; +return dmc_help (st, dptr, uptr, flag, DMC_HLP_ATTACH); } void dmc_setinint(CTLR *controller) @@ -2529,7 +2594,7 @@ if (controller->state == Running) { BUFFER *buffer = dmc_buffer_queue_head(controller->rcv_queue); while (buffer) { - ddcmp_tmxr_get_packet_ln (controller->line, (const uint8 **)&controller->link.rcv_pkt, &controller->link.rcv_pkt_size); + ddcmp_tmxr_get_packet_ln (controller->line, (const uint8 **)&controller->link.rcv_pkt, &controller->link.rcv_pkt_size, *controller->corruption_factor); if (!controller->link.rcv_pkt) break; ans = TRUE; @@ -3292,7 +3357,7 @@ while (buffer) { if (buffer->transfer_buffer[0] == 0) return; /* Need to make sure we dynamically compute the packet CRCs since header details can change */ - r = ddcmp_tmxr_put_packet_crc_ln (controller->line, buffer->transfer_buffer, buffer->count); + r = ddcmp_tmxr_put_packet_crc_ln (controller->line, buffer->transfer_buffer, buffer->count, *controller->corruption_factor); if (r == SCPE_OK) { controller->link.xmt_buffer = buffer; controller->ddcmp_control_packets_sent += (buffer->transfer_buffer[0] == DDCMP_ENQ) ? 1 : 0; @@ -3494,6 +3559,7 @@ for (i=0; i < DMC_NUMDEVICE; i++) { controller->baseaddr = &dmc_baseaddr[i]; controller->basesize = &dmc_basesize[i]; controller->modem = &dmc_modem[i]; + controller->corruption_factor = &dmc_corruption[i]; controller->unit = &controller->device->units[i]; controller->unit->ctlr = (void *)controller; controller->index = i; @@ -3519,6 +3585,7 @@ for (i=0; i < DMP_NUMDEVICE; i++) { controller->baseaddr = &dmp_baseaddr[i]; controller->basesize = &dmp_basesize[i]; controller->modem = &dmp_modem[i]; + controller->corruption_factor = &dmp_corruption[i]; controller->unit = &controller->device->units[i]; controller->unit->ctlr = (void *)controller; controller->index = i + DMC_NUMDEVICE; @@ -3539,6 +3606,7 @@ if (0 == dmc_units[0].flags) { /* First Time Initializations */ dmc_dev.units[i] = dmc_unit_template; controller->unit->ctlr = (void *)controller; dmc_microdiag[i] = TRUE; + dmc_corruption[i] = 0; } tmxr_set_modem_control_passthru (&dmc_desc); /* We always want Modem Control */ dmc_units[dmc_dev.numunits-2] = dmc_poll_unit_template; @@ -3556,6 +3624,7 @@ if (0 == dmc_units[0].flags) { /* First Time Initializations */ *controller->modem = 0; dmp_dev.units[i] = dmc_unit_template; controller->unit->ctlr = (void *)controller; + dmp_corruption[i] = 0; } tmxr_set_modem_control_passthru (&dmp_desc); /* We always want Modem Control */ dmp_units[dmp_dev.numunits-2] = dmc_poll_unit_template; diff --git a/PDP11/pdp11_dup.c b/PDP11/pdp11_dup.c index c0b3e27c..9a89bffe 100644 --- a/PDP11/pdp11_dup.c +++ b/PDP11/pdp11_dup.c @@ -87,6 +87,7 @@ static uint16 dup_xmtpkoffset[DUP_LINES]; /* xmt buffer off static uint32 dup_xmtpkstart[DUP_LINES]; /* xmt packet start time */ static uint16 dup_xmtpkbytes[DUP_LINES]; /* xmt packet size of packet */ static uint16 dup_xmtpkdelaying[DUP_LINES]; /* xmt packet speed delaying completion */ +static int32 dup_corruption[DUP_LINES]; /* data corrupting troll hunger value */ static PACKET_DATA_AVAILABLE_CALLBACK dup_rcv_packet_data_callback[DUP_LINES]; static PACKET_TRANSMIT_COMPLETE_CALLBACK dup_xmt_complete_callback[DUP_LINES]; @@ -114,6 +115,8 @@ static void dup_set_txint (int32 dup); static t_stat dup_setnl (UNIT *uptr, int32 val, char *cptr, void *desc); static t_stat dup_setspeed (UNIT* uptr, int32 val, char* cptr, void* desc); static t_stat dup_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc); +static t_stat dup_setcorrupt (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat dup_showcorrupt (FILE *st, UNIT *uptr, int32 val, void *desc); static t_stat dup_set_W3 (UNIT* uptr, int32 val, char* cptr, void* desc); static t_stat dup_show_W3 (FILE* st, UNIT* uptr, int32 val, void* desc); static t_stat dup_set_W5 (UNIT* uptr, int32 val, char* cptr, void* desc); @@ -364,6 +367,7 @@ static REG dup_reg[] = { { BRDATAD (TPDELAY,dup_xmtpkdelaying, DEV_RDX, 16, DUP_LINES, "transmit packet completion delay") }, { BRDATAD (TPSTART, dup_xmtpkstart, DEV_RDX, 32, DUP_LINES, "transmit digest packet start time") }, { BRDATAD (RPINOFF, dup_rcvpkinoff, DEV_RDX, 16, DUP_LINES, "receive digest packet offset") }, + { BRDATAD (CORRUPT, dup_corruption, DEV_RDX, 32, DUP_LINES, "data corruption factor (0.1%)") }, { NULL } }; @@ -373,6 +377,8 @@ static TMXR dup_desc = { INITIAL_DUP_LINES, 0, 0, NULL }; /* mux descriptor static MTAB dup_mod[] = { { MTAB_XTD|MTAB_VUN, 0, "SPEED", "SPEED=bits/sec (0=unrestricted)" , &dup_setspeed, &dup_showspeed, NULL, "Display rate limit" }, + { MTAB_XTD|MTAB_VUN, 0, "CORRUPTION", "CORRUPTION=factor (0=uncorrupted)" , + &dup_setcorrupt, &dup_showcorrupt, NULL, "Display corruption factor (0.1% of packets)" }, { MTAB_XTD|MTAB_VUN, 1, "W3", NULL , NULL, &dup_show_W3, NULL, "Display Reset Option" }, { MTAB_XTD|MTAB_VUN, 1, NULL, "W3" , @@ -910,7 +916,7 @@ if (!tmxr_tpbusyln(&dup_ldsc[dup])) { /* Not Busy sending? */ dup_xmtpacket[dup][dup_xmtpkoffset[dup]++] = crc16 >> 8; if ((dup_xmtpkoffset[dup] > 8) || (dup_xmtpacket[dup][0] == DDCMP_ENQ)) { dup_xmtpkbytes[dup] = dup_xmtpkoffset[dup]; - ddcmp_tmxr_put_packet_ln (&dup_ldsc[dup], dup_xmtpacket[dup], dup_xmtpkbytes[dup]); + ddcmp_tmxr_put_packet_ln (&dup_ldsc[dup], dup_xmtpacket[dup], dup_xmtpkbytes[dup], dup_corruption[dup]); } } breturn = TRUE; @@ -1057,7 +1063,7 @@ for (dup=active=attached=0; dup < dup_desc.lines; dup++) { uint16 size; if (dup_parcsr[dup] & PARCSR_M_DECMODE) - ddcmp_tmxr_get_packet_ln (lp, &buf, &size); + ddcmp_tmxr_get_packet_ln (lp, &buf, &size, dup_corruption[dup]); else { size_t size_t_size; @@ -1318,6 +1324,36 @@ dup_speed[dup] = newspeed; return SCPE_OK; } +/* SET/SHOW CORRUPTION processor */ + +static t_stat dup_showcorrupt (FILE* st, UNIT* uptr, int32 val, void* desc) +{ +DEVICE *dptr = DUPDPTR; +int32 dup = (int32)(uptr-dptr->units); + +if (dup_corruption[dup]) + fprintf(st, "Corruption=%d milligulps (%.1f%% of messages processed)", dup_corruption[dup], ((double)dup_corruption[dup])/10.0); +else + fprintf(st, "No Corruption"); +return SCPE_OK; +} + +static t_stat dup_setcorrupt (UNIT* uptr, int32 val, char* cptr, void* desc) +{ +DEVICE *dptr = DUPDPTR; +int32 dup = (int32)(uptr-dptr->units); +t_stat r; +int32 appetite; + +if (cptr == NULL) + return SCPE_ARG; +appetite = (int32) get_uint (cptr, 10, 999, &r); +if (r != SCPE_OK) + return r; +dup_corruption[dup] = appetite; +return SCPE_OK; +} + /* SET/SHOW W3 processor */ static t_stat dup_show_W3 (FILE* st, UNIT* uptr, int32 val, void* desc) @@ -1421,38 +1457,191 @@ return dup_reset (dptr); /* setup lines and auto conf static t_stat dup_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { -fprintf (st, "Bit Serial Synchronous interface (%s)\n\n", dptr->name); -fprintf (st, "The %s connects two systems to provide a network connection.\n", dptr->name); -fprintf (st, "A maximum of %d %s devices/lines can be configured in the system.\n", DUP_LINES, dptr->name); -fprintf (st, "The number of configured devices can be changed with:\n\n"); -fprintf (st, " sim> SET %s LINES=n\n\n", dptr->name); -fprintf (st, "If you want to experience the actual data rates of the physical hardware you\n"); -fprintf (st, "can set the bit rate of the simulated line can be set using the following\n"); -fprintf (st, "command:\n\n"); -fprintf (st, " sim> SET %sn SPEED=bps\n\n", dptr->name); -fprintf (st, "Where bps is the number of data bits per second that the simulated line runs\n"); -fprintf (st, "at. Use a value of zero to run at full speed with no artificial\n"); -fprintf (st, "throttling.\n\n"); -fprint_set_help (st, dptr); -fprint_show_help (st, dptr); -fprint_reg_help (st, dptr); -return SCPE_OK; +const char helpString[] = + /* The '*'s in the next line represent the standard text width of a help line */ + /****************************************************************************/ + " The %D11 is a single-line, program controlled, double buffered\n" + " communications device designed to interface the %1s system to a\n" + " serial synchronous line. The original hardware is capable of handling\n" + " a wide variety of protocols, including byte oriented protocols, such\n" + " as DDCMP and BISYNC and bit-oriented protocols such as SDLC, HDLC\n" + " and ADCCP. The emulated device currently only supports connections\n" + " using the DDCMP protocol.\n\n" + " The %D11 is ideally suited for interfacing the %1s system\n" + " to medium-speed synchronous lines for remote batch, remote data\n" + " collection, remote concentration and network applications. Multiple\n" + " %D11's on a %1s allow its use in applications requiring several\n" + " synchronous lines.\n\n" + " The %D11 is capable of transmitting data at the maximum speed of\n" + " 9600 baud. The emulated device can move data at significantly faster\n" + " data rates. The maximum emulated rate is dependent on the host CPU's\n" + " available cycles.\n" + "1 Hardware Description\n" + " The %1s %D11 consists of a microprocessor module and a synchronous line unit\n" + " module.\n" + "2 $Registers\n" + "\n" + " These registers contain the emulated state of the device. These values\n" + " don't necessarily relate to any detail of the original device being\n" + " emulated but are merely internal details of the emulation.\n" + "1 Configuration\n" + " A %D device is configured with various simh SET and ATTACH commands\n" + "2 $Set commands\n" + "3 Lines\n" + " A maximum of %2s %D11 devices can be emulated concurrently in the %S\n" + " simulator. The number of simulated %D devices or lines can be\n" + " specified with command:\n" + "\n" + "+sim> SET %D LINES=n\n" + "3 Peer\n" + " To set the host and port to which data is to be transmitted use the\n" + " following command:\n" + "\n" + "+sim> SET %U PEER=host:port\n" + "3 Connectpoll\n" + " The minimum interval between attempts to connect to the other side is set\n" + " using the following command:\n" + "\n" + "+sim> SET %U CONNECTPOLL=n\n" + "\n" + " Where n is the number of seconds. The default is %3s seconds.\n" + "3 Speed\n" + " If you want to experience the actual data rates of the physical hardware\n" + " you can set the bit rate of the simulated line can be set using the\n" + " following command:\n" + "\n" + "+sim> SET %U SPEED=n\n" + "\n" + " Where n is the number of data bits per second that the simulated line\n" + " runs at. In practice this is implemented as a delay while transmitting\n" + " bytes to the socket. Use a value of zero to run at full speed with no\n" + " artificial throttling.\n" + "3 Corruption\n" + " Corruption Troll - the DDCMP emulation includes the ability to enable a\n" + " process that will intentionally drop or corrupt some messages. This\n" + " emulates the less-than-perfect communications lines encountered in the\n" + " real world, and enables network monitoring software to see non-zero error\n" + " counters.\n" + "\n" + " The troll selects messages with a probablility selected by the SET %U\n" + " CORRUPT command. The units are 0.1%%; that is, a value of 1 means that\n" + " every message has a 1/1000 chance of being selected to be corrupted\n" + " or discarded.\n" + /****************************************************************************/ +#define DUP_HLP_ATTACH "Configuration Attach" + "2 Attach\n" + " The communication line performs input and output through a TCP session\n" + " (or UDP session) connected to a user-specified port. The ATTACH command\n" + " specifies the port to be used as well as the peer address:\n" + "\n" + "+sim> ATTACH %U {interface:}port{,UDP},Connect=peerhost:port\n" + "\n" + " where port is a decimal number between 1 and 65535 that is not being\n" + " used for other TCP/IP activities.\n" + "\n" + " Specifying symmetric attach configuration (with both a listen port and\n" + " a peer address) will cause the side receiving an incoming\n" + " connection to validate that the connection actually comes from the\n" + " connecction destination system.\n" + " A symmetric attach configuration is required when using UDP packet\n" + " transport.\n" + "\n" + " The default connection uses TCP transport between the local system and\n" + " the peer. Alternatively, UDP can be used by specifying UDP on the\n" + " ATTACH command.\n" + "\n" + "2 Examples\n" + " To configure two simulators to talk to each other use the following\n" + " example:\n" + " \n" + " Machine 1\n" + "+sim> SET %D ENABLE\n" + "+sim> ATTACH %U 1111,connect=LOCALHOST:2222\n" + " \n" + " Machine 2\n" + "+sim> SET %D ENABLE\n" + "+sim> ATTACH %U 2222,connect=LOCALHOST:1111\n" + "\n" + "1 Monitoring\n" + " The %D device and %U line configuration and state can be displayed with\n" + " one of the available show commands.\n" + "2 $Show commands\n" + "1 Diagnostics\n" + " Corruption Troll - the DDCMP emulation includes a process that will\n" + " intentionally drop or corrupt some messages. This emulates the\n" + " less-than-perfect communications lines encountered in the real world,\n" + " and enables network monitoring software to see non-zero error counters.\n" + "\n" + " The troll selects messages with a probablility selected by the SET %U\n" + " CORRUPT command. The units are 0.1%%; that is, a value of 1 means that\n" + " every message has a 1/1000 chance of being selected to be corrupted\n" + " or discarded.\n" + "1 Restrictions\n" + " Real hardware synchronous connections could operate in Multi-Point mode.\n" + " Multi-Point mode was a way of sharing a single wire with multiple\n" + " destination systems or devices. Multi-Point mode is not currently\n" + " emulated by this or other simulated synchronous devices.\n" + "\n" + "1 Implementation\n" + " A real %D11 transports host generated protocol implemented data via a\n" + " synchronous connection, the emulated device makes a TCP (or UDP)\n" + " connection to another emulated device which either speaks DDCMP over the\n" + " TCP connection directly, or interfaces to a simulated computer where the\n" + " operating system speaks the DDCMP protocol on the wire.\n" + "\n" + " The %D11 can be used for point-to-point DDCMP connections carrying\n" + " DECnet and other types of networking, e.g. from ULTRIX or DSM.\n" + "1 Debugging\n" + " The simulator has a number of debug options, these are:\n" + "\n" + "++REG Shows whenever a CSR is programatically read or written\n" + "++++and the current value.\n" + "++INT Shows Interrupt activity.\n" + "++PKT Shows Packet activity.\n" + "++XMT Shows Transmitted data.\n" + "++RCV Shows Received data.\n" + "++MDM Shows Modem Signal Transitions.\n" + "++CON Shows connection activities.\n" + "++TRC Shows routine call traces.\n" + "++ASY Shows Asynchronous activities.\n" + "\n" + " To get a full trace use\n" + "\n" + "+sim> SET %D DEBUG\n" + "\n" + " However it is recommended to use the following when sending traces:\n" + "\n" + "+sim> SET %D DEBUG=REG;PKT;XMT;RCV;CON\n" + "\n" + "1 Related Devices\n" + " The %D11 can facilitate communication with other simh simulators which\n" + " have emulated synchronous network devices available. These include\n" + " the following:\n" + "\n" + "++DUP11* Unibus PDP11 simulators\n" + "++DPV11* Qbus PDP11 simulators\n" + "++KDP11* Unibus PDP11 simulators and PDP10 simulators\n" + "++DMR11 Unibus PDP11 simulators and Unibus VAX simulators\n" + "++DMC11 Unibus PDP11 simulators and Unibus VAX simulators\n" + "++DMP11 Unibus PDP11 simulators and Unibus VAX simulators\n" + "++DMV11 Qbus VAX simulators\n" + "\n" + "++* Indicates systems which have OS provided DDCMP implementations.\n" + ; +char busname[16]; +char devcount[16]; +char connectpoll[16]; + +sprintf (busname, UNIBUS ? "Unibus" : "Qbus"); +sprintf (devcount, "%d", DUP_LINES); +sprintf (connectpoll, "%d", DUP_CONNECT_POLL); + +return scp_help (st, dptr, uptr, flag, helpString, cptr, busname, devcount, connectpoll); } static t_stat dup_help_attach (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { -fprintf (st, "The communication line performs input and output through a TCP session\n"); -fprintf (st, "connected to a user-specified port. The ATTACH command specifies the\n"); -fprintf (st, "port to be used as well as the peer address:\n\n"); -fprintf (st, " sim> ATTACH %sn {interface:}port{,UDP},Connect=peerhost:port\n\n", dptr->name); -fprintf (st, "where port is a decimal number between 1 and 65535 that is not being used for\n"); -fprintf (st, "other TCP/IP activities.\n\n"); -fprintf (st, "Specifying symmetric attach configuration (with both a listen port and\n"); -fprintf (st, "a peer address) will cause the side receiving an incoming\n"); -fprintf (st, "connection to validate that the connection actually comes from the\n"); -fprintf (st, "connecction destination system.\n\n"); -fprintf (st, "A symmetric attach configuration is required when using UDP packet transport.\n\n"); -return SCPE_OK; +return dup_help (st, dptr, uptr, flag, DUP_HLP_ATTACH); } static char *dup_description (DEVICE *dptr) diff --git a/PDP11/pdp11_kmc.c b/PDP11/pdp11_kmc.c index e34b8490..482d3609 100644 --- a/PDP11/pdp11_kmc.c +++ b/PDP11/pdp11_kmc.c @@ -93,14 +93,6 @@ #define KMC_DIS 0 #endif -/* Data troll facility - * - * Enables data troll, which simulates imperfect links. - */ -#ifndef KMC_TROLL -#define KMC_TROLL 1 -#endif - /* Define DUP_RXRESYNC to disable/enable RCVEN at the expected times. * This is used to resynch the receiver, but I'm not sure if it would * cause the emulated DUP to lose data...especially with QSYNC @@ -479,10 +471,6 @@ static QH kmc_freecqHead[KMC_UNITS]; #define freecqHead kmc_freecqHead[k] static int32 kmc_freecqCount[KMC_UNITS]; #define freecqCount kmc_freecqCount[k] -#if KMC_TROLL -static int32 kmc_trollHungerLevel[KMC_UNITS]; -#define trollHungerLevel kmc_trollHungerLevel[k] -#endif /* *** End of per-KMC state *** */ @@ -502,10 +490,6 @@ static t_stat kmc_showDeviceCount (FILE *st, UNIT *txup, int32 val, void *desc); #endif static t_stat kmc_setLineSpeed (UNIT *txup, int32 val, char *cptr, void *desc); static t_stat kmc_showLineSpeed (FILE *st, UNIT *txup, int32 val, void *desc); -#if KMC_TROLL -static t_stat kmc_setTrollHunger (UNIT *txup, int32 val, char *cptr, void *desc); -static t_stat kmc_showTrollHunger (FILE *st, UNIT *txup, int32 val, void *desc); -#endif static t_stat kmc_showStatus (FILE *st, UNIT *up, int32 v, void *dp); static t_stat kmc_help (FILE *st, struct sim_device *dptr, @@ -603,10 +587,6 @@ MTAB kmc_mod[] = { #if KMC_UNITS > 1 { MTAB_XTD|MTAB_VDV|MTAB_VALR, 0, "DEVICES", "DEVICES=n", &kmc_setDeviceCount, &kmc_showDeviceCount, NULL, "Display number of KMC devices enabled" }, -#endif -#if KMC_TROLL - { MTAB_XTD|MTAB_VUN|MTAB_VALR|MTAB_NMO, 0, "TROLL", "TROLL=appetite", - &kmc_setTrollHunger, &kmc_showTrollHunger, NULL, "Appetite in milligulps" }, #endif { 0 }, }; @@ -689,9 +669,6 @@ static int32 kmc_BintAck (void); static t_bool kmc_printBufferIn (int32 k, DEVICE *dev, int32 line, t_bool rx, int32 count, int32 ba, uint16 sel6v); static t_bool kmc_printBDL(int32 k, uint32 dbits, DEVICE *dev, uint8 line, int32 ba, int prbuf); -#if KMC_TROLL -static t_bool kmc_feedTroll (int32 k, int32 line, uint8 *msg, t_bool rx); -#endif /* Environment */ static const char *kmc_verifyUcode (int32 k); @@ -721,9 +698,6 @@ static t_stat kmc_reset(DEVICE* dptr) { d->dupidx = -1; d->linespeed = DFLT_SPEED; } - for (k = 0; ((uint32)k) < kmc_dev.numunits; k++) { - trollHungerLevel = 0; - } } for (k = 0; ((uint32)k) < kmc_dev.numunits; k++) { @@ -1189,14 +1163,6 @@ static t_stat kmc_txService (UNIT *txup) { */ case TXMRDY: /* Data with OS-embedded HCRC */ d->txstate = TXACT; -#if KMC_TROLL - if (trollHungerLevel) { /* Troll in the house? */ - if (kmc_feedTroll (k, d->line, d->txmsg + d->txslen, TRUE)) { - kmc_txComplete (d->dupidx, 0); - TXDELAY (TXDONE, TXDONE_DELAY); - } - } -#endif assert (d->txmsg[d->txslen + 0] != DDCMP_ENQ); assert (((d->txmlen - d->txslen) > 8) && /* Data, length should match count */ (((size_t)(((d->txmsg[d->txslen + 2] & 077) << 8) | d->txmsg[d->txslen + 1])) == @@ -1210,14 +1176,6 @@ static t_stat kmc_txService (UNIT *txup) { case TXRDY: /* Control or DATA with KDP-CRCH */ d->txstate = TXACT; /* Note that DUP can complete before returning */ -#if KMC_TROLL - if (trollHungerLevel) { /* Troll in the house? */ - if (kmc_feedTroll (k, d->line, d->txmsg + d->txslen, TRUE)) { - kmc_txComplete (d->dupidx, 0); - TXDELAY (TXDONE, TXDONE_DELAY); - } - } -#endif if (d->txmsg[d->txslen + 0] == DDCMP_ENQ) { /* Control message */ assert ((d->txmlen - d->txslen) == 6); if (!dup_put_msg_bytes (d->dupidx, d->txmsg, d->txslen + 6, TRUE, TRUE)) { @@ -1366,14 +1324,6 @@ static t_stat kmc_rxService (UNIT *rxup) { break; } -#if KMC_TROLL - if (trollHungerLevel) { /* Troll in the house? */ - if (kmc_feedTroll (k, d->line, d->rxmsg, TRUE)) { - break; - } - } -#endif - d->rxstate = RXBDL; d->rxused = 0; @@ -2694,73 +2644,6 @@ static t_bool kmc_printBDL(int32 k, uint32 dbits, DEVICE *dev, uint8 line, int32 return TRUE; } -/* Evaluate the troll's appetite. - * - * A message can be eaten (dropped), nibbled (corrupted) or spared. - * - * The probability of a message not being spared is trollHungerLevel, - * expressed in milli-gulps - 0.1%. The troll selects which action - * to taken on selected messages with equal probability. - * - * Nibbled messages' CRCs are changed when possible to simplify - * identifying them when debugging. When it's too much work to - * find the CRC, the first byte of data is changed. The change - * is an XOR to make it possible to reconstruct the original data. - * - * A particularly unfortunate message can be nibbled by both - * the transmitter and receiver; thus the troll applies a direction- - * dependent pattern. - * - * Return TRUE if the troll ate the message. - * Return FALSE if the message was nibbled or spared. - */ -#if KMC_TROLL -static t_bool kmc_feedTroll (int32 k, int32 line, uint8 *msg, t_bool rx) { -#if defined(_POSIX_VERSION) || defined (_XOPEN_VERSION) - double r = (double)random(); - double rmax = (double)0x7fffffff; -#else - double r = rand(); - double rmax = (double)RAND_MAX; -#endif - - if (msg[0] == DDCMP_ENQ) { - int eat = 0 + (int) (2000.0 * (r / rmax)); - - if (eat <= (trollHungerLevel * 2)) { /* Hungry? */ - if (eat <= trollHungerLevel) { /* Eat the packet */ - sim_debug (DF_PKT, &kmc_dev, "KMC%u line %u: troll ate a %s control message\n", - k, line, (rx? "rx" : "tx")); - return TRUE; - } - sim_debug (DF_PKT, &kmc_dev, "KMC%u line %u: troll bit %d control CRC\n", - k, line, (rx? "rx" : "tx")); - msg[6] ^= rx? 0114: 0154; /* Eat the CRC */ - } - } else { - int eat = 0 + (int) (3000.0 * (r / rmax)); - - if (eat <= (trollHungerLevel * 3)) { /* Hungry? */ - if (eat <= trollHungerLevel) { /* Eat the packet */ - sim_debug (DF_PKT, &kmc_dev, "KMC%u line %u: troll ate a %s %s message\n", - k, line, (rx? "rx" : "tx"), ((msg[0] == DDCMP_SOH)? "data" : "maintenance")); - return TRUE; - } - if (eat <= (trollHungerLevel * 2)) { /* HCRC */ - sim_debug (DF_PKT, &kmc_dev, "KMC%u line %u: troll bit %s %s HCRC\n", - k, line, (rx? "rx" : "tx"), ((msg[0] == DDCMP_SOH)? "data" : "maintenance")); - msg[6] ^= rx? 0124: 0164; - } else { /* DCRC */ - sim_debug (DF_PKT, &kmc_dev, "KMC%u line %u: troll bit %s %s DCRC\n", - k, line, (rx? "rx" : "tx"), ((msg[0] == DDCMP_SOH)? "data" : "maintenance")); - msg[8] ^= rx? 0114: 0154; /* Rather than find the CRC, the first data byte will do */ - } - } - } - return FALSE; -} -#endif - /* Verify that the microcode image is one that this code knows how to emulate. * As far as I know, there was COMM IOP-DUP V1.0 and one patch, V1.0A. * This is the patched version, which I have verified by rebuilding the @@ -2991,45 +2874,6 @@ static t_stat kmc_showLineSpeed (FILE *st, UNIT *txup, int32 val, void *desc) { return SCPE_OK; } -#if KMC_TROLL -/* Manage the troll's appetite, in units of milli-gulps. - * - * See kmc_feedTroll for usage. - */ -static t_stat kmc_setTrollHunger (UNIT *txup, int32 val, char *cptr, void *desc) { - int32 k = txup->unit_kmc; - t_stat r; - int32 appetite; - - if (cptr == NULL) - return SCPE_ARG; - - appetite = (int32) get_uint (cptr, 10, 999, &r); - if (r != SCPE_OK) { - return r; - } - - trollHungerLevel = appetite; - - return SCPE_OK; -} - -/* Display the troll's appetite */ - -static t_stat kmc_showTrollHunger (FILE *st, UNIT *txup, int32 val, void *desc) { - int32 k = txup->unit_kmc; - - if (trollHungerLevel) { - fprintf (st, "Troll's share: %u milligulps (%.1f%% of messages processed)\n", - trollHungerLevel, ((double)trollHungerLevel)/10.0); - } else { - fprintf (st, "Troll is not at the table\n"); - } - - return SCPE_OK; -} -#endif - /* Show KMC status */ t_stat kmc_showStatus (FILE *st, UNIT *up, int32 v, void *dp) { diff --git a/sim_tmxr.h b/sim_tmxr.h index b244152d..208f539f 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -245,6 +245,7 @@ t_stat tmxr_stop_poll (void); void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize); extern FILE *sim_deb; /* debug file */ #define tmxr_debug(dbits, lp, msg, buf, bufsize) if (sim_deb && (lp)->mp && (lp)->mp->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) _tmxr_debug (dbits, lp, msg, buf, bufsize); else (void)0 +#define tmxr_debug_msg(dbits, lp, msg) if (sim_deb && (lp)->mp && (lp)->mp->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) sim_debug (dbits, (lp)->mp->dptr, msg); else (void)0 #define tmxr_debug_return(lp, val) if (sim_deb && (val) && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_RET & (lp)->mp->dptr->dctrl)) sim_debug (TMXR_DBG_RET, (lp)->mp->dptr, "Ln%d: 0x%x\n", (int)((lp)-(lp)->mp->ldsc), val); else (void)0 #define tmxr_debug_trace(mp, msg) if (sim_deb && (mp)->dptr && (TMXR_DBG_TRC & (mp)->dptr->dctrl)) sim_debug (TMXR_DBG_TRC, mp->dptr, "%s\n", (msg)); else (void)0 #define tmxr_debug_trace_line(lp, msg) if (sim_deb && (lp)->mp && (lp)->mp->dptr && (TMXR_DBG_TRC & (lp)->mp->dptr->dctrl)) sim_debug (TMXR_DBG_TRC, (lp)->mp->dptr, "Ln%d:%s\n", (int)((lp)-(lp)->mp->ldsc), (msg)); else (void)0