diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index 379c28ab..eaa2709f 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -156,9 +156,9 @@ Note 2: Root access will likely be needed to configure or start the vde Note 3: Simulators running using VDE networking can run without root privilege. -Linux (Ubuntu 10.04): +Linux (Ubuntu 11.10): apt-get install make - apt-get install libvdeplug-dev + apt-get install libvdeplug2-dev apt-get install vde2 vde_switch -s /tmp/switch1 -tap tap0 -m 666 diff --git a/ALTAIR/altair_cpu.c b/ALTAIR/altair_cpu.c index 196893c4..834006b4 100644 --- a/ALTAIR/altair_cpu.c +++ b/ALTAIR/altair_cpu.c @@ -366,7 +366,7 @@ int32 sim_instr (void) if ((OP & 0xCF) == 0x01) { /* LXI */ DAR = M[PC] & 0x00ff; PC++; - DAR = DAR | (M[PC] <<8) & 0xFF00;; + DAR = DAR | ((M[PC] <<8) & 0xFF00); putpair((OP >> 4) & 0x03, DAR); PC++; continue; diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c index fa5e5103..f6d71ffe 100644 --- a/AltairZ80/altairz80_net.c +++ b/AltairZ80/altairz80_net.c @@ -150,36 +150,33 @@ static t_stat net_reset(DEVICE *dptr) { } static t_stat net_attach(UNIT *uptr, char *cptr) { - uint32 i, ipa, ipp; - t_stat r = get_ipaddr(cptr, &ipa, &ipp); + uint32 i; + char host[CBUFSIZE], port[CBUFSIZE]; + t_stat r; + + r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), "3000", NULL); if (r != SCPE_OK) return SCPE_ARG; - if (ipa == 0) - ipa = 0x7F000001; /* localhost = 127.0.0.1 */ - if (ipp == 0) - ipp = 3000; - net_unit.u3 = ipp; - net_unit.u4 = ipa; net_reset(&net_dev); for (i = 0; i <= MAX_CONNECTIONS; i++) serviceDescriptor[i].ioSocket = 0; if (net_unit.flags & UNIT_SERVER) { net_unit.wait = NET_INIT_POLL_SERVER; - serviceDescriptor[1].masterSocket = sim_master_sock(ipp); + serviceDescriptor[1].masterSocket = sim_master_sock(cptr, NULL); if (serviceDescriptor[1].masterSocket == INVALID_SOCKET) return SCPE_IOERR; } else { net_unit.wait = NET_INIT_POLL_CLIENT; - serviceDescriptor[0].ioSocket = sim_connect_sock(ipa, ipp); + serviceDescriptor[0].ioSocket = sim_connect_sock(cptr, "localhost", "3000"); if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR; } net_unit.flags |= UNIT_ATT; - net_unit.filename = (char *) calloc(CBUFSIZE, sizeof (char)); /* alloc name buf */ + net_unit.filename = (char *) calloc(1, strlen(cptr)+1); /* alloc name buf */ if (net_unit.filename == NULL) return SCPE_MEM; - strncpy(net_unit.filename, cptr, CBUFSIZE); /* save name */ + strcpy(net_unit.filename, cptr); /* save name */ return SCPE_OK; } @@ -216,7 +213,7 @@ static t_stat net_svc(UNIT *uptr) { } } else if (serviceDescriptor[0].ioSocket == 0) { - serviceDescriptor[0].ioSocket = sim_connect_sock(net_unit.u4, net_unit.u3); + serviceDescriptor[0].ioSocket = sim_connect_sock(net_unit.filename, "localhost", "3000"); if (serviceDescriptor[0].ioSocket == INVALID_SOCKET) return SCPE_IOERR; printf("\rWaiting for server ... Type g (possibly twice) when ready" NLP); diff --git a/HP2100/hp2100_baci.c b/HP2100/hp2100_baci.c index 063705a6..0fa2d2c7 100644 --- a/HP2100/hp2100_baci.c +++ b/HP2100/hp2100_baci.c @@ -26,6 +26,7 @@ BACI 12966A BACI card 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Removed DEV_NET to allow restoration of listening port 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index 9ee83e32..d5126db4 100644 --- a/HP2100/hp2100_defs.h +++ b/HP2100/hp2100_defs.h @@ -81,6 +81,7 @@ #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wlogical-op-parentheses" +#pragma GCC diagnostic ignored "-Wbitwise-op-parentheses" #endif diff --git a/HP2100/hp2100_di_da.c b/HP2100/hp2100_di_da.c index 9ce38860..a3d73fdd 100644 --- a/HP2100/hp2100_di_da.c +++ b/HP2100/hp2100_di_da.c @@ -25,6 +25,7 @@ DA 12821A Disc Interface with Amigo disc drives + 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash 07-May-12 JDB Cancel the intersector delay if an untalk is received 29-Mar-12 JDB First release 04-Nov-11 JDB Created DA device @@ -757,7 +758,7 @@ switch (if_state [unit]) { /* dispatch the inte case disc_command: /* execute a disc command */ result = dl_service_drive (cvptr, uptr); /* service the disc unit */ - if (cvptr->opcode == clear) /* is this a Clear command? */ + if (cvptr->opcode == Clear) /* is this a Clear command? */ if_dsj [unit] = 2; /* indicate that the self test is complete */ if (cvptr->state != cntlr_busy) { /* has the controller stopped? */ @@ -857,7 +858,7 @@ switch (if_state [unit]) { /* dispatch the inte if (cvptr->length == 0 || cvptr->eod == SET) { /* is the data phase complete? */ uptr->PHASE = end_phase; /* set the end phase */ - if (cvptr->opcode == request_status) /* is it a Request Status command? */ + if (cvptr->opcode == Request_Status) /* is it a Request Status command? */ if_dsj [unit] = 0; /* clear the DSJ value */ if_state [unit] = command_exec; /* set to execute the command */ @@ -981,7 +982,7 @@ if (result == SCPE_IERR && DEBUG_PRI (da_dev, DEB_RWSC)) { /* did an internal e if (if_state [unit] == idle) { /* is the command now complete? */ if (if_command [unit] == disc_command) { /* did a disc command complete? */ - if (cvptr->opcode != end) /* yes; if the command was not End, */ + if (cvptr->opcode != End) /* yes; if the command was not End, */ di_poll_response (da, unit, SET); /* then enable PPR */ if (DEBUG_PRI (da_dev, DEB_RWSC)) @@ -1267,7 +1268,7 @@ result = dl_load_unload (&icd_cntlr [unit], uptr, load); /* load or unload th if (result == SCPE_OK && ! load) { /* was the unload successful? */ icd_cntlr [unit].status = drive_attention; /* set Drive Attention status */ - if (uptr->OP == end) /* is the controller in idle state 2? */ + if (uptr->OP == End) /* is the controller in idle state 2? */ di_poll_response (da, unit, SET); /* enable PPR */ } diff --git a/HP2100/hp2100_ds.c b/HP2100/hp2100_ds.c index 29df4589..f42a7c8c 100644 --- a/HP2100/hp2100_ds.c +++ b/HP2100/hp2100_ds.c @@ -26,6 +26,7 @@ DS 13037D/13175D disc controller/interface + 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash 29-Mar-12 JDB Rewritten to use the MAC/ICD disc controller library ioIOO now notifies controller service of parameter output 14-Feb-12 JDB Corrected SRQ generation and FIFO under/overrun detection @@ -705,10 +706,10 @@ result = dl_service_drive (&mac_cntlr, uptr); /* service the drive */ if ((CNTLR_PHASE) uptr->PHASE == data_phase) /* is the drive in the data phase? */ switch ((CNTLR_OPCODE) uptr->OP) { /* dispatch the current operation */ - case read: /* read operations */ - case read_full_sector: - case read_with_offset: - case read_without_verify: + case Read: /* read operations */ + case Read_Full_Sector: + case Read_With_Offset: + case Read_Without_Verify: if (mac_cntlr.length == 0 || ds.edt == SET) { /* is the data phase complete? */ mac_cntlr.eod = ds.edt; /* set EOD if DCPC is done */ uptr->PHASE = end_phase; /* set the end phase */ @@ -729,9 +730,9 @@ if ((CNTLR_PHASE) uptr->PHASE == data_phase) /* is the drive in the d break; - case write: /* write operations */ - case write_full_sector: - case initialize: + case Write: /* write operations */ + case Write_Full_Sector: + case Initialize: if (entry_phase == start_phase) { /* is this the phase transition? */ ds.srq = SET; /* start the DCPC transfer */ ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ @@ -850,19 +851,19 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current case end_phase: /* start and end on the same phase */ switch (opcode) { /* dispatch the current operation */ - case request_status: - case request_sector_address: - case address_record: - case request_syndrome: - case load_tio_register: - case request_disc_address: - case end: + case Request_Status: + case Request_Sector_Address: + case Address_Record: + case Request_Syndrome: + case Load_TIO_Register: + case Request_Disc_Address: + case End: break; /* complete the operation without setting the flag */ - case clear: - case set_file_mask: - case wakeup: + case Clear: + case Set_File_Mask: + case Wakeup: ds_io (&ds_dib, ioENF, 0); /* complete the operation and set the flag */ break; @@ -877,11 +878,11 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current case data_phase: switch (opcode) { /* dispatch the current operation */ - case seek: /* operations that accept parameters */ - case verify: - case address_record: - case read_with_offset: - case load_tio_register: + case Seek: /* operations that accept parameters */ + case Verify: + case Address_Record: + case Read_With_Offset: + case Load_TIO_Register: buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */ mac_cntlr.length--; /* count it */ @@ -891,7 +892,7 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current else { /* all parameters have been received */ uptr->PHASE = end_phase; /* set the end phase */ - if (opcode == read_with_offset) /* a Read With Offset command sets the flag */ + if (opcode == Read_With_Offset) /* a Read With Offset command sets the flag */ ds_io (&ds_dib, ioENF, 0); /* to indicate that offsetting is complete */ start_command (); /* the command is now ready to execute */ @@ -899,10 +900,10 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current break; - case request_status: /* operations that supply parameters */ - case request_sector_address: - case request_syndrome: - case request_disc_address: + case Request_Status: /* operations that supply parameters */ + case Request_Sector_Address: + case Request_Syndrome: + case Request_Disc_Address: if (mac_cntlr.length) { /* are there more words to return? */ fifo_load (buffer [mac_cntlr.index++]); /* load the next word into the FIFO */ mac_cntlr.length--; /* count it */ @@ -1258,7 +1259,7 @@ unit = GET_S1UNIT (mac_cntlr.spd_unit); /* get the (prepared) un if (unit <= DL_MAXDRIVE) /* is the unit number valid? */ drive_command = (CNTLR_OPCODE) ds_unit [unit].OP; /* get the opcode from the unit that will be used */ else /* the unit is invalid, so the command will not start */ - drive_command = end; /* but the compiler doesn't know this! */ + drive_command = End; /* but the compiler doesn't know this! */ uptr = dl_start_command (&mac_cntlr, ds_unit, DL_MAXDRIVE); /* ask the controller to start the command */ diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 32e77f17..5a5c8cad 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -25,6 +25,7 @@ IPLI, IPLO 12875A interprocessor link + 25-Oct-12 JDB Removed DEV_NET to allow restoration of listening ports 09-May-12 JDB Separated assignments from conditional expressions 10-Feb-12 JDB Deprecated DEVNO in favor of SC Added CARD_INDEX casts to dib.card_index @@ -188,7 +189,7 @@ DEVICE ipli_dev = { 1, 10, 31, 1, 16, 16, &tmxr_ex, &tmxr_dep, &ipl_reset, &ipl_boot, &ipl_attach, &ipl_detach, - &ipli_dib, DEV_NET | DEV_DISABLE | DEV_DIS | DEV_DEBUG, + &ipli_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, ipl_deb, NULL, NULL }; @@ -217,7 +218,7 @@ DEVICE iplo_dev = { 1, 10, 31, 1, 16, 16, &tmxr_ex, &tmxr_dep, &ipl_reset, &ipl_boot, &ipl_attach, &ipl_detach, - &iplo_dib, DEV_NET | DEV_DISABLE | DEV_DIS | DEV_DEBUG, + &iplo_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, 0, ipl_deb, NULL, NULL }; @@ -570,56 +571,56 @@ return SCPE_OK; t_stat ipl_attach (UNIT *uptr, char *cptr) { SOCKET newsock; -uint32 i, t, ipa, ipp, oldf; -char *tptr; +uint32 i, t, oldf; +char host[CBUFSIZE], port[CBUFSIZE], hostport[2*CBUFSIZE+3]; +char *tptr = NULL; t_stat r; -r = get_ipaddr (cptr, &ipa, &ipp); -if ((r != SCPE_OK) || (ipp == 0)) - return SCPE_ARG; oldf = uptr->flags; if (oldf & UNIT_ATT) ipl_detach (uptr); if ((sim_switches & SWMASK ('C')) || ((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) { - if (ipa == 0) - ipa = 0x7F000001; - newsock = sim_connect_sock (ipa, ipp); + r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), NULL, NULL); + if ((r != SCPE_OK) || (port[0] == '\0')) + return SCPE_ARG; + sprintf(hostport, "%s%s%s%s%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", host[0] ? ":" : "", port); + newsock = sim_connect_sock (hostport, NULL, NULL); if (newsock == INVALID_SOCKET) return SCPE_IOERR; - printf ("Connecting to IP address %d.%d.%d.%d, port %d\n", - (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, - (ipa >> 8) & 0xff, ipa & 0xff, ipp); + printf ("Connecting to %s\n", hostport); if (sim_log) fprintf (sim_log, - "Connecting to IP address %d.%d.%d.%d, port %d\n", - (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, - (ipa >> 8) & 0xff, ipa & 0xff, ipp); + "Connecting to %s\n", hostport); uptr->flags = uptr->flags | UNIT_ACTV; uptr->LSOCKET = 0; uptr->DSOCKET = newsock; } else { - if (ipa != 0) + r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); + if (r != SCPE_OK) return SCPE_ARG; - newsock = sim_master_sock (ipp); + sprintf(hostport, "%s%s%s%s%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", host[0] ? ":" : "", port); + newsock = sim_master_sock (hostport, &r); + if (r != SCPE_OK) + return r; if (newsock == INVALID_SOCKET) return SCPE_IOERR; - printf ("Listening on port %d\n", ipp); + printf ("Listening on port %s\n", hostport); if (sim_log) - fprintf (sim_log, "Listening on port %d\n", ipp); + fprintf (sim_log, "Listening on port %s\n", hostport); uptr->flags = uptr->flags & ~UNIT_ACTV; uptr->LSOCKET = newsock; uptr->DSOCKET = 0; } uptr->IBUF = uptr->OBUF = 0; uptr->flags = (uptr->flags | UNIT_ATT) & ~(UNIT_ESTB | UNIT_HOLD); -tptr = (char *) malloc (strlen (cptr) + 1); /* get string buf */ +tptr = (char *) malloc (strlen (hostport) + 1); /* get string buf */ if (tptr == NULL) { /* no memory? */ ipl_detach (uptr); /* close sockets */ return SCPE_MEM; } -strcpy (tptr, cptr); /* copy ipaddr:port */ +strcpy (tptr, hostport); /* copy ipaddr:port */ uptr->filename = tptr; /* save */ sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */ if (sim_switches & SWMASK ('W')) { /* wait? */ diff --git a/HP2100/hp2100_mpx.c b/HP2100/hp2100_mpx.c index a4d91dd9..3c0a0180 100644 --- a/HP2100/hp2100_mpx.c +++ b/HP2100/hp2100_mpx.c @@ -26,6 +26,7 @@ MPX 12792C 8-channel multiplexer card 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Removed DEV_NET to allow restoration of listening port 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index f341a51d..672ba3cf 100644 --- a/HP2100/hp2100_mux.c +++ b/HP2100/hp2100_mux.c @@ -26,6 +26,7 @@ MUX,MUXL,MUXM 12920A terminal multiplexor 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Removed DEV_NET to allow restoration of listening port 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines diff --git a/HP2100/hp_disclib.c b/HP2100/hp_disclib.c index d6320e82..cb3fd649 100644 --- a/HP2100/hp_disclib.c +++ b/HP2100/hp_disclib.c @@ -24,6 +24,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. + 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash 07-May-12 JDB Corrected end-of-track delay time logic 02-May-12 JDB First release 09-Nov-11 JDB Created disc controller common library from DS simulator @@ -594,8 +595,8 @@ set_timer (cvptr, CLEAR); /* stop the command wait opcode = GET_OPCODE (cvptr->buffer [0]); /* get the opcode from the command */ -if (opcode > last_opcode) /* is the opcode invalid? */ - props = &cmd_props [invalid_opcode]; /* undefined commands clear prior status */ +if (opcode > Last_Opcode) /* is the opcode invalid? */ + props = &cmd_props [Invalid_Opcode]; /* undefined commands clear prior status */ else /* the opcode is potentially valid */ props = &cmd_props [opcode]; /* get the command properties */ @@ -794,7 +795,7 @@ cvptr->eod = CLEAR; /* clear the end of data switch (cvptr->opcode) { /* dispatch the command */ - case cold_load_read: + case Cold_Load_Read: cvptr->cylinder = 0; /* set the cylinder address to 0 */ cvptr->head = GET_CHEAD (cvptr->buffer [0]); /* set the head */ cvptr->sector = GET_CSECT (cvptr->buffer [0]); /* and sector from the command */ @@ -802,7 +803,7 @@ switch (cvptr->opcode) { /* dispatch the command if (is_seeking) { /* if a seek is in progress, */ uptr->STAT |= DL_S2SC; /* a Seek Check occurs */ cvptr->file_mask = DL_FSPEN; /* enable sparing */ - uptr->OP = read; /* start the read on the seek completion */ + uptr->OP = Read; /* start the read on the seek completion */ uptr->PHASE = start_phase; /* and reset the command phase */ return uptr; /* to allow the seek to complete normally */ } @@ -813,7 +814,7 @@ switch (cvptr->opcode) { /* dispatch the command break; - case seek: + case Seek: cvptr->cylinder = cvptr->buffer [1]; /* get the supplied cylinder */ cvptr->head = GET_HEAD (cvptr->buffer [2]); /* and head */ cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector addresses */ @@ -827,7 +828,7 @@ switch (cvptr->opcode) { /* dispatch the command break; - case request_status: + case Request_Status: cvptr->buffer [0] = /* set the Status-1 value */ cvptr->spd_unit | SET_S1STAT (cvptr->status); /* into the buffer */ @@ -854,12 +855,12 @@ switch (cvptr->opcode) { /* dispatch the command break; - case request_disc_address: + case Request_Disc_Address: set_address (cvptr, 0); /* return the CHS values in buffer 0-1 */ break; - case request_sector_address: + case Request_Sector_Address: if (unit > unit_limit) /* if the unit number is invalid */ rptr = NULL; /* it does not correspond to a unit */ else /* otherwise, the unit is valid */ @@ -872,7 +873,7 @@ switch (cvptr->opcode) { /* dispatch the command break; - case request_syndrome: + case Request_Syndrome: cvptr->buffer [0] = /* return the Status-1 value in buffer 0 */ cvptr->spd_unit | SET_S1STAT (cvptr->status); @@ -885,7 +886,7 @@ switch (cvptr->opcode) { /* dispatch the command break; - case address_record: + case Address_Record: cvptr->cylinder = cvptr->buffer [1]; /* get the supplied cylinder */ cvptr->head = GET_HEAD (cvptr->buffer [2]); /* and head */ cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector addresses */ @@ -893,7 +894,7 @@ switch (cvptr->opcode) { /* dispatch the command break; - case set_file_mask: + case Set_File_Mask: cvptr->file_mask = GET_FMASK (cvptr->buffer [0]); /* get the supplied file mask */ if (cvptr->type == MAC) /* if this is a MAC controller, */ @@ -901,14 +902,14 @@ switch (cvptr->opcode) { /* dispatch the command break; - case initialize: + case Initialize: if (uptr) /* if the unit is valid, */ cvptr->spd_unit |= /* merge the SPD flags */ SET_S1SPD (GET_SPD (cvptr->buffer [0])); /* from the command word */ break; - case verify: + case Verify: cvptr->verify_count = cvptr->buffer [1]; /* get the supplied sector count */ break; @@ -1078,35 +1079,35 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case start_phase: switch (opcode) { /* dispatch the current operation */ - case recalibrate: - case seek: + case Recalibrate: + case Seek: if (start_seek (cvptr, uptr, opcode, end_phase) /* start the seek; if it succeeded, */ && (cvptr->type == MAC)) /* and this a MAC controller, */ dl_idle_controller (cvptr); /* then go idle until it completes */ break; - case cold_load_read: - if (start_seek (cvptr, uptr, read, start_phase)) /* start the seek; did it succeed? */ + case Cold_Load_Read: + if (start_seek (cvptr, uptr, Read, start_phase)) /* start the seek; did it succeed? */ cvptr->file_mask = DL_FSPEN; /* set sparing enabled now */ break; - case read: - case read_with_offset: - case read_without_verify: + case Read: + case Read_With_Offset: + case Read_Without_Verify: cvptr->length = DL_WPSEC; /* transfer just the data */ result = start_read (cvptr, uptr); /* start the sector read */ break; - case read_full_sector: + case Read_Full_Sector: cvptr->length = DL_WPFSEC; /* transfer the header/data/trailer */ result = start_read (cvptr, uptr); /* start the sector read */ break; - case verify: + case Verify: cvptr->length = 0; /* no data transfer needed */ result = start_read (cvptr, uptr); /* start the sector read */ @@ -1118,29 +1119,29 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ break; - case write: - case initialize: + case Write: + case Initialize: cvptr->length = DL_WPSEC; /* transfer just the data */ start_write (cvptr, uptr); /* start the sector write */ break; - case write_full_sector: + case Write_Full_Sector: cvptr->length = DL_WPFSEC; /* transfer the header/data/trailer */ start_write (cvptr, uptr); /* start the sector write */ break; - case request_status: - case request_sector_address: - case clear: - case address_record: - case request_syndrome: - case set_file_mask: - case load_tio_register: - case request_disc_address: - case end: - case wakeup: + case Request_Status: + case Request_Sector_Address: + case Clear: + case Address_Record: + case Request_Syndrome: + case Set_File_Mask: + case Load_TIO_Register: + case Request_Disc_Address: + case End: + case Wakeup: dl_service_controller (cvptr, uptr); /* the controller service handles these */ break; @@ -1154,13 +1155,13 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case data_phase: switch (opcode) { /* dispatch the current operation */ - case read: - case read_full_sector: - case read_with_offset: - case read_without_verify: - case write: - case write_full_sector: - case initialize: + case Read: + case Read_Full_Sector: + case Read_With_Offset: + case Read_Without_Verify: + case Write: + case Write_Full_Sector: + case Initialize: break; /* data transfers are handled by the caller */ @@ -1174,8 +1175,8 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case end_phase: switch (opcode) { /* dispatch the operation command */ - case recalibrate: - case seek: + case Recalibrate: + case Seek: if (cvptr->type == ICD) /* is this an ICD controller? */ dl_end_command (cvptr, drive_attention); /* seeks end with Drive Attention status */ else /* if not an ICD controller, */ @@ -1183,22 +1184,22 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ break; - case read: - case read_full_sector: - case read_with_offset: + case Read: + case Read_Full_Sector: + case Read_With_Offset: end_read (cvptr, uptr); /* end the sector read */ break; - case read_without_verify: + case Read_Without_Verify: if (cvptr->sector == 0) /* have we reached the end of the track? */ - uptr->OP = read; /* begin verifying the next time */ + uptr->OP = Read; /* begin verifying the next time */ end_read (cvptr, uptr); /* end the sector read */ break; - case verify: + case Verify: cvptr->verify_count = /* decrement the count */ (cvptr->verify_count - 1) & DMASK; /* modulo 65536 */ @@ -1209,16 +1210,16 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ break; - case write: - case write_full_sector: - case initialize: + case Write: + case Write_Full_Sector: + case Initialize: result = end_write (cvptr, uptr); /* end the sector write */ break; - case request_status: - case request_sector_address: - case request_disc_address: + case Request_Status: + case Request_Sector_Address: + case Request_Disc_Address: dl_service_controller (cvptr, uptr); /* the controller service handles these */ break; @@ -1278,33 +1279,33 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case start_phase: case end_phase: switch (opcode) { /* dispatch the current operation */ - case request_status: + case Request_Status: dl_end_command (cvptr, cvptr->status); /* the command completes with no status change */ break; - case clear: + case Clear: dl_clear_controller (cvptr, uptr, soft_clear); /* clear the controller */ dl_end_command (cvptr, normal_completion); /* the command is complete */ break; - case request_sector_address: - case address_record: - case request_syndrome: - case set_file_mask: - case load_tio_register: - case request_disc_address: + case Request_Sector_Address: + case Address_Record: + case Request_Syndrome: + case Set_File_Mask: + case Load_TIO_Register: + case Request_Disc_Address: dl_end_command (cvptr, normal_completion); /* the command is complete */ break; - case end: + case End: dl_idle_controller (cvptr); /* the command completes with the controller idle */ break; - case wakeup: + case Wakeup: dl_end_command (cvptr, unit_available); /* the command completes with Unit Available status */ break; @@ -1319,11 +1320,11 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case data_phase: switch (opcode) { /* dispatch the current operation */ - case seek: - case verify: - case address_record: - case read_with_offset: - case load_tio_register: + case Seek: + case Verify: + case Address_Record: + case Read_With_Offset: + case Load_TIO_Register: if (cvptr->length > 1) /* at least one more parameter to input? */ set_timer (cvptr, SET); /* restart the timer for the next parameter */ else /* this is the last one */ @@ -1331,10 +1332,10 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ break; - case request_status: - case request_sector_address: - case request_syndrome: - case request_disc_address: + case Request_Status: + case Request_Sector_Address: + case Request_Syndrome: + case Request_Disc_Address: if (cvptr->length > 0) /* at least one more to parameter output? */ set_timer (cvptr, SET); /* restart the timer for the next parameter */ else /* this is the last one */ @@ -1505,8 +1506,8 @@ for (unit = 0; unit < unit_count; unit++) { /* loop through the unit if (!(uptr->flags & UNIT_DIS)) { /* is the unit enabled? */ if (clear_type == hard_clear /* a hard clear cancels */ - && uptr->OP != seek /* only if not seeking */ - && uptr->OP != recalibrate) /* or recalibrating */ + && uptr->OP != Seek /* only if not seeking */ + && uptr->OP != Recalibrate) /* or recalibrating */ sim_cancel (uptr); /* cancel the service */ uptr->STAT &= ~DL_S2CPS; /* do "Controller Preset" for the unit */ @@ -1597,7 +1598,7 @@ return SCPE_OK; CNTLR_CLASS dl_classify (CNTLR_VARS cntlr) { if (cntlr.type <= last_type /* if the controller type is legal */ - && cntlr.opcode <= last_opcode /* and the opcode is legal */ + && cntlr.opcode <= Last_Opcode /* and the opcode is legal */ && cmd_props [cntlr.opcode].valid [cntlr.type]) /* and is defined for this controller, */ return cmd_props [cntlr.opcode].classification; /* then return the command classification */ else /* the type or opcode is illegal */ @@ -1615,7 +1616,7 @@ else /* the type or opcode is const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode) { if (controller <= last_type /* if the controller type is legal */ - && opcode <= last_opcode /* and the opcode is legal */ + && opcode <= Last_Opcode /* and the opcode is legal */ && cmd_props [opcode].valid [controller]) /* and is defined for this controller, */ return opcode_name [opcode]; /* then return the opcode name */ else /* the type or opcode is illegal, */ @@ -1776,7 +1777,7 @@ if (cvptr->eod == SET) { /* is the end of data in return SCPE_OK; } -if (opcode == read_full_sector) { /* are we starting a Read Full Sector command? */ +if (opcode == Read_Full_Sector) { /* are we starting a Read Full Sector command? */ if (cvptr->type == ICD) /* is this an ICD controller? */ cvptr->buffer [0] = 0100377; /* ICD does not support ECC */ else @@ -1789,7 +1790,7 @@ if (opcode == read_full_sector) { /* are we starting a Rea else { /* it's another read command */ offset = 0; /* data starts at the beginning */ - verify = (opcode != read_without_verify); /* set for address verification unless it's a RWV */ + verify = (opcode != Read_Without_Verify); /* set for address verification unless it's a RWV */ } if (! position_sector (cvptr, uptr, verify)) /* position the sector */ @@ -1911,7 +1912,7 @@ return; static void start_write (CVPTR cvptr, UNIT *uptr) { -const t_bool verify = (CNTLR_OPCODE) uptr->OP == write; /* only Write verifies the sector address */ +const t_bool verify = (CNTLR_OPCODE) uptr->OP == Write; /* only Write verifies the sector address */ if ((uptr->flags & UNIT_WPROT) /* is the unit write protected, */ || !verify && !(uptr->flags & UNIT_FMT)) /* or is formatting required but not enabled? */ @@ -1959,7 +1960,7 @@ static t_stat end_write (CVPTR cvptr, UNIT *uptr) uint32 count; uint16 pad; const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; -const uint32 offset = (opcode == write_full_sector ? 3 : 0); +const uint32 offset = (opcode == Write_Full_Sector ? 3 : 0); if (uptr->flags & UNIT_UNLOAD) { /* if the drive is not ready, */ dl_end_command (cvptr, access_not_ready); /* terminate the command with an error */ @@ -2200,7 +2201,7 @@ if (uptr->flags & UNIT_UNLOAD) { /* are the heads unloade return FALSE; /* as the drive was not ready */ } -if ((CNTLR_OPCODE) uptr->OP == recalibrate) /* is the unit recalibrating? */ +if ((CNTLR_OPCODE) uptr->OP == Recalibrate) /* is the unit recalibrating? */ target_cylinder = 0; /* seek to cylinder 0 and don't reset the EOC flag */ else { /* it's a Seek command or an auto-seek request */ diff --git a/HP2100/hp_disclib.h b/HP2100/hp_disclib.h index 90b2d82b..fb5d6ef8 100644 --- a/HP2100/hp_disclib.h +++ b/HP2100/hp_disclib.h @@ -24,6 +24,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. + 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash 07-May-12 JDB Added end-of-track delay time as a controller variable 02-May-12 JDB First release 09-Nov-11 JDB Created disc controller common library from DS simulator @@ -206,29 +207,29 @@ typedef enum { /* Controller opcodes */ typedef enum { - cold_load_read = 000, - recalibrate = 001, - seek = 002, - request_status = 003, - request_sector_address = 004, - read = 005, - read_full_sector = 006, - verify = 007, - write = 010, - write_full_sector = 011, - clear = 012, - initialize = 013, - address_record = 014, - request_syndrome = 015, - read_with_offset = 016, - set_file_mask = 017, - invalid_opcode = 020, - read_without_verify = 022, - load_tio_register = 023, - request_disc_address = 024, - end = 025, - wakeup = 026, - last_opcode = wakeup /* last valid opcode */ + Cold_Load_Read = 000, + Recalibrate = 001, + Seek = 002, + Request_Status = 003, + Request_Sector_Address = 004, + Read = 005, + Read_Full_Sector = 006, + Verify = 007, + Write = 010, + Write_Full_Sector = 011, + Clear = 012, + Initialize = 013, + Address_Record = 014, + Request_Syndrome = 015, + Read_With_Offset = 016, + Set_File_Mask = 017, + Invalid_Opcode = 020, + Read_Without_Verify = 022, + Load_TIO_Register = 023, + Request_Disc_Address = 024, + End = 025, + Wakeup = 026, + Last_Opcode = Wakeup /* last valid opcode */ } CNTLR_OPCODE; #define DL_OPCODE_MASK 037 @@ -353,7 +354,7 @@ typedef CNTLR_VARS *CVPTR; /* pointer to controller */ #define CNTLR_INIT(ctype,bufptr,auxptr) \ - (ctype), cntlr_idle, end, normal_completion, \ + (ctype), cntlr_idle, End, normal_completion, \ CLEAR, CLEAR, \ 0, 0, 0, 0, 0, 0, 0, 0, \ (bufptr), 0, 0, (auxptr), \ diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c index 7bd64b70..255dccd5 100644 --- a/I1401/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -398,7 +398,7 @@ static const unsigned char boot_rom[] = { t_stat cdr_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_IS; for (i = 0; i < CDR_WIDTH; i++) /* clear buffer */ diff --git a/I1620/i1620_pt.c b/I1620/i1620_pt.c index 42a1ac63..88323ade 100644 --- a/I1620/i1620_pt.c +++ b/I1620/i1620_pt.c @@ -348,7 +348,7 @@ return SCPE_OK; /* Bootstrap routine */ -const static uint8 boot_rom[] = { +static const uint8 boot_rom[] = { 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* NOP */ 3, 6, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, /* RNPT 31 */ 2, 5, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, /* TD 71,loc */ @@ -363,7 +363,7 @@ const static uint8 boot_rom[] = { t_stat ptr_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint32 saved_PC; for (i = 0; i < BOOT_LEN; i++) diff --git a/I7094/i7094_com.c b/I7094/i7094_com.c index 8f0d4e7c..c6e2c7e6 100644 --- a/I7094/i7094_com.c +++ b/I7094/i7094_com.c @@ -183,10 +183,10 @@ uint32 com_chob_v = 0; /* valid flag */ t_uint64 com_buf[COM_BUFSIZ]; /* channel buffer */ LISTHD com_free; /* free list */ uint32 com_not_ret[COM_TLINES] = { 0 }; /* chars not returned */ -LISTHD com_inpq[COM_TLINES] = { 0 }; /* input queues */ -LISTHD com_outq[COM_TLINES] = { 0 }; /* output queues */ +LISTHD com_inpq[COM_TLINES] = { {0} }; /* input queues */ +LISTHD com_outq[COM_TLINES] = { {0} }; /* output queues */ LISTENT com_pkt[COM_PKTSIZ]; /* character packets */ -TMLN com_ldsc[COM_MLINES] = { 0 }; /* line descriptors */ +TMLN com_ldsc[COM_MLINES] = { {0} }; /* line descriptors */ TMXR com_desc = { COM_MLINES, 0, 0, com_ldsc }; /* mux descriptor */ /* Even parity truth table */ diff --git a/Ibm1130/ibm1130_cpu.c b/Ibm1130/ibm1130_cpu.c index d35bbcbd..bcc5ad19 100644 --- a/Ibm1130/ibm1130_cpu.c +++ b/Ibm1130/ibm1130_cpu.c @@ -768,7 +768,7 @@ t_stat sim_instr (void) CCC--; } C = (CCC != 0); - WriteIndex(TAG, ReadIndex(TAG) & 0xFF00 | CCC); /* put 6 bits back into low byte of index register */ + WriteIndex(TAG, (ReadIndex(TAG) & 0xFF00) | CCC); /* put 6 bits back into low byte of index register */ break; } /* if TAG == 0, fall through and treat like normal shift SLT */ @@ -814,8 +814,8 @@ t_stat sim_instr (void) while (CCC > 0) { xbit = (ACC & 0x0001) << 15; abit = (ACC & 0x8000); - ACC = (ACC >> 1) & 0x7FFF | abit; - EXT = (EXT >> 1) & 0x7FFF | xbit; + ACC = ((ACC >> 1) & 0x7FFF) | abit; + EXT = ((EXT >> 1) & 0x7FFF) | xbit; CCC--; } break; @@ -824,8 +824,8 @@ t_stat sim_instr (void) while (CCC > 0) { abit = (EXT & 0x0001) << 15; xbit = (ACC & 0x0001) << 15; - ACC = (ACC >> 1) & 0x7FFF | abit; - EXT = (EXT >> 1) & 0x7FFF | xbit; + ACC = ((ACC >> 1) & 0x7FFF) | abit; + EXT = ((EXT >> 1) & 0x7FFF) | xbit; CCC--; } break; diff --git a/Ibm1130/ibm1130_sca.c b/Ibm1130/ibm1130_sca.c index b0e8e293..8310ac40 100644 --- a/Ibm1130/ibm1130_sca.c +++ b/Ibm1130/ibm1130_sca.c @@ -85,9 +85,6 @@ #include "ibm1130_defs.h" #include "sim_sock.h" /* include path must include main simh directory */ #include -#ifndef INADDR_NONE -#define INADDR_NONE ((unsigned long)-1) -#endif #define DEBUG_SCA_FLUSH 0x0001 /* debugging options */ #define DEBUG_SCA_TRANSMIT 0x0002 @@ -106,7 +103,7 @@ /* #define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_TRANSMIT|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_RECEIVE_SYNC|DEBUG_SCA_RECEIVE_DATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW) */ #define DEBUG_SCA (DEBUG_SCA_TIMERS|DEBUG_SCA_FLUSH|DEBUG_SCA_CHECK_INDATA|DEBUG_SCA_XIO_INITR|DEBUG_SCA_XIO_INITW) -#define SCA_DEFAULT_PORT 2703 /* default socket, This is the number of the IBM 360's BSC device */ +#define SCA_DEFAULT_PORT "2703" /* default socket, This is the number of the IBM 360's BSC device */ #define MAX_SYNS 100 /* number of consecutive syn's after which we stop buffering them */ @@ -164,7 +161,7 @@ static uint32 sca_state = SCA_STATE_IDLE; static uint8 sichar = 0; /* sync/idle character */ static uint8 rcvd_char = 0; /* most recently received character */ static uint8 sca_frame = 8; -static uint16 sca_port = SCA_DEFAULT_PORT; /* listening port number */ +static char sca_port[CBUFSIZE]; /* listening port */ static int32 sca_keepalive = 0; /* keepalive SYN packet period in msec, default = 0 (disabled) */ static SCA_TIMER_STATE sca_timer_state[3]; /* current timer state */ static int sca_timer_endtime[3]; /* clocktime when timeout is to occur if state is RUNNING */ @@ -221,7 +218,7 @@ REG sca_reg[] = { /* DEVICE STATE/SETTABLE PARAMETERS: */ { DRDATA (SCASTATE, sca_state, 32), PV_LEFT }, /* current state */ { DRDATA (CTIME, sca_cwait, 32), PV_LEFT }, /* inter-character wait */ { DRDATA (ITIME, sca_iwait, 32), PV_LEFT }, /* idle wait (polling interval for socket connects) */ - { DRDATA (SCASOCKET, sca_port, 16), PV_LEFT }, /* listening port number */ + { BRDATA (SCASOCKET, sca_port, 8, 8, sizeof(sca_port)) }, /* listening port number */ { DRDATA (KEEPALIVE, sca_keepalive, 32), PV_LEFT }, /* keepalive packet period in msec */ { NULL } }; @@ -317,7 +314,7 @@ static void sca_socket_error (void) free(sca_unit.filename); if (sca_unit.flags & UNIT_LISTEN) { - sprintf(name, "(Listening on port %d)", sca_port); + sprintf(name, "(Listening on port %s)", sca_port); sca_unit.filename = mstring(name); printf("%s\n", name); } @@ -454,99 +451,75 @@ static t_stat sca_reset (DEVICE *dptr) static t_stat sca_attach (UNIT *uptr, char *cptr) { + char host[CBUFSIZE], port[CBUFSIZE]; t_bool do_listen; - char *colon; - uint32 ipaddr; - int32 port; - struct hostent *he; - char name[256]; - static SOCKET sdummy = INVALID_SOCKET; - fd_set wr_set, err_set; + char name[CBUFSIZE]; + t_stat r; do_listen = sim_switches & SWMASK('L'); /* -l means listen mode */ if (sca_unit.flags & UNIT_ATT) /* if already attached, detach */ detach_unit(&sca_unit); - if (do_listen) { /* if listen mode, string specifies socket number (only; otherwise it's a dummy argument) */ - if (isdigit(*cptr)) { /* if digits specified, extract port number */ - port = atoi(cptr); - if (port <= 0 || port > 65535) - return SCPE_ARG; - else - sca_port = port; - } + if (do_listen) { /* if listen mode, string specifies port number (only; otherwise it's a dummy argument) */ + r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL); + if (r != SCPE_OK) + return r; + if ((0 == strcmp(port, cptr)) && (0 == strcmp(port, "dummy"))) + strcpy(port, SCA_DEFAULT_PORT); + + sprintf(sca_port, "%s%s%s:%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", port); + /* else if nondigits specified, ignore... but the command has to have something there otherwise the core scp */ /* attach_cmd() routine complains "too few arguments". */ - if ((sca_lsock = sim_master_sock(sca_port)) == INVALID_SOCKET) + sca_lsock = sim_master_sock(sca_port, &r); + if (r != SCPE_OK) + return r; + if (sca_lsock == INVALID_SOCKET) return SCPE_OPENERR; SETBIT(sca_unit.flags, UNIT_LISTEN); /* note that we are listening, not yet connected */ - sprintf(name, "(Listening on port %d)", sca_port); - sca_unit.filename = mstring(name); - printf("%s\n", name); + sprintf(name, "(Listening on port %s)", sca_port); + sca_unit.filename = mstring(name); + printf("%s\n", sca_unit.filename); } else { - while (*cptr && *cptr <= ' ') + while (*cptr && *cptr <= ' ') cptr++; if (! *cptr) return SCPE_2FARG; - if ((colon = strchr(cptr, ':')) != NULL) { - *colon++ = '\0'; /* clip hostname at colon */ + r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL); + if (r != SCPE_OK) + return r; + if ((0 == strcmp(cptr, port)) && (0 == strcmp(host, ""))) { + strcpy(host, port); + strcpy(port, SCA_DEFAULT_PORT); + } - port = atoi(colon); /* extract port number that follows it */ - if (port <= 0 || port > 65535) - return SCPE_ARG; - else - sca_port = port; - } + sprintf(sca_port, "%s%s%s:%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", port); - if (sdummy == INVALID_SOCKET) - if ((sdummy = sim_create_sock()) == INVALID_SOCKET) /* create and keep a socket, to force initialization */ - return SCPE_IERR; /* of socket library (e.g on Win32 call WSAStartup), else gethostbyname fails */ - - if (get_ipaddr(cptr, &ipaddr, NULL) != SCPE_OK) { /* try to parse hostname as dotted decimal nnn.nnn.nnn.nnn */ - if ((he = gethostbyname(cptr)) == NULL) /* if not decimal, look up name through DNS */ - return SCPE_OPENERR; - - if ((ipaddr = * (unsigned long *) he->h_addr_list[0]) == INADDR_NONE) - return SCPE_OPENERR; - - ipaddr = ntohl(ipaddr); /* convert to host byte order; gethostbyname() gives us network order */ - } - - if ((sca_sock = sim_connect_sock(ipaddr, sca_port)) == INVALID_SOCKET) + if ((sca_sock = sim_connect_sock(sca_port, NULL, NULL)) == INVALID_SOCKET) return SCPE_OPENERR; /* sim_connect_sock() sets socket to nonblocking before initiating the connect, so * the connect is pending when it returns. For outgoing connections, the attach command should wait - * until the connection succeeds or fails. We use "accept" to wait and find out which way it goes... + * until the connection succeeds or fails. We use "sim_check_conn" to wait and find out which way it goes... */ - FD_ZERO(&wr_set); /* we are only interested in info for sca_sock */ - FD_ZERO(&err_set); - FD_SET(sca_sock, &wr_set); - FD_SET(sca_sock, &err_set); + while (0 == sim_check_conn(sca_sock, 0))/* wait for connection to complete or fail */ + sim_os_ms_sleep(1000); - select(3, NULL, &wr_set, &err_set, NULL); /* wait for connection to complete or fail */ - - if (FD_ISSET(sca_sock, &wr_set)) { /* sca_sock appears in "writable" set -- connect completed */ - sprintf(name, "%s:%d", cptr, sca_port); + if (1 == sim_check_conn(sca_sock, 0)) { /* sca_sock appears in "writable" set -- connect completed */ + sprintf(name, "%s%s%s:%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", port); sca_unit.filename = mstring(name); SETBIT(sca_dsw, SCA_DSW_READY); } - else if (FD_ISSET(sca_sock, &err_set)) { /* sca_sock appears in "error" set -- connect failed */ - sim_close_sock(sca_sock, TRUE); - sca_sock = INVALID_SOCKET; - return SCPE_OPENERR; - } - else { /* if we get here my assumption about how select works is wrong */ - printf("SCA_SOCK NOT FOUND IN WR_SET -OR- ERR_SET, CODING IN IBM1130_SCA IS WRONG\n"); + else { /* sca_sock appears in "error" set -- connect failed */ sim_close_sock(sca_sock, TRUE); sca_sock = INVALID_SOCKET; return SCPE_OPENERR; @@ -610,22 +583,17 @@ static t_stat sca_detach (UNIT *uptr) static void sca_check_connect (void) { - uint32 ipaddr; - char name[100]; + char *connectaddress; - if ((sca_sock = sim_accept_conn(sca_lsock, &ipaddr)) == INVALID_SOCKET) + if ((sca_sock = sim_accept_conn(sca_lsock, &connectaddress)) == INVALID_SOCKET) return; - ipaddr = htonl(ipaddr); /* convert to network order so we can print it */ - - sprintf(name, "%d.%d.%d.%d", ipaddr & 0xFF, (ipaddr >> 8) & 0xFF, (ipaddr >> 16) & 0xFF, (ipaddr >> 24) & 0xFF); - - printf("(SCA connection from %s)\n", name); + printf("(SCA connection from %s)\n", connectaddress); if (sca_unit.filename != NULL) free(sca_unit.filename); - sca_unit.filename = mstring(name); + sca_unit.filename = connectaddress; SETBIT(sca_dsw, SCA_DSW_READY); /* indicate active connection */ diff --git a/Interdata/id32_cpu.c b/Interdata/id32_cpu.c index 6b874df3..ed5a0ad6 100644 --- a/Interdata/id32_cpu.c +++ b/Interdata/id32_cpu.c @@ -222,7 +222,7 @@ uint32 GREG[16 * NRSETS] = { 0 }; /* general registers */ uint32 *M = NULL; /* memory */ uint32 *R = &GREG[0]; /* working reg set */ uint32 F[8] = { 0 }; /* sp fp registers */ -dpr_t D[8] = { 0 }; /* dp fp registers */ +dpr_t D[8] = { {0} }; /* dp fp registers */ uint32 PSW = 0; /* processor status word */ uint32 PC = 0; /* program counter */ uint32 oPC = 0; /* PC at inst start */ diff --git a/Interdata/id_fd.c b/Interdata/id_fd.c index a016436c..079d05ef 100644 --- a/Interdata/id_fd.c +++ b/Interdata/id_fd.c @@ -115,7 +115,7 @@ uint32 fd_cmd = 0; /* command */ uint32 fd_db = 0; /* data buffer */ uint32 fd_bptr = 0; /* buffer pointer */ uint8 fdxb[FD_NUMBY] = { 0 }; /* sector buffer */ -uint8 fd_es[FD_NUMDR][ES_SIZE] = { 0 }; /* ext status */ +uint8 fd_es[FD_NUMDR][ES_SIZE] = { {0} }; /* ext status */ uint32 fd_lrn = 0; /* log rec # */ uint32 fd_wdv = 0; /* wd valid */ uint32 fd_stopioe = 1; /* stop on error */ diff --git a/Interdata/id_pas.c b/Interdata/id_pas.c index 3e2d105a..ea0b4bd4 100644 --- a/Interdata/id_pas.c +++ b/Interdata/id_pas.c @@ -103,7 +103,7 @@ uint8 pas_xarm[PAS_LINES]; /* xmt int armed */ uint8 pas_rchp[PAS_LINES]; /* rcvr chr pend */ uint8 pas_tplte[PAS_LINES * 2 + 1]; /* template */ -TMLN pas_ldsc[PAS_LINES] = { 0 }; /* line descriptors */ +TMLN pas_ldsc[PAS_LINES] = { {0} }; /* line descriptors */ TMXR pas_desc = { 8, 0, 0, pas_ldsc }; /* mux descriptor */ #define PAS_ENAB pas_desc.lines diff --git a/Interdata/id_ttp.c b/Interdata/id_ttp.c index 660fd469..eb9fd393 100644 --- a/Interdata/id_ttp.c +++ b/Interdata/id_ttp.c @@ -130,7 +130,7 @@ DEVICE ttp_dev = { uint32 ttp (uint32 dev, uint32 op, uint32 dat) { int32 xmt = dev & 1; -int32 t, old_cmd; +int32 t; switch (op) { /* case IO op */ @@ -160,7 +160,6 @@ switch (op) { /* case IO op */ return t; case IO_OC: /* command */ - old_cmd = ttp_cmd; /* old cmd */ if (dat & CMD_TYP) { /* type 1? */ ttp_cmd = (ttp_cmd & 0xFF) | (dat << 8); if (ttp_cmd & CMD_WRT) /* write? */ diff --git a/NOVA/nova_qty.c b/NOVA/nova_qty.c index 215ac3fe..7a40e1bb 100644 --- a/NOVA/nova_qty.c +++ b/NOVA/nova_qty.c @@ -222,7 +222,7 @@ DEVICE qty_dev = #define QTY_LINE_RX_CHAR( line ) (qty_status[ (line) ] & QTY_S_DMASK) #define QTY_UNIT_ACTIVE( unitp ) ( (unitp)->conn ) -#define QTY_LINE_BITS( line, bits ) qty_status[ (line) ] & bits +#define QTY_LINE_BITS( line, bits ) (qty_status[ (line) ] & bits) #define QTY_LINE_SET_BIT( line, bit ) qty_status[ (line) ] |= (bit) ; #define QTY_LINE_CLEAR_BIT( line, bit ) qty_status[ (line) ] &= ~(bit) ; diff --git a/PDP1/pdp1_dcs.c b/PDP1/pdp1_dcs.c index 93c9eefc..99896110 100644 --- a/PDP1/pdp1_dcs.c +++ b/PDP1/pdp1_dcs.c @@ -48,7 +48,7 @@ uint8 dcs_buf[DCS_LINES]; /* line bufffers */ extern int32 iosta, stop_inst; extern int32 tmxr_poll; -TMLN dcs_ldsc[DCS_LINES] = { 0 }; /* line descriptors */ +TMLN dcs_ldsc[DCS_LINES] = { {0} }; /* line descriptors */ TMXR dcs_desc = { DCS_LINES, 0, 0, dcs_ldsc }; /* mux descriptor */ t_stat dcsi_svc (UNIT *uptr); diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c index f7bae99f..ceed19c5 100644 --- a/PDP10/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -1286,7 +1286,7 @@ static const d10 boot_rom_its[] = { t_stat rp_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern a10 saved_PC; M[FE_UNIT] = unitno & CS2_M_UNIT; diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index 52867de4..a4e2a836 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -1273,7 +1273,7 @@ static const d10 boot_rom_its[] = { t_stat tu_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern a10 saved_PC; M[FE_UNIT] = 0; diff --git a/PDP11/pdp11_cis.c b/PDP11/pdp11_cis.c index 9f78f1bd..95bcc381 100644 --- a/PDP11/pdp11_cis.c +++ b/PDP11/pdp11_cis.c @@ -170,7 +170,7 @@ typedef struct { uint32 val[DSTRLNT]; } DSTR; -static DSTR Dstr0 = { 0, 0, 0, 0, 0 }; +static DSTR Dstr0 = { 0, {0, 0, 0, 0} }; extern int32 isenable, dsenable; extern int32 N, Z, V, C, fpd, ipl; @@ -321,14 +321,12 @@ static int32 overbin[128] = { /* Overpunch to ASCII table: indexed by sign and digit */ static int32 binover[2][16] = { - '{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', - '0', '0', '0', '0', '0', '0', - '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - '0', '0', '0', '0', '0', '0' + {'{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + '0', '0', '0', '0', '0', '0'}, + {'}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + '0', '0', '0', '0', '0', '0'} }; -static unsigned char movbuf[65536]; - /* CIS emulator */ t_stat cis11 (int32 IR) @@ -342,7 +340,7 @@ uint32 nc, digit, result; t_stat st; static DSTR accum, src1, src2, dst; static DSTR mptable[10]; -static DSTR Dstr1 = { 0, 0x10, 0, 0, 0 }; +static DSTR Dstr1 = { 0, {0x10, 0, 0, 0} }; old_PC = (PC - 2) & 0177777; /* original PC */ op = IR & 0177; /* IR <6:0> */ diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 7f8eac70..65f0ec5e 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -256,7 +256,7 @@ typedef struct { extern FILE *sim_log; uint16 *M = NULL; /* memory */ -int32 REGFILE[6][2] = { 0 }; /* R0-R5, two sets */ +int32 REGFILE[6][2] = { {0} }; /* R0-R5, two sets */ int32 STACKFILE[4] = { 0 }; /* SP, four modes */ int32 saved_PC = 0; /* program counter */ int32 R[8] = { 0 }; /* working registers */ @@ -273,7 +273,7 @@ int32 trap_req = 0; /* trap requests */ int32 int_req[IPL_HLVL] = { 0 }; /* interrupt requests */ int32 PIRQ = 0; /* programmed int req */ int32 STKLIM = 0; /* stack limit */ -fpac_t FR[6] = { 0 }; /* fp accumulators */ +fpac_t FR[6] = { {0} }; /* fp accumulators */ int32 FPS = 0; /* fp status */ int32 FEC = 0; /* fp exception code */ int32 FEA = 0; /* fp exception addr */ @@ -1246,7 +1246,7 @@ while (reason == 0) { else dst = R[dstspec]; } else { - i = ((cm == pm) && (cm == MD_USR))? calc_ds (pm): calc_is (pm); + i = ((cm == pm) && (cm == MD_USR))? (int32)calc_ds (pm): (int32)calc_is (pm); dst = ReadW ((GeteaW (dstspec) & 0177777) | i); } N = GET_SIGN_W (dst); diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index faf5a2b2..c74e96c9 100644 --- a/PDP11/pdp11_cpumod.c +++ b/PDP11/pdp11_cpumod.c @@ -1159,7 +1159,7 @@ if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE)) nM = (uint16 *) calloc (val >> 1, sizeof (uint16)); if (nM == NULL) return SCPE_MEM; -clim = (((t_addr) val) < MEMSIZE)? val: MEMSIZE; +clim = (((t_addr) val) < MEMSIZE)? (uint32)val: MEMSIZE; for (i = 0; i < clim; i = i + 2) nM[i >> 1] = M[i >> 1]; free (M); diff --git a/PDP11/pdp11_dc.c b/PDP11/pdp11_dc.c index 1c653fe8..99eecf2d 100644 --- a/PDP11/pdp11_dc.c +++ b/PDP11/pdp11_dc.c @@ -86,7 +86,7 @@ uint32 dci_ireq = 0; uint16 dco_csr[DCX_LINES] = { 0 }; /* control/status */ uint8 dco_buf[DCX_LINES] = { 0 }; uint32 dco_ireq = 0; -TMLN dcx_ldsc[DCX_LINES] = { 0 }; /* line descriptors */ +TMLN dcx_ldsc[DCX_LINES] = { {0} }; /* line descriptors */ TMXR dcx_desc = { DCX_LINES, 0, 0, dcx_ldsc }; /* mux descriptor */ static const uint8 odd_par[] = { diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 8f2d07ab..bf79a4f7 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -662,6 +662,8 @@ typedef struct pdp_dib DIB; #define INT_V_TU 15 #define INT_V_RF 16 #define INT_V_RC 17 +#define INT_V_DMCRX 18 +#define INT_V_DMCTX 19 #define INT_V_PIR4 0 /* BR4 */ #define INT_V_TTI 1 @@ -705,6 +707,8 @@ typedef struct pdp_dib DIB; #define INT_TU (1u << INT_V_TU) #define INT_RF (1u << INT_V_RF) #define INT_RC (1u << INT_V_RC) +#define INT_DMCRX (1u << INT_V_DMCRX) +#define INT_DMCTX (1u << INT_V_DMCTX) #define INT_PIR4 (1u << INT_V_PIR4) #define INT_TTI (1u << INT_V_TTI) #define INT_TTO (1u << INT_V_TTO) @@ -751,6 +755,8 @@ typedef struct pdp_dib DIB; #define IPL_TU 5 #define IPL_RF 5 #define IPL_RC 5 +#define IPL_DMCRX 5 +#define IPL_DMCTX 5 #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_TTI 4 diff --git a/PDP11/pdp11_dl.c b/PDP11/pdp11_dl.c index ec8cc9ab..9b264667 100644 --- a/PDP11/pdp11_dl.c +++ b/PDP11/pdp11_dl.c @@ -87,7 +87,7 @@ uint32 dli_ireq[2] = { 0, 0}; uint16 dlo_csr[DLX_LINES] = { 0 }; /* control/status */ uint8 dlo_buf[DLX_LINES] = { 0 }; uint32 dlo_ireq = 0; -TMLN dlx_ldsc[DLX_LINES] = { 0 }; /* line descriptors */ +TMLN dlx_ldsc[DLX_LINES] = { {0} }; /* line descriptors */ TMXR dlx_desc = { DLX_LINES, 0, 0, dlx_ldsc }; /* mux descriptor */ t_stat dlx_rd (int32 *data, int32 PA, int32 access); diff --git a/PDP11/pdp11_dmc.c b/PDP11/pdp11_dmc.c new file mode 100644 index 00000000..d2c53fe8 --- /dev/null +++ b/PDP11/pdp11_dmc.c @@ -0,0 +1,2267 @@ +/* pdp11_dmc.c: DMC11 Emulation + ------------------------------------------------------------------------------ + + Copyright (c) 2011, Robert M. A. Jarratt + + 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 + THE AUTHOR 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. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + + +I/O is done through sockets so that the remote system can be on the same host machine. The device starts polling for +incoming connections when it receives its first read buffer. The device opens the connection for writing when it receives +the first write buffer. + +Transmit and receive buffers are added to their respective queues and the polling method in dmc_svc() checks for input +and sends any output. + +On the wire the format is a 2-byte block length followed by that number of bytes. Some of the diagnostics expect to receive +the same number of bytes in a buffer as were sent by the other end. Using sockets without a block length can cause the +buffers to coalesce and then the buffer lengths in the diagnostics fail. The block length is always sent in network byte +order. + +Tested with two diagnostics. To run the diagnostics set the default directory to SYS$MAINTENANCE, run ESSAA and then +configure it for the DMC-11 with the following commands: + +The above commands can be put into a COM file in SYS$MAINTENANCE (works on VMS 3.0 but not 4.6, not sure why). + +ATT DW780 SBI DW0 3 4 +ATT DMC11 DW0 XMA0 760070 300 5 +SELECT XMA0 +(if putting these into a COM file to be executed by ESSAA add a "DS> " prefix) + + +The first is EVDCA which takes no parameters. Invoke it with the command R EVDCA. This diagnostic uses the DMC-11 loopback +functionality and the transmit port is not used when LU LOOP is enabled. Seems to work only under later versions of VMS +such as 4.6, does not work on 3.0. + +The second is EVDMC, invoke this with the command R EVDMC. For this I used the following commands inside the diagnostic: + +RUN MODE=TRAN on one machine +RUN MODE=REC on the other (unless the one instance is configured with the ports looping back). + +You can add /PASS=n to the above commands to get the diagnostic to send and receive more buffers. + +The other test was to configure DECnet on VMS 4.6 and do SET HOST. +*/ + +// TODO: Avoid need for manifests and newest runtime, compile with 2003 +// TODO: Investigate line number and set parameters at the unit level (?) +// TODO: Multipoint. In this case perhaps don't need transmit port, allow all lines to connect to port on control node. +// TODO: Show active connections like DZ does, for multipoint. +// TODO: Test MOP. +// TODO: Implement actual DDCMP protocol and run over UDP. +// TODO: Allow NCP SHOW COUNTERS to work (think this is the base address thing). Since fixing how I get the addresses this should work now. + +#include +#include + +#include "pdp11_dmc.h" + +#define POLL 1000 +#define TRACE_BYTES_PER_LINE 16 + +struct csrs { + uint16 sel0; + uint16 sel2; + uint16 sel4; + uint16 sel6; +}; + +typedef struct csrs CSRS; + +typedef enum +{ + Initialised, /* after MASTER CLEAR */ + Running /* after any transmit or receive buffer has been supplied */ +} ControllerState; + +typedef enum +{ + Idle, + InputTransfer, + OutputTransfer +} TransferState; + +typedef enum +{ + Available, /* when empty or partially filled on read */ + ContainsData, + TransferInProgress +} BufferState; + +typedef struct +{ + int isPrimary; + SOCKET socket; // socket used bidirectionally + int receive_readable; + char *receive_port; + int transmit_writeable; + char transmit_host[CBUFSIZE]; + int transmit_is_loopback; /* if true the transmit socket is the loopback to the receive */ + int speed; /* bits per second in each direction, 0 for no limit */ + int last_second; + int bytes_sent_in_last_second; + int bytes_received_in_last_second; + time_t last_connect_attempt; +} LINE; + +/* A partially filled buffer (during a read from the socket) will have block_len_bytes_read = 1 or actual_bytes_transferred < actual_block_len */ +typedef struct buffer +{ + uint32 address; /* unibus address of the buffer */ + uint16 count; /* size of the buffer passed to the device by the driver */ + uint16 actual_block_len; /* actual length of the received block */ + uint8 *transfer_buffer; /* the buffer into which data is received or from which it is transmitted*/ + int block_len_bytes_read; /* the number of bytes read so far for the block length */ + int actual_bytes_transferred; /* the number of bytes from the actual block that have been read or written so far*/ + struct buffer *next; /* next buffer in the queue */ + BufferState state; /* state of this buffer */ + int is_loopback; /* loopback was requested when this buffer was queued */ +} BUFFER; + +typedef struct +{ + char * name; + BUFFER queue[BUFFER_QUEUE_SIZE]; + int head; + int tail; + int count; + struct dmc_controller *controller; /* back pointer to the containing controller */ +} BUFFER_QUEUE; + +typedef struct +{ + int started; + clock_t start_time; + clock_t cumulative_time; +} TIMER; + +typedef struct +{ + TIMER between_polls_timer; + TIMER poll_timer; + uint32 poll_count; + +} UNIT_STATS; + +typedef enum +{ + DMC, + DMR, + DMP +} DEVTYPE; + +struct dmc_controller { + CSRS *csrs; + DEVICE *device; + ControllerState state; + TransferState transfer_state; /* current transfer state (type of transfer) */ + int transfer_type; + int transfer_in_io; // remembers IN I/O setting at start of input transfer as host changes it during transfer! + LINE *line; + BUFFER_QUEUE *receive_queue; + BUFFER_QUEUE *transmit_queue; + SOCKET master_socket; + int32 connect_poll_interval; + DEVTYPE dev_type; + uint32 rxi; + uint32 txi; + uint32 buffers_received_from_net; + uint32 buffers_transmitted_to_net; + uint32 receive_buffer_output_transfers_completed; + uint32 transmit_buffer_output_transfers_completed; + uint32 receive_buffer_input_transfers_completed; + uint32 transmit_buffer_input_transfers_completed; +}; + +typedef struct dmc_controller CTLR; + +t_stat dmc_rd(int32* data, int32 PA, int32 access); +t_stat dmc_wr(int32 data, int32 PA, int32 access); +t_stat dmc_svc(UNIT * uptr); +t_stat dmc_reset (DEVICE * dptr); +t_stat dmc_attach (UNIT * uptr, char * cptr); +int dmc_isattached(CTLR *controller); +t_stat dmc_detach (UNIT * uptr); +int32 dmc_rxint (void); +int32 dmc_txint (void); +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_settype (UNIT* uptr, int32 val, char* cptr, void* desc); +t_stat dmc_showtype (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat dmc_setstats (UNIT* uptr, int32 val, char* cptr, void* desc); +t_stat dmc_showstats (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat dmc_setconnectpoll (UNIT* uptr, int32 val, char* cptr, void* desc); +t_stat dmc_showconnectpoll (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat dmc_setlinemode (UNIT* uptr, int32 val, char* cptr, void* desc); +t_stat dmc_showlinemode (FILE* st, UNIT* uptr, int32 val, void* desc); +int dmc_is_dmc(CTLR *controller); +int dmc_is_rqi_set(CTLR *controller); +int dmc_is_rdyi_set(CTLR *controller); +int dmc_is_iei_set(CTLR *controller); +int dmc_is_ieo_set(CTLR *controller); +void dmc_process_command(CTLR *controller); +int dmc_buffer_fill_receive_buffers(CTLR *controller); +void dmc_start_transfer_receive_buffer(CTLR *controller); +int dmc_buffer_send_transmit_buffers(CTLR *controller); +void dmc_buffer_queue_init(CTLR *controller, BUFFER_QUEUE *q, char *name); +BUFFER *dmc_buffer_queue_head(BUFFER_QUEUE *q); +int dmc_buffer_queue_full(BUFFER_QUEUE *q); +void dmc_buffer_queue_get_stats(BUFFER_QUEUE *q, int *available, int *contains_data, int *transfer_in_progress); +void dmc_start_transfer_transmit_buffer(CTLR *controller); +void dmc_error_and_close_receive(CTLR *controller, char *format); +void dmc_close_receive(CTLR *controller, char *reason, char *from); +void dmc_close_transmit(CTLR *controller, char *reason); +int dmc_get_socket(CTLR *controller, int forRead); +int dmc_get_receive_socket(CTLR *controller, int forRead); +int dmc_get_transmit_socket(CTLR *controller, int is_loopback, int forRead); +void dmc_line_update_speed_stats(LINE *line); +UNIT_STATS *dmc_get_unit_stats(UNIT *uptr); +void dmc_set_unit_stats(UNIT *uptr, UNIT_STATS *stats); + +DEBTAB dmc_debug[] = { + {"TRACE", DBG_TRC}, + {"WARN", DBG_WRN}, + {"REG", DBG_REG}, + {"INFO", DBG_INF}, + {"DATA", DBG_DAT}, + {"DATASUM",DBG_DTS}, + {"SOCKET", DBG_SOK}, + {"CONNECT", DBG_CON}, + {0} +}; + +UNIT dmc_unit[] = { + { UDATA (&dmc_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) }, + { UDATA (&dmc_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) }, + { UDATA (&dmc_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) }, + { UDATA (&dmc_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) } +}; + +UNIT dmp_unit[] = { + { UDATA (&dmc_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) } +}; + +CSRS dmc_csrs[DMC_NUMDEVICE]; + +CSRS dmp_csrs[DMP_NUMDEVICE]; + +REG dmca_reg[] = { + { HRDATA (SEL0, dmc_csrs[0].sel0, 16) }, + { HRDATA (SEL2, dmc_csrs[0].sel2, 16) }, + { HRDATA (SEL4, dmc_csrs[0].sel4, 16) }, + { HRDATA (SEL6, dmc_csrs[0].sel6, 16) }, + { GRDATA (BSEL0, dmc_csrs[0].sel0, DEV_RDX, 8, 0) }, + { GRDATA (BSEL1, dmc_csrs[0].sel0, DEV_RDX, 8, 8) }, + { GRDATA (BSEL2, dmc_csrs[0].sel2, DEV_RDX, 8, 0) }, + { GRDATA (BSEL3, dmc_csrs[0].sel2, DEV_RDX, 8, 8) }, + { GRDATA (BSEL4, dmc_csrs[0].sel4, DEV_RDX, 8, 0) }, + { GRDATA (BSEL5, dmc_csrs[0].sel4, DEV_RDX, 8, 8) }, + { GRDATA (BSEL6, dmc_csrs[0].sel6, DEV_RDX, 8, 0) }, + { GRDATA (BSEL7, dmc_csrs[0].sel6, DEV_RDX, 8, 8) }, + { NULL } }; + +REG dmcb_reg[] = { + { HRDATA (SEL0, dmc_csrs[1].sel0, 16) }, + { HRDATA (SEL2, dmc_csrs[1].sel2, 16) }, + { HRDATA (SEL4, dmc_csrs[1].sel4, 16) }, + { HRDATA (SEL6, dmc_csrs[1].sel6, 16) }, + { GRDATA (BSEL0, dmc_csrs[1].sel0, DEV_RDX, 8, 0) }, + { GRDATA (BSEL1, dmc_csrs[1].sel0, DEV_RDX, 8, 8) }, + { GRDATA (BSEL2, dmc_csrs[1].sel2, DEV_RDX, 8, 0) }, + { GRDATA (BSEL3, dmc_csrs[1].sel2, DEV_RDX, 8, 8) }, + { GRDATA (BSEL4, dmc_csrs[1].sel4, DEV_RDX, 8, 0) }, + { GRDATA (BSEL5, dmc_csrs[1].sel4, DEV_RDX, 8, 8) }, + { GRDATA (BSEL6, dmc_csrs[1].sel6, DEV_RDX, 8, 0) }, + { GRDATA (BSEL7, dmc_csrs[1].sel6, DEV_RDX, 8, 8) }, + { NULL } }; + +REG dmcc_reg[] = { + { HRDATA (SEL0, dmc_csrs[2].sel0, 16) }, + { HRDATA (SEL2, dmc_csrs[2].sel2, 16) }, + { HRDATA (SEL4, dmc_csrs[2].sel4, 16) }, + { HRDATA (SEL6, dmc_csrs[2].sel6, 16) }, + { GRDATA (BSEL0, dmc_csrs[2].sel0, DEV_RDX, 8, 0) }, + { GRDATA (BSEL1, dmc_csrs[2].sel0, DEV_RDX, 8, 8) }, + { GRDATA (BSEL2, dmc_csrs[2].sel2, DEV_RDX, 8, 0) }, + { GRDATA (BSEL3, dmc_csrs[2].sel2, DEV_RDX, 8, 8) }, + { GRDATA (BSEL4, dmc_csrs[2].sel4, DEV_RDX, 8, 0) }, + { GRDATA (BSEL5, dmc_csrs[2].sel4, DEV_RDX, 8, 8) }, + { GRDATA (BSEL6, dmc_csrs[2].sel6, DEV_RDX, 8, 0) }, + { GRDATA (BSEL7, dmc_csrs[2].sel6, DEV_RDX, 8, 8) }, + { NULL } }; + +REG dmcd_reg[] = { + { HRDATA (SEL0, dmc_csrs[3].sel0, 16) }, + { HRDATA (SEL2, dmc_csrs[3].sel2, 16) }, + { HRDATA (SEL4, dmc_csrs[3].sel4, 16) }, + { HRDATA (SEL6, dmc_csrs[3].sel6, 16) }, + { GRDATA (BSEL0, dmc_csrs[3].sel0, DEV_RDX, 8, 0) }, + { GRDATA (BSEL1, dmc_csrs[3].sel0, DEV_RDX, 8, 8) }, + { GRDATA (BSEL2, dmc_csrs[3].sel2, DEV_RDX, 8, 0) }, + { GRDATA (BSEL3, dmc_csrs[3].sel2, DEV_RDX, 8, 8) }, + { GRDATA (BSEL4, dmc_csrs[3].sel4, DEV_RDX, 8, 0) }, + { GRDATA (BSEL5, dmc_csrs[3].sel4, DEV_RDX, 8, 8) }, + { GRDATA (BSEL6, dmc_csrs[3].sel6, DEV_RDX, 8, 0) }, + { GRDATA (BSEL7, dmc_csrs[3].sel6, DEV_RDX, 8, 8) }, + { NULL } }; + +REG dmp_reg[] = { + { HRDATA (SEL0, dmc_csrs[3].sel0, 16) }, + { HRDATA (SEL2, dmc_csrs[3].sel2, 16) }, + { HRDATA (SEL4, dmc_csrs[3].sel4, 16) }, + { HRDATA (SEL6, dmc_csrs[3].sel6, 16) }, + { GRDATA (BSEL0, dmc_csrs[3].sel0, DEV_RDX, 8, 0) }, + { GRDATA (BSEL1, dmc_csrs[3].sel0, DEV_RDX, 8, 8) }, + { GRDATA (BSEL2, dmc_csrs[3].sel2, DEV_RDX, 8, 0) }, + { GRDATA (BSEL3, dmc_csrs[3].sel2, DEV_RDX, 8, 8) }, + { GRDATA (BSEL4, dmc_csrs[3].sel4, DEV_RDX, 8, 0) }, + { GRDATA (BSEL5, dmc_csrs[3].sel4, DEV_RDX, 8, 8) }, + { GRDATA (BSEL6, dmc_csrs[3].sel6, DEV_RDX, 8, 0) }, + { GRDATA (BSEL7, dmc_csrs[3].sel6, DEV_RDX, 8, 8) }, + { NULL } }; + +MTAB dmc_mod[] = { + { MTAB_XTD | MTAB_VDV, 0, "PEER", "PEER=address:port" ,&dmc_setpeer, &dmc_showpeer, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "SPEED", "SPEED" ,&dmc_setspeed, &dmc_showspeed, NULL }, +#ifdef DMP + { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE" ,&dmc_settype, &dmc_showtype, NULL }, +#endif + { MTAB_XTD | MTAB_VDV, 0, "LINEMODE", "LINEMODE" ,&dmc_setlinemode, &dmc_showlinemode, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATS", "STATS" ,&dmc_setstats, &dmc_showstats, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "CONNECTPOLL", "CONNECTPOLL" ,&dmc_setconnectpoll, &dmc_showconnectpoll, NULL }, + { MTAB_XTD | MTAB_VDV, 006, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL }, + { MTAB_XTD |MTAB_VDV, 0, "VECTOR", "VECTOR", &set_vec, &show_vec, NULL }, + { 0 }, +}; + +#define IOLN_DMC 010 +#ifndef IOBA_FLOAT +#define IOBA_FLOAT 0 +#define VEC_FLOAT 0 +#endif +DIB dmc_dib[] = +{ + { IOBA_FLOAT, IOLN_DMC, &dmc_rd, &dmc_wr, 2, IVCL (DMCRX), VEC_FLOAT, {&dmc_rxint, &dmc_txint} }, + { IOBA_FLOAT, IOLN_DMC, &dmc_rd, &dmc_wr, 2, IVCL (DMCRX), VEC_FLOAT, {&dmc_rxint, &dmc_txint} }, + { IOBA_FLOAT, IOLN_DMC, &dmc_rd, &dmc_wr, 2, IVCL (DMCRX), VEC_FLOAT, {&dmc_rxint, &dmc_txint} }, + { IOBA_FLOAT, IOLN_DMC, &dmc_rd, &dmc_wr, 2, IVCL (DMCRX), VEC_FLOAT, {&dmc_rxint, &dmc_txint} } +}; + +#define IOLN_DMP 010 + +DIB dmp_dib[] = +{ + { IOBA_FLOAT, IOLN_DMP, &dmc_rd, &dmc_wr, 2, IVCL (DMCRX), VEC_FLOAT, {&dmc_rxint, &dmc_txint} } +}; + +DEVICE dmc_dev[] = +{ + { "DMA", &dmc_unit[0], dmca_reg, dmc_mod, DMC_UNITSPERDEVICE, DMC_RDX, 8, 1, DMC_RDX, 8, + NULL,NULL,&dmc_reset,NULL,&dmc_attach,&dmc_detach, + &dmc_dib[0], DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_NET | DEV_DEBUG, 0, dmc_debug }, + { "DMB", &dmc_unit[1], dmcb_reg, dmc_mod, DMC_UNITSPERDEVICE, DMC_RDX, 8, 1, DMC_RDX, 8, + NULL,NULL,&dmc_reset,NULL,&dmc_attach,&dmc_detach, + &dmc_dib[1], DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_NET | DEV_DEBUG, 0, dmc_debug }, + { "DMC", &dmc_unit[2], dmcc_reg, dmc_mod, DMC_UNITSPERDEVICE, DMC_RDX, 8, 1, DMC_RDX, 8, + NULL,NULL,&dmc_reset,NULL,&dmc_attach,&dmc_detach, + &dmc_dib[2], DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_NET | DEV_DEBUG, 0, dmc_debug }, + { "DMD", &dmc_unit[3], dmcd_reg, dmc_mod, DMC_UNITSPERDEVICE, DMC_RDX, 8, 1, DMC_RDX, 8, + NULL,NULL,&dmc_reset,NULL,&dmc_attach,&dmc_detach, + &dmc_dib[3], DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_NET | DEV_DEBUG, 0, dmc_debug } +}; + +#ifdef DMP +DEVICE dmp_dev[] = +{ + { "DMP", &dmp_unit[0], dmp_reg, dmc_mod, DMP_UNITSPERDEVICE, DMC_RDX, 8, 1, DMC_RDX, 8, + NULL,NULL,&dmc_reset,NULL,&dmc_attach,&dmc_detach, + &dmp_dib[0], DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_NET | DEV_DEBUG, 0, dmc_debug } +}; +#endif + +LINE dmc_line[DMC_NUMDEVICE] = +{ + { 0, INVALID_SOCKET }, + { 0, INVALID_SOCKET }, + { 0, INVALID_SOCKET }, + { 0, INVALID_SOCKET } +}; + +BUFFER_QUEUE dmc_receive_queues[DMC_NUMDEVICE]; +BUFFER_QUEUE dmc_transmit_queues[DMC_NUMDEVICE]; + +LINE dmp_line[DMP_NUMDEVICE] = +{ + { 0, INVALID_SOCKET } +}; + +BUFFER_QUEUE dmp_receive_queues[DMP_NUMDEVICE]; +BUFFER_QUEUE dmp_transmit_queues[DMP_NUMDEVICE]; + +CTLR dmc_ctrls[] = +{ + { &dmc_csrs[0], &dmc_dev[0], Initialised, Idle, 0, 0, &dmc_line[0], &dmc_receive_queues[0], &dmc_transmit_queues[0], INVALID_SOCKET, -1, 30, DMC }, + { &dmc_csrs[1], &dmc_dev[1], Initialised, Idle, 0, 0, &dmc_line[1], &dmc_receive_queues[1], &dmc_transmit_queues[1], INVALID_SOCKET, -1, 30, DMC }, + { &dmc_csrs[2], &dmc_dev[2], Initialised, Idle, 0, 0, &dmc_line[2], &dmc_receive_queues[2], &dmc_transmit_queues[2], INVALID_SOCKET, -1, 30, DMC }, + { &dmc_csrs[3], &dmc_dev[3], Initialised, Idle, 0, 0, &dmc_line[3], &dmc_receive_queues[3], &dmc_transmit_queues[3], INVALID_SOCKET, -1, 30, DMC }, +#ifdef DMP + { &dmp_csrs[0], &dmp_dev[0], Initialised, Idle, 0, 0, &dmp_line[0], &dmp_receive_queues[0], &dmp_transmit_queues[0], INVALID_SOCKET, -1, 30, DMP } +#endif +}; + +extern int32 tmxr_poll; /* calibrated delay */ + +UNIT_STATS *dmc_get_unit_stats(UNIT *uptr) +{ + UNIT_STATS *ans = NULL; +#ifdef USE_ADDR64 + ans = (UNIT_STATS *)(((t_uint64)uptr->u3 << 32) | uptr->u4); +#else + ans = (UNIT_STATS *)(uptr->u3); +#endif + return ans; +} + +void dmc_set_unit_stats(UNIT *uptr, UNIT_STATS *stats) +{ +#ifdef USE_ADDR64 + uptr->u3 = (int32)((t_uint64)stats >> 32); + uptr->u4 = (int32)((t_uint64)stats & 0xFFFFFFFF); +#else + uptr->u3 = (int32)stats; +#endif +} + +void dmc_reset_unit_stats(UNIT_STATS *s) +{ + s->between_polls_timer.started = FALSE; + s->poll_timer.started = FALSE; + s->poll_count = 0; +} + +int dmc_timer_started(TIMER *t) +{ + return t->started; +} + +void dmc_timer_start(TIMER *t) +{ + t->start_time = clock(); + t->cumulative_time = 0; + t->started = TRUE; +} + +void dmc_timer_stop(TIMER *t) +{ + clock_t end_time = clock(); + t->cumulative_time += end_time - t->start_time; +} + +void dmc_timer_resume(TIMER *t) +{ + t->start_time = clock(); +} + +double dmc_timer_cumulative_seconds(TIMER *t) +{ + return (double)t->cumulative_time/CLOCKS_PER_SEC; +} + +int dmc_is_dmc(CTLR *controller) +{ + return controller->dev_type != DMP; +} + +CTLR *dmc_get_controller_from_unit(UNIT *unit) +{ + int i; + CTLR *ans = NULL; + for (i = 0; i < DMC_NUMDEVICE + DMP_NUMDEVICE; i++) + { + if (dmc_ctrls[i].device->units == unit) + { + ans = &dmc_ctrls[i]; + break; + } + } + + return ans; +} + +CTLR* dmc_get_controller_from_address(uint32 address) +{ + int i; + for (i=0; ictxt; + if ((address >= dib->ba) && (address < (dib->ba + dib->lnt))) + return &dmc_ctrls[i]; + } + /* not found */ + return 0; +} + +CTLR *dmc_get_controller_from_device(DEVICE *device) +{ + int i; + CTLR *ans = NULL; + for (i = 0; i < DMC_NUMDEVICE + DMP_NUMDEVICE; i++) + { + if (dmc_ctrls[i].device == device) + { + ans = &dmc_ctrls[i]; + break; + } + } + + return ans; +} + +t_stat dmc_showpeer (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + CTLR *controller = dmc_get_controller_from_unit(uptr); + if (controller->line->transmit_host[0]) + { + fprintf(st, "PEER=%s", controller->line->transmit_host); + } + else + { + fprintf(st, "PEER Unspecified"); + } + + return SCPE_OK; +} + +t_stat dmc_setpeer (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + t_stat status = SCPE_OK; + char host[CBUFSIZE], port[CBUFSIZE]; + CTLR *controller = dmc_get_controller_from_unit(uptr); + + if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; + status = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); + if (status != SCPE_OK) + return status; + if (host[0] == '\0') + return SCPE_ARG; + strncpy(controller->line->transmit_host, cptr, sizeof(controller->line->transmit_host)-1); + + return status; +} + +t_stat dmc_showspeed (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + CTLR *controller = dmc_get_controller_from_unit(uptr); + fprintf(st, "SPEED=%d", controller->line->speed); + return SCPE_OK; +} + +t_stat dmc_setspeed (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + t_stat status = SCPE_OK; + CTLR *controller = dmc_get_controller_from_unit(uptr); + + if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; + if (sscanf(cptr, "%d", &controller->line->speed) != 1) + { + status = SCPE_ARG; + } + + return status; +} + +t_stat dmc_showtype (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + CTLR *controller = dmc_get_controller_from_unit(uptr); + switch (controller->dev_type) + { + case DMC: + { + fprintf(st, "TYPE=DMC"); + break; + } + case DMR: + { + fprintf(st, "TYPE=DMR"); + break; + } + case DMP: + { + fprintf(st, "TYPE=DMP"); + break; + } + default: + { + fprintf(st, "TYPE=???"); + break; + } + } + return SCPE_OK; +} + +t_stat dmc_settype (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + char buf[80]; + t_stat status = SCPE_OK; + CTLR *controller = dmc_get_controller_from_unit(uptr); + + if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; + if (sscanf(cptr, "%s", buf) != 1) + { + status = SCPE_ARG; + } + else + { + if (strcmp(buf,"DMC")==0) + { + controller->dev_type = DMC; + } + else if (strcmp(buf,"DMR")==0) + { + controller->dev_type = DMR; + } + else if (strcmp(buf,"DMP")==0) + { + controller->dev_type = DMP; + } + else + { + status = SCPE_ARG; + } + } + + return status; +} + +t_stat dmc_showstats (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + CTLR *controller = dmc_get_controller_from_unit(uptr); + TIMER *poll_timer = &dmc_get_unit_stats(uptr)->poll_timer; + TIMER *between_polls_timer = &dmc_get_unit_stats(uptr)->between_polls_timer; + uint32 poll_count = dmc_get_unit_stats(uptr)->poll_count; + + if (dmc_timer_started(between_polls_timer) && poll_count > 0) + { + fprintf(st, "Average time between polls=%f (sec)\n", dmc_timer_cumulative_seconds(between_polls_timer)/poll_count); + } + else + { + fprintf(st, "Average time between polls=n/a\n"); + } + + if (dmc_timer_started(poll_timer) && poll_count > 0) + { + fprintf(st, "Average time within poll=%f (sec)\n", dmc_timer_cumulative_seconds(poll_timer)/poll_count); + } + else + { + fprintf(st, "Average time within poll=n/a\n"); + } + + fprintf(st, "Buffers received from the network=%d\n", controller->buffers_received_from_net); + fprintf(st, "Buffers sent to the network=%d\n", controller->buffers_transmitted_to_net); + fprintf(st, "Output transfers completed for receive buffers=%d\n", controller->receive_buffer_output_transfers_completed); + fprintf(st, "Output transfers completed for transmit buffers=%d\n", controller->transmit_buffer_output_transfers_completed); + fprintf(st, "Input transfers completed for receive buffers=%d\n", controller->receive_buffer_input_transfers_completed); + fprintf(st, "Input transfers completed for transmit buffers=%d\n", controller->transmit_buffer_input_transfers_completed); + + return SCPE_OK; +} + +t_stat dmc_setstats (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + t_stat status = SCPE_OK; + CTLR *controller = dmc_get_controller_from_unit(uptr); + + dmc_reset_unit_stats(dmc_get_unit_stats(uptr)); + + controller->receive_buffer_output_transfers_completed = 0; + controller->transmit_buffer_output_transfers_completed = 0; + controller->receive_buffer_input_transfers_completed = 0; + controller->transmit_buffer_input_transfers_completed = 0; + + printf("Statistics reset\n" ); + + return status; +} + +t_stat dmc_showconnectpoll (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + CTLR *controller = dmc_get_controller_from_unit(uptr); + fprintf(st, "CONNECTPOLL=%d", controller->connect_poll_interval); + return SCPE_OK; +} + +t_stat dmc_setconnectpoll (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + t_stat status = SCPE_OK; + CTLR *controller = dmc_get_controller_from_unit(uptr); + + if (!cptr) return SCPE_IERR; + if (sscanf(cptr, "%d", &controller->connect_poll_interval) != 1) + { + status = SCPE_ARG; + } + + return status; +} + +t_stat dmc_showlinemode (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + CTLR *controller = dmc_get_controller_from_unit(uptr); + fprintf(st, "LINEMODE=%s", controller->line->isPrimary? "PRIMARY" : "SECONDARY"); + return SCPE_OK; +} + +t_stat dmc_setlinemode (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + t_stat status = SCPE_OK; + CTLR *controller = dmc_get_controller_from_unit(uptr); + + if (!cptr) return SCPE_IERR; + if (uptr->flags & UNIT_ATT) return SCPE_ALATT; + + if (MATCH_CMD(cptr, "PRIMARY") == 0) + { + controller->line->isPrimary = 1; + } + else if (MATCH_CMD(cptr, "SECONDARY") == 0) + { + controller->line->isPrimary = 0; + } + else + { + status = SCPE_ARG; + } + + return status; +} + +void dmc_setrxint(CTLR *controller) +{ + controller->rxi = 1; + SET_INT(DMCRX); +} + +void dmc_clrrxint(CTLR *controller) +{ + controller->rxi = 0; + CLR_INT(DMCRX); +} + +void dmc_settxint(CTLR *controller) +{ + controller->txi = 1; + SET_INT(DMCTX); +} + +void dmc_clrtxint(CTLR *controller) +{ + controller->txi = 0; + CLR_INT(DMCTX); +} + +int dmc_getsel(int addr) +{ + return (addr >> 1) & 03; +} + +uint16 dmc_bitfld(int data, int start_bit, int length) +{ + uint16 ans = data >> start_bit; + uint32 mask = (1 << (length))-1; + ans &= mask; + return ans; +} + +void dmc_dumpregsel0(CTLR *controller, int trace_level, char * prefix, uint16 data) +{ + char *type_str = ""; + uint16 type = dmc_bitfld(data, SEL0_TYPEI_BIT, 2); + + if (dmc_is_dmc(controller)) + { + if (dmc_is_rqi_set(controller)) + { + if (type==TYPE_BACCI) + type_str = "BA/CC I"; + else if (type==TYPE_CNTLI) + type_str = "CNTL I"; + else if (type==TYPE_BASEI) + type_str = "BASE I"; + else + type_str = "?????"; + } + + sim_debug( + trace_level, + controller->device, + "%s SEL0 (0x%04x) %s%s%s%s%s%s%s%s\n", + prefix, + data, + dmc_bitfld(data, SEL0_RUN_BIT, 1) ? "RUN " : "", + dmc_bitfld(data, SEL0_MCLR_BIT, 1) ? "MCLR " : "", + dmc_bitfld(data, SEL0_LU_LOOP_BIT, 1) ? "LU LOOP " : "", + dmc_bitfld(data, SEL0_RDI_BIT, 1) ? "RDI " : "", + dmc_bitfld(data, SEL0_DMC_IEI_BIT, 1) ? "IEI " : "", + dmc_bitfld(data, SEL0_DMC_RQI_BIT, 1) ? "RQI " : "", + dmc_bitfld(data, SEL0_IN_IO_BIT, 1) ? "IN I/O " : "", + type_str + ); + } + else + { + sim_debug( + trace_level, + controller->device, + "%s SEL0 (0x%04x) %s%s%s%s%s%s\n", + prefix, + data, + dmc_bitfld(data, SEL0_RUN_BIT, 1) ? "RUN " : "", + dmc_bitfld(data, SEL0_MCLR_BIT, 1) ? "MCLR " : "", + dmc_bitfld(data, SEL0_LU_LOOP_BIT, 1) ? "LU LOOP " : "", + dmc_bitfld(data, SEL0_DMP_RQI_BIT, 1) ? "RQI " : "", + dmc_bitfld(data, SEL0_DMP_IEO_BIT, 1) ? "IEO " : "", + dmc_bitfld(data, SEL0_DMP_IEI_BIT, 1) ? "IEI " : "" + ); + } +} + +void dmc_dumpregsel2(CTLR *controller, int trace_level, char *prefix, uint16 data) +{ + char *type_str = ""; + uint16 type = dmc_bitfld(data, SEL2_TYPEO_BIT, 2); + + if (type==TYPE_BACCO) + type_str = "BA/CC O"; + else if (type==TYPE_CNTLO) + type_str = "CNTL O"; + else + type_str = "?????"; + + sim_debug( + trace_level, + controller->device, + "%s SEL2 (0x%04x) PRIO=%d LINE=%d %s%s%s%s\n", + prefix, + data, + dmc_bitfld(data, SEL2_PRIO_BIT, SEL2_PRIO_BIT_LENGTH), + dmc_bitfld(data, SEL2_LINE_BIT, SEL2_LINE_BIT_LENGTH), + dmc_bitfld(data, SEL2_RDO_BIT, 1) ? "RDO " : "", + dmc_bitfld(data, SEL2_IEO_BIT, 1) ? "IEO " : "", + dmc_bitfld(data, SEL2_OUT_IO_BIT, 1) ? "OUT I/O " : "", + type_str + ); +} + +void dmc_dumpregsel4(CTLR *controller, int trace_level, char *prefix, uint16 data) +{ + sim_debug(trace_level, controller->device, "%s SEL4 (0x%04x)\n", prefix, data); +} + +void dmc_dumpregsel6(CTLR *controller, int trace_level, char *prefix, uint16 data) +{ + sim_debug( + trace_level, + controller->device, + "%s SEL6 (0x%04x) %s\n", + prefix, + data, + dmc_bitfld(data, SEL6_LOST_DATA_BIT, 1) ? "LOST_DATA " : ""); +} + +uint16 dmc_getreg(CTLR *controller, int reg, int ext) +{ + uint16 ans = 0; + switch (dmc_getsel(reg)) + { + case 00: + ans = controller->csrs->sel0; + if (ext) dmc_dumpregsel0(controller, DBG_REG, "Getting", ans); + break; + case 01: + ans = controller->csrs->sel2; + if (ext) dmc_dumpregsel2(controller, DBG_REG, "Getting", ans); + break; + case 02: + ans = controller->csrs->sel4; + if (ext) dmc_dumpregsel4(controller, DBG_REG, "Getting", ans); + break; + case 03: + ans = controller->csrs->sel6; + if (ext) dmc_dumpregsel6(controller, DBG_REG, "Getting", ans); + break; + default: + { + sim_debug(DBG_WRN, controller->device, "dmc_getreg(). Invalid register %d", reg); + } + } + + return ans; +} + +void dmc_setreg(CTLR *controller, int reg, uint16 data, int ext) +{ + char *trace = (ext) ? "Writing" : "Setting"; + switch (dmc_getsel(reg)) + { + case 00: + dmc_dumpregsel0(controller, DBG_REG, trace, data); + controller->csrs->sel0 = data; + break; + case 01: + dmc_dumpregsel2(controller, DBG_REG, trace, data); + controller->csrs->sel2 = data; + break; + case 02: + dmc_dumpregsel4(controller, DBG_REG, trace, data); + controller->csrs->sel4 = data; + break; + case 03: + dmc_dumpregsel6(controller, DBG_REG, trace, data); + controller->csrs->sel6 = data; + break; + default: + { + sim_debug(DBG_WRN, controller->device, "dmc_setreg(). Invalid register %d", reg); + } + } +} + +int dmc_is_master_clear_set(CTLR *controller) +{ + return controller->csrs->sel0 & MASTER_CLEAR_MASK; +} + +int dmc_is_lu_loop_set(CTLR *controller) +{ + return controller->csrs->sel0 & LU_LOOP_MASK; +} + +int dmc_is_rqi_set(CTLR *controller) +{ + int ans = 0; + if (dmc_is_dmc(controller)) + { + ans = controller->csrs->sel0 & DMC_RQI_MASK; + } + else + { + ans = controller->csrs->sel0 & DMP_RQI_MASK; + } + return ans; +} + +int dmc_is_rdyi_set(CTLR *controller) +{ + int ans = 0; + if (dmc_is_dmc(controller)) + { + ans = controller->csrs->sel0 & DMC_RDYI_MASK; + } + else + { + ans = controller->csrs->sel2 & DMP_RDYI_MASK; + } + return ans; +} + +int dmc_is_iei_set(CTLR *controller) +{ + int ans = 0; + if (dmc_is_dmc(controller)) + { + ans = controller->csrs->sel0 & DMC_IEI_MASK; + } + else + { + ans = controller->csrs->sel0 & DMP_IEI_MASK; + } + + return ans; +} +int dmc_is_ieo_set(CTLR *controller) +{ + int ans = 0; + if (dmc_is_dmc(controller)) + { + ans = controller->csrs->sel2 & DMC_IEO_MASK; + } + else + { + ans = controller->csrs->sel0 & DMP_IEO_MASK; + } + + return ans; +} +int dmc_is_in_io_set(CTLR *controller) +{ + int ans = 0; + if (dmc_is_dmc(controller)) + { + ans = controller->csrs->sel0 & DMC_IN_IO_MASK; + } + else + { + ans = !controller->csrs->sel2 & DMP_IN_IO_MASK; + } + + return ans; +} +int dmc_is_out_io_set(CTLR *controller) +{ + int ans = controller->csrs->sel2 & OUT_IO_MASK; + return ans; +} + +int dmc_is_rdyo_set(CTLR *controller) +{ + return controller->csrs->sel2 & DMC_RDYO_MASK; +} + +void dmc_set_rdyi(CTLR *controller) +{ + if (dmc_is_dmc(controller)) + { + dmc_setreg(controller, 0, controller->csrs->sel0 | DMC_RDYI_MASK, 0); + } + else + { + dmc_setreg(controller, 2, controller->csrs->sel2 | DMP_RDYI_MASK, 0); + } + + if (dmc_is_iei_set(controller)) + { + dmc_setrxint(controller); + } +} + +void dmc_clear_rdyi(CTLR *controller) +{ + if (dmc_is_dmc(controller)) + { + dmc_setreg(controller, 0, controller->csrs->sel0 & ~DMC_RDYI_MASK, 0); + } + else + { + dmc_setreg(controller, 2, controller->csrs->sel2 & ~DMP_RDYI_MASK, 0); + } +} + +void dmc_set_rdyo(CTLR *controller) +{ + dmc_setreg(controller, 2, controller->csrs->sel2 | DMC_RDYO_MASK, 0); + + if (dmc_is_ieo_set(controller)) + { + dmc_settxint(controller); + } +} + +void dmc_set_lost_data(CTLR *controller) +{ + dmc_setreg(controller, 6, controller->csrs->sel6 | LOST_DATA_MASK, 0); +} + +void dmc_clear_master_clear(CTLR *controller) +{ + dmc_setreg(controller, 0, controller->csrs->sel0 & ~MASTER_CLEAR_MASK, 0); +} + +void dmc_set_run(CTLR *controller) +{ + dmc_setreg(controller, 0, controller->csrs->sel0 | RUN_MASK, 0); +} + +int dmc_get_input_transfer_type(CTLR *controller) +{ + int ans = 0; + + if (dmc_is_dmc(controller)) + { + ans = controller->csrs->sel0 & DMC_TYPE_INPUT_MASK; + } + else + { + ans = controller->csrs->sel2 & DMP_TYPE_INPUT_MASK; + } + + return ans; +} +int dmc_get_output_transfer_type(CTLR *controller) +{ + return controller->csrs->sel2 & TYPE_OUTPUT_MASK; +} +void dmc_set_type_output(CTLR *controller, int type) +{ + dmc_setreg(controller, 2, controller->csrs->sel2 | (type & TYPE_OUTPUT_MASK), 0); +} + +void dmc_set_out_io(CTLR *controller) +{ + dmc_setreg(controller, 2, controller->csrs->sel2 | OUT_IO_MASK, 0); +} + +void dmc_clear_out_io(CTLR *controller) +{ + dmc_setreg(controller, 2, controller->csrs->sel2 & ~OUT_IO_MASK, 0); +} + +void dmc_process_master_clear(CTLR *controller) +{ + sim_debug(DBG_INF, controller->device, "Master clear\n"); + dmc_clear_master_clear(controller); + controller->state = Initialised; + dmc_setreg(controller, 0, 0, 0); + if (controller->dev_type == DMR) + { + /* DMR-11 indicates microdiagnostics complete when this is set */ + dmc_setreg(controller, 2, 0x8000, 0); + } + else + { + /* preserve contents of BSEL3 if DMC-11 */ + dmc_setreg(controller, 2, controller->csrs->sel2 & 0xFF00, 0); + } + if (controller->dev_type == DMP) + { + dmc_setreg(controller, 4, 077, 0); + } + else + { + dmc_setreg(controller, 4, 0, 0); + } + + if (controller->dev_type == DMP) + { + dmc_setreg(controller, 6, 0305, 0); + } + else + { + dmc_setreg(controller, 6, 0, 0); + } + dmc_buffer_queue_init(controller, controller->receive_queue, "receive"); + dmc_buffer_queue_init(controller, controller->transmit_queue, "transmit"); + + controller->transfer_state = Idle; + dmc_set_run(controller); + + sim_cancel (controller->device->units); /* stop poll */ + sim_activate_abs(controller->device->units, clk_cosched (tmxr_poll)); +} + +void dmc_start_input_transfer(CTLR *controller) +{ + int ok = 1; + int type = dmc_get_input_transfer_type(controller); + + /* if this is a BA/CC I then check that the relevant queue has room first */ + if (type == TYPE_BACCI) + { + ok = (dmc_is_in_io_set(controller) && !dmc_buffer_queue_full(controller->receive_queue)) + || + (!dmc_is_in_io_set(controller) && !dmc_buffer_queue_full(controller->transmit_queue)); + } + + if (ok) + { + sim_debug(DBG_INF, controller->device, "Starting input transfer\n"); + controller->transfer_state = InputTransfer; + controller->transfer_type = type; + controller->transfer_in_io = dmc_is_in_io_set(controller); + dmc_set_rdyi(controller); + } + else + { + sim_debug(DBG_WRN, controller->device, "Input transfer request not granted as queue is full\n"); + } +} + +void dmc_start_data_output_transfer(CTLR *controller, uint32 addr, int16 count, int is_receive) +{ + if (is_receive) + { + sim_debug(DBG_INF, controller->device, "Starting data output transfer for receive, address=0x%08x, count=%d\n", addr, count); + dmc_set_out_io(controller); + } + else + { + sim_debug(DBG_INF, controller->device, "Starting data output transfer for transmit, address=0x%08x, count=%d\n", addr, count); + dmc_clear_out_io(controller); + } + + dmc_setreg(controller, 4, addr & 0xFFFF, 0); + dmc_setreg(controller, 6, (((addr & 0x30000)) >> 2) | count, 0); + controller->transfer_state = OutputTransfer; + dmc_set_type_output(controller, TYPE_BACCO); + dmc_set_rdyo(controller); +} + +void dmc_start_control_output_transfer(CTLR *controller) +{ + sim_debug(DBG_INF, controller->device, "Starting control output transfer\n"); + controller->transfer_state = OutputTransfer; + dmc_set_type_output(controller, TYPE_CNTLO); + dmc_set_rdyo(controller); +} + +t_stat dmc_svc(UNIT* uptr) +{ + CTLR *controller; + int32 poll; + + TIMER *poll_timer = &dmc_get_unit_stats(uptr)->poll_timer; + TIMER *between_polls_timer = &dmc_get_unit_stats(uptr)->between_polls_timer; + + poll = clk_cosched (tmxr_poll); + + if (dmc_timer_started(between_polls_timer)) + { + dmc_timer_stop(between_polls_timer); + } + + if (dmc_timer_started(poll_timer)) + { + dmc_timer_resume(poll_timer); + } + else + { + dmc_timer_start(poll_timer); + } + + controller = dmc_get_controller_from_unit(uptr); + + if (dmc_isattached(controller)) + { + dmc_line_update_speed_stats(controller->line); + + dmc_buffer_fill_receive_buffers(controller); + if (controller->transfer_state == Idle) dmc_start_transfer_receive_buffer(controller); + + dmc_buffer_send_transmit_buffers(controller); + if (controller->transfer_state == Idle) dmc_start_transfer_transmit_buffer(controller); + } + + /* resubmit service timer */ + sim_activate(controller->device->units, poll); + + dmc_timer_stop(poll_timer); + if (dmc_timer_started(between_polls_timer)) + { + dmc_timer_resume(between_polls_timer); + } + else + { + dmc_timer_start(between_polls_timer); + } + dmc_get_unit_stats(uptr)->poll_count++; + + return SCPE_OK; +} + +void dmc_line_update_speed_stats(LINE *line) +{ + clock_t current = clock(); + int current_second = current / CLOCKS_PER_SEC; + if (current_second != line->last_second) + { + line->bytes_received_in_last_second = 0; + line->bytes_sent_in_last_second = 0; + line->last_second = current_second; + } +} + +/* given the number of bytes sent/received in the last second, the number of bytes to send or receive and the line speed, calculate how many bytes can be sent/received now */ +int dmc_line_speed_calculate_byte_length(int bytes_in_last_second, int num_bytes, int speed) +{ + int ans; + + if (speed == 0) + { + ans = num_bytes; + } + else + { + int clocks_this_second = clock() % CLOCKS_PER_SEC; + int allowable_bytes_to_date = ((speed/8) * clocks_this_second)/CLOCKS_PER_SEC; + int allowed_bytes = allowable_bytes_to_date - bytes_in_last_second; + if (allowed_bytes < 0) + { + allowed_bytes = 0; + } + + if (num_bytes > allowed_bytes) + { + ans = allowed_bytes; + } + else + { + ans = num_bytes; + } +//sim_debug(DBG_WRN, dmc_ctrls[0].device, "Bytes in last second %4d, clocks this sec %3d allowable bytes %4d, requested %4d allowed %4d\n", bytes_in_last_second, clocks_this_second, allowable_bytes_to_date, num_bytes, ans); + } + + return ans; +} + +void dmc_buffer_trace_line(int tracelevel, CTLR *controller, uint8 *buf, int length, char *prefix) +{ + char hex[TRACE_BYTES_PER_LINE*3+1]; + char ascii[TRACE_BYTES_PER_LINE+1]; + int i; + hex[0] = 0; + ascii[TRACE_BYTES_PER_LINE] = 0; + + for (i = 0; i=length) + { + strcat(hex, " "); + ascii[i] = ' '; + } + else + { + char hexByte[4]; + sprintf(hexByte, "%02X ", buf[i]); + strcat(hex, hexByte); + if (isprint(buf[i])) + { + ascii[i] = (char)buf[i]; + } + else + { + ascii[i] = '.'; + } + } + } + + sim_debug(tracelevel, controller->device, "%s %s %s\n", prefix, hex, ascii); +} + +void dmc_buffer_trace(CTLR *controller, uint8 *buf, int length, char *prefix, uint32 address) +{ + int i; + if (length >= 0 && controller->device->dctrl & DBG_DAT) + { + sim_debug(DBG_DAT, controller->device, "%s Buffer address 0x%08x (%d bytes)\n", prefix, address, length); + for(i = 0; i < length / TRACE_BYTES_PER_LINE; i++) + { + dmc_buffer_trace_line(DBG_DAT, controller, buf + i*TRACE_BYTES_PER_LINE, TRACE_BYTES_PER_LINE, prefix); + } + + if (length %TRACE_BYTES_PER_LINE > 0) + { + dmc_buffer_trace_line(DBG_DAT, controller, buf + length/TRACE_BYTES_PER_LINE, length % TRACE_BYTES_PER_LINE, prefix); + } + } + else if (length >= 0 && controller->device->dctrl & DBG_DTS) + { + char prefix2[80]; + sprintf(prefix2, "%s (len=%d)", prefix, length); + dmc_buffer_trace_line(DBG_DTS, controller, buf, (length > TRACE_BYTES_PER_LINE)? TRACE_BYTES_PER_LINE : length, prefix2); + } +} + +void dmc_buffer_queue_init(CTLR *controller, BUFFER_QUEUE *q, char *name) +{ + q->name = name; + q->head = 0; + q->tail = 0; + q->count = 0; + q->controller = controller; +} + +int dmc_buffer_queue_full(BUFFER_QUEUE *q) +{ + return q->count > BUFFER_QUEUE_SIZE; +} + +void dmc_buffer_queue_add(BUFFER_QUEUE *q, uint32 address, uint16 count) +{ + if (!dmc_buffer_queue_full(q)) + { + int new_buffer = 0; + if (q->count > 0) + { + int last_buffer = q->tail; + new_buffer = (q->tail +1) % BUFFER_QUEUE_SIZE; + + /* Link last buffer to the new buffer */ + q->queue[last_buffer].next = &q->queue[new_buffer]; + } + else + { + q->head = 0; + new_buffer = 0; + } + + q->tail = new_buffer; + q->queue[new_buffer].address = address; + q->queue[new_buffer].count = count; + q->queue[new_buffer].actual_block_len = 0; + q->queue[new_buffer].transfer_buffer = NULL; + q->queue[new_buffer].block_len_bytes_read = 0; + q->queue[new_buffer].actual_bytes_transferred = 0; + q->queue[new_buffer].next = NULL; + q->queue[new_buffer].state = Available; + q->queue[new_buffer].is_loopback = dmc_is_lu_loop_set(q->controller); + q->count++; + sim_debug(DBG_INF, q->controller->device, "Queued %s buffer address=0x%08x count=%d\n", q->name, address, count); + } + else + { + sim_debug(DBG_WRN, q->controller->device, "Failed to queue %s buffer address=0x%08x, queue full\n", q->name, address); + // TODO: Report error here. + } +} + +void dmc_buffer_queue_release_head(BUFFER_QUEUE *q) +{ + if (q->count > 0) + { + q->head = (q->head + 1) % BUFFER_QUEUE_SIZE; + q->count--; + } + else + { + sim_debug(DBG_INF, q->controller->device, "Failed to release %s buffer, queue already empty\n", q->name); + } +} + +BUFFER *dmc_buffer_queue_head(BUFFER_QUEUE *q) +{ + BUFFER *ans = NULL; + if (q->count >0) + { + ans = &q->queue[q->head]; + } + + return ans; +} + +BUFFER *dmc_buffer_queue_find_first_available(BUFFER_QUEUE *q) +{ + BUFFER *ans = dmc_buffer_queue_head(q); + while (ans != NULL) + { + if (ans->state == Available) + { + break; + } + + ans = ans->next; + } + + return ans; +} + +BUFFER *dmc_buffer_queue_find_first_contains_data(BUFFER_QUEUE *q) +{ + BUFFER *ans = dmc_buffer_queue_head(q); + while (ans != NULL) + { + if (ans->state == ContainsData) + { + break; + } + + ans = ans->next; + } + + return ans; +} + +void dmc_buffer_queue_get_stats(BUFFER_QUEUE *q, int *available, int *contains_data, int *transfer_in_progress) +{ + BUFFER *buf = dmc_buffer_queue_head(q); + *available = 0; + *contains_data = 0; + *transfer_in_progress = 0; + + while (buf != NULL) + { + switch (buf->state) + { + case Available: + { + (*available)++; + break; + } + + case ContainsData: + { + (*contains_data)++; + break; + } + + case TransferInProgress: + { + (*transfer_in_progress)++; + break; + } + } + + buf = buf->next; + } +} + +t_stat dmc_open_master_socket(CTLR *controller, char *port) +{ + t_stat ans; + ans = SCPE_OK; + if (controller->master_socket == INVALID_SOCKET) + { + controller->master_socket = sim_master_sock(port, &ans); + if (controller->master_socket == INVALID_SOCKET) + { + sim_debug(DBG_WRN, controller->device, "Failed to open master socket on port %s\n", port); + ans = SCPE_OPENERR; + } + else + { + printf ("DMC-11 %s listening on port %s\n", controller->device->name, port); + } + } + + return ans; +} + +t_stat dmc_close_master_socket(CTLR *controller) +{ + sim_close_sock (controller->master_socket, TRUE); + controller->master_socket = INVALID_SOCKET; + return SCPE_OK; +} + +// Gets the bidirectional socket and handles arbitration of determining which socket to use. +int dmc_get_socket(CTLR *controller, int forRead) +{ + int ans = 0; + if (controller->line->isPrimary) + { + ans = dmc_get_transmit_socket(controller, 0, forRead); // TODO: After change to single socket, loopback may not work. + } + else + { + ans = dmc_get_receive_socket(controller, forRead); // TODO: After change to single socket, loopback may not work. + } + return ans; +} + +int dmc_get_receive_socket(CTLR *controller, int forRead) +{ + int ans = 0; + if (controller->line->socket == INVALID_SOCKET) + { + char *ipaddr; + //sim_debug(DBG_SOK, controller->device, "Trying to open receive socket\n"); + controller->line->socket = sim_accept_conn (controller->master_socket, &ipaddr); /* poll connect */ + if (controller->line->socket != INVALID_SOCKET) + { + char host[sizeof(controller->line->transmit_host)]; + + if (sim_parse_addr (controller->line->transmit_host, host, sizeof(host), NULL, NULL, 0, NULL, ipaddr)) + { + sim_debug(DBG_WRN, controller->device, "Received connection from unexpected source IP %s. Closing the connection.\n", ipaddr); + dmc_close_receive(controller, "Unathorized connection", ipaddr); + } + else + { + sim_debug(DBG_SOK, controller->device, "Opened receive socket %d\n", controller->line->socket); + controller->line->receive_readable = FALSE; + } + free(ipaddr); + } + } + + if (controller->line->socket != INVALID_SOCKET) + { + int readable = sim_check_conn(controller->line->socket, forRead); + if (readable == 0) /* Still opening */ + { + // Socket is still being opened, or is open but there is no data ready to be read. + ans = 0; + } + else if (readable == -1) /* Failed to open */ + { + dmc_close_receive(controller, "failed to connect", NULL); + ans = 0; + } + else /* connected */ + { + if (!controller->line->receive_readable) + { + sim_debug(DBG_CON, controller->device, "Receive socket is now readable\n"); + } + controller->line->receive_readable = TRUE; + ans = 1; + } + } + + return ans; +} + +int dmc_get_transmit_socket(CTLR *controller, int is_loopback, int forRead) +{ + int ans = 0; + /* close transmit socket if there is a change in the loopback setting */ + if (is_loopback ^ controller->line->transmit_is_loopback) + { + dmc_close_transmit(controller, "loopback change"); + } + + if (controller->line->socket == INVALID_SOCKET && ((int32)(time(NULL) - controller->line->last_connect_attempt)) > controller->connect_poll_interval) + { + char host_port_buf[CBUFSIZE]; + char *host_port = host_port_buf; + + controller->line->transmit_is_loopback = is_loopback; + + controller->line->last_connect_attempt = time(NULL); + if (is_loopback) + { + if (strrchr(controller->line->receive_port, ':')) + { + host_port = controller->line->receive_port; + } + else + { + sprintf(host_port_buf, "localhost:%s", controller->line->receive_port); + } + } + else + { + host_port = controller->line->transmit_host; + } + + sim_debug(DBG_SOK, controller->device, "Trying to open transmit socket to address:port %s\n", host_port); + controller->line->last_connect_attempt = time(NULL); + controller->line->socket = sim_connect_sock(host_port, NULL, NULL); + if (controller->line->socket != INVALID_SOCKET) + { + sim_debug(DBG_SOK, controller->device, "Opened transmit socket to port %s\n", host_port); + controller->line->transmit_writeable = FALSE; + } + } + + if (controller->line->socket != INVALID_SOCKET) + { + int writeable = sim_check_conn(controller->line->socket, forRead); + if (writeable == 0) /* Still opening */ + { + //sim_debug(DBG_SOK, controller->device, "Waiting for transmit socket to become writeable\n"); + ans = 0; + } + else if (writeable == -1) /* Failed to open */ + { + dmc_close_transmit(controller, "failed to connect"); + ans = 0; + } + else /* connected */ + { + if (!controller->line->transmit_writeable) + { + sim_debug(DBG_CON, controller->device, "Transmit socket is now writeable\n"); + } + controller->line->transmit_writeable = TRUE; + ans = 1; + } + } + + return ans; +} + +void dmc_close_receive(CTLR *controller, char *reason, char *from) +{ + sim_debug(DBG_SOK, controller->device, "Closing receive socket on port %s, reason: %s%s%s\n", controller->line->receive_port, reason, from ? " from " : "", from ? from : ""); + sim_close_sock(controller->line->socket, FALSE); + controller->line->socket = INVALID_SOCKET; + + if (controller->line->receive_readable) + { + sim_debug(DBG_CON, controller->device, "Readable receive socket closed, reason: %s\n", reason); + } + controller->line->receive_readable = FALSE; +} + +void dmc_error_and_close_receive(CTLR *controller, char *format) +{ + int err = WSAGetLastError(); + char errmsg[80]; + sprintf(errmsg, format, err); + if (controller->line->isPrimary) + { + dmc_close_transmit(controller, errmsg); + } + else + { + dmc_close_receive(controller, errmsg, NULL); + } +} + +void dmc_close_transmit(CTLR *controller, char *reason) +{ + sim_debug(DBG_SOK, controller->device, "Closing transmit socket to port %s, socket %d, reason: %s\n", controller->line->transmit_host, controller->line->socket, reason); + sim_close_sock(controller->line->socket, FALSE); + controller->line->socket = INVALID_SOCKET; + + if (controller->line->transmit_writeable) + { + sim_debug(DBG_CON, controller->device, "Writeable transmit socket closed, reason: %s\n", reason); + } + controller->line->transmit_writeable = FALSE; +} + +/* returns true if some data was received */ +int dmc_buffer_fill_receive_buffers(CTLR *controller) +{ + int ans = FALSE; + SOCKET socket; + if (controller->state == Initialised) + { + /* accept any inbound connection but just throw away any data */ + if (dmc_get_socket(controller, TRUE)) + { + char buffer[1000]; + int bytes_read = 0; + socket = controller->line->socket; + bytes_read = sim_read_sock(socket, buffer, sizeof(buffer)); + if (bytes_read < 0) + { + dmc_error_and_close_receive(controller, "read error, code=%d"); + } + else if (bytes_read > 0) + { + sim_debug(DBG_SOK, controller->device, "Discarding received data while controller is not running\n"); + } + } + } + else + { + BUFFER *buffer = dmc_buffer_queue_find_first_available(controller->receive_queue); + while (buffer != NULL && buffer->state == Available) + { + if (dmc_get_socket(controller, TRUE)) + { + int bytes_read = 0; + int lost_data = 0; + + socket = controller->line->socket; + /* read block length and allocate buffer */ + if ((size_t)buffer->block_len_bytes_read < sizeof(buffer->actual_block_len)) + { + char *start_addr = ((char *)&buffer->actual_block_len) + buffer->block_len_bytes_read; + bytes_read = sim_read_sock(socket, start_addr, sizeof(buffer->actual_block_len) - buffer->block_len_bytes_read); + if (bytes_read >= 0) + { + buffer->block_len_bytes_read += bytes_read; + if (buffer->block_len_bytes_read == sizeof(buffer->actual_block_len)) + { + buffer->actual_block_len = ntohs(buffer->actual_block_len); + if (buffer->actual_block_len > buffer->count) + { + sim_debug(DBG_WRN, controller->device, "LOST DATA, buffer available has %d bytes, but the block is %d bytes\n", buffer->count, buffer->actual_block_len); + dmc_setreg(controller, 4, 0, 0); + dmc_setreg(controller, 6, 0, 0); + dmc_set_lost_data(controller); + dmc_start_control_output_transfer(controller); + lost_data = 1; + } + + if (buffer->actual_block_len > 0) + { + buffer->transfer_buffer = (uint8 *)malloc(buffer->actual_block_len); /* read full buffer regardless, so bad buffer is flushed */ + } + } + } + } + else + { + lost_data = buffer->actual_block_len > buffer->count; /* need to preserve this variable if need more than one attempt to read the buffer */ + } + + /* read the actual block */ + if (buffer->block_len_bytes_read == sizeof(buffer->actual_block_len)) + { + bytes_read = 0; + if (buffer->actual_block_len > 0) + { + int bytes_to_read = dmc_line_speed_calculate_byte_length(controller->line->bytes_received_in_last_second, buffer->actual_block_len - buffer->actual_bytes_transferred, controller->line->speed); + if (bytes_to_read > 0) + { + bytes_read = sim_read_sock(controller->line->socket, (char *)(buffer->transfer_buffer + buffer->actual_bytes_transferred), bytes_to_read); + } + } + + if (bytes_read >= 0) + { + buffer->actual_bytes_transferred += bytes_read; + controller->line->bytes_received_in_last_second += bytes_read; + + if (buffer->actual_bytes_transferred >= buffer->actual_block_len) + { + dmc_buffer_trace(controller, buffer->transfer_buffer, buffer->actual_bytes_transferred, "REC ", buffer->address); + controller->buffers_received_from_net++; + buffer->state = ContainsData; + if (!lost_data) + { + Map_WriteB(buffer->address, buffer->actual_bytes_transferred, buffer->transfer_buffer); + } + else + { + buffer->actual_block_len = 0; /* so an empty buffer is returned to the driver */ + } + + if (buffer->actual_block_len > 0) + { + free(buffer->transfer_buffer); + buffer->transfer_buffer = NULL; + } + + ans = TRUE; + } + } + } + + /* Only close the socket if there was an error or no more data */ + if (bytes_read < 0) + { + dmc_error_and_close_receive(controller, "read error, code=%d"); + break; + } + + /* if buffer is incomplete do not try to read any more buffers and continue filling this one later */ + if (buffer->state == Available) + { + break; /* leave buffer available and continue filling it later */ + } + } + else + { + break; + } + + buffer = buffer ->next; + } + } + + return ans; +} + +/* returns true if some data was actually sent */ +int dmc_buffer_send_transmit_buffers(CTLR *controller) +{ + int ans = FALSE; + /* when transmit buffer is queued it is marked as available, not as ContainsData */ + BUFFER *buffer = dmc_buffer_queue_find_first_available(controller->transmit_queue); + while (buffer != NULL) + { + if (dmc_get_socket(controller, FALSE)) // TODO: , buffer->is_loopback); + { + int bytes = 0; + int bytes_to_send; + uint16 block_len; + int total_buffer_len = (buffer->count > 0) ? buffer->count + sizeof(block_len) : 0; + + /* only send the buffer if it actually has some data, sometimes get zero length buffers - don't send these */ + if (total_buffer_len > 0) + { + if (buffer->transfer_buffer == NULL) + { + int n; + /* construct buffer and include block length bytes */ + buffer->transfer_buffer = (uint8 *)malloc(total_buffer_len); + block_len = htons(buffer->count); + memcpy(buffer->transfer_buffer, (char *)&block_len, sizeof(block_len)); + n = Map_ReadB(buffer->address, buffer->count, buffer->transfer_buffer + sizeof(block_len)); + if (n > 0) + { + sim_debug(DBG_WRN, controller->device, "DMA error\n"); + } + } + + bytes_to_send = dmc_line_speed_calculate_byte_length(controller->line->bytes_sent_in_last_second, buffer->count + sizeof(block_len) - buffer->actual_bytes_transferred, controller->line->speed); + if (bytes_to_send > 0) + { + bytes = sim_write_sock (controller->line->socket, (char *)(buffer->transfer_buffer + buffer->actual_bytes_transferred), bytes_to_send); + if (bytes >= 0) + { + buffer->actual_bytes_transferred += bytes; + controller->line->bytes_sent_in_last_second += bytes; + } + + if (buffer->actual_bytes_transferred >= total_buffer_len || bytes < 0) + { + dmc_buffer_trace(controller, buffer->transfer_buffer+sizeof(block_len), buffer->count, "TRAN", buffer->address); + free(buffer->transfer_buffer); + } + } + } + + if (buffer->actual_bytes_transferred >= total_buffer_len) + { + controller->buffers_transmitted_to_net++; + buffer->state = ContainsData; // so won't try to transmit again + ans = TRUE; + } + else if (bytes < 0) + { + int err = WSAGetLastError (); + char errmsg[80]; + sprintf(errmsg, "write failure, code=%d", err); + + dmc_close_transmit(controller, errmsg); + break; + } + else + { + break; /* poll again later to send more bytes */ + } + + } + else + { + break; + } + + buffer = buffer ->next; + } + + return ans; +} + +void dmc_start_transfer_receive_buffer(CTLR *controller) +{ + BUFFER *head = dmc_buffer_queue_head(controller->receive_queue); + if (head != NULL) + { + if (head->state == ContainsData) + { + head->state = TransferInProgress; + dmc_start_data_output_transfer(controller, head->address, head->actual_block_len, TRUE); + } + } +} + +void dmc_start_transfer_transmit_buffer(CTLR *controller) +{ + BUFFER *head = dmc_buffer_queue_head(controller->transmit_queue); + if (head != NULL) + { + if (head->state == ContainsData) + { + head->state = TransferInProgress; + dmc_start_data_output_transfer(controller, head->address, head->count, FALSE); + } + } +} + +void dmc_check_for_output_transfer_completion(CTLR *controller) +{ + if (!dmc_is_rdyo_set(controller)) + { + sim_debug(DBG_INF, controller->device, "Output transfer completed\n"); + controller->transfer_state = Idle; + if (dmc_get_output_transfer_type(controller) == TYPE_BACCO) + { + if (dmc_is_out_io_set(controller)) + { + dmc_buffer_queue_release_head(controller->receive_queue); + controller->receive_buffer_output_transfers_completed++; + } + else + { + dmc_buffer_queue_release_head(controller->transmit_queue); + controller->transmit_buffer_output_transfers_completed++; + } + } + dmc_process_command(controller); // check for any input transfers + } +} + +void dmc_process_input_transfer_completion(CTLR *controller) +{ + if (dmc_is_dmc(controller)) + { + if (!dmc_is_rqi_set(controller)) + { + uint16 sel4 = controller->csrs->sel4; + uint16 sel6 = controller->csrs->sel6; + dmc_clear_rdyi(controller); + if (controller->transfer_type == TYPE_BASEI) + { + uint32 baseaddr = ((sel6 >> 14) << 16) | sel4; + uint16 count = sel6 & 0x3FFF; + sim_debug(DBG_INF, controller->device, "Completing Base In input transfer, base address=0x%08x count=%d\n", baseaddr, count); + } + else if (controller->transfer_type == TYPE_BACCI) + { + uint32 addr = ((sel6 >> 14) << 16) | sel4; + uint16 count = sel6 & 0x3FFF; + if (controller->transfer_in_io != dmc_is_in_io_set(controller)) + { + sim_debug(DBG_TRC, controller->device, "IN IO MISMATCH\n"); + } + + controller->transfer_in_io = dmc_is_in_io_set(controller); // using evdmc the flag is set when the transfer completes - not when it starts, evdca seems to set in only at the start of the transfer - clearing it when it completes + controller->state = Running; + if (controller->transfer_in_io) + { + dmc_buffer_queue_add(controller->receive_queue, addr, count); + dmc_buffer_fill_receive_buffers(controller); + controller->receive_buffer_input_transfers_completed++; + } + else + { + dmc_buffer_queue_add(controller->transmit_queue, addr, count); + dmc_buffer_send_transmit_buffers(controller); + controller->transmit_buffer_input_transfers_completed++; + } + } + + controller->transfer_state = Idle; + } + } + else + { + if (!dmc_is_rdyi_set(controller)) + { + uint16 sel6 = controller->csrs->sel6; + if (controller->transfer_type == TYPE_DMP_MODE) + { + uint16 mode = sel6 & DMP_TYPE_INPUT_MASK; + char * duplex = (mode & 1) ? "Full-Duplex" : "Half-Duplex"; + char * config; + if (mode & 4) + { + config = "Point-to-point"; + } + else + { + config = (mode & 2) ? "Tributary station" : "Control Station"; + } + + sim_debug(DBG_INF, controller->device, "Completing Mode input transfer, %s %s\n", duplex, config); + } + else if (controller->transfer_type == TYPE_DMP_CONTROL) + { + sim_debug(DBG_WRN, controller->device, "Control command (not processed yet)\n"); + } + else if (controller->transfer_type == TYPE_DMP_RECEIVE) + { + sim_debug(DBG_WRN, controller->device, "Receive Buffer command (not processed yet)\n"); + } + else if (controller->transfer_type == TYPE_DMP_TRANSMIT) + { + sim_debug(DBG_WRN, controller->device, "Transmit Buffer command (not processed yet)\n"); + } + else + { + sim_debug(DBG_WRN, controller->device, "Unrecognised command code %hu\n", controller->transfer_type); + } + + controller->transfer_state = Idle; + } + } +} + +void dmc_process_command(CTLR *controller) +{ + if (dmc_is_master_clear_set(controller)) + { + dmc_process_master_clear(controller); + } + else + { + if (controller->transfer_state == InputTransfer) + { + dmc_process_input_transfer_completion(controller); + } + else if (controller->transfer_state == OutputTransfer) + { + dmc_check_for_output_transfer_completion(controller); + } + else if (dmc_is_rqi_set(controller)) + { + dmc_start_input_transfer(controller); + } + } +} + +t_stat dmc_rd(int32 *data, int32 PA, int32 access) +{ + CTLR *controller = dmc_get_controller_from_address(PA); + sim_debug(DBG_TRC, controller->device, "dmc_rd(), addr=0x%x access=%d\n", PA, access); + *data = dmc_getreg(controller, PA, 1); + + return SCPE_OK; +} + +t_stat dmc_wr(int32 data, int32 PA, int32 access) +{ + CTLR *controller = dmc_get_controller_from_address(PA); + int reg = PA & 07; + uint16 oldValue = dmc_getreg(controller, PA, 0); + if (access == WRITE) + { + sim_debug(DBG_TRC, controller->device, "dmc_wr(), addr=0x%08x, SEL%d, data=0x%04x\n", PA, reg, data); + } + else + { + sim_debug(DBG_TRC, controller->device, "dmc_wr(), addr=0x%08x, BSEL%d, data=%04x\n", PA, reg, data); + } + + if (access == WRITE) + { + if (PA & 1) + sim_debug(DBG_WRN, controller->device, "dmc_wr(), Unexpected non-16-bit write access to SEL%d\n", reg); + dmc_setreg(controller, PA, data, 1); + } + else + { + uint16 mask; + if (PA & 1) + { + mask = 0xFF00; + data = data << 8; + } + else + { + mask = 0x00FF; + } + + dmc_setreg(controller, PA, (oldValue & ~mask) | (data & mask), 1); + } + + if (dmc_getsel(reg) == 0 || dmc_getsel(reg) == 1) + { + dmc_process_command(controller); + } + + return SCPE_OK; +} + +int32 dmc_rxint (void) +{ + int i; + int32 ans = 0; /* no interrupt request active */ + for (i=0; irxi != 0) + { + DIB *dib = (DIB *)controller->device->ctxt; + ans = dib->vec; + dmc_clrrxint(controller); + break; + } + } + + return ans; + } + +int32 dmc_txint (void) +{ + int i; + int32 ans = 0; /* no interrupt request active */ + for (i=0; itxi != 0) + { + DIB *dib = (DIB *)controller->device->ctxt; + ans = dib->vec + 4; + dmc_clrtxint(controller); + break; + } + } + + return ans; +} + +t_stat dmc_reset (DEVICE *dptr) +{ + t_stat ans = SCPE_OK; + CTLR *controller = dmc_get_controller_from_device(dptr); + + sim_debug(DBG_TRC, dptr, "dmc_reset()\n"); + + if (dmc_get_unit_stats(dptr->units) == NULL) + { + dmc_set_unit_stats(dptr->units, (UNIT_STATS *)malloc(sizeof(UNIT_STATS))); + dmc_reset_unit_stats(dmc_get_unit_stats(dptr->units)); + } + + dmc_clrrxint(controller); + dmc_clrtxint(controller); + sim_cancel (controller->device->units); /* stop poll */ + + if (!(dptr->flags & DEV_DIS)) + { + ans = auto_config (dptr->name, DMC_UNITSPERDEVICE); + } + return ans; +} + +t_stat dmc_attach (UNIT *uptr, char *cptr) +{ + CTLR *controller = dmc_get_controller_from_unit(uptr); + t_stat ans = SCPE_OK; + + ans = dmc_open_master_socket(controller, cptr); + if (ans == SCPE_OK) + { + controller->line->socket = INVALID_SOCKET; + uptr->flags = uptr->flags | UNIT_ATT; /* set unit attached flag */ + uptr->filename = (char *)malloc(strlen(cptr)+1); + strcpy(uptr->filename, cptr); + controller->line->receive_port = uptr->filename; + //sim_activate_abs(controller->device->units, clk_cosched (tmxr_poll)); + } + + return ans; +} + +int dmc_isattached(CTLR *controller) +{ + return controller->master_socket != INVALID_SOCKET; +} + +t_stat dmc_detach (UNIT *uptr) +{ + CTLR *controller = dmc_get_controller_from_unit(uptr); + dmc_error_and_close_receive(controller, "Detach"); + dmc_close_master_socket(controller); + uptr->flags = uptr->flags & ~UNIT_ATT; /* clear unit attached flag */ + free(uptr->filename); + uptr->filename = NULL; + sim_cancel(uptr); + + return SCPE_OK; +} diff --git a/PDP11/pdp11_dmc.h b/PDP11/pdp11_dmc.h new file mode 100644 index 00000000..3984960c --- /dev/null +++ b/PDP11/pdp11_dmc.h @@ -0,0 +1,132 @@ +/* pdp11_dmc.h: DMC11 Emulation + ------------------------------------------------------------------------------ + + Copyright (c) 2011, Robert M. A. Jarratt + + 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 + THE AUTHOR 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. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------*/ + +// Notes +// Base address needs to be 760060 according to DMC11 manual, but SYSGEN seems to think CSR is 0760100. However if I use +// 0760100 I get a conflict with the DZ because the first 13 bits are still 00100. If I use 760060 VMS sees the XM device, but +// if I remove the DZ to prevent the conflict VMS does not see an XM device, but I do get lots of reads and writes, possibly +// because it thinks it is a different device. What worries me more though is that there seems to be overlap in the 13-bit base +// addresses of the DZ and DMC. + + +#ifndef _PDP11_DMC_H +#define _PDP11_DMC_H + +#if defined (VM_VAX) /* VAX version */ +#include "vax_defs.h" +extern int32 int_req[IPL_HLVL]; +#else /* PDP-11 version */ +#include "pdp11_defs.h" +extern int32 int_req[IPL_HLVL]; +#endif + +#include "sim_sock.h" + +#define DMC_NUMDEVICE 4 /* # DMC-11 devices */ +#define DMC_UNITSPERDEVICE 1 /* # units per DMC-11 */ + +#define DMP_NUMDEVICE 1 /* # DMP-11 devices */ +#define DMP_UNITSPERDEVICE 1 /* # units per DMP-11 */ + +#define DMC_RDX 8 + +/* debugging bitmaps */ +#define DBG_TRC 0x0001 /* trace routine calls */ +#define DBG_REG 0x0002 /* trace read/write registers */ +#define DBG_WRN 0x0004 /* display warnings */ +#define DBG_INF 0x0008 /* display informational messages (high level trace) */ +#define DBG_DAT 0x0010 /* display data buffer contents */ +#define DBG_DTS 0x0020 /* display data summary */ +#define DBG_SOK 0x0040 /* display socket open/close */ +#define DBG_CON 0x0080 /* display socket connection establishment */ + +#define TYPE_BACCI 0 +#define TYPE_CNTLI 1 +#define TYPE_BASEI 03 +#define TYPE_BACCO 0 +#define TYPE_CNTLO 1 + +#define TYPE_DMP_MODE 2 +#define TYPE_DMP_CONTROL 1 +#define TYPE_DMP_RECEIVE 0 +#define TYPE_DMP_TRANSMIT 4 + + +/* SEL0 */ +#define DMC_TYPE_INPUT_MASK 0x0003 +#define DMC_IN_IO_MASK 0x0004 +#define DMP_IEO_MASK 0x0010 +#define DMC_RQI_MASK 0x0020 +#define DMP_RQI_MASK 0x0080 +#define DMC_RDYI_MASK 0x0080 +#define DMC_IEI_MASK 0x0040 +#define DMP_IEI_MASK 0x0001 +#define LU_LOOP_MASK 0x0800 +#define MASTER_CLEAR_MASK 0x4000 +#define RUN_MASK 0x8000 + +/* SEL2 */ +#define DMP_IN_IO_MASK 0x0004 +#define DMP_TYPE_INPUT_MASK 0x0007 +#define TYPE_OUTPUT_MASK 0x0003 +#define OUT_IO_MASK 0x0004 +#define DMC_RDYO_MASK 0x0080 +#define DMC_IEO_MASK 0x0040 +#define DMP_RDYI_MASK 0x0010 + +/* BSEL6 */ +#define LOST_DATA_MASK 0x0010 +#define DISCONNECT_MASK 0x0040 + +#define SEL0_RUN_BIT 15 +#define SEL0_MCLR_BIT 14 +#define SEL0_LU_LOOP_BIT 11 +#define SEL0_RDI_BIT 7 +#define SEL0_DMC_IEI_BIT 6 +#define SEL0_DMP_IEI_BIT 0 +#define SEL0_DMP_IEO_BIT 4 +#define SEL0_DMC_RQI_BIT 5 +#define SEL0_DMP_RQI_BIT 7 +#define SEL0_IN_IO_BIT 2 +#define SEL0_TYPEI_BIT 0 + +#define SEL2_TYPEO_BIT 0 +#define SEL2_RDO_BIT 7 +#define SEL2_IEO_BIT 6 +#define SEL2_OUT_IO_BIT 2 +#define SEL2_LINE_BIT 8 +#define SEL2_LINE_BIT_LENGTH 6 +#define SEL2_PRIO_BIT 14 +#define SEL2_PRIO_BIT_LENGTH 2 + +#define SEL6_LOST_DATA_BIT 4 +#define SEL6_DISCONNECT_BIT 6 + +#define BUFFER_QUEUE_SIZE 7 + +#endif /* _VAX_DMC_H */ diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index bdaee4f7..15f5145d 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -124,9 +124,26 @@ extern int32 int_req[IPL_HLVL]; #define RBUF_VALID 0100000 /* rcv valid */ #define RBUF_MBZ 0004000 +char *dz_charsizes[] = {"5", "6", "7", "8"}; +char *dz_baudrates[] = {"50", "75", "110", "134.5", "150", "300", "600", "1200", + "1800", "2000", "2400", "3600", "4800", "7200", "9600", "19200"}; +char *dz_parity[] = {"N", "E", "N", "O"}; +char *dz_stopbits[] = {"1", "2", "1", "1.5"}; + /* DZLPR - 160102 - line parameter register, write only, word access only */ #define LPR_V_LINE 0 /* line */ +#define LPR_V_SPEED 8 /* speed code */ +#define LPR_M_SPEED 0007400 /* speed code mask */ +#define LPR_V_CHARSIZE 3 /* char size code */ +#define LPR_M_CHARSIZE 0000030 /* char size code mask */ +#define LPR_V_STOPBITS 5 /* stop bits code */ +#define LPR_V_PARENB 6 /* parity enable */ +#define LPR_V_PARODD 7 /* parity odd */ +#define LPR_GETSPD(x) dz_baudrates[((x) & LPR_M_SPEED) >> LPR_V_SPEED] +#define LPR_GETCHARSIZE(x) dz_charsizes[((x) & LPR_M_CHARSIZE) >> LPR_V_CHARSIZE] +#define LPR_GETPARITY(x) dz_parity[(((x) >> LPR_V_PARENB) & 1) | (((x) >> (LPR_V_PARODD-1)) & 2)] +#define LPR_GETSTOPBITS(x) dz_stopbits[(((x) >> LPR_V_STOPBITS) & 1) + (((((x) & LPR_M_CHARSIZE) >> LPR_V_CHARSIZE) == 5) ? 2 : 0)] #define LPR_LPAR 0007770 /* line pars - NI */ #define LPR_RCVE 0010000 /* receive enb */ #define LPR_GETLN(x) (((x) >> LPR_V_LINE) & DZ_LNOMASK) @@ -170,12 +187,16 @@ TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, NULL }; /* mux descriptor */ #define DBG_INT 0x0002 /* display transfer requests */ #define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */ #define DBG_RCV TMXR_DBG_RCV /* display Received Data */ +#define DBG_TRC TMXR_DBG_TRC /* display trace routine calls */ +#define DBG_ASY TMXR_DBG_ASY /* display Asynchronous Activities */ DEBTAB dz_debug[] = { {"REG", DBG_REG}, {"INT", DBG_INT}, {"XMT", DBG_XMT}, {"RCV", DBG_RCV}, + {"TRC", DBG_TRC}, + {"ASY", DBG_ASY}, {0} }; @@ -268,7 +289,7 @@ DEVICE dz_dev = { 1, DEV_RDX, 8, 1, DEV_RDX, 8, &tmxr_ex, &tmxr_dep, &dz_reset, NULL, &dz_attach, &dz_detach, - &dz_dib, DEV_FLTA | DEV_DISABLE | DEV_NET | DEV_UBUS | DEV_QBUS | DEV_DEBUG, + &dz_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG, 0, dz_debug }; @@ -282,6 +303,7 @@ static char *dz_wr_regs[] = t_stat dz_rd (int32 *data, int32 PA, int32 access) { +int i; int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */ switch ((PA >> 1) & 03) { /* case on PA<2:1> */ @@ -311,6 +333,20 @@ switch ((PA >> 1) & 03) { /* case on PA<2:1> */ break; case 03: /* MSR */ + if (dz_mctl) + for (i=0; i> 3) & DZ_MNOMASK; /* get mux num */ int32 i, c, line; +char lineconfig[16]; TMLN *lp; sim_debug(DBG_REG, &dz_dev, "dz_wr(PA=0x%08X [%s], access=%d, data=0x%X)\n", PA, dz_wr_regs[(PA >> 1) & 03], access, data); @@ -359,6 +396,11 @@ switch ((PA >> 1) & 03) { /* case on PA<2:1> */ if (dz_lpr[dz] & LPR_RCVE) /* rcv enb? on */ lp->rcve = 1; else lp->rcve = 0; /* else line off */ + if (dz_mctl) { + sprintf(lineconfig, "%s-%s%s%s", LPR_GETSPD(data), LPR_GETCHARSIZE(data), LPR_GETPARITY(data), LPR_GETSTOPBITS(data)); + if (!lp->serconfig || (0 != strcmp(lp->serconfig, lineconfig))) /* config changed? */ + tmxr_set_config_line (lp, lineconfig); /* set it */ + } tmxr_poll_rx (&dz_desc); /* poll input */ dz_update_rcvi (); /* update rx intr */ break; @@ -368,23 +410,20 @@ switch ((PA >> 1) & 03) { /* case on PA<2:1> */ (dz_tcr[dz] & 0377) | (data << 8): (dz_tcr[dz] & ~0377) | data; if (dz_mctl) { /* modem ctl? */ - dz_msr[dz] |= ((data & 0177400) & /* dcd |= dtr & ring */ - ((dz_msr[dz] & DZ_LMASK) << MSR_V_CD)); - dz_msr[dz] &= ~(data >> TCR_V_DTR); /* ring &= ~dtr */ - if (dz_auto) { /* auto disconnect? */ - int32 drop; - drop = (dz_tcr[dz] & ~data) >> TCR_V_DTR; /* drop = dtr & ~data */ - for (i = 0; i < DZ_LINES; i++) { /* drop hangups */ - line = (dz * DZ_LINES) + i; /* get line num */ - lp = &dz_ldsc[line]; /* get line desc */ - if (lp->conn && (drop & (1 << i))) { - tmxr_linemsg (lp, "\r\nLine hangup\r\n"); - tmxr_reset_ln (lp); /* reset line, cdet */ - dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); - } /* end if drop */ - } /* end for */ - } /* end if auto */ - } /* end if modem */ + int32 changed = data ^ dz_tcr[dz]; + + for (i = 0; i < DZ_LINES; i++) { + if (0 == (changed & (1 << (TCR_V_DTR + i)))) + continue; /* line unchanged skip */ + line = (dz * DZ_LINES) + i; /* get line num */ + lp = &dz_ldsc[line]; /* get line desc */ + if (data & (1 << (TCR_V_DTR + i))) + tmxr_set_get_modem_bits (lp, TMXR_MDM_DTR|TMXR_MDM_RTS, 0, NULL); + else + if (dz_auto) + tmxr_set_get_modem_bits (lp, 0, TMXR_MDM_DTR|TMXR_MDM_RTS, NULL); + } + } dz_tcr[dz] = data; tmxr_poll_tx (&dz_desc); /* poll output */ dz_update_xmti (); /* update int */ @@ -424,7 +463,7 @@ return SCPE_OK; t_stat dz_svc (UNIT *uptr) { -int32 dz, t, newln; +int32 dz, t, newln, muxln; for (dz = t = 0; dz < dz_desc.lines/DZ_LINES; dz++) /* check enabled */ t = t | (dz_csr[dz] & CSR_MSE); @@ -432,9 +471,10 @@ if (t) { /* any enabled? */ newln = tmxr_poll_conn (&dz_desc); /* poll connect */ if ((newln >= 0) && dz_mctl) { /* got a live one? */ dz = newln / DZ_LINES; /* get mux num */ - if (dz_tcr[dz] & (1 << (newln + TCR_V_DTR))) /* DTR set? */ - dz_msr[dz] |= (1 << (newln + MSR_V_CD)); /* set cdet */ - else dz_msr[dz] |= (1 << newln); /* set ring */ + muxln = newln % DZ_LINES; /* get line in mux */ + if (dz_tcr[dz] & (1 << (muxln + TCR_V_DTR))) /* DTR set? */ + dz_msr[dz] |= (1 << (muxln + MSR_V_CD)); /* set cdet */ + else dz_msr[dz] |= (1 << (muxln + MSR_V_RI)); /* set ring */ } tmxr_poll_rx (&dz_desc); /* poll input */ dz_update_rcvi (); /* upd rcv intr */ @@ -630,13 +670,17 @@ return auto_config (dptr->name, ndev); /* auto config */ t_stat dz_attach (UNIT *uptr, char *cptr) { +int32 dz, muxln; t_stat r; extern int32 sim_switches; -dz_mctl = dz_auto = 0; /* modem ctl off */ +if (sim_switches & SWMASK ('M')) /* modem control? */ + tmxr_set_modem_control_passthru (&dz_desc); r = tmxr_attach (&dz_desc, uptr, cptr); /* attach mux */ -if (r != SCPE_OK) /* error? */ +if (r != SCPE_OK) { /* error? */ + tmxr_clear_modem_control_passthru (&dz_desc); return r; + } if (sim_switches & SWMASK ('M')) { /* modem control? */ dz_mctl = 1; printf ("Modem control activated\n"); @@ -649,6 +693,18 @@ if (sim_switches & SWMASK ('M')) { /* modem control? */ fprintf (sim_log, "Auto disconnect activated\n"); } } + +for (dz = 0; dz < DZ_MUXES; dz++) { + if (!dz_mctl || (0 == (dz_csr[dz] & CSR_MSE))) /* enabled? */ + continue; + for (muxln = 0; muxln < DZ_LINES; muxln++) { + if (dz_tcr[dz] & (1 << (muxln + TCR_V_DTR))) { + TMLN *lp = &dz_ldsc[(dz * DZ_LINES) + muxln]; + + tmxr_set_get_modem_bits (lp, TMXR_MDM_DTR|TMXR_MDM_RTS, 0, NULL); + } + } + } return SCPE_OK; } @@ -656,6 +712,7 @@ return SCPE_OK; t_stat dz_detach (UNIT *uptr) { +dz_mctl = dz_auto = 0; /* modem ctl off */ return tmxr_detach (&dz_desc, uptr); } @@ -663,7 +720,7 @@ return tmxr_detach (&dz_desc, uptr); t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc) { -int32 newln, i, t, ndev; +int32 newln, i, t; t_stat r; if (cptr == NULL) @@ -690,7 +747,6 @@ if (newln < dz_desc.lines) { dz_dib.lnt = (newln / DZ_LINES) * IOLN_DZ; /* set length */ dz_desc.lines = newln; dz_desc.ldsc = dz_ldsc = realloc(dz_ldsc, dz_desc.lines*sizeof(*dz_ldsc)); -ndev = ((dz_dev.flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES)); return dz_reset (&dz_dev); /* setup lines and auto config */ } diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index 08404648..0b57cb2c 100644 --- a/PDP11/pdp11_hk.c +++ b/PDP11/pdp11_hk.c @@ -772,11 +772,9 @@ return SCPE_OK; t_stat hk_wr (int32 data, int32 PA, int32 access) { -int32 drv, i, j, old_val, new_val; -UNIT *uptr; +int32 drv, i, j, old_val = 0, new_val = 0; drv = GET_UNIT (hkcs2); /* get current unit */ -uptr = hk_dev.units + drv; /* get unit */ j = (PA >> 1) & 017; /* get reg offset */ if ((hkcs1 & CS1_GO) && /* busy? */ !(((j == 0) && (data & CS1_CCLR)) || /* not cclr or sclr? */ @@ -1245,9 +1243,10 @@ if (old_hkcs1 != hkcs1) sim_debug_bits (HKDEB_OPS, &hk_dev, hk_cs1_bits, old_hkcs1, hkcs1, 1); if (old_hkcs2 != hkcs2) sim_debug_bits (HKDEB_OPS, &hk_dev, hk_cs2_bits, old_hkcs2, hkcs2, 1); -if (flag & CS1_DONE) /* set done */ +if (flag & CS1_DONE) { /* set done */ sim_debug (HKDEB_OPS, &hk_dev, ">>HK%d done: fnc=%s, cs1=%o, cs2=%o, ds=%o, er=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", drv, hk_funcs[GET_FNC (hkcs1)], hkcs1, hkcs2, hkds[drv], hker[drv], hkdc, hkda, hkba, hkwc); + } return; } @@ -1552,7 +1551,7 @@ static const uint16 boot_rom[] = { t_stat hk_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; for (i = 0; i < BOOT_LEN; i++) diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c index 167d5d10..7e7e566f 100644 --- a/PDP11/pdp11_io_lib.c +++ b/PDP11/pdp11_io_lib.c @@ -352,7 +352,7 @@ AUTO_CON auto_tab[] = { { { NULL }, 1, 2, 8, 8 }, /* DU11 */ { { NULL }, 1, 2, 8, 8 }, /* DUP11 */ { { NULL }, 10, 2, 8, 8 }, /* LK11A */ - { { NULL }, 1, 2, 8, 8 }, /* DMC11 */ + { { "DMA", "DMB", "DMC", "DMD" }, 1, 2, 8, 8 }, /* DMC11 */ { { "DZ" }, DZ_MUXES, 2, 8, 8 }, /* DZ11 */ { { NULL }, 1, 2, 8, 8 }, /* KMC11 */ { { NULL }, 1, 2, 8, 8 }, /* LPP11 */ @@ -369,7 +369,7 @@ AUTO_CON auto_tab[] = { { { "RX", "RY" }, 1, 1, 8, 4, {IOBA_RX} , {VEC_RX} }, /* RX11/RX211 */ { { NULL }, 1, 1, 8, 4 }, /* DR11W */ { { NULL }, 1, 1, 8, 4, { 0, 0 }, { 0 } }, /* DR11B - fx CSRs,vec */ - { { NULL }, 1, 2, 8, 8 }, /* DMP11 */ + { { "DMP" }, 1, 2, 8, 8 }, /* DMP11 */ { { NULL }, 1, 2, 8, 8 }, /* DPV11 */ { { NULL }, 1, 2, 8, 8 }, /* ISB11 */ { { NULL }, 1, 2, 16, 8 }, /* DMV11 */ diff --git a/PDP11/pdp11_rc.c b/PDP11/pdp11_rc.c index 1f32ec59..f0bab9ba 100644 --- a/PDP11/pdp11_rc.c +++ b/PDP11/pdp11_rc.c @@ -437,7 +437,7 @@ static uint32 sectorCRC (const uint16 *data) static t_stat rc_svc (UNIT *uptr) { - uint32 ma, da, t, u_old, u_new, last_da; + uint32 ma, da, t, u_old, u_new, last_da = 0; uint16 dat; uint16 *fbuf = uptr->filebuf; diff --git a/PDP11/pdp11_rf.c b/PDP11/pdp11_rf.c index 439fa7b2..6af0f800 100644 --- a/PDP11/pdp11_rf.c +++ b/PDP11/pdp11_rf.c @@ -144,7 +144,7 @@ uint32 update_rfcs (uint32 newcs, uint32 newdae); DIB rf_dib = { IOBA_RF, IOLN_RF, &rf_rd, &rf_wr, - 1, IVCL (RF), VEC_RF, NULL + 1, IVCL (RF), VEC_RF, {NULL} }; @@ -461,7 +461,7 @@ static const uint16 boot_rom[] = { t_stat rf_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; for (i = 0; i < BOOT_LEN; i++) diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index d870ca8f..cb27b06d 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -746,7 +746,7 @@ static const uint16 boot_rom[] = { t_stat rk_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; for (i = 0; i < BOOT_LEN; i++) diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 25802bee..146eeadb 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -1187,7 +1187,7 @@ static const uint16 boot_rom[] = { t_stat rl_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint16 *M; extern int32 saved_PC; diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index 8f374aa1..d851f77b 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -1459,7 +1459,7 @@ static const uint16 boot_rom[] = { t_stat rp_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern uint16 *M; UNIT *uptr = dptr->units + unitno; diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index 02834019..66e27737 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -2917,7 +2917,7 @@ static const uint16 boot_rom[] = { t_stat rq_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern uint16 *M; DIB *dibp = (DIB *) dptr->ctxt; diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index f4267b61..9112e8b4 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -522,7 +522,7 @@ static const uint16 boot_rom[] = { t_stat rx_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern uint16 *M; diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index a973e2e0..2cf63568 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -678,7 +678,7 @@ static const uint16 boot_rom[] = { t_stat ry_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern uint16 *M; diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index b0b358cf..265b011c 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -102,6 +102,7 @@ extern DEVICE xq_dev, xqb_dev; extern DEVICE xu_dev, xub_dev; extern DEVICE ke_dev; extern DEVICE kg_dev; +extern DEVICE dmc_dev[]; extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint16 *M; @@ -166,6 +167,10 @@ DEVICE *sim_devices[] = { &xub_dev, &ke_dev, &kg_dev, + &dmc_dev[0], + &dmc_dev[1], + &dmc_dev[2], + &dmc_dev[3], NULL }; diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c index 1af3df29..4fc1fd19 100644 --- a/PDP11/pdp11_tc.c +++ b/PDP11/pdp11_tc.c @@ -749,7 +749,7 @@ t_bool dt_setpos (UNIT *uptr) { uint32 new_time, ut, ulin, udelt; int32 mot = DTS_GETMOT (uptr->STATE); -int32 unum, delta; +int32 unum, delta = 0; new_time = sim_grtime (); /* current time */ ut = new_time - uptr->LASTT; /* elapsed time */ @@ -1183,7 +1183,7 @@ static const uint16 boot_rom[] = { t_stat dt_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; dt_unit[unitno].pos = DT_EZLIN; diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c index e8430b17..55a4ef3a 100644 --- a/PDP11/pdp11_tm.c +++ b/PDP11/pdp11_tm.c @@ -711,7 +711,7 @@ static const uint16 boot2_rom[] = { t_stat tm_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern int32 sim_switches; diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index 95d76ba2..50a0ead3 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -1691,7 +1691,7 @@ return tq_putpkt (pkt, TRUE); t_bool tq_plf (uint32 err) { -int32 pkt; +int32 pkt = 0; if (!tq_deqf (&pkt)) /* get log pkt */ return ERR; @@ -2202,7 +2202,7 @@ static const uint16 boot_rom[] = { t_stat tq_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern uint16 *M; diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c index 5966a062..e9326eeb 100644 --- a/PDP11/pdp11_ts.c +++ b/PDP11/pdp11_ts.c @@ -1150,7 +1150,7 @@ static const uint16 boot_rom[] = { t_stat ts_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern uint16 *M; diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index 3a763c90..ce827ea9 100644 --- a/PDP11/pdp11_tu.c +++ b/PDP11/pdp11_tu.c @@ -793,7 +793,7 @@ if (DEBUG_PRS (tu_dev)) { fprintf (sim_deb, ">>TU%d DONE: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=", drv, tu_fname[fnc], tufc, tufs, tuer); fprint_val (sim_deb, uptr->pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, "\n"); + fprintf (sim_deb, ", r=%d\n", r); } return SCPE_OK; } @@ -1036,7 +1036,7 @@ static const uint16 boot_rom[] = { t_stat tu_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern uint16 *M; diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index 29055816..23722268 100644 --- a/PDP11/pdp11_vh.c +++ b/PDP11/pdp11_vh.c @@ -34,6 +34,7 @@ of lines available to be 8, 16, 24, or 32. Fixed performance issue avoiding redundant polling 03-Jan-10 JAD Eliminate gcc warnings + 24-Nov-08 JDB Removed tmxr_send_buffered_data declaration (now in sim_tmxr.h) 19-Nov-08 RMS Revised for common TMXR show routines 18-Jun-07 RMS Added UNIT_IDLE flag 29-Oct-06 RMS Synced poll and clock @@ -304,12 +305,16 @@ static TMLX vh_parm[VH_MUXES * VH_LINES_ALLOC] = { { 0 } }; #define DBG_INT 0x0002 /* display transfer requests */ #define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */ #define DBG_RCV TMXR_DBG_RCV /* display Received Data */ +#define DBG_TRC TMXR_DBG_TRC /* display trace routine calls */ +#define DBG_ASY TMXR_DBG_ASY /* display Asynchronous Activities */ DEBTAB vh_debug[] = { {"REG", DBG_REG}, {"INT", DBG_INT}, {"XMT", DBG_XMT}, {"RCV", DBG_RCV}, + {"TRC", DBG_TRC}, + {"ASY", DBG_ASY}, {0} }; @@ -335,8 +340,6 @@ static t_stat vh_set_log (UNIT *uptr, int32 val, char *cptr, void *desc); static t_stat vh_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc); static t_stat vh_show_log (FILE *st, UNIT *uptr, int32 val, void *desc); -int32 tmxr_send_buffered_data (TMLN *lp); - /* SIMH I/O Structures */ static DIB vh_dib = { @@ -421,7 +424,7 @@ DEVICE vh_dev = { &vh_attach, /* attach routine */ &vh_detach, /* detach routine */ (void *)&vh_dib,/* context */ - DEV_FLTA | DEV_DISABLE | DEV_DIS |DEV_NET | DEV_QBUS | DEV_UBUS | DEV_DEBUG, /* flags */ + DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_QBUS | DEV_UBUS | DEV_DEBUG, /* flags */ 0, vh_debug }; diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index 12d3c5dc..ae147377 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -1101,7 +1101,6 @@ t_stat xq_process_rbdl(CTLR* xq) t_stat xq_process_mop(CTLR* xq) { uint32 address; - uint16 size; int32 wstatus; struct xq_meb* meb = (struct xq_meb*) &xq->var->write_buffer.msg[0200]; const struct xq_meb* limit = (struct xq_meb*) &xq->var->write_buffer.msg[0400]; @@ -1113,7 +1112,6 @@ t_stat xq_process_mop(CTLR* xq) while ((meb->type != 0) && (meb < limit)) { address = (meb->add_hi << 16) || (meb->add_mi << 8) || meb->add_lo; - size = (meb->siz_hi << 8) || meb->siz_lo; /* MOP stuff here - NOT YET FULLY IMPLEMENTED */ sim_debug (DBG_WRN, xq->dev, "Processing MEB type: %d\n", meb->type); @@ -1634,8 +1632,9 @@ t_stat xq_process_turbo_rbdl(CTLR* xq) ethq_remove(&xq->var->ReadQ); } while (0 == (xq->var->rring[xq->var->rbindx].rmd3 & XQ_RMD3_OWN)); - if (xq->var->rring[xq->var->rbindx].rmd3 & XQ_RMD3_OWN) + if (xq->var->rring[xq->var->rbindx].rmd3 & XQ_RMD3_OWN) { sim_debug(DBG_WRN, xq->dev, "xq_process_turbo_rbdl() - receive ring full\n"); + } if (descriptors_consumed) /* Interrupt for Packet Reception Completion */ @@ -2019,7 +2018,8 @@ t_stat xq_process_bootrom (CTLR* xq) uint16 b_length, w_length; uint32 address; uint8* bootrom = (uint8*) xq_bootrom; - int i, checksum; + size_t i; + int checksum; sim_debug(DBG_TRC, xq->dev, "xq_process_bootrom()\n"); @@ -2645,7 +2645,7 @@ t_stat xq_tmrsvc(UNIT* uptr) /* has sanity timer expired? if so, reboot */ if (xq->var->sanity.enabled) - if (--xq->var->sanity.timer <= 0) + if (--xq->var->sanity.timer <= 0) { if (xq->var->mode != XQ_T_DELQA_PLUS) return xq_boot_host(xq); else { /* DELQA-T Host Inactivity Timer expiration means switch out of DELQA-T mode */ @@ -2654,6 +2654,7 @@ t_stat xq_tmrsvc(UNIT* uptr) xq->var->iba = xq->var->srr = 0; xq->var->var = XQ_VEC_MS | XQ_VEC_OS; } + } /* has system id timer expired? if so, do system id */ if (--xq->var->idtmr <= 0) { @@ -2895,8 +2896,9 @@ void xq_debug_setup(CTLR* xq) if (!(sim_deb && (xq->dev->dctrl & DBG_SET))) return; - if (xq->var->write_buffer.msg[0]) + if (xq->var->write_buffer.msg[0]) { sim_debug(DBG_SET, xq->dev, "%s: setup> MOP info present!\n", xq->dev->name); + } for (i = 0; i < XQ_FILTER_MAX; i++) { eth_mac_fmt(&xq->var->setup.macs[i], buffer); diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index 8ef1cd7b..0a7b54d2 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -674,18 +674,16 @@ t_stat xu_sw_reset (CTLR* xu) for (i=0; i<6; i++) xu->var->setup.macs[1][i] = 0xff; /* Broadcast Address */ xu->var->setup.mac_count = 2; - if (xu->var->etherface) + if (xu->var->etherface) { eth_filter (xu->var->etherface, xu->var->setup.mac_count, xu->var->setup.macs, xu->var->setup.multicast, xu->var->setup.promiscuous); - /* activate device if not disabled */ - if ((xu->dev->flags & DEV_DIS) == 0) { + /* activate device */ sim_activate_abs(&xu->unit[0], clk_cosched (tmxr_poll)); /* start service timer */ - if (xu->var->etherface) - sim_activate_abs(&xu->unit[1], tmr_poll * clk_tps); + sim_activate_abs(&xu->unit[1], tmr_poll * clk_tps); } /* clear load_server address */ @@ -1033,7 +1031,7 @@ int32 xu_command(CTLR* xu) void xu_process_receive(CTLR* xu) { uint32 segb, ba; - int slen, wlen, off; + int slen, wlen, off = 0; t_stat rstatus, wstatus; ETH_ITEM* item = 0; int state = xu->var->pcsr1 & PCSR1_STATE; @@ -1215,6 +1213,7 @@ void xu_process_transmit(CTLR* xu) sim_debug(DBG_TRC, xu->dev, "xu_process_transmit()\n"); /* xu_dump_txring(xu); *//* debug receive ring */ + off = giant = runt = 0; for (;;) { /* get next transmit buffer */ @@ -1481,8 +1480,9 @@ t_stat xu_rd(int32 *data, int32 PA, int32 access) break; } sim_debug(DBG_REG, xu->dev, "xu_rd(), PCSR%d, data=%04x\n", reg, *data); - if (PA & 1) + if (PA & 1) { sim_debug(DBG_WRN, xu->dev, "xu_rd(), Unexpected Odd address access of PCSR%d\n", reg); + } return SCPE_OK; } @@ -1622,6 +1622,8 @@ t_stat xu_detach(UNIT* uptr) sim_debug(DBG_TRC, xu->dev, "xu_detach()\n"); if (uptr->flags & UNIT_ATT) { + sim_cancel (uptr); /* stop the receiver */ + sim_cancel (uptr+1); /* stop the timer services */ eth_close (xu->var->etherface); free(xu->var->etherface); xu->var->etherface = 0; @@ -1684,7 +1686,8 @@ void xu_dump_rxring (CTLR* xu) int own = (rxhdr[2] & RXR_OWN) >> 15; int len = rxhdr[0]; uint32 addr = rxhdr[1] + ((rxhdr[2] & 3) << 16); - printf (" header[%d]: own:%d, len:%d, address:%08x data:{%04x,%04x,%04x,%04x}\n", i, own, len, addr, rxhdr[0], rxhdr[1], rxhdr[2], rxhdr[3]); + if (rstatus == 0) + printf (" header[%d]: own:%d, len:%d, address:%08x data:{%04x,%04x,%04x,%04x}\n", i, own, len, addr, rxhdr[0], rxhdr[1], rxhdr[2], rxhdr[3]); } } @@ -1700,6 +1703,7 @@ void xu_dump_txring (CTLR* xu) int own = (txhdr[2] & RXR_OWN) >> 15; int len = txhdr[0]; uint32 addr = txhdr[1] + ((txhdr[2] & 3) << 16); - printf (" header[%d]: own:%d, len:%d, address:%08x data:{%04x,%04x,%04x,%04x}\n", i, own, len, addr, txhdr[0], txhdr[1], txhdr[2], txhdr[3]); + if (tstatus == 0) + printf (" header[%d]: own:%d, len:%d, address:%08x data:{%04x,%04x,%04x,%04x}\n", i, own, len, addr, txhdr[0], txhdr[1], txhdr[2], txhdr[3]); } } diff --git a/PDP18B/pdp18b_drm.c b/PDP18B/pdp18b_drm.c index c65990b1..4141e465 100644 --- a/PDP18B/pdp18b_drm.c +++ b/PDP18B/pdp18b_drm.c @@ -244,7 +244,7 @@ static const int32 boot_rom[] = { t_stat drm_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 PC; if (drm_dib.dev != DEV_DRM) /* non-std addr? */ diff --git a/PDP18B/pdp18b_stddev.c b/PDP18B/pdp18b_stddev.c index 78cfeba3..60e9e528 100644 --- a/PDP18B/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -453,7 +453,6 @@ int32 clk_task_upd (t_bool clr) { uint32 delta, val, iusec10; uint32 cur = sim_grtime (); -uint32 old = clk_task_timer; double usec10; if (cur > clk_task_last) @@ -861,7 +860,8 @@ static const int32 boot_rom[] = { t_stat ptr_boot (int32 unitno, DEVICE *dptr) { -int32 i, mask, wd; +size_t i; +int32 mask, wd; extern int32 sim_switches; #if defined (PDP7) @@ -994,7 +994,7 @@ if (pulse & 001) { /* KSF */ } if (pulse & 002) { /* KRS/KRB */ CLR_INT (TTI); /* clear flag */ - dat = dat | tti_unit.buf & TTI_MASK; /* return buffer */ + dat = dat | (tti_unit.buf & TTI_MASK); /* return buffer */ #if defined (PDP15) if (pulse & 020) /* KRS? */ tti_fdpx = 1; diff --git a/PDP18B/pdp18b_tt1.c b/PDP18B/pdp18b_tt1.c index d29bde0e..6a73f977 100644 --- a/PDP18B/pdp18b_tt1.c +++ b/PDP18B/pdp18b_tt1.c @@ -57,7 +57,7 @@ uint32 ttix_done = 0; /* input flags */ uint32 ttox_done = 0; /* output flags */ uint8 ttix_buf[TTX_MAXL] = { 0 }; /* input buffers */ uint8 ttox_buf[TTX_MAXL] = { 0 }; /* output buffers */ -TMLN ttx_ldsc[TTX_MAXL] = { 0 }; /* line descriptors */ +TMLN ttx_ldsc[TTX_MAXL] = { {0} }; /* line descriptors */ TMXR ttx_desc = { 1, 0, 0, ttx_ldsc }; /* mux descriptor */ #define ttx_lines ttx_desc.lines /* current number of lines */ diff --git a/PDP8/pdp8_df.c b/PDP8/pdp8_df.c index a802e6e0..9ccfba64 100644 --- a/PDP8/pdp8_df.c +++ b/PDP8/pdp8_df.c @@ -334,7 +334,7 @@ static const uint16 dm4_rom[] = { t_stat df_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 sim_switches, saved_PC; if (sim_switches & SWMASK ('D')) { diff --git a/PDP8/pdp8_dt.c b/PDP8/pdp8_dt.c index 2b0ffe9b..987bb969 100644 --- a/PDP8/pdp8_dt.c +++ b/PDP8/pdp8_dt.c @@ -1178,7 +1178,7 @@ static const uint16 boot_rom[] = { t_stat dt_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; if (unitno) /* only unit 0 */ diff --git a/PDP8/pdp8_pt.c b/PDP8/pdp8_pt.c index f2b1352a..f7102012 100644 --- a/PDP8/pdp8_pt.c +++ b/PDP8/pdp8_pt.c @@ -278,7 +278,7 @@ static const uint16 boot_rom[] = { t_stat ptr_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern uint16 M[]; diff --git a/PDP8/pdp8_rf.c b/PDP8/pdp8_rf.c index aef1c76d..ce5ed632 100644 --- a/PDP8/pdp8_rf.c +++ b/PDP8/pdp8_rf.c @@ -398,7 +398,7 @@ static const uint16 dm4_rom[] = { t_stat rf_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 sim_switches, saved_PC; if (rf_dib.dev != DEV_RF) /* only std devno */ diff --git a/PDP8/pdp8_rk.c b/PDP8/pdp8_rk.c index 10b0e5ad..93293e49 100644 --- a/PDP8/pdp8_rk.c +++ b/PDP8/pdp8_rk.c @@ -450,7 +450,7 @@ static const uint16 boot_rom[] = { t_stat rk_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; if (rk_dib.dev != DEV_RK) /* only std devno */ diff --git a/PDP8/pdp8_rl.c b/PDP8/pdp8_rl.c index 22beb05a..de3cda88 100644 --- a/PDP8/pdp8_rl.c +++ b/PDP8/pdp8_rl.c @@ -689,7 +689,7 @@ static const uint16 boot_rom[] = { t_stat rl_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; if (unitno) /* only unit 0 */ diff --git a/PDP8/pdp8_rx.c b/PDP8/pdp8_rx.c index 7a51df0d..18b43c22 100644 --- a/PDP8/pdp8_rx.c +++ b/PDP8/pdp8_rx.c @@ -733,7 +733,7 @@ static const uint16 boot2_rom[] = { t_stat rx_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; extern uint16 M[]; diff --git a/PDP8/pdp8_td.c b/PDP8/pdp8_td.c index 46703def..d2699ba4 100644 --- a/PDP8/pdp8_td.c +++ b/PDP8/pdp8_td.c @@ -742,7 +742,7 @@ static const uint16 boot_rom[] = { t_stat td_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; if (unitno) diff --git a/PDP8/pdp8_ttx.c b/PDP8/pdp8_ttx.c index 5c335a48..fc1b320d 100644 --- a/PDP8/pdp8_ttx.c +++ b/PDP8/pdp8_ttx.c @@ -66,7 +66,7 @@ extern int32 tmxr_poll, sim_is_running; uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */ uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */ int32 ttx_tps = 100; /* polls per second */ -TMLN ttx_ldsc[TTX_LINES] = { 0 }; /* line descriptors */ +TMLN ttx_ldsc[TTX_LINES] = { {0} }; /* line descriptors */ TMXR ttx_desc = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */ DEVICE ttix_dev, ttox_dev; diff --git a/S3/s3_sys.c b/S3/s3_sys.c index 39cec895..bb9911c9 100644 --- a/S3/s3_sys.c +++ b/S3/s3_sys.c @@ -270,13 +270,12 @@ int32 fprint_sym (FILE *of, int32 addr, uint32 *val, int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { -int32 cflag, c1, c2, group, len1, len2, inst, aaddr, baddr; +int32 c1, c2, group, len1, len2, inst, aaddr, baddr; int32 oplen, groupno, i, j, vpos, qbyte, da, m, n; char bld[128], bldaddr[32], boperand[32], aoperand[32]; int32 blk[16], blt[16]; int32 blkadd; -cflag = (uptr == NULL) || (uptr == &cpu_unit); c1 = val[0] & 0xff; if (sw & SWMASK ('A')) { for (i = 0; i < 16; i++) { diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index f045b6e7..0621dc4f 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -1341,7 +1341,7 @@ if (sc >= 24) { A = sgn; } else { - B = ((B >> sc) | (A << (24 - sc)) & DMASK); + B = ((B >> sc) | (A << (24 - sc))) & DMASK; A = ((A >> sc) | (sgn << (24 - sc))) & DMASK; } return; diff --git a/SDS/sds_io.c b/SDS/sds_io.c index bd0b01f4..ae402e86 100644 --- a/SDS/sds_io.c +++ b/SDS/sds_io.c @@ -224,7 +224,7 @@ uint32 dev_map[64][NUM_CHAN]; /* dev_dsp maps device and channel numbers to dispatch routines */ -t_stat (*dev_dsp[64][NUM_CHAN])() = { NULL }; +t_stat (*dev_dsp[64][NUM_CHAN])() = { {NULL} }; /* dev3_dsp maps system device numbers to dispatch routines */ diff --git a/SDS/sds_mux.c b/SDS/sds_mux.c index 8cc7023a..3cdf9b25 100644 --- a/SDS/sds_mux.c +++ b/SDS/sds_mux.c @@ -112,7 +112,7 @@ uint32 mux_tps = 100; /* polls/second */ uint32 mux_scan = 0; /* scanner */ uint32 mux_slck = 0; /* scanner locked */ -TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */ +TMLN mux_ldsc[MUX_LINES] = { {0} }; /* line descriptors */ TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc }; /* mux descriptor */ t_stat mux (uint32 fnc, uint32 inst, uint32 *dat); diff --git a/VAX/vax610_mem.c b/VAX/vax610_mem.c index 64ca0597..2275f0ba 100644 --- a/VAX/vax610_mem.c +++ b/VAX/vax610_mem.c @@ -57,7 +57,7 @@ DIB mctl_dib = { 1, 0, 0, { NULL } }; -UNIT mctl_unit[] = { UDATA (NULL, 0, 0) }; +UNIT mctl_unit = { UDATA (NULL, 0, 0) }; REG mctl_reg[] = { { DRDATA (COUNT, mctl_count, 16) }, @@ -66,7 +66,7 @@ REG mctl_reg[] = { }; DEVICE mctl_dev = { - "MCTL", mctl_unit, mctl_reg, NULL, + "MCTL", &mctl_unit, mctl_reg, NULL, 1, DEV_RDX, 20, 1, DEV_RDX, 8, NULL, NULL, &mctl_reset, NULL, NULL, NULL, diff --git a/VAX/vax630_sysdev.c b/VAX/vax630_sysdev.c index 99b4dd39..f2df66d5 100644 --- a/VAX/vax630_sysdev.c +++ b/VAX/vax630_sysdev.c @@ -831,7 +831,6 @@ return run_cmd (flag, "CPU"); t_stat cpu_boot (int32 unitno, DEVICE *dptr) { extern t_stat load_cmd (int32 flag, char *cptr); -extern FILE *sim_log; t_stat r; PC = ROMBASE; diff --git a/VAX/vax730_mem.c b/VAX/vax730_mem.c index 5c819203..f408366e 100644 --- a/VAX/vax730_mem.c +++ b/VAX/vax730_mem.c @@ -83,7 +83,7 @@ t_stat mctl_wrreg (int32 val, int32 pa, int32 mode); mctlx_reg MCTLx register list */ -DIB mctl_dib[] = { TR_MCTL, 0, &mctl_rdreg, &mctl_wrreg, 0 }; +DIB mctl_dib = { TR_MCTL, 0, &mctl_rdreg, &mctl_wrreg, 0 }; UNIT mctl_unit = { UDATA (NULL, 0, 0) }; diff --git a/VAX/vax730_rb.c b/VAX/vax730_rb.c index fa0f4f25..66dd8826 100644 --- a/VAX/vax730_rb.c +++ b/VAX/vax730_rb.c @@ -490,7 +490,7 @@ if (func == RBCS_SEEK) { /* seek? */ if (uptr->SIP == 0) { sim_debug(DBG_CMD, &rb_dev, "Seek, CYL=%d, TRK=%d, SECT=%d\n", GET_CYL(rbda), GET_TRACK(rbda), GET_SECT(rbda)); uptr->SIP = 1; - if (rbda == 0xFFFFFFFF) swait = rb_swait; + if ((uint32)rbda == 0xFFFFFFFF) swait = rb_swait; else { curr = GET_CYL (uptr->TRK); /* current cylinder */ newc = GET_CYL (rbda); /* offset */ diff --git a/VAX/vax750_mem.c b/VAX/vax750_mem.c index a3755bd0..97e49cf1 100644 --- a/VAX/vax750_mem.c +++ b/VAX/vax750_mem.c @@ -95,7 +95,7 @@ t_stat mctl_wrreg (int32 val, int32 pa, int32 mode); mctl_reg MCTL register list */ -DIB mctl_dib[] = { TR_MCTL, 0, &mctl_rdreg, &mctl_wrreg, 0 }; +DIB mctl_dib = { TR_MCTL, 0, &mctl_rdreg, &mctl_wrreg, 0 }; UNIT mctl_unit = { UDATA (NULL, 0, 0) }; diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index 7a26f754..48563b72 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -319,6 +319,8 @@ typedef struct { #define IOLN_PTR 004 #define IOBA_PTP (IOPAGEBASE + 017554) /* PC11 punch */ #define IOLN_PTP 004 +#define IOBA_DMC (IOPAGEBASE + 0760060) /* DMC11 */ +#define IOLN_DMC 010 /* Interrupt assignments; within each level, priority is right to left */ @@ -331,6 +333,8 @@ typedef struct { #define INT_V_TS 6 #define INT_V_RY 7 #define INT_V_XU 8 +#define INT_V_DMCRX 9 +#define INT_V_DMCTX 10 #define INT_V_LPT 0 /* BR4 */ #define INT_V_PTR 1 @@ -354,6 +358,8 @@ typedef struct { #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) #define INT_CR (1u << INT_V_CR) +#define INT_DMCRX (1u << INT_V_DMCRX) +#define INT_DMCTX (1u << INT_V_DMCTX) #define IPL_DZRX (0x15 - IPL_HMIN) #define IPL_DZTX (0x15 - IPL_HMIN) @@ -370,6 +376,8 @@ typedef struct { #define IPL_CR (0x14 - IPL_HMIN) #define IPL_VHRX (0x14 - IPL_HMIN) #define IPL_VHTX (0x14 - IPL_HMIN) +#define IPL_DMCRX (0x15 - IPL_HMIN) +#define IPL_DMCTX (0x15 - IPL_HMIN) /* Device vectors */ @@ -392,6 +400,8 @@ typedef struct { #define VEC_DZTX 0304 #define VEC_VHRX 0310 #define VEC_VHTX 0314 +#define VEC_DMCRX 0310 +#define VEC_DMCTX 0314 /* Interrupt macros */ diff --git a/VAX/vax780_mem.c b/VAX/vax780_mem.c index 2183b832..32996679 100644 --- a/VAX/vax780_mem.c +++ b/VAX/vax780_mem.c @@ -98,7 +98,7 @@ t_stat mctl_wrreg (int32 val, int32 pa, int32 mode); mctlx_reg MCTLx register list */ -DIB mctl0_dib[] = { TR_MCTL0, 0, &mctl_rdreg, &mctl_wrreg, 0 }; +DIB mctl0_dib = { TR_MCTL0, 0, &mctl_rdreg, &mctl_wrreg, 0 }; UNIT mctl0_unit = { UDATA (NULL, 0, 0) }; @@ -117,7 +117,7 @@ MTAB mctl0_mod[] = { { 0 } }; -DIB mctl1_dib[] = { TR_MCTL1, 0, &mctl_rdreg, &mctl_wrreg, 0 }; +DIB mctl1_dib = { TR_MCTL1, 0, &mctl_rdreg, &mctl_wrreg, 0 }; UNIT mctl1_unit = { UDATA (NULL, 0, 0) }; diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index 9025f616..5f0aa965 100644 --- a/VAX/vax780_syslist.c +++ b/VAX/vax780_syslist.c @@ -54,6 +54,7 @@ extern DEVICE tu_dev; extern DEVICE dz_dev; extern DEVICE vh_dev; extern DEVICE xu_dev, xub_dev; +extern DEVICE dmc_dev[]; extern int32 sim_switches; extern UNIT cpu_unit; @@ -91,6 +92,10 @@ DEVICE *sim_devices[] = { &tq_dev, &xu_dev, &xub_dev, + &dmc_dev[0], + &dmc_dev[1], + &dmc_dev[2], + &dmc_dev[3], NULL }; diff --git a/VAX/vax7x0_mba.c b/VAX/vax7x0_mba.c index a17e3dcf..ac10afb5 100644 --- a/VAX/vax7x0_mba.c +++ b/VAX/vax7x0_mba.c @@ -820,8 +820,9 @@ if (mba_sr[mb] != o_sr) sim_debug_bits(MBA_DEB_RWR, &mba_dev[mb], mba_sr_bits, o_sr, mba_sr[mb], 1); if ((set & MBASR_INTR) && (mba_cr[mb] & MBACR_IE) && !(mba_sr[mb] & MBASR_DTBUSY)) mba_set_int (mb); -if (set & MBASR_ERRORS) +if (set & MBASR_ERRORS) { sim_debug (MBA_DEB_ERR, &mba_dev[mb], "mba_upd_sr(CS error=0x%X)\n", mba_sr[mb]); + } return; } diff --git a/VAX/vax_cis.c b/VAX/vax_cis.c index 3eec163e..8a5465a5 100644 --- a/VAX/vax_cis.c +++ b/VAX/vax_cis.c @@ -71,8 +71,8 @@ typedef struct { uint32 val[DSTRLNT]; } DSTR; -static DSTR Dstr_zero = { 0, 0, 0, 0, 0 }; -static DSTR Dstr_one = { 0, 0x10, 0, 0, 0 }; +static DSTR Dstr_zero = { 0, {0, 0, 0, 0} }; +static DSTR Dstr_one = { 0, {0x10, 0, 0, 0} }; extern int32 R[16]; extern int32 PSL; diff --git a/VAX/vax_cmode.c b/VAX/vax_cmode.c index dbf6d4cf..eca9f824 100644 --- a/VAX/vax_cmode.c +++ b/VAX/vax_cmode.c @@ -597,7 +597,7 @@ switch ((IR >> 12) & 017) { /* decode IR<15:12> */ cc = CC_V | CC_C; /* set cc's */ break; /* done */ } - if ((src == LSIGN) && (src2 == WMASK)) { /* -2^31 / -1? */ + if (((uint32)src == LSIGN) && ((uint32)src2 == WMASK)) { /* -2^31 / -1? */ cc = CC_V; /* overflow */ break; /* done */ } @@ -669,7 +669,7 @@ switch ((IR >> 12) & 017) { /* decode IR<15:12> */ dst = ((uint32) src) << src2; i = ((src >> (32 - src2)) | (-sign << src2)) & LMASK; oc = (i & 1)? CC_C: 0; - if ((dst & LSIGN)? (i != LMASK): (i != 0)) + if ((dst & LSIGN)? ((uint32)i != LMASK): (i != 0)) oc = oc | CC_V; } else if (src2 == 32) { /* [32] = -32 */ diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index 67971693..8327513b 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -1941,7 +1941,8 @@ for ( ;; ) { temp = CC_V; SET_TRAP (TRAP_DIVZRO); } - else if ((op0 == LMASK) && (op1 == LSIGN)) { /* overflow? */ + else if ((((uint32)op0) == LMASK) && + (((uint32)op1) == LSIGN)) { /* overflow? */ r = op1; temp = CC_V; INTOV; @@ -3205,7 +3206,7 @@ return SCPE_NXM; t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; -uint32 i, clim; +uint32 i, clim, uval = (uint32)val; uint32 *nM = NULL; if ((val <= 0) || (val > MAXMEMSIZE_X)) @@ -3214,15 +3215,15 @@ for (i = val; i < MEMSIZE; i = i + 4) mc = mc | M[i >> 2]; if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE)) return SCPE_OK; -nM = (uint32 *) calloc (val >> 2, sizeof (uint32)); +nM = (uint32 *) calloc (uval >> 2, sizeof (uint32)); if (nM == NULL) return SCPE_MEM; -clim = (uint32) ((((uint32) val) < MEMSIZE)? val: MEMSIZE); +clim = (uint32)((uval < MEMSIZE)? uval: MEMSIZE); for (i = 0; i < clim; i = i + 4) nM[i >> 2] = M[i >> 2]; free (M); M = nM; -MEMSIZE = val; +MEMSIZE = uval; return SCPE_OK; } diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index e01e555e..1629368f 100644 --- a/VAX/vax_mmu.c +++ b/VAX/vax_mmu.c @@ -178,7 +178,10 @@ if (mapen) { /* mapping on? */ xpte = fill (va, lnt, acc, NULL); /* fill if needed */ pa = (xpte.pte & TLB_PFN) | off; /* get phys addr */ } -else pa = va & PAMASK; +else { + pa = va & PAMASK; + off = 0; + } if ((pa & (lnt - 1)) == 0) { /* aligned? */ if (lnt >= L_LONG) /* long, quad? */ return ReadL (pa); @@ -186,7 +189,7 @@ if ((pa & (lnt - 1)) == 0) { /* aligned? */ return ReadW (pa); return ReadB (pa); /* byte */ } -if (mapen && ((off + lnt) > VA_PAGSIZE)) { /* cross page? */ +if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { /* cross page? */ vpn = VA_GETVPN (va + lnt); /* vpn 2nd page */ tbi = VA_GETTBI (vpn); xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ @@ -240,7 +243,10 @@ if (mapen) { xpte = fill (va, lnt, acc, NULL); pa = (xpte.pte & TLB_PFN) | off; } -else pa = va & PAMASK; +else { + pa = va & PAMASK; + off = 0; + } if ((pa & (lnt - 1)) == 0) { /* aligned? */ if (lnt >= L_LONG) /* long, quad? */ WriteL (pa, val); @@ -249,7 +255,7 @@ if ((pa & (lnt - 1)) == 0) { /* aligned? */ else WriteB (pa, val); /* byte */ return; } -if (mapen && ((off + lnt) > VA_PAGSIZE)) { +if (mapen && ((uint32)(off + lnt) > VA_PAGSIZE)) { vpn = VA_GETVPN (va + 4); tbi = VA_GETTBI (vpn); xpte = (va & VA_S0)? stlb[tbi]: ptlb[tbi]; /* access tlb */ diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index 4884ecba..86b278e2 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -1577,7 +1577,6 @@ return run_cmd (flag, "CPU"); t_stat cpu_boot (int32 unitno, DEVICE *dptr) { extern t_stat load_cmd (int32 flag, char *cptr); -extern FILE *sim_log; t_stat r; PC = ROMBASE; diff --git a/VAX/vax_syslist.c b/VAX/vax_syslist.c index 054c5e43..6554aaf6 100644 --- a/VAX/vax_syslist.c +++ b/VAX/vax_syslist.c @@ -51,6 +51,7 @@ extern DEVICE dz_dev; extern DEVICE csi_dev, cso_dev; extern DEVICE xq_dev, xqb_dev; extern DEVICE vh_dev; +extern DEVICE dmc_dev[]; extern int32 sim_switches; extern void WriteB (uint32 pa, int32 val); @@ -83,6 +84,10 @@ DEVICE *sim_devices[] = { &tq_dev, &xq_dev, &xqb_dev, + &dmc_dev[0], + &dmc_dev[1], + &dmc_dev[2], + &dmc_dev[3], NULL }; diff --git a/VAX/vax_watch.c b/VAX/vax_watch.c index cedd3f04..ecd89b57 100644 --- a/VAX/vax_watch.c +++ b/VAX/vax_watch.c @@ -97,7 +97,7 @@ int32 wtc_rd (int32 pa) int32 rg = (pa >> 1) & 0xF; int32 val = 0; time_t curr; -struct tm *ctm; +struct tm *ctm = NULL; if (rg < 10) { /* time reg? */ curr = time (NULL); /* get curr time */ diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index 9bd1832d..8527f1b0 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -327,6 +327,8 @@ typedef struct { #define IOLN_PTR 004 #define IOBA_PTP (IOPAGEBASE + 017554) /* PC11 punch */ #define IOLN_PTP 004 +#define IOBA_DMC (IOPAGEBASE + 017060) /* DMC11 */ +#define IOLN_DMC 010 /* The KA65x maintains 4 separate hardware IPL levels, IPL 17 to IPL 14; however, DEC Qbus controllers all interrupt on IPL 14 @@ -365,6 +367,8 @@ typedef struct { #define INT_V_VHTX 18 #define INT_V_QDSS 19 /* QDSS */ #define INT_V_CR 20 +#define INT_V_DMCRX 21 /* DMC11 */ +#define INT_V_DMCTX 22 #define INT_CLK (1u << INT_V_CLK) #define INT_RQ (1u << INT_V_RQ) @@ -388,6 +392,8 @@ typedef struct { #define INT_VHTX (1u << INT_V_VHTX) #define INT_QDSS (1u << INT_V_QDSS) #define INT_CR (1u << INT_V_CR) +#define INT_DMCRX (1u << INT_V_DMCRX) +#define INT_DMCTX (1u << INT_V_DMCTX) #define IPL_CLK (0x16 - IPL_HMIN) /* relative IPL */ #define IPL_RQ (0x14 - IPL_HMIN) @@ -411,6 +417,8 @@ typedef struct { #define IPL_VHTX (0x14 - IPL_HMIN) #define IPL_QDSS (0x14 - IPL_HMIN) #define IPL_CR (0x14 - IPL_HMIN) +#define IPL_DMCRX (0x14 - IPL_HMIN) +#define IPL_DMCTX (0x14 - IPL_HMIN) #define IPL_HMAX 0x17 /* highest hwre level */ #define IPL_HMIN 0x14 /* lowest hwre level */ @@ -437,6 +445,8 @@ typedef struct { #define VEC_DZTX (VEC_Q + 0304) #define VEC_VHRX (VEC_Q + 0310) #define VEC_VHTX (VEC_Q + 0314) +#define VEC_DMCRX (VEC_Q + 0310) +#define VEC_DMCTX (VEC_Q + 0314) /* Interrupt macros */ diff --git a/Visual Studio Projects/ALTAIR.vcproj b/Visual Studio Projects/ALTAIR.vcproj index 50953c79..20741a3b 100644 --- a/Visual Studio Projects/ALTAIR.vcproj +++ b/Visual Studio Projects/ALTAIR.vcproj @@ -218,6 +218,10 @@ RelativePath="..\sim_fio.c" > + + @@ -267,6 +271,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/AltairZ80.vcproj b/Visual Studio Projects/AltairZ80.vcproj index 9125307d..12d0702f 100644 --- a/Visual Studio Projects/AltairZ80.vcproj +++ b/Visual Studio Projects/AltairZ80.vcproj @@ -321,6 +321,10 @@ RelativePath="..\AltairZ80\sim_imd.c" > + + @@ -378,6 +382,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/BuildROMs.vcproj b/Visual Studio Projects/BuildROMs.vcproj index 570688c6..684766a5 100644 --- a/Visual Studio Projects/BuildROMs.vcproj +++ b/Visual Studio Projects/BuildROMs.vcproj @@ -50,7 +50,7 @@ UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="false" - DebugInformationFormat="4" + DebugInformationFormat="3" /> + + @@ -294,6 +298,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/GRI.vcproj b/Visual Studio Projects/GRI.vcproj index 3f88b5bb..29b5acba 100644 --- a/Visual Studio Projects/GRI.vcproj +++ b/Visual Studio Projects/GRI.vcproj @@ -213,6 +213,10 @@ RelativePath="..\sim_fio.c" > + + @@ -262,6 +266,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/H316.vcproj b/Visual Studio Projects/H316.vcproj index 8bd7530e..a48ef4fe 100644 --- a/Visual Studio Projects/H316.vcproj +++ b/Visual Studio Projects/H316.vcproj @@ -229,6 +229,10 @@ RelativePath="..\sim_fio.c" > + + @@ -278,6 +282,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/HP2100.vcproj b/Visual Studio Projects/HP2100.vcproj index 2978e132..8cdd3fbc 100644 --- a/Visual Studio Projects/HP2100.vcproj +++ b/Visual Studio Projects/HP2100.vcproj @@ -317,6 +317,10 @@ RelativePath="..\sim_fio.c" > + + @@ -390,6 +394,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/I1401.vcproj b/Visual Studio Projects/I1401.vcproj index e9b6d64e..3de4930f 100644 --- a/Visual Studio Projects/I1401.vcproj +++ b/Visual Studio Projects/I1401.vcproj @@ -229,6 +229,10 @@ RelativePath="..\sim_fio.c" > + + @@ -282,6 +286,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/I1620.vcproj b/Visual Studio Projects/I1620.vcproj index 7a3afc53..4f1eb453 100644 --- a/Visual Studio Projects/I1620.vcproj +++ b/Visual Studio Projects/I1620.vcproj @@ -233,6 +233,10 @@ RelativePath="..\sim_fio.c" > + + @@ -282,6 +286,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/I7094.vcproj b/Visual Studio Projects/I7094.vcproj index 6f04a6b1..d1871c95 100644 --- a/Visual Studio Projects/I7094.vcproj +++ b/Visual Studio Projects/I7094.vcproj @@ -249,6 +249,10 @@ RelativePath="..\sim_fio.c" > + + @@ -302,6 +306,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/IBM1130.vcproj b/Visual Studio Projects/IBM1130.vcproj index 2a116ced..c59f1b04 100644 --- a/Visual Studio Projects/IBM1130.vcproj +++ b/Visual Studio Projects/IBM1130.vcproj @@ -253,6 +253,10 @@ RelativePath="..\sim_fio.c" > + + @@ -326,6 +330,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/ID16.vcproj b/Visual Studio Projects/ID16.vcproj index 0c50ccc7..340ec469 100644 --- a/Visual Studio Projects/ID16.vcproj +++ b/Visual Studio Projects/ID16.vcproj @@ -261,6 +261,10 @@ RelativePath="..\sim_fio.c" > + + @@ -310,6 +314,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/ID32.vcproj b/Visual Studio Projects/ID32.vcproj index 9474205e..c7b34690 100644 --- a/Visual Studio Projects/ID32.vcproj +++ b/Visual Studio Projects/ID32.vcproj @@ -261,6 +261,10 @@ RelativePath="..\sim_fio.c" > + + @@ -310,6 +314,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/NOVA.vcproj b/Visual Studio Projects/NOVA.vcproj index ed896b38..be2bc396 100644 --- a/Visual Studio Projects/NOVA.vcproj +++ b/Visual Studio Projects/NOVA.vcproj @@ -249,6 +249,10 @@ RelativePath="..\sim_fio.c" > + + @@ -298,6 +302,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/PDP1.vcproj b/Visual Studio Projects/PDP1.vcproj index d367998d..c1954faa 100644 --- a/Visual Studio Projects/PDP1.vcproj +++ b/Visual Studio Projects/PDP1.vcproj @@ -233,6 +233,10 @@ RelativePath="..\sim_fio.c" > + + @@ -282,6 +286,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/PDP10.vcproj b/Visual Studio Projects/PDP10.vcproj index 36c52831..766ca9e9 100644 --- a/Visual Studio Projects/PDP10.vcproj +++ b/Visual Studio Projects/PDP10.vcproj @@ -267,6 +267,10 @@ RelativePath="..\sim_fio.c" > + + @@ -316,6 +320,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/PDP11.vcproj b/Visual Studio Projects/PDP11.vcproj index ef31b431..030a8c27 100644 --- a/Visual Studio Projects/PDP11.vcproj +++ b/Visual Studio Projects/PDP11.vcproj @@ -215,6 +215,10 @@ RelativePath="..\PDP11\pdp11_dl.c" > + + @@ -375,6 +379,10 @@ RelativePath="..\sim_fio.c" > + + @@ -408,6 +416,10 @@ RelativePath="..\PDP11\pdp11_defs.h" > + + @@ -460,6 +472,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/PDP15.vcproj b/Visual Studio Projects/PDP15.vcproj index 8241c99f..8ecf0638 100644 --- a/Visual Studio Projects/PDP15.vcproj +++ b/Visual Studio Projects/PDP15.vcproj @@ -245,6 +245,10 @@ RelativePath="..\sim_fio.c" > + + @@ -294,6 +298,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/PDP4.vcproj b/Visual Studio Projects/PDP4.vcproj index b7049eca..c6accca9 100644 --- a/Visual Studio Projects/PDP4.vcproj +++ b/Visual Studio Projects/PDP4.vcproj @@ -245,6 +245,10 @@ RelativePath="..\sim_fio.c" > + + @@ -294,6 +298,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/PDP7.vcproj b/Visual Studio Projects/PDP7.vcproj index 0364ef2e..cd589e1b 100644 --- a/Visual Studio Projects/PDP7.vcproj +++ b/Visual Studio Projects/PDP7.vcproj @@ -245,6 +245,10 @@ RelativePath="..\sim_fio.c" > + + @@ -294,6 +298,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/PDP8.vcproj b/Visual Studio Projects/PDP8.vcproj index a71bbc0a..758c4555 100644 --- a/Visual Studio Projects/PDP8.vcproj +++ b/Visual Studio Projects/PDP8.vcproj @@ -273,6 +273,10 @@ RelativePath="..\sim_fio.c" > + + @@ -322,6 +326,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/PDP9.vcproj b/Visual Studio Projects/PDP9.vcproj index 781b2de3..58360e59 100644 --- a/Visual Studio Projects/PDP9.vcproj +++ b/Visual Studio Projects/PDP9.vcproj @@ -249,6 +249,10 @@ RelativePath="..\sim_fio.c" > + + @@ -298,6 +302,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/S3.vcproj b/Visual Studio Projects/S3.vcproj index 752d9fba..6037598e 100644 --- a/Visual Studio Projects/S3.vcproj +++ b/Visual Studio Projects/S3.vcproj @@ -225,6 +225,10 @@ RelativePath="..\sim_fio.c" > + + @@ -274,6 +278,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/SDS.vcproj b/Visual Studio Projects/SDS.vcproj index c15a9b5c..1df76ae1 100644 --- a/Visual Studio Projects/SDS.vcproj +++ b/Visual Studio Projects/SDS.vcproj @@ -241,6 +241,10 @@ RelativePath="..\sim_fio.c" > + + @@ -290,6 +294,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/TX-0.vcproj b/Visual Studio Projects/TX-0.vcproj index 5fb8d758..667b6b68 100644 --- a/Visual Studio Projects/TX-0.vcproj +++ b/Visual Studio Projects/TX-0.vcproj @@ -203,6 +203,10 @@ RelativePath="..\sim_fio.c" > + + @@ -268,6 +272,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/VAX.vcproj b/Visual Studio Projects/VAX.vcproj index 4e30884e..f7415627 100644 --- a/Visual Studio Projects/VAX.vcproj +++ b/Visual Studio Projects/VAX.vcproj @@ -27,7 +27,7 @@ + + @@ -288,6 +292,10 @@ RelativePath="..\sim_fio.c" > + + @@ -361,6 +369,10 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc" > + + @@ -409,6 +421,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/VAX610.vcproj b/Visual Studio Projects/VAX610.vcproj index 7d9cee8f..4a3753de 100644 --- a/Visual Studio Projects/VAX610.vcproj +++ b/Visual Studio Projects/VAX610.vcproj @@ -27,7 +27,7 @@ + + @@ -413,6 +417,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/VAX620.vcproj b/Visual Studio Projects/VAX620.vcproj index 7bd3c56a..9f690213 100644 --- a/Visual Studio Projects/VAX620.vcproj +++ b/Visual Studio Projects/VAX620.vcproj @@ -27,7 +27,7 @@ + + @@ -413,6 +417,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/VAX630.vcproj b/Visual Studio Projects/VAX630.vcproj index 122c078e..2eb6b7eb 100644 --- a/Visual Studio Projects/VAX630.vcproj +++ b/Visual Studio Projects/VAX630.vcproj @@ -27,7 +27,7 @@ + + @@ -413,6 +417,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/VAX730.vcproj b/Visual Studio Projects/VAX730.vcproj index f82b08cb..446cafcd 100644 --- a/Visual Studio Projects/VAX730.vcproj +++ b/Visual Studio Projects/VAX730.vcproj @@ -27,7 +27,7 @@ + + @@ -411,6 +415,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/VAX750.vcproj b/Visual Studio Projects/VAX750.vcproj index 02a0a694..f64d767e 100644 --- a/Visual Studio Projects/VAX750.vcproj +++ b/Visual Studio Projects/VAX750.vcproj @@ -27,7 +27,7 @@ + + @@ -419,6 +423,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/VAX780.vcproj b/Visual Studio Projects/VAX780.vcproj index 2044067c..494f12e8 100644 --- a/Visual Studio Projects/VAX780.vcproj +++ b/Visual Studio Projects/VAX780.vcproj @@ -27,7 +27,7 @@ + + @@ -302,6 +306,10 @@ RelativePath="..\sim_fio.c" > + + @@ -387,6 +395,10 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc" > + + @@ -431,6 +443,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/lgp.vcproj b/Visual Studio Projects/lgp.vcproj index 67701a97..bc15eb08 100644 --- a/Visual Studio Projects/lgp.vcproj +++ b/Visual Studio Projects/lgp.vcproj @@ -213,6 +213,10 @@ RelativePath="..\sim_fio.c" > + + @@ -262,6 +266,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/swtp6800mp-a.vcproj b/Visual Studio Projects/swtp6800mp-a.vcproj index bf86be0d..fcd0851a 100644 --- a/Visual Studio Projects/swtp6800mp-a.vcproj +++ b/Visual Studio Projects/swtp6800mp-a.vcproj @@ -237,6 +237,14 @@ RelativePath="..\sim_fio.c" > + + + + @@ -282,6 +290,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/Visual Studio Projects/swtp6800mp-a2.vcproj b/Visual Studio Projects/swtp6800mp-a2.vcproj index b3230803..6dd27c3e 100644 --- a/Visual Studio Projects/swtp6800mp-a2.vcproj +++ b/Visual Studio Projects/swtp6800mp-a2.vcproj @@ -241,6 +241,10 @@ RelativePath="..\sim_fio.c" > + + @@ -286,6 +290,10 @@ RelativePath="..\sim_rev.h" > + + diff --git a/build_mingw.bat b/build_mingw.bat index ff738d41..a87e8c0d 100644 --- a/build_mingw.bat +++ b/build_mingw.bat @@ -17,4 +17,4 @@ if ERRORLEVEL 1 path C:\MinGW\bin;%path% if not exist BIN mkdir BIN gcc -v 1>NUL 2>NUL if ERRORLEVEL 1 echo "MinGW Environment Unavailable" -mingw32-make WIN32=1 -f makefile %1 %2 %3 %4 +mingw32-make WIN32=1 -f makefile %* diff --git a/build_mingw_ether.bat b/build_mingw_ether.bat index 51ec0bfd..e50f29fd 100644 --- a/build_mingw_ether.bat +++ b/build_mingw_ether.bat @@ -13,4 +13,4 @@ if ERRORLEVEL 1 path C:\MinGW\bin;%path% if not exist BIN mkdir BIN gcc -v 1>NUL 2>NUL if ERRORLEVEL 1 echo "MinGW Environment Unavailable" -mingw32-make WIN32=1 USE_NETWORK=1 -f makefile %1 %2 %3 %4 +mingw32-make WIN32=1 USE_NETWORK=1 -f makefile %* diff --git a/build_mingw_noasync.bat b/build_mingw_noasync.bat index 04f4a19f..a53eab53 100644 --- a/build_mingw_noasync.bat +++ b/build_mingw_noasync.bat @@ -12,4 +12,4 @@ if ERRORLEVEL 1 path C:\MinGW\bin;%path% if not exist BIN mkdir BIN gcc -v 1>NUL 2>NUL if ERRORLEVEL 1 echo "MinGW Environment Unavailable" -mingw32-make WIN32=1 NOASYNCH=1 -f makefile %1 %2 %3 %4 +mingw32-make WIN32=1 NOASYNCH=1 -f makefile %* diff --git a/descrip.mms b/descrip.mms index a362c2a2..2ac2de0a 100644 --- a/descrip.mms +++ b/descrip.mms @@ -194,7 +194,8 @@ SIMH_LIB = $(LIB_DIR)SIMH-$(ARCH).OLB SIMH_SOURCE = $(SIMH_DIR)SIM_CONSOLE.C,$(SIMH_DIR)SIM_SOCK.C,\ $(SIMH_DIR)SIM_TMXR.C,$(SIMH_DIR)SIM_ETHER.C,\ $(SIMH_DIR)SIM_TAPE.C,$(SIMH_DIR)SIM_FIO.C,\ - $(SIMH_DIR)SIM_TIMER.C,$(SIMH_DIR)SIM_DISK.C + $(SIMH_DIR)SIM_TIMER.C,$(SIMH_DIR)SIM_DISK.C,\ + $(SIMH_DIR)SIM_SERIAL.C SIMH_MAIN = SCP.C .IFDEF ALPHA_OR_IA64 SIMH_LIB64 = $(LIB_DIR)SIMH64-$(ARCH).OLB @@ -526,7 +527,8 @@ PDP11_SOURCE1 = $(PDP11_DIR)PDP11_FP.C,$(PDP11_DIR)PDP11_CPU.C,\ $(PDP11_DIR)PDP11_RX.C,$(PDP11_DIR)PDP11_STDDEV.C,\ $(PDP11_DIR)PDP11_SYS.C,$(PDP11_DIR)PDP11_TC.C, \ $(PDP11_DIR)PDP11_CPUMOD.C,$(PDP11_DIR)PDP11_CR.C,\ - $(PDP11_DIR)PDP11_TA.C,$(PDP11_DIR)PDP11_IO_LIB.C + $(PDP11_DIR)PDP11_TA.C,$(PDP11_DIR)PDP11_DMC.C,\ + $(PDP11_DIR)PDP11_IO_LIB.C PDP11_LIB2 = $(LIB_DIR)PDP11L2-$(ARCH).OLB PDP11_SOURCE2 = $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ $(PDP11_DIR)PDP11_IO.C,$(PDP11_DIR)PDP11_RQ.C,\ @@ -619,7 +621,8 @@ VAX_SOURCE2 = $(PDP11_DIR)PDP11_IO_LIB.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_XQ.C,$(PDP11_DIR)PDP11_CR.C,\ - $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_VH.C + $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_VH.C,\ + $(PDP11_DIR)PDP11_DMC.C .IFDEF ALPHA_OR_IA64 VAX_OPTIONS = /INCL=($(SIMH_DIR),$(VAX_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS)) @@ -736,7 +739,8 @@ VAX780_SOURCE2 = $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ $(PDP11_DIR)PDP11_XU.C,$(PDP11_DIR)PDP11_RY.C,\ $(PDP11_DIR)PDP11_CR.C,$(PDP11_DIR)PDP11_RP.C,\ $(PDP11_DIR)PDP11_TU.C,$(PDP11_DIR)PDP11_HK.C,\ - $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_IO_LIB.C + $(PDP11_DIR)PDP11_VH.C,$(PDP11_DIR)PDP11_DMC.C,\ + $(PDP11_DIR)PDP11_IO_LIB.C .IFDEF ALPHA_OR_IA64 VAX780_OPTIONS = /INCL=($(SIMH_DIR),$(VAX780_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEF=($(CC_DEFS),"VM_VAX=1","USE_ADDR64=1","USE_INT64=1"$(PCAP_DEFS),"VAX_780=1") diff --git a/doc/simh.doc b/doc/simh.doc new file mode 100644 index 00000000..5271183e --- /dev/null +++ b/doc/simh.doc @@ -0,0 +1,2968 @@ +{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi0\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} +{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\fbidi \froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f10\fbidi \fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;} +{\f11\fbidi \fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}MS Mincho{\*\falt MS ??};}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;}{\f37\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;} +{\f38\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Tahoma;}{\f39\fbidi \fmodern\fcharset128\fprq1{\*\panose 02020609040205080304}@MS Mincho;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria;} +{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2{\*\panose 020f0502020204030204}Calibri;} +{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f293\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f294\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\f296\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f297\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f298\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f299\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} +{\f300\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f301\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f303\fbidi \fswiss\fcharset238\fprq2 Arial CE;}{\f304\fbidi \fswiss\fcharset204\fprq2 Arial Cyr;} +{\f306\fbidi \fswiss\fcharset161\fprq2 Arial Greek;}{\f307\fbidi \fswiss\fcharset162\fprq2 Arial Tur;}{\f308\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f309\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);} +{\f310\fbidi \fswiss\fcharset186\fprq2 Arial Baltic;}{\f311\fbidi \fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\f313\fbidi \fmodern\fcharset238\fprq1 Courier New CE;}{\f314\fbidi \fmodern\fcharset204\fprq1 Courier New Cyr;} +{\f316\fbidi \fmodern\fcharset161\fprq1 Courier New Greek;}{\f317\fbidi \fmodern\fcharset162\fprq1 Courier New Tur;}{\f318\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew);}{\f319\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic);} +{\f320\fbidi \fmodern\fcharset186\fprq1 Courier New Baltic;}{\f321\fbidi \fmodern\fcharset163\fprq1 Courier New (Vietnamese);}{\f405\fbidi \fmodern\fcharset0\fprq1 MS Mincho Western{\*\falt MS ??};} +{\f403\fbidi \fmodern\fcharset238\fprq1 MS Mincho CE{\*\falt MS ??};}{\f404\fbidi \fmodern\fcharset204\fprq1 MS Mincho Cyr{\*\falt MS ??};}{\f406\fbidi \fmodern\fcharset161\fprq1 MS Mincho Greek{\*\falt MS ??};} +{\f407\fbidi \fmodern\fcharset162\fprq1 MS Mincho Tur{\*\falt MS ??};}{\f410\fbidi \fmodern\fcharset186\fprq1 MS Mincho Baltic{\*\falt MS ??};}{\f633\fbidi \froman\fcharset238\fprq2 Cambria Math CE;} +{\f634\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;}{\f636\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f637\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f640\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;} +{\f641\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);}{\f663\fbidi \fswiss\fcharset238\fprq2 Calibri CE;}{\f664\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f666\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;} +{\f667\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f670\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\f671\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\f673\fbidi \fswiss\fcharset238\fprq2 Tahoma CE;} +{\f674\fbidi \fswiss\fcharset204\fprq2 Tahoma Cyr;}{\f676\fbidi \fswiss\fcharset161\fprq2 Tahoma Greek;}{\f677\fbidi \fswiss\fcharset162\fprq2 Tahoma Tur;}{\f678\fbidi \fswiss\fcharset177\fprq2 Tahoma (Hebrew);} +{\f679\fbidi \fswiss\fcharset178\fprq2 Tahoma (Arabic);}{\f680\fbidi \fswiss\fcharset186\fprq2 Tahoma Baltic;}{\f681\fbidi \fswiss\fcharset163\fprq2 Tahoma (Vietnamese);}{\f682\fbidi \fswiss\fcharset222\fprq2 Tahoma (Thai);} +{\f685\fbidi \fmodern\fcharset0\fprq1 @MS Mincho Western;}{\f683\fbidi \fmodern\fcharset238\fprq1 @MS Mincho CE;}{\f684\fbidi \fmodern\fcharset204\fprq1 @MS Mincho Cyr;}{\f686\fbidi \fmodern\fcharset161\fprq1 @MS Mincho Greek;} +{\f687\fbidi \fmodern\fcharset162\fprq1 @MS Mincho Tur;}{\f690\fbidi \fmodern\fcharset186\fprq1 @MS Mincho Baltic;}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\fhimajor\f31528\fbidi \froman\fcharset238\fprq2 Cambria CE;}{\fhimajor\f31529\fbidi \froman\fcharset204\fprq2 Cambria Cyr;}{\fhimajor\f31531\fbidi \froman\fcharset161\fprq2 Cambria Greek;}{\fhimajor\f31532\fbidi \froman\fcharset162\fprq2 Cambria Tur;} +{\fhimajor\f31535\fbidi \froman\fcharset186\fprq2 Cambria Baltic;}{\fhimajor\f31536\fbidi \froman\fcharset163\fprq2 Cambria (Vietnamese);}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} +{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} +{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;} +{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;} +{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0; +\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red163\green21\blue21;}{\*\defchp +\fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa200\sl276\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{ +\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{ +\s1\ql \fi-360\li360\ri0\sb240\sa60\keepn\widctlpar\jclisttab\tx360\wrapdefault\faauto\ls1\outlinelevel0\adjustright\rin0\lin360\itap0 \rtlch\fcs1 \ab\af1\afs28\alang1025 \ltrch\fcs0 +\b\fs28\lang1033\langfe1033\kerning28\loch\f1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink15 \sqformat heading 1;}{\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\f1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext0 \slink16 \sqformat heading 2;}{\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 +\fs24\lang1033\langfe1033\loch\f1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink17 \sqformat heading 3;}{\*\cs10 \additive Default Paragraph Font;}{\* +\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa200\sl276\slmult1 +\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0 \fs22\lang1033\langfe1033\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1033\langfenp1033 \snext11 \ssemihidden \sunhideused +Normal Table;}{\*\cs15 \additive \rtlch\fcs1 \ab\af0\afs32 \ltrch\fcs0 \b\fs32\kerning32\loch\f31502\hich\af31502\dbch\af31501 \sbasedon10 \slink1 \slocked \spriority9 Heading 1 Char;}{\*\cs16 \additive \rtlch\fcs1 \ab\ai\af0\afs28 \ltrch\fcs0 +\b\i\fs28\loch\f31502\hich\af31502\dbch\af31501 \sbasedon10 \slink2 \slocked \ssemihidden \spriority9 Heading 2 Char;}{\*\cs17 \additive \rtlch\fcs1 \ab\af0\afs26 \ltrch\fcs0 \b\fs26\loch\f31502\hich\af31502\dbch\af31501 +\sbasedon10 \slink3 \slocked \ssemihidden \spriority9 Heading 3 Char;}{\*\cs18 \additive \rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b \sbasedon10 \sqformat Strong;}{\s19\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 +\ab\af1\afs20\alang1025 \ltrch\fcs0 \b\fs20\lang1033\langfe1033\loch\f1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext19 \slink20 Body Text;}{\*\cs20 \additive \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f0\fs20 +\sbasedon10 \slink19 \slocked \ssemihidden Body Text Char;}{\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 +\fs20\lang1033\langfe1033\loch\f1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext21 \slink22 Body Text 2;}{\*\cs22 \additive \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f0\fs20 \sbasedon10 \slink21 \slocked \ssemihidden Body Text 2 Char;}{ +\s23\ql \li0\ri0\sb120\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\ai\af0\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext0 \sautoupd \spriority39 toc 1;}{\s24\ql \li200\ri0\sb120\widctlpar\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \sautoupd \spriority39 toc 2;}{\s25\ql \li400\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin400\itap0 \rtlch\fcs1 \af0\afs20\alang1025 +\ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \sautoupd \spriority39 toc 3;}{\s26\ql \li600\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin600\itap0 \rtlch\fcs1 +\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \sautoupd toc 4;}{\s27\ql \li800\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin800\itap0 \rtlch\fcs1 +\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \sautoupd toc 5;}{\s28\ql \li1000\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin1000\itap0 \rtlch\fcs1 +\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \sautoupd toc 6;}{\s29\ql \li1200\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin1200\itap0 \rtlch\fcs1 +\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \sautoupd toc 7;}{\s30\ql \li1400\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin1400\itap0 \rtlch\fcs1 +\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \sautoupd toc 8;}{\s31\ql \li1600\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin1600\itap0 \rtlch\fcs1 +\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \sautoupd toc 9;}{\s32\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \cbpat9 \rtlch\fcs1 +\af38\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f38\hich\af38\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext32 \slink33 Document Map;}{\*\cs33 \additive \rtlch\fcs1 \af38\afs16 \ltrch\fcs0 \f38\fs16 +\sbasedon10 \slink32 \slocked \ssemihidden Document Map Char;}{\s34\ql \li390\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 +\fs20\lang1033\langfe1033\loch\f1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext34 \slink35 Body Text Indent 2;}{\*\cs35 \additive \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f0\fs20 \sbasedon10 \slink34 \slocked \ssemihidden +Body Text Indent 2 Char;}{\s36\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af2\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f2\hich\af2\dbch\af31505\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext36 \slink37 Plain Text;}{\*\cs37 \additive \rtlch\fcs1 \af2\afs20 \ltrch\fcs0 \f2\fs20 \sbasedon10 \slink36 \slocked \ssemihidden Plain Text Char;}{\s38\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 +\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\f0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext38 \sqformat \spriority34 \styrsid10051909 List Paragraph;}{ +\s39\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af38\afs16\alang1025 \ltrch\fcs0 \fs16\lang1033\langfe1033\loch\f38\hich\af38\dbch\af31505\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext39 \slink40 \ssemihidden \sunhideused \styrsid10051909 Balloon Text;}{\*\cs40 \additive \rtlch\fcs1 \af38\afs16 \ltrch\fcs0 \f38\fs16 \sbasedon10 \slink39 \slocked \ssemihidden \styrsid10051909 Balloon Text Char;}}{\*\listtable +{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listname +;}\listid22442644}{\list\listtemplateid846903958\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 +\fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0 +{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693 +\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid40597282}{\list\listtemplateid1593215596{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0 +{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 +\fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0 +{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 +\fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel +\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid56512481}{\list\listtemplateid-1973507402 +\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-360\li1080\jclisttab\tx1080\lin1080 }{\listname +;}\listid154348404}{\list\listtemplateid-332364684{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \s1\fi-360\li360 +\jclisttab\tx360\lin360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \s2\fi-390\li390 +\jclisttab\tx390\lin390 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \s3\fi-720\li720 +\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 +\fi-1080\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\rtlch\fcs1 \af0 +\ltrch\fcs0 \fbias0 \fi-1080\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers +\'01\'03\'05\'07\'09\'0b;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext +\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal +\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1800\li1800\jclisttab\tx1800\lin1800 }{\listlevel\levelnfc0\levelnfcn0\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1800\li1800 +\jclisttab\tx1800\lin1800 }{\listname ;}\listid155609463}{\list\listtemplateid-847613572\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689 +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;} +\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160 +\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid586499726}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listname ;}\listid602111040}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listname ;}\listid621424954}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listname ;}\listid717362522}{\list\listtemplateid67698689\listsimple{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li360\jclisttab\tx360\lin360 }{\listname ;}\listid1064328194}{\list\listtemplateid1706078190\listsimple +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listname ;}\listid1080104542} +{\list\listtemplateid-40875858\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-360\li1080 +\jclisttab\tx1080\lin1080 }{\listname ;}\listid1106123233}{\list\listtemplateid-5054418{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'01\'00;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 +\ltrch\fcs0 \fbias0 \fi-435\li435\jclisttab\tx435\lin435 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 +\fi-435\li435\jclisttab\tx435\lin435 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li720 +\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li720 +\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 +\fi-1080\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\rtlch\fcs1 \af0 +\ltrch\fcs0 \fbias0 \fi-1080\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers +\'01\'03\'05\'07\'09\'0b\'0d;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1800\li1800\jclisttab\tx1800\lin1800 }{\listname ;}\listid1262834005} +{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listname +;}\listid1272592440}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 +\jclisttab\tx720\lin720 }{\listname ;}\listid1339387548}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;} +\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listname ;}\listid1409111490}{\list\listtemplateid-1973507402\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext +\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-360\li1080\jclisttab\tx1080\lin1080 }{\listname ;}\listid1463183950}{\list\listtemplateid1666980492{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160 +\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760 +\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname +;}\listid1484007768}{\list\listtemplateid230209238{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat3\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-360\li360 +\jclisttab\tx360\lin360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-360\li360 +\jclisttab\tx360\lin360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li720 +\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 +\fi-720\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\rtlch\fcs1 \af0 +\ltrch\fcs0 \fbias0 \fi-720\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers +\'01\'03\'05\'07\'09\'0b;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1080\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext +\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1080\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levellegal +\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0 +\leveljcn0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li1440 +\jclisttab\tx1440\lin1440 }{\listname ;}\listid1502426668}{\list\listtemplateid1089363688\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689 +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;} +\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160 +\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid1510413937}{\list\listtemplateid355235766{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li360\jclisttab\tx360\lin360 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li1800 +\jclisttab\tx1800\lin1800 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2520\jclisttab\tx2520\lin2520 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3240\jclisttab\tx3240\lin3240 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li3960\jclisttab\tx3960\lin3960 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li4680\jclisttab\tx4680\lin4680 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5400 +\jclisttab\tx5400\lin5400 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6120\jclisttab\tx6120\lin6120 }{\listname +;}\listid1523011899}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720 +\jclisttab\tx720\lin720 }{\listname ;}\listid1645162521}{\list\listtemplateid1955916020\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689 +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;} +\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160 +\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 } +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23 +\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0 +\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\leveltemplateid67698689\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace360\levelindent0{\leveltext\leveltemplateid67698691\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\leveltemplateid67698693\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid1893996833}{\list\listtemplateid-40875858\listsimple{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-360\li1080\jclisttab\tx1080\lin1080 }{\listname ;}\listid1999114611}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listname ;}\listid2006126440}{\list\listtemplateid1706078190\listsimple +{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listname ;}\listid2076124660} +{\list\listtemplateid1666980492{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1 +\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600 +\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23 +\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0 +\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext +\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid2112620548}}{\*\listoverridetable{\listoverride\listid155609463\listoverridecount0\ls1}{\listoverride\listid1409111490\listoverridecount0\ls2} +{\listoverride\listid1272592440\listoverridecount0\ls3}{\listoverride\listid2076124660\listoverridecount0\ls4}{\listoverride\listid717362522\listoverridecount0\ls5}{\listoverride\listid1339387548\listoverridecount0\ls6}{\listoverride\listid621424954 +\listoverridecount0\ls7}{\listoverride\listid1080104542\listoverridecount0\ls8}{\listoverride\listid1262834005\listoverridecount0\ls9}{\listoverride\listid2006126440\listoverridecount0\ls10}{\listoverride\listid602111040\listoverridecount0\ls11} +{\listoverride\listid22442644\listoverridecount0\ls12}{\listoverride\listid1502426668\listoverridecount0\ls13}{\listoverride\listid1645162521\listoverridecount0\ls14}{\listoverride\listid1064328194\listoverridecount0\ls15}{\listoverride\listid2112620548 +\listoverridecount0\ls16}{\listoverride\listid1484007768\listoverridecount0\ls17}{\listoverride\listid1523011899\listoverridecount0\ls18}{\listoverride\listid56512481\listoverridecount0\ls19}{\listoverride\listid154348404\listoverridecount0\ls20} +{\listoverride\listid1106123233\listoverridecount0\ls21}{\listoverride\listid1463183950\listoverridecount0\ls22}{\listoverride\listid1999114611\listoverridecount0\ls23}{\listoverride\listid586499726\listoverridecount0\ls24}{\listoverride\listid1510413937 +\listoverridecount0\ls25}{\listoverride\listid40597282\listoverridecount0\ls26}{\listoverride\listid1893996833\listoverridecount0\ls27}}{\*\revtbl {Unknown;}}{\*\rsidtbl \rsid1049593\rsid1264706\rsid2698330\rsid3806017\rsid3891160\rsid3951926\rsid4462419\rsid4550150 +\rsid7674256\rsid8084824\rsid8129972\rsid8352301\rsid9308345\rsid9462171\rsid9973523\rsid10051909\rsid11167734\rsid13897431\rsid15957281\rsid16013944}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1 +\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\title Writing a Simulator for the SIMH System}{\author Bob Supnik}{\operator Admin}{\creatim\yr1997\mo8\dy30\hr19}{\revtim\yr2012\mo12\dy18\hr9\min27}{\printim\yr2008\mo8\dy17\hr11\min45}{\version99} +{\edmins2245}{\nofpages36}{\nofwords13773}{\nofchars78512}{\*\company Digital Equipment Corporation}{\nofcharsws92101}{\vern49275}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}} +\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect +\widowctrl\ftnbj\aenddoc\revisions\trackmoves0\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0 +\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\formshade\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\nolnhtadjtbl\rsidroot1049593 \fet0 +{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3 +\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}} +{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ltrpar +\qc \fi-720\li720\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1\afs32 +\ltrch\fcs0 \b\f1\fs32\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Writing a Simulator for the SIMH System +\par }\pard \ltrpar\qc \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \ab\af1\afs32 \ltrch\fcs0 \b\f1\fs32\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Revised }{\rtlch\fcs1 \ab\af1\afs32 \ltrch\fcs0 \b\f1\fs32\insrsid10051909 +\hich\af1\dbch\af31505\loch\f1 17-Dec-2012}{\rtlch\fcs1 \ab\af1\afs32 \ltrch\fcs0 \b\f1\fs32\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 for SIMH }{\rtlch\fcs1 \ab\af1\afs32 \ltrch\fcs0 \b\f1\fs32\insrsid10051909 \hich\af1\dbch\af31505\loch\f1 V4.0}{ +\rtlch\fcs1 \ab\af1\afs32 \ltrch\fcs0 \b\f1\fs32\insrsid4550150 +\par }\pard\plain \ltrpar\s36\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af2\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af2\hich\af2\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 +\ab\af2 \ltrch\fcs0 \b\loch\af1\hich\af1\dbch\af11\insrsid4550150 +\par +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\loch\af1\hich\af1\dbch\af11\insrsid4550150 \hich\af1\dbch\af11\loch\f1 COPYRIGHT NOTICE +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \loch\af1\hich\af1\dbch\af11\insrsid4550150 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \loch\af1\hich\af1\dbch\af11\insrsid4550150 \hich\af1\dbch\af11\loch\f1 The following copyright notice applies to the SIMH source, binary, and documentation: +\par +\par }\pard \ltrpar\s36\ql \li720\ri962\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin962\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \loch\af1\hich\af1\dbch\af11\insrsid4550150 \hich\af1\dbch\af11\loch\f1 +Original code published in 1993-2008, written by Robert M Supnik +\par \hich\af1\dbch\af11\loch\f1 Copyright \hich\af1\dbch\af11\loch\f1 (c) 1993-2008, Robert M Supnik +\par +\par \hich\af1\dbch\af11\loch\f1 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 +\hich\af1\dbch\af11\loch\f1 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: +\par +\par \hich\af1\dbch\af11\loch\f1 The above copyright notice and this permission\hich\af1\dbch\af11\loch\f1 notice shall be included in all copies or substantial portions of the Software. +\par +\par \hich\af1\dbch\af11\loch\f1 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 P\hich\af1\dbch\af11\loch\f1 +URPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +\par \hich\af1\dbch\af11\loch\f1 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\hich\af1\dbch\af11\loch\f1 THE SOFTWARE. +\par +\par \hich\af1\dbch\af11\loch\f1 Except as contained in this notice, the name of Robert M Supnik shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + +\par }\pard \ltrpar\s36\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \loch\af1\hich\af1\dbch\af11\insrsid4550150 +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 +\dbch\af11\insrsid4550150 \page }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard\plain \ltrpar\s23\ql \li0\ri0\sb120\widctlpar\tx600\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\ai\af0\afs24\alang1025 \ltrch\fcs0 +\b\i\fs24\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\field\fldedit{\*\fldinst {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 TOC \\o\hich\af1\dbch\af31505\loch\f1 }}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 1.}{\rtlch\fcs1 \ab0\ai0\af31507\afs22 \ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 +\af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Overview\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577871 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800370031000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 4}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\ai0\af31507\afs22 \ltrch\fcs0 +\b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 2.}{\rtlch\fcs1 \ab0\ai0\af31507\afs22 \ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{ +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Data Types\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577872 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800370032000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 4}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\ai0\af31507\afs22 \ltrch\fcs0 +\b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.}{\rtlch\fcs1 \ab0\ai0\af31507\afs22 \ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{ +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 VM Organization\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577873 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800370033000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 5}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\ai0\af31507\afs22 \ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s24\ql \li200\ri0\sb120\widctlpar\tx800\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.1}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 CPU Organization\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 +\lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577874 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800370034000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 6}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s25\ql \li400\ri0\widctlpar\tx1200\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin400\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.1.1}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Time Base\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577875 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800370035000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 6}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.1.2}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Step F\hich\af0\dbch\af31505\loch\f0 unction\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577876 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800370036000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 6}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.1.3}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Memory Organization\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577877 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800370037000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 7}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.1.4}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Interrupt Organization\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577878 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800370038000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 7}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.1.5}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 I/O Dispatching\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577879 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800370039000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 8}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.1.6}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Instruction Execution\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc3\hich\af0\dbch\af31505\loch\f0 43577880 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380030000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 8}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s24\ql \li200\ri0\sb120\widctlpar\tx800\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.2}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Peripheral Device Organization\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577881 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380031000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 9}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s25\ql \li400\ri0\widctlpar\tx1200\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin400\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.2.1}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Device Timing\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577882 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380032000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 10}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.2.2}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Clock Calibration\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577883 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380033000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 11}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.2.3}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Idling\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577884 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380034000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 11}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 3.2.4}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Data I/O\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577885 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380035000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 12}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s23\ql \li0\ri0\sb120\widctlpar\tx600\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\ai\af0\afs24\alang1025 \ltrch\fcs0 +\b\i\fs24\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.}{\rtlch\fcs1 \ab0\ai0\af31507\afs22 +\ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Data Structures\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577886 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380036000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 13}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\ai0\af31507\afs22 \ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s24\ql \li200\ri0\sb120\widctlpar\tx800\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 sim_device Structure\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 +\lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577887 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380037000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 13}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s25\ql \li400\ri0\widctlpar\tx1200\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin400\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1.1}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Awidth and Aincr\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577888 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380038000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 14}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1.2}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Device Flags\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577889 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800380039000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 15}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1.3}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Context\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577890 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390030000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 15}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1.4}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Examine and Deposit Routines\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577891 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390031000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 15}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1.5}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Reset Routine\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577892 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390032000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 16}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1.6}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Boot Routine\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577893 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390033000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 16}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1.7}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Attach and Detach Routines\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF\hich\af0\dbch\af31505\loch\f0 _Toc343577894 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390034000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 16}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1.8}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Memory Size Change Routine\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577895 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390035000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 17}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.1.9}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Debug Controls\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577896 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390036000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 17}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s24\ql \li200\ri0\sb120\widctlpar\tx800\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.2}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 sim_unit Structure\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 +\lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577897 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390037000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 18}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s25\ql \li400\ri0\widctlpar\tx1200\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin400\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.2.1}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Unit Flags\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577898 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390038000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 19}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.2.2}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Service Routine\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577899 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003800390039000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 20}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s24\ql \li200\ri0\sb120\widctlpar\tx800\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.3}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 sim_reg Structure\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 +\lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577900 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300030000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 20}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s25\ql \li400\ri0\widctlpar\tx1200\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin400\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.3.1}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Register Flags\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577901 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300031000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 21}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s24\ql \li200\ri0\sb120\widctlpar\tx800\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.4}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 sim_mtab Structure\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 +\lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577902 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300032000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 21}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s25\ql \li400\ri0\widctlpar\tx1200\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin400\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.4.1}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Validation Routine\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343\hich\af0\dbch\af31505\loch\f0 577903 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300033000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 23}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.4.2}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Display Routine\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577904 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300034000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 23}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s24\ql \li200\ri0\sb120\widctlpar\tx800\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 4.5}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Other Data Structures\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 +\lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577905 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300035000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 24}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s23\ql \li0\ri0\sb120\widctlpar\tx600\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\ai\af0\afs24\alang1025 \ltrch\fcs0 +\b\i\fs24\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 5.}{\rtlch\fcs1 \ab0\ai0\af31507\afs22 +\ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 VM Provided Routines\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 +\af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577906 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300036000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 24}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\ai0\af31507\afs22 \ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s24\ql \li200\ri0\sb120\widctlpar\tx800\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 5.1}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Instruction Execution\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 +\lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577907 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300037000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 24}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 5.2}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Binary\hich\af0\dbch\af31505\loch\f0 Load and Dump\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577908 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300038000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 24}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 5.3}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Symbolic Examination and Deposit\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577909 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900300039000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 24}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 5.4}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Optional Interfaces\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577910 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310030000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 25}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s25\ql \li400\ri0\widctlpar\tx1200\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin400\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 5.4.1}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Once Only Initialization Routine\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577911 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310031000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 25}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 5.4.2}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Add\hich\af0\dbch\af31505\loch\f0 ress Input and Display\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577912 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310032000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 26}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 5.4.3}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Command Input and Post-Processing\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577913 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310033000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 26}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 5.4.4}{\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 \f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 VM-Specific Commands\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577914 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310034000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 26}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \af31507\afs22 \ltrch\fcs0 +\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s23\ql \li0\ri0\sb120\widctlpar\tx600\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\ai\af0\afs24\alang1025 \ltrch\fcs0 +\b\i\fs24\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 6.}{\rtlch\fcs1 \ab0\ai0\af31507\afs22 +\ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Other SCP Facilities\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 +\af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577915 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310035000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 27}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\ai0\af31507\afs22 \ltrch\fcs0 \b0\i0\f31506\fs22\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\s24\ql \li200\ri0\sb120\widctlpar\tx800\tqr\tldot\tx9350\wrapdefault\faauto\adjustright\rin0\lin200\itap0 \rtlch\fcs1 \ab\af0\afs22\alang1025 \ltrch\fcs0 +\b\fs22\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 6.1}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Termin\hich\af0\dbch\af31505\loch\f0 al Input/Output Formatting Library\tab } +{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577916 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310036000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 27}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 6.2}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Terminal Multiplexer Emulation Library\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577917 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310037000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 28}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 6.3}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Magnetic Tape Emulation Library\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 +\hich\af0\dbch\af31505\loch\f0 PAGEREF _Toc343577918 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310038000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 31}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 6.4}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Disk Emulation Library\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc34\hich\af0\dbch\af31505\loch\f0 3577919 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield +08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900310039000000}}}{\fldrslt {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 32}}}\sectd \ltrsect +\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944\charrsid10236607 \hich\af0\dbch\af31505\loch\f0 6.5}{\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 \b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 \tab }{\rtlch\fcs1 \af0 +\ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 Breakpoint Support\tab }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 + PAGEREF _Toc343577920 \\h }{\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003300340033003500370037003900320030000000}}}{\fldrslt { +\rtlch\fcs1 \af0 \ltrch\fcs0 \lang1024\langfe1024\noproof\insrsid16013944 \hich\af0\dbch\af31505\loch\f0 34}}}\sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 \ab0\af31507 \ltrch\fcs0 +\b0\f31506\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 }}\pard\plain \ltrpar +\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 \sectd \ltrsect\linex0\endnhere\sectdefaultcl\sftnbj +{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \page +\par {\*\bkmkstart _Toc343577871}{\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af0\afs28 \ltrch\fcs0 \b\f1\fs28\kerning28\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 1.\tab}}\pard\plain \ltrpar\s1\ql \fi-360\li360\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx360\wrapdefault\faauto\ls1\outlinelevel0\adjustright\rin0\lin360\itap0 \rtlch\fcs1 \ab\af1\afs28\alang1025 \ltrch\fcs0 \b\fs28\lang1033\langfe1033\kerning28\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Overview{\*\bkmkend _Toc343577871} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SIMH (history simulators) is a set of portable programs, writt\hich\af1\dbch\af31505\loch\f1 +en in C, which simulate various historically interesting computers. This document describes how to design, write, and check out a new simulator for SIMH. It is not an introduction to either the philosophy or external operation of SIMH, and the reader sh +\hich\af1\dbch\af31505\loch\f1 o\hich\af1\dbch\af31505\loch\f1 +uld be familiar with both of those topics before proceeding. Nor is it a guide to the internal design or operation of SIMH, except insofar as those areas interact with simulator design. Instead, this manual presents and explains the form, meaning, and o +\hich\af1\dbch\af31505\loch\f1 p\hich\af1\dbch\af31505\loch\f1 +eration of the interfaces between simulators and the SIMH simulator control package. It also offers some suggestions for utilizing the services SIMH offers and explains the constraints that all simulators operating within SIMH will experience. +\par +\par \hich\af1\dbch\af31505\loch\f1 Some termi\hich\af1\dbch\af31505\loch\f1 nology: Each simulator consists of a standard }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 simulator control package}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (SCP and related libraries), which provides a control framework and utility routines for a simulator; and a unique }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 virtual machine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (VM), which implements the simulated processor and se\hich\af1\dbch\af31505\loch\f1 +lected peripherals. A VM consists of multiple }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 devices}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +, such as the CPU, paper tape reader, disk controller, etc. Each controller consists of a named state space (called }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 registers}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ) and one or more }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 units}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +. Each unit consists of a numbered state space (call\hich\af1\dbch\af31505\loch\f1 ed a }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 data set}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 ). }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 The }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 host computer}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is the system on which SIMH runs; the }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 target computer}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is the system being simulated. +\par +\par \hich\af1\dbch\af31505\loch\f1 SIMH is unabashedly based on the MIMIC simulation system, designed in the late 1960\hich\f1 \rquote \loch\f1 s by Len Fehskens, Mike McCarthy, and Bob Supnik. \hich\af1\dbch\af31505\loch\f1 This document is based on MIMIC +\hich\f1 \rquote \loch\f1 \hich\f1 s published interface specification, \'93\loch\f1 \hich\f1 How to Write a Virtual Machine for the MIMIC Simulation System\'94\loch\f1 , by Len Fehskens and Bob Supnik. +\par +\par {\*\bkmkstart _Toc343577872}{\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af0\afs28 \ltrch\fcs0 \b\f1\fs28\kerning28\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 2.\tab}}\pard\plain \ltrpar\s1\ql \fi-360\li360\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx360\wrapdefault\faauto\ls1\outlinelevel0\adjustright\rin0\lin360\itap0 \rtlch\fcs1 \ab\af1\afs28\alang1025 \ltrch\fcs0 \b\fs28\lang1033\langfe1033\kerning28\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Data Types{\*\bkmkend _Toc343577872} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SIMH is written in C. The host system must support (at least) 32-bit data \hich\af1\dbch\af31505\loch\f1 +types (64-bit data types for the PDP-10 and other large-word target systems). To cope with the vagaries of C data types, SIMH defines some unambiguous data types for its interfaces: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 SIMH data type\tab \tab \tab interpretation in typical 32-bit C +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 int8, uint8\tab \tab \tab sig\hich\af1\dbch\af31505\loch\f1 ned char, unsigned char +\par \tab \hich\af1\dbch\af31505\loch\f1 int16, uint16\tab \tab \tab signed short, unsigned short +\par \tab \hich\af1\dbch\af31505\loch\f1 int32, uint32\tab \tab \tab signed int, unsigned int +\par \tab \hich\af1\dbch\af31505\loch\f1 t_int64, t_uint64\tab \tab \tab long long, _int64 (system specific) +\par \tab \hich\af1\dbch\af31505\loch\f1 t_addr\tab \tab \tab \tab simulated address, uint32 or t_uint64 +\par \tab \hich\af1\dbch\af31505\loch\f1 t_value\tab \tab \tab \tab simulated value, uint32 or\hich\af1\dbch\af31505\loch\f1 t_uint64 +\par \tab \hich\af1\dbch\af31505\loch\f1 t_svalue\tab \tab \tab simulated signed value, int32 or t_int64 +\par \tab \hich\af1\dbch\af31505\loch\f1 t_mtrec\tab \tab \tab \tab mag tape record length, uint32 +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab \tab \tab status code, int +\par \tab \hich\af1\dbch\af31505\loch\f1 t_bool\tab \tab \tab \tab true/false value, int +\par +\par \hich\af1\dbch\af31505\loch\f1 [The inconsistency in naming t_int64 and t_uint64 is due to Microsoft VC++, which uses i\hich\af1\dbch\af31505\loch\f1 nt64 as a structure name member in the master Windows definitions file.] +\par +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 In addition, SIMH defines structures for each of its major data elements: + +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 DEVICE}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 device definition structure +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 UNIT}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 unit definition structure +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 REG}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 register definition struct\hich\af1\dbch\af31505\loch\f1 ure + +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 MTAB}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 modifier definition structure +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 CTAB}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 command definition structure +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 DEBTAB}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 debug table entry structure +\par +\par {\*\bkmkstart _Toc343577873}{\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af0\afs28 \ltrch\fcs0 \b\f1\fs28\kerning28\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.\tab}}\pard\plain \ltrpar\s1\ql \fi-360\li360\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx360\wrapdefault\faauto\ls1\outlinelevel0\adjustright\rin0\lin360\itap0 \rtlch\fcs1 \ab\af1\afs28\alang1025 \ltrch\fcs0 \b\fs28\lang1033\langfe1033\kerning28\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 VM Organization{\*\bkmkend _Toc343577873} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 A virtual machine (VM) is a collection of devices bound together through their internal logic. Each device is named an\hich\af1\dbch\af31505\loch\f1 +d corresponds more or less to a hunk of hardware on the real machine; for example: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 VM device\tab \tab \tab Real machine hardware +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 CPU\tab \tab \tab \tab central processor and main memory +\par \tab \hich\af1\dbch\af31505\loch\f1 PTR\tab \tab \tab \tab paper tape reader controller and paper tape reader +\par \tab \hich\af1\dbch\af31505\loch\f1 TTI\tab \tab \tab \tab console keyboard +\par \tab \hich\af1\dbch\af31505\loch\f1 TTO\tab \tab \tab \tab co\hich\af1\dbch\af31505\loch\f1 nsole output +\par \tab \hich\af1\dbch\af31505\loch\f1 DKP\tab \tab \tab \tab disk pack controller and drives +\par +\par \hich\af1\dbch\af31505\loch\f1 There may be more than one device per physical hardware entity, as for the console; but for each user-accessible device there must be at least one. One of these devices will have the pre-eminent respon +\hich\af1\dbch\af31505\loch\f1 sibility for directing simulated operations. Normally, this is the CPU, but it could be a higher-level entity, such as a bus master. +\par +\par \hich\af1\dbch\af31505\loch\f1 The VM actually runs as a subroutine of the simulator control package (SCP). It provides a master routine for running si\hich\af1\dbch\af31505\loch\f1 mulated programs and other routines and data structures to implement SCP +\hich\f1 \rquote \loch\f1 s command and control functions. The interfaces between a VM and SCP are relatively few: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 Interface\tab \tab \tab Function +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 char }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_name[]}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 simulator name string + +\par \tab \hich\af1\dbch\af31505\loch\f1 REG *}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_pc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 pointer to sim +\hich\af1\dbch\af31505\loch\f1 ulated program counter +\par \tab \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_emax}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 +maximum number of words in an instruction +\par \tab \hich\af1\dbch\af31505\loch\f1 DEVICE *}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_devices[]}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 +table of pointers to simulated devices, NULL terminated +\par \tab \hich\af1\dbch\af31505\loch\f1 char *}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_stop_messages[]}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 +table of pointers to error messages +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_load}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 (\'85\loch\f1 )\tab \tab +binary loa\hich\af1\dbch\af31505\loch\f1 der subroutine +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_inst}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (void)\tab \tab +instruction execution subroutine +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 parse_sym}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 (\'85\loch\f1 )\tab \tab +symbolic instruction parse subroutine +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fprint_sym}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 (\'85\loch\f1 )\tab \tab +symbolic instruction print subroutine +\par +\par \hich\af1\dbch\af31505\loch\f1 In addition, there are six optional interfaces, which can b\hich\af1\dbch\af31505\loch\f1 e used for special situations, such as GUI implementations: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 Interface\tab \tab \tab \tab Function +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 void (*}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_init}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ) (void)\tab \tab +pointer to once-only initialization routine for VM +\par \tab \hich\af1\dbch\af31505\loch\f1 t_addr (*}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_parse_addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 ) (\'85\loch\f1 ) +\tab pointer to address parsing routine +\par \tab \hich\af1\dbch\af31505\loch\f1 void (*}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_fprint_a\hich\af1\dbch\af31505\loch\f1 ddr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 \hich\f1 ) (\'85\loch\f1 )\tab pointer to address output routine +\par \tab \hich\af1\dbch\af31505\loch\f1 char (}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 *sim_vm_read}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 ) (\'85\loch\f1 )\tab +\tab pointer to command input routine +\par \tab \hich\af1\dbch\af31505\loch\f1 void (*}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_post}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 ) (\'85\loch\f1 )\tab +\tab pointer to command post-processing routine +\par \tab \hich\af1\dbch\af31505\loch\f1 CTAB }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 *sim_vm_cmd}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 +pointer to simulator-specific command table +\par +\par \hich\af1\dbch\af31505\loch\f1 There is no required\hich\af1\dbch\af31505\loch\f1 organization for VM code. The following convention has been used so far. Let name be the }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 name}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 of the real system (i1401 for the IBM 1401; i1620 for the IBM 1620; pdp1 for the PDP-1; pdp18b for the other 18-bit PDP\hich\f1 \rquote +\loch\f1 s; pdp8 for the PDP-8; pdp11 for the PD\hich\af1\dbch\af31505\loch\f1 P-11; nova for Nova; hp2100 for the HP 21XX; h316 for the Honeywell 315/516; gri for the GRI-909; pdp10 for the PDP-10; vax for the VAX; sds for the SDS-940): +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \ai\af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 name}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 .h contains definitions for the particular simulator +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \ai\af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 name}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 _sys.c contains all the SCP interfa\hich\af1\dbch\af31505\loch\f1 ces except the instruction simulator +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \ai\af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 name}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 _cpu.c contains the instruction simulator and CPU data structures +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \ai\af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 name}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 _stddev.c contains the peripherals which were standard with the real system. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \ai\af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 name}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 _lp.c contains the line printer. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \ai\af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls2\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 name}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 _mt.c contains the mag tape\hich\af1\dbch\af31505\loch\f1 controller and drives, etc. +\par }\pard \ltrpar\ql \fi1440\li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 The SIMH standard definitions are in sim_defs.h. The base components of SIMH are: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 Source module\tab \tab header file\tab \tab module +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 scp.c\tab \tab \tab scp.h\tab \tab \tab control package +\par \tab \hich\af1\dbch\af31505\loch\f1 sim_console.c\tab \tab sim_console.h\tab \tab terminal I/O library +\par \tab \hich\af1\dbch\af31505\loch\f1 sim_fio.c\tab \tab sim_fio.\hich\af1\dbch\af31505\loch\f1 h\tab \tab file I/O library +\par \tab \hich\af1\dbch\af31505\loch\f1 sim_timer.c\tab \tab sim_timer.h\tab \tab timer library +\par \tab \hich\af1\dbch\af31505\loch\f1 sim_sock.c\tab \tab sim_sock.h\tab \tab socket I/O library +\par \tab \hich\af1\dbch\af31505\loch\f1 sim_ether.c\tab \tab sim_ether.h\tab \tab Ethernet I/O library +\par \tab \hich\af1\dbch\af31505\loch\f1 sim_tmxr.c\tab \tab sim_tmxr.h\tab \tab terminal multiplexer simulation library +\par \tab \hich\af1\dbch\af31505\loch\f1 sim_tape.c\tab \tab sim_tape.h\tab \tab magtape simul\hich\af1\dbch\af31505\loch\f1 ation library +\par {\*\bkmkstart _Toc343577874}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.1\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 CPU Organization{\*\bkmkend _Toc343577874} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Most CPU\hich\f1 \rquote \loch\f1 s perform at least the following functions: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Time keeping +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Instruction fetching +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Address decoding +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Execution of non-I/O instructions +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 I/O command processing +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls3\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Interrupt processing +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Instruction execution is actually the le\hich\af1\dbch\af31505\loch\f1 ast complicated part of the design; memory and I/O organization should be tackled first. +\par {\*\bkmkstart _Toc343577875}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.1.1\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Time Base{\*\bkmkend _Toc343577875} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 In order to simulate asynchronous events, such as I/O completion, the VM must define and keep a time base. This can be accurate (for example, nanoseconds o\hich\af1\dbch\af31505\loch\f1 +f execution) or arbitrary (for example, number of instructions executed), but it must be used consistently throughout the VM. All existing VM\hich\f1 \rquote \loch\f1 s count time in instructions. +\par +\par \hich\af1\dbch\af31505\loch\f1 The CPU is responsible for counting down the event counter }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_interval}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 and callin\hich\af1\dbch\af31505\loch\f1 g the asynchronous event controller }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_process_event}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . SCP does the record keeping for timing. +\par {\*\bkmkstart _Toc343577876}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.1.2\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Step Function{\*\bkmkend _Toc343577876} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SCP implements a stepping function using the step command. STEP counts down a specified number of time units (as described in section 3.1.1) and\hich\af1\dbch\af31505\loch\f1 + then stops simulation. The VM can override the STEP command\hich\f1 \rquote \loch\f1 s counts by calling routine }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_cancel_step}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 : +\par +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault\faauto\ls25\adjustright\rin0\lin720\itap0 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat sim_cancel_step (void) \hich\f1 \endash \loch\f1 cancel STEP count down. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The VM can then inspect variable }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_step}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + to see if a STEP command is in progress. If }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_\hich\af1\dbch\af31505\loch\f1 step}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + is non-zero, it represents the number of steps to execute. The VM can count down }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_step}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 using its own counting method, such as cycles, instructions, or memory references. +\par {\*\bkmkstart _Toc343577877}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.1.3\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Memory Organization{\*\bkmkend _Toc343577877} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The criterion for memory layout is very simple: use the \hich\af1\dbch\af31505\loch\f1 +SIMH data type that is as large as (or if necessary, larger than), the word length of the real machine. Note that the criterion is word length, not addressability: the PDP-11 has byte addressable memory, but it is a 16-bit machine, and its memory is defi +\hich\af1\dbch\af31505\loch\f1 n\hich\af1\dbch\af31505\loch\f1 +ed as uint16 M[]. It may seem tempting to define memory as a union of int8 and int16 data types, but this would make the resulting VM endian-dependent. Instead, the VM should be based on the underlying word size of the real machine, and byte manipulatio +\hich\af1\dbch\af31505\loch\f1 n\hich\af1\dbch\af31505\loch\f1 should be done explicitly. Examples: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 Simulator\tab \tab memory size\tab \tab memory declaration +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 IBM 1620\tab \tab 5-bit\tab \tab \tab uint8 +\par \tab \hich\af1\dbch\af31505\loch\f1 IBM 1401\tab \tab 7-bit\tab \tab \tab uint8 +\par \tab \hich\af1\dbch\af31505\loch\f1 PDP-8\tab \tab \tab 12-bit\tab \tab \tab uint16 +\par \tab \hich\af1\dbch\af31505\loch\f1 PDP-11, Nova\tab \tab 16-bit\tab \tab \tab uint16 +\par \tab \hich\af1\dbch\af31505\loch\f1 PDP-1\tab \tab \tab 18-bit\tab \tab \tab uint32 +\par \tab \hich\af1\dbch\af31505\loch\f1 VAX\tab \tab \tab 32-bit\tab \tab \tab uint32 +\par \tab \hich\af1\dbch\af31505\loch\f1 PDP-10, IBM 7094\tab \hich\af1\dbch\af31505\loch\f1 36-bit\tab \tab \tab t_uint64 +\par {\*\bkmkstart _Toc343577878}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.1.4\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Interrupt Organization{\*\bkmkend _Toc343577878} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The design of the VM\hich\f1 \rquote \loch\f1 s interrupt structure is a complex interaction between efficiency and fidelity to the hardware. If the VM\hich\f1 \rquote \loch\f1 +s interrupt structure is too abstract, interrupt driven software may not run. On the\hich\af1\dbch\af31505\loch\f1 + other hand, if it follows the hardware too literally, it may significantly reduce simulation speed. One rule I can offer is to minimize the fetch-phase cost of interrupts, even if this complicates the (much less frequent) evaluation of the interrupt sys +\hich\af1\dbch\af31505\loch\f1 t\hich\af1\dbch\af31505\loch\f1 +em following an I/O operation or asynchronous event. Another is not to over-generalize; even if the real hardware could support 64 or 256 interrupting devices, the simulators will be running much smaller configurations. I\hich\f1 \rquote \loch\f1 +ll start with a simple interrup\hich\af1\dbch\af31505\loch\f1 t\hich\af1\dbch\af31505\loch\f1 structure and then offer suggestions for generalization. +\par +\par \hich\af1\dbch\af31505\loch\f1 In the simplest structure, interrupt requests correspond to device flags and are kept in an interrupt request variable, with one flag per bit. The fetch-phase evaluation of interrupts consists of +\hich\af1\dbch\af31505\loch\f1 two steps: are interrupts enabled, and is there an interrupt outstanding? If all the interrupt requests are kept as single-bit flags in a variable, the fetch-phase test is very fast: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 if (int_enable && int_requests) \{\hich\f1 \'85\loch\f1 \hich\f1 process interrupt\'85\loch\f1 \} +\par +\par \hich\af1\dbch\af31505\loch\f1 Indeed, the i\hich\af1\dbch\af31505\loch\f1 nterrupt enable flag can be made the highest bit in the interrupt request variable, and the two tests combined: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 if (int_requests > INT_ENABLE) \{\hich\f1 \'85\loch\f1 \hich\f1 process interrupt\'85\loch\f1 \} +\par +\par \hich\af1\dbch\af31505\loch\f1 Setting or clearing device flags directly sets or clears the appropriate interrupt req\hich\af1\dbch\af31505\loch\f1 uest flag: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 set: \tab int_requests = int_requests | DEVICE_FLAG; +\par \tab \hich\af1\dbch\af31505\loch\f1 clear:\tab int_requests = int_requests & ~DEVICE_FLAG; +\par +\par \hich\af1\dbch\af31505\loch\f1 At a slightly higher complexity, interrupt requests do not correspond directly to device flags but are based on masking the device flags with\hich\af1\dbch\af31505\loch\f1 + an enable (or disable) mask. There are now two parallel variables: device flags and interrupt enable mask. The fetch-phase test is now: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 If (int_enable && (dev_flags & int_enables)) \{\hich\f1 \'85\loch\f1 \hich\f1 process interrupt\'85\loch\f1 \} +\par +\par \hich\af1\dbch\af31505\loch\f1 As a next step, the VM may keep a summary int\hich\af1\dbch\af31505\loch\f1 errupt request variable, which is updated by any change to a device flag or interrupt enable/disable: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 enable:\tab int_requests = device_flags & int_enables; +\par \tab \hich\af1\dbch\af31505\loch\f1 disable:\tab int_requests = device_flags & ~int_disables; +\par +\par \hich\af1\dbch\af31505\loch\f1 This simplifies the fetch phase test slightly. +\par +\par \hich\af1\dbch\af31505\loch\f1 +At yet higher complexity, the interrupt system may be too complex or too large to evaluate during the fetch-phase. In this case, an interrupt pending flag is created, and it is evaluated by subroutine call whenever a change could occur (start of execut +\hich\af1\dbch\af31505\loch\f1 ion, I/O instruction issued, device time out occurs). This makes fetch-phase evaluation simple and isolates interrupt evaluation to a common subroutine. +\par +\par \hich\af1\dbch\af31505\loch\f1 If required for interrupt processing, the highest priority interrupting device can be determined by s\hich\af1\dbch\af31505\loch\f1 +canning the interrupt request variable from high priority to low until a set bit is found. The bit position can then be back-mapped through a table to determine the address or interrupt vector of the interrupting device. +\par {\*\bkmkstart _Toc343577879}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.1.5\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 I/O Dispatching{\*\bkmkend _Toc343577879} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 I/O dispatching c\hich\af1\dbch\af31505\loch\f1 onsists of four steps: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls14\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Identify the I/O command and analyze for the device address. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls14\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Locate the selected device. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls14\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Break down the I/O command into standard fields. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls14\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Call the device processor. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Analyzing an I/O command is usually easy. Most systems have one o\hich\af1\dbch\af31505\loch\f1 +r more explicit I/O instructions containing an I/O command and a device address. Memory mapped I/O is more complicated; the identification of a reference to I/O space becomes part of memory addressing. This usually requires centralizing memory reads and +\hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 writes into subroutines, rather than as inline code. +\par +\par \hich\af1\dbch\af31505\loch\f1 Once an I/O command has been analyzed, the CPU must locate the device subroutine. The simplest way is a large switch statement with hardwired subroutine calls. More modular is to call through a dispatc +\hich\af1\dbch\af31505\loch\f1 +h table, with NULL entries representing non-existent devices; this also simplifies support for modifiable device addresses and configurable devices. Before calling the device routine, the CPU usually breaks down the I/O command into standard fields. Thi +\hich\af1\dbch\af31505\loch\f1 s\hich\af1\dbch\af31505\loch\f1 simplifies writing the peripheral simulator. +\par {\*\bkmkstart _Toc343577880}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.1.6\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Instruction Execution{\*\bkmkend _Toc343577880} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Instruction execution is the responsibility of VM subroutine }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_instr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 . It is called from SCP as a result of a RUN, GO, CONT, or BOOT command. It begins executing instructions at the cu\hich\af1\dbch\af31505\loch\f1 rrent PC (}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_PC}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 points to its register description block) and continues until halted by an error or an external event. +\par +\par \hich\af1\dbch\af31505\loch\f1 When called, the CPU needs to account for any state changes that the user made. For example, it may need to re-evaluate whether an int\hich\af1\dbch\af31505\loch\f1 +errupt is pending, or restore frequently used state to local register variables for efficiency. The actual instruction fetch and execute cycle is usually structured as a loop controlled by an error variable, e.g., +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 reason = 0; +\par \tab \hich\af1\dbch\af31505\loch\f1 do \{\hich\f1 \'85\loch\f1 \} while (reason == \hich\af1\dbch\af31505\loch\f1 0);\tab or\tab while (reason == 0) \{\hich\f1 \'85\loch\f1 \} +\par +\par \hich\af1\dbch\af31505\loch\f1 Within this loop, the usual order of events is: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 If the event timer }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_interval}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 has reached zero, process any timed events. This is done by SCP subroutine }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_process_event}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Because this is the polling mechanism for use\hich\af1\dbch\af31505\loch\f1 +r-generated processor halts (^E), errors must be recognized immediately: +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li1440\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin1440\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 if (sim_interval <= 0) \{ +\par }\pard \ltrpar\ql \fi720\li1440\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin1440\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +if (reason = sim_process_event ()) break; \} +\par }\pard \ltrpar\ql \fi2160\li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Check for outstanding interrupts and process if required. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Check for other processor-unique events, such as wai +\hich\af1\dbch\af31505\loch\f1 t-state outstanding or traps outstanding. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +Check for an instruction breakpoint. SCP has a comprehensive breakpoint facility. It allows a VM to define many different kinds of breakpoints. The VM checks for execution (type E) breakpoints during instructio\hich\af1\dbch\af31505\loch\f1 n fetch. + +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls4\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +Fetch the next instruction, increment the PC, optionally decode the address, and dispatch (via a switch statement) for execution. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 A few guidelines for implementation: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls5\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls5\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +In general, code should reflect the hardware being simulated. This is usuall\hich\af1\dbch\af31505\loch\f1 y simplest and easiest to debug. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls5\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls5\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 The VM should provide some debugging aids. The existing CPU\hich\f1 +\rquote \loch\f1 s all provide multiple instruction breakpoints, a PC change queue, error stops on invalid instructions or operations, and symbolic examination and modification o\hich\af1\dbch\af31505\loch\f1 f memory. +\par {\*\bkmkstart _Toc343577881}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.2\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Peripheral Device Organization{\*\bkmkend _Toc343577881} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The basic elements of a VM are devices, each corresponding roughly to a real chunk of hardware. A device consists of register-based state and one or more units. Thus, a multi-drive disk subsystem is a single devi +\hich\af1\dbch\af31505\loch\f1 +ce (representing the hardware of the real controller) and one or more units (each representing a single disk drive). Sometimes the device and its unit are the same entity as, for example, in the case of a paper tape reader. However, a single physical de +\hich\af1\dbch\af31505\loch\f1 v\hich\af1\dbch\af31505\loch\f1 ice, such as the console, may be broken up for convenience into separate input and output devices. +\par +\par \hich\af1\dbch\af31505\loch\f1 In general, units correspond to individual sources of input or output (one tape transport, one A-to-D channel). Units are the basic medium for both device \hich\af1\dbch\af31505\loch\f1 +timing and device I/O. Except for the console, all I/O devices are simulated as host-resident files. SCP allows the user to make an explicit association between a host-resident file and a simulated hardware entity. +\par +\par \hich\af1\dbch\af31505\loch\f1 Both devices and units have state. De\hich\af1\dbch\af31505\loch\f1 vices operate on }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 registers}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , which contain information about the state of the device, and indirectly, about the state of the units. Units operate on }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 data sets}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , which may be thought of as individual instances of input or output, such as a disk pack or a pun\hich\af1\dbch\af31505\loch\f1 +ched paper tape. In a typical multi-unit device, all units are the same, and the device performs similar operations on all of them, depending on which one has been selected by the program being simulated. +\par +\par \hich\af1\dbch\af31505\loch\f1 (Note: SIMH, like MIMIC, restricts registers to d\hich\af1\dbch\af31505\loch\f1 evices. Replicated registers, for example, disk drive current state, are handled via register arrays.) +\par +\par \hich\af1\dbch\af31505\loch\f1 For each structural level, SIMH defines, and the VM must supply, a corresponding data structure. }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_device}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structures correspond to devices, }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_reg}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 s\hich\af1\dbch\af31505\loch\f1 tructures to registers, and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_unit}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 structures to units. These structures are described in detail in section 4. +\par +\par \hich\af1\dbch\af31505\loch\f1 The primary functions of a peripheral are: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls6\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 command decoding and execution +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls6\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 device timing +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls6\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 data transmission. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Command decoding is fairly obvio\hich\af1\dbch\af31505\loch\f1 +us. At least one section of the peripheral code module will be devoted to processing directives issued by the CPU. Typically, the command decoder will be responsible for register and flag manipulation, and for issuing or canceling I/O requests. The for +\hich\af1\dbch\af31505\loch\f1 m\hich\af1\dbch\af31505\loch\f1 er is easy, but the later requires a thorough understanding of device timing. +\par {\*\bkmkstart _Toc343577882}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.2.1\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Device Timing{\*\bkmkend _Toc343577882} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The principal problem in I/O device simulation is imitating asynchronous operations in a sequential simulation environment. Fortunately, the timing characteristic\hich\af1\dbch\af31505\loch\f1 +s of most I/O devices do not vary with external circumstances. The distinction between devices whose timing is externally generated (e.g., console keyboard) and those whose timing is }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid1049593 +\hich\af1\dbch\af31505\loch\f1 internally}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 generated (disk, paper tape reader) is crucial. With an exte\hich\af1\dbch\af31505\loch\f1 +rnally timed device, there is no way to know when an in-progress operation will begin or end; with an internally timed device, given the time when an operation starts, the end time can be calculated. +\par +\par \hich\af1\dbch\af31505\loch\f1 For an internally timed device, the elapsed time betwee\hich\af1\dbch\af31505\loch\f1 n the start and conclusion of an operation is called the wait time. Some typical internally timed devices and their wait times include: + +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 PTR (300 char/sec)\tab \tab 3.3 msec +\par \tab \hich\af1\dbch\af31505\loch\f1 PTP (50 char/sec)\tab \tab 20 msec +\par \tab \hich\af1\dbch\af31505\loch\f1 CLK (line frequency)\tab \tab 16.6 msec +\par \tab \hich\af1\dbch\af31505\loch\f1 TTO (30 char/sec)\tab \tab 33 msec +\par +\par \hich\af1\dbch\af31505\loch\f1 Mass storage devices, such as disks and tapes, do not have a fixed response time, but a start-to-finish time can be calculated based on current versus desired position, state of motion, etc. +\par +\par \hich\af1\dbch\af31505\loch\f1 For an externally timed device, there is no portable mechanism\hich\af1\dbch\af31505\loch\f1 by which a VM can be notified of an external event (for example, a key stroke). Accordingly, all current VM\hich\f1 \rquote +\loch\f1 s poll for keyboard input, thus converting the externally timed keyboard to a pseudo-internally timed device. A more general restriction is that\hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 +SIMH is single-threaded. Threaded operations must be done by polling using the unit timing mechanism, either with real units or fake units created expressly for polling. +\par +\par \hich\af1\dbch\af31505\loch\f1 SCP provides the supporting routines for device timing. SCP maintains a list of dev\hich\af1\dbch\af31505\loch\f1 +ices (called active devices) that are in the process of timing out. It also provides routines for querying or manipulating this list (called the active queue). Lastly, it provides a routine for checking for timed-out units and executing a VM-specified a +\hich\af1\dbch\af31505\loch\f1 c\hich\af1\dbch\af31505\loch\f1 tion when a time-out occurs. +\par +\par \hich\af1\dbch\af31505\loch\f1 +Device timing is done with the UNIT structure, described in section 4. To set up a timed operation, the peripheral calculates a waiting period for a unit and places that unit on the active queue. The CPU counts down the wait +\hich\af1\dbch\af31505\loch\f1 ing period. When the waiting period has expired, }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_process_event}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 removes the unit from the active queue and calls a device subroutine. A device may also cancel an outstanding timed operation and query the state of the queue. The timing subroutines are\hich\af1\dbch\af31505\loch\f1 : + +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_activate}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr, int32 wait). This routine places the specified unit on the active queue with the specified waiting period. A waiting period of 0 is legal; negative waits cause an error. If the unit is already active, the active queue +\hich\af1\dbch\af31505\loch\f1 is not changed, and no error occurs. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_cancel}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr). This routine removes the specified unit from the active queue. If the unit is not on the queue, no error occurs. + +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_is_active}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr). This routine tests whether a unit \hich\af1\dbch\af31505\loch\f1 +is in the active queue. If it is, the routine returns }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid10051909 \hich\af1\dbch\af31505\loch\f1 TRUE(1)}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +; if it is not, the routine returns }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid10051909 \hich\af1\dbch\af31505\loch\f1 FALSE(}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 0}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid10051909 +\hich\af1\dbch\af31505\loch\f1 )}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0\pararsid13897431 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid10051909 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid10051909 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0\pararsid13897431 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid10051909 \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid10051909 \hich\af1\dbch\af31505\loch\f1 sim_activate_time}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid10051909 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr). This routine returns the time the device has remaining in the queue + 1. if it is not pending, the routine \hich\af1\dbch\af31505\loch\f1 returns 0.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid10051909\charrsid10051909 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 double }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_gtime}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (void). This routine returns the time elapsed since the last RUN or BOOT command. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uint32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_grtime}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (void). This routine returns the low-order 32b of the time elapsed since the last RUN or BOOT command. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_qcount}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (vo\hich\af1\dbch\af31505\loch\f1 id). This routine returns the number of entries on the clock queue. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_process_event}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (void). This routine removes all timed out units from the active queue and calls the appropriate device subroutine to service the time-out. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls7\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_interval}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 .\hich\af1\dbch\af31505\loch\f1 \hich\f1 + This variable counts down the first outstanding timed event. If there are no timed events outstanding, SCP counts down a \'93\loch\f1 \hich\f1 null interval\'94\loch\f1 of 10,000 time units. +\par {\*\bkmkstart _Toc343577883}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.2.2\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Clock Calibration{\*\bkmkend _Toc343577883} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The timing mechanism described in the previous section is approximate. Dev\hich\af1\dbch\af31505\loch\f1 +ices, such as real-time clocks, which track wall time will be inaccurate. SCP provides routines to synchronize multiple simulated clocks (to a maximum of 8) to wall time. +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls15\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls15\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_rtcn_init}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (int32 clock_interval, int32 clk). This routine initializes th\hich\af1\dbch\af31505\loch\f1 +e clock calibration mechanism for simulated clock }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 clk}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +. The argument is returned as the result. +\par }\pard \ltrpar\ql \li360\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin360\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls15\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls15\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_rtcn_calb}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (int32 tickspersecond, int32 clk). This routine calibrates simulated clock }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 clk}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . The argument is the number of clock ticks expected per se\hich\af1\dbch\af31505\loch\f1 cond. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The VM must call }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_rtcn_init}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + for each simulated clock in two places: in the prolog of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_instr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +, before instruction execution starts, and whenever the real-time clock is started. The simulator calls }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_rtcn_calb}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 to calculate the actual interval \hich\af1\dbch\af31505\loch\f1 delay when the real-time clock is serviced: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 /* clock start */ +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 if (!sim_is_active (&clk_unit)) sim_activate (&clk_unit, sim_rtcn_init (clk_delay, clkno)); +\par \tab \hich\af1\dbch\af31505\loch\f1 etc. +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 /* clock service */ +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 sim_activate (&clk_unit, sim_rtcb_calb (clk_ticks_per_second, clkno)\hich\af1\dbch\af31505\loch\f1 ; +\par +\par \hich\af1\dbch\af31505\loch\f1 The real-time clock is usually simulated clock 0; other clocks are used for polling asynchronous multiplexers or intervals timers. +\par {\*\bkmkstart _Toc343577884}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.2.3\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Idling{\*\bkmkend _Toc343577884} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 If a VM implements a free-running, calibrated clock of 100Hz or less, then the VM can also implement idling. Idli\hich\af1\dbch\af31505\loch\f1 +ng is a way of pausing simulation when no real work is happening, without losing clock calibration. The VM must detect when it is idle; it can then inform the host of this situation by calling }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_idle}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 : +\par +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault\faauto\ls26\adjustright\rin0\lin720\itap0 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_bool }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_idle}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 (int32 clk, t_bool one_tick) \hich\f1 \endash \loch\f1 atte\hich\af1\dbch\af31505\loch\f1 mpt to idle the VM until the next scheduled I/O event, using simulated clock }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 clk}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 as the time base, and decrement }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_interval}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 by an appropriate number of cycles. If a calibrated timer is not available, or the time until the next event is less than 1ms, de\hich\af1\dbch\af31505\loch\f1 crement }{ +\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_interval}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 by 1 if }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 one_tick}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is TRUE; otherwise, leave sim_interval unchanged. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_idle}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 returns TRUE if the VM actually idled, FALSE if it did not. +\par +\par \hich\af1\dbch\af31505\loch\f1 Because idling and throttling are mutually exclusive, the VM must inform SCP when idling is turne\hich\af1\dbch\af31505\loch\f1 d on or off: +\par +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault\faauto\ls26\adjustright\rin0\lin720\itap0 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_set_idle}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int32 val, char *cptr, void *desc) \hich\f1 \endash \loch\f1 informs SCP that idling is enabled. +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}\hich\af1\dbch\af31505\loch\f1 t_stat}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + sim_clr_idle}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int32 val, char *cptr, void *desc) \hich\f1 \endash \loch\f1 informs SCP that idling is disabled. +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}\hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +sim_show_idle}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (FILE *s\hich\af1\dbch\af31505\loch\f1 t, UNIT *uptr, int32 val, void *desc) \hich\f1 \endash \loch\f1 + displays whether idling is enabled or disabled, as seen by SCP. +\par {\*\bkmkstart _Toc343577885}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.2.4\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Data I/O{\*\bkmkend _Toc343577885} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 For most devices, timing is half the battle (for clocks it is the entire war); the other half is I/O. Some devices are simulated on real hard\hich\af1\dbch\af31505\loch\f1 +ware (for example, Ethernet controllers). Most I/O devices are simulated as files on the host file system in little-endian format. SCP provides facilities for associating files with units (ATTACH command) and for reading and writing data from and to dev +\hich\af1\dbch\af31505\loch\f1 i\hich\af1\dbch\af31505\loch\f1 ces in a endian- and size-independent way. +\par +\par \hich\af1\dbch\af31505\loch\f1 For most devices, the VM designer does not have to be concerned about the formatting of simulated device files. I/O occurs in 1, 2, 4, or 8 byte quantities; SCP automatically chooses the correct data size and co +\hich\af1\dbch\af31505\loch\f1 rrects for byte ordering. Specific issues: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls8\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +Line printers should write data as 7-bit ASCII, with newlines replacing carriage-return/line-feed sequences. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls8\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +Disks should be viewed as linear data sets, from sector 0 of surface 0 of cylinder 0 to the last sect\hich\af1\dbch\af31505\loch\f1 or on the disk. This allows easy transcription of real disks to files usable by the simulator. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls8\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +Magtapes, by convention, use a record based format. Each record consists of a leading 32-bit record length, the record data (padded with a byte of 0 if the re\hich\af1\dbch\af31505\loch\f1 +cord length is odd), and a trailing 32-bit record length. File marks are recorded as one record length of 0. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls8\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +Cards have 12 bits of data per column, but the data is most conveniently viewed as (ASCII) characters. Column binary can be implemented using tw\hich\af1\dbch\af31505\loch\f1 o successive characters per card column.. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Data I/O varies between fixed and variable capacity devices, and between buffered and non-buffered devices. A fixed capacity device differs from a variable capacity device in that the file attached to the former +\hich\af1\dbch\af31505\loch\f1 +has a maximum size, while the file attached to the latter may expand indefinitely. A buffered device differs from a non-buffered device in that the former buffers its data set in host memory, while the latter maintains it as a file. Most variable capaci +\hich\af1\dbch\af31505\loch\f1 t\hich\af1\dbch\af31505\loch\f1 y devices (such as the paper tape reader and punch) are sequential; all buffered devices are fixed capacity. +\par +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.2.4.1\tab}}\pard \ltrpar\ql \fi-1080\li1080\ri0\widctlpar +\jclisttab\tx1080\wrapdefault\faauto\ls1\ilvl3\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Reading and Writing Data +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The ATTACH command creates an association between a host file and an I/O unit. For non-buffered devices, ATTACH stores \hich\af1\dbch\af31505\loch\f1 the file pointer for the host file in the }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fileref}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + field of the UNIT structure. For buffered devices, ATTACH reads the entire host file into a buffer pointed to by the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 filebuf }{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 field of the UNIT structure. If unit flag UNIT_MUSTBUF is set, the buffer is al\hich\af1\dbch\af31505\loch\f1 located dynamically; otherwise, it must be statically allocated. +\par +\par \hich\af1\dbch\af31505\loch\f1 For non-buffered devices, I/O is done with standard C subroutines plus the SCP routines }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_fread}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_fwrite}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . }{\rtlch\fcs1 +\ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_fread}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +sim_fwrite}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 are identical in calling sequence and function to \hich\af1\dbch\af31505\loch\f1 +fread and fwrite, respectively, but will correct for endian dependencies. For buffered devices, I/O is done by copying data to or from the allocated buffer. The device code must maintain the number (+1) of the highest address modified in the }{ +\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 hwmark}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 field\hich\af1\dbch\af31505\loch\f1 + of the UNIT structure. For both the non-buffered and buffered cases, the device must perform all address calculations and positioning operations. +\par +\par \hich\af1\dbch\af31505\loch\f1 SIMH provides capabilities to access files >2GB (the int32 position limit). If a VM is compiled with flags\hich\af1\dbch\af31505\loch\f1 + USE_INT64 and USE_ADDR64 defined, then t_addr is defined as t_uint64 rather than uint32. Routine sim_fseek allows simulated devices to perform random access in large files: +\par +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault\faauto\ls24\adjustright\rin0\lin720\itap0 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 int }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_fseek}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 (FILE *handle, t_addr position, int where) +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 sim_fseek is identical\hich\af1\dbch\af31505\loch\f1 to standard C }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fseek}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 , with two exceptions: where = SEEK_END is not supported, and the position argument can be 64b wide. +\par +\par \hich\af1\dbch\af31505\loch\f1 The DETACH command breaks the association between a host file and an I/O unit. For buffered devices, DETACH writes the allocated buff\hich\af1\dbch\af31505\loch\f1 er back to the host file. +\par +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.2.4.2\tab}}\pard \ltrpar\ql \fi-1080\li1080\ri0\widctlpar +\jclisttab\tx1080\wrapdefault\faauto\ls1\ilvl3\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Console I/O +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 SCP provides three routines for console I/O. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls10\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_poll_char }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +(void). This routine polls for keyboard input. If there is a character, it returns SCPE_KFLAG + the character. If the user typed the interrupt cha\hich\af1\dbch\af31505\loch\f1 +racter (^E), it returns SCPE_STOP. If the console is attached to a Telnet connection, and the connection is lost, the routine returns SCPE_LOST. If there is no input, it returns SCPE_OK. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls10\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_putchar}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (int32 char). This routine types the specified\hich\af1\dbch\af31505\loch\f1 + ASCII character to the console. If the console is attached to a Telnet connection, and the connection is lost, the routine returns SCPE_LOST. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0 +\pnf3\pnstart1\pnindent360\pnsp120\pnhang {\pntxtb \'b7}}\faauto\ls10\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_putchar_s}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (int32 char). This routine outputs the specified ASCII character to the console. If the \hich\af1\dbch\af31505\loch\f1 +console is attached to a Telnet connection, and the connection is lost, the routine returns SCPE_LOST; if the connection is backlogged, the routine returns SCPE_STALL. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\*\bkmkstart _Toc343577886}{\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af0\afs28 \ltrch\fcs0 \b\f1\fs28\kerning28\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.\tab}}\pard\plain \ltrpar\s1\ql \fi-360\li360\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx360\wrapdefault\faauto\ls1\outlinelevel0\adjustright\rin0\lin360\itap0 \rtlch\fcs1 \ab\af1\afs28\alang1025 \ltrch\fcs0 \b\fs28\lang1033\langfe1033\kerning28\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Data Structures{\*\bkmkend _Toc343577886} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The devices, units, and registers that make up a VM are formally descr\hich\af1\dbch\af31505\loch\f1 +ibed through a set of data structures which interface the VM to the control portions of SCP. The devices themselves are pointed to by the device list array }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +sim_devices[]}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Within a device, both units and registers are allocated contiguously as arrays of s\hich\af1\dbch\af31505\loch\f1 +tructures. In addition, many devices allow the user to set or clear options via a modifications table. +\par +\par \hich\af1\dbch\af31505\loch\f1 Note that a device must always have at least one unit, even if that unit is not needed for simulation purposes. A device must always point to a valid \hich\af1\dbch\af31505\loch\f1 \hich\f1 +register table, but the register table can consist of just the \'93\loch\f1 \hich\f1 end of table\'94\loch\f1 entry. +\par {\*\bkmkstart _Toc343577887}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_device Structure{\*\bkmkend _Toc343577887} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Devices are defined by the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_device}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structure (typedef +}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 DEVICE}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ): +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 struct sim_device \{ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab *name;\tab \tab \tab \tab /* name */ +\par \tab \hich\af1\dbch\af31505\loch\f1 struct sim_unit \tab *units;\tab \tab \tab \tab /* un\hich\af1\dbch\af31505\loch\f1 its */ +\par \tab \hich\af1\dbch\af31505\loch\f1 struct sim_reg\tab *registers;\tab \tab \tab /* registers */ +\par \tab \hich\af1\dbch\af31505\loch\f1 struct sim_mtab\tab *modifiers;\tab \tab \tab /* modifiers */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab numunits;\tab \tab \tab /* #units */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab aradix;\tab \tab \tab \tab /* address radix */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab awidth;\tab \tab \tab \tab /* address width */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab aincr;\tab \tab \tab \tab /* addr increment */ +\par \tab \hich\af1\dbch\af31505\loch\f1 ui\hich\af1\dbch\af31505\loch\f1 nt32\tab \tab dradix;\tab \tab \tab \tab /* data radix */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab dwidth;\tab \tab \tab \tab /* data width */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*examine)();\tab \tab \tab /* examine routine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*deposit)();\tab \tab \tab /* deposit routine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*reset)();\tab \tab \tab /* reset routine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*boot)();\tab \tab \tab /* boot routine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab \hich\af1\dbch\af31505\loch\f1 (*attach)();\tab \tab \tab /* attach routine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*detach)();\tab \tab \tab /* detach routine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 void\tab \tab *ctxt}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 /}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 * context */ + +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab flags;\tab \tab \tab \tab /* flags */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab dctrl;\tab \tab \tab \tab /* debug control flags */ +\par \tab \hich\af1\dbch\af31505\loch\f1 struct sim_debtab debflags;}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 /}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +* debug flag names */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*ms\hich\af1\dbch\af31505\loch\f1 ize)();\tab \tab \tab /* memory size change */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab *lname;}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 /*}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + logical name */ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \}\hich\af1\dbch\af31505\loch\f1 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The fields are the following: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 name}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab +\hich\af1\dbch\af31505\loch\f1 device name, string of all capital alphanumeric characters. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 units}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 pointer to array of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_unit}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structures, or NULL if none. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 registers}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 pointer \hich\af1\dbch\af31505\loch\f1 to array of }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_reg}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structures, or NULL if none. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 modifiers}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 pointer to array of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_mtab}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structures, or NULL if none. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 numunits}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \tab number of units in this device. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aradix}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 radix for input and display of device addresses, 2 to 16 inclusive. + +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 awidth}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 width in bits\hich\af1\dbch\af31505\loch\f1 + of a device address, 1 to 64 inclusive. +\par }\pard \ltrpar\ql \fi-1440\li2160\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin2160\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab +\hich\af1\dbch\af31505\loch\f1 increment between device addresses, normally 1; however, byte addressed devices with 16-bit words specify 2, with 32-bit words 4. +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 dradix}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab +\hich\af1\dbch\af31505\loch\f1 radix for input and display of device data, 2 to 16 inclusive. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 dwidth}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 width in bits of device data, 1 to 64 inclusive. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 examine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 address of special device data read routine, or NULL if none is required. + +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 deposit}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 +address of special device data write routine, or NULL if none is required. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 reset}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 address of device reset routine, o\hich\af1\dbch\af31505\loch\f1 +r NULL if none is required. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 boot}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 address of device bootstrap routine, or NULL if none is required. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 attach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 address of special device attach routine, or NULL if none is required. + +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 detach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 address of special device detach routine, or NULL if none is required. + +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ctxt}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 address of VM-specific device context table, or NULL if none is required. + +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flags}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 device flags. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 dctrl\tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 debug control flags. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 debflags\tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pointer to array of sim_debtab structures, or NULL if none. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 msize}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 address of memory size change routine, or NULL if +\hich\af1\dbch\af31505\loch\f1 none is required. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lname\tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pointer to logical name string. +\par {\*\bkmkstart _Toc343577888}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1.1\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Awidth and Aincr{\*\bkmkend _Toc343577888} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 +\insrsid4550150 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 The }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 awidth}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 field specifies the width of the VM\hich\f1 \rquote \loch\f1 \hich\f1 s fundamental computer \'93\loch\f1 \hich\f1 word\'94\loch\f1 . For example, on the PDP-11, }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 awidth}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is 16b, even though memory is byte-addressable. The }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 field s\hich\af1\dbch\af31505\loch\f1 \hich\f1 pecifies how many addressing units comprise the fundamental \'93\loch\f1 \hich\f1 word\'94 +\loch\f1 . For example, on the PDP-11, }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is 2 (2 bytes per word). +\par +\par \hich\af1\dbch\af31505\loch\f1 If }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + is greater than 1, SCP assumes that data is naturally aligned on addresses that are multiples of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 . VM\hich\f1 \rquote \loch\f1 s that sup\hich\af1\dbch\af31505\loch\f1 port arbitrary byte alignment of data (like the VAX) can follow one of two strategies: +\par +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault\faauto\ls24\adjustright\rin0\lin720\itap0 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Set }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 awidth}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 = 8 and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + = 1 and support only byte access in the examine/deposit routines. +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}\hich\af1\dbch\af31505\loch\f1 Set }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 awidth +}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 to the fundamental sizes and support unaligned data acce\hich\af1\dbch\af31505\loch\f1 ss in the examine/deposit routines. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 In a byte-addressable VM, SAVE and RESTORE will require (memory_size_bytes / }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 ) iterations to save or restore memory. Thus, it is significantly more efficient to use word-wide rather than byte-wide memory; but requ\hich\af1\dbch\af31505\loch\f1 +irements for unaligned access can add significantly to the complexity of the examine and deposit routines. +\par {\*\bkmkstart _Toc343577889}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1.2\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Device Flags{\*\bkmkend _Toc343577889} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flags }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +field contains indicators of current device status. SIMH defines 2 flags: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flag name\tab \tab meaning if set +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \tab \hich\af1\dbch\af31505\loch\f1 DEV_DISABLE\tab \tab device c\hich\af1\dbch\af31505\loch\f1 an be set enabled or disabled +\par \tab \hich\af1\dbch\af31505\loch\f1 DEV_DIS\tab \tab device is currently disabled +\par \tab \hich\af1\dbch\af31505\loch\f1 DEV_DYNM\tab \tab device requires call on }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 msize}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + routine to change memory size +\par \tab \hich\af1\dbch\af31505\loch\f1 DEV_NET\tab \tab device attaches to the network rather than a file +\par \tab \hich\af1\dbch\af31505\loch\f1 DEV_DEBUG\tab \tab device supports SET DEBUG command +\par \tab \hich\af1\dbch\af31505\loch\f1 DEV_RAW\tab \tab \hich\af1\dbch\af31505\loch\f1 device supports raw I/O +\par \tab \hich\af1\dbch\af31505\loch\f1 DEV_RAWONLY\tab device supports only raw I/O +\par +\par \hich\af1\dbch\af31505\loch\f1 Starting at bit position DEV_V_UF, the remaining flags are device-specific. Device flags are automatically saved and restored; the device need not supply a register for these bits. +\par {\*\bkmkstart _Toc343577890}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1.3\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Context{\*\bkmkend _Toc343577890} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The field contains a pointer to a VM-specific device context table, if required. SIMH never accesses this field. The context field allows VM-specific code to walk VM-specific data structures from the }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_devices }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 root pointer. +\par {\*\bkmkstart _Toc343577891}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1.4\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Examine and Deposit Routin\hich\af1\dbch\af31505\loch\f1 es{\*\bkmkend _Toc343577891} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 +For devices which maintain their data sets as host files, SCP implements the examine and deposit data functions. However, devices which maintain their data sets as private state (for example, the CPU) must supply special examine and deposit routines. +\hich\af1\dbch\af31505\loch\f1 The calling sequences are: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 examine_routine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (t_val *eval_array, t_addr addr, UNIT *uptr, int32 switches) \hich\f1 \endash \loch\f1 Copy }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_emax}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 consecutive addresses for unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , starting at }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , into }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 eval_array}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . The }{\rtlch\fcs1 +\ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 switch}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 variable has bit set if the n\hich\f1 \rquote \loch\f1 th letter +\hich\af1\dbch\af31505\loch\f1 was specified as a switch to the examine command. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 deposit_routine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (t_val value, t_addr addr, UNIT *uptr, int32 switches) \hich\f1 \endash \loch\f1 Store the specified }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 value}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 in the specified }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 for unit }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . The }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 switch}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 variable is the same as for the examine routine. +\par {\*\bkmkstart _Toc343577892}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1.5\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 R\hich\af1\dbch\af31505\loch\f1 eset Routine{\*\bkmkend _Toc343577892} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The reset routine implements the device reset function for the RESET, RUN, and BOOT commands. Its calling sequence is: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 reset_routine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (DEVICE *dptr) \hich\f1 +\endash \loch\f1 Reset the specified device to its initial state. +\par +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 A typical reset routine clears a\hich\af1\dbch\af31505\loch\f1 +ll device flags and cancels any outstanding timing operations. Switch \hich\f1 \endash \loch\f1 p specifies a reset to power-up state. +\par {\*\bkmkstart _Toc343577893}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1.6\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Boot Routine{\*\bkmkend _Toc343577893} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 If a device responds to a BOOT command, the boot routine implements the bootstrapping function. Its calling sequence is: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 b\hich\af1\dbch\af31505\loch\f1 oot_routine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (int32 unit_num, DEVICE *dptr) \hich\f1 \endash \loch\f1 Bootstrap unit }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 unit_num}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 on the device }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +dptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 A typical bootstrap routine copies a bootstrap loader into main memory and sets the PC to the starting address of the loader. SCP then starts simulation at the spec\hich\af1\dbch\af31505\loch\f1 ified address. +\par {\*\bkmkstart _Toc343577894}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1.7\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Attach and Detach Routines{\*\bkmkend _Toc343577894} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Normally, the ATTACH and DETACH commands are handled by SCP. However, devices which need to pre- or post-process these commands must supply special attach and detach routines. The calling sequences are: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 attach_routine }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, char *file) \hich\f1 \endash \loch\f1 Attach the specified }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 file}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to the unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 . +\par \hich\af1\dbch\af31505\loch\f1 Sim_switches contains the command switch; bit SIM_SW_REST indicates that attach is being called by the RESTORE command rather than the ATTACH command. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 detach_rout\hich\af1\dbch\af31505\loch\f1 ine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr) \hich\f1 \endash \loch\f1 Detach unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 In practice, these routines usually invoke the standard SCP routines, }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 attach_unit}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 detach_unit}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +, respectively. For example, here are special attach and detach routines to update line printer error state: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 t_stat lpt\hich\af2\dbch\af31505\loch\f2 _attach (UNIT *uptr, char *cptr) \{ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 t_stat r; +\par \hich\af2\dbch\af31505\loch\f2 if ((r = attach_unit (uptr, cptr)) != SCPE_OK) return r; +\par \hich\af2\dbch\af31505\loch\f2 lpt_error = 0; +\par \hich\af2\dbch\af31505\loch\f2 return SCPE_OK; +\par \} +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 +\par \hich\af2\dbch\af31505\loch\f2 t_stat lpt_detach (UNIT *uptr) \{ +\par \tab \hich\af2\dbch\af31505\loch\f2 lpt_error = 1; +\par \tab \hich\af2\dbch\af31505\loch\f2 return detach_unit (uptr); +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \} +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 If the VM specifies an ATTACH or DETACH \hich\af1\dbch\af31505\loch\f1 +routine, SCP bypasses its normal tests before calling the VM routine. Thus, a VM DETACH routine cannot be assured that the unit is actually attached and must test the unit flags if required. +\par +\par \hich\af1\dbch\af31505\loch\f1 SCP executes a DETACH ALL command as part of simulator exit. N\hich\af1\dbch\af31505\loch\f1 ormally, DETACH ALL only calls a unit\hich\f1 \rquote \loch\f1 s detach routine if the unit\hich\f1 \rquote \loch\f1 +s UNIT_ATT flag is set. During simulator exit, the detach routine is also called if the unit is not flagged as attachable (UNIT_ATTABLE is not set). This allows the detach routine of a n\hich\af1\dbch\af31505\loch\f1 o\hich\af1\dbch\af31505\loch\f1 +n-attachable unit to function as a simulator-specific cleanup routine for the unit, device, or entire simulator. +\par {\*\bkmkstart _Toc343577895}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1.8\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Memory Size Change Routine{\*\bkmkend _Toc343577895} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Most units instantiate any memory array at the maximum size possible. This allows apparent memory size to be chang\hich\af1\dbch\af31505\loch\f1 ed by varying the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 capac}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + field in the unit structure. For some devices (like the VAX CPU), instantiating the maximum memory size would impose a significant resource burden if less memory was actually needed. These devices must provide a routine, the memor +\hich\af1\dbch\af31505\loch\f1 y size change routine, for RESTORE to use if memory size must be changed: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 change_mem_size}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int32 val, char *cptr, void *desc) \hich\f1 \endash \loch\f1 Change the capacity (memory size) of unit }{ +\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 val}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . The }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + arguments are included for compati\hich\af1\dbch\af31505\loch\f1 bility with the SET command\hich\f1 \rquote \loch\f1 s validation routine calling sequence. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par {\*\bkmkstart _Toc343577896}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.1.9\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Debug Controls{\*\bkmkend _Toc343577896} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Devices can support debug printouts. Debug printouts are controlled by the SET \{NO\}DEBUG command, which specifies where debug output should be printed; and by the SET \{NO\} +DEBUG command, which enables or disables individual debug printouts. +\par +\par \hich\af1\dbch\af31505\loch\f1 If a device supports debug printouts, device flag DEV_DEBUG must be set. Field }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 dctrl}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 is used for the debug control flags. If a device supports only a single debug on/off flag,\hich\af1\dbch\af31505\loch\f1 then the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +debflags}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 field should be set to NULL. If a device supports multiple debug on/off flags, then the correspondence between bit positions in }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 dctrl}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and debug flag names is specified by table }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 debflags}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 debflags}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 points to a continguous array of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_d\hich\af1\dbch\af31505\loch\f1 ebtab}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structures (typedef }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 DEBTAB}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +). Each sim_debtab structure specifies a single debug flag: +\par +\par \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid16013944 \hich\af1\dbch\af31505\loch\f1 s}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 truct sim_debtab \{ +\par \tab \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab name}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ;\tab \tab \tab \tab /}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +* flag name */ +\par \tab \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab mask;\tab \tab \tab \tab /* control bit */ +\par \tab \tab \}\hich\af1\dbch\af31505\loch\f1 ; +\par +\par \hich\af1\dbch\af31505\loch\f1 The fields are the following: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 name\tab \tab name of the debug flag. +\par \tab \hich\af1\dbch\af31505\loch\f1 ma\hich\af1\dbch\af31505\loch\f1 sk\tab \tab bit mask of the debug flag. +\par +\par \hich\af1\dbch\af31505\loch\f1 The array is terminated with a NULL entry. +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8129972 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\rin0\lin0\itap0\pararsid8129972 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8129972 \hich\af1\dbch\af31505\loch\f1 Simulator code can produce debug output by calling }{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid8084824 \hich\af1\dbch\af31505\loch\f1 sim_debug }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8129972 \hich\af1\dbch\af31505\loch\f1 which is declared: +\par +\par }\pard \ltrpar\ql \fi720\li0\ri0\widctlpar\wrapdefault\faauto\rin0\lin0\itap0\pararsid16013944 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf2\lang1024\langfe1024\noproof\insrsid8129972 \hich\af2\dbch\af31505\loch\f2 void}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\lang1024\langfe1024\noproof\insrsid8129972 \hich\af2\dbch\af31505\loch\f2 _}{\rtlch\fcs1 \af2 \ltrch\fcs0 \b\f2\lang1024\langfe1024\noproof\insrsid8129972\charrsid16013944 \hich\af2\dbch\af31505\loch\f2 sim_debug}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\lang1024\langfe1024\noproof\insrsid8129972 \hich\af2\dbch\af31505\loch\f2 (uint32 dbits, DEVICE* dptr, }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf2\lang1024\langfe1024\noproof\insrsid8129972 \hich\af2\dbch\af31505\loch\f2 const}{\rtlch\fcs1 \af2 +\ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8129972 \hich\af2\dbch\af31505\loch\f2 }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf2\lang1024\langfe1024\noproof\insrsid8129972 \hich\af2\dbch\af31505\loch\f2 char}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\lang1024\langfe1024\noproof\insrsid8129972 \hich\af2\dbch\af31505\loch\f2 * fmt, ...); +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\rin0\lin0\itap0\pararsid8129972 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8129972 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\lang1024\langfe1024\noproof\insrsid8129972\charrsid16013944 \hich\af1\dbch\af31505\loch\f1 The dbits is a flag which mat\hich\af1\dbch\af31505\loch\f1 ches a mask in a sim_debtab structure, and the }{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\lang1024\langfe1024\noproof\insrsid8352301\charrsid16013944 \hich\af1\dbch\af31505\loch\f1 the dptr is the DEVICE which has the corresponding dctl field.}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\lang1024\langfe1024\noproof\insrsid8129972\charrsid16013944 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\lang1024\langfe1024\noproof\insrsid8352301\charrsid16013944 +\par \hich\af1\dbch\af31505\loch\f1 Additionally support exists for displaying bit and bitfield values. Bit field values are defined using the BITFIELD}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\lang1024\langfe1024\noproof\insrsid8084824\charrsid16013944 +\hich\af1\dbch\af31505\loch\f1 structure and the BIT macros\hich\af1\dbch\af31505\loch\f1 to declare the bits and bitfields.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\lang1024\langfe1024\noproof\insrsid8352301\charrsid16013944 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8352301 +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\rin0\lin720\itap0\pararsid16013944 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 BIT(nm) }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\lang1024\langfe1024\noproof\insrsid8084824 \tab \tab \tab }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 - Single Bit definition}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf11\lang1024\langfe1024\noproof\insrsid8352301 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 BITNC }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8084824 \tab \tab \tab }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf11\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 - Don't care Bit definition}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8352301 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 BITF(nm,sz) }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8084824 \tab \tab }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf11\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 - Bit Field definition}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8352301 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 BITNCF(sz)}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8084824 \tab \tab \tab }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf11\lang1024\langfe1024\noproof\insrsid8084824 -}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 Do}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8084824 +\hich\af2\dbch\af31505\loch\f2 n't care Bit Field definition}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8352301 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 BITFFMT(nm,sz,fmt)}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 \tab }{ +\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8084824 -}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 Bit Field }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf11\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 definition with Output format}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8352301 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 BITFNAM(nm,sz,names)}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8084824 \tab }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf11\lang1024\langfe1024\noproof\insrsid8084824 -}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 Bit Field definition with va}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf11\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 lue->name map}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid8352301 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8352301 \hich\af2\dbch\af31505\loch\f2 ENDBITS +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\rin0\lin0\itap0\pararsid16013944 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\lang1024\langfe1024\noproof\insrsid16013944\charrsid16013944 \hich\af1\dbch\af31505\loch\f1 For example: +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\rin0\lin720\itap0\pararsid16013944 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 static}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 }{\rtlch\fcs1 \af2 +\ltrch\fcs0 \f2\cf2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 const}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 char}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 *rp_fname[CS1_N_FNC] = \{ +\par \hich\af2\dbch\af31505\loch\f2 }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "NOP"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "UNLD"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "SEEK"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "RECAL"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "DCLR"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "RLS"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 , +\par \hich\af2\dbch\af31505\loch\f2 }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "OFFS"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "RETN"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 ,}{\rtlch\fcs1 \af2 +\ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "PRESET"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "PACK"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "SEARCH"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 , +\par \hich\af2\dbch\af31505\loch\f2 }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "WRCHK"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "WRITE"}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "W\hich\af2\dbch\af31505\loch\f2 RHDR"}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "READ"}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 , }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf17\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 "RDHDR" +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 \}; +\par +\par \hich\af2\dbch\af31505\loch\f2 BITFIELD xx_csr_bits[] = \{ +\par \hich\af2\dbch\af31505\loch\f2 BIT(GO), }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 /* Go */ +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 BITFNAM(FUNC,5,rp_fname), }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 /* Function Code */ +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 BIT(IE), }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 /* Interrupt Enable */ +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 BIT(RDY), \hich\af2\dbch\af31505\loch\f2 }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf11\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 /* Drive Ready */ +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 BIT(DVA), }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 /* Drive Available */ +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 BITNCF(1), }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 /* 12 Reserved */ +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 BIT(TRE), }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf11\lang1024\langfe1024\noproof\insrsid16013944 +\hich\af2\dbch\af31505\loch\f2 /* Transfer Error */ +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 BIT(SC), \hich\af2\dbch\af31505\loch\f2 }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf11\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 /* Special Condition */ +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid16013944 \hich\af2\dbch\af31505\loch\f2 ENDBITS +\par \}\hich\af2\dbch\af31505\loch\f2 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8129972 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid16013944 \hich\af1\dbch\af31505\loch\f1 The fields in a register can be displayed (along with transition indicators) by calling sim_debug_bits. +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\rin0\lin720\itap0\pararsid16013944 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\cf2\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 void}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 }{\rtlch\fcs1 \af2 \ltrch\fcs0 \b\f2\lang1024\langfe1024\noproof\insrsid8084824\charrsid16013944 \hich\af2\dbch\af31505\loch\f2 sim_debug_bits}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 (uint32 dbits, DEVICE* dptr, BITFIELD* bitdefs, uint32 before, u\hich\af2\dbch\af31505\loch\f2 int32 after, }{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\cf2\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 int}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\lang1024\langfe1024\noproof\insrsid8084824 \hich\af2\dbch\af31505\loch\f2 terminate); +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8084824 +\par {\*\bkmkstart _Toc343577897}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.2\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_unit Structure{\*\bkmkend _Toc343577897} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Units are allocated as contiguous array. Each unit is defined with a }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_unit}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structure (typedef }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 UNIT}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 ): +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 struct sim_unit \{ +\par \tab \hich\af1\dbch\af31505\loch\f1 struct sim_unit\tab *next;\tab \tab \tab \tab /* next active */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*action)();\tab \tab \tab /* action rou\hich\af1\dbch\af31505\loch\f1 tine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab *filename;\tab \tab \tab /* open file name */ +\par \tab \hich\af1\dbch\af31505\loch\f1 FILE\tab \tab *fileref;\tab \tab \tab \tab /* file reference */ +\par \tab \hich\af1\dbch\af31505\loch\f1 void\tab \tab *filebuf;\tab \tab \tab \tab /* memory buffer */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab hwmark;\tab \tab \tab /* high water mark */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab time;\tab \tab \tab \tab /* time out */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab flags;\tab \tab \tab \tab /* flags */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_addr\tab \tab capac;\tab \tab \tab \tab /* \hich\af1\dbch\af31505\loch\f1 capacity */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_addr\tab \tab pos;\tab \tab \tab \tab /* file position */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab buf;\tab \tab \tab \tab /* buffer */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab wait;\tab \tab \tab \tab /* wait */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab u3;\tab \tab \tab \tab /* device specific */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab u4;\tab \tab \tab \tab /* device specific */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab u5;\tab \tab \tab \tab /* device specific */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab u6;\tab \tab \tab \tab /* device specific */ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \}\hich\af1\dbch\af31505\loch\f1 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The fields are the following: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 next}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab +\hich\af1\dbch\af31505\loch\f1 pointer to next unit in active queue, NULL if none. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 action}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 address of unit time-out service routine. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 filename}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 pointer to name of attached file, NULL if none. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fileref}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 pointer to FILE structure of attached file, NULL +\hich\af1\dbch\af31505\loch\f1 if none. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 hwmark}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 buffered devices only; highest modified address, + 1. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 time}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 increment until time-out beyond previous unit in active queue. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flags}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 unit flags. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 capac}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 unit capacity, 0 if variable. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pos}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 sequential devices only; next device address to be read +\hich\af1\dbch\af31505\loch\f1 or written. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 buf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 by convention, the unit buffer, but can be used for other purposes. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 wait}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 by convention, the unit wait time, but can be used for other purposes. + +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 u3}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 user-defined. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 u4}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 user-defined. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 u5\tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 user-defined. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 u6\tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 user-defined. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 buf, wait, u3, u4, u5\hich\af1\dbch\af31505\loch\f1 , u6, }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and parts of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 flags}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 are all saved and restored by the SAVE and RESTORE commands and thus can be used for unit state which must be preserved. +\par +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Macro }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 UDATA}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is available to fill in the common fields of a UNIT. It is invoked by +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \tab \hich\af1\dbch\af31505\loch\f1 UDATA\tab \tab (action_routine, \hich\af1\dbch\af31505\loch\f1 flags, capacity) +\par +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Fields after }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 buf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 can be filled in manually, e.g, +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \hich\af2\dbch\af31505\loch\f2 UNIT lpt_unit = +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \{\hich\af2\dbch\af31505\loch\f2 UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 500 \}; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 defines the line printer as a sequential unit with a wait time of 500. +\par {\*\bkmkstart _Toc343577898}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.2.1\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Unit Flags{\*\bkmkend _Toc343577898} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flags }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 field contains indicato +\hich\af1\dbch\af31505\loch\f1 rs of current unit status. SIMH defines 12 flags: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flag name\tab \tab meaning if set +\par +\par \hich\af1\dbch\af31505\loch\f1 UNIT_ATTABLE\tab the unit responds to ATTACH and DETACH. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_RO\tab \tab the unit is currently read only. +\par \hich\af1\dbch\af31505\loch\f1 UNIX_FIX\tab \tab the unit is fixed capacity. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_SEQ\tab \tab the unit is sequential. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_ATT\tab \tab \hich\af1\dbch\af31505\loch\f1 the unit is currently attached to a file. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_BINK\tab \tab \hich\f1 the unit measures \'93\loch\f1 \hich\f1 K\'94\loch\f1 as 1024, rather than 1000. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_BUFABLE\tab the unit buffers its data set in memory. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_MUSTBUF\tab the unit allocates its data buffer dynamically. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_BUF\tab \tab the unit is currently bufferi\hich\af1\dbch\af31505\loch\f1 ng its data set in memory. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_ROABLE\tab \tab the unit can be ATTACHed read only. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_DISABLE\tab \tab the unit responds to ENABLE and DISABLE. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_DIS\tab \tab the unit is currently disabled. +\par \hich\af1\dbch\af31505\loch\f1 UNIT_RAW\tab \tab the unit is attached in RAW mode. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Starting at bit position UNIT_V_UF, th\hich\af1\dbch\af31505\loch\f1 +e remaining flags are unit-specific. Unit-specific flags are set and cleared with the SET and CLEAR commands, which reference the MTAB array (see below). Unit-specific flags and UNIT_DIS are automatically saved and restored; the device need not supply a +\hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 register for these bits. +\par {\*\bkmkstart _Toc343577899}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.2.2\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Service Routine{\*\bkmkend _Toc343577899} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 This routine is called by }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_process_event}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + when a unit times out. Its calling sequence is: +\par +\par }\pard \ltrpar\ql \fi720\li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 service_routine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 The status returned by the service routine is passed by }{\rtlch\fcs1 +\ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_process_event}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 back to t\hich\af1\dbch\af31505\loch\f1 he CPU. +\par {\*\bkmkstart _Toc343577900}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.3\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_reg Structure{\*\bkmkend _Toc343577900} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Registers are allocated as contiguous array, with a NULL register at the end. Each register is defined with a }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_reg}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structure (typedef }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 REG}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ): +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 struct reg \{ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab *name;\tab \tab \tab \tab /* name */ +\par \tab \hich\af1\dbch\af31505\loch\f1 void\tab \tab *loc;\tab \tab \tab \tab /* location */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab rad\hich\af1\dbch\af31505\loch\f1 ix;\tab \tab \tab \tab /* radix */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab width;\tab \tab \tab \tab /* width */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab offset;\tab \tab \tab \tab /* starting bit */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab depth;\tab \tab \tab \tab /* save depth */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab flags;\tab \tab \tab \tab /* flags */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab qptr;\tab \tab \tab \tab /* current queue pointer */ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \}\hich\af1\dbch\af31505\loch\f1 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The fields are the following: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 name}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab +\hich\af1\dbch\af31505\loch\f1 device name, \hich\af1\dbch\af31505\loch\f1 string of all capital alphanumeric characters. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 loc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 pointer to location of the register value. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 radix}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 radix for input and display of data, 2 to 16 inclusive. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 width}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 width in bits of data, 1 to 32 inclusive. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 width\tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 bit offset (from right end of data). +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 depth\tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 size of data array (normally 1). +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flags}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 flags and formatting information. +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 qptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 for a circular queue, the entry number for the first entry +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 depth}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 field is used with \'93\loch\f1 +\hich\f1 arrayed registers\'94\loch\f1 . Arrayed registers are used to represent structures with multipl\hich\af1\dbch\af31505\loch\f1 +e data values, such as the locations in a transfer buffer; or structures which are replicated in every unit, such as a drive status register. The }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 qptr}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 field is used with \'93\loch\f1 \hich\f1 queued registers\'94\loch\f1 . Queued registers are arrays that are organized as circular queue\hich\af1\dbch\af31505\loch\f1 +s, such as the PC change queue. +\par +\par \hich\af1\dbch\af31505\loch\f1 A register that is 32b or less keeps its data in a 32b scalar variable (signed or unsigned). A register that is 33b or more keeps its data in a 64b scalar variable (signed or unsigned). There are several exceptions to thi +\hich\af1\dbch\af31505\loch\f1 s rule: +\par +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}}\pard \ltrpar\ql \fi-360\li720\ri0\widctlpar\jclisttab\tx720\wrapdefault\faauto\ls27\adjustright\rin0\lin720\itap0 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +An arrayed register keeps its data in a C-array whose SIMH data type is as large as (or if necessary, larger than), the width of a register element. For example, an array of 6b registers would keep its data in a uint8 (or int8) array; an array of +\hich\af1\dbch\af31505\loch\f1 16b registers would keep its data in a uint16 (or int16) array; an array of 24b registers would keep its data in a uint32 (or int32) array. +\par {\listtext\pard\plain\ltrpar \rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f3\fs20\insrsid4550150 \loch\af3\dbch\af31505\hich\f3 \'b7\tab}\hich\af1\dbch\af31505\loch\f1 +A register flagged with REG_FIT obeys the sizing rules of an arrayed register, rather than a normal scalar register\hich\af1\dbch\af31505\loch\f1 . This is useful for aliasing registers into memory or into structures. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Macros }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ORDATA}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 DRDATA}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 HRDATA}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 define right-justified octal, decimal, and hexidecimal registers, respectively. They are invoked by: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 xRDATA\tab (name, location, width) +\par +\par \hich\af1\dbch\af31505\loch\f1 Macro }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 FLDATA}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + defines a one-bit binary flag at an arbitrary offset in a 32-bit word. It is invoked by: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 FLDATA\tab (name, location, bit_position) +\par +\par \hich\af1\dbch\af31505\loch\f1 Macro }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 GRDATA}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + defines a register with arbitrary location and radix. It is invoked by: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 GRDATA\tab (name, location, radix, width\hich\af1\dbch\af31505\loch\f1 , bit_position) +\par +\par \hich\af1\dbch\af31505\loch\f1 Macro }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 BRDATA}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + defines an arrayed register whose data is kept in a standard C array. It is invoked by: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 BRDATA\tab (name, location, radix, width, depth) +\par +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 For all of these macros, the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flag}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 field can be filled in manually, e.g., +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \hich\af2\dbch\af31505\loch\f2 REG lpt_reg = \{ +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \tab \{\hich\af2\dbch\af31505\loch\f2 DRDATA\tab (POS, lpt_unit.pos, 31), PV_LFT \}\hich\f2 , \'85\loch\f2 \} + +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Finally, macro }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 URDATA}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + defines an arrayed register whose data is part of the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 UNIT}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + structure. This macro must be used with great care. If the fields are set up wrong, or the data is actually kept somewhe\hich\af1\dbch\af31505\loch\f1 re else, storing through this register declaration can trample over memory. The macro is invoked by: + +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 URDATA\tab (name, location, radix, width, offset, depth, flags) +\par +\par \hich\af1\dbch\af31505\loch\f1 The location should be an offset in the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 UNIT }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +structure for unit 0. The width should be 32 \hich\af1\dbch\af31505\loch\f1 for an int32 or uint32 field, and T_ADDR_W for a t_addr filed. The flags can be any of the normal register flags; REG_UNIT will be OR\hich\f1 \rquote \loch\f1 +d in automatically. For example, the following declares an arrayed register of all the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 UNIT }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 position fields in a device \hich\af1\dbch\af31505\loch\f1 with 4 units: +\par +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \{\hich\af2\dbch\af31505\loch\f2 URDATA\tab (POS, dev_unit[0].pos, 8, T_ADDR_W, 0, 4, 0) \} +\par {\*\bkmkstart _Toc343577901}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.3.1\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Register Flags{\*\bkmkend _Toc343577901} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 The }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 flags }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 field contains indicators that control register examination and deposit. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flag name\tab \tab meaning if specified +\par +\par \hich\af1\dbch\af31505\loch\f1 PV_RZRO\tab \tab print register right justified with leadin\hich\af1\dbch\af31505\loch\f1 g zeroes. +\par \hich\af1\dbch\af31505\loch\f1 PV_RSPC\tab \tab print register right justified with leading spaces. +\par \hich\af1\dbch\af31505\loch\f1 PV_LEFT\tab \tab print register left justified. +\par \hich\af1\dbch\af31505\loch\f1 REG_RO\tab \tab register is read only. +\par \hich\af1\dbch\af31505\loch\f1 REG_HIDDEN\tab \tab register is hidden (will not appear in EXAMINE STATE). +\par \hich\af1\dbch\af31505\loch\f1 REG_HRO\tab \tab register is read only and hidden. +\par \hich\af1\dbch\af31505\loch\f1 REG_\hich\af1\dbch\af31505\loch\f1 NZ\tab \tab new register values must be non-zero. +\par \hich\af1\dbch\af31505\loch\f1 REG_UNIT\tab \tab register resides in the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 UNIT}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structure. + +\par \hich\af1\dbch\af31505\loch\f1 REG_CIRC\tab \tab register is a circular queue. +\par \hich\af1\dbch\af31505\loch\f1 REG_VMIO\tab \tab register is displayed and parsed using VM data routines. +\par \hich\af1\dbch\af31505\loch\f1 REG_VMAD\tab \tab register is displayed and parsed using VM addre\hich\af1\dbch\af31505\loch\f1 ss routines. +\par \hich\af1\dbch\af31505\loch\f1 REG_FIT\tab \tab register container uses arrayed rather than scalar size rules. +\par {\*\bkmkstart _Toc343577902}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.4\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_mtab Structure{\*\bkmkend _Toc343577902} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Device-specific SHOW and SET commands are processed using the modifications array, which is allocated as contiguous array, with a NULL at the end. Eac +\hich\af1\dbch\af31505\loch\f1 h possible modification is defined with a }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_mtab}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + structure (synonym }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 MTAB}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ), which has the following fields: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 struct sim_mtab \{ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab mask;\tab \tab \tab \tab /* mask */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab match;\tab \tab \tab \tab /* match */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab *pstring;\tab \tab \tab /* print string */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab *mstring;\tab \tab \tab /* match st\hich\af1\dbch\af31505\loch\f1 ring */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*valid)();\tab \tab \tab /* validation routine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*disp)();\tab \tab \tab /* display routine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 void\tab \tab *desc}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ;\tab \tab \tab \tab /}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +* location descriptor */ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \}\hich\af1\dbch\af31505\loch\f1 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 MTAB supports two different structure interpretations: regular and extended. A regular MTAB entry modifies f\hich\af1\dbch\af31505\loch\f1 +lags in the UNIT flags word; the descriptor entry is not used. The fields are the following: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mask}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab +\hich\af1\dbch\af31505\loch\f1 bit mask for testing the unit.}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flags}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 field +\par }\pard \ltrpar\ql \fi-1440\li2160\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin2160\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 match}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab +\hich\af1\dbch\af31505\loch\f1 value to be stored (SET) or compared (SHOW) +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 pointer to character string printed on a match (SHOW), +\hich\af1\dbch\af31505\loch\f1 or NULL +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 pointer to character string to be matched (SET), or NULL +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 valid}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 address of validation routine (SET), or NULL +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 disp\tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 address of display routine (SHOW), or NULL +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 For SET, a regular MTAB entry is interpreted as follows: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 1.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls20\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls20\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Test to see if the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 mstrin\hich\af1\dbch\af31505\loch\f1 g}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 entry exists. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 2.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls20\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls20\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Test to see if the SET parameter matches the }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls20\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls20\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Call the validation routine, if any. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls20\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls20\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Apply the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 mask}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 value to the UNIT flags word and then or in the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +match}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 value. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 For SHOW, a regular MTAB entry is interpreted as follows: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 1.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls21\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls21\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Test to see \hich\af1\dbch\af31505\loch\f1 if the }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 entry exists. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 2.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls21\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls21\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Test to see if the UNIT flags word, masked with the }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mask}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 value, equals the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +match}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 value. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls21\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls21\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 If a display routine exists, call it, otherwise +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls21\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls21\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Print the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 pstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Extended MTAB entries have a different interpretation: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mask}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab +\hich\af1\dbch\af31505\loch\f1 entry fla\hich\af1\dbch\af31505\loch\f1 gs +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 MTAB_XTD\tab extended entry +\par \tab \tab \hich\af1\dbch\af31505\loch\f1 MTAB_VDV\tab valid for devices +\par \tab \tab \hich\af1\dbch\af31505\loch\f1 MTAB_VUN\tab valid for units +\par \tab \tab \hich\af1\dbch\af31505\loch\f1 MTAB_VAL\tab takes a value +\par \tab \tab \hich\af1\dbch\af31505\loch\f1 MTAB_NMO\tab valid only in named SHOW +\par \tab \tab \hich\af1\dbch\af31505\loch\f1 MTAB_NC\tab do not convert option value to upper case +\par \tab \tab \hich\af1\dbch\af31505\loch\f1 MTAB_SHP\tab SHOW parameter takes optional value +\par }\pard \ltrpar\ql \fi-1440\li2160\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin2160\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 match}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab +\hich\af1\dbch\af31505\loch\f1 value\hich\af1\dbch\af31505\loch\f1 to be stored (SET) +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 pointer to character string printed on a match (SHOW), or NULL +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 pointer to character string to be matched (SET), or NULL +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 valid}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 address of validation routine (SET), or NULL +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 disp\tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 address of display routine (SHOW), or NULL +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 d\hich\af1\dbch\af31505\loch\f1 esc\tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pointer to a REG structure (MTAB_VAL set) or + +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 a validation-specific structure (MTAB_VAL clear) +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 For SET, an extended MTAB entry is interpreted as follows: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 1.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls22\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls22\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Test to see if the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 mstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 entry exists. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 2.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls22\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls22\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Test to see if the SET parameter matches the }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls22\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls22\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 T\hich\af1\dbch\af31505\loch\f1 +est to see if the entry is valid for the type of SET being done (SET device or SET unit). +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls22\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls22\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +If a validation routine exists, call it and return its status. The validation routine is responsible for storing the result. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls22\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls22\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 If }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is NULL, exit. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 6.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls22\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls22\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 If MTAB_VAL is s\hich\af1\dbch\af31505\loch\f1 \hich\f1 +et, parse the SET option for \'93\loch\f1 \hich\f1 option=n\'94\loch\f1 , and store the value n in the register described by }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 . +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 7.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls22\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls22\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Otherwise, store the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 match}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 value in the int32 pointed to by }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 For SHOW, an extended MTAB entry is interpreted as follows: +\par +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 1.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls23\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls23\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Test to see if the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 pstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ent\hich\af1\dbch\af31505\loch\f1 ry exists. +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 2.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls23\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls23\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +Test to see if the entry is valid for the type of SHOW being done (device or unit). +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 3.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls23\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls23\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 If a display routine exists, call it, otherwise, +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls23\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls23\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 If MTAB_VAL is set, print \'93\loch\f1 \hich\f1 pstring=n\'94 +\loch\f1 , where the value, radix, and width are taken from the register described b\hich\af1\dbch\af31505\loch\f1 y }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , otherwise, +\par {\pntext\pard\plain\ltrpar \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \f1\fs20\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.\tab}}\pard \ltrpar\ql \fi-360\li1080\ri0\widctlpar\jclisttab\tx1080\wrapdefault{\*\pn \pnlvlbody\ilvl0\ls23\pnrnot0 +\pndec\pnstart1\pnindent360\pnsp120\pnhang {\pntxta .}}\faauto\ls23\adjustright\rin0\lin1080\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Print the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 pstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SHOW [dev|unit] \{=\} is a special case. Only two kinds of modifiers can be displayed individually: an extended MTAB entry that takes a value; and any MTAB entry with both a display routine and a }{ +\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pstri\hich\af1\dbch\af31505\loch\f1 ng}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +. Recall that if a display routine exists, SHOW does not use the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + entry. For displaying a named modifier, }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + is used as the string match. This allows implementation of complex display routines that are only invoked by name, e.g., +\par +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \hich\af2\dbch\af31505\loch\f2 MTAB cp\hich\af2\dbch\af31505\loch\f2 u_tab[] = \{ +\par \tab \tab \{\hich\af2\dbch\af31505\loch\f2 \hich\f2 mask, value, \'93\loch\f2 \hich\f2 normal\'94\loch\f2 \hich\f2 , \'93\loch\f2 \hich\f2 NORMAL\'94\loch\f2 , NULL, NULL, NULL \}, +\par \tab \tab \{\hich\af2\dbch\af31505\loch\f2 \hich\f2 MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, \'93\loch\f2 \hich\f2 SPECIAL\'94, +\par }\pard \ltrpar\ql \fi720\li1440\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin1440\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 NULL, NULL, NULL, &spec_disp \}, +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \tab \{\hich\af2\dbch\af31505\loch\f2 0 \} +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \}\hich\af2\dbch\af31505\loch\f2 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 A SHOW CPU command will display only the modifier named NORMAL; but SHOW CPU SPECIAL will invoke \hich\af1\dbch\af31505\loch\f1 the special display routine. +\par {\*\bkmkstart _Toc343577903}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.4.1\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Validation Routine{\*\bkmkend _Toc343577903} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The validation routine can be used to validate input during SET processing. It can make other state changes required by the modification or initiate additional dialogs needed by the modifier. Its calling s +\hich\af1\dbch\af31505\loch\f1 equence is: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 validation_routine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int32 value, char *cptr, void *desc) \hich\f1 \endash \loch\f1 test that }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 .}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flags}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 can be set to }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 value}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 points to the value portion of the parameter string (any characters after the = sign); if }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is NULL, no value was \hich\af1\dbch\af31505\loch\f1 given. }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 points to the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 REG}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 or int32 used to store the parameter. +\par {\*\bkmkstart _Toc343577904}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.4.2\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Display Routine{\*\bkmkend _Toc343577904} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The display routine is called during SHOW processing to display device- or unit-specific state. Its calling sequence is: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 display_routine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (FILE *st, UNIT *uptr, i\hich\af1\dbch\af31505\loch\f1 nt value, void *desc) \hich\f1 \endash \loch\f1 + output device- or unit-specific state for }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to stream }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . If the modifier is regular MTAB entry, or an extended entry without MTAB_SHP set, }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 points to the structure in the MTAB entry. If the modifier is an extended MTAB ent +\hich\af1\dbch\af31505\loch\f1 ry with MTAB_SHP set, }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + points to the optional value string or is NULL if no value was supplied. }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 value}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + is the value field of the matched MTAB entry. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 When the display routine is called for a regular MTAB entry, SHOW has output the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pstring}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 argument but \hich\af1\dbch\af31505\loch\f1 has not appended a newline. When it is called for an extended MTAB entry, SHOW hasn\hich\f1 \rquote \loch\f1 +t output anything. SHOW will append a newline after the display routine returns, except for entries with the MTAB_NMO flag set. +\par {\*\bkmkstart _Toc343577905}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 4.5\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Other Data Structures{\*\bkmkend _Toc343577905} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 char }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_name[]}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is \hich\af1\dbch\af31505\loch\f1 +a character array containing the VM name. +\par +\par \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_emax}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + contains the maximum number of words needed to hold the largest instruction or data item in the VM. Examine and deposit will process up to }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_emax}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 words. +\par +\par \hich\af1\dbch\af31505\loch\f1 DEVICE *}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_devices[]}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is an array of poin +\hich\af1\dbch\af31505\loch\f1 ters to all the devices in the VM. It is terminated by a NULL. By convention, the CPU is always the first device in the array. +\par +\par \hich\af1\dbch\af31505\loch\f1 REG *}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_PC}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 points to the }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 reg}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structure for the program counter. By convention, the PC is always the first register in the CP +\hich\af1\dbch\af31505\loch\f1 U\hich\f1 \rquote \loch\f1 s register array. +\par +\par \hich\af1\dbch\af31505\loch\f1 char *}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_stop_messages[]}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + is an array of pointers to character strings, corresponding to error status returns greater than zero. If }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_instr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 returns status code n > 0, then }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_stop_message[n]}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + is printed by SCP. +\par +\par {\*\bkmkstart _Toc343577906}{\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af0\afs28 \ltrch\fcs0 \b\f1\fs28\kerning28\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.\tab}}\pard\plain \ltrpar\s1\ql \fi-360\li360\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx360\wrapdefault\faauto\ls1\outlinelevel0\adjustright\rin0\lin360\itap0 \rtlch\fcs1 \ab\af1\afs28\alang1025 \ltrch\fcs0 \b\fs28\lang1033\langfe1033\kerning28\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 VM Provided Routines{\*\bkmkend _Toc343577906} +\par {\*\bkmkstart _Toc343577907}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.1\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Instruction Execution{\*\bkmkend _Toc343577907} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Instruction execution is performed by routine }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_instr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +. Its calling sequence is: +\par +\par }\pard \ltrpar\ql \fi720\li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_instr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (void) \hich\f1 \endash \loch\f1 execute from current PC until error or halt. +\par {\*\bkmkstart _Toc343577908}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.2\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Binary Load and Dump{\*\bkmkend _Toc343577908} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 If the VM responds to the LOAD (or DUMP) command, the l\hich\af1\dbch\af31505\loch\f1 oad routine (dump routine) is implemented by routine }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_load}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Its calling sequence is: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_load}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (FILE *fptr, char *buf, char *fnam, t_bool flag) - If }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 flag}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 = 0, load data from binary file }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fptr}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . If }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 flag}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + = 1, dump data to binary file }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . For eit\hich\af1\dbch\af31505\loch\f1 +her command, }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 buf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 contains any VM-specific arguments, and }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fnam}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 contains the file name. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 If LOAD or DUMP is not implemented, }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_load}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + should simply return SCPE_ARG. The LOAD and DUMP commands open and close the specified file for }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_load}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par {\*\bkmkstart _Toc343577909}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.3\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Symbolic Examin\hich\af1\dbch\af31505\loch\f1 ation and Deposit{\*\bkmkend _Toc343577909} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 If the VM provides symbolic examination and deposit of data, it must provide two routines, }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fprint_sym}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 for output and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 parse_sym}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + for input. Their calling sequences are: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 fprint_sym}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (FILE *ofile, t_addr addr, t_value *val, UNIT *upt\hich\af1\dbch\af31505\loch\f1 r, int32 switch) \hich\f1 \endash \loch\f1 + Based on the }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 switch}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 variable, symbolically output to stream }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ofile}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 the data in array }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +val}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 at the specified }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 in unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 parse_sym}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 switch) \hich\f1 \endash \loch\f1 Based on the }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 switch}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 variabl\hich\af1\dbch\af31505\loch\f1 e, parse character string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 for a symbolic value }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 val}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 at the specified }{\rtlch\fcs1 +\ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 in unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 If symbolic processing is not implemented, or the output value or input string cannot be parsed, these routines should return SCPE_ARG. If the processing was succ\hich\af1\dbch\af31505\loch\f1 +essful and consumed more than a single word, then these routines should return extra number of addressing units consumed as a }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 negative}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 number. If the processing was successful and consumed a single addressing unit, then these routines should return SCPE_O\hich\af1\dbch\af31505\loch\f1 K. For example, PDP-11 }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 parse_sym}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 would respond as follows to various inputs: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 input\tab \tab \tab \tab return value +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 XYZGH\tab \tab \tab \tab SCPE_ARG +\par \tab \hich\af1\dbch\af31505\loch\f1 MOV R0,R1\tab \tab \tab -1 +\par \tab \hich\af1\dbch\af31505\loch\f1 MOV #4,R5\tab \tab \tab -3 +\par \tab \hich\af1\dbch\af31505\loch\f1 MOV 1234,5670\tab \tab -5 +\par +\par \hich\af1\dbch\af31505\loch\f1 There is an implicit relationship between the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and }{ +\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 val}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 arguments and the devic\hich\af1\dbch\af31505\loch\f1 e\hich\f1 \rquote \loch\f1 s }{ +\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fields. Each entry in }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 val}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is assumed to represent }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 aincr}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 addressing units, starting at }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 : +\par +\par \ltrrow}\trowd \irow0\irowband0\ltrrow\ts11\trgaph108\trleft1350\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 +\trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3\tblind1458\tblindtype3 \clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx4320 +\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx7290\pard \ltrpar\ql \li0\ri0\widctlpar\intbl\wrapdefault\faauto\adjustright\rin0\lin0 {\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 val[0]\cell \hich\af1\dbch\af31505\loch\f1 addr + 0\cell }\pard \ltrpar\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \trowd \irow0\irowband0\ltrrow\ts11\trgaph108\trleft1350\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 +\trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3\tblind1458\tblindtype3 \clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx4320 +\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx7290\row \ltrrow}\pard \ltrpar\ql \li0\ri0\widctlpar\intbl\wrapdefault\faauto\adjustright\rin0\lin0 +{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 val[1]\cell \hich\af1\dbch\af31505\loch\f1 addr + aincr\cell }\pard \ltrpar\ql \li0\ri0\sa200\sl276\slmult1 +\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \trowd \irow1\irowband1\ltrrow\ts11\trgaph108\trleft1350\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 +\trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3\tblind1458\tblindtype3 \clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr +\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx4320\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx7290\row \ltrrow +}\pard \ltrpar\ql \li0\ri0\widctlpar\intbl\wrapdefault\faauto\adjustright\rin0\lin0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 val[2]\cell \hich\af1\dbch\af31505\loch\f1 addr + (2 * aincr)\cell }\pard \ltrpar +\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \trowd \irow2\irowband2\ltrrow\ts11\trgaph108\trleft1350\trbrdrt\brdrs\brdrw10 \trbrdrl +\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3\tblind1458\tblindtype3 \clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 +\clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx4320\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil +\cellx7290\row \ltrrow}\pard \ltrpar\ql \li0\ri0\widctlpar\intbl\wrapdefault\faauto\adjustright\rin0\lin0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 val[3]\cell \hich\af1\dbch\af31505\loch\f1 addr + (3 * aincr)\cell +}\pard \ltrpar\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \trowd \irow3\irowband3\ltrrow\ts11\trgaph108\trleft1350\trbrdrt\brdrs\brdrw10 +\trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3\tblind1458\tblindtype3 \clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl +\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx4320\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 +\cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx7290\row \ltrrow}\pard \ltrpar\ql \li0\ri0\widctlpar\intbl\wrapdefault\faauto\adjustright\rin0\lin0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 :\cell +\hich\af1\dbch\af31505\loch\f1 :\cell }\pard \ltrpar\ql \li0\ri0\sa200\sl276\slmult1\widctlpar\intbl\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \trowd \irow4\irowband4\lastrow \ltrrow +\ts11\trgaph108\trleft1350\trbrdrt\brdrs\brdrw10 \trbrdrl\brdrs\brdrw10 \trbrdrb\brdrs\brdrw10 \trbrdrr\brdrs\brdrw10 \trbrdrh\brdrs\brdrw10 \trbrdrv\brdrs\brdrw10 \trftsWidth1\trautofit1\trpaddl108\trpaddr108\trpaddfl3\trpaddfr3\tblind1458\tblindtype3 +\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx4320\clvertalt\clbrdrt\brdrs\brdrw10 \clbrdrl\brdrs\brdrw10 \clbrdrb\brdrs\brdrw10 \clbrdrr +\brdrs\brdrw10 \cltxlrtb\clftsWidth3\clwWidth2970\clshdrawnil \cellx7290\row }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Because }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 val}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is typically filled in and stored by calls +\hich\af1\dbch\af31505\loch\f1 on the device\hich\f1 \rquote \loch\f1 s examine and deposit routines, respectively, the examine and deposit routines and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fprint_sym}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fparse_sym}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 must agree on the expected width of items in }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 val}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +, and on the alignment of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Further, if }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fparse_sym}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 wants to modify a storage un\hich\af1\dbch\af31505\loch\f1 it narrower than }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 awidth}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , it must insert the new data into the appropriate entry in }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 val}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 without destroying surrounding fields. +\par +\par \hich\af1\dbch\af31505\loch\f1 The interpretation of switch values is arbitrary, but the following are used by existing VM\hich\f1 \rquote \loch\f1 s: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 switch\tab \tab \tab \tab interpretation +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 -a\tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 single character +\par \tab \hich\af1\dbch\af31505\loch\f1 -c\tab \tab \tab \tab character string +\par \tab \hich\af1\dbch\af31505\loch\f1 -m\tab \tab \tab \tab instruction mnemonic +\par +\par \hich\af1\dbch\af31505\loch\f1 In addition, on input, a leading \hich\f1 \lquote \loch\f1 \hich\f1 (apostrophe) is interpreted to mean a single character, and a leading \'93\loch\f1 (double quote) is interpreted to mean a character string. +\par {\*\bkmkstart _Toc343577910}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.4\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Optional Interfaces{\*\bkmkend _Toc343577910} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 +For greater flexibility, SCP provides some optional interfaces that can be used to extend its command input, command processing, and command post-processing capabilities. These interfaces are strictly optional and are off by default. Using them requires +\hich\af1\dbch\af31505\loch\f1 intimate knowledge of how SCP functions internally and is not recommended to the novice VM writer. +\par {\*\bkmkstart _Toc343577911}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.4.1\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Once Only Initialization Routine{\*\bkmkend _Toc343577911} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SCP defines a pointer (*}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_init}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 +)(void). This is a \'93\loch\f1 \hich\f1 weak global\'94\loch\f1 ; if no other module defines this value, it will defau\hich\af1\dbch\af31505\loch\f1 +lt to NULL. A VM requiring special initialization should fill in this pointer with the address of its special initialization routine: +\par +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \hich\af2\dbch\af31505\loch\f2 void sim_special_init (void); +\par \tab \hich\af2\dbch\af31505\loch\f2 void (*sim_vm_init)(void) = &sim_special_init; +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The special initialization routine can p\hich\af1\dbch\af31505\loch\f1 +erform any actions required by the VM. If the other optional interfaces are to be used, the initialization routine can fill in the appropriate pointers; however, this can just as easily be done in the CPU reset routine. +\par {\*\bkmkstart _Toc343577912}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.4.2\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Address Input and Display{\*\bkmkend _Toc343577912} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SCP defi\hich\af1\dbch\af31505\loch\f1 nes a pointer t_addr *(}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_parse_addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 )(DEVICE *, char *, char **). This is initialized to NULL. If it is filled in by the VM, SCP will use the specified routine to parse addresses in place of its standard numerical input routine. The calling sequence +\hich\af1\dbch\af31505\loch\f1 for the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_parse_addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 routine is: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_addr }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_vm_parse_addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (DEVICE *dptr, char *cptr, char **optr) \hich\f1 \endash \loch\f1 parse the string pointed to by }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 as an address for the device pointed to by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 dptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . o}{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 points to the first character not successfully parsed. If\hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 == }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 optr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , parsing failed. + +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SCP defines a pointer void *(}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_fprint_addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +)(FILE *, DEVICE *, t_addr). This is initialized to NULL. If it is filled in by the VM, SCP will use the specified routine to print addresses in place of its standard numerica\hich\af1\dbch\af31505\loch\f1 +l output routine. The calling sequence for the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_fprint_addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 routine is: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_addr }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_vm_fprint_addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (FILE *stream, DEVICE *dptr, t_addr addr) \hich\f1 \endash \loch\f1 output address }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 stream}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 in the format required by the device pointed to by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 dptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . + +\par {\*\bkmkstart _Toc343577913}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.4.3\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Command Input and P\hich\af1\dbch\af31505\loch\f1 ost-Processing{\*\bkmkend _Toc343577913} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SCP defines a pointer char* (}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_read}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +)(char *, int32 *, FILE *). This is initialized to NULL. If it is filled in by the VM, SCP will use the specified routine to obtain command input in place of its standard routine, read_line. The ca\hich\af1\dbch\af31505\loch\f1 lling sequence for the } +{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_read}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 routine is: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 char }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_vm_input}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (char *buf, int32 *max, FILE *stream) \hich\f1 \endash \loch\f1 read the next command line from }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 stream}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and store it in }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +buf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , up to a maximum of }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 max}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 characters +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The routine is expected to strip off leading whitespace\hich\af1\dbch\af31505\loch\f1 characters and to return NULL on end of file. +\par +\par \hich\af1\dbch\af31505\loch\f1 SCP defines a pointer void *(}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_post}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +)(t_bool from_scp). This is initialized to NULL. If filled in by the VM, SCP will call the specified routine at the end of every command. This allows the VM to updat\hich\af1\dbch\af31505\loch\f1 +e any local state, such as a GUI console display. The calling sequence for the vm_post routine is: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_vm_postupdate}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (t_bool from_scp) \hich\f1 \endash \loch\f1 if called from SCP, the argument }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 from_scp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is TRUE; otherwise, it is FALSE. +\par {\*\bkmkstart _Toc343577914}{\listtext\pard\plain\ltrpar \s3 \rtlch\fcs1 \af0 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 5.4.4\tab}}\pard\plain \ltrpar\s3\ql \fi-720\li720\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx720\wrapdefault\faauto\ls1\ilvl2\outlinelevel2\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs24\alang1025 \ltrch\fcs0 \fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 VM-Specific Commands{\*\bkmkend _Toc343577914} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SCP defines a p\hich\af1\dbch\af31505\loch\f1 ointer CTAB *}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_vm_cmd}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 . This is initialized to NULL. If filled in by the VM, SCP interprets it as a pointer to SCP command table. This command table is checked before user input is looked up in the standard command table. +\par +\par \hich\af1\dbch\af31505\loch\f1 A command table is allocated \hich\af1\dbch\af31505\loch\f1 as a contiguous array. Each entry is defined with a }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_ctab}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structure (typedef }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 CTAB}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 ): +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 struct sim_ctab \{ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab *name;\tab \tab \tab \tab /* name */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_stat\tab \tab (*action)();\tab \tab \tab /* action routine */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab arg;\tab \tab \tab \tab /* argument */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab *help;\tab \tab \tab \tab /* help string */ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \}\hich\af1\dbch\af31505\loch\f1 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 If the\hich\af1\dbch\af31505\loch\f1 first word of a command line matches ctab.name, then the action routine is called with the following arguments: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 action_routine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (int32 arg, char *buf) \hich\f1 \endash \loch\f1 process input string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 buf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 based on optional argument }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 arg}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The string passed to the action routin\hich\af1\dbch\af31505\loch\f1 e starts at the first non-blank character past the command name. +\par {\*\bkmkstart _Toc343577915}{\listtext\pard\plain\ltrpar \s1 \rtlch\fcs1 \ab\af0\afs28 \ltrch\fcs0 \b\f1\fs28\kerning28\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 6.\tab}}\pard\plain \ltrpar\s1\ql \fi-360\li360\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx360\wrapdefault\faauto\ls1\outlinelevel0\adjustright\rin0\lin360\itap0 \rtlch\fcs1 \ab\af1\afs28\alang1025 \ltrch\fcs0 \b\fs28\lang1033\langfe1033\kerning28\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Other SCP Facilities{\*\bkmkend _Toc343577915} +\par {\*\bkmkstart _Toc343577916}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 6.1\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Terminal Input/Output Formatting Library{\*\bkmkend _Toc343577916} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SIMH provides routines to convert ASCII input characters to the format expected VM, and to convert VM-supplied ASCII characters \hich\af1\dbch\af31505\loch\f1 to C-standard format. The routines are +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_tt_inpcvt}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (int32 c, uint32 mode) \hich\f1 \endash \loch\f1 convert input character }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 c}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 according to the }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mode }{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 specification and return the converted result (-1 if the character is not valid in the specified mode). +\par +\par \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tt_outc\hich\af1\dbch\af31505\loch\f1 vt}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (int32 c, uint32 mode) \hich\f1 \endash \loch\f1 convert output character }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 c}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + according to the }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mode}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + specification and return the converted result (-1 if the character is not valid in the specified mode). +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The supported modes are: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 TTUF_MODE_8B\tab 8b mode; no conversion +\par \tab \hich\af1\dbch\af31505\loch\f1 TTUF_MODE_\hich\af1\dbch\af31505\loch\f1 7B\tab 7b mode; the high-order bit is masked off +\par \tab \hich\af1\dbch\af31505\loch\f1 TTUF_MODE_7P\tab 7b printable mode; the high-order bit is masked off +\par \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 In addition, on output, if the character is not printable, +\par \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 -1 is returned +\par \tab \hich\af1\dbch\af31505\loch\f1 TTUF_MODE_UC\tab 7b upper case mode; the high-order bit is masked \hich\af1\dbch\af31505\loch\f1 off +\par \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 In addition, lower case is converted to upper case +\par \tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 If the character is not printable, -1 is returned +\par +\par \hich\af1\dbch\af31505\loch\f1 On input, TTUF_MODE_UC has an additional modifier, TTUF_MODE_KSR, which forces the high order bit to be set rather than cleared. +\par +\par \hich\af1\dbch\af31505\loch\f1 The set of p\hich\af1\dbch\af31505\loch\f1 rintable control characters is contained in the global bit-vector variable }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tt_pchar}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Each bit represents the character corresponding to the bit number (e.g., bit 0 represents NUL, bit 1 represents SOH, etc.). If a bit is set, the corresponding contro +\hich\af1\dbch\af31505\loch\f1 l character is considered printable. It initially contains the following characters: BEL, BS, HT, LF, and CR. The set may be manipulated with these routines: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_set_pchar}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (int32 flag, char *cptr) \hich\f1 \endash \loch\f1 set }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_tt_pchar}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to the value pointed to by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cpt +\hich\af1\dbch\af31505\loch\f1 r}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ; return SCPE_2FARG if }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is null or points to a null string, or SCPE_ARG if the value cannot be converted or does not contain at least CR and LF. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_show_pchar}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) \hich\f1 \endash \loch\f1 output the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tt_pc\hich\af1\dbch\af31505\loch\f1 har}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 value to the stream }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Note that the DEL character is always considered non-printable and will be suppressed in the UC and 7P modes. +\par +\par {\*\bkmkstart _Toc343577917}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 6.2\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Terminal Multiplexer Emulation Library{\*\bkmkend _Toc343577917} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SIMH supports the use of multiple terminals. All terminals except the conso\hich\af1\dbch\af31505\loch\f1 le are accessed via Telnet}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8129972 \hich\af1\dbch\af31505\loch\f1 + or serial ports on the host machine}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . SIMH provides }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8129972 \hich\af1\dbch\af31505\loch\f1 three }{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 supporting libraries for implementing multiple terminals: sim_tmxr.c (and its header file, sim_tmxr.h), which provide OS-independent support routines for terminal multiple\hich\af1\dbch\af31505\loch\f1 +xers; }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8129972 \hich\af1\dbch\af31505\loch\f1 sim_serial.c (and its header file sim_serial.h), which provide OS-dependent serial I/O routines; }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 and sim_sock.c (and its header file, sim_sock.h), which provide OS-dependent socket routines. Sim_sock.c }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8129972 \hich\af1\dbch\af31505\loch\f1 and sim_serial.c are}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 implemented under Windows,\hich\af1\dbch\af31505\loch\f1 VMS, UNIX, and MacOS. +\par +\par \hich\af1\dbch\af31505\loch\f1 Two basic data structures define the multiple terminals. Individual lines are defined by an array of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmln}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structures (typedef }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 TMLN}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ): +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 struct tmln \{ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid4462419 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 int\tab }{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \tab \hich\af1\dbch\af31505\loch\f1 conn;\tab \tab \tab \tab /* line conn\hich\af1\dbch\af31505\loch\f1 e}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 cte}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 d flag\hich\af1\dbch\af31505\loch\f1 */ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid4462419 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 SOCKET\tab \hich\af1\dbch\af31505\loch\f1 sock +\hich\af1\dbch\af31505\loch\f1 ;\tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 /* \hich\af1\dbch\af31505\loch\f1 connection socket\hich\af1\dbch\af31505\loch\f1 */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 char }{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 *}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ipad;\tab \tab \tab \tab /* IP address */ +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \tab \hich\af1\dbch\af31505\loch\f1 SOCKET\tab master;\tab \tab \tab \tab /* line specific master socket */ +\par \tab \hich\af1\dbch\af31505\loch\f1 c\hich\af1\dbch\af31505\loch\f1 har\tab \tab \hich\af1\dbch\af31505\loch\f1 *port;\tab \tab \tab \tab /* line specific listening port */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab sessions;\tab \tab \tab /* \hich\af1\dbch\af31505\loch\f1 count of tcp connections received\hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 */ +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab cnms;\tab \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 /* connect time ms */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab tsta;\tab \tab \tab \tab /* Telnet state */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab rcve;\tab \tab \tab \tab /* rcv enable */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab xmte;\tab \tab \tab \tab /* xmt enable */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab dstb;\tab \tab \tab \tab /* disable Tlnt bin */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid4462419 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 +\hich\af1\dbch\af31505\loch\f1 notelnet}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 ;\tab \tab \tab \hich\af1\dbch\af31505\loch\f1 /* }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 +raw binar\hich\af1\dbch\af31505\loch\f1 y d\hich\af1\dbch\af31505\loch\f1 ata (no telnet interpret)}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab rxbpr;\tab \tab \tab \tab /* rcv buf remove */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab rxbpi;\tab \tab \tab \tab /* rcv buf insert */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab \hich\af1\dbch\af31505\loch\f1 rxcnt;\tab \tab \tab \tab /* rcv count */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab txbpr;\tab \tab \tab \tab /* xmt buf remove */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab txbpi;\tab \tab \tab \tab /* xmt buf insert */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid4462419 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab txcnt;\tab \tab \tab \tab /* xmt count */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab txdrp;\tab \tab \tab \tab /* xmt drop count */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid4462419 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab txbsz}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 ;\tab \tab \tab \tab /* xmt buf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 fer size}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 +\hich\af1\dbch\af31505\loch\f1 */ +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab txbfd}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 ;\tab \tab \tab \tab /* xmt buf\hich\af1\dbch\af31505\loch\f1 fer}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 ed}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 flag}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4462419 \hich\af1\dbch\af31505\loch\f1 */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 FILE\tab \tab *txlog;\tab \tab \tab \tab /* xmt log file */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid3891160 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab \hich\af1\dbch\af31505\loch\f1 FILE}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 +\hich\af1\dbch\af31505\loch\f1 REF}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab \hich\af1\dbch\af31505\loch\f1 *txlog}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 ref}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 ;\tab \tab \tab \hich\af1\dbch\af31505\loch\f1 /* xmt log file }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 reference }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 +\hich\af1\dbch\af31505\loch\f1 */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab *txlogname;\tab \tab \tab /* xmt log file name */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab rxb[TMXR_MAXBUF];\tab \tab /* rcv bu\hich\af1\dbch\af31505\loch\f1 ffer */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab rbr[TMXR_MAXBUF];\tab \tab /* rcv break */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 *}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 txb\hich\af1\dbch\af31505\loch\f1 ;}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 /* xmt buffer */ +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab \hich\af1\dbch\af31505\loch\f1 TMXR\tab \tab *mp;\tab \tab \tab \tab /* \hich\af1\dbch\af31505\loch\f1 back pointer to mux */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab \hich\af1\dbch\af31505\loch\f1 *serconfig;\tab \tab \tab /* \hich\af1\dbch\af31505\loch\f1 line config\hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid3891160 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 SERHANDLE\tab }{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 ser}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 port}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 ;}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab \tab \tab \hich\af1\dbch\af31505\loch\f1 /* }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 serial port handle}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 */ +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab \hich\af1\dbch\af31505\loch\f1 t_\hich\af1\dbch\af31505\loch\f1 bool\tab \tab ser_connect_pending;\tab \tab +/* serial connection notice pending */ +\par \tab \hich\af1\dbch\af31505\loch\f1 SOCKET\tab connecting;\tab \tab \tab /* \hich\af1\dbch\af31505\loch\f1 Outgoing socket while connecting\hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char\tab \tab \hich\af1\dbch\af31505\loch\f1 *destination;\tab \tab \tab /* \hich\af1\dbch\af31505\loch\f1 Outgoing destination address\hich\af1\dbch\af31505\loch\f1 :port\hich\af1\dbch\af31505\loch\f1 +\hich\af1\dbch\af31505\loch\f1 */ +\par \tab \hich\af1\dbch\af31505\loch\f1 UNIT\tab \tab *uptr;\tab \tab \tab \tab /* \hich\af1\dbch\af31505\loch\f1 input polling unit -\hich\af1\dbch\af31505\loch\f1 default to mp->uptr\hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 */ +\par \tab \hich\af1\dbch\af31505\loch\f1 UNIT\tab \tab *o_uptr;\tab \tab \tab \tab /* output polling unit \loch\af1\dbch\af31505\hich\f1 \endash \hich\af1\dbch\af31505\loch\f1 default \hich\af1\dbch\af31505\loch\f1 to lp->uptr */ +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \}\hich\af1\dbch\af31505\loch\f1 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The fields are the following: +\par +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 conn}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 connection }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 +\hich\af1\dbch\af31505\loch\f1 flag}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (0 = disconnected) +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid3891160 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\insrsid3891160\charrsid3891160 \hich\af1\dbch\af31505\loch\f1 +sock}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 connection socket}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid3806017 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \hich\af1\dbch\af31505\loch\f1 ipad}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid3806017 \tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \hich\af1\dbch\af31505\loch\f1 IP address of \hich\af1\dbch\af31505\loch\f1 remote end of conne\hich\af1\dbch\af31505\loch\f1 ction}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid3806017 +\par \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\insrsid3806017\charrsid3806017 \hich\af1\dbch\af31505\loch\f1 master}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \tab \tab \hich\af1\dbch\af31505\loch\f1 optional }{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid3806017 \hich\af1\dbch\af31505\loch\f1 line specific listening }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \hich\af1\dbch\af31505\loch\f1 socket +\par \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\insrsid3806017\charrsid3806017 \hich\af1\dbch\af31505\loch\f1 port}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \hich\af1\dbch\af31505\loch\f1 +optional \hich\af1\dbch\af31505\loch\f1 line specific listening port}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 +\par \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\insrsid3806017 \hich\af1\dbch\af31505\loch\f1 sessions}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \tab \hich\af1\dbch\af31505\loch\f1 count of tcp connections received}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid3806017 +\par \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\insrsid3806017\charrsid3806017 \hich\af1\dbch\af31505\loch\f1 cnms}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 \hich\af1\dbch\af31505\loch\f1 +connect time}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3806017 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tsta}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 Telnet state +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 rcve}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 receive enable flag (0 = disabled) +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 xmte}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 transmit flow \hich\af1\dbch\af31505\loch\f1 +control flag (0 = transmit disabled) +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 dstb}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 Telnet bin mode disabled +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 rxbp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 r\tab \tab receive buffer remove pointer +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 rxbpi}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 receive buffer insert pointer +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 rxcnt}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 receive count +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 txbpr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 transmit buffer remove pointer +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 txbpi}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 transmit buffer insert pointer +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 txcnt}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 tra\hich\af1\dbch\af31505\loch\f1 nsmit count +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 txlog}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 pointer to log file descriptor +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 txlogname}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 pointer to log file name +\par }\pard \ltrpar\ql \fi720\li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 rxb}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab +\hich\af1\dbch\af31505\loch\f1 receive buffer +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 rbr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 receive buffer break flags +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 txb}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 transmit buffer +\par +\par \hich\af1\dbch\af31505\loch\f1 The overall set of extra terminals is defined by the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + structure (typedef }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 TMXR}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ): +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 struct tm\hich\af1\dbch\af31505\loch\f1 xr \{ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab lines;\tab \tab \tab \tab /* # lines */ +\par \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 char}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \hich\af1\dbch\af31505\loch\f1 *}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 port;\tab \tab \tab \tab /* listening port */ +\par \tab \hich\af1\dbch\af31505\loch\f1 SOCKET\tab master;\tab \tab \tab \tab /* master socket */ +\par \tab \hich\af1\dbch\af31505\loch\f1 TMLN\tab \tab *ldsc;\tab \tab \tab \tab /* pointer to line descriptors */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab *lnorder;\tab \tab \tab /* line connection order */ +\par \tab \hich\af1\dbch\af31505\loch\f1 DEVICE\tab *dptr;\tab \tab \tab \tab /* multiplexer device */ +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 \tab \hich\af1\dbch\af31505\loch\f1 UNIT\tab \tab *uptr;\tab \tab \tab \tab /* polling unit (connection) */ +\par \tab \hich\af1\dbch\af31505\loch\f1 char \tab \tab \hich\af1\dbch\af31505\loch\f1 logfiletmpl[FILENAMEMAX];\tab /* te\hich\af1\dbch\af31505\loch\f1 mplate logfile name */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int23\tab \tab buffered;\tab \tab \tab /* \hich\af1\dbch\af31505\loch\f1 Buffered line behavior and buffer size\hich\af1\dbch\af31505\loch\f1 */ +\par \tab \hich\af1\dbch\af31505\loch\f1 int32\tab \tab sessions;\tab \tab \tab /* count of tcp connections received */ +\par \tab \hich\af1\dbch\af31505\loch\f1 uint32\tab \tab last_poll_time;\tab \tab \tab /* time of last connection poll */ +\par \tab \hich\af1\dbch\af31505\loch\f1 t_bool\tab \tab notelnet;\tab \tab \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 /* default telnet capabili\hich\af1\dbch\af31505\loch\f1 ty for incoming connections */}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid3891160 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \tab \hich\af1\dbch\af31505\loch\f1 t_bool\tab \tab modem_control;\tab \tab \tab /* multiplexer supports modem control behaviors */ +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \}\hich\af1\dbch\af31505\loch\f1 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The fields are the following: +\par +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lines}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 number of lines (constant) +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 port}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 master listening port (specified by ATTACH command) +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 master}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 master listening socket (filled in by ATTACH command) +\par \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ldsc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \tab \hich\af1\dbch\af31505\loch\f1 array of line descriptors +\par }\pard \ltrpar\ql \fi-1440\li2160\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin2160\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lnorder}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab +\hich\af1\dbch\af31505\loch\f1 array of line numbers \hich\af1\dbch\af31505\loch\f1 in order of connection sequence, or NULL if user-defined connection order is not required +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 dptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab \hich\af1\dbch\af31505\loch\f1 pointer to the multiplexer\hich\f1 \rquote \loch\f1 +s DEVICE structure, or NULL if the device is to be derived from the UNIT passed to the \hich\af1\dbch\af31505\loch\f1 a\hich\af1\dbch\af31505\loch\f1 t\hich\af1\dbch\af31505\loch\f1 t\hich\af1\dbch\af31505\loch\f1 a\hich\af1\dbch\af31505\loch\f1 c +\hich\af1\dbch\af31505\loch\f1 h\hich\af1\dbch\af31505\loch\f1 call. +\par }\pard \ltrpar\ql \fi-1440\li2160\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin2160\itap0\pararsid1264706 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid1264706 \hich\af1\dbch\af31505\loch\f1 u}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid1264706 +\hich\af1\dbch\af31505\loch\f1 ptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid1264706 \tab \hich\af1\dbch\af31505\loch\f1 the UNIT passed to the \hich\af1\dbch\af31505\loch\f1 attach call. +\par }\pard \ltrpar\ql \fi-1440\li2160\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin2160\itap0\pararsid7674256 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 logfiletmpl}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid1264706 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 template logfile name used to create names for per line log files\hich\af1\dbch\af31505\loch\f1 l.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid1264706 + +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 buffered}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid1264706 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 +Buffered line behaviors enabled flag and the size of the line buffer.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid1264706 +\par }\pard \ltrpar\ql \fi-1440\li2160\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin2160\itap0\pararsid1264706 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 sessions}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid1264706 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 count of tcp connections received on the master socket}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid1264706 .}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid1264706 +\par }\pard \ltrpar\ql \fi-1440\li2160\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin2160\itap0\pararsid7674256 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 last_\hich\af1\dbch\af31505\loch\f1 poll_time}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 time of last connection poll}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 . +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 notelnet}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 +default telnet capability for tcp connections}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 . +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 modem_\hich\af1\dbch\af31505\loch\f1 control}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 \tab }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 +\hich\af1\dbch\af31505\loch\f1 flag indicating that multiplexer supports full modem control behaviors}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid7674256 . +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid1264706 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid1264706 +\par +\par }\pard \ltrpar\ql \fi-1440\li2160\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin2160\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid1264706 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The number of elements in t\hich\af1\dbch\af31505\loch\f1 he }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ldsc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lnorder}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 arrays must equal the value of the }{ +\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lines}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 field. Set }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 lnorder}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to NULL if the connection order feature is not needed. If the first element of the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lnorder}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 array is \hich\f1 \endash \loch\f1 1, then the default ascending sequential connection order is used. Set }{ +\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 d\hich\af1\dbch\af31505\loch\f1 ptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + to NULL if the device should be derived from the unit passed to the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_attach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 call. + +\par +\par \hich\af1\dbch\af31505\loch\f1 Library sim_tmxr.c provides the following routines to support Telnet}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid8129972 \hich\af1\dbch\af31505\loch\f1 and Serial port}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 -based terminals: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 tmxr_poll_conn}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMXR *mp) \hich\f1 \endash \loch\f1 poll for a new connection to\hich\af1\dbch\af31505\loch\f1 the terminals described by }{ +\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +. If there is a new connection, the routine resets all the line descriptor state (including receive enable) and returns the line number (index to line descriptor) for the new connection. If there isn\hich\f1 \rquote \loch\f1 t a new connection, the +\hich\af1\dbch\af31505\loch\f1 routine returns \hich\f1 \endash \loch\f1 1. +\par +\par \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_reset_ln}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMLN *lp) \hich\f1 \endash \loch\f1 + reset the line described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +. The connection is closed and all line descriptor state is reset. +\par +\par \hich\af1\dbch\af31505\loch\f1 int32 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_getc_ln}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMLN *lp) \hich\f1 \endash \loch\f1 + return the next available character from the line described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . If a +\hich\af1\dbch\af31505\loch\f1 character is available, the return variable is: +\par +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \hich\af2\dbch\af31505\loch\f2 (1 << TMXR_V_VALID) | character +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 If a BREAK occurred on the line, SCPE_BREAK will be ORed into the return variable. }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +If no character is available, the return variable is 0. +\par +\par \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_poll_rx}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMXR *mp) \hich\f1 \endash \loch\f1 + poll for input available on the terminals described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . +\par +\par \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_rqln}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMLN *l\hich\af1\dbch\af31505\loch\f1 p) +\hich\f1 \endash \loch\f1 return the number of characters in the receive queue of the line described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_putc_ln}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (TMLN *lp, int32 chr) \hich\f1 \endash \loch\f1 output character }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 chr }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +to the line described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +. Possible errors are SCPE_LOST (connection lost) and SCPE_STALL (connectio\hich\af1\dbch\af31505\loch\f1 n backlogged). +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_poll_tx}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMXR *mp) +\hich\f1 \endash \loch\f1 poll for output complete on the terminals described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 . +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_tqln}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMLN *lp) \hich\f1 \endash \loch\f1 + return the number of characters in the transmit queue of the line described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid9308345 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9308345 +\hich\af1\dbch\af31505\loch\f1 tmxr_}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 send_buffered_data}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 (TMLN *lp) \hich\f1 \endash +\loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 flush any buffered data for the line described \hich\af1\dbch\af31505\loch\f1 by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9308345 +\hich\af1\dbch\af31505\loch\f1 lp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 . +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 tmxr_attach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMXR *mp, UNIT *u\hich\af1\dbch\af31505\loch\f1 ptr, char *cptr) \hich\f1 \endash \loch\f1 + attach the port contained in character string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to the terminals described by }{ +\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_open_master}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMXR *mp, char *cptr) \hich\f1 +\endash \loch\f1 associate the port contained in character string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + to the terminals described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . \hich\af1\dbch\af31505\loch\f1 + This routine is a subset of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_attach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_detach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (TMXR *mp, UNIT *uptr) \hich\f1 \endash \loch\f1 detach all connections for the terminals described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 and unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_close_master}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMXR *mp) \hich\f1 \endash \loch\f1 + close the master port for the terminals described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . \hich\af1\dbch\af31505\loch\f1 +This routine is a subset of}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_detach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 . +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_ex}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) \hich\f1 \endash \loch\f1 stub examine routine, needed because the extra terminals are marked as attached; always returns an error. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_dep}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (t_value val, t_addr ad +\hich\af1\dbch\af31505\loch\f1 dr, UNIT *uptr, int32 sw) \hich\f1 \endash \loch\f1 stub deposit routine, needed because the extra terminals are marked as detached; always returns an error. +\par }\pard \ltrpar\ql \li360\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin360\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \fi360\li360\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin360\itap0\pararsid9308345 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9308345 +\hich\af1\dbch\af31505\loch\f1 tmxr_\hich\af1\dbch\af31505\loch\f1 msg}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 (}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 SOCKET}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 sock}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 , char *msg) +\hich\f1 \endash \loch\f1 output character string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 msg}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 to }{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 s\hich\af1\dbch\af31505\loch\f1 ocket sock}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 .}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 +\par }\pard \ltrpar\ql \fi360\li360\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin360\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 tmxr_linemsg}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (TMLN *lp, char *msg) \hich\f1 \endash \loch\f1 output character string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 msg}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to line }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lp}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 . +\par +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_fconns}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (FILE *st, TMLN *lp, \hich\af1\dbch\af31505\loch\f1 int32 ln) \hich\f1 \endash \loch\f1 output connection status to stream }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 for the line described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . If }{ +\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ln}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is >= 0, preface the output with the specified line number. +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 void }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_fstats}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (FILE *st, TMLN *lp, int32 ln) \hich\f1 +\endash \loch\f1 output connection statistics to stream }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 for the line des +\hich\af1\dbch\af31505\loch\f1 cribed by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 lp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . If }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ln}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is >= 0, preface the output with the specified line num\hich\af1\dbch\af31505\loch\f1 b\hich\af1\dbch\af31505\loch\f1 e +\hich\af1\dbch\af31505\loch\f1 r. +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 \hich\af1\dbch\af31505\loch\f1 tstat }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\insrsid9308345\charrsid2698330 \hich\af1\dbch\af31505\loch\f1 tmxr_set_log}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9308345 +\hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int32 val, char *cptr, void *mp) \loch\af1\dbch\af31505\hich\f1 \endash \hich\af1\dbch\af31505\loch\f1 enable \hich\af1\dbch\af31505\loch\f1 +logging of a line of the multipleser described by mp to the filename pointed to by cptr. If uptr is NULL, then val indicates the line number; otherwise, the unit numbe\hich\af1\dbch\af31505\loch\f1 +r within the associated device implies the line number. This function may be used as an MTAB validation routine. +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid2698330 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid2698330 \hich\af1\dbch\af31505\loch\f1 tstat }{\rtlch\fcs1 \af1 \ltrch\fcs0 +\b\f1\insrsid2698330\charrsid5979563 \hich\af1\dbch\af31505\loch\f1 tmxr_set_}{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\insrsid2698330 \hich\af1\dbch\af31505\loch\f1 no}{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\insrsid2698330\charrsid5979563 +\hich\af1\dbch\af31505\loch\f1 log}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid2698330 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int32 val, char *cptr, void *mp) \loch\af1\dbch\af31505\hich\f1 \endash }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid2698330 +\hich\af1\dbch\af31505\loch\f1 dis}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid2698330 \hich\af1\dbch\af31505\loch\f1 able \hich\af1\dbch\af31505\loch\f1 +logging of a line of the multipleser described by mp to the filename pointed to by cptr. If uptr is NULL, then val indicates the line number; otherwise, the unit numbe\hich\af1\dbch\af31505\loch\f1 +r within the associated device implies the line number. This function may be used as an MTAB validation routine.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid2698330 +\par +\par \hich\af1\dbch\af31505\loch\f1 tstat }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\f1\insrsid2698330\charrsid2698330 \hich\af1\dbch\af31505\loch\f1 tmxr_show_log}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid2698330 \hich\af1\dbch\af31505\loch\f1 + (FILE *st, UNIT *uptr, int32 val, void *mp) \loch\af1\dbch\af31505\hich\f1 \endash \hich\af1\dbch\af31505\loch\f1 outputs \hich\af1\dbch\af31505\loch\f1 the logging status of a line of the multiplexer describ\hich\af1\dbch\af31505\loch\f1 +ed by mp to stream st. If uptr is NULL, then val indicates the line number; otherwise, the unit number within the associated device implies the line \hich\af1\dbch\af31505\loch\f1 number.\hich\af1\dbch\af31505\loch\f1 + This function may be used as an MTAB display routine.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid2698330 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid2698330 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 tmxr_dscln}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int32 val, char *cptr, void *mp) \hich\f1 \endash \loch\f1 parse the string pointed to by }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 for a decimal line number. If the line number is valid, disconnect the \hich\af1\dbch\af31505\loch\f1 +specified line in the terminal multiplexer described by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 mp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +. The calling sequence allows }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_dscln}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to be used as an MTAB processing routine.}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid2698330 \hich\af1\dbch\af31505\loch\f1 A line connected via a tcp session will be disconnected, a line connected to a serial port will be closed\hich\af1\dbch\af31505\loch\f1 if the sim_switches +\loch\af1\dbch\af31505\hich\f1 \endash \hich\af1\dbch\af31505\loch\f1 C \hich\af1\dbch\af31505\loch\f1 flag is enabled when the routine is called, otherwise a \hich\af1\dbch\af31505\loch\f1 serial\hich\af1\dbch\af31505\loch\f1 +\hich\af1\dbch\af31505\loch\f1 port will have DTR dropped for 500ms and raised \hich\af1\dbch\af31505\loch\f1 again.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_set_lnorder}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr, int32 val, char *cptr, void *desc) \hich\f1 \endash \loch\f1 set the line connection order array ass\hich\af1\dbch\af31505\loch\f1 ociated with the TMXR structure pointed to by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . The string pointed to by }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is parsed for a semicolon-delimited list of ranges. Ranges are of the form: +\par +\par }\pard \ltrpar\ql \fi-2160\li3600\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin3600\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 line1-line2\tab ascending sequence from }{\rtlch\fcs1 \ab\af2 \ltrch\fcs0 +\b\f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 line1}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 to }{\rtlch\fcs1 \ab\af2 \ltrch\fcs0 \b\f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 line2}{\rtlch\fcs1 \af2 +\ltrch\fcs0 \f2\insrsid4550150 +\par \hich\af2\dbch\af31505\loch\f2 line1/length\tab ascending sequence from }{\rtlch\fcs1 \ab\af2 \ltrch\fcs0 \b\f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 line1}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 t +\hich\af2\dbch\af31505\loch\f2 o }{\rtlch\fcs1 \ab\af2 \ltrch\fcs0 \b\f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 line1}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 +}{\rtlch\fcs1 \ab\af2 \ltrch\fcs0 +\b\f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 length}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 -1 +\par \hich\af2\dbch\af31505\loch\f2 ALL\tab ascending sequence of all lines defined by the multiplexer +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 The line order array must provide an int32 element for each line. The calling sequence allows }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_set_lnorder}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to be used as an MTAB processing routine. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_show_lno\hich\af1\dbch\af31505\loch\f1 rder}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (FILE *st, UNIT *uptr, int32 val, void *desc) \hich\f1 \endash \loch\f1 output the line connection order associated multiplexer (TMXR *) }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af0 +\ltrch\fcs0 \insrsid4550150 \hich\af0\dbch\af31505\loch\f0 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to stream }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . The order is rendered as a semicolon-delimited list of ranges. The calling sequence allows }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +tmxr_show_lnorder}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to be us\hich\af1\dbch\af31505\loch\f1 ed as an MTAB processing routine. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_show_summ}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (FILE *st, UNIT *uptr, int32 val, void *desc) \hich\f1 \endash \loch\f1 outputs the summary status of the multiplexer (TMXR *) }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to stream }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_show_cstat}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (FILE *st, UNIT *uptr, int32 val, void *desc) \hich\f1 \endash \loch\f1 outpu\hich\af1\dbch\af31505\loch\f1 ts either the connections (val = 1) or the statistics (val = 0) of the multiplexer (TMXR *) }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 desc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to stream }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Also checks for multiplexer not attached, or all lines disconnected. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tmxr_show_lines}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (FILE *st, UNIT *uptr, int32 val, void *desc) \hich\f1 \endash \loch\f1 outp\hich\af1\dbch\af31505\loch\f1 uts the number of lines in the terminal multiplexer (TMXR *) I to stream I. +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 +\par }\pard \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid7674256 {\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid7674256 +\hich\af1\dbch\af31505\loch\f1 tmxr_s}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 et_modem_control_passthru}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 (}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 TMXR *mp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 ) \hich\f1 \endash \loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 +Enables modem cont\hich\af1\dbch\af31505\loch\f1 rol passthru behaviors, and disables \hich\af1\dbch\af31505\loch\f1 internal \hich\af1\dbch\af31505\loch\f1 manipulation \hich\af1\dbch\af31505\loch\f1 +of DTR (&RTS) by tmxr apis. Enables the tmxr_set_get_modem_bits and tmxr_set_config_line apis. +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 tmxr_s\hich\af1\dbch\af31505\loch\f1 et_modem_control_passthru}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 +\hich\af1\dbch\af31505\loch\f1 (\hich\af1\dbch\af31505\loch\f1 TMXR *mp\hich\af1\dbch\af31505\loch\f1 ) \hich\f1 \endash \loch\f1 \hich\af1\dbch\af31505\loch\f1 Enables modem cont\hich\af1\dbch\af31505\loch\f1 rol passthru behaviors, and disables +\hich\af1\dbch\af31505\loch\f1 internal \hich\af1\dbch\af31505\loch\f1 manipulation \hich\af1\dbch\af31505\loch\f1 of DTR (&RTS) by tmxr apis. Enables the tmxr_set_get_modem_bits and tmxr_set_config_line apis. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 tmxr_clear}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 _modem_control_passthru}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 (\hich\af1\dbch\af31505\loch\f1 TMXR *mp\hich\af1\dbch\af31505\loch\f1 ) \hich\f1 \endash \loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 Dis}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 ables modem cont\hich\af1\dbch\af31505\loch\f1 rol passthru behaviors, and }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 en}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 ables \hich\af1\dbch\af31505\loch\f1 internal \hich\af1\dbch\af31505\loch\f1 manipulation \hich\af1\dbch\af31505\loch\f1 of DTR (&RTS) by tmxr apis. }{\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid7674256 \hich\af1\dbch\af31505\loch\f1 Dis}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 \hich\af1\dbch\af31505\loch\f1 ables the tmxr_set_get_modem_bits and tmxr_set_config_line apis. +\par +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid9462171 \hich\af1\dbch\af31505\loch\f1 t_\hich\af1\dbch\af31505\loch\f1 stat }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\insrsid9462171\charrsid9462171 \hich\af1\dbch\af31505\loch\f1 tmxr_set_get_modem_bits}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid9462171 \hich\af1\dbch\af31505\loch\f1 (TMLN *lp, int32 bits_to_set, int32 bits_\hich\af1\dbch\af31505\loch\f1 to_clear\hich\af1\dbch\af31505\loch\f1 , int32 *incoming_bits) \loch\af1\dbch\af31505\hich\f1 \endash +\hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 For \hich\af1\dbch\af31505\loch\f1 a line connected to a serial port on a TMXR device with modem_control_passthru enabled, then the bits_to_set and/or bits_to_clear ( +\hich\af1\dbch\af31505\loch\f1 DTR and RTS) are changed and if incoming_bits is not NULL, then the current modem bits are returned (DCD,RNG,CTS, DSR).}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid7674256 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid9462171 +\par \hich\af1\dbch\af31505\loch\f1 t_\hich\af1\dbch\af31505\loch\f1 stat }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\insrsid9462171\charrsid9462171 \hich\af1\dbch\af31505\loch\f1 tmxr_set_config_line}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid9462171 +\hich\af1\dbch\af31505\loch\f1 (TMLN *lp, \hich\af1\dbch\af31505\loch\f1 char \hich\af1\dbch\af31505\loch\f1 *config\hich\af1\dbch\af31505\loch\f1 ) \loch\af1\dbch\af31505\hich\f1 \endash \hich\af1\dbch\af31505\loch\f1 set\hich\af1\dbch\af31505\loch\f1 +s the line configuration \hich\af1\dbch\af31505\loch\f1 (speed, parity, \hich\af1\dbch\af31505\loch\f1 character size, \hich\af1\dbch\af31505\loch\f1 stopbits) \hich\af1\dbch\af31505\loch\f1 on a serial port\hich\af1\dbch\af31505\loch\f1 . +\hich\af1\dbch\af31505\loch\f1 C\hich\af1\dbch\af31505\loch\f1 onf\hich\af1\dbch\af31505\loch\f1 ig \hich\af1\dbch\af31505\loch\f1 is a string of the form: \hich\af1\dbch\af31505\loch\f1 9600-8N1. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_\hich\af1\dbch\af31505\loch\f1 stat }{\rtlch\fcs1 \af1 \ltrch\fcs0 \b\insrsid9462171\charrsid3806017 \hich\af1\dbch\af31505\loch\f1 tmxr_set_line_unit}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid9462171 +\hich\af1\dbch\af31505\loch\f1 (TM\hich\af1\dbch\af31505\loch\f1 XR\hich\af1\dbch\af31505\loch\f1 *\hich\af1\dbch\af31505\loch\f1 mp, int line\hich\af1\dbch\af31505\loch\f1 , UNIT *uptr) }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid3806017 +\loch\af1\dbch\af31505\hich\f1 \endash }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid9462171 \hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid3806017 \hich\af1\dbch\af31505\loch\f1 Declare \hich\af1\dbch\af31505\loch\f1 +which unit polls for input on a given line (only needed if the input polling unit is different than the \hich\af1\dbch\af31505\loch\f1 unit provided when\hich\af1\dbch\af31505\loch\f1 the multiplexer was attached.}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid9462171 +\par }\pard \ltrpar\s21\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid3806017 {\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid2698330 +\par }\pard \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid8129972 +\par }\pard \ltrpar\s21\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid8129972 {\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid8129972 \hich\af1\dbch\af31505\loch\f1 +The OS dependent serial I/O and socket routines should not need to be accessed by the terminal simulators. +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 +\par {\*\bkmkstart _Toc343577918}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 6.3\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Magnetic Tape Emulation Library{\*\bkmkend _Toc343577918} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SIMH supports the use of emulated magn\hich\af1\dbch\af31505\loch\f1 \hich\f1 +etic tapes. Magnetic tapes are emulated as disk files containing both data records and metadata markers; the format is fully described in the paper \'93\loch\f1 \hich\f1 SIMH Magtape Representation and Handling\'94\loch\f1 +. SIMH provides a supporting library, sim_tape.c (and its heade\hich\af1\dbch\af31505\loch\f1 r\hich\af1\dbch\af31505\loch\f1 + file, sim_tape.h), that abstracts handling of magnetic tapes. This allows support for multiple tape formats, without change to magnetic device simulators. +\par +\par \hich\af1\dbch\af31505\loch\f1 The magtape library does not require any special data structures. However, it does define some ad\hich\af1\dbch\af31505\loch\f1 ditional unit flags: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 MTUF_WLK\tab \tab unit is write locked +\par +\par \hich\af1\dbch\af31505\loch\f1 If magtape simulators need to define private unit flags, those flags should begin at bit number MTUF_V_UF instead of UNIT_V_UF. The magtape library maintains the current magtape position in the }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 pos}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 fi\hich\af1\dbch\af31505\loch\f1 eld of the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 UNIT}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 structure. +\par +\par \hich\af1\dbch\af31505\loch\f1 Library sim_tape.c provides the following routines to support emulated magnetic tapes: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_tape_attach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, char *cptr) \hich\f1 \endash \loch\f1 Attach tape unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 uptr }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to file }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Tape +\par \hich\af1\dbch\af31505\loch\f1 Simulators should call this routine, rather tha\hich\af1\dbch\af31505\loch\f1 n the standard attach_unit routine, to allow for future expansion of format support. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_detach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash +\loch\f1 Detach tape unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 from its current file. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_set_fmt}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr, int32 val, char *cptr, void *desc) \hich\f1 \endash \loch\f1 Set the tape\hich\af1\dbch\af31505\loch\f1 format for unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to the format specified by string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_show_fmt}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (FILE *st, UNIT *uptr, int32 val, void *desc) \hich\f1 \endash \loch\f1 Write the tape format for unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 to the file specified by descriptor }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_set_capac}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int3 +\hich\af1\dbch\af31505\loch\f1 2 val, char *cptr, void *desc) \hich\f1 \endash \loch\f1 Set the tape capacity for unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 to the capacity, in MB, specified by string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_show_capac}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (FILE *st, UNIT *uptr, int32 val, void *desc) \hich\f1 \endash \loch\f1 Write the capacity for unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 to the file specified by des\hich\af1\dbch\af31505\loch\f1 criptor }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_rdrecf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr, uint8 *buf, t_mtrlnt *tbc, t_mtrlnt max) \hich\f1 \endash \loch\f1 Forward read the next record on unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 into buffer }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 buf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 of size }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 max}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Return the actual record size in }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tbc}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 . +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_rdrecr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, uint8 *buf, t_mtr +\hich\af1\dbch\af31505\loch\f1 lnt *tbc, t_mtrlnt max) \hich\f1 \endash \loch\f1 Reverse read the next record on unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 into buffer }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 buf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 of size }{ +\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 max}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Return the actual record size in }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tbc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . Note that the record is returned in forward order, that is, byte 0 of the record is stored in buf[0], and so on. + +\par +\par \hich\af1\dbch\af31505\loch\f1 t_sta\hich\af1\dbch\af31505\loch\f1 t }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_wrrecf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr, uint8 buf, t_mtrlnt tbc) \hich\f1 \endash \loch\f1 Write buffer }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + of size }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tbc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 as the next record on unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape sprecf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, t_mtrlnt *tbc) +\hich\f1 \endash \loch\f1 Space unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + forward one record. The size of the record is returned in }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 tbc}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_sprecr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, t_mtrlnt *tbc) +\hich\f1 \endash \loch\f1 Space unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + reverse one record. The size of the record is returned in tbc. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_wrtmk}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash +\loch\f1 Write a tape mark on unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_wreom}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash +\loch\f1 Write an end-of\hich\af1\dbch\af31505\loch\f1 -medium marker on unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (this effectively erases the rest of the tape). +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_wrgap}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr, uint32 gaplen, uint32 bpi) \hich\f1 \endash \loch\f1 Write an erase gap on unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 of }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 gaplen}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + tenths of an inch in length at a tape density of }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 bpi}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 bits per inch. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_st\hich\af1\dbch\af31505\loch\f1 at }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_rewind}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr) \hich\f1 \endash \loch\f1 Rewind unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +. This operation succeeds whether or not the unit is attached to a file. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_reset}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash +\loch\f1 Reset unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . This routine should be called when a tape unit is reset. + +\par +\par \hich\af1\dbch\af31505\loch\f1 t_bool }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_bo\hich\af1\dbch\af31505\loch\f1 t}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + (UNIT *uptr) \hich\f1 \endash \loch\f1 Return TRUE if unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + is at beginning-of-tape. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_bool }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape wrp}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash +\loch\f1 Return TRUE if unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is write-protected. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_bool }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_eot}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash +\loch\f1 Return TRUE if unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 has exceed the capacity specified of the specif +\hich\af1\dbch\af31505\loch\f1 ied unit (kept in uptr->capac). +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Sim_tape_attach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_tape_detach, sim_tape_set_fmt,}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +sim_tape_show_fmt, sim_tape_set_capac}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 , and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_tape_show_capac}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 return standard SCP status codes; the other magtape library routines return return private codes for success\hich\af1\dbch\af31505\loch\f1 + and failure. The currently defined magtape status codes are: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_OK\tab \tab operation successful +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_UNATT\tab \tab unit is not attached to a file +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_FMT\tab \tab unit specifies an unsupported tape file format +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_IOERR\tab \tab host operating system I/O error during operati\hich\af1\dbch\af31505\loch\f1 on +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_INVRL\tab \tab invalid record length (exceeds maximum allowed) +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_RECE\tab \tab record header contains error flag +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_TMK\tab \tab tape mark encountered +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_BOT\tab \tab beginning of tape encountered during reverse operation +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_EOM\tab \tab end of medium encountered +\par \tab \hich\af1\dbch\af31505\loch\f1 MTSE_WRP\tab \tab \hich\af1\dbch\af31505\loch\f1 write protected unit during write operation +\par +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Sim_tape_set_fmt,}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_tape_show_fmt, sim_tape_set_capac, }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 +sim_tape_show_capac}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 should be referenced by an entry in the tape device\hich\f1 \rquote \loch\f1 s modifier list, as follows: +\par +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \hich\af2\dbch\af31505\loch\f2 MTAB tape_mod[] = \{ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \{\hich\af2\dbch\af31505\loch\f2 \hich\f2 MTAB_XTD|MTAB_VDV, 0, \'93\loch\f2 F\hich\af2\dbch\af31505\loch\f2 +\hich\f2 ORMAT\'94\loch\f2 \hich\f2 , \'93\loch\f2 \hich\f2 FORMAT\'94, +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \tab \hich\af2\dbch\af31505\loch\f2 \tab &sim_tape_set_fmt, &sim_tape_show_fmt, NULL \}, +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \{\hich\af2\dbch\af31505\loch\f2 \hich\f2 MTAB_XTD|MTAB_VUN, 0, \'93\loch\f2 \hich\f2 CAPACITY\'94\loch\f2 +\hich\f2 , \'93\loch\f2 \hich\f2 CAPACITY\'94, +\par }\pard \ltrpar\ql \li1440\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin1440\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 &sim_tape_set_capac, &sim_tape_show_capac, NULL \}\hich\f2 , \'85 +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \}\hich\af2\dbch\af31505\loch\f2 ; +\par {\*\bkmkstart _Toc343577919}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 6.4\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0\pararsid9973523 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid9973523 \hich\af1\dbch\af31505\loch\f1 Disk Emulation Library{\*\bkmkend _Toc343577919} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid9973523 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid9973523 +\par \hich\af1\dbch\af31505\loch\f1 SIMH supports the use of disk drives. Disk drives as d\hich\af1\dbch\af31505\loch\f1 \hich\f1 isk files containing both data records and metadata markers; the format is fully described in the paper \'93\loch\f1 \hich\f1 +SIMH Magtape Representation and Handling\'94\loch\f1 . SIMH provides a supporting library, sim_disk.c (and its header file, sim_disk.h), that abstracts handling \hich\af1\dbch\af31505\loch\f1 o\hich\af1\dbch\af31505\loch\f1 +f disk drives tapes. This allows support for disk formats, without change to magnetic device simulators. +\par +\par \hich\af1\dbch\af31505\loch\f1 The disk library does not require any special data structures. However, it does define some additional unit flags: +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 DKUF_WLK\tab \tab unit is write locked +\par +\par \hich\af1\dbch\af31505\loch\f1 If magtape simulators need to define private unit flags, those flags should begin at bit number DKUF_V_UF instead of UNIT_V_UF. The disk library maintains the current magtape position in the }{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 pos}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 field of the }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 UNIT}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 structure. +\par \hich\af1\dbch\af31505\loch\f1 Library sim_tape.c provides th\hich\af1\dbch\af31505\loch\f1 e following routines to support emulated magnetic tapes: +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid11167734 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 +\hich\af1\dbch\af31505\loch\f1 sim_disk_attach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, char *cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 , s}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 ize_t sector_size, size_t xfer_element_size, t_bool dontautosize, uint32 debugbit, const char *drivetype, uint32 pdp11_tracksize, int completion_dela\hich\af1\dbch\af31505\loch\f1 y) \hich\f1 +\endash \loch\f1 Attach disk unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 uptr }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 to file }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 . Disk Simulators should call this routine, rather than the standard attach_unit routine, +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid9973523 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid11167734 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 sim_disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 +\hich\af1\dbch\af31505\loch\f1 _detach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash \loch\f1 Detach }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 disk}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 +\hich\af1\dbch\af31505\loch\f1 from its current file. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 sim_disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _set_fmt}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int\hich\af1\dbch\af31505\loch\f1 32 val, char *cptr, void *desc) \hich\f1 \endash \loch\f1 Set the }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid11167734 +\hich\af1\dbch\af31505\loch\f1 disk}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 format for unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 to the format specified by string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 sim_}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _show_fmt}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 (FILE *st, UNIT *uptr, int32 v}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 +al, void *desc) \hich\f1 \endash \loch\f1 Write the disk}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 format for unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 uptr}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 to the file specified by descriptor }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 . + +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 sim_disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _set_capac}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int32 val, char *}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 cptr, void *desc) \hich\f1 \endash \loch\f1 Set the disk}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 capacity for unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 + to the capacity, in MB, specified by string }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 cptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 . +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 sim_disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _show_capac}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 (FILE *st, UNIT *uptr, int32 val, void *desc) \hich\f1 \endash \loch\f1 Write the capac\hich\af1\dbch\af31505\loch\f1 ity for unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 +\hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 to the file specified by descriptor }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 st}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid9973523 . +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid9973523 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid9973523 +\par }\pard \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid11167734 {\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid11167734 +\hich\af1\dbch\af31505\loch\f1 sim_disk_rdsect}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, , t_seccnt *sectstoread) \hich\f1 \endash \loch\f1 + Read up to sectstoread sectors from sector number lba on unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 \hich\af1\dbch\af31505\loch\f1 into buffer }{ +\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 buf}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 \hich\af1\dbch\af31505\loch\f1 . Retur\hich\af1\dbch\af31505\loch\f1 n the number of sectors read in }{\rtlch\fcs1 +\ai\af1 \ltrch\fcs0 \i\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 sectsread}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 . +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid11167734 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid11167734 +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid11167734 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 sim_disk_rdsect_a}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 +\hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, , t_seccnt *sectstoread}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 , DISK_PCALLBACK callback}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 ) \hich\f1 \endash \loch\f1 Read up to sectstoread sectors from sector number lba on unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid11167734 \hich\af1\dbch\af31505\loch\f1 into buffer\hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 buf}{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid15957281 +\hich\af1\dbch\af31505\loch\f1 asynchronously}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 \hich\af1\dbch\af31505\loch\f1 . Return the number of sectors read in }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 +sectsread}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 , and call callback routine on completion.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid11167734 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid11167734 +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid15957281 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 sim_disk_wrsect}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 +\hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, , t_seccnt *sectstowrite) \hich\f1 \endash \loch\f1 Write sectstowrite sectors from b\hich\af1\dbch\af31505\loch\f1 +uffer buf to disk sector number lba on unit uptr. Return the number of sectors written in }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 sectswritten}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 . +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid15957281 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid15957281 +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid15957281 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 sim_disk_wrsect_a}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 +\hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, , t_seccnt *sectstowrite, DISK_PCALLBACK callback) \hich\f1 \endash \loch\f1 Write sectst\hich\af1\dbch\af31505\loch\f1 +owrite sectors from buffer buf to disk sector number lba on unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \ai\af1 +\ltrch\fcs0 \i\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 asynchronously}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 . Return the number of sectors written in }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid15957281 +\hich\af1\dbch\af31505\loch\f1 sectswritten}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 , and call callback routine on completion. +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid15957281 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid15957281 +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid11167734 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid11167734 \hich\af1\dbch\af31505\loch\f1 sim_}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid15957281 +\hich\af1\dbch\af31505\loch\f1 disk_unload}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash \loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 +Unload or detach a disk as needed.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid11167734 +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid11167734 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid11167734 +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid15957281 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 sim_disk_set_asynch}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 +\hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int latency) \hich\f1 \endash \loch\f1 Enable asynchronouos operation for I/O to disk unit uptr. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 sim_disk_clr_asynch}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr, int latency) +\hich\f1 \endash \loch\f1 Disable asynchronouos operation for I/O to disk unit uptr. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_stat }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 sim_disk_reset}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 (UNI\hich\af1\dbch\af31505\loch\f1 +T *uptr) \hich\f1 \endash \loch\f1 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid13897431 \hich\af1\dbch\af31505\loch\f1 Reset unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 . This routine should be called when a tape unit is reset.}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 +\par +\par \hich\af1\dbch\af31505\loch\f1 t_bool }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 sim_disk_isavailable }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash +\loch\f1 Check to see if disk is available for I/O, return TRUE if so. +\par +\par \hich\af1\dbch\af31505\loch\f1 t_bool }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid15957281 \hich\af1\dbch\af31505\loch\f1 sim_disk_isavailable_a }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 +(UNIT *uptr, DISK_PCALLBACK callb\hich\af1\dbch\af31505\loch\f1 ack) \hich\f1 \endash \loch\f1 Check to see if disk is available for I/O asynchronously. Return }{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid13897431 \hich\af1\dbch\af31505\loch\f1 TRUE}{ +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 \hich\af1\dbch\af31505\loch\f1 if so. +\par +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid13897431 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15957281 \hich\af0\dbch\af31505\loch\f0 t_}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid13897431 \hich\af0\dbch\af31505\loch\f0 bool}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15957281 \hich\af0\dbch\af31505\loch\f0 }{ +\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid15957281 \hich\af0\dbch\af31505\loch\f0 sim_disk_}{\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\insrsid13897431 \hich\af0\dbch\af31505\loch\f0 wrp}{\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid15957281 +\hich\af0\dbch\af31505\loch\f0 (UNIT *uptr) \hich\f0 \endash \loch\f0 }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 Return TRUE if unit }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid13897431 +\hich\af1\dbch\af31505\loch\f1 uptr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 is write-protected. +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid15957281 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid15957281 +\par }\pard \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid13897431 {\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid13897431 \hich\af1\dbch\af31505\loch\f1 t_addr }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\insrsid13897431 +\hich\af1\dbch\af31505\loch\f1 sim_disk_size}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid13897431 \hich\af1\dbch\af31505\loch\f1 (UNIT *uptr) \hich\f1 \endash \loch\f1 get disk size +\par +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid9973523 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 +\ab\af1 \ltrch\fcs0 \b\f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 Sim_disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _attach}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 +, }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 sim_disk_detach, sim_\hich\af1\dbch\af31505\loch\f1 disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _set_fmt,}{\rtlch\fcs1 +\af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 sim_disk_show_fmt, sim_disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 +\hich\af1\dbch\af31505\loch\f1 _set_capac}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 , and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 sim_tape_disk}{\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _capac}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 return standard SCP status codes; the other }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid13897431 +\hich\af1\dbch\af31505\loch\f1 disk}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 library routines return return private codes for success and failure. }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid13897431 +\hich\af1\dbch\af31505\loch\f1 Success status is DKSE_OK and any other value is an error. \hich\af1\dbch\af31505\loch\f1 Errno usually will have the appropriate error code}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 : + +\par +\par \tab \hich\af1\dbch\af31505\loch\f1 DKSE_OK\tab \tab operation successful +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid13897431 +\par }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 +\par }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 Sim_disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _set_fmt,}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 +\hich\af1\dbch\af31505\loch\f1 }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 sim_}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 +\b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _show_fmt, sim_}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 +_set_capac, }{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 and }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 sim_}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid13897431 +\hich\af1\dbch\af31505\loch\f1 disk}{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 _show_capac}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 should be referenced by an entry in the } +{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid13897431 \hich\af1\dbch\af31505\loch\f1 disk}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 \hich\af1\dbch\af31505\loch\f1 device\hich\f1 \rquote \loch\f1 s modifier list, as follows: +\par +\par }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid9973523 \tab \hich\af2\dbch\af31505\loch\f2 MTAB \hich\af2\dbch\af31505\loch\f2 tape_mod[] = \{ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid9973523 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid9973523 \{\hich\af2\dbch\af31505\loch\f2 \hich\f2 MTAB_XTD|MTAB_VDV, 0, \'93\loch\f2 \hich\f2 FORMAT +\'94\loch\f2 \hich\f2 , \'93\loch\f2 \hich\f2 FORMAT\'94, +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid9973523 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid9973523 \tab \hich\af2\dbch\af31505\loch\f2 \tab }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid13897431 +\hich\af2\dbch\af31505\loch\f2 &sim_disk}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid9973523 \hich\af2\dbch\af31505\loch\f2 _set_fmt, &sim_}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid13897431 \hich\af2\dbch\af31505\loch\f2 disk}{\rtlch\fcs1 \af2 \ltrch\fcs0 +\f2\insrsid9973523 \hich\af2\dbch\af31505\loch\f2 _show_fmt, NULL \}, +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid9973523 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid9973523 \{\hich\af2\dbch\af31505\loch\f2 \hich\f2 MTAB_XTD|MTAB_VUN, 0, \'93\loch\f2 \hich\f2 CAPACITY +\'94\loch\f2 \hich\f2 , \'93\loch\f2 \hich\f2 CAPACITY\'94, +\par }\pard \ltrpar\ql \li1440\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin1440\itap0\pararsid9973523 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid13897431 \hich\af2\dbch\af31505\loch\f2 &sim_disk}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid9973523 +\hich\af2\dbch\af31505\loch\f2 _set_capac, &sim_}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid13897431 \hich\af2\dbch\af31505\loch\f2 disk}{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid9973523 \hich\af2\dbch\af31505\loch\f2 _show_capac, NULL \}\hich\f2 , \'85 + +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0\pararsid9973523 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid9973523 \}\hich\af2\dbch\af31505\loch\f2 ; +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0\pararsid9973523 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid9973523 +\par {\*\bkmkstart _Toc343577920}{\listtext\pard\plain\ltrpar \s2 \rtlch\fcs1 \ab\ai\af0 \ltrch\fcs0 \b\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 6.5\tab}}\pard\plain \ltrpar\s2\ql \fi-390\li390\ri0\sb240\sa60\keepn\widctlpar +\jclisttab\tx390\wrapdefault\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin390\itap0 \rtlch\fcs1 \ab\ai\af1\afs24\alang1025 \ltrch\fcs0 \b\i\fs24\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 Breakpoint Support{\*\bkmkend _Toc343577920} +\par }\pard\plain \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 SCP provides unde\hich\af1\dbch\af31505\loch\f1 rlying mechanisms to track multiple breakpoints of different types. Most VM\hich\f1 \rquote \loch\f1 +s implement at least instruction execution breakpoints (type E); but a VM might also allow for break on read (type R), write (type W), and so on. Up to 26 different breakpoint t\hich\af1\dbch\af31505\loch\f1 y\hich\af1\dbch\af31505\loch\f1 +pes, identified by the letters A through Z, are supported. +\par +\par \hich\af1\dbch\af31505\loch\f1 The VM interface to the breakpoint package consists of three variables and one subroutine: +\par +\par }\pard\plain \ltrpar\s21\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af1\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af1\hich\af1\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1 +\ltrch\fcs0 \b\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_brk_types}{\rtlch\fcs1 \af1 \ltrch\fcs0 \insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 \endash \loch\f1 + initialized by the VM (usually in the CPU reset routine) to a mask of all supported brea\hich\af1\dbch\af31505\loch\f1 kpoints. +\par }\pard\plain \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\loch\af0\hich\af0\dbch\af31505\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \tab }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_brk_dflt}{\rtlch\fcs1 \af1 +\ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 \hich\f1 \endash \loch\f1 initialized by the VM to the mask for the default breakpoint type. +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_brk_summ}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 \hich\f1 \endash \loch\f1 maintained by SCP, providing a bit mask summary of whether any breakpoints of a particular type have been defined. +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 If the VM only implements one t\hich\af1\dbch\af31505\loch\f1 ype of breakpoint, then }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_brk_summ}{\rtlch\fcs1 \af1 \ltrch\fcs0 +\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is non-zero if any breakpoints are set. +\par +\par \hich\af1\dbch\af31505\loch\f1 To test whether a breakpoint of particular type is set for an address, the VM calls +\par +\par }\pard \ltrpar\ql \li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 uint32l }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_brk_test}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 (t_addr addr, int32 typ) \hich\f1 \endash \loch\f1 test to see if a breakpoint of type }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 +\i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 typ}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 is se\hich\af1\dbch\af31505\loch\f1 t for location }{\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 addr}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 ; returns 0 if no, and a bit mask of all breakpoints that match typ if yes +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 Because }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_brk_test}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 + can be a lengthy procedure, it is usually prefaced with a test of }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 sim_brk_summ}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 : +\par +\par \tab }{\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 if (sim_brk_summ && sim_brk_test (PC, SWMASK (\hich\f2 \lquote \loch\f2 E\hich\f2 \rquote \loch\f2 ))) \{ +\par }\pard \ltrpar\ql \fi720\li720\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin720\itap0 {\rtlch\fcs1 \af2 \ltrch\fcs0 \f2\insrsid4550150 \hich\af2\dbch\af31505\loch\f2 \} +\par }\pard \ltrpar\ql \li0\ri0\widctlpar\wrapdefault\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 +\par \hich\af1\dbch\af31505\loch\f1 +To accommodate more complex breakpoint schemes, SCP implements a concept of breakpoint spaces. Each breakpoint space is an orthogonal collection of breakpoints that are tracked independently. For example, in a symmetric multiprocessing +\hich\af1\dbch\af31505\loch\f1 simulation, breakpoint spaces could be assigned to each CPU to distinguish E (execution) breakpoints for different processors. SCP supports up to 64 breakpoint spaces; the space is specified by bits <31:26> of the }{ +\rtlch\fcs1 \ai\af1 \ltrch\fcs0 \i\f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 typ}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 argument to }{\rtlch\fcs1 \ab\af1 \ltrch\fcs0 \b\f1\insrsid4550150 +\hich\af1\dbch\af31505\loch\f1 sim_brk_test}{\rtlch\fcs1 \af1 \ltrch\fcs0 \f1\insrsid4550150 \hich\af1\dbch\af31505\loch\f1 . By default\hich\af1\dbch\af31505\loch\f1 , there is only one breakpoint space (space 0). +\par +\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a +9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad +5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 +b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 +0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 +a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f +c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 +0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 +a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 +6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b +4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b +4757e8d3f729e245eb2b260a0238fd010000ffff0300504b03041400060008000000210030dd4329a8060000a41b0000160000007468656d652f7468656d652f +7468656d65312e786d6cec594f6fdb3614bf0fd87720746f6327761a07758ad8b19b2d4d1bc46e871e698996d850a240d2497d1bdae38001c3ba618715d86d87 +615b8116d8a5fb34d93a6c1dd0afb0475292c5585e9236d88aad3e2412f9e3fbff1e1fa9abd7eec70c1d1221294fda5efd72cd4324f1794093b0eddd1ef62fad +79482a9c0498f184b4bd2991deb58df7dfbb8ad755446282607d22d771db8b944ad79796a40fc3585ee62949606ecc458c15bc8a702910f808e8c66c69b9565b +5d8a314d3c94e018c8de1a8fa94fd05093f43672e23d06af89927ac06762a049136785c10607758d9053d965021d62d6f6804fc08f86e4bef210c352c144dbab +999fb7b4717509af678b985ab0b6b4ae6f7ed9ba6c4170b06c788a705430adf71bad2b5b057d03606a1ed7ebf5babd7a41cf00b0ef83a6569632cd467faddec9 +699640f6719e76b7d6ac355c7c89feca9cccad4ea7d36c65b258a206641f1b73f8b5da6a6373d9c11b90c537e7f08dce66b7bbeae00dc8e257e7f0fd2badd586 +8b37a088d1e4600ead1ddaef67d40bc898b3ed4af81ac0d76a197c86826828a24bb318f3442d8ab518dfe3a20f000d6458d104a9694ac6d88728eee2782428d6 +0cf03ac1a5193be4cbb921cd0b495fd054b5bd0f530c1931a3f7eaf9f7af9e3f45c70f9e1d3ff8e9f8e1c3e3073f5a42ceaa6d9c84e5552fbffdeccfc71fa33f +9e7ef3f2d117d57859c6fffac327bffcfc793510d26726ce8b2f9ffcf6ecc98baf3efdfdbb4715f04d814765f890c644a29be408edf3181433567125272371be +15c308d3f28acd249438c19a4b05fd9e8a1cf4cd296699771c393ac4b5e01d01e5a30a787d72cf1178108989a2159c77a2d801ee72ce3a5c545a6147f32a9979 +3849c26ae66252c6ed637c58c5bb8b13c7bfbd490a75330f4b47f16e441c31f7184e140e494214d273fc80900aedee52ead87597fa824b3e56e82e451d4c2b4d +32a423279a668bb6690c7e9956e90cfe766cb37b077538abd27a8b1cba48c80acc2a841f12e698f13a9e281c57911ce298950d7e03aba84ac8c154f8655c4f2a +f074481847bd804859b5e696007d4b4edfc150b12addbecba6b18b148a1e54d1bc81392f23b7f84137c2715a851dd0242a633f900710a218ed715505dfe56e86 +e877f0034e16bafb0e258ebb4faf06b769e888340b103d331115bebc4eb813bf83291b63624a0d1475a756c734f9bbc2cd28546ecbe1e20a3794ca175f3fae90 +fb6d2dd99bb07b55e5ccf68942bd0877b23c77b908e8db5f9db7f024d9239010f35bd4bbe2fcae387bfff9e2bc289f2fbe24cfaa301468dd8bd846dbb4ddf1c2 +ae7b4c191ba8292337a469bc25ec3d411f06f53a73e224c5292c8de0516732307070a1c0660d125c7d44553488700a4d7bddd3444299910e254ab984c3a219ae +a4adf1d0f82b7bd46cea4388ad1c12ab5d1ed8e1153d9c9f350a3246aad01c6873462b9ac05999ad5cc988826eafc3acae853a33b7ba11cd1445875ba1b236b1 +399483c90bd560b0b0263435085a21b0f22a9cf9356b38ec6046026d77eba3dc2dc60b17e92219e180643ed27acffba86e9c94c7ca9c225a0f1b0cfae0788ad5 +4adc5a9aec1b703b8b93caec1a0bd8e5de7b132fe5113cf312503b998e2c2927274bd051db6b35979b1ef271daf6c6704e86c73805af4bdd476216c26593af84 +0dfb5393d964f9cc9bad5c313709ea70f561ed3ea7b053075221d51696910d0d339585004b34272bff7213cc7a510a5454a3b349b1b206c1f0af490176745d4b +c663e2abb2b34b23da76f6352ba57ca2881844c1111ab189d8c7e07e1daaa04f40255c77988aa05fe06e4e5bdb4cb9c5394bbaf28d98c1d971ccd20867e556a7 +689ec9166e0a522183792b8907ba55ca6e943bbf2a26e52f48957218ffcf54d1fb09dc3eac04da033e5c0d0b8c74a6b43d2e54c4a10aa511f5fb021a07533b20 +5ae07e17a621a8e082dafc17e450ffb739676998b48643a4daa7211214f623150942f6a02c99e83b85583ddbbb2c4996113211551257a656ec1139246ca86be0 +aadedb3d1441a89b6a929501833b197fee7b9641a3503739e57c732a59b1f7da1cf8a73b1f9bcca0945b874d4393dbbf10b1680f66bbaa5d6f96e77b6f59113d +316bb31a795600b3d256d0cad2fe354538e7566b2bd69cc6cbcd5c38f0e2bcc63058344429dc2121fd07f63f2a7c66bf76e80d75c8f7a1b622f878a18941d840 +545fb28d07d205d20e8ea071b283369834296bdaac75d256cb37eb0bee740bbe278cad253b8bbfcf69eca23973d939b97891c6ce2cecd8da8e2d343578f6648a +c2d0383fc818c798cf64e52f597c740f1cbd05df0c264c49134cf09d4a60e8a107260f20f92d47b374e32f000000ffff0300504b030414000600080000002100 +0dd1909fb60000001b010000270000007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f7 +8277086f6fd3ba109126dd88d0add40384e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89 +d93b64b060828e6f37ed1567914b284d262452282e3198720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd500 +1996509affb3fd381a89672f1f165dfe514173d9850528a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100e9de0f +bfff0000001c0200001300000000000000000000000000000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6 +a7e7c0000000360100000b00000000000000000000000000300100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a +0000001c00000000000000000000000000190200007468656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d00140006000800000021 +0030dd4329a8060000a41b00001600000000000000000000000000d60200007468656d652f7468656d652f7468656d65312e786d6c504b01022d001400060008 +00000021000dd1909fb60000001b0100002700000000000000000000000000b20900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000ad0a00000000} +{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d +617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 +6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 +656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} +{\*\latentstyles\lsdstimax267\lsdlockeddef0\lsdsemihiddendef1\lsdunhideuseddef1\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal; +\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdlocked0 heading 1;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdlocked0 heading 2;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdlocked0 heading 3;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4; +\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9; +\lsdunhideused0 \lsdpriority39 \lsdlocked0 toc 1;\lsdunhideused0 \lsdpriority39 \lsdlocked0 toc 2;\lsdunhideused0 \lsdpriority39 \lsdlocked0 toc 3;\lsdunhideused0 \lsdlocked0 toc 4;\lsdunhideused0 \lsdlocked0 toc 5;\lsdunhideused0 \lsdlocked0 toc 6; +\lsdunhideused0 \lsdlocked0 toc 7;\lsdunhideused0 \lsdlocked0 toc 8;\lsdunhideused0 \lsdlocked0 toc 9;\lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority10 \lsdlocked0 Title; +\lsdunhideused0 \lsdlocked0 Default Paragraph Font;\lsdunhideused0 \lsdlocked0 Body Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdunhideused0 \lsdlocked0 Body Text 2; +\lsdunhideused0 \lsdlocked0 Body Text Indent 2;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdlocked0 Strong;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdunhideused0 \lsdlocked0 Document Map; +\lsdunhideused0 \lsdlocked0 Plain Text;\lsdsemihidden0 \lsdunhideused0 \lsdpriority59 \lsdlocked0 Table Grid;\lsdunhideused0 \lsdlocked0 Placeholder Text;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 1; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdunhideused0 \lsdlocked0 Revision; +\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 1; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 2; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 2; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 2; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 3; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 3; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 3; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 4; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 4; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 4; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 5; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 5; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdsemihidden0 \lsdunhideused0 \lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority61 \lsdlocked0 Light List Accent 6; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority62 \lsdlocked0 Light Grid Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority70 \lsdlocked0 Dark List Accent 6; +\lsdsemihidden0 \lsdunhideused0 \lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdsemihidden0 \lsdunhideused0 \lsdpriority73 \lsdlocked0 Colorful Grid Accent 6; +\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; +\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference; +\lsdsemihidden0 \lsdunhideused0 \lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdpriority37 \lsdlocked0 Bibliography;\lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;}}{\*\datastore 010500000200000018000000 +4d73786d6c322e534158584d4c5265616465722e362e30000000000000000000000e0000 +d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffdffffff04000000feffffff05000000fefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff010000000c6ad98892f1d411a65f0040963251e5000000000000000000000000c046 +980545ddcd010300000080020000000000004d0073006f004400610074006100530074006f0072006500000000000000000000000000000000000000000000000000000000000000000000000000000000001a000101ffffffffffffffff020000000000000000000000000000000000000000000000c046980545ddcd01 +c046980545ddcd0100000000000000000000000051004a004b003300d000d300c400c400c60045004b00ca005800db004f00ce00cb00ce0042005400ce0051003d003d000000000000000000000000000000000032000101ffffffffffffffff030000000000000000000000000000000000000000000000c046980545dd +cd01c046980545ddcd010000000000000000000000004900740065006d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffff04000000ffffffff000000000000000000000000000000000000000000000000 +00000000000000000000000000000000cd00000000000000010000000200000003000000feffffff0500000006000000070000000800000009000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c623a536f757263657320786d6c6e733a623d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f6772617068792220786d6c6e733d +22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222053656c65637465645374796c653d225c4150412e58534c22205374796c654e616d653d22415041222f3e000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000003c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d226e6f223f3e0d0a3c64733a6461746173746f72654974656d2064733a6974656d49443d227b43333944 +393234302d323433392d343239382d414135462d4233414541454530353342397d2220786d6c6e733a64733d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f637573746f6d586d6c223e3c64733a736368656d61526566733e3c +64733a736368656d615265662064733a7572693d22687474703a2f2f736368656d61732e6f70656e500072006f007000650072007400690065007300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000200ffffffffffffffffffffffff000000000000 +0000000000000000000000000000000000000000000000000000000000000400000055010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222f3e3c2f64733a736368656d61526566733e3c2f64733a6461746173746f +72654974656d3e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105000000000000}} \ No newline at end of file diff --git a/doc/simh_breakpoints.doc b/doc/simh_breakpoints.doc new file mode 100644 index 00000000..103d2d63 Binary files /dev/null and b/doc/simh_breakpoints.doc differ diff --git a/doc/simh_vmio.doc b/doc/simh_vmio.doc new file mode 100644 index 00000000..4dc78bae Binary files /dev/null and b/doc/simh_vmio.doc differ diff --git a/doc/vax780_doc.doc b/doc/vax780_doc.doc index 7d35a37d..f96b47d7 100644 Binary files a/doc/vax780_doc.doc and b/doc/vax780_doc.doc differ diff --git a/doc/vax_doc.doc b/doc/vax_doc.doc index ade17da1..07f644fb 100644 Binary files a/doc/vax_doc.doc and b/doc/vax_doc.doc differ diff --git a/makefile b/makefile index 724426ac..5bd7a2e9 100644 --- a/makefile +++ b/makefile @@ -319,19 +319,17 @@ else endif endif ifeq (pcap,$(shell if exist ..\windows-build\winpcap\Wpdpack\include\pcap.h echo pcap)) - PCAP_CCDEFS = -I../windows-build/winpcap/Wpdpack/include -I$(GCC_Path)..\include\ddk -DUSE_SHARED NETWORK_LDFLAGS = - NETWORK_OPT = -DUSE_SHARED + NETWORK_OPT = -DUSE_SHARED -I../windows-build/winpcap/Wpdpack/include -I$(GCC_Path)..\include\ddk NETWORK_FEATURES = - dynamic networking support using windows-build provided libpcap components else ifeq (pcap,$(shell if exist $(dir $(GCC_Path))..\include\pcap.h echo pcap)) - PCAP_CCDEFS = -DUSE_SHARED -I$(GCC_Path)..\include\ddk NETWORK_LDFLAGS = - NETWORK_OPT = -DUSE_SHARED + NETWORK_OPT = -DUSE_SHARED -I$(GCC_Path)..\include\ddk NETWORK_FEATURES = - dynamic networking support using libpcap components found in the MinGW directories endif endif - OS_CCDEFS = -fms-extensions $(PTHREADS_CCDEFS) $(PCAP_CCDEFS) + OS_CCDEFS = -fms-extensions $(PTHREADS_CCDEFS) OS_LDFLAGS = -lm -lwsock32 -lwinmm $(PTHREADS_LDFLAGS) EXE = .exe ifneq (binexists,$(shell if exist BIN echo binexists)) @@ -429,7 +427,7 @@ LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) $(LDFLAGS_O) # BIN = BIN/ SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \ - sim_tmxr.c sim_ether.c sim_tape.c sim_disk.c + sim_tmxr.c sim_ether.c sim_tape.c sim_disk.c sim_serial.c # @@ -480,7 +478,8 @@ PDP11 = ${PDP11D}/pdp11_fp.c ${PDP11D}/pdp11_cpu.c ${PDP11D}/pdp11_dz.c \ ${PDP11D}/pdp11_rh.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_cpumod.c \ ${PDP11D}/pdp11_cr.c ${PDP11D}/pdp11_rf.c ${PDP11D}/pdp11_dl.c \ ${PDP11D}/pdp11_ta.c ${PDP11D}/pdp11_rc.c ${PDP11D}/pdp11_kg.c \ - ${PDP11D}/pdp11_ke.c ${PDP11D}/pdp11_dc.c ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_ke.c ${PDP11D}/pdp11_dc.c ${PDP11D}/pdp11_dmc.c \ + ${PDP11D}/pdp11_io_lib.c PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} @@ -492,7 +491,7 @@ VAX = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c ${VAXD}/vax_io.c \ ${PDP11D}/pdp11_rl.c ${PDP11D}/pdp11_rq.c ${PDP11D}/pdp11_ts.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xq.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_vh.c \ - ${PDP11D}/pdp11_cr.c ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_cr.c ${PDP11D}/pdp11_dmc.c ${PDP11D}/pdp11_io_lib.c VAX_OPT = -DVM_VAX -DUSE_INT64 -DUSE_ADDR64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} @@ -556,7 +555,7 @@ VAX780 = ${VAXD}/vax_cpu.c ${VAXD}/vax_cpu1.c ${VAXD}/vax_fpa.c \ ${PDP11D}/pdp11_dz.c ${PDP11D}/pdp11_lp.c ${PDP11D}/pdp11_tq.c \ ${PDP11D}/pdp11_xu.c ${PDP11D}/pdp11_ry.c ${PDP11D}/pdp11_cr.c \ ${PDP11D}/pdp11_rp.c ${PDP11D}/pdp11_tu.c ${PDP11D}/pdp11_hk.c \ - ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_io_lib.c + ${PDP11D}/pdp11_vh.c ${PDP11D}/pdp11_dmc.c \${PDP11D}/pdp11_io_lib.c VAX780_OPT = -DVM_VAX -DVAX_780 -DUSE_INT64 -DUSE_ADDR64 -I VAX -I ${PDP11D} ${NETWORK_OPT} diff --git a/scp.c b/scp.c index db207e16..5923b11a 100644 --- a/scp.c +++ b/scp.c @@ -216,6 +216,8 @@ #include "sim_defs.h" #include "sim_rev.h" #include "sim_ether.h" +#include "sim_serial.h" +#include "sim_sock.h" #include #include #include @@ -334,6 +336,7 @@ t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat set_unit_enbdis (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat ssh_break (FILE *st, char *cptr, int32 flg); t_stat set_default_cmd (int32 flg, char *cptr); +t_stat pwd_cmd (int32 flg, char *cptr); t_stat show_cmd_fi (FILE *ofile, int32 flag, char *cptr); t_stat show_config (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); @@ -381,7 +384,7 @@ char *get_sim_sw (char *cptr); t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); t_value get_rval (REG *rptr, uint32 idx); void put_rval (REG *rptr, uint32 idx, t_value val); -t_value strtotv (char *inptr, char **endptr, uint32 radix); +t_value strtotv (const char *inptr, char **endptr, uint32 radix); void fprint_help (FILE *st); void fprint_stopped (FILE *st, t_stat r); void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr); @@ -425,13 +428,15 @@ t_stat set_prompt (int32 flag, char *cptr); /* Global data */ DEVICE *sim_dflt_dev = NULL; -UNIT *sim_clock_queue = NULL; +UNIT *sim_clock_queue = QUEUE_LIST_END; int32 sim_interval = 0; int32 sim_switches = 0; FILE *sim_ofile = NULL; SCHTAB *sim_schptr = FALSE; DEVICE *sim_dfdev = NULL; UNIT *sim_dfunit = NULL; +DEVICE **sim_internal_devices = NULL; +uint32 sim_internal_device_count = 0; int32 sim_opt_out = 0; int32 sim_is_running = 0; uint32 sim_brk_summ = 0; @@ -621,6 +626,10 @@ static CTAB cmd_table[] = { "exi{t}|q{uit}|by{e} exit from simulation\n" }, { "QUIT", &exit_cmd, 0, NULL }, { "BYE", &exit_cmd, 0, NULL }, + { "CD", &set_default_cmd, 0, + "cd set the current directory\n" }, + { "PWD", &pwd_cmd, 0, + "pwd show current directory\n" }, { "SET", &set_cmd, 0, "set console arg{,arg...} set console options\n" "set console WRU specify console drop to simh char\n" @@ -639,6 +648,10 @@ static CTAB cmd_table[] = { "set console TELNET=UNBUFFERED\n" " disables console telnet buffering\n" "set console NOTELNET disable console telnet\n" + "set console SERIAL=serialport[;config]\n" + " specify console serial port and optionally\n" + " the port config (i.e. ;9600-8n1)\n" + "set console NOSERIAL disable console serial session\n" "set console LOG=log_file enable console logging to the\n" " specified destination {STDOUT,DEBUG or filename)\n" "set console NOLOG disable console logging\n" @@ -646,7 +659,7 @@ static CTAB cmd_table[] = { " enable console debugging to the\n" " specified destination {LOG,STDOUT or filename)\n" "set console NODEBUG disable console debugging\n" - "set default set the default directory\n" + "set default set the current directory\n" "set log log_file specify the log destination\n" " (STDOUT,DEBUG or filename)\n" "set nolog disables any currently active logging\n" @@ -706,6 +719,8 @@ static CTAB cmd_table[] = { "sh{ow} {arg,...} show device parameters\n" "sh{ow} {arg,...} show unit parameters\n" "sh{ow} ethernet show ethernet devices\n" + "sh{ow} serial show serial devices\n" + "sh{ow} multiplexer show open multiplexer devices\n" "sh{ow} on show on condition actions\n" }, { "DO", &do_cmd, 1, "do {-V} {-O} {-E} {-Q} {arg,arg...}\b" @@ -798,6 +813,7 @@ for (i = 1; i < argc; i++) { /* loop thru args */ sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */ sim_on_inherit = sim_switches & SWMASK ('O'); /* -o means inherit on state */ +sim_init_sock (); /* init socket capabilities */ AIO_INIT; /* init Asynch I/O */ if (sim_vm_init != NULL) /* call once only */ (*sim_vm_init)(); @@ -807,7 +823,7 @@ stop_cpu = 0; sim_interval = 0; sim_time = sim_rtime = 0; noqueue_time = 0; -sim_clock_queue = NULL; +sim_clock_queue = QUEUE_LIST_END; sim_is_running = 0; sim_log = NULL; if (sim_emax <= 0) @@ -875,9 +891,10 @@ while (stat != SCPE_EXIT) { /* in case exit */ cptr = (*sim_vm_read) (cbuf, sizeof(cbuf), stdin); } else cptr = read_line_p (sim_prompt, cbuf, sizeof(cbuf), stdin);/* read with prmopt*/ - if (cptr == NULL) /* EOF? */ + if (cptr == NULL) { /* EOF? */ if (sim_ttisatty()) continue; /* ignore tty EOF */ else break; /* otherwise exit */ + } if (*cptr == 0) /* ignore blank */ continue; sub_args (cbuf, sizeof(cbuf), argv); @@ -892,7 +909,7 @@ while (stat != SCPE_EXIT) { /* in case exit */ stat_nomessage = stat_nomessage || (!sim_show_message);/* Apply global suppression */ stat = SCPE_BARE_STATUS(stat); /* remove possible flag */ sim_last_cmd_stat = stat; /* save command error status */ - if (!stat_nomessage) /* displaying message status? */ + if (!stat_nomessage) { /* displaying message status? */ if (cmdp && (cmdp->message)) /* special message handler? */ cmdp->message (NULL, stat); /* let it deal with display */ else @@ -901,6 +918,7 @@ while (stat != SCPE_EXIT) { /* in case exit */ if (sim_log) fprintf (sim_log, "%s\n", sim_error_text (stat)); } + } if (sim_vm_post != NULL) (*sim_vm_post) (TRUE); } /* end while */ @@ -911,6 +929,7 @@ sim_set_logoff (0, NULL); /* close log */ sim_set_notelnet (0, NULL); /* close Telnet */ sim_ttclose (); /* close console */ AIO_CLEANUP; /* Asynch I/O */ +sim_cleanup_sock (); /* cleanup sockets */ return 0; } @@ -1241,6 +1260,7 @@ do { cmdp->message ((!echo && !sim_quiet) ? ocptr : NULL, stat); else if (stat >= SCPE_BASE) { /* report error if not suppressed */ + printf ("%s\n", sim_error_text (stat)); if (sim_log) fprintf (sim_log, "%s\n", sim_error_text (stat)); @@ -1249,11 +1269,12 @@ do { if (staying && (sim_on_check[sim_do_depth]) && (stat != SCPE_OK) && - (stat != SCPE_STEP)) + (stat != SCPE_STEP)) { if ((stat <= SCPE_MAX_ERR) && sim_on_actions[sim_do_depth][stat]) sim_brk_act[sim_do_depth] = sim_on_actions[sim_do_depth][stat]; else sim_brk_act[sim_do_depth] = sim_on_actions[sim_do_depth][0]; + } if (sim_vm_post != NULL) (*sim_vm_post) (TRUE); } while (staying); @@ -2082,6 +2103,9 @@ static SHTAB show_glob_tab[] = { { "THROTTLE", &sim_show_throt, 0 }, { "ASYNCH", &sim_show_asynch, 0 }, { "ETHERNET", ð_show_devices, 0 }, + { "SERIAL", &sim_show_serial, 0 }, + { "MULTIPLEXER", &tmxr_show_open_devices, 0 }, + { "MUX", &tmxr_show_open_devices, 0 }, { "ON", &show_on, 0 }, { NULL, NULL, 0 } }; @@ -2103,8 +2127,6 @@ GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) /* must be more */ return SCPE_2FARG; cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -if ((shptr = find_shtab (show_glob_tab, gbuf))) /* global? */ - return shptr->action (ofile, NULL, NULL, shptr->arg, cptr); if ((dptr = find_dev (gbuf))) { /* device match? */ uptr = dptr->units; /* first unit */ @@ -2119,7 +2141,10 @@ else if ((dptr = find_unit (gbuf, &uptr))) { /* unit match? */ shtb = show_unit_tab; /* global table */ lvl = MTAB_VUN; /* unit match */ } -else return SCPE_NXDEV; /* no match */ +else if ((shptr = find_shtab (show_glob_tab, gbuf))) /* global? */ + return shptr->action (ofile, NULL, NULL, shptr->arg, cptr); +else + return SCPE_NXDEV; /* no match */ if (*cptr == 0) { /* now eol? */ return (lvl == MTAB_VDV)? @@ -2317,7 +2342,7 @@ int32 accum; if (cptr && (*cptr != 0)) return SCPE_2MARG; -if (sim_clock_queue == NULL) { +if (sim_clock_queue == QUEUE_LIST_END) { fprintf (st, "%s event queue empty, time = %.0f\n", sim_name, sim_time); return SCPE_OK; @@ -2325,7 +2350,7 @@ if (sim_clock_queue == NULL) { fprintf (st, "%s event queue status, time = %.0f\n", sim_name, sim_time); accum = 0; -for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) { +for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) { if (uptr == &sim_step_unit) fprintf (st, " Step timer"); else if ((dptr = find_dev_from_unit (uptr)) != NULL) { @@ -2340,10 +2365,10 @@ for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) { #if defined (SIM_ASYNCH_IO) pthread_mutex_lock (&sim_asynch_lock); fprintf (st, "asynchronous pending event queue\n"); -if (sim_asynch_queue == AIO_LIST_END) +if (sim_asynch_queue == QUEUE_LIST_END) fprintf (st, "Empty\n"); else { - for (uptr = sim_asynch_queue; uptr != AIO_LIST_END; uptr = uptr->a_next) { + for (uptr = sim_asynch_queue; uptr != QUEUE_LIST_END; uptr = uptr->a_next) { if ((dptr = find_dev_from_unit (uptr)) != NULL) { fprintf (st, " %s", sim_dname (dptr)); if (dptr->numunits > 1) fprintf (st, " unit %d", @@ -2449,6 +2474,8 @@ if (cptr && (*cptr != 0)) /* now eol? */ return SCPE_2MARG; for (i = 0; (dptr = sim_devices[i]) != NULL; i++) show_dev_modifiers (st, dptr, NULL, flag, cptr); +for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) + show_dev_modifiers (st, dptr, NULL, flag, cptr); return SCPE_OK; } @@ -2539,6 +2566,8 @@ if (cptr && (*cptr != 0)) /* now eol? */ return SCPE_2MARG; for (i = 0; (dptr = sim_devices[i]) != NULL; i++) show_dev_show_commands (st, dptr, NULL, flag, cptr); +for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) + show_dev_show_commands (st, dptr, NULL, flag, cptr); return SCPE_OK; } @@ -2602,6 +2631,11 @@ if (chdir(cptr) != 0) { return SCPE_OK; } +t_stat pwd_cmd (int32 flg, char *cptr) +{ +return show_cmd (0, "DEFAULT"); +} + /* Breakpoint commands */ t_stat brk_cmd (int32 flg, char *cptr) @@ -2738,6 +2772,13 @@ for (i = start; (dptr = sim_devices[i]) != NULL; i++) { return reason; } } +for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) { + if (dptr->reset != NULL) { + reason = dptr->reset (dptr); + if (reason != SCPE_OK) + return reason; + } + } return SCPE_OK; } @@ -2809,7 +2850,8 @@ if (dptr == NULL) /* found dev? */ return SCPE_NXDEV; if (uptr == NULL) /* valid unit? */ return SCPE_NXUN; -if (uptr->flags & UNIT_ATT) { /* already attached? */ +if ((uptr->flags & UNIT_ATT) && /* already attached? */ + !(uptr->flags & UNIT_ATTMULT)) { /* and only single attachable */ r = scp_detach_unit (dptr, uptr); /* detach it */ if (r != SCPE_OK) /* error? */ return r; @@ -2967,6 +3009,7 @@ for (i = start; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ return SCPE_OK; } + /* Call device-specific or file-oriented detach unit routine */ t_stat scp_detach_unit (DEVICE *dptr, UNIT *uptr) @@ -2986,11 +3029,12 @@ if (uptr == NULL) return SCPE_IERR; if (!(uptr->flags & UNIT_ATTABLE)) /* attachable? */ return SCPE_NOATT; -if (!(uptr->flags & UNIT_ATT)) /* not attached? */ +if (!(uptr->flags & UNIT_ATT)) { /* not attached? */ if (sim_switches & SIM_SW_REST) /* restoring? */ return SCPE_OK; /* allow detach */ else - return SCPE_NOATT; /* complain */ + return SCPE_NOATT; /* complain */ + } if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK; if (uptr->flags & UNIT_BUF) { @@ -3092,6 +3136,19 @@ char *sim_dname (DEVICE *dptr) return (dptr->lname? dptr->lname: dptr->name); } +/* Get unit display name */ + +char *sim_uname (UNIT *uptr) +{ +DEVICE *d = find_dev_from_unit(uptr); +static AIO_TLS char uname[CBUFSIZE]; + +if (d->numunits == 1) + return sim_dname (d); +sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units)); +return uname; +} + /* Save command sa[ve] filename save state to specified file @@ -3311,7 +3368,7 @@ if (v32) { /* [V3.2+] time as strin } else READ_I (sim_time); /* sim time */ READ_I (sim_rtime); /* [V2.6+] sim rel time */ - +detach_all (0, 0); /* Detach everything to start from a consistent state */ for ( ;; ) { /* device loop */ READ_S (buf); /* read device name */ if (buf[0] == 0) /* last? */ @@ -3650,19 +3707,20 @@ for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files uptr = dptr->units + j; if ((uptr->flags & UNIT_ATT) && /* attached, */ !(uptr->flags & UNIT_BUF) && /* not buffered, */ - (uptr->fileref)) /* real file, */ + (uptr->fileref)) { /* real file, */ if (uptr->io_flush) /* unit specific flush routine */ uptr->io_flush (uptr); else if (!(uptr->flags & UNIT_RAW) && /* not raw, */ !(uptr->flags & UNIT_RO)) /* not read only? */ fflush (uptr->fileref); + } } } sim_cancel (&sim_step_unit); /* cancel step timer */ sim_throt_cancel (); /* cancel throttle */ AIO_UPDATE_QUEUE; -if (sim_clock_queue != NULL) { /* update sim time */ +if (sim_clock_queue != QUEUE_LIST_END) { /* update sim time */ UPDATE_SIM_TIME (sim_clock_queue->time); } else { @@ -3693,10 +3751,15 @@ if (sim_log) /* log if enabled */ t_stat run_boot_prep (void) { +UNIT *uptr; + sim_interval = 0; /* reset queue */ sim_time = sim_rtime = 0; noqueue_time = 0; -sim_clock_queue = NULL; +for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = sim_clock_queue) { + sim_clock_queue = uptr->next; + uptr->next = NULL; + } return reset_all (0); } @@ -4402,8 +4465,10 @@ char *read_line_p (char *prompt, char *cptr, int32 size, FILE *stream) char *tptr; #if defined(HAVE_DLOPEN) static int initialized = 0; -static char *(*p_readline)(const char *) = NULL; -static void (*p_add_history)(const char *) = NULL; +typedef char *(*readline_func)(const char *); +static readline_func p_readline = NULL; +typedef void (*add_history_func)(const char *); +static add_history_func p_add_history = NULL; if (!initialized) { initialized = 1; @@ -4419,8 +4484,8 @@ if (!initialized) { if (!handle) handle = dlopen("libreadline." __STR(HAVE_DLOPEN) ".5", RTLD_NOW|RTLD_GLOBAL); if (handle) { - p_readline = dlsym(handle, "readline"); - p_add_history = dlsym(handle, "add_history"); + p_readline = (readline_func)((size_t)dlsym(handle, "readline")); + p_add_history = (add_history_func)((size_t)dlsym(handle, "add_history")); } } if (prompt) { /* interactive? */ @@ -4636,69 +4701,6 @@ if (term && (*tptr++ != term)) return tptr; } -/* get_ipaddr IP address:port - - Inputs: - cptr = pointer to input string - Outputs: - ipa = pointer to IP address (may be NULL), 0 = none - ipp = pointer to IP port (may be NULL), 0 = none - result = status -*/ - -t_stat get_ipaddr (char *cptr, uint32 *ipa, uint32 *ipp) -{ -char gbuf[CBUFSIZE]; -char *addrp, *portp, *octetp; -uint32 i, addr, port, octet; -t_stat r; - -if ((cptr == NULL) || (*cptr == 0)) - return SCPE_ARG; -strncpy (gbuf, cptr, sizeof(gbuf)); -addrp = gbuf; /* default addr */ -if ((portp = strchr (gbuf, ':'))) /* x:y? split */ - *portp++ = 0; -else if (strchr (gbuf, '.')) /* x.y...? */ - portp = NULL; -else { - portp = gbuf; /* port only */ - addrp = NULL; /* no addr */ - } -if (portp) { /* port string? */ - if (ipp == NULL) /* not wanted? */ - return SCPE_ARG; - port = (int32) get_uint (portp, 10, 65535, &r); - if ((r != SCPE_OK) || (port == 0)) - return SCPE_ARG; - } -else port = 0; -if (addrp) { /* addr string? */ - if (ipa == NULL) /* not wanted? */ - return SCPE_ARG; - for (i = addr = 0; i < 4; i++) { /* four octets */ - octetp = strchr (addrp, '.'); /* find octet end */ - if (octetp != NULL) /* split string */ - *octetp++ = 0; - else if (i < 3) /* except last */ - return SCPE_ARG; - octet = (int32) get_uint (addrp, 10, 255, &r); - if (r != SCPE_OK) - return SCPE_ARG; - addr = (addr << 8) | octet; - addrp = octetp; - } - if (((addr & 0377) == 0) || ((addr & 0377) == 255)) - return SCPE_ARG; - } -else addr = 0; -if (ipp) /* return req values */ - *ipp = port; -if (ipa) - *ipa = addr; -return SCPE_OK; -} - /* Find_device find device matching input string Inputs: @@ -4718,6 +4720,12 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { (strcmp (cptr, dptr->lname) == 0))) return dptr; } +for (i = 0; sim_internal_device_count && (dptr = sim_internal_devices[i]); ++i) { + if ((strcmp (cptr, dptr->name) == 0) || + (dptr->lname && + (strcmp (cptr, dptr->lname) == 0))) + return dptr; + } return NULL; } @@ -4729,6 +4737,7 @@ return NULL; Outputs: result = pointer to device (null if no dev) *iptr = pointer to unit (null if nx unit) + */ DEVICE *find_unit (char *cptr, UNIT **uptr) @@ -4768,6 +4777,29 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */ return NULL; } +/* sim_register_internal_device Add device to internal device list + + Inputs: + dptr = pointer to device +*/ + +t_stat sim_register_internal_device (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; (sim_devices[i] != NULL); ++i) + if (sim_devices[i] == dptr) + return SCPE_OK; +for (i = 0; i < sim_internal_device_count; ++i) + if (sim_internal_devices[i] == dptr) + return SCPE_OK; +++sim_internal_device_count; +sim_internal_devices = realloc(sim_internal_devices, (sim_internal_device_count+1)*sizeof(*sim_internal_devices)); +sim_internal_devices[sim_internal_device_count-1] = dptr; +sim_internal_devices[sim_internal_device_count] = NULL; +return SCPE_OK; +} + /* Find_dev_from_unit find device for unit Inputs: @@ -4789,6 +4821,13 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { return dptr; } } +for (i = 0; inumunits; j++) { + if (uptr == (dptr->units + j)) + return dptr; + } + } return NULL; } @@ -5136,13 +5175,13 @@ return 0; On an error, the endptr will equal the inptr. */ -t_value strtotv (char *inptr, char **endptr, uint32 radix) +t_value strtotv (const char *inptr, char **endptr, uint32 radix) { int32 nodigit; t_value val; uint32 c, digit; -*endptr = inptr; /* assume fails */ +*endptr = (char *)inptr; /* assume fails */ if ((radix < 2) || (radix > 36)) return 0; while (isspace (*inptr)) /* bypass white space */ @@ -5164,7 +5203,7 @@ for (c = *inptr; isalnum(c); c = *++inptr) { /* loop through char */ } if (nodigit) /* no digits? */ return 0; -*endptr = inptr; /* result pointer */ +*endptr = (char *)inptr; /* result pointer */ return val; } @@ -5218,6 +5257,7 @@ return SCPE_OK; /* Event queue package sim_activate add entry to event queue + sim_activate_after add entry to event queue after a specified amount of wall time sim_cancel remove entry from event queue sim_process_event process entries on event queue sim_is_active see if entry is on event queue @@ -5254,7 +5294,7 @@ t_stat reason; if (stop_cpu) /* stop CPU? */ return SCPE_STOP; AIO_UPDATE_QUEUE; -if (sim_clock_queue == NULL) { /* queue empty? */ +if (sim_clock_queue == QUEUE_LIST_END) { /* queue empty? */ UPDATE_SIM_TIME (noqueue_time); /* update sim time */ sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */ return SCPE_OK; @@ -5265,7 +5305,7 @@ do { sim_clock_queue = uptr->next; /* remove first */ uptr->next = NULL; /* hygiene */ uptr->time = 0; - if (sim_clock_queue != NULL) + if (sim_clock_queue != QUEUE_LIST_END) sim_interval = sim_clock_queue->time; else sim_interval = noqueue_time = NOQUEUE_WAIT; if (uptr->action != NULL) @@ -5289,13 +5329,18 @@ return reason; t_stat sim_activate (UNIT *uptr, int32 event_time) { +return _sim_activate (uptr, event_time); +} + +t_stat _sim_activate (UNIT *uptr, int32 event_time) +{ UNIT *cptr, *prvptr; int32 accum; -AIO_ACTIVATE (sim_activate, uptr, event_time); +AIO_ACTIVATE (_sim_activate, uptr, event_time); if (sim_is_active (uptr)) /* already active? */ return SCPE_OK; -if (sim_clock_queue == NULL) { +if (sim_clock_queue == QUEUE_LIST_END) { UPDATE_SIM_TIME (noqueue_time); } else { /* update sim time */ @@ -5304,7 +5349,7 @@ else { /* update sim time */ prvptr = NULL; accum = 0; -for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { +for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) { if (event_time < (accum + cptr->time)) break; accum = accum + cptr->time; @@ -5319,7 +5364,7 @@ else { prvptr->next = uptr; } uptr->time = event_time - accum; -if (cptr != NULL) +if (cptr != QUEUE_LIST_END) cptr->time = cptr->time - uptr->time; sim_interval = sim_clock_queue->time; return SCPE_OK; @@ -5358,12 +5403,35 @@ uint32 rtimenow, urtime = (uint32)rtime; AIO_ACTIVATE (sim_activate_notbefore, uptr, rtime); sim_cancel (uptr); rtimenow = sim_grtime(); +sim_cancel (uptr); if (0x80000000 <= urtime-rtimenow) return sim_activate (uptr, 0); else return sim_activate (uptr, urtime-rtimenow); } +/* sim_activate_after - activate (queue) event + + Inputs: + uptr = pointer to unit + usec_delay = relative timeout (in microseconds) + Outputs: + reason = result (SCPE_OK if ok) +*/ + +t_stat sim_activate_after (UNIT *uptr, int32 event_time) +{ +return _sim_activate_after (uptr, event_time); +} + +t_stat _sim_activate_after (UNIT *uptr, int32 usec_delay) +{ +if (sim_is_active (uptr)) /* already active? */ + return SCPE_OK; +AIO_ACTIVATE (_sim_activate_after, uptr, usec_delay); +return sim_timer_activate_after (uptr, usec_delay); +} + /* sim_cancel - cancel (dequeue) event Inputs: @@ -5380,27 +5448,28 @@ UNIT *cptr, *nptr; AIO_VALIDATE; AIO_CANCEL(uptr); AIO_UPDATE_QUEUE; -if (sim_clock_queue == NULL) +if (sim_clock_queue == QUEUE_LIST_END) return SCPE_OK; UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */ if (!sim_is_active (uptr)) return SCPE_OK; -nptr = NULL; +nptr = QUEUE_LIST_END; + if (sim_clock_queue == uptr) nptr = sim_clock_queue = uptr->next; else { - for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { + for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) { if (cptr->next == uptr) { nptr = cptr->next = uptr->next; break; /* end queue scan */ } } } -if (nptr != NULL) +if (nptr != QUEUE_LIST_END) nptr->time = nptr->time + uptr->time; uptr->next = NULL; /* hygiene */ uptr->time = 0; -if (sim_clock_queue != NULL) +if (sim_clock_queue != QUEUE_LIST_END) sim_interval = sim_clock_queue->time; else sim_interval = noqueue_time = NOQUEUE_WAIT; return SCPE_OK; @@ -5414,7 +5483,7 @@ return SCPE_OK; result = absolute activation time + 1, 0 if inactive */ -t_bool sim_is_active (UNIT *uptr) +t_bool sim_is_activeXX (UNIT *uptr) { UNIT *cptr; int32 accum; @@ -5422,7 +5491,7 @@ int32 accum; AIO_VALIDATE; AIO_UPDATE_QUEUE; accum = 0; -for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { +for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) { if (cptr == sim_clock_queue) { if (sim_interval > 0) accum = accum + sim_interval; @@ -5434,7 +5503,7 @@ for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { return 0; } -/* sim_is_active_bool - test for entry in queue +/* sim_is_active - test for entry in queue Inputs: uptr = pointer to unit @@ -5442,7 +5511,7 @@ return 0; result = TRUE if unit is busy, FALSE inactive */ -t_bool sim_is_active_bool (UNIT *uptr) +t_bool sim_is_active (UNIT *uptr) { AIO_VALIDATE; AIO_UPDATE_QUEUE; @@ -5460,11 +5529,10 @@ return (((uptr->next) || AIO_IS_ACTIVE(uptr)) ? TRUE : FALSE); int32 sim_activate_time (UNIT *uptr) { UNIT *cptr; -int32 accum; +int32 accum = 0; AIO_VALIDATE; -accum = 0; -for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { +for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) { if (cptr == sim_clock_queue) { if (sim_interval > 0) accum = accum + sim_interval; @@ -5486,7 +5554,7 @@ return 0; double sim_gtime (void) { -if (sim_clock_queue == NULL) { +if (sim_clock_queue == QUEUE_LIST_END) { UPDATE_SIM_TIME (noqueue_time); } else { @@ -5497,7 +5565,7 @@ return sim_time; uint32 sim_grtime (void) { -if (sim_clock_queue == NULL) { +if (sim_clock_queue == QUEUE_LIST_END) { UPDATE_SIM_TIME (noqueue_time); } else { @@ -5519,7 +5587,7 @@ int32 cnt; UNIT *uptr; cnt = 0; -for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) +for (uptr = sim_clock_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) cnt++; return cnt; } @@ -5921,7 +5989,7 @@ if (sim_deb && (dptr->dctrl & dbits)) { uint32 value, beforevalue, mask; for (fields=offset=0; bitdefs[fields].name; ++fields) { - if (bitdefs[fields].offset == -1) /* fixup uninitialized offsets */ + if (bitdefs[fields].offset == 0xffffffff) /* fixup uninitialized offsets */ bitdefs[fields].offset = offset; offset += bitdefs[fields].width; } diff --git a/scp.h b/scp.h index 4abaf186..bd14fd1b 100644 --- a/scp.h +++ b/scp.h @@ -1,6 +1,6 @@ /* scp.h: simulator control program headers - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2009, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -86,8 +86,11 @@ t_stat echo_cmd (int32 flag, char *ptr); t_stat sim_process_event (void); t_stat sim_activate (UNIT *uptr, int32 interval); +t_stat _sim_activate (UNIT *uptr, int32 interval); t_stat sim_activate_abs (UNIT *uptr, int32 interval); t_stat sim_activate_notbefore (UNIT *uptr, int32 rtime); +t_stat sim_activate_after (UNIT *uptr, int32 usecs_walltime); +t_stat _sim_activate_after (UNIT *uptr, int32 usecs_walltime); t_stat sim_cancel (UNIT *uptr); t_bool sim_is_active (UNIT *uptr); int32 sim_activate_time (UNIT *uptr); @@ -101,6 +104,7 @@ t_stat deassign_device (DEVICE *dptr); t_stat reset_all (uint32 start_device); t_stat reset_all_p (uint32 start_device); char *sim_dname (DEVICE *dptr); +char *sim_uname (UNIT *dptr); t_stat get_yn (char *ques, t_stat deflt); char *get_sim_opt (int32 opt, char *cptr, t_stat *st); char *get_glyph (char *iptr, char *optr, char mchar); @@ -108,13 +112,13 @@ char *get_glyph_nc (char *iptr, char *optr, char mchar); t_value get_uint (char *cptr, uint32 radix, t_value max, t_stat *status); char *get_range (DEVICE *dptr, char *cptr, t_addr *lo, t_addr *hi, uint32 rdx, t_addr max, char term); -t_stat get_ipaddr (char *cptr, uint32 *ipa, uint32 *ipp); -t_value strtotv (char *cptr, char **endptr, uint32 radix); +t_value strtotv (const char *cptr, char **endptr, uint32 radix); t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt); CTAB *find_cmd (char *gbuf); DEVICE *find_dev (char *ptr); DEVICE *find_unit (char *ptr, UNIT **uptr); DEVICE *find_dev_from_unit (UNIT *uptr); +t_stat sim_register_internal_device (DEVICE *dptr); REG *find_reg (char *ptr, char **optr, DEVICE *dptr); CTAB *find_ctab (CTAB *tab, char *gbuf); C1TAB *find_c1tab (C1TAB *tab, char *gbuf); @@ -123,6 +127,8 @@ BRKTAB *sim_brk_fnd (t_addr loc); uint32 sim_brk_test (t_addr bloc, uint32 btyp); void sim_brk_clrspc (uint32 spc); char *match_ext (char *fnam, char *ext); +t_stat set_dev_debug (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); const char *sim_error_text (t_stat stat); t_stat sim_string_to_stat (char *cptr, t_stat *cond); t_stat sim_cancel_step (void); diff --git a/sim_BuildROMs.c b/sim_BuildROMs.c index 7f0646f9..5f706cef 100644 --- a/sim_BuildROMs.c +++ b/sim_BuildROMs.c @@ -329,7 +329,7 @@ return 0; void Usage(void) { -int i; +size_t i; printf ("sim_BuildROMs Usage:\n"); printf ("sim_BuildROMs\n"); @@ -360,7 +360,7 @@ exit(2); int main(int argc, char **argv) { -int i; +size_t i; int status = 0; if (argc == 1) { /* invoked without any arguments */ diff --git a/sim_console.c b/sim_console.c index 956c8cbd..edce24d6 100644 --- a/sim_console.c +++ b/sim_console.c @@ -118,10 +118,21 @@ */ #include "sim_defs.h" -#include "sim_sock.h" #include "sim_tmxr.h" +#include "sim_timer.h" #include +/* Forward Declaraations of Platform specific routines */ + +t_stat sim_os_poll_kbd (void); +t_bool sim_os_poll_kbd_ready (int ms_timeout); +t_stat sim_os_putchar (int32 out); +t_stat sim_os_ttinit (void); +t_stat sim_os_ttrun (void); +t_stat sim_os_ttcmd (void); +t_stat sim_os_ttclose (void); +t_bool sim_os_ttisatty (void); + #define KMAP_WRU 0 #define KMAP_BRK 1 #define KMAP_DEL 2 @@ -136,8 +147,52 @@ int32 sim_del_char = '\b'; /* delete character */ #else int32 sim_del_char = 0177; #endif -TMLN sim_con_ldsc = { 0 }; /* console line descr */ -TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */ +t_stat sim_con_poll_svc (UNIT *uptr); /* console connection poll routine */ +t_stat sim_con_reset (DEVICE *dptr); /* console connection poll routine */ +UNIT sim_con_unit = { UDATA (&sim_con_poll_svc, 0, 0) }; /* console connection unit */ +/* debugging bitmaps */ +#define DBG_TRC TMXR_DBG_TRC /* trace routine calls */ +#define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */ +#define DBG_RCV TMXR_DBG_RCV /* display Received Data */ +#define DBG_ASY TMXR_DBG_ASY /* asynchronous thread activity */ + +DEBTAB sim_con_debug[] = { + {"TRC", DBG_TRC}, + {"XMT", DBG_XMT}, + {"RCV", DBG_RCV}, + {"ASY", DBG_ASY}, + {0} +}; + +MTAB sim_con_mod[] = { + { 0 }, +}; + +DEVICE sim_con_telnet = { + "CON-TEL", &sim_con_unit, NULL, sim_con_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, sim_con_reset, NULL, NULL, NULL, + NULL, DEV_DEBUG, 0, sim_con_debug}; +TMLN sim_con_ldsc = { 0 }; /* console line descr */ +TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc, NULL, &sim_con_telnet };/* console line mux */ + +/* Unit service for console connection polling */ + +t_stat sim_con_poll_svc (UNIT *uptr) +{ +if (sim_con_tmxr.master == 0) /* not Telnet? done */ + return SCPE_OK; +if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */ + sim_con_ldsc.rcve = 1; /* rcv enabled */ +sim_activate_after(uptr, 1000000); /* check again in 1 second */ +tmxr_send_buffered_data (&sim_con_ldsc); /* try to flush any buffered data */ +return SCPE_OK; +} + +t_stat sim_con_reset (DEVICE *dptr) +{ +return sim_con_poll_svc (&dptr->units[0]); /* establish polling as needed */ +} extern volatile int32 stop_cpu; extern int32 sim_quiet; @@ -154,10 +209,12 @@ static CTAB set_con_tab[] = { { "PCHAR", &sim_set_pchar, 0 }, { "TELNET", &sim_set_telnet, 0 }, { "NOTELNET", &sim_set_notelnet, 0 }, + { "SERIAL", &sim_set_serial, 0 }, + { "NOSERIAL", &sim_set_noserial, 0 }, { "LOG", &sim_set_logon, 0 }, { "NOLOG", &sim_set_logoff, 0 }, - { "DEBUG", &sim_set_debon, 0 }, - { "NODEBUG", &sim_set_deboff, 0 }, + { "DEBUG", &sim_set_cons_debug, 1 }, + { "NODEBUG", &sim_set_cons_debug, 0 }, { NULL, NULL, 0 } }; @@ -168,7 +225,7 @@ static SHTAB show_con_tab[] = { { "PCHAR", &sim_show_pchar, 0 }, { "LOG", &sim_show_cons_log, 0 }, { "TELNET", &sim_show_telnet, 0 }, - { "DEBUG", &sim_show_debug, 0 }, + { "DEBUG", &sim_show_cons_debug, 0 }, { "BUFFERED", &sim_show_cons_buff, 0 }, { NULL, NULL, 0 } }; @@ -182,6 +239,12 @@ static CTAB set_con_telnet_tab[] = { { NULL, NULL, 0 } }; +static CTAB set_con_serial_tab[] = { + { "LOG", &sim_set_cons_log, 0 }, + { "NOLOG", &sim_set_cons_nolog, 0 }, + { NULL, NULL, 0 } + }; + static int32 *cons_kmap[] = { &sim_int_char, &sim_brk_char, @@ -428,18 +491,23 @@ while (*cptr != 0) { /* do all mods */ if ((cvptr = strchr (gbuf, '='))) /* = value? */ *cvptr++ = 0; get_glyph (gbuf, gbuf, 0); /* modifier to UC */ - if (isdigit (*gbuf)) { - if (sim_con_tmxr.master) /* already open? */ - sim_set_notelnet (0, NULL); /* close first */ - return tmxr_open_master (&sim_con_tmxr, gbuf); /* open master socket */ + if ((ctptr = find_ctab (set_con_telnet_tab, gbuf))) { /* match? */ + r = ctptr->action (ctptr->arg, cvptr); /* do the rest */ + if (r != SCPE_OK) + return r; } - else - if ((ctptr = find_ctab (set_con_telnet_tab, gbuf))) { /* match? */ - r = ctptr->action (ctptr->arg, cvptr); /* do the rest */ - if (r != SCPE_OK) - return r; + else { + r = sim_parse_addr (gbuf, NULL, 0, NULL, NULL, 0, NULL, NULL); + if (r == SCPE_OK) { + if (sim_con_tmxr.master) /* already open? */ + sim_set_notelnet (0, NULL); /* close first */ + r = tmxr_attach (&sim_con_tmxr, &sim_con_unit, gbuf);/* open master socket */ + if (r == SCPE_OK) + sim_activate_after(&sim_con_unit, 1000000); /* check for connection in 1 second */ + return r; } - else return SCPE_NOPARAM; + return SCPE_NOPARAM; + } } return SCPE_OK; } @@ -461,16 +529,22 @@ t_stat sim_show_telnet (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, ch { if (cptr && (*cptr != 0)) return SCPE_2MARG; -if (sim_con_tmxr.master == 0) +if ((sim_con_tmxr.master == 0) && + (sim_con_ldsc.serport == 0)) fprintf (st, "Connected to console window\n"); else { - if (sim_con_ldsc.conn == 0) - fprintf (st, "Listening on port %d\n", sim_con_tmxr.port); - else { - fprintf (st, "Listening on port %d, connected to socket %d\n", - sim_con_tmxr.port, sim_con_ldsc.conn); + if (sim_con_ldsc.serport) { + fprintf (st, "Connected to "); tmxr_fconns (st, &sim_con_ldsc, -1); } + else + if (sim_con_ldsc.conn == 0) + fprintf (st, "Listening on port %s\n", sim_con_tmxr.port); + else { + fprintf (st, "Listening on port %s, connected to socket %d\n", + sim_con_tmxr.port, sim_con_ldsc.conn); + tmxr_fconns (st, &sim_con_ldsc, -1); + } tmxr_fstats (st, &sim_con_ldsc, -1); } return SCPE_OK; @@ -539,6 +613,73 @@ else return SCPE_OK; } +/* Set console Debug Mode */ + +t_stat sim_set_cons_debug (int32 flg, char *cptr) +{ +return set_dev_debug (&sim_con_telnet, &sim_con_unit, flg, cptr); +} + +t_stat sim_show_cons_debug (FILE *st, DEVICE *dunused, UNIT *uunused, int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) + return SCPE_2MARG; +return show_dev_debug (st, &sim_con_telnet, &sim_con_unit, flag, cptr); +} + +/* Set console to Serial port (and parameters) */ + +t_stat sim_set_serial (int32 flag, char *cptr) +{ +char *cvptr, gbuf[CBUFSIZE], ubuf[CBUFSIZE]; +CTAB *ctptr; +t_stat r; + +if ((cptr == NULL) || (*cptr == 0)) + return SCPE_2FARG; +while (*cptr != 0) { /* do all mods */ + cptr = get_glyph_nc (cptr, gbuf, ','); /* get modifier */ + if ((cvptr = strchr (gbuf, '='))) /* = value? */ + *cvptr++ = 0; + get_glyph (gbuf, ubuf, 0); /* modifier to UC */ + if ((ctptr = find_ctab (set_con_serial_tab, ubuf))) { /* match? */ + r = ctptr->action (ctptr->arg, cvptr); /* do the rest */ + if (r != SCPE_OK) + return r; + } + else { + SERHANDLE serport = sim_open_serial (gbuf, NULL, &r); + if (serport != INVALID_HANDLE) { + sim_close_serial (serport); + if (r == SCPE_OK) { + char cbuf[CBUFSIZE]; + if ((sim_con_tmxr.master) || /* already open? */ + (sim_con_ldsc.serport)) + sim_set_noserial (0, NULL); /* close first */ + sprintf(cbuf, "Connect=%s", gbuf); + r = tmxr_attach (&sim_con_tmxr, &sim_con_unit, cbuf);/* open master socket */ + sim_con_ldsc.rcve = 1; /* rcv enabled */ + if (r == SCPE_OK) + sim_activate_after(&sim_con_unit, 1000000); /* check for connection in 1 second */ + return r; + } + } + return SCPE_ARG; + } + } +return SCPE_OK; +} + +/* Close console Serial port */ + +t_stat sim_set_noserial (int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) /* too many arguments? */ + return SCPE_2MARG; +if (sim_con_ldsc.serport == 0) /* ignore if already closed */ + return SCPE_OK; +return tmxr_close_master (&sim_con_tmxr); /* close master socket */ +} /* Log File Open/Close/Show Support */ @@ -685,9 +826,12 @@ t_stat sim_poll_kbd (void) int32 c; c = sim_os_poll_kbd (); /* get character */ -if ((c == SCPE_STOP) || (sim_con_tmxr.master == 0)) /* ^E or not Telnet? */ +if ((c == SCPE_STOP) || /* ^E or not Telnet? */ + ((sim_con_tmxr.master == 0) && /* and not serial? */ + (sim_con_ldsc.serport == 0))) return c; /* in-window */ -if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */ +if ((sim_con_ldsc.conn == 0) && /* no Telnet conn */ + (sim_con_ldsc.serport == 0)) { /* and no serial conn? */ if (!sim_con_ldsc.txbfd) /* unbuffered? */ return SCPE_LOST; /* connection lost */ if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */ @@ -705,14 +849,16 @@ return SCPE_OK; t_stat sim_putchar (int32 c) { -if (sim_con_tmxr.master == 0) { /* not Telnet? */ +if ((sim_con_tmxr.master == 0) && /* not Telnet? */ + (sim_con_ldsc.serport == 0)) { /* and not serial port */ if (sim_log) /* log file? */ fputc (c, sim_log); return sim_os_putchar (c); /* in-window version */ } if (sim_log && !sim_con_ldsc.txlog) /* log file, but no line log? */ fputc (c, sim_log); -if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */ +if ((sim_con_ldsc.serport == 0) && /* no serial port */ + (sim_con_ldsc.conn == 0)) { /* and no Telnet conn? */ if (!sim_con_ldsc.txbfd) /* unbuffered? */ return SCPE_LOST; /* connection lost */ if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */ @@ -727,14 +873,16 @@ t_stat sim_putchar_s (int32 c) { t_stat r; -if (sim_con_tmxr.master == 0) { /* not Telnet? */ +if ((sim_con_tmxr.master == 0) && /* not Telnet? */ + (sim_con_ldsc.serport == 0)) { /* and not serial port */ if (sim_log) /* log file? */ fputc (c, sim_log); return sim_os_putchar (c); /* in-window version */ } if (sim_log && !sim_con_ldsc.txlog) /* log file, but no line log? */ fputc (c, sim_log); -if (sim_con_ldsc.conn == 0) { /* no Telnet conn? */ +if ((sim_con_ldsc.serport == 0) && /* no serial port */ + (sim_con_ldsc.conn == 0)) { /* and no Telnet conn? */ if (!sim_con_ldsc.txbfd) /* non-buffered Telnet conn? */ return SCPE_LOST; /* lost */ if (tmxr_poll_conn (&sim_con_tmxr) >= 0) /* poll connect */ @@ -789,6 +937,69 @@ else c = c & 0377; return c; } + +t_stat sim_ttinit (void) +{ +sim_register_internal_device (&sim_con_telnet); +tmxr_startup (); +return sim_os_ttinit (); +} + +t_stat sim_ttrun (void) +{ +if (!sim_con_tmxr.ldsc->uptr) /* If simulator didn't declare its input polling unit */ + sim_con_unit.flags &= ~UNIT_TM_POLL; /* we can't poll asynchronously */ +#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX) +pthread_mutex_lock (&sim_tmxr_poll_lock); +if (sim_asynch_enabled) { + pthread_attr_t attr; + + pthread_cond_init (&sim_console_startup_cond, NULL); + pthread_attr_init (&attr); + pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); + pthread_create (&sim_console_poll_thread, &attr, _console_poll, NULL); + pthread_attr_destroy( &attr); + pthread_cond_wait (&sim_console_startup_cond, &sim_tmxr_poll_lock); /* Wait for thread to stabilize */ + pthread_cond_destroy (&sim_console_startup_cond); + sim_console_poll_running = TRUE; + } +pthread_mutex_unlock (&sim_tmxr_poll_lock); +#endif +tmxr_start_poll (); +return sim_os_ttrun (); +} + +t_stat sim_ttcmd (void) +{ +#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX) +pthread_mutex_lock (&sim_tmxr_poll_lock); +if (sim_console_poll_running) { + pthread_cond_signal (&sim_tmxr_poll_cond); + pthread_mutex_unlock (&sim_tmxr_poll_lock); + pthread_join (sim_console_poll_thread, NULL); + sim_console_poll_running = FALSE; + } +else + pthread_mutex_unlock (&sim_tmxr_poll_lock); +#endif +tmxr_stop_poll (); +return sim_os_ttcmd (); +} + +t_stat sim_ttclose (void) +{ +tmxr_shutdown (); +return sim_os_ttclose (); +} + +t_bool sim_ttisatty (void) +{ +return sim_os_ttisatty (); +} + + +/* Platform specific routine definitions */ + /* VMS routines, from Ben Thomas, with fixes from Robert Alan Byer */ #if defined (VMS) @@ -796,6 +1007,7 @@ return c; #if defined(__VAX) #define sys$assign SYS$ASSIGN #define sys$qiow SYS$QIOW +#define sys$dassgn SYS$DASSGN #endif #include @@ -808,6 +1020,7 @@ return c; #define EFN 0 uint32 tty_chan = 0; +int buffered_character = 0; typedef struct { unsigned short sense_count; @@ -824,7 +1037,7 @@ typedef struct { SENSE_BUF cmd_mode = { 0 }; SENSE_BUF run_mode = { 0 }; -t_stat sim_ttinit (void) +t_stat sim_os_ttinit (void) { unsigned int status; IOSB iosb; @@ -843,7 +1056,7 @@ run_mode.stat2 = cmd_mode.stat2 | TT2$M_PASTHRU; return SCPE_OK; } -t_stat sim_ttrun (void) +t_stat sim_os_ttrun (void) { unsigned int status; IOSB iosb; @@ -855,7 +1068,7 @@ if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_OK; } -t_stat sim_ttcmd (void) +t_stat sim_os_ttcmd (void) { unsigned int status; IOSB iosb; @@ -867,17 +1080,19 @@ if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_OK; } -t_stat sim_ttclose (void) +t_stat sim_os_ttclose (void) { -return sim_ttcmd (); +sim_ttcmd (); +sys$dassgn (tty_chan); +return SCPE_OK; } -t_bool sim_ttisatty (void) +t_bool sim_os_ttisatty (void) { return isatty (fileno (stdin)); } -t_stat sim_os_poll_kbd (void) +t_stat sim_os_poll_kbd_data (void) { unsigned int status, term[2]; unsigned char buf[4]; @@ -902,6 +1117,40 @@ if (sim_brk_char && (buf[0] == sim_brk_char)) return (buf[0] | SCPE_KFLAG); } +t_stat sim_os_poll_kbd (void) +{ +t_stat response; + +if (response = buffered_character) { + buffered_character = 0; + return response; + } +return sim_os_poll_kbd_data (); +} + +t_bool sim_os_poll_kbd_ready (int ms_timeout) +{ +unsigned int status, term[2]; +unsigned char buf[4]; +IOSB iosb; + +term[0] = 0; term[1] = 0; +status = sys$qiow (EFN, tty_chan, + IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO, + &iosb, 0, 0, buf, 1, (ms_timeout+999)/1000, term, 0, 0); +if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) + return FALSE; +if (buf[0] == sim_int_char) + buffered_character = SCPE_STOP; +else + if (sim_brk_char && (buf[0] == sim_brk_char)) + buffered_character = SCPE_BREAK; + else + buffered_character = (buf[0] | SCPE_KFLAG); +return TRUE; +} + + t_stat sim_os_putchar (int32 out) { unsigned int status; @@ -958,7 +1207,7 @@ ControlHandler(DWORD dwCtrlType) return FALSE; } -t_stat sim_ttinit (void) +t_stat sim_os_ttinit (void) { SetConsoleCtrlHandler( ControlHandler, TRUE ); std_input = GetStdHandle (STD_INPUT_HANDLE); @@ -969,7 +1218,7 @@ if ((std_input) && /* Not Background proces return SCPE_OK; } -t_stat sim_ttrun (void) +t_stat sim_os_ttrun (void) { if ((std_input) && /* If Not Background process? */ (std_input != INVALID_HANDLE_VALUE) && @@ -984,7 +1233,7 @@ SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); return SCPE_OK; } -t_stat sim_ttcmd (void) +t_stat sim_os_ttcmd (void) { if (sim_log) { fflush (sim_log); @@ -998,12 +1247,12 @@ if ((std_input) && /* If Not Background pro return SCPE_OK; } -t_stat sim_ttclose (void) +t_stat sim_os_ttclose (void) { return SCPE_OK; } -t_bool sim_ttisatty (void) +t_bool sim_os_ttisatty (void) { DWORD Mode; @@ -1016,7 +1265,7 @@ int c = -1; DWORD nkbevents, nkbevent; INPUT_RECORD rec; -\ +sim_debug (DBG_TRC, &sim_con_telnet, "sim_os_poll_kbd()\n"); if ((std_input == NULL) || /* No keyboard for */ (std_input == INVALID_HANDLE_VALUE)) /* background processes */ @@ -1053,6 +1302,17 @@ if ((sim_brk_char && ((c & 0177) == sim_brk_char)) || (c & SCPE_BREAK)) return c | SCPE_KFLAG; } +t_bool sim_os_poll_kbd_ready (int ms_timeout) +{ +sim_debug (DBG_TRC, &sim_con_telnet, "sim_os_poll_kbd_ready()\n"); +if ((std_input == NULL) || /* No keyboard for */ + (std_input == INVALID_HANDLE_VALUE)) { /* background processes */ + Sleep (ms_timeout); + return FALSE; + } +return (WAIT_OBJECT_0 == WaitForSingleObject (std_input, ms_timeout)); +} + t_stat sim_os_putchar (int32 c) { DWORD unused; @@ -1068,27 +1328,27 @@ return SCPE_OK; #include -t_stat sim_ttinit (void) +t_stat sim_os_ttinit (void) { return SCPE_OK; } -t_stat sim_ttrun (void) +t_stat sim_os_ttrun (void) { return SCPE_OK; } -t_stat sim_ttcmd (void) +t_stat sim_os_ttcmd (void) { return SCPE_OK; } -t_stat sim_ttclose (void) +t_stat sim_os_ttclose (void) { return SCPE_OK; } -t_bool sim_ttisatty (void) +t_bool sim_os_ttisatty (void) { return 1; } @@ -1124,6 +1384,12 @@ if (sim_brk_char && ((c & 0177) == sim_brk_char)) return c | SCPE_KFLAG; } +t_bool sim_os_poll_kbd_ready (int ms_timeout) /* Don't know how to do this on this platform */ +{ +sim_os_ms_sleep (MIN(20,ms_timeout)); /* Wait a little */ +return TRUE; /* force a poll */ +} + t_stat sim_os_putchar (int32 c) { if (c != 0177) { @@ -1251,7 +1517,7 @@ int ps_getch(void) { /* Note that this only works if the call to sim_ttinit comes before any output to the console */ -t_stat sim_ttinit (void) { +t_stat sim_os_ttinit (void) { int i; /* this blank will later be replaced by the number of characters */ char title[50] = " "; @@ -1274,22 +1540,22 @@ t_stat sim_ttinit (void) { return SCPE_OK; } -t_stat sim_ttrun (void) +t_stat sim_os_ttrun (void) { return SCPE_OK; } -t_stat sim_ttcmd (void) +t_stat sim_os_ttcmd (void) { return SCPE_OK; } -t_stat sim_ttclose (void) +t_stat sim_os_ttclose (void) { return SCPE_OK; } -t_bool sim_ttisatty (void) +t_bool sim_os_ttisatty (void) { return 1; } @@ -1309,6 +1575,12 @@ if (sim_brk_char && ((c & 0177) == sim_brk_char)) return c | SCPE_KFLAG; } +t_bool sim_os_poll_kbd_ready (int ms_timeout) /* Don't know how to do this on this platform */ +{ +sim_os_ms_sleep (MIN(20,ms_timeout)); /* Wait a little */ +return TRUE; /* force a poll */ +} + t_stat sim_os_putchar (int32 c) { if (c != 0177) { @@ -1331,7 +1603,7 @@ struct tchars cmdtchars,runtchars; /* V7 editing */ struct ltchars cmdltchars,runltchars; /* 4.2 BSD editing */ int cmdfl,runfl; /* TTY flags */ -t_stat sim_ttinit (void) +t_stat sim_os_ttinit (void) { cmdfl = fcntl (0, F_GETFL, 0); /* get old flags and status */ runfl = cmdfl | FNDELAY; @@ -1358,7 +1630,7 @@ runltchars.t_lnextc = 0xFF; return SCPE_OK; /* return success */ } -t_stat sim_ttrun (void) +t_stat sim_os_ttrun (void) { runtchars.t_intrc = sim_int_char; /* in case changed */ fcntl (0, F_SETFL, runfl); /* non-block mode */ @@ -1372,7 +1644,7 @@ nice (10); /* lower priority */ return SCPE_OK; } -t_stat sim_ttcmd (void) +t_stat sim_os_ttcmd (void) { nice (-10); /* restore priority */ fcntl (0, F_SETFL, cmdfl); /* block mode */ @@ -1385,12 +1657,12 @@ if (ioctl (0, TIOCSLTC, &cmdltchars) < 0) return SCPE_OK; } -t_stat sim_ttclose (void) +t_stat sim_os_ttclose (void) { return sim_ttcmd (); } -t_bool sim_ttisatty (void) +t_bool sim_os_ttisatty (void) { return isatty (0); } @@ -1407,6 +1679,22 @@ if (sim_brk_char && (buf[0] == sim_brk_char)) else return (buf[0] | SCPE_KFLAG); } +t_bool sim_os_poll_kbd_ready (int ms_timeout) +{ +fd_set readfds; +struct timeval timeout; + +if (!isatty (0)) { /* skip if !tty */ + sim_os_ms_sleep (ms_timeout); + return FALSE; + } +FD_ZERO (&readfds); +FD_SET (0, &readfds); +timeout.tv_sec = (ms_timeout*1000)/1000000; +timeout.tv_usec = (ms_timeout*1000)%1000000; +return (1 == select (1, &readfds, NULL, NULL, &timeout)); +} + t_stat sim_os_putchar (int32 out) { char c; @@ -1426,7 +1714,7 @@ return SCPE_OK; struct termios cmdtty, runtty; static int prior_norm = 1; -t_stat sim_ttinit (void) +t_stat sim_os_ttinit (void) { if (!isatty (fileno (stdin))) /* skip if !tty */ return SCPE_OK; @@ -1468,7 +1756,7 @@ runtty.c_cc[VSTATUS] = 0; return SCPE_OK; } -t_stat sim_ttrun (void) +t_stat sim_os_ttrun (void) { if (!isatty (fileno (stdin))) /* skip if !tty */ return SCPE_OK; @@ -1477,19 +1765,19 @@ if (tcsetattr (0, TCSAFLUSH, &runtty) < 0) return SCPE_TTIERR; if (prior_norm) { /* at normal pri? */ errno = 0; - nice (10); /* try to lower pri */ + (void)nice (10); /* try to lower pri */ prior_norm = errno; /* if no error, done */ } return SCPE_OK; } -t_stat sim_ttcmd (void) +t_stat sim_os_ttcmd (void) { if (!isatty (fileno (stdin))) /* skip if !tty */ return SCPE_OK; if (!prior_norm) { /* priority down? */ errno = 0; - nice (-10); /* try to raise pri */ + (void)nice (-10); /* try to raise pri */ prior_norm = (errno == 0); /* if no error, done */ } if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0) @@ -1497,12 +1785,12 @@ if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0) return SCPE_OK; } -t_stat sim_ttclose (void) +t_stat sim_os_ttclose (void) { return sim_ttcmd (); } -t_bool sim_ttisatty(void) +t_bool sim_os_ttisatty (void) { return isatty (fileno (stdin)); } @@ -1519,12 +1807,28 @@ if (sim_brk_char && (buf[0] == sim_brk_char)) else return (buf[0] | SCPE_KFLAG); } +t_bool sim_os_poll_kbd_ready (int ms_timeout) +{ +fd_set readfds; +struct timeval timeout; + +if (!sim_os_ttisatty()) { /* skip if !tty */ + sim_os_ms_sleep (ms_timeout); + return FALSE; + } +FD_ZERO (&readfds); +FD_SET (0, &readfds); +timeout.tv_sec = (ms_timeout*1000)/1000000; +timeout.tv_usec = (ms_timeout*1000)%1000000; +return (1 == select (1, &readfds, NULL, NULL, &timeout)); +} + t_stat sim_os_putchar (int32 out) { char c; c = out; -write (1, &c, 1); +(void)write (1, &c, 1); return SCPE_OK; } diff --git a/sim_console.h b/sim_console.h index 78d51dd7..df032838 100644 --- a/sim_console.h +++ b/sim_console.h @@ -55,9 +55,12 @@ t_stat sim_set_console (int32 flag, char *cptr); t_stat sim_set_kmap (int32 flag, char *cptr); t_stat sim_set_telnet (int32 flag, char *cptr); t_stat sim_set_notelnet (int32 flag, char *cptr); +t_stat sim_set_serial (int32 flag, char *cptr); +t_stat sim_set_noserial (int32 flag, char *cptr); t_stat sim_set_logon (int32 flag, char *cptr); t_stat sim_set_logoff (int32 flag, char *cptr); t_stat sim_set_debon (int32 flag, char *cptr); +t_stat sim_set_cons_debug (int32 flg, char *cptr); t_stat sim_set_cons_buff (int32 flg, char *cptr); t_stat sim_set_cons_unbuff (int32 flg, char *cptr); t_stat sim_set_cons_log (int32 flg, char *cptr); @@ -72,6 +75,7 @@ t_stat sim_show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cpt t_stat sim_show_pchar (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat sim_show_cons_buff (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat sim_show_cons_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat sim_show_cons_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat sim_check_console (int32 sec); t_stat sim_open_logfile (char *filename, t_bool binary, FILE **pf, FILEREF **pref); t_stat sim_close_logfile (FILEREF **pref); @@ -85,7 +89,6 @@ t_stat sim_ttcmd (void); t_stat sim_ttclose (void); t_bool sim_ttisatty(void); t_stat sim_os_poll_kbd (void); -t_stat sim_os_putchar (int32 out); int32 sim_tt_inpcvt (int32 c, uint32 mode); int32 sim_tt_outcvt (int32 c, uint32 mode); diff --git a/sim_defs.h b/sim_defs.h index f1e97d72..ebca45ed 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -275,9 +275,17 @@ typedef uint32 t_addr; #define SWMASK(x) (1u << (((int) (x)) - ((int) 'A'))) -/* String match */ +/* String match - at least one character required */ -#define MATCH_CMD(ptr,cmd) strncmp ((ptr), (cmd), strlen (ptr)) +#define MATCH_CMD(ptr,cmd) ((NULL == (ptr)) || (!*(ptr)) || strncmp ((ptr), (cmd), strlen (ptr))) + +/* End of Linked List/Queue value */ +/* Chosen for 2 reasons: */ +/* 1 - to not be NULL, this allowing the NULL value to */ +/* indicate inclusion on a list */ +/* and */ +/* 2 - to not be a valid/possible pointer (alignment) */ +#define QUEUE_LIST_END ((void *)1) /* Device data structure */ @@ -378,25 +386,29 @@ struct sim_unit { /* Unit flags */ -#define UNIT_V_UF_31 12 /* dev spec, V3.1 */ -#define UNIT_V_UF 16 /* device specific */ -#define UNIT_V_RSV 31 /* reserved!! */ +#define UNIT_V_UF_31 12 /* dev spec, V3.1 */ +#define UNIT_V_UF 16 /* device specific */ +#define UNIT_V_RSV 31 /* reserved!! */ -#define UNIT_ATTABLE 000001 /* attachable */ -#define UNIT_RO 000002 /* read only */ -#define UNIT_FIX 000004 /* fixed capacity */ -#define UNIT_SEQ 000010 /* sequential */ -#define UNIT_ATT 000020 /* attached */ -#define UNIT_BINK 000040 /* K = power of 2 */ -#define UNIT_BUFABLE 000100 /* bufferable */ -#define UNIT_MUSTBUF 000200 /* must buffer */ -#define UNIT_BUF 000400 /* buffered */ -#define UNIT_ROABLE 001000 /* read only ok */ -#define UNIT_DISABLE 002000 /* disable-able */ -#define UNIT_DIS 004000 /* disabled */ -#define UNIT_RAW 010000 /* raw mode */ -#define UNIT_TEXT 020000 /* text mode */ -#define UNIT_IDLE 040000 /* idle eligible */ +#define UNIT_ATTABLE 0000001 /* attachable */ +#define UNIT_RO 0000002 /* read only */ +#define UNIT_FIX 0000004 /* fixed capacity */ +#define UNIT_SEQ 0000010 /* sequential */ +#define UNIT_ATT 0000020 /* attached */ +#define UNIT_BINK 0000040 /* K = power of 2 */ +#define UNIT_BUFABLE 0000100 /* bufferable */ +#define UNIT_MUSTBUF 0000200 /* must buffer */ +#define UNIT_BUF 0000400 /* buffered */ +#define UNIT_ROABLE 0001000 /* read only ok */ +#define UNIT_DISABLE 0002000 /* disable-able */ +#define UNIT_DIS 0004000 /* disabled */ +#define UNIT_RAW 0010000 /* raw mode */ +#define UNIT_TEXT 0020000 /* text mode */ +#define UNIT_IDLE 0040000 /* idle eligible */ +#define UNIT_ATTMULT 0100000 /* Allow multiple attach commands */ +#define UNIT_TM_POLL 0400000 /* TMXR Polling unit */ + /* This flag is ONLY set dynamically */ + /* it should NOT be set via initialization */ #define UNIT_UFMASK_31 (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF_31) - 1)) #define UNIT_UFMASK (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF) - 1)) @@ -536,12 +548,12 @@ struct sim_fileref { #define BRDATA(nm,loc,rdx,wd,dep) #nm, (loc), (rdx), (wd), 0, (dep) #define URDATA(nm,loc,rdx,wd,off,dep,fl) \ #nm, &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#define BIT(nm) {#nm, -1, 1} /* Single Bit definition */ -#define BITNC {"", -1, 1} /* Don't care Bit definition */ -#define BITF(nm,sz) {#nm, -1, sz} /* Bit Field definition */ -#define BITNCF(sz) {"", -1, sz} /* Don't care Bit Field definition */ -#define BITFFMT(nm,sz,fmt) {#nm, -1, sz, NULL, #fmt}/* Bit Field definition with Output format */ -#define BITFNAM(nm,sz,names) {#nm, -1, sz, names} /* Bit Field definition with value->name map */ +#define BIT(nm) {#nm, 0xffffffff, 1} /* Single Bit definition */ +#define BITNC {"", 0xffffffff, 1} /* Don't care Bit definition */ +#define BITF(nm,sz) {#nm, 0xffffffff, sz} /* Bit Field definition */ +#define BITNCF(sz) {"", 0xffffffff, sz} /* Don't care Bit Field definition */ +#define BITFFMT(nm,sz,fmt) {#nm, 0xffffffff, sz, NULL, #fmt}/* Bit Field definition with Output format */ +#define BITFNAM(nm,sz,names) {#nm, 0xffffffff, sz, names} /* Bit Field definition with value->name map */ #else #define ORDATA(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1 #define DRDATA(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1 @@ -551,12 +563,12 @@ struct sim_fileref { #define BRDATA(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep) #define URDATA(nm,loc,rdx,wd,off,dep,fl) \ "nm", &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#define BIT(nm) {"nm", -1, 1} /* Single Bit definition */ -#define BITNC {"", -1, 1} /* Don't care Bit definition */ -#define BITF(nm,sz) {"nm", -1, sz} /* Bit Field definition */ -#define BITNCF(sz) {"", -1, sz} /* Don't care Bit Field definition */ -#define BITFFMT(nm,sz,fmt) {"nm", -1, sz, NULL, "fmt"}/* Bit Field definition with Output format */ -#define BITFNAM(nm,sz,names) {"nm", -1, sz, names} /* Bit Field definition with value->name map */ +#define BIT(nm) {"nm", 0xffffffff, 1} /* Single Bit definition */ +#define BITNC {"", 0xffffffff, 1} /* Don't care Bit definition */ +#define BITF(nm,sz) {"nm", 0xffffffff, sz} /* Bit Field definition */ +#define BITNCF(sz) {"", 0xffffffff, sz} /* Don't care Bit Field definition */ +#define BITFFMT(nm,sz,fmt) {"nm", 0xffffffff, sz, NULL, "fmt"}/* Bit Field definition with Output format */ +#define BITFNAM(nm,sz,names) {"nm", 0xffffffff, sz, names} /* Bit Field definition with value->name map */ #endif #define ENDBITS {NULL} /* end of bitfield list */ @@ -597,22 +609,41 @@ extern int32 sim_asynch_check; extern int32 sim_asynch_latency; extern int32 sim_asynch_inst_latency; -#define AIO_LIST_END ((void *)1) /* Chosen to deliberately not be a valid pointer (alignment) */ +/* Thread local storage */ +#if defined(__GNUC__) && !defined(__APPLE__) +#define AIO_TLS __thread +#elif defined(_MSC_VER) +#define AIO_TLS __declspec(thread) +#else +/* Other compiler environment, then don't worry about thread local storage. */ +/* It is primarily used only used in debugging messages */ +#define AIO_TLS +#endif + #define AIO_INIT \ if (1) { \ sim_asynch_main_threadid = pthread_self(); \ /* Empty list/list end uses the point value (void *)1. \ This allows NULL in an entry's a_next pointer to \ indicate that the entry is not currently in any list */ \ - sim_asynch_queue = AIO_LIST_END; \ - } + sim_asynch_queue = QUEUE_LIST_END; \ + } \ + else \ + (void)0 #define AIO_CLEANUP \ if (1) { \ pthread_mutex_destroy(&sim_asynch_lock); \ pthread_cond_destroy(&sim_asynch_wake); \ - } + } \ + else \ + (void)0 #define AIO_IS_ACTIVE(uptr) (((uptr)->a_is_active ? (uptr)->a_is_active (uptr) : FALSE) || ((uptr)->a_next)) #define AIO_CANCEL(uptr) if ((uptr)->a_cancel) (uptr)->a_cancel (uptr); else (void)0 +#define AIO_LOCK \ + pthread_mutex_lock(&sim_asynch_lock) +#define AIO_UNLOCK \ + pthread_mutex_unlock(&sim_asynch_lock) + #if defined(__DECC_VER) #include #if defined(__IA64) @@ -641,13 +672,13 @@ extern int32 sim_asynch_inst_latency; #define AIO_QUEUE_VAL InterlockedCompareExchangePointer(&sim_asynch_queue, sim_asynch_queue, NULL) #define AIO_QUEUE_SET(val, queue) InterlockedCompareExchangePointer(&sim_asynch_queue, val, queue) #define AIO_UPDATE_QUEUE \ - if (AIO_QUEUE_VAL != AIO_LIST_END) { /* List !Empty */ \ + if (AIO_QUEUE_VAL != QUEUE_LIST_END) { /* List !Empty */ \ UNIT *q, *uptr; \ int32 a_event_time; \ do \ q = AIO_QUEUE_VAL; \ - while (q != AIO_QUEUE_SET(AIO_LIST_END, q)); \ - while (q != AIO_LIST_END) { /* List !Empty */ \ + while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q)); \ + while (q != QUEUE_LIST_END) { /* List !Empty */ \ uptr = q; \ q = q->a_next; \ uptr->a_next = NULL; /* hygiene */ \ @@ -671,18 +702,18 @@ extern int32 sim_asynch_inst_latency; UNIT *q, *qe; \ uptr->a_event_time = event_time; \ uptr->a_activate_call = sim_activate; \ - uptr->a_next = AIO_LIST_END; /* Mark as on list */ \ + uptr->a_next = QUEUE_LIST_END; /* Mark as on list */ \ do { \ do \ q = AIO_QUEUE_VAL; \ - while (q != AIO_QUEUE_SET(AIO_LIST_END, q));/* Grab current list */ \ - for (qe = uptr; qe->a_next != AIO_LIST_END; qe = qe->a_next); \ + while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q));/* Grab current list */\ + for (qe = uptr; qe->a_next != QUEUE_LIST_END; qe = qe->a_next); \ qe->a_next = q; /* append current list */\ do \ q = AIO_QUEUE_VAL; \ while (q != AIO_QUEUE_SET(uptr, q)); \ uptr = q; \ - } while (uptr != AIO_LIST_END); \ + } while (uptr != QUEUE_LIST_END); \ } \ if (sim_idle_wait) \ pthread_cond_signal (&sim_asynch_wake); \ @@ -696,7 +727,7 @@ extern int32 sim_asynch_inst_latency; if (1) { \ UNIT *uptr; \ pthread_mutex_lock (&sim_asynch_lock); \ - while (sim_asynch_queue != AIO_LIST_END) { /* List !Empty */ \ + while (sim_asynch_queue != QUEUE_LIST_END) { /* List !Empty */ \ int32 a_event_time; \ uptr = sim_asynch_queue; \ sim_asynch_queue = uptr->a_next; \ @@ -753,9 +784,11 @@ extern int32 sim_asynch_inst_latency; #define AIO_CHECK_EVENT #define AIO_INIT #define AIO_CLEANUP +#define AIO_RETURN_TIME(uptr) #define AIO_IS_ACTIVE(uptr) FALSE #define AIO_CANCEL(uptr) #define AIO_SET_INTERRUPT_LATENCY(instpersec) +#define AIO_TLS #endif /* SIM_ASYNCH_IO */ #endif diff --git a/sim_disk.c b/sim_disk.c index 7ada5cc4..d46ea99c 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -137,7 +137,7 @@ if ((!callback) || !ctx->asynch_io) \ sim_debug (ctx->dbit, ctx->dptr, \ "sim_disk AIO_CALL(op=%d, unit=%d, lba=0x%X, sects=%d)\n",\ - op, uptr-ctx->dptr->units, _lba, _sects); \ + op, (int)(uptr-ctx->dptr->units), _lba, _sects);\ \ if (ctx->callback) \ abort(); /* horrible mistake, stop */ \ @@ -175,7 +175,7 @@ pthread_getschedparam (pthread_self(), &sched_policy, &sched_priority); ++sched_priority.sched_priority; pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); -sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) starting\n", uptr-ctx->dptr->units); +sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) starting\n", (int)(uptr-ctx->dptr->units)); pthread_mutex_lock (&ctx->io_lock); pthread_cond_signal (&ctx->startup_cond); /* Signal we're ready to go */ @@ -202,7 +202,7 @@ while (ctx->asynch_io) { } pthread_mutex_unlock (&ctx->io_lock); -sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) exiting\n", uptr-ctx->dptr->units); +sim_debug (ctx->dbit, ctx->dptr, "_disk_io(unit=%d) exiting\n", (int)(uptr-ctx->dptr->units)); return NULL; } @@ -223,7 +223,7 @@ static void _disk_completion_dispatch (UNIT *uptr) struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; DISK_PCALLBACK callback = ctx->callback; -sim_debug (ctx->dbit, ctx->dptr, "_disk_completion_dispatch(unit=%d, dop=%d, callback=%p)\n", uptr-ctx->dptr->units, ctx->io_dop, ctx->callback); +sim_debug (ctx->dbit, ctx->dptr, "_disk_completion_dispatch(unit=%d, dop=%d, callback=%p)\n", (int)(uptr-ctx->dptr->units), ctx->io_dop, ctx->callback); if (ctx->io_dop != DOP_DONE) abort(); /* horribly wrong, stop */ @@ -265,6 +265,7 @@ static t_stat sim_vhd_disk_implemented (void); static FILE *sim_vhd_disk_open (const char *rawdevicename, const char *openmode); static FILE *sim_vhd_disk_create (const char *szVHDPath, t_addr desiredsize); static FILE *sim_vhd_disk_create_diff (const char *szVHDPath, const char *szParentVHDPath); +static FILE *sim_vhd_disk_merge (const char *szVHDPath, char **ParentVHD); static int sim_vhd_disk_close (FILE *f); static void sim_vhd_disk_flush (FILE *f); static t_addr sim_vhd_disk_size (FILE *f); @@ -283,6 +284,8 @@ static t_stat sim_os_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *s static t_stat sim_os_disk_wrsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectswritten, t_seccnt sects); static t_stat sim_os_disk_info_raw (FILE *f, uint32 *sector_size, uint32 *removable); static t_stat sim_disk_pdp11_bad_block (UNIT *uptr, int32 sec); +static char *HostPathToVhdPath (const char *szHostPath, char *szVhdPath, size_t VhdPathSize); +static char *VhdPathToHostPath (const char *szVhdPath, char *szHostPath, size_t HostPathSize); struct sim_disk_fmt { char *name; /* name */ @@ -499,7 +502,7 @@ uint32 err, tbc; size_t i; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; -sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); +sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); da = ((t_addr)lba) * ctx->sector_size; tbc = sects * ctx->sector_size; @@ -523,7 +526,7 @@ t_stat r; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; t_seccnt sread; -sim_debug (ctx->dbit, ctx->dptr, "sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); +sim_debug (ctx->dbit, ctx->dptr, "sim_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); if ((sects == 1) && /* Single sector reads */ (lba >= (uptr->capac*ctx->capac_factor)/ctx->sector_size)) {/* beyond the end of the disk */ @@ -556,7 +559,7 @@ if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) || /* Sector Al return r; } else { /* Unaligned and/or partial sector transfers */ - uint8 *tbuf = malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size); + uint8 *tbuf = (uint8*) malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size); t_lba sspsts = ctx->storage_sector_size/ctx->sector_size; /* sim sectors in a storage sector */ t_lba tlba = lba & ~(sspsts - 1); t_seccnt tsects = sects + (lba - tlba); @@ -615,7 +618,7 @@ uint32 err, tbc; size_t i; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; -sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); +sim_debug (ctx->dbit, ctx->dptr, "_sim_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); da = ((t_addr)lba) * ctx->sector_size; tbc = sects * ctx->sector_size; @@ -638,7 +641,7 @@ uint32 f = DK_GET_FMT (uptr); t_stat r; uint8 *tbuf = NULL; -sim_debug (ctx->dbit, ctx->dptr, "sim_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); +sim_debug (ctx->dbit, ctx->dptr, "sim_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); if (f == DKUF_F_STD) return _sim_disk_wrsect (uptr, lba, buf, sectswritten, sects); @@ -656,7 +659,7 @@ if ((0 == (ctx->sector_size & (ctx->storage_sector_size - 1))) || /* Sector Al return SCPE_NOFNC; } - tbuf = malloc (sects * ctx->sector_size); + tbuf = (uint8*) malloc (sects * ctx->sector_size); if (NULL == tbuf) return SCPE_MEM; sim_buf_copy_swapped (tbuf, buf, ctx->xfer_element_size, (sects * ctx->sector_size) / ctx->xfer_element_size); @@ -678,7 +681,7 @@ else { /* Unaligned and/or partial sector transfers */ t_lba tlba = lba & ~(sspsts - 1); t_seccnt tsects = sects + (lba - tlba); - tbuf = malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size); + tbuf = (uint8*) malloc (sects*ctx->sector_size + 2*ctx->storage_sector_size); tsects = (tsects + (sspsts - 1)) & ~(sspsts - 1); if (sectswritten) *sectswritten = 0; @@ -868,7 +871,7 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop return SCPE_OPENERR; } else { - uint8 *copy_buf = malloc (1024*1024); + uint8 *copy_buf = (uint8*) malloc (1024*1024); t_lba lba; t_seccnt sectors_per_buffer = (t_seccnt)((1024*1024)/sector_size); t_lba total_sectors = (t_lba)((uptr->capac*capac_factor)/sector_size); @@ -908,6 +911,24 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop /* fall through and open/return the newly created & copied vhd */ } } +else if (sim_switches & SWMASK ('M')) { /* merge difference disk? */ + char gbuf[CBUFSIZE], *Parent = NULL; + FILE *vhd; + + sim_switches = sim_switches & ~(SWMASK ('M')); + get_glyph_nc (cptr, gbuf, 0); /* get spec */ + vhd = sim_vhd_disk_merge (gbuf, &Parent); + if (vhd) { + t_stat r; + + sim_vhd_disk_close (vhd); + r = sim_disk_attach (uptr, Parent, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize, completion_delay); + free (Parent); + return r; + } + return SCPE_ARG; + } + switch (DK_GET_FMT (uptr)) { /* case on format */ case DKUF_F_STD: /* SIMH format */ if (NULL == (uptr->fileref = sim_vhd_disk_open (cptr, "rb"))) { @@ -1032,7 +1053,7 @@ if (created) { } capac = size_function (uptr->fileref); -if (capac && (capac != (t_addr)-1)) +if (capac && (capac != (t_addr)-1)) { if (dontautosize) { if ((capac < (uptr->capac*ctx->capac_factor)) && (DKUF_F_STD != DK_GET_FMT (uptr))) { if (!sim_quiet) { @@ -1047,6 +1068,7 @@ if (capac && (capac != (t_addr)-1)) else if ((capac > (uptr->capac*ctx->capac_factor)) || (DKUF_F_STD != DK_GET_FMT (uptr))) uptr->capac = capac/ctx->capac_factor; + } #if defined (SIM_ASYNCH_IO) sim_disk_set_async (uptr, completion_delay); @@ -1176,7 +1198,7 @@ void sim_disk_data_trace(UNIT *uptr, const uint8 *data, size_t lba, size_t len, struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; if (ctx->dptr->dctrl & reason) { - sim_debug (reason, ctx->dptr, "%s%d %s lbn: %08X len: %08X\n", ctx->dptr->name, uptr-ctx->dptr->units, txt, lba, len); + sim_debug (reason, ctx->dptr, "%s%d %s lbn: %08X len: %08X\n", ctx->dptr->name, (int)(uptr-ctx->dptr->units), txt, lba, len); if (detail) { size_t i, same, group, sidx, oidx; char outbuf[80], strbuf[18]; @@ -1186,11 +1208,11 @@ if (ctx->dptr->dctrl & reason) { if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) { ++same; continue; - } + } if (same > 0) { sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), i-1); same = 0; - } + } group = (((len - i) > 16) ? 16 : (len - i)); for (sidx=oidx=0; sidxdptr->dctrl & reason) { strbuf[sidx] = data[i+sidx]; else strbuf[sidx] = '.'; - } + } outbuf[oidx] = '\0'; strbuf[sidx] = '\0'; sim_debug (reason, ctx->dptr, "%04X%-48s %s\n", i, outbuf, strbuf); - } - if (same > 0) - sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), len-1); + } + if (same > 0) { + sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), len-1); + } } } } @@ -1287,7 +1310,12 @@ if ((dwStatus >= ERROR_INVALID_STARTING_CODESEG) && (dwStatus <= ERROR_INFLOOP_I } errno = EINVAL; } +#if defined(__GNUC__) +#include +#include +#else #include +#endif struct _device_type { int32 Type; char *desc; @@ -1528,7 +1556,6 @@ return TRUE; static t_stat sim_os_disk_info_raw (FILE *Disk, uint32 *sector_size, uint32 *removable) { DWORD IoctlReturnSize; -#ifndef __GNUC__ STORAGE_DEVICE_NUMBER Device; ZeroMemory (&Device, sizeof (Device)); @@ -1540,8 +1567,7 @@ if (DeviceIoControl((HANDLE)Disk, /* handle to volume */ (DWORD) sizeof(Device), /* size of output buffer */ (LPDWORD) &IoctlReturnSize, /* number of bytes returned */ (LPOVERLAPPED) NULL)) /* OVERLAPPED structure */ - printf ("Device OK - Type: %s, Number: %d\n", _device_type_name (Device.DeviceType), Device.DeviceNumber); -#endif + printf ("Device OK - Type: %s, Number: %d\n", _device_type_name (Device.DeviceType), (int)Device.DeviceNumber); if (sector_size) *sector_size = 512; @@ -1626,7 +1652,7 @@ OVERLAPPED pos; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; long long addr; -sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); +sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); addr = ((long long)lba) * ctx->sector_size; memset (&pos, 0, sizeof (pos)); @@ -1647,7 +1673,7 @@ OVERLAPPED pos; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; long long addr; -sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); +sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); addr = ((long long)lba) * ctx->sector_size; memset (&pos, 0, sizeof (pos)); @@ -1676,7 +1702,6 @@ return SCPE_OK; static FILE *sim_os_disk_open_raw (const char *rawdevicename, const char *openmode) { -int fd; int mode = 0; if (strchr (openmode, 'r') && (strchr (openmode, '+') || strchr (openmode, 'w'))) @@ -1728,7 +1753,7 @@ struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; off_t addr; ssize_t bytesread; -sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); +sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_rdsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); addr = ((off_t)lba) * ctx->sector_size; bytesread = pread((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr); @@ -1748,7 +1773,7 @@ struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; off_t addr; ssize_t byteswritten; -sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", uptr-ctx->dptr->units, lba, sects); +sim_debug (ctx->dbit, ctx->dptr, "sim_os_disk_wrsect(unit=%d, lba=0x%X, sects=%d)\n", (int)(uptr-ctx->dptr->units), lba, sects); addr = ((off_t)lba) * ctx->sector_size; byteswritten = pwrite((int)((long)uptr->fileref), buf, sects * ctx->sector_size, addr); @@ -1845,7 +1870,12 @@ static t_stat sim_vhd_disk_implemented (void) return SCPE_NOFNC; } -static FILE *sim_vhd_disk_open (const char *rawdevicename, const char *openmode) +static FILE *sim_vhd_disk_open (const char *vhdfilename, const char *openmode) +{ +return NULL; +} + +static FILE *sim_vhd_disk_merge (const char *szVHDPath, char **ParentVHD) { return NULL; } @@ -1919,7 +1949,7 @@ typedef struct _VHD_Footer { table displays the list of features. Any fields not listed are reserved. - Feature Value: + Feature Value: No features enabled 0x00000000 Temporary 0x00000001 Reserved 0x00000002 @@ -2192,19 +2222,9 @@ typedef struct _VHD_DynamicDiskHeader { #define VHD_BAT_FREE_ENTRY (0xFFFFFFFF) #define VHD_DATA_BLOCK_ALIGNMENT ((uint64)4096) /* Optimum when underlying storage has 4k sectors */ -static char *VHD_DiskTypes[] = - { - "None", /* 0 */ - "Reserved (deprecated)", /* 1 */ - "Fixed hard disk", /* 2 */ -#define VHD_DT_Fixed 2 - "Dynamic hard disk", /* 3 */ -#define VHD_DT_Dynamic 3 - "Differencing hard disk", /* 4 */ -#define VHD_DT_Differencing 4 - "Reserved (deprecated)", /* 5 */ - "Reserved (deprecated)", /* 6 */ - }; +#define VHD_DT_Fixed 2 /* Fixed hard disk */ +#define VHD_DT_Dynamic 3 /* Dynamic hard disk */ +#define VHD_DT_Differencing 4 /* Differencing hard disk */ static uint32 NtoHl(uint32 value); @@ -2321,7 +2341,7 @@ static int GetVHDFooter(const char *szVHDPath, VHD_Footer *sFooter, - VHD_DynamicDiskHeader *sDynamic, + VHD_DynamicDiskHeader *sDynamic, uint32 **aBAT, uint32 *ModifiedTimeStamp, char *szParentVHDPath, @@ -2345,13 +2365,14 @@ if (!File) { Return = errno; goto Return_Cleanup; } -if (ModifiedTimeStamp) +if (ModifiedTimeStamp) { if (stat (szVHDPath, &statb)) { Return = errno; goto Return_Cleanup; } else *ModifiedTimeStamp = NtoHl ((uint32)(statb.st_mtime-946684800)); + } position = sim_fsize_ex (File); if (((int64)position) == -1) { Return = errno; @@ -2413,9 +2434,8 @@ if ((sDynamic) && Return = errno; goto Return_Cleanup; } - if (aBAT) - { - *aBAT = malloc(512*((sizeof(**aBAT)*NtoHl(sDynamic->MaxTableEntries)+511)/512)); + if (aBAT) { + *aBAT = (uint32*) malloc(512*((sizeof(**aBAT)*NtoHl(sDynamic->MaxTableEntries)+511)/512)); if (ReadFilePosition(File, *aBAT, sizeof (**aBAT)*NtoHl(sDynamic->MaxTableEntries), @@ -2429,27 +2449,27 @@ if ((sDynamic) && VHD_Footer sParentFooter; memset (szParentVHDPath, '\0', ParentVHDPathSize); - if (NtoHl (sFooter->DiskType) == VHD_DT_Differencing) - { + if (NtoHl (sFooter->DiskType) == VHD_DT_Differencing) { size_t i, j; - for (j=0; j<8; ++j) - { + for (j=0; j<8; ++j) { uint8 *Pdata; - char ParentName[256]; - char CheckPath[256]; + uint32 PdataSize; + char ParentName[512]; + char CheckPath[512]; uint32 ParentModificationTime; if ('\0' == sDynamic->ParentLocatorEntries[j].PlatformCode[0]) continue; memset (ParentName, '\0', sizeof(ParentName)); memset (CheckPath, '\0', sizeof(CheckPath)); - Pdata = calloc (1, NtoHl(sDynamic->ParentLocatorEntries[j].PlatformDataSpace)+1); + PdataSize = NtoHl(sDynamic->ParentLocatorEntries[j].PlatformDataSpace); + Pdata = (uint8*) calloc (1, PdataSize+2); if (!Pdata) continue; if (ReadFilePosition(File, Pdata, - NtoHl (sDynamic->ParentLocatorEntries[j].PlatformDataSpace), + PdataSize, NULL, NtoHll (sDynamic->ParentLocatorEntries[j].PlatformDataOffset))) { free (Pdata); @@ -2465,14 +2485,15 @@ if ((sDynamic) && free (Pdata); if (0 == memcmp (sDynamic->ParentLocatorEntries[j].PlatformCode, "W2ku", 4)) strncpy (CheckPath, ParentName, sizeof (CheckPath)-1); - else - if (0 == memcmp (sDynamic->ParentLocatorEntries[j].PlatformCode, "W2ru", 4)) { - char *c; + else + if (0 == memcmp (sDynamic->ParentLocatorEntries[j].PlatformCode, "W2ru", 4)) { + const char *c; - if ((c = strrchr (szVHDPath, '/')) || (c = strrchr (szVHDPath, '\\'))) - memcpy (CheckPath, szVHDPath, c-szVHDPath+1); - strncpy (CheckPath+strlen(CheckPath), ParentName, sizeof (CheckPath)-(strlen (CheckPath)+1)); - } + if ((c = strrchr (szVHDPath, '\\'))) + memcpy (CheckPath, szVHDPath, c-szVHDPath+1); + strncpy (CheckPath+strlen(CheckPath), ParentName, sizeof (CheckPath)-(strlen (CheckPath)+1)); + } + VhdPathToHostPath (CheckPath, CheckPath, sizeof (CheckPath)); if ((0 == GetVHDFooter(CheckPath, &sParentFooter, NULL, @@ -2481,12 +2502,11 @@ if ((sDynamic) && NULL, 0)) && (0 == memcmp (sDynamic->ParentUniqueID, sParentFooter.UniqueID, sizeof (sParentFooter.UniqueID))) && - (sDynamic->ParentTimeStamp == ParentModificationTime)) - { + (sDynamic->ParentTimeStamp == ParentModificationTime)) { strncpy (szParentVHDPath, CheckPath, ParentVHDPathSize); break; } - } + } if (!szParentVHDPath) Return = EINVAL; /* File Corrupt */ } @@ -2577,25 +2597,43 @@ return (char *)(&hVHD->Footer.DriveType[0]); static FILE *sim_vhd_disk_open (const char *szVHDPath, const char *DesiredAccess) { - VHDHANDLE hVHD = calloc (1, sizeof(*hVHD)); + VHDHANDLE hVHD = (VHDHANDLE) calloc (1, sizeof(*hVHD)); int Status; if (!hVHD) return (FILE *)hVHD; - if (0 != (Status = GetVHDFooter (szVHDPath, - &hVHD->Footer, - &hVHD->Dynamic, - &hVHD->BAT, - NULL, - hVHD->ParentVHDPath, - sizeof (hVHD->ParentVHDPath)))) + Status = GetVHDFooter (szVHDPath, + &hVHD->Footer, + &hVHD->Dynamic, + &hVHD->BAT, + NULL, + hVHD->ParentVHDPath, + sizeof (hVHD->ParentVHDPath)); + if (Status) goto Cleanup_Return; if (NtoHl (hVHD->Footer.DiskType) == VHD_DT_Differencing) { + uint32 ParentModifiedTimeStamp; + VHD_Footer ParentFooter; + VHD_DynamicDiskHeader ParentDynamic; + hVHD->Parent = (VHDHANDLE)sim_vhd_disk_open (hVHD->ParentVHDPath, "rb"); if (!hVHD->Parent) { Status = errno; goto Cleanup_Return; } + Status = GetVHDFooter (hVHD->ParentVHDPath, + &ParentFooter, + &ParentDynamic, + NULL, + &ParentModifiedTimeStamp, + NULL, + 0); + if (Status) + goto Cleanup_Return; + if (ParentModifiedTimeStamp != hVHD->Dynamic.ParentTimeStamp) { + Status = EBADF; + goto Cleanup_Return; + } } if (hVHD->Footer.SavedState) { Status = EAGAIN; /* Busy */ @@ -2607,10 +2645,131 @@ static FILE *sim_vhd_disk_open (const char *szVHDPath, const char *DesiredAccess goto Cleanup_Return; } Cleanup_Return: + if (Status) { + sim_vhd_disk_close ((FILE *)hVHD); + hVHD = NULL; + } + errno = Status; + return (FILE *)hVHD; + } + +static t_stat +WriteVirtualDiskSectors(VHDHANDLE hVHD, + uint8 *buf, + t_seccnt sects, + t_seccnt *sectswritten, + uint32 SectorSize, + t_lba lba); + +static FILE *sim_vhd_disk_merge (const char *szVHDPath, char **ParentVHD) + { + VHDHANDLE hVHD = (VHDHANDLE) calloc (1, sizeof(*hVHD)); + VHDHANDLE Parent = NULL; + int Status; + uint32 SectorSize, SectorsPerBlock, BlockSize, BlockNumber, BitMapBytes, BitMapSectors, BlocksToMerge, NeededBlock; + uint64 BlockOffset; + size_t BytesRead; + t_seccnt SectorsWritten; + void *BlockData = NULL; + + if (!hVHD) + return (FILE *)hVHD; + if (0 != (Status = GetVHDFooter (szVHDPath, + &hVHD->Footer, + &hVHD->Dynamic, + &hVHD->BAT, + NULL, + hVHD->ParentVHDPath, + sizeof (hVHD->ParentVHDPath)))) + goto Cleanup_Return; + if (NtoHl (hVHD->Footer.DiskType) != VHD_DT_Differencing) { + Status = EINVAL; + goto Cleanup_Return; + } + if (hVHD->Footer.SavedState) { + Status = EAGAIN; /* Busy */ + goto Cleanup_Return; + } + SectorSize = 512; + BlockSize = NtoHl (hVHD->Dynamic.BlockSize); + BlockData = malloc (BlockSize*SectorSize); + if (NULL == BlockData) { + Status = errno; + goto Cleanup_Return; + } + Parent = (VHDHANDLE)sim_vhd_disk_open (hVHD->ParentVHDPath, "rb+"); + if (!Parent) { + Status = errno; + goto Cleanup_Return; + } + hVHD->File = sim_fopen (szVHDPath, "rb"); + if (!hVHD->File) { + Status = errno; + goto Cleanup_Return; + } + SectorsPerBlock = NtoHl (hVHD->Dynamic.BlockSize)/SectorSize; + BitMapBytes = (7+(NtoHl (hVHD->Dynamic.BlockSize)/SectorSize))/8; + BitMapSectors = (BitMapBytes+SectorSize-1)/SectorSize; + for (BlockNumber=BlocksToMerge=0; BlockNumber< NtoHl (hVHD->Dynamic.MaxTableEntries); ++BlockNumber) { + if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) + continue; + ++BlocksToMerge; + } + if (!sim_quiet) + printf ("Merging %s\ninto %s\n", szVHDPath, hVHD->ParentVHDPath); + for (BlockNumber=NeededBlock=0; BlockNumber < NtoHl (hVHD->Dynamic.MaxTableEntries); ++BlockNumber) { + uint32 BlockSectors = SectorsPerBlock; + + if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) + continue; + ++NeededBlock; + BlockOffset = SectorSize*((uint64)(NtoHl (hVHD->BAT[BlockNumber]) + BitMapSectors)); + if ((BlockNumber*SectorsPerBlock + BlockSectors) > ((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize) + BlockSectors = (uint32)(((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize - (BlockNumber*SectorsPerBlock)); + if (ReadFilePosition(hVHD->File, + BlockData, + SectorSize*BlockSectors, + &BytesRead, + BlockOffset)) + break; + if (WriteVirtualDiskSectors (Parent, + (uint8*)BlockData, + BlockSectors, + &SectorsWritten, + SectorSize, + SectorsPerBlock*BlockNumber)) + break; + if (!sim_quiet) + printf ("Merged %dMB. %d%% complete.\r", (int)(((float)NeededBlock*SectorsPerBlock)*SectorSize/1000000), (int)((NeededBlock*100)/BlocksToMerge)); + hVHD->BAT[BlockNumber] = VHD_BAT_FREE_ENTRY; + } + if (BlockNumber < NtoHl (hVHD->Dynamic.MaxTableEntries)) { + Status = errno; + } + else { + Status = 0; + if (!sim_quiet) + printf ("Merged %dMB. 100%% complete.\n", (int)(((float)NeededBlock*SectorsPerBlock)*SectorSize/1000000)); + fclose (hVHD->File); + hVHD->File = NULL; + remove (szVHDPath); + *ParentVHD = (char*) malloc (strlen (hVHD->ParentVHDPath)+1); + strcpy (*ParentVHD, hVHD->ParentVHDPath); + } +Cleanup_Return: + free (BlockData); + if (hVHD->File) + fclose (hVHD->File); if (Status) { free (hVHD->BAT); free (hVHD); hVHD = NULL; + sim_vhd_disk_close ((FILE *)Parent); + } + else { + free (hVHD->BAT); + free (hVHD); + hVHD = Parent; } errno = Status; return (FILE *)hVHD; @@ -2674,7 +2833,7 @@ RPC_STATUS (RPC_ENTRY *UuidCreate_c) (void *); if (!UuidCreate_c) { - HMODULE hDll; + HINSTANCE hDll; hDll = LoadLibraryA("rpcrt4.dll"); UuidCreate_c = (RPC_STATUS (RPC_ENTRY *) (void *))GetProcAddress(hDll, "UuidCreate"); } @@ -2696,7 +2855,7 @@ void *handle; #define __STR(tok) __STR_QUOTE(tok) handle = dlopen("libuuid." __STR(HAVE_DLOPEN), RTLD_NOW|RTLD_GLOBAL); if (handle) - uuid_generate_c = dlsym(handle, "uuid_generate"); + uuid_generate_c = (void (*)(void *))((size_t)dlsym(handle, "uuid_generate")); if (uuid_generate_c) uuid_generate_c(uuidaddr); else @@ -2727,6 +2886,7 @@ FILE *File = NULL; uint32 Status = 0; uint32 BytesPerSector = 512; uint64 SizeInBytes = ((uint64)SizeInSectors)*BytesPerSector; +uint64 TableOffset; uint32 MaxTableEntries; VHDHANDLE hVHD = NULL; @@ -2734,7 +2894,8 @@ if (SizeInBytes > ((uint64)(1024*1024*1024))*2040) { Status = EFBIG; goto Cleanup_Return; } -if (NULL != (File = sim_fopen (szVHDPath, "rb"))) { +File = sim_fopen (szVHDPath, "rb"); +if (File) { fclose (File); File = NULL; Status = EEXIST; @@ -2788,7 +2949,7 @@ if (1) { /* CHS Calculation */ { sectorsPerTrack = 31; heads = 16; - cylinderTimesHeads = totalSectors / sectorsPerTrack; + cylinderTimesHeads = totalSectors / sectorsPerTrack; } if (cylinderTimesHeads >= (heads * 1024)) { @@ -2816,7 +2977,10 @@ if (bFixedVHD) { memset (&Dynamic, 0, sizeof(Dynamic)); memcpy (Dynamic.Cookie, "cxsparse", 8); Dynamic.DataOffset = NtoHll (0xFFFFFFFFFFFFFFFFLL); -Dynamic.TableOffset = NtoHll ((uint64)(BytesPerSector*((sizeof(Dynamic)+sizeof(Footer)+BytesPerSector-1)/BytesPerSector))); +TableOffset = (uint64)(BytesPerSector*((sizeof(Dynamic)+sizeof(Footer)+BytesPerSector-1)/BytesPerSector)); +TableOffset += VHD_DATA_BLOCK_ALIGNMENT-1; +TableOffset &= ~(VHD_DATA_BLOCK_ALIGNMENT-1); +Dynamic.TableOffset = NtoHll (TableOffset); Dynamic.HeaderVersion = NtoHl (0x00010000); if (0 == BlockSize) BlockSize = 2*1024*1024; @@ -2824,7 +2988,7 @@ Dynamic.BlockSize = NtoHl (BlockSize); MaxTableEntries = (uint32)((SizeInBytes+BlockSize-1)/BlockSize); Dynamic.MaxTableEntries = NtoHl (MaxTableEntries); Dynamic.Checksum = NtoHl (CalculateVhdFooterChecksum(&Dynamic, sizeof(Dynamic))); -BAT = malloc (BytesPerSector*((MaxTableEntries*sizeof(*BAT)+BytesPerSector-1)/BytesPerSector)); +BAT = (uint32*) malloc (BytesPerSector*((MaxTableEntries*sizeof(*BAT)+BytesPerSector-1)/BytesPerSector)); memset (BAT, 0, BytesPerSector*((MaxTableEntries*sizeof(*BAT)+BytesPerSector-1)/BytesPerSector)); for (i=0; i +#endif static void ExpandToFullPath (const char *szFileSpec, char *szFullFileSpecBuffer, size_t BufferSize) { +char *c; #ifdef _WIN32 +for (c = strchr (szFullFileSpecBuffer, '/'); c; c = strchr (szFullFileSpecBuffer, '/')) + *c = '\\'; GetFullPathNameA (szFileSpec, (DWORD)BufferSize, szFullFileSpecBuffer, NULL); +for (c = strchr (szFullFileSpecBuffer, '\\'); c; c = strchr (szFullFileSpecBuffer, '\\')) + *c = '/'; #else -strncpy (szFullFileSpecBuffer, szFileSpec, BufferSize); +char buffer[PATH_MAX]; +char *wd = getcwd(buffer, PATH_MAX); + +if ((szFileSpec[0] != '/') || (strchr (szFileSpec, ':'))) + snprintf (szFullFileSpecBuffer, BufferSize, "%s/%s", wd, szFileSpec); +else + strncpy (szFullFileSpecBuffer, szFileSpec, BufferSize); +if ((c = strstr (szFullFileSpecBuffer, "]/"))) + strcpy (c+1, c+2); +memset (szFullFileSpecBuffer + strlen (szFullFileSpecBuffer), 0, BufferSize - strlen (szFullFileSpecBuffer)); #endif } +static char * +HostPathToVhdPath (const char *szHostPath, + char *szVhdPath, + size_t VhdPathSize) +{ +char *c, *d; + +strncpy (szVhdPath, szHostPath, VhdPathSize-1); +szVhdPath[VhdPathSize-1] = '\0'; +if ((c = strrchr (szVhdPath, ']'))) { + *c = '\0'; + if (!(d = strchr (szVhdPath, '['))) + return d; + *d = '/'; + while ((d = strchr (d, '.'))) + *d = '/'; + *c = '/'; + } +while ((c = strchr (szVhdPath, '/'))) + *c = '\\'; +for (c = strstr (szVhdPath, "\\.\\"); c; c = strstr (szVhdPath, "\\.\\")) + strcpy (c, c+2); +for (c = strstr (szVhdPath, "\\\\"); c; c = strstr (szVhdPath, "\\\\")) + strcpy (c, c+1); +while ((c = strstr (szVhdPath, "\\..\\"))) { + *c = '\0'; + d = strrchr (szVhdPath, '\\'); + if (d) + strcpy (d, c+3); + else + return d; + } +memset (szVhdPath + strlen (szVhdPath), 0, VhdPathSize - strlen (szVhdPath)); +return szVhdPath; +} + +static char * +VhdPathToHostPath (const char *szVhdPath, + char *szHostPath, + size_t HostPathSize) +{ +char *c; +char *d = szHostPath; + +strncpy (szHostPath, szVhdPath, HostPathSize-1); +szHostPath[HostPathSize-1] = '\0'; +#if defined(VMS) +c = strchr (szVhdPath, ':'); +if (*(c+1) != '\\') + return NULL; +*(c+1) = '['; +d = strrchr (c+2, '\\'); +if (d) { + *d = ']'; + while ((d = strrchr (c+2, '\\'))) + *d = '.'; + } +else + return NULL; +#else +while ((c = strchr (d, '\\'))) + *c = '/'; +#endif +memset (szHostPath + strlen (szHostPath), 0, HostPathSize - strlen (szHostPath)); +return szHostPath; +} + static VHDHANDLE CreateDifferencingVirtualDisk(const char *szVHDPath, const char *szParentVHDPath) @@ -2903,19 +3151,19 @@ uint32 ParentTimeStamp; uint32 Status = 0; char *RelativeParentVHDPath = NULL; char *FullParentVHDPath = NULL; -char *RelativeParentVHDPathBuffer = NULL; -char *FullParentVHDPathBuffer = NULL; +char *RelativeParentVHDPathUnicode = NULL; +char *FullParentVHDPathUnicode = NULL; char *FullVHDPath = NULL; size_t i, RelativeMatch, UpDirectories, LocatorsWritten = 0; int64 LocatorPosition; -if (0 != (Status = GetVHDFooter (szParentVHDPath, - &ParentFooter, - &ParentDynamic, - NULL, - &ParentTimeStamp, - NULL, - 0))) +if ((Status = GetVHDFooter (szParentVHDPath, + &ParentFooter, + &ParentDynamic, + NULL, + &ParentTimeStamp, + NULL, + 0))) goto Cleanup_Return; hVHD = CreateVirtualDisk (szVHDPath, (uint32)(NtoHll(ParentFooter.CurrentSize)/BytesPerSector), @@ -2925,27 +3173,30 @@ if (!hVHD) { Status = errno; goto Cleanup_Return; } -LocatorPosition = NtoHll (hVHD->Dynamic.TableOffset)+BytesPerSector*((NtoHl (hVHD->Dynamic.MaxTableEntries)*sizeof(*hVHD->BAT)+BytesPerSector-1)/BytesPerSector); +LocatorPosition = ((sizeof (hVHD->Footer) + BytesPerSector - 1)/BytesPerSector + (sizeof (hVHD->Dynamic) + BytesPerSector - 1)/BytesPerSector)*BytesPerSector; hVHD->Dynamic.Checksum = 0; -RelativeParentVHDPath = calloc (1, BytesPerSector+2); -FullParentVHDPath = calloc (1, BytesPerSector+2); -RelativeParentVHDPathBuffer = calloc (1, BytesPerSector+2); -FullParentVHDPathBuffer = calloc (1, BytesPerSector+2); -FullVHDPath = calloc (1, BytesPerSector+2); +RelativeParentVHDPath = (char*) calloc (1, BytesPerSector+2); +FullParentVHDPath = (char*) calloc (1, BytesPerSector+2); +RelativeParentVHDPathUnicode = (char*) calloc (1, BytesPerSector+2); +FullParentVHDPathUnicode = (char*) calloc (1, BytesPerSector+2); +FullVHDPath = (char*) calloc (1, BytesPerSector+2); ExpandToFullPath (szParentVHDPath, FullParentVHDPath, BytesPerSector); +HostPathToVhdPath (FullParentVHDPath, FullParentVHDPath, BytesPerSector); for (i=0; i < strlen (FullParentVHDPath); i++) - hVHD->Dynamic.ParentUnicodeName[i*2+1] = FullParentVHDPath[i]; + hVHD->Dynamic.ParentUnicodeName[i*2+1] = FullParentVHDPath[i]; /* Big Endian Unicode */ for (i=0; i < strlen (FullParentVHDPath); i++) - FullParentVHDPathBuffer[i*2] = FullParentVHDPath[i]; + FullParentVHDPathUnicode[i*2] = FullParentVHDPath[i]; /* Little Endian Unicode */ ExpandToFullPath (szVHDPath, FullVHDPath, BytesPerSector); +HostPathToVhdPath (FullVHDPath, FullVHDPath, BytesPerSector); for (i=0, RelativeMatch=UpDirectories=0; iDynamic.ParentTimeStamp = ParentTimeStamp; memcpy (hVHD->Dynamic.ParentUniqueID, ParentFooter.UniqueID, sizeof (hVHD->Dynamic.ParentUniqueID)); hVHD->Dynamic.ParentLocatorEntries[7].PlatformDataSpace = NtoHl (BytesPerSector); +hVHD->Dynamic.ParentLocatorEntries[7].Reserved = 0; hVHD->Dynamic.ParentLocatorEntries[7].PlatformDataOffset = NtoHll (LocatorPosition+LocatorsWritten*BytesPerSector); ++LocatorsWritten; +memcpy (hVHD->Dynamic.ParentLocatorEntries[6].PlatformCode, "Wi2k", 4); hVHD->Dynamic.ParentLocatorEntries[6].PlatformDataSpace = NtoHl (BytesPerSector); +hVHD->Dynamic.ParentLocatorEntries[6].Reserved = 0; hVHD->Dynamic.ParentLocatorEntries[6].PlatformDataOffset = NtoHll (LocatorPosition+LocatorsWritten*BytesPerSector); ++LocatorsWritten; if (RelativeMatch) { + memcpy (hVHD->Dynamic.ParentLocatorEntries[7].PlatformCode, "Wi2r", 4); + hVHD->Dynamic.ParentLocatorEntries[7].PlatformDataLength = NtoHl ((uint32)(strlen(RelativeParentVHDPath))); memcpy (hVHD->Dynamic.ParentLocatorEntries[5].PlatformCode, "W2ru", 4); hVHD->Dynamic.ParentLocatorEntries[5].PlatformDataSpace = NtoHl (BytesPerSector); hVHD->Dynamic.ParentLocatorEntries[5].PlatformDataLength = NtoHl ((uint32)(2*strlen(RelativeParentVHDPath))); @@ -3001,52 +3257,43 @@ if (WriteFilePosition (hVHD->File, Status = errno; goto Cleanup_Return; } -LocatorsWritten = 0; -if (RelativeMatch) { - if (WriteFilePosition (hVHD->File, - RelativeParentVHDPath, - BytesPerSector, - NULL, - LocatorPosition+LocatorsWritten*BytesPerSector)) { - Status = errno; - goto Cleanup_Return; - } - ++LocatorsWritten; +if (WriteFilePosition (hVHD->File, + &hVHD->Footer, + sizeof (hVHD->Footer), + NULL, + NtoHll (hVHD->Dynamic.TableOffset)+BytesPerSector*((NtoHl (hVHD->Dynamic.MaxTableEntries)*sizeof(*hVHD->BAT)+BytesPerSector-1)/BytesPerSector))) { + Status = errno; + goto Cleanup_Return; + } +if (WriteFilePosition (hVHD->File, + RelativeParentVHDPath, + BytesPerSector, + NULL, + NtoHll (hVHD->Dynamic.ParentLocatorEntries[7].PlatformDataOffset))) { + Status = errno; + goto Cleanup_Return; } if (WriteFilePosition (hVHD->File, FullParentVHDPath, BytesPerSector, NULL, - LocatorPosition+LocatorsWritten*BytesPerSector)) { + NtoHll (hVHD->Dynamic.ParentLocatorEntries[6].PlatformDataOffset))) { Status = errno; goto Cleanup_Return; } -++LocatorsWritten; -if (RelativeMatch) { - if (WriteFilePosition (hVHD->File, - RelativeParentVHDPathBuffer, - BytesPerSector, - NULL, - LocatorPosition+LocatorsWritten*BytesPerSector)) { - Status = errno; - goto Cleanup_Return; - } - ++LocatorsWritten; - } if (WriteFilePosition (hVHD->File, - FullParentVHDPathBuffer, + RelativeParentVHDPathUnicode, BytesPerSector, NULL, - LocatorPosition+LocatorsWritten*BytesPerSector)) { + NtoHll (hVHD->Dynamic.ParentLocatorEntries[5].PlatformDataOffset))) { Status = errno; goto Cleanup_Return; } -++LocatorsWritten; if (WriteFilePosition (hVHD->File, - &hVHD->Footer, - sizeof(hVHD->Footer), + FullParentVHDPathUnicode, + BytesPerSector, NULL, - LocatorPosition+LocatorsWritten*BytesPerSector)) { + NtoHll (hVHD->Dynamic.ParentLocatorEntries[4].PlatformDataOffset))) { Status = errno; goto Cleanup_Return; } @@ -3054,8 +3301,8 @@ if (WriteFilePosition (hVHD->File, Cleanup_Return: free (RelativeParentVHDPath); free (FullParentVHDPath); -free (RelativeParentVHDPathBuffer); -free (FullParentVHDPathBuffer); +free (RelativeParentVHDPathUnicode); +free (FullParentVHDPathUnicode); free (FullVHDPath); sim_vhd_disk_close ((FILE *)hVHD); hVHD = NULL; @@ -3093,7 +3340,7 @@ ReadVirtualDiskSectors(VHDHANDLE hVHD, uint64 BlockOffset = ((uint64)lba)*SectorSize; uint32 BlocksRead = 0; uint32 SectorsInRead; -size_t BytesRead; +size_t BytesRead = 0; if (!hVHD || (hVHD->File == NULL)) { errno = EBADF; @@ -3124,14 +3371,13 @@ while (sects) { uint32 BitMapBytes = (7+(NtoHl (hVHD->Dynamic.BlockSize)/SectorSize))/8; uint32 BitMapSectors = (BitMapBytes+SectorSize-1)/SectorSize; - SectorsInRead = 1; + SectorsInRead = SectorsPerBlock - lba%SectorsPerBlock; + if (SectorsInRead > sects) + SectorsInRead = sects; if (hVHD->BAT[BlockNumber] == VHD_BAT_FREE_ENTRY) { if (!hVHD->Parent) - memset (buf, 0, SectorSize); + memset (buf, 0, SectorSize*SectorsInRead); else { - SectorsInRead = SectorsPerBlock - lba%SectorsPerBlock; - if (SectorsInRead > sects) - SectorsInRead = sects; if (ReadVirtualDiskSectors(hVHD->Parent, buf, SectorsInRead, @@ -3146,9 +3392,6 @@ while (sects) { } else { BlockOffset = SectorSize*((uint64)(NtoHl (hVHD->BAT[BlockNumber]) + lba%SectorsPerBlock + BitMapSectors)); - SectorsInRead = SectorsPerBlock - lba%SectorsPerBlock; - if (SectorsInRead > sects) - SectorsInRead = sects; if (ReadFilePosition(hVHD->File, buf, SectorsInRead*SectorSize, @@ -3189,33 +3432,6 @@ for (i=0; iFile) { errno = EBADF; @@ -3281,7 +3497,7 @@ while (sects) { return SCPE_IOERR; if (BitMapSectors*SectorSize > BitMapBufferSize) BitMapBufferSize = BitMapSectors*SectorSize; - BitMapBuffer = calloc(1, BitMapBufferSize + SectorSize*SectorsPerBlock); + BitMapBuffer = (uint8 *)calloc(1, BitMapBufferSize + SectorSize*SectorsPerBlock); if (BitMapBufferSize > BitMapSectors*SectorSize) BitMap = BitMapBuffer + BitMapBufferSize-BitMapBytes; else @@ -3331,11 +3547,12 @@ while (sects) { NULL, BlockOffset)) goto Fatal_IO_Error; + /* Write back just the aligned sector which contains the updated BAT entry */ BATUpdateBufferAddress = ((uint8 *)hVHD->BAT) + - (((((size_t)&hVHD->BAT[BlockNumber]) - ((size_t)hVHD->BAT) + VHD_DATA_BLOCK_ALIGNMENT - 1)/VHD_DATA_BLOCK_ALIGNMENT)*VHD_DATA_BLOCK_ALIGNMENT); - BATUpdateBufferSize = SectorSize*((sizeof(*hVHD->BAT)*NtoHl(hVHD->Dynamic.MaxTableEntries)+511)/512); - if (BATUpdateBufferSize > VHD_DATA_BLOCK_ALIGNMENT) - BATUpdateBufferSize = VHD_DATA_BLOCK_ALIGNMENT; + (((((size_t)&hVHD->BAT[BlockNumber]) - (size_t)hVHD->BAT)/VHD_DATA_BLOCK_ALIGNMENT)*VHD_DATA_BLOCK_ALIGNMENT); + BATUpdateBufferSize = VHD_DATA_BLOCK_ALIGNMENT; + if ((size_t)(BATUpdateBufferAddress - (uint8 *)hVHD->BAT + BATUpdateBufferSize) > 512*((sizeof(*hVHD->BAT)*NtoHl(hVHD->Dynamic.MaxTableEntries) + 511)/512)) + BATUpdateBufferSize = 512*((sizeof(*hVHD->BAT)*NtoHl(hVHD->Dynamic.MaxTableEntries) + 511)/512) - (BATUpdateBufferAddress - ((uint8 *)hVHD->BAT)); BATUpdateStorageAddress = NtoHll(hVHD->Dynamic.TableOffset) + BATUpdateBufferAddress - ((uint8 *)hVHD->BAT); if (WriteFilePosition(hVHD->File, BATUpdateBufferAddress, @@ -3345,17 +3562,22 @@ while (sects) { goto Fatal_IO_Error; if (hVHD->Parent) { /* Need to populate data block contents from parent VHD */ + uint32 BlockSectors = SectorsPerBlock; + BlockData = malloc(SectorsPerBlock*SectorSize); + + if (((lba/SectorsPerBlock)*SectorsPerBlock + BlockSectors) > ((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize) + BlockSectors = (uint32)(((uint64)NtoHll (hVHD->Footer.CurrentSize))/SectorSize - (lba/SectorsPerBlock)*SectorsPerBlock); if (ReadVirtualDiskSectors(hVHD->Parent, - BlockData, - SectorsPerBlock, + (uint8*) BlockData, + BlockSectors, NULL, SectorSize, (lba/SectorsPerBlock)*SectorsPerBlock)) goto Fatal_IO_Error; if (WriteVirtualDiskSectors(hVHD, - BlockData, - SectorsPerBlock, + (uint8*) BlockData, + BlockSectors, NULL, SectorSize, (lba/SectorsPerBlock)*SectorsPerBlock)) diff --git a/sim_ether.c b/sim_ether.c index 44677a3c..f272dcf4 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -528,6 +528,7 @@ void eth_packet_trace_ex(ETH_DEV* dev, const uint8 *msg, int len, char* txt, int int i, same, group, sidx, oidx; char outbuf[80], strbuf[18]; static char hex[] = "0123456789ABCDEF"; + for (i=same=0; i 0) && (0 == memcmp(&msg[i], &msg[i-16], 16))) { ++same; @@ -551,8 +552,9 @@ void eth_packet_trace_ex(ETH_DEV* dev, const uint8 *msg, int len, char* txt, int strbuf[sidx] = '\0'; sim_debug(reason, dev->dptr, "%04X%-48s %s\n", i, outbuf, strbuf); } - if (same > 0) + if (same > 0) { sim_debug(reason, dev->dptr, "%04X thru %04X same as above\n", i-(16*same), len-1); + } } } } @@ -666,6 +668,7 @@ void eth_zero(ETH_DEV* dev) static ETH_DEV **eth_open_devices = NULL; static int eth_open_device_count = 0; +#if defined (USE_NETWORK) || defined (USE_SHARED) static void _eth_add_to_open_list (ETH_DEV* dev) { eth_open_devices = realloc(eth_open_devices, (eth_open_device_count+1)*sizeof(*eth_open_devices)); @@ -684,6 +687,7 @@ for (i=0; i min) min = len; for (i=0; iname, desc); + if (d) + fprintf(st, " %-7s%s (%s)\n", eth_open_devices[i]->dptr->name, eth_open_devices[i]->dptr->units[0].filename, d); + else + fprintf(st, " %-7s%s\n", eth_open_devices[i]->dptr->name, eth_open_devices[i]->dptr->units[0].filename); + } } if (eth_open_device_count) { int i; @@ -785,7 +802,7 @@ void ethq_remove(ETH_QUE* que) } } -void ethq_insert_data(ETH_QUE* que, int32 type, const uint8 *data, int used, int len, int crc_len, const uint8 *crc_data, int32 status) +void ethq_insert_data(ETH_QUE* que, int32 type, const uint8 *data, int used, size_t len, size_t crc_len, const uint8 *crc_data, int32 status) { struct eth_item* item; @@ -960,11 +977,11 @@ static char* (*p_pcap_lib_version) (void); /* load function pointer from DLL */ typedef int (*_func)(); -void load_function(char* function, _func* func_ptr) { +static void load_function(char* function, _func* func_ptr) { #ifdef _WIN32 - *func_ptr = (_func)GetProcAddress(hLib, function); + *func_ptr = (_func)((size_t)GetProcAddress(hLib, function)); #else - *func_ptr = (_func)dlsym(hLib, function); + *func_ptr = (_func)((size_t)dlsym(hLib, function)); #endif if (*func_ptr == 0) { char* msg = "Eth: Failed to find function '%s' in %s\r\n"; @@ -1411,7 +1428,7 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname) memset(command, 0, sizeof(command)); for (i=0; patterns[i] && (0 == dev->have_host_nic_phy_addr); ++i) { snprintf(command, sizeof(command)-1, "ifconfig %s | %s >NIC.hwaddr", devname, patterns[i]); - system(command); + (void)system(command); if (NULL != (f = fopen("NIC.hwaddr", "r"))) { while (0 == dev->have_host_nic_phy_addr) { if (fgets(command, sizeof(command)-1, f)) { @@ -1421,7 +1438,7 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname) while (p1) { p2 = strchr(p1+1, ':'); if (p2 <= p1+3) { - int mac_bytes[6]; + unsigned int mac_bytes[6]; if (6 == sscanf(p1-2, "%02x:%02x:%02x:%02x:%02x:%02x", &mac_bytes[0], &mac_bytes[1], &mac_bytes[2], &mac_bytes[3], &mac_bytes[4], &mac_bytes[5])) { dev->host_nic_phy_hw_addr[0] = mac_bytes[0]; dev->host_nic_phy_hw_addr[1] = mac_bytes[1]; @@ -1469,7 +1486,7 @@ HANDLE hWait = pcap_getevent ((pcap_t*)dev->handle); #else int sel_ret; int do_select = 0; -int select_fd; +int select_fd = 0; switch (dev->eth_api) { case ETH_API_PCAP: @@ -1697,7 +1714,6 @@ memset(errbuf, 0, sizeof(errbuf)); if (0 == strncmp("tap:", savname, 4)) { int tun = -1; /* TUN/TAP Socket */ int on = 1; - char dev_name[64] = ""; #if defined(USE_TAP_NETWORK) if (!strcmp(savname, "tap:tapN")) { @@ -1733,41 +1749,45 @@ if (0 == strncmp("tap:", savname, 4)) { else strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); #elif defined(USE_BSDTUNTAP) && defined(USE_TAP_NETWORK) - snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4); - dev_name[sizeof(dev_name)-1] = '\0'; + if (1) { + char dev_name[64] = ""; - if ((tun = open(dev_name, O_RDWR)) >= 0) { - if (ioctl(tun, FIONBIO, &on)) { - strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); - close(tun); - } - else { - dev->fd_handle = tun; - strcpy(savname, savname+4); - } -#if defined (__APPLE__) - if (1) { - struct ifreq ifr; - int s; + snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4); + dev_name[sizeof(dev_name)-1] = '\0'; - memset (&ifr, 0, sizeof(ifr)); - ifr.ifr_addr.sa_family = AF_INET; - strncpy(ifr.ifr_name, savname, sizeof(ifr.ifr_name)); - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { - if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) { - ifr.ifr_flags |= IFF_UP; - if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr)) { - strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); - close(tun); - } - } - close(s); + if ((tun = open(dev_name, O_RDWR)) >= 0) { + if (ioctl(tun, FIONBIO, &on)) { + strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); + close(tun); + } + else { + dev->fd_handle = tun; + strcpy(savname, savname+4); + } +#if defined (__APPLE__) + if (1) { + struct ifreq ifr; + int s; + + memset (&ifr, 0, sizeof(ifr)); + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, savname, sizeof(ifr.ifr_name)); + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) { + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) >= 0) { + ifr.ifr_flags |= IFF_UP; + if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr)) { + strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); + close(tun); + } + } + close(s); + } } - } #endif - } - else - strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); + } + else + strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); + } #else strncpy(errbuf, "No support for tap: devices", sizeof(errbuf)-1); #endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */ @@ -2116,13 +2136,13 @@ if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) { break; #ifdef USE_TAP_NETWORK case ETH_API_TAP: - status = ((packet->len == write(dev->fd_handle, (void *)packet->msg, packet->len)) ? 0 : -1); + status = (((int)packet->len == write(dev->fd_handle, (void *)packet->msg, packet->len)) ? 0 : -1); break; #endif #ifdef USE_VDE_NETWORK case ETH_API_VDE: status = vde_send((VDECONN*)dev->handle, (void *)packet->msg, packet->len, 0); - if ((status == packet->len) || (status == 0)) + if ((status == (int)packet->len) || (status == 0)) status = 0; else if ((status == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))) @@ -2218,6 +2238,7 @@ key ^= 0x3f; return (hash[key>>3] & (1 << (key&0x7))); } +#if 0 static int _eth_hash_validate(ETH_MAC *MultiCastList, int count, ETH_MULTIHASH hash) { @@ -2269,6 +2290,7 @@ ETH_MULTIHASH thash = {0x01, 0x40, 0x00, 0x00, 0x48, 0x88, 0x40, 0x00}; _eth_hash_validate(tMacs, sizeof(tMacs)/sizeof(tMacs[0]), thash); } +#endif /* The IP header */ struct IPHeader { @@ -2936,10 +2958,12 @@ if (dev->dptr->dctrl & dev->dbit) { eth_mac_fmt(&dev->filter_address[i], mac); sim_debug(dev->dbit, dev->dptr, " Addr[%d]: %s\n", i, mac); } - if (dev->all_multicast) + if (dev->all_multicast) { sim_debug(dev->dbit, dev->dptr, "All Multicast\n"); - if (dev->promiscuous) + } + if (dev->promiscuous) { sim_debug(dev->dbit, dev->dptr, "Promiscuous\n"); + } } /* setup BPF filters and other fields to minimize packet delivery */ diff --git a/sim_ether.h b/sim_ether.h index 36cb11f5..d1c09ba4 100644 --- a/sim_ether.h +++ b/sim_ether.h @@ -304,8 +304,8 @@ void ethq_remove (ETH_QUE* que); /* remove item from FIFO void ethq_insert (ETH_QUE* que, int32 type, /* insert item into FIFO queue */ ETH_PACK* packet, int32 status); void ethq_insert_data(ETH_QUE* que, int32 type, /* insert item into FIFO queue */ - const uint8 *data, int used, int len, - int crc_len, const uint8 *crc_data, int32 status); + const uint8 *data, int used, size_t len, + size_t crc_len, const uint8 *crc_data, int32 status); t_stat ethq_destroy(ETH_QUE* que); /* release FIFO queue */ diff --git a/sim_serial.c b/sim_serial.c new file mode 100644 index 00000000..a5d91558 --- /dev/null +++ b/sim_serial.c @@ -0,0 +1,1773 @@ +/* sim_serial.c: OS-dependent serial port routines + + Copyright (c) 2008, J. David Bryan + + 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 + THE AUTHOR 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. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + The author gratefully acknowledges the assistance of Holger Veit with the + UNIX-specific code and testing. + + 07-Oct-08 JDB [serial] Created file + + + This module provides OS-dependent routines to access serial ports on the host + machine. The terminal multiplexer library uses these routines to provide + serial connections to simulated terminal interfaces. + + Currently, the module supports Windows and UNIX. Use on other systems + returns error codes indicating that the functions failed, inhibiting serial + port support in SIMH. + + The following routines are provided: + + sim_open_serial open a serial port + sim_config_serial change baud rate and character framing configuration + sim_control_serial manipulate and/or return the modem bits on a serial port + sim_read_serial read from a serial port + sim_write_serial write to a serial port + sim_close_serial close a serial port + sim_show_serial shows the available host serial ports + + + The calling sequences are as follows: + + + SERHANDLE sim_open_serial (char *name) + -------------------------------------- + + The serial port referenced by the OS-dependent "name" is opened. If the open + is successful, and "name" refers to a serial port on the host system, then a + handle to the port is returned. If not, then the value INVALID_HANDLE is + returned. + + + t_stat sim_config_serial (SERHANDLE port, const char *config) + ------------------------------------------------------------- + + The baud rate and framing parameters (character size, parity, and number of + stop bits) of the serial port associated with "port" are set. If any + "config" field value is unsupported by the host system, or if the combination + of values (e.g., baud rate and number of stop bits) is unsupported, SCPE_ARG + is returned. If the configuration is successful, SCPE_OK is returned. + + + sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits) + ------------------------------------------------------------------------------------------------- + + The DTR and RTS line of the serial port is set or cleared as indicated in + the respective bits_to_set or bits_to_clear parameters. If the + incoming_bits parameter is not NULL, then the modem status bits DCD, RNG, + DSR and CTS are returned. + + If unreasonable or nonsense bits_to_set or bits_to_clear bits are + specified, then the return status is SCPE_ARG; + If an error occurs, SCPE_IOERR is returned. + + + int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk) + ---------------------------------------------------------------------------- + + A non-blocking read is issued for the serial port indicated by "port" to get + at most "count" bytes into the string "buffer". If a serial line break was + detected during the read, the variable pointed to by "brk" is set to 1. If + the read is successful, the actual number of characters read is returned. If + no characters were available, then the value 0 is returned. If an error + occurs, then the value -1 is returned. + + + int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count) + ------------------------------------------------------------------ + + A write is issued to the serial port indicated by "port" to put "count" + characters from "buffer". If the write is successful, the actual number of + characters written is returned. If an error occurs, then the value -1 is + returned. + + + void sim_close_serial (SERHANDLE port) + -------------------------------------- + + The serial port indicated by "port" is closed. + + + int sim_serial_devices (int max, SERIAL_LIST* list) + --------------------------------------------------- + + enumerates the available host serial ports + + + t_stat sim_show_serial (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, void* desc) + --------------------------------- + + displays the available host serial ports + +*/ + + +#include "sim_defs.h" +#include "sim_serial.h" +#include "sim_tmxr.h" + +#include + +#define SER_DEV_NAME_MAX 256 /* maximum device name size */ +#define SER_DEV_DESC_MAX 256 /* maximum device description size */ +#define SER_DEV_CONFIG_MAX 64 /* maximum device config size */ +#define SER_MAX_DEVICE 64 /* maximum serial devices */ + +typedef struct serial_list { + char name[SER_DEV_NAME_MAX]; + char desc[SER_DEV_DESC_MAX]; + } SERIAL_LIST; + +typedef struct serial_config { /* serial port configuration */ + uint32 baudrate; /* baud rate */ + uint32 charsize; /* character size in bits */ + char parity; /* parity (N/O/E/M/S) */ + uint32 stopbits; /* 0/1/2 stop bits (0 implies 1.5) */ + } SERCONFIG; + +static int sim_serial_os_devices (int max, SERIAL_LIST* list); +static SERHANDLE sim_open_os_serial (char *name); +static void sim_close_os_serial (SERHANDLE port); +static t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config); + + +static struct open_serial_device { + SERHANDLE port; + TMLN *line; + char name[SER_DEV_NAME_MAX]; + char config[SER_DEV_CONFIG_MAX]; + } *serial_open_devices = NULL; +static int serial_open_device_count = 0; + +static struct open_serial_device *_get_open_device (SERHANDLE port) +{ +int i; + +for (i=0; iname, b->name); +} + +static int sim_serial_devices (int max, SERIAL_LIST *list) +{ +int i, j, ports = sim_serial_os_devices(max, list); + +/* Open ports may not show up in the list returned by sim_serial_os_devices + so we add the open ports to the list removing duplicates before sorting + the resulting list */ + +for (i=0; i= max) + break; + strcpy(list[ports].name, serial_open_devices[i].name); + strcpy(list[ports].desc, serial_open_devices[i].config); + ++ports; + } +if (ports) /* Order the list returned alphabetically by the port name */ + qsort (list, ports, sizeof(list[0]), _serial_name_compare); +return ports; +} + +static char* sim_serial_getname (int number, char* name) +{ +SERIAL_LIST list[SER_MAX_DEVICE]; +int count = sim_serial_devices(SER_MAX_DEVICE, list); + +if (count <= number) + return NULL; +strcpy(name, list[number].name); +return name; +} + +static char* sim_serial_getname_bydesc (char* desc, char* name) +{ +SERIAL_LIST list[SER_MAX_DEVICE]; +int count = sim_serial_devices(SER_MAX_DEVICE, list); +int i; +size_t j=strlen(desc); + +for (i=0; i s2) + return 1; + if (s1 == 0) + return 0; +} +return 0; +} + +static char* sim_serial_getname_byname (char* name, char* temp) +{ +SERIAL_LIST list[SER_MAX_DEVICE]; +int count = sim_serial_devices(SER_MAX_DEVICE, list); +size_t n; +int i, found; + +found = 0; +n = strlen(name); +for (i=0; i min) + min = len; + for (i=0; imp->dptr->name, (int)(serial_open_devices[i].line->mp->ldsc-serial_open_devices[i].line), + serial_open_devices[i].line->destination, d ? " {" : "", d ? d : "", d ? ")" : "", serial_open_devices[i].line->serconfig); + } + } +return SCPE_OK; +} + +SERHANDLE sim_open_serial (char *name, TMLN *lp, t_stat *stat) +{ +char temp1[1024], devname [1024]; +char *savname = name; +SERHANDLE port = INVALID_HANDLE; +char *config; +t_stat status; + +config = get_glyph_nc (name, devname, ';'); /* separate port name from optional config params */ + +if ((config == NULL) || (*config == '\0')) + config = "9600-8N1"; + +if (stat) + *stat = SCPE_OK; + +/* translate name of type "serX" to real device name */ +if ((strlen(devname) <= 5) + && (tolower(devname[0]) == 's') + && (tolower(devname[1]) == 'e') + && (tolower(devname[2]) == 'r') + && (isdigit(devname[3])) + && (isdigit(devname[4]) || (devname[4] == '\0')) + ) { + int num = atoi(&devname[3]); + savname = sim_serial_getname(num, temp1); + if (savname == NULL) { /* didn't translate */ + if (stat) + *stat = SCPE_OPENERR; + return port; + } + } +else { + /* are they trying to use device description? */ + savname = sim_serial_getname_bydesc(devname, temp1); + if (savname == NULL) { /* didn't translate */ + /* probably is not serX and has no description */ + savname = sim_serial_getname_byname(devname, temp1); + if (savname == NULL) /* didn't translate */ + savname = devname; + } + } + +port = sim_open_os_serial (savname); + +if (port == INVALID_HANDLE) { + if (stat) + *stat = SCPE_OPENERR; + return port; + } + +status = sim_config_serial (port, config); /* set serial configuration */ + +if (status != SCPE_OK) { /* port configuration error? */ + sim_close_serial (port); /* close the port */ + if (stat) + *stat = status; + port = INVALID_HANDLE; /* report error */ + } + +if ((port != INVALID_HANDLE) && (*config) && (lp)) { + lp->serconfig = realloc (lp->serconfig, 1 + strlen (config)); + strcpy (lp->serconfig, config); + } +if (port != INVALID_HANDLE) + _serial_add_to_open_list (port, lp, savname, config); + +return port; +} + +void sim_close_serial (SERHANDLE port) +{ +sim_close_os_serial (port); +_serial_remove_from_open_list (port); +} + +t_stat sim_config_serial (SERHANDLE port, const char *sconfig) +{ +const char *pptr; +char *sptr, *tptr; +SERCONFIG config = { 0 }; +t_bool arg_error = FALSE; +t_stat r; +struct open_serial_device *dev; + +if ((sconfig == NULL) || (*sconfig == '\0')) + sconfig = "9600-8N1"; /* default settings */ +pptr = sconfig; + +config.baudrate = (uint32)strtotv (pptr, &sptr, 10); /* parse baud rate */ +arg_error = (pptr == sptr); /* check for bad argument */ + +if (*sptr) /* separator present? */ + sptr++; /* skip it */ + +config.charsize = (uint32)strtotv (sptr, &tptr, 10); /* parse character size */ +arg_error = arg_error || (sptr == tptr); /* check for bad argument */ + +if (*tptr) /* parity character present? */ + config.parity = toupper (*tptr++); /* save parity character */ + +config.stopbits = (uint32)strtotv (tptr, &sptr, 10); /* parse number of stop bits */ +arg_error = arg_error || (tptr == sptr); /* check for bad argument */ + +if (arg_error) /* bad conversions? */ + return SCPE_ARG; /* report argument error */ +if (strcmp (sptr, ".5") == 0) /* 1.5 stop bits requested? */ + config.stopbits = 0; /* code request */ + +r = sim_config_os_serial (port, config); +dev = _get_open_device (port); +if (dev) { + dev->line->serconfig = realloc (dev->line->serconfig, 1 + strlen (sconfig)); + strcpy (dev->line->serconfig, sconfig); + } +return r; +} + +#if defined (_WIN32) + +/* Windows serial implementation */ + +/* Enumerate the available serial ports. + + The serial port names are extracted from the appropriate place in the + windows registry (HKLM\HARDWARE\DEVICEMAP\SERIALCOMM\). The resulting + list is sorted alphabetically by device name (COMn). The device description + is set to the OS internal name for the COM device. + +*/ + +static int sim_serial_os_devices (int max, SERIAL_LIST* list) +{ +int ports = 0; +HKEY hSERIALCOMM; + +memset(list, 0, max*sizeof(*list)); +if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hSERIALCOMM) == ERROR_SUCCESS) { + DWORD dwIndex = 0; + DWORD dwType; + DWORD dwValueNameSize = sizeof(list[ports].desc); + DWORD dwDataSize = sizeof(list[ports].name); + + /* Enumerate all the values underneath HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM */ + while (RegEnumValueA(hSERIALCOMM, dwIndex, list[ports].desc, &dwValueNameSize, NULL, &dwType, (BYTE *)list[ports].name, &dwDataSize) == ERROR_SUCCESS) { + /* String values with non-zero size are the interesting ones */ + if ((dwType == REG_SZ) && (dwDataSize > 0)) + if (ports < max) + ++ports; + else + break; + /* Besure to clear the working entry before trying again */ + memset(list[ports].name, 0, sizeof(list[ports].name)); + memset(list[ports].desc, 0, sizeof(list[ports].desc)); + dwValueNameSize = sizeof(list[ports].desc); + dwDataSize = sizeof(list[ports].name); + ++dwIndex; + } + RegCloseKey(hSERIALCOMM); + } +return ports; +} + +/* Open a serial port. + + The serial port designated by "name" is opened, and the handle to the port is + returned. If an error occurs, INVALID_HANDLE is returned instead. After + opening, the port is configured with the default communication parameters + established by the system, and the timeouts are set for immediate return on a + read request to enable polling. + + Implementation notes: + + 1. We call "GetDefaultCommConfig" to obtain the default communication + parameters for the specified port. If the name does not refer to a + communications port (serial or parallel), the function fails. + + 2. There is no way to limit "CreateFile" just to serial ports, so we must + check after the port is opened. The "GetCommState" routine will return + an error if the handle does not refer to a serial port. + + 3. Calling "GetDefaultCommConfig" for a serial port returns a structure + containing a DCB. This contains the default parameters. However, some + of the DCB fields are not set correctly, so we cannot use this directly + in a call to "SetCommState". Instead, we must copy the fields of + interest to a DCB retrieved from a call to "GetCommState". +*/ + +SERHANDLE sim_open_os_serial (char *name) +{ +SERHANDLE port; +DCB dcb; +COMMCONFIG commdefault; +DWORD error; +DWORD commsize = sizeof (commdefault); +COMMTIMEOUTS cto; + +if (!GetDefaultCommConfig (name, &commdefault, &commsize)) { /* get default comm parameters */ + error = GetLastError (); /* function failed; get error */ + + if (error != ERROR_INVALID_PARAMETER) /* not a communications port name? */ + sim_error_serial ("GetDefaultCommConfig", (int) error); /* no, so report unexpected error */ + + return INVALID_HANDLE; /* indicate bad port name */ + } + +port = CreateFile (name, GENERIC_READ | GENERIC_WRITE, /* open the port */ + 0, NULL, OPEN_EXISTING, 0, 0); + +if (port == INVALID_HANDLE_VALUE) { /* open failed? */ + error = GetLastError (); /* get error code */ + + if ((error != ERROR_FILE_NOT_FOUND) && /* bad filename? */ + (error != ERROR_ACCESS_DENIED)) /* already open? */ + sim_error_serial ("CreateFile", (int) error); /* no, so report unexpected error */ + + return INVALID_HANDLE; /* indicate bad port name */ + } + +if (!GetCommState (port, &dcb)) { /* get the current comm parameters */ + error = GetLastError (); /* function failed; get error */ + + if (error != ERROR_INVALID_PARAMETER) /* not a serial port name? */ + sim_error_serial ("GetCommState", (int) error); /* no, so report unexpected error */ + + CloseHandle (port); /* close the port */ + return INVALID_HANDLE; /* and indicate bad port name */ + } + +dcb.BaudRate = commdefault.dcb.BaudRate; /* copy default parameters of interest */ +dcb.Parity = commdefault.dcb.Parity; +dcb.ByteSize = commdefault.dcb.ByteSize; +dcb.StopBits = commdefault.dcb.StopBits; +dcb.fOutX = commdefault.dcb.fOutX; +dcb.fInX = commdefault.dcb.fInX; + +dcb.fDtrControl = DTR_CONTROL_DISABLE; /* disable DTR initially until poll connects */ + +if (!SetCommState (port, &dcb)) { /* configure the port with default parameters */ + sim_error_serial ("SetCommState", /* function failed; report unexpected error */ + (int) GetLastError ()); + CloseHandle (port); /* close port */ + return INVALID_HANDLE; /* and indicate failure to caller */ + } + +cto.ReadIntervalTimeout = MAXDWORD; /* set port to return immediately on read */ +cto.ReadTotalTimeoutMultiplier = 0; /* i.e., to enable polling */ +cto.ReadTotalTimeoutConstant = 0; +cto.WriteTotalTimeoutMultiplier = 0; +cto.WriteTotalTimeoutConstant = 0; + +if (!SetCommTimeouts (port, &cto)) { /* configure port timeouts */ + sim_error_serial ("SetCommTimeouts", /* function failed; report unexpected error */ + (int) GetLastError ()); + CloseHandle (port); /* close port */ + return INVALID_HANDLE; /* and indicate failure to caller */ + } + +return port; /* return port handle on success */ +} + + +/* Configure a serial port. + + Port parameters are configured as specified in the "config" structure. If + "config" contains an invalid configuration value, or if the host system + rejects the configuration (e.g., by requesting an unsupported combination of + character size and stop bits), SCPE_ARG is returned to the caller. If an + unexpected error occurs, SCPE_IOERR is returned. If the configuration + succeeds, SCPE_OK is returned. + + Implementation notes: + + 1. We do not enable input parity checking, as the multiplexer library has no + way of communicating parity errors back to the target simulator. + + 2. A zero value for the "stopbits" field of the "config" structure implies + 1.5 stop bits. +*/ + +t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) +{ +static const struct { + char parity; + BYTE parity_code; + } parity_map [] = + { { 'E', EVENPARITY }, { 'M', MARKPARITY }, { 'N', NOPARITY }, + { 'O', ODDPARITY }, { 'S', SPACEPARITY } }; + +static const int32 parity_count = sizeof (parity_map) / sizeof (parity_map [0]); + +DCB dcb; +DWORD error; +int32 i; + +if (!GetCommState (port, &dcb)) { /* get the current comm parameters */ + sim_error_serial ("GetCommState", /* function failed; report unexpected error */ + (int) GetLastError ()); + return SCPE_IOERR; /* return failure status */ + } + +dcb.BaudRate = config.baudrate; /* assign baud rate */ + +if (config.charsize >= 5 && config.charsize <= 8) /* character size OK? */ + dcb.ByteSize = config.charsize; /* assign character size */ +else + return SCPE_ARG; /* not a valid size */ + +for (i = 0; i < parity_count; i++) /* assign parity */ + if (config.parity == parity_map [i].parity) { /* match mapping value? */ + dcb.Parity = parity_map [i].parity_code; /* assign corresponding code */ + break; + } + +if (i == parity_count) /* parity assigned? */ + return SCPE_ARG; /* not a valid parity specifier */ + +if (config.stopbits == 1) /* assign stop bits */ + dcb.StopBits = ONESTOPBIT; +else if (config.stopbits == 2) + dcb.StopBits = TWOSTOPBITS; +else if (config.stopbits == 0) /* 0 implies 1.5 stop bits */ + dcb.StopBits = ONE5STOPBITS; +else + return SCPE_ARG; /* not a valid number of stop bits */ + +if (!SetCommState (port, &dcb)) { /* set the configuration */ + error = GetLastError (); /* check for error */ + + if (error == ERROR_INVALID_PARAMETER) /* invalid configuration? */ + return SCPE_ARG; /* report as argument error */ + + sim_error_serial ("SetCommState", (int) error); /* function failed; report unexpected error */ + return SCPE_IOERR; /* return failure status */ + } + +return SCPE_OK; /* return success status */ +} + + +/* Control a serial port. + + The DTR and RTS line of the serial port is set or cleared as indicated in + the respective bits_to_set or bits_to_clear parameters. If the + incoming_bits parameter is not NULL, then the modem status bits DCD, RNG, + DSR and CTS are returned. + + If unreasonable or nonsense bits_to_set or bits_to_clear bits are + specified, then the return status is SCPE_ARG; + If an error occurs, SCPE_IOERR is returned. +*/ + +t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits) +{ +if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) || /* Assure only settable bits */ + (bits_to_clear & ~(TMXR_MDM_OUTGOING)) || + (bits_to_set & bits_to_clear)) /* and can't set and clear the same bits */ + return SCPE_ARG; +if (bits_to_set&TMXR_MDM_DTR) + if (!EscapeCommFunction (port, SETDTR)) { + sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); + return SCPE_IOERR; + } +if (bits_to_clear&TMXR_MDM_DTR) + if (!EscapeCommFunction (port, CLRDTR)) { + sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); + return SCPE_IOERR; + } +if (bits_to_set&TMXR_MDM_RTS) + if (!EscapeCommFunction (port, SETRTS)) { + sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); + return SCPE_IOERR; + } +if (bits_to_clear&TMXR_MDM_RTS) + if (!EscapeCommFunction (port, CLRRTS)) { + sim_error_serial ("EscapeCommFunction", (int) GetLastError ()); + return SCPE_IOERR; + } +if (incoming_bits) { + DWORD ModemStat; + if (GetCommModemStatus (port, &ModemStat)) { + sim_error_serial ("GetCommModemStatus", (int) GetLastError ()); + return SCPE_IOERR; + } + *incoming_bits = ((ModemStat&MS_CTS_ON) ? TMXR_MDM_CTS : 0) | + ((ModemStat&MS_DSR_ON) ? TMXR_MDM_DSR : 0) | + ((ModemStat&MS_RING_ON) ? TMXR_MDM_RNG : 0) | + ((ModemStat&MS_RLSD_ON) ? TMXR_MDM_DCD : 0); + } +return SCPE_OK; +} + + +/* Read from a serial port. + + The port is checked for available characters. If any are present, they are + copied to the passed buffer, and the count of characters is returned. If no + characters are available, 0 is returned. If an error occurs, -1 is returned. + If a BREAK is detected on the communications line, the corresponding flag in + the "brk" array is set. + + Implementation notes: + + 1. The "ClearCommError" function will set the CE_BREAK flag in the returned + errors value if a BREAK has occurred. However, we do not know where in + the serial stream it happened, as CE_BREAK isn't associated with a + specific character. Because the "brk" array does want a flag associated + with a specific character, we guess at the proper location by setting + the "brk" entry corresponding to the first NUL in the character stream. + If no NUL is present, then the "brk" entry associated with the first + character is set. +*/ + +int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk) +{ +DWORD read; +DWORD commerrors; +COMSTAT cs; +char *bptr; + +if (!ClearCommError (port, &commerrors, &cs)) { /* get the comm error flags */ + sim_error_serial ("ClearCommError", /* function failed; report unexpected error */ + (int) GetLastError ()); + return -1; /* return failure to caller */ + } + +if (!ReadFile (port, (LPVOID) buffer, /* read any available characters */ + (DWORD) count, &read, NULL)) { + sim_error_serial ("ReadFile", /* function failed; report unexpected error */ + (int) GetLastError ()); + return -1; /* return failure to caller */ + } + +if (commerrors & CE_BREAK) { /* was a BREAK detected? */ + bptr = (char *) memchr (buffer, 0, read); /* search for the first NUL in the buffer */ + + if (bptr) /* was one found? */ + brk = brk + (bptr - buffer); /* calculate corresponding position */ + + *brk = 1; /* set the BREAK flag */ + } + +return read; /* return the number of characters read */ +} + + +/* Write to a serial port. + + "Count" characters are written from "buffer" to the serial port. The actual + number of characters written to the port is returned. If an error occurred + on writing, -1 is returned. +*/ + +int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count) +{ +DWORD written; + +if (!WriteFile (port, (LPVOID) buffer, /* write the buffer to the serial port */ + (DWORD) count, &written, NULL)) { + sim_error_serial ("WriteFile", /* function failed; report unexpected error */ + (int) GetLastError ()); + return -1; /* return failure to caller */ + } +else + return written; /* return number of characters written */ +} + + +/* Close a serial port. + + The serial port is closed. Errors are ignored. +*/ + +void sim_close_os_serial (SERHANDLE port) +{ +CloseHandle (port); /* close the port */ +return; +} + + + +#elif defined (__unix__) || defined(__APPLE__) + +/* UNIX implementation */ + +/* Enumerate the available serial ports. + + The serial port names generated by attempting to open /dev/ttyS0 thru + /dev/ttyS53 and /dev/ttyUSB0 thru /dev/ttyUSB0. Ones we can open and + are ttys (as determined by isatty()) are added to the list. The list + is sorted alphabetically by device name. + +*/ + +static int sim_serial_os_devices (int max, SERIAL_LIST* list) +{ +int i; +int port; +int ports = 0; + +memset(list, 0, max*sizeof(*list)); +for (i=0; (ports < max) && (i < 64); ++i) { + sprintf (list[ports].name, "/dev/ttyS%d", i); + port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ + if (port != -1) { /* open OK? */ + if (isatty (port)) /* is device a TTY? */ + ++ports; + close (port); + } + } +for (i=0; (ports < max) && (i < 64); ++i) { + sprintf (list[ports].name, "/dev/ttyUSB%d", i); + port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ + if (port != -1) { /* open OK? */ + if (isatty (port)) /* is device a TTY? */ + ++ports; + close (port); + } + } +for (i=1; (ports < max) && (i < 64); ++i) { + sprintf (list[ports].name, "/dev/tty.serial%d", i); + port = open (list[ports].name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ + if (port != -1) { /* open OK? */ + if (isatty (port)) /* is device a TTY? */ + ++ports; + close (port); + } + } +return ports; +} + +/* Open a serial port. + + The serial port designated by "name" is opened, and the handle to the port is + returned. If an error occurs, INVALID_HANDLE is returned instead. After + opening, the port is configured to "raw" mode. + + Implementation notes: + + 1. We use a non-blocking open to allow for polling during reads. + + 2. There is no way to limit "open" just to serial ports, so we must check + after the port is opened. We do this with a combination of "isatty" and + "tcgetattr". + + 3. We configure with PARMRK set and IGNBRK and BRKINT cleared. This will + mark a communication line BREAK condition in the input stream with the + three-character sequence \377 \000 \000. This is detected during + reading. +*/ + +SERHANDLE sim_open_os_serial (char *name) +{ +static const tcflag_t i_clear = IGNBRK | /* ignore BREAK */ + BRKINT | /* signal on BREAK */ + INPCK | /* enable parity checking */ + ISTRIP | /* strip character to 7 bits */ + INLCR | /* map NL to CR */ + IGNCR | /* ignore CR */ + ICRNL | /* map CR to NL */ + IXON | /* enable XON/XOFF output control */ + IXOFF; /* enable XON/XOFF input control */ + +static const tcflag_t i_set = PARMRK | /* mark parity errors and line breaks */ + IGNPAR; /* ignore parity errors */ + +static const tcflag_t o_clear = OPOST; /* post-process output */ + +static const tcflag_t o_set = 0; + +static const tcflag_t c_clear = HUPCL; /* hang up line on last close */ + +static const tcflag_t c_set = CREAD | /* enable receiver */ + CLOCAL; /* ignore modem status lines */ + +static const tcflag_t l_clear = ISIG | /* enable signals */ + ICANON | /* canonical input */ + ECHO | /* echo characters */ + ECHOE | /* echo ERASE as an error correcting backspace */ + ECHOK | /* echo KILL */ + ECHONL | /* echo NL */ + NOFLSH | /* disable flush after interrupt */ + TOSTOP | /* send SIGTTOU for background output */ + IEXTEN; /* enable extended functions */ + +static const tcflag_t l_set = 0; + + +SERHANDLE port; +struct termios tio; + +port = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the port */ + +if (port == -1) { /* open failed? */ + if (errno != ENOENT && errno != EACCES) /* file not found or can't open? */ + sim_error_serial ("open", errno); /* no, so report unexpected error */ + + return INVALID_HANDLE; /* indicate failure to caller */ + } + +if (!isatty (port)) { /* is device a TTY? */ + close (port); /* no, so close it */ + return INVALID_HANDLE; /* and return failure to caller */ + } + +if (tcgetattr (port, &tio)) { /* get the terminal attributes */ + sim_error_serial ("tcgetattr", errno); /* function failed; report unexpected error */ + close (port); /* close the port */ + return INVALID_HANDLE; /* and return failure to caller */ + } + +// which of these methods is best? + +#if 1 + +tio.c_iflag = (tio.c_iflag & ~i_clear) | i_set; /* configure the serial line for raw mode */ +tio.c_oflag = (tio.c_oflag & ~o_clear) | o_set; +tio.c_cflag = (tio.c_cflag & ~c_clear) | c_set; +tio.c_lflag = (tio.c_lflag & ~l_clear) | l_set; + +#elif 0 + +tio.c_iflag &= ~(IGNBRK | BRKINT | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF); +tio.c_iflag |= PARMRK | IGNPAR; +tio.c_oflag &= ~(OPOST); +tio.c_cflag &= ~(HUPCL); +tio.c_cflag |= CREAD | CLOCAL; +tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH | TOSTOP | IEXTEN); + +#elif 0 + +tio.c_iflag = PARMRK | IGNPAR; +tio.c_oflag = 0; +tio.c_cflag = tio.c_cflag | CLOCAL | CREAD; +tio.c_lflag = 0; + +#endif + +if (tcsetattr (port, TCSANOW, &tio)) { /* set the terminal attributes */ + sim_error_serial ("tcsetattr", errno); /* function failed; report unexpected error */ + close (port); /* close the port */ + return INVALID_HANDLE; /* and return failure to caller */ + } + +return port; /* return port fd for success */ +} + + +/* Configure a serial port. + + Port parameters are configured as specified in the "config" structure. If + "config" contains an invalid configuration value, or if the host system + rejects the configuration (e.g., by requesting an unsupported combination of + character size and stop bits), SCPE_ARG is returned to the caller. If an + unexpected error occurs, SCPE_IOERR is returned. If the configuration + succeeds, SCPE_OK is returned. + + Implementation notes: + + 1. 1.5 stop bits is not a supported configuration. + +*/ + +t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) +{ +struct termios tio; +int32 i; + +static const struct { + uint32 rate; + speed_t rate_code; + } baud_map [] = + { { 50, B50 }, { 75, B75 }, { 110, B110 }, { 134, B134 }, + { 150, B150 }, { 200, B200 }, { 300, B300 }, { 600, B600 }, + { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, { 4800, B4800 }, + { 9600, B9600 }, { 19200, B19200 }, { 38400, B38400 }, { 57600, B57600 }, + { 115200, B115200 } }; + +static const int32 baud_count = sizeof (baud_map) / sizeof (baud_map [0]); + +static const tcflag_t charsize_map [4] = { CS5, CS6, CS7, CS8 }; + + +if (tcgetattr (port, &tio)) { /* get the current configuration */ + sim_error_serial ("tcgetattr", errno); /* function failed; report unexpected error */ + return SCPE_IOERR; /* return failure status */ + } + +for (i = 0; i < baud_count; i++) /* assign baud rate */ + if (config.baudrate == baud_map [i].rate) { /* match mapping value? */ + cfsetispeed(&tio, baud_map [i].rate_code); /* set input rate */ + cfsetospeed(&tio, baud_map [i].rate_code); /* set output rate */ + break; + } + +if (i == baud_count) /* baud rate assigned? */ + return SCPE_ARG; /* invalid rate specified */ + +if ((config.charsize >= 5) && (config.charsize <= 8)) /* character size OK? */ + tio.c_cflag = (tio.c_cflag & ~CSIZE) | /* replace character size code */ + charsize_map [config.charsize - 5]; +else + return SCPE_ARG; /* not a valid size */ + +switch (config.parity) { /* assign parity */ + case 'E': + tio.c_cflag = (tio.c_cflag & ~PARODD) | PARENB; /* set for even parity */ + break; + + case 'N': + tio.c_cflag = tio.c_cflag & ~PARENB; /* set for no parity */ + break; + + case 'O': + tio.c_cflag = tio.c_cflag | PARODD | PARENB; /* set for odd parity */ + break; + + default: + return SCPE_ARG; /* not a valid parity specifier */ + } + +if (config.stopbits == 1) /* one stop bit? */ + tio.c_cflag = tio.c_cflag & ~CSTOPB; /* clear two-bits flag */ +else if (config.stopbits == 2) /* two stop bits? */ + tio.c_cflag = tio.c_cflag | CSTOPB; /* set two-bits flag */ +else /* some other number? */ + return SCPE_ARG; /* not a valid number of stop bits */ + +if (tcsetattr (port, TCSAFLUSH, &tio)) { /* set the new configuration */ + sim_error_serial ("tcsetattr", errno); /* function failed; report unexpected error */ + return SCPE_IERR; /* return failure status */ + } + +return SCPE_OK; /* configuration set successfully */ +} + + +/* Control a serial port. + + The DTR and RTS line of the serial port is set or cleared as indicated in + the respective bits_to_set or bits_to_clear parameters. If the + incoming_bits parameter is not NULL, then the modem status bits DCD, RNG, + DSR and CTS are returned. + + If unreasonable or nonsense bits_to_set or bits_to_clear bits are + specified, then the return status is SCPE_ARG; + If an error occurs, SCPE_IOERR is returned. +*/ + +t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits) +{ +int bits; + +if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) || /* Assure only settable bits */ + (bits_to_clear & ~(TMXR_MDM_OUTGOING)) || + (bits_to_set & bits_to_clear)) /* and can't set and clear the same bits */ + return SCPE_ARG; +if (bits_to_set) { + bits = ((bits_to_set&TMXR_MDM_DTR) ? TIOCM_DTR : 0) | + ((bits_to_set&TMXR_MDM_RTS) ? TIOCM_RTS : 0); + if (ioctl (port, TIOCMBIS, &bits)) { /* set the desired bits */ + sim_error_serial ("ioctl", errno); /* report unexpected error */ + return SCPE_IOERR; /* return failure status */ + } + } +if (bits_to_clear) { + bits = ((bits_to_clear&TMXR_MDM_DTR) ? TIOCM_DTR : 0) | + ((bits_to_clear&TMXR_MDM_RTS) ? TIOCM_RTS : 0); + if (ioctl (port, TIOCMBIC, &bits)) { /* clear the desired bits */ + sim_error_serial ("ioctl", errno); /* report unexpected error */ + return SCPE_IOERR; /* return failure status */ + } + } +if (incoming_bits) { + if (ioctl (port, TIOCMGET, &bits)) { /* get the modem bits */ + sim_error_serial ("ioctl", errno); /* report unexpected error */ + return SCPE_IOERR; /* return failure status */ + } + *incoming_bits = ((bits&TIOCM_CTS) ? TMXR_MDM_CTS : 0) | + ((bits&TIOCM_DSR) ? TMXR_MDM_DSR : 0) | + ((bits&TIOCM_RNG) ? TMXR_MDM_RNG : 0) | + ((bits&TIOCM_CAR) ? TMXR_MDM_DCD : 0); + } + +return SCPE_OK; +} + + +/* Read from a serial port. + + The port is checked for available characters. If any are present, they are + copied to the passed buffer, and the count of characters is returned. If no + characters are available, 0 is returned. If an error occurs, -1 is returned. + If a BREAK is detected on the communications line, the corresponding flag in + the "brk" array is set. + + Implementation notes: + + 1. A character with a framing or parity error is indicated in the input + stream by the three-character sequence \377 \000 \ccc, where "ccc" is the + bad character. A communications line BREAK is indicated by the sequence + \377 \000 \000. A received \377 character is indicated by the + two-character sequence \377 \377. If we find any of these sequences, + they are replaced by the single intended character by sliding the + succeeding characters backward by one or two positions. If a BREAK + sequence was encountered, the corresponding location in the "brk" array + is determined, and the flag is set. Note that there may be multiple + sequences in the buffer. +*/ + +int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk) +{ +int read_count; +char *bptr, *cptr; +int32 remaining; + +read_count = read (port, (void *) buffer, (size_t) count); /* read from the serial port */ + +if (read_count == -1) /* read error? */ + if (errno == EAGAIN) /* no characters available? */ + return 0; /* return 0 to indicate */ + else /* some other problem */ + sim_error_serial ("read", errno); /* report unexpected error */ + +else { /* read succeeded */ + cptr = buffer; /* point at start of buffer */ + remaining = read_count - 1; /* stop search one char from end of string */ + + while (remaining > 0 && /* still characters to search? */ + (bptr = memchr (cptr, '\377', remaining))) { /* search for start of PARMRK sequence */ + remaining = remaining - (bptr - cptr) - 1; /* calc characters remaining */ + + if (*(bptr + 1) == '\377') { /* is it a \377 \377 sequence? */ + memmove (bptr + 1, bptr + 2, remaining); /* slide string backward to leave first \377 */ + remaining = remaining - 1; /* drop remaining count */ + read_count = read_count - 1; /* and read count by char eliminated */ + } + + else if (remaining > 0 && *(bptr + 1) == '\0') { /* is it a \377 \000 \ccc sequence? */ + memmove (bptr, bptr + 2, remaining); /* slide string backward to leave \ccc */ + remaining = remaining - 2; /* drop remaining count */ + read_count = read_count - 2; /* and read count by chars eliminated */ + + if (*bptr == '\0') /* is it a BREAK sequence? */ + *(brk + (bptr - buffer)) = 1; /* set corresponding BREAK flag */ + } + + cptr = bptr + 1; /* point at remainder of string */ + } + } + +return (int32) read_count; /* return the number of characters read */ +} + + +/* Write to a serial port. + + "Count" characters are written from "buffer" to the serial port. The actual + number of characters written to the port is returned. If an error occurred + on writing, -1 is returned. +*/ + +int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count) +{ +int written; + +written = write (port, (void *) buffer, (size_t) count); /* write the buffer to the serial port */ + +if (written == -1) { + if (errno != EAGAIN) /* unexpected error? */ + sim_error_serial ("write", errno); /* report it */ + else + written = 0; /* not an error, but nothing written */ + } + +return (int32) written; /* return number of characters written */ +} + + +/* Close a serial port. + + The serial port is closed. Errors are ignored. +*/ + +void sim_close_os_serial (SERHANDLE port) +{ +close (port); /* close the port */ +return; +} + + +#elif defined (VMS) + +/* VMS implementation */ + +#if defined(__VAX) +#define sys$assign SYS$ASSIGN +#define sys$qiow SYS$QIOW +#define sys$dassgn SYS$DASSGN +#define sys$device_scan SYS$DEVICE_SCAN +#define sys$getdviw SYS$GETDVIW +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + unsigned short sense_count; + unsigned char sense_first_char; + unsigned char sense_reserved; + unsigned int stat; + unsigned int stat2; } SENSE_BUF; + +typedef struct { + unsigned short status; + unsigned short count; + unsigned int dev_status; } IOSB; + +typedef struct { + unsigned short buffer_size; + unsigned short item_code; + void *buffer_address; + void *return_length_address; + } ITEM; + +/* Enumerate the available serial ports. + + The serial port names generated by attempting to open /dev/ttyS0 thru + /dev/ttyS53 and /dev/ttyUSB0 thru /dev/ttyUSB0. Ones we can open and + are ttys (as determined by isatty()) are added to the list. The list + is sorted alphabetically by device name. + +*/ + +static int sim_serial_os_devices (int max, SERIAL_LIST* list) +{ +$DESCRIPTOR (wild, "*"); +char devstr[sizeof(list[0].name)]; +$DESCRIPTOR (device, devstr); +int ports; +IOSB iosb; +uint32 status; +uint32 devsts; +#define UCB$M_TEMPLATE 0x2000 /* Device is a template device */ +#define UCB$M_ONLINE 0x0010 /* Device is online */ +uint32 devtype; +uint32 devdepend; +#define DEV$M_RTM 0x20000000 +uint32 devnamlen = 0; +t_bool done = FALSE; +uint32 context[2]; +uint32 devclass = DC$_TERM; /* Only interested in terminal devices */ +ITEM select_items[] = { {sizeof (devclass), DVS$_DEVCLASS, &devclass, NULL}, + { 0, 0, NULL, NULL}}; +ITEM valid_items[] = { { sizeof (devsts), DVI$_STS, &devsts, NULL}, + { sizeof(devstr), DVI$_DEVNAM, devstr, &devnamlen}, + { sizeof(devtype), DVI$_DEVTYPE, &devtype, NULL}, + { sizeof(devdepend), DVI$_DEVDEPEND, &devdepend, NULL}, + { 0, 0, NULL, NULL}}; + +memset(context, 0, sizeof(context)); +memset(devstr, 0, sizeof(devstr)); +memset(list, 0, max*sizeof(*list)); +for (ports=0; (ports < max); ++ports) { + device.dsc$w_length = sizeof (devstr) - 1; + status = sys$device_scan (&device, + &device.dsc$w_length, + &wild, + select_items, + &context); + switch (status) { + case SS$_NOSUCHDEV: + case SS$_NOMOREDEV: + done = TRUE; + break; + default: + if (0 == (status&1)) + done = TRUE; + else { + status = sys$getdviw (0, 0, &device, valid_items, &iosb, NULL, 0, NULL); + if (status == SS$_NORMAL) + status = iosb.status; + if (status != SS$_NORMAL) { + done = TRUE; + break; + } + device.dsc$w_length = devnamlen; + if ((0 == (devsts & UCB$M_TEMPLATE)) && + (0 != (devsts & UCB$M_ONLINE)) && + (0 == (devdepend & DEV$M_RTM)) { + devstr[device.dsc$w_length] = '\0'; + strcpy (list[ports].name, devstr); + while (list[ports].name[0] == '_') + strcpy (list[ports].name, list[ports].name+1); + } + else + --ports; + } + break; + } + if (done) + break; + } +return ports; +} + +/* Open a serial port. + + The serial port designated by "name" is opened, and the handle to the port is + returned. If an error occurs, INVALID_HANDLE is returned instead. After + opening, the port is configured to "raw" mode. + + Implementation notes: + + 1. We use a non-blocking open to allow for polling during reads. + + 2. There is no way to limit "open" just to serial ports, so we must check + after the port is opened. We do this with sys$getdvi. + +*/ + +SERHANDLE sim_open_os_serial (char *name) +{ +uint32 status; +uint32 chan = 0; +IOSB iosb; +$DESCRIPTOR (devnam, name); +uint32 devclass; +ITEM items[] = { {sizeof (devclass), DVI$_DEVCLASS, &devclass, NULL}, + { 0, 0, NULL, NULL}}; +SENSE_BUF start_mode = { 0 }; +SENSE_BUF run_mode = { 0 }; + +devnam.dsc$w_length = strlen (devnam.dsc$a_pointer); +status = sys$assign (&devnam, &chan, 0, 0); +if (status != SS$_NORMAL) + return INVALID_HANDLE; +status = sys$getdviw (0, chan, NULL, items, &iosb, NULL, 0, NULL); +if ((status != SS$_NORMAL) || + (iosb.status != SS$_NORMAL) || + (devclass != DC$_TERM)) { + sys$dassgn (chan); + return INVALID_HANDLE; + } +status = sys$qiow (0, chan, IO$_SENSEMODE, &iosb, 0, 0, + &start_mode, sizeof (start_mode), 0, 0, 0, 0); +if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) { + sys$dassgn (chan); + return INVALID_HANDLE; + } +run_mode = start_mode; +run_mode.stat = start_mode.stat | TT$M_NOECHO & ~(TT$M_HOSTSYNC | TT$M_TTSYNC | TT$M_HALFDUP); +run_mode.stat2 = start_mode.stat2 | TT2$M_PASTHRU; +status = sys$qiow (0, chan, IO$_SETMODE, &iosb, 0, 0, + &run_mode, sizeof (run_mode), 0, 0, 0, 0); +if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) { + sys$dassgn (chan); + return INVALID_HANDLE; + } +return chan; /* return channel for success */ +} + + +/* Configure a serial port. + + Port parameters are configured as specified in the "config" structure. If + "config" contains an invalid configuration value, or if the host system + rejects the configuration (e.g., by requesting an unsupported combination of + character size and stop bits), SCPE_ARG is returned to the caller. If an + unexpected error occurs, SCPE_IOERR is returned. If the configuration + succeeds, SCPE_OK is returned. + + Implementation notes: + + 1. 1.5 stop bits is not a supported configuration. + +*/ + +t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) +{ +int32 i; +SENSE_BUF sense; +uint32 status, speed, parity, charsize, stopbits; +IOSB iosb; +static const struct { + uint32 rate; + uint32 rate_code; + } baud_map [] = + { { 50, TT$C_BAUD_50 }, { 75, TT$C_BAUD_75 }, { 110, TT$C_BAUD_110 }, { 134, TT$C_BAUD_134 }, + { 150, TT$C_BAUD_150 }, { 300, TT$C_BAUD_300 }, { 600, TT$C_BAUD_600 }, { 1200, TT$C_BAUD_1200 }, + { 1800, TT$C_BAUD_1800 }, { 2000, TT$C_BAUD_2000 }, { 2400, TT$C_BAUD_2400 }, { 3600, TT$C_BAUD_3600 }, + { 4800, TT$C_BAUD_4800 }, { 7200, TT$C_BAUD_7200 }, { 9600, TT$C_BAUD_9600 }, { 19200, TT$C_BAUD_19200 }, + { 38400, TT$C_BAUD_38400 }, { 57600, TT$C_BAUD_57600 }, { 76800, TT$C_BAUD_76800 }, { 115200, TT$C_BAUD_115200} }; + +static const int32 baud_count = sizeof (baud_map) / sizeof (baud_map [0]); + +status = sys$qiow (0, port, IO$_SENSEMODE, &iosb, 0, 0, &sense, sizeof(sense), 0, NULL, 0, 0); +if (status == SS$_NORMAL) + status = iosb.status; +if (status != SS$_NORMAL) { + sim_error_serial ("config-SENSEMODE", status); /* report unexpected error */ + return SCPE_IOERR; + } + +for (i = 0; i < baud_count; i++) /* assign baud rate */ + if (config.baudrate == baud_map [i].rate) { /* match mapping value? */ + speed = baud_map [i].rate_code << 8 | /* set input rate */ + baud_map [i].rate_code; /* set output rate */ + break; + } + +if (i == baud_count) /* baud rate assigned? */ + return SCPE_ARG; /* invalid rate specified */ + +if (config.charsize >= 5 && config.charsize <= 8) /* character size OK? */ + charsize = TT$M_ALTFRAME | config.charsize; /* set character size */ +else + return SCPE_ARG; /* not a valid size */ + +switch (config.parity) { /* assign parity */ + case 'E': + parity = TT$M_ALTRPAR | TT$M_PARITY; /* set for even parity */ + break; + + case 'N': + parity = TT$M_ALTRPAR; /* set for no parity */ + break; + + case 'O': + parity = TT$M_ALTRPAR | TT$M_PARITY | TT$M_ODD; /* set for odd parity */ + break; + + default: + return SCPE_ARG; /* not a valid parity specifier */ + } + + +switch (config.stopbits) { + case 1: /* one stop bit? */ + stopbits = 0; + break; + case 2: /* two stop bits? */ + if ((speed & 0xff) <= TT$C_BAUD_150) { /* Only valid for */ + stopbits = TT$M_TWOSTOP; /* speeds 150baud or less */ + break; + } + default: + return SCPE_ARG; /* not a valid number of stop bits */ + } + +status = sys$qiow (0, port, IO$_SETMODE, &iosb, 0, 0, + &sense, sizeof (sense), speed, 0, parity | charsize | stopbits, 0); +if (status == SS$_NORMAL) + status = iosb.status; +if (status != SS$_NORMAL) { + sim_error_serial ("config-SETMODE", status); /* report unexpected error */ + return SCPE_IOERR; + } +return SCPE_OK; /* configuration set successfully */ +} + + +/* Control a serial port. + + The DTR and RTS line of the serial port is set or cleared as indicated in + the respective bits_to_set or bits_to_clear parameters. If the + incoming_bits parameter is not NULL, then the modem status bits DCD, RNG, + DSR and CTS are returned. + + If unreasonable or nonsense bits_to_set or bits_to_clear bits are + specified, then the return status is SCPE_ARG; + If an error occurs, SCPE_IOERR is returned. +*/ + +t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits) +{ +uint32 status; +IOSB iosb; +uint32 bits[2] = {0, 0}; + +if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) || /* Assure only settable bits */ + (bits_to_clear & ~(TMXR_MDM_OUTGOING)) || + (bits_to_set & bits_to_clear)) /* and can't set and clear the same bits */ + return SCPE_ARG; +if (bits_to_set) + bits[0] |= (((bits_to_set&TMXR_MDM_DTR) ? TT$M_DS_DTR : 0) | + ((bits_to_set&TMXR_MDM_RTS) ? TT$M_DS_RTS : 0)) << 16; +if (bits_to_clear) + bits[0] |= (((bits_to_clear&TMXR_MDM_DTR) ? TT$M_DS_DTR : 0) | + ((bits_to_clear&TMXR_MDM_RTS) ? TT$M_DS_RTS : 0)) << 24; +if (bits_to_set || bits_to_clear) { + status = sys$qiow (0, port, IO$_SETMODE|IO$M_SET_MODEM|IO$M_MAINT, &iosb, 0, 0, + bits, 0, 0, 0, 0, 0); + if (status == SS$_NORMAL) + status = iosb.status; + if (status != SS$_NORMAL) { + sim_error_serial ("control-SETMODE", status); /* report unexpected error */ + return SCPE_IOERR; + } + } +if (incoming_bits) { + uint32 modem; + + status = sys$qiow (0, port, IO$_SENSEMODE|IO$M_RD_MODEM, &iosb, 0, 0, + bits, 0, 0, 0, 0, 0); + if (status == SS$_NORMAL) + status = iosb.status; + if (status != SS$_NORMAL) { + sim_error_serial ("control-SENSEMODE", status); /* report unexpected error */ + return SCPE_IOERR; + } + modem = bits[0] >> 16; + *incoming_bits = ((modem&TT$M_DS_CTS) ? TMXR_MDM_CTS : 0) | + ((modem&TT$M_DS_DSR) ? TMXR_MDM_DSR : 0) | + ((modem&TT$M_DS_RING) ? TMXR_MDM_RNG : 0) | + ((modem&TT$M_DS_CARRIER) ? TMXR_MDM_DCD : 0); + } + +return SCPE_OK; +} + + +/* Read from a serial port. + + The port is checked for available characters. If any are present, they are + copied to the passed buffer, and the count of characters is returned. If no + characters are available, 0 is returned. If an error occurs, -1 is returned. + If a BREAK is detected on the communications line, the corresponding flag in + the "brk" array is set. + + Implementation notes: + + 1. A character with a framing or parity error is indicated in the input + stream by the three-character sequence \377 \000 \ccc, where "ccc" is the + bad character. A communications line BREAK is indicated by the sequence + \377 \000 \000. A received \377 character is indicated by the + two-character sequence \377 \377. If we find any of these sequences, + they are replaced by the single intended character by sliding the + succeeding characters backward by one or two positions. If a BREAK + sequence was encountered, the corresponding location in the "brk" array + is determined, and the flag is set. Note that there may be multiple + sequences in the buffer. +*/ + +int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk) +{ +int read_count = 0; +uint32 status; +static uint32 term[2] = {0, 0}; +unsigned char buf[4]; +IOSB iosb; +SENSE_BUF sense; + +status = sys$qiow (0, port, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &iosb, + 0, 0, &sense, 8, 0, term, 0, 0); +if (status == SS$_NORMAL) + status = iosb.status; +if (status != SS$_NORMAL) { + sim_error_serial ("read", status); /* report unexpected error */ + return -1; + } +if (sense.sense_count == 0) /* no characters available? */ + return 0; /* return 0 to indicate */ +status = sys$qiow (0, port, IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED | IO$M_TRMNOECHO, + &iosb, 0, 0, buffer, (count < sense.sense_count) ? count : sense.sense_count, 0, term, 0, 0); +if (status == SS$_NORMAL) + status = iosb.status; +if (status != SS$_NORMAL) { + sim_error_serial ("read", status); /* report unexpected error */ + return -1; + } +return (int32)iosb.count; /* return the number of characters read */ +} + + +/* Write to a serial port. + + "Count" characters are written from "buffer" to the serial port. The actual + number of characters written to the port is returned. If an error occurred + on writing, -1 is returned. +*/ + +int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count) +{ +uint32 status; +static uint32 term[2] = {0, 0}; +unsigned char buf[4]; +IOSB iosb; +uint32 devsts = 0; +#define UCB$M_BSY 0x100 /* Device I/O busy flag */ +ITEM items[] = { {sizeof (devsts), DVI$_STS, &devsts, NULL}, + { 0, 0, NULL, NULL}}; + +status = sys$getdviw (0, port, NULL, items, &iosb, NULL, 0, 0); +if (status == SS$_NORMAL) + status = iosb.status; +if (status != SS$_NORMAL) { + sim_error_serial ("write-GETDVI", status); /* report unexpected error */ + return -1; + } +if (devsts & UCB$M_BSY) + return 0; /* Would block */ +status = sys$qio (0, port, IO$_WRITELBLK | IO$M_NOFORMAT, + NULL, 0, 0, buffer, count, 0, 0, 0, 0); +if (status != SS$_NORMAL) { + sim_error_serial ("write", status); /* report unexpected error */ + return -1; + } +return (int32)iosb.count; /* return number of characters written */ +} + + +/* Close a serial port. + + The serial port is closed. Errors are ignored. +*/ + +void sim_close_os_serial (SERHANDLE port) +{ +sys$dassgn (port); /* close the port */ +return; +} + + +#else + +/* Non-implemented stubs */ + +/* Enumerate the available serial ports. */ + +static int sim_serial_os_devices (int max, SERIAL_LIST* list) +{ +return 0; +} + +/* Open a serial port */ + +SERHANDLE sim_open_os_serial (char *name) +{ +return INVALID_HANDLE; +} + + +/* Configure a serial port */ + +t_stat sim_config_os_serial (SERHANDLE port, SERCONFIG config) +{ +return SCPE_IERR; +} + + +/* Control a serial port */ + +t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits) +{ +return SCPE_NOFNC; +} + + +/* Read from a serial port */ + +int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk) +{ +return -1; +} + + +/* Write to a serial port */ + +int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count) +{ +return -1; +} + + +/* Close a serial port */ + +void sim_close_os_serial (SERHANDLE port) +{ +return; +} + + + +#endif /* end else !implemented */ diff --git a/sim_serial.h b/sim_serial.h new file mode 100644 index 00000000..f632e973 --- /dev/null +++ b/sim_serial.h @@ -0,0 +1,99 @@ +/* sim_serial.h: OS-dependent serial port routines header file + + Copyright (c) 2008, J. David Bryan + + 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 + THE AUTHOR 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. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + 07-Oct-08 JDB [serial] Created file +*/ + + +#ifndef _SIM_SERIAL_H_ +#define _SIM_SERIAL_H_ 0 + +#if defined (_WIN32) + +/* Windows definitions */ + +/* We need the basic Win32 definitions, but including "windows.h" also includes + "winsock.h" as well. However, "sim_sock.h" explicitly includes "winsock2.h," + and this file cannot coexist with "winsock.h". So we set a guard definition + that prevents "winsock.h" from being included. +*/ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#include + +typedef HANDLE SERHANDLE; + +#define INVALID_HANDLE INVALID_HANDLE_VALUE + + +#elif defined (__unix__) || defined(__APPLE__) + +/* UNIX definitions */ + +#include +#include +#include +#include + +typedef int SERHANDLE; + +#define INVALID_HANDLE -1 + + +#elif defined (VMS) + +/* VMS definitions */ + +typedef int SERHANDLE; + +#define INVALID_HANDLE (uint32)(-1) + +#else + +/* Non-implemented definitions */ + +typedef int SERHANDLE; + +#define INVALID_HANDLE -1 + +#endif + +/* Common definitions */ + +/* Global routines */ +#include "sim_tmxr.h" /* need TMLN definition and modem definitions */ + +extern SERHANDLE sim_open_serial (char *name, TMLN *lp, t_stat *status); +extern t_stat sim_config_serial (SERHANDLE port, const char *config); +extern t_stat sim_control_serial (SERHANDLE port, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits); +extern int32 sim_read_serial (SERHANDLE port, char *buffer, int32 count, char *brk); +extern int32 sim_write_serial (SERHANDLE port, char *buffer, int32 count); +extern void sim_close_serial (SERHANDLE port); +extern t_stat sim_show_serial (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, char* desc); + +#endif diff --git a/sim_sock.c b/sim_sock.c index 027f7f1d..f2648616 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -23,6 +23,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 15-Oct-12 MP Added definitions needed to detect possible tcp + connect failures + 25-Sep-12 MP Reworked for RFC3493 interfaces supporting IPv6 and IPv4 22-Jun-10 RMS Fixed types in sim_accept_conn (from Mark Pizzolato) 19-Nov-05 RMS Added conditional for OpenBSD (from Federico G. Schwindt) 16-Aug-05 RMS Fixed spurious SIGPIPE signal error in Unix @@ -43,6 +46,28 @@ #include "sim_sock.h" #include +extern FILE *sim_log; + +#if defined(AF_INET6) && defined(_WIN32) +#include +#endif + +#ifdef HAVE_DLOPEN +#include +#endif + +#ifndef WSAAPI +#define WSAAPI +#endif + +#if defined(SHUT_RDWR) && !defined(SD_BOTH) +#define SD_BOTH SHUT_RDWR +#endif + +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif + /* OS dependent routines sim_master_sock create master socket @@ -54,23 +79,29 @@ sim_msg_sock send message to socket */ -int32 sim_sock_cnt = 0; - /* First, all the non-implemented versions */ #if defined (__OS2__) && !defined (__EMX__) -SOCKET sim_master_sock (int32 port) +void sim_init_sock (void) +{ +} + +void sim_cleanup_sock (void) +{ +} + +SOCKET sim_master_sock (const char *hostport, t_stat *parse_status) { return INVALID_SOCKET; } -SOCKET sim_connect_sock (int32 ip, int32 port) +SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port) { return INVALID_SOCKET; } -SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr) +SOCKET sim_accept_conn (SOCKET master, char **connectaddr); { return INVALID_SOCKET; } @@ -90,11 +121,6 @@ void sim_close_sock (SOCKET sock, t_bool master) return; } -int32 sim_setnonblock (SOCKET sock) -{ -return SOCKET_ERROR; -} - #else /* endif unimpl */ /* UNIX, Win32, Macintosh, VMS, OS2 (Berkeley socket) routines */ @@ -108,30 +134,521 @@ sim_close_sock (s, flg); return INVALID_SOCKET; } -SOCKET sim_create_sock (void) +typedef void (WSAAPI *freeaddrinfo_func) (struct addrinfo *ai); +static freeaddrinfo_func p_freeaddrinfo; + +typedef int (WSAAPI *getaddrinfo_func) (const char *hostname, + const char *service, + const struct addrinfo *hints, + struct addrinfo **res); +static getaddrinfo_func p_getaddrinfo; + +typedef int (WSAAPI *getnameinfo_func) (const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags); +static getnameinfo_func p_getnameinfo; + +static void WSAAPI s_freeaddrinfo (struct addrinfo *ai) +{ +struct addrinfo *a, *an; + +for (a=ai; a != NULL; a=an) { + an = a->ai_next; + free (a->ai_canonname); + free (a->ai_addr); + free (a); + } +} + +static int WSAAPI s_getaddrinfo (const char *hostname, + const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ +struct hostent *he; +struct servent *se = NULL; +struct sockaddr_in *sin; +struct addrinfo *result = NULL; +struct addrinfo *ai, *lai; +struct addrinfo dhints; +struct in_addr ipaddr; +struct in_addr *fixed[2]; +struct in_addr **ips = NULL; +struct in_addr **ip; +const char *cname = NULL; +int port = 0; + +// Validate parameters +if ((hostname == NULL) && (service == NULL)) + return EAI_NONAME; + +if (hints) { + if ((hints->ai_family != PF_INET) && (hints->ai_family != PF_UNSPEC)) + return EAI_FAMILY; + switch (hints->ai_socktype) + { + default: + return EAI_SOCKTYPE; + case SOCK_DGRAM: + case SOCK_STREAM: + case 0: + break; + } + } +else { + hints = &dhints; + memset(&dhints, 0, sizeof(dhints)); + dhints.ai_family = PF_UNSPEC; + } +if (service) { + char *c; + + port = strtoul(service, &c, 10); + if ((port == 0) || (*c != '\0')) { + switch (hints->ai_socktype) + { + case SOCK_DGRAM: + se = getservbyname(service, "udp"); + break; + case SOCK_STREAM: + case 0: + se = getservbyname(service, "tcp"); + break; + } + if (NULL == se) + return EAI_SERVICE; + port = se->s_port; + } + } + +if (hostname) { + if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) || + (0 == strcmp("255.255.255.255", hostname))) { + fixed[0] = &ipaddr; + fixed[1] = NULL; + } + else { + if ((0xffffffff != (ipaddr.s_addr = inet_addr(hostname))) || + (0 == strcmp("255.255.255.255", hostname))) { + fixed[0] = &ipaddr; + fixed[1] = NULL; + if ((hints->ai_flags & AI_CANONNAME) && !(hints->ai_flags & AI_NUMERICHOST)) { + he = gethostbyaddr((char *)&ipaddr, 4, AF_INET); + if (NULL != he) + cname = he->h_name; + else + cname = hostname; + } + ips = fixed; + } + else { + if (hints->ai_flags & AI_NUMERICHOST) + return EAI_NONAME; + he = gethostbyname(hostname); + if (he) { + ips = (struct in_addr **)he->h_addr_list; + if (hints->ai_flags & AI_CANONNAME) + cname = he->h_name; + } + else { + switch (h_errno) + { + case HOST_NOT_FOUND: + case NO_DATA: + return EAI_NONAME; + case TRY_AGAIN: + return EAI_AGAIN; + default: + return EAI_FAIL; + } + } + } + } + } +else { + if (hints->ai_flags & AI_PASSIVE) + ipaddr.s_addr = htonl(INADDR_ANY); + else + ipaddr.s_addr = htonl(INADDR_LOOPBACK); + fixed[0] = &ipaddr; + fixed[1] = NULL; + ips = fixed; + } +for (ip=ips; *ip != NULL; ++ip) { + ai = calloc(1, sizeof(*ai)); + if (NULL == ai) { + s_freeaddrinfo(result); + return EAI_MEMORY; + } + ai->ai_family = PF_INET; + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + ai->ai_addr = NULL; + ai->ai_addrlen = sizeof(struct sockaddr_in); + ai->ai_canonname = NULL; + ai->ai_next = NULL; + ai->ai_addr = calloc(1, sizeof(struct sockaddr_in)); + if (NULL == ai->ai_addr) { + free(ai); + s_freeaddrinfo(result); + return EAI_MEMORY; + } + sin = (struct sockaddr_in *)ai->ai_addr; + sin->sin_family = PF_INET; + sin->sin_port = port; + memcpy(&sin->sin_addr, *ip, sizeof(sin->sin_addr)); + if (NULL == result) + result = ai; + else + lai->ai_next = ai; + lai = ai; + } +if (cname) { + result->ai_canonname = calloc(1, strlen(cname)+1); + if (NULL == result->ai_canonname) { + s_freeaddrinfo(result); + return EAI_MEMORY; + } + strcpy(result->ai_canonname, cname); + } +*res = result; +return 0; +} + +#ifndef EAI_OVERFLOW +#define EAI_OVERFLOW WSAENAMETOOLONG +#endif + +static int WSAAPI s_getnameinfo (const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, + int flags) +{ +struct hostent *he; +struct servent *se = NULL; +struct sockaddr_in *sin = (struct sockaddr_in *)sa; + +if (sin->sin_family != PF_INET) + return EAI_FAMILY; +if ((NULL == host) && (NULL == serv)) + return EAI_NONAME; +if ((serv) && (servlen > 0)) { + if (flags & NI_NUMERICSERV) + se = NULL; + else + if (flags & NI_DGRAM) + se = getservbyport(sin->sin_port, "udp"); + else + se = getservbyport(sin->sin_port, "tcp"); + if (se) { + if (servlen <= strlen(se->s_name)) + return EAI_OVERFLOW; + strcpy(serv, se->s_name); + } + else { + char buf[16]; + + sprintf(buf, "%d", ntohs(sin->sin_port)); + if (servlen <= strlen(buf)) + return EAI_OVERFLOW; + strcpy(serv, buf); + } + } +if ((host) && (hostlen > 0)) { + if (flags & NI_NUMERICHOST) + he = NULL; + else + he = gethostbyaddr((char *)&sin->sin_addr, 4, AF_INET); + if (he) { + if (hostlen < strlen(he->h_name)+1) + return EAI_OVERFLOW; + strcpy(host, he->h_name); + } + else { + if (flags & NI_NAMEREQD) + return EAI_NONAME; + if (hostlen < strlen(inet_ntoa(sin->sin_addr))+1) + return EAI_OVERFLOW; + strcpy(host, inet_ntoa(sin->sin_addr)); + } + } +return 0; +} + +#if defined(_WIN32) || defined(__CYGWIN__) + +/* Dynamic DLL load variables */ +#ifdef _WIN32 +static HINSTANCE hLib = 0; /* handle to DLL */ +#else +static void *hLib = NULL; /* handle to Library */ +#endif +static int lib_loaded = 0; /* 0=not loaded, 1=loaded, 2=library load failed, 3=Func load failed */ +static char* lib_name = "Ws2_32.dll"; + +/* load function pointer from DLL */ +typedef int (*_func)(); + +static void load_function(char* function, _func* func_ptr) { +#ifdef _WIN32 + *func_ptr = (_func)GetProcAddress(hLib, function); +#else + *func_ptr = (_func)dlsym(hLib, function); +#endif + if (*func_ptr == 0) { + char* msg = "Sockets: Failed to find function '%s' in %s\r\n"; + + printf (msg, function, lib_name); + if (sim_log) fprintf (sim_log, msg, function, lib_name); + lib_loaded = 3; + } +} + +/* load Ws2_32.dll as required */ +int load_ws2(void) { + switch(lib_loaded) { + case 0: /* not loaded */ + /* attempt to load DLL */ +#ifdef _WIN32 + hLib = LoadLibraryA(lib_name); +#else + hLib = dlopen(lib_name, RTLD_NOW); +#endif + if (hLib == 0) { + /* failed to load DLL */ + char* msg = "Sockets: Failed to load %s\r\n"; + + printf (msg, lib_name); + if (sim_log) + fprintf (sim_log, msg, lib_name); + lib_loaded = 2; + break; + } else { + /* library loaded OK */ + lib_loaded = 1; + } + + /* load required functions; sets dll_load=3 on error */ + load_function("getaddrinfo", (_func *) &p_getaddrinfo); + load_function("getnameinfo", (_func *) &p_getnameinfo); + load_function("freeaddrinfo", (_func *) &p_freeaddrinfo); + + if (lib_loaded != 1) { + /* unsuccessful load, connect stubs */ + p_getaddrinfo = (getaddrinfo_func)s_getaddrinfo; + p_getnameinfo = (getnameinfo_func)s_getnameinfo; + p_freeaddrinfo = (freeaddrinfo_func)s_freeaddrinfo; + } + break; + default: /* loaded or failed */ + break; + } + return (lib_loaded == 1) ? 1 : 0; +} +#endif + +/* OS independent routines + + sim_parse_addr parse a hostname/ipaddress from port and apply defaults and + optionally validate an address match +*/ + +/* sim_parse_addr host:port + + Presumption is that the input, if it doesn't contain a ':' character is a port specifier. + If the host field contains one or more colon characters (i.e. it is an IPv6 address), + the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format) + + Inputs: + cptr = pointer to input string + default_host + = optional pointer to default host if none specified + host_len = length of host buffer + default_port + = optional pointer to default host if none specified + port_len = length of port buffer + validate_addr = optional name/addr which is checked to be equivalent + to the host result of parsing the other input. This + address would usually be returned by sim_accept_conn. + Outputs: + host = pointer to buffer for IP address (may be NULL), 0 = none + port = pointer to buffer for IP port (may be NULL), 0 = none + result = status (SCPE_OK on complete success or SCPE_ARG if + parsing can't happen due to bad syntax, a value is + out of range, a result can't fit into a result buffer, + a service name doesn't exist, or a validation name + doesn't match the parsed host) +*/ + +t_stat sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr) +{ +char gbuf[CBUFSIZE]; +char *hostp, *portp; +char *endc; +unsigned long portval; + +if ((cptr == NULL) || (*cptr == 0)) + return SCPE_ARG; +if ((host != NULL) && (host_len != 0)) + memset (host, 0, host_len); +if ((port != NULL) && (port_len != 0)) + memset (port, 0, port_len); +strncpy (gbuf, cptr, CBUFSIZE); +hostp = gbuf; /* default addr */ +portp = NULL; +if ((portp = strrchr (gbuf, ':')) && /* x:y? split */ + (NULL == strchr (portp, ']'))) { + *portp++ = 0; + if (*portp == '\0') + portp = (char *)default_port; + } +else + if (default_port) + portp = (char *)default_port; + else { + portp = gbuf; + hostp = NULL; + } +if (portp != NULL) { + portval = strtoul(portp, &endc, 10); + if ((*endc == '\0') && ((portval == 0) || (portval > 65535))) + return SCPE_ARG; /* numeric value too big */ + if (*endc != '\0') { + struct servent *se = getservbyname(portp, "tcp"); + + if (se == NULL) + return SCPE_ARG; /* invalid service name */ + } + } +if (port) /* port wanted? */ + if (portp != NULL) { + if (strlen(portp) >= port_len) + return SCPE_ARG; /* no room */ + else + strcpy (port, portp); + } +if (hostp != NULL) { + if (']' == hostp[strlen(hostp)-1]) { + if ('[' != hostp[0]) + return SCPE_ARG; /* invalid domain literal */ + strcpy(hostp, hostp+1); /* remove brackets from domain literal host */ + hostp[strlen(hostp)-1] = '\0'; + } + } +if (host) /* host wanted? */ + if (hostp != NULL) { + if (strlen(hostp) >= host_len) + return SCPE_ARG; /* no room */ + else + strcpy (host, hostp); + } +if (validate_addr) { + struct addrinfo *ai_host, *ai_validate, *ai; + t_stat status; + + if (hostp == NULL) + return SCPE_ARG; + if (p_getaddrinfo(hostp, NULL, NULL, &ai_host)) + return SCPE_ARG; + if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) { + p_freeaddrinfo (ai_host); + return SCPE_ARG; + } + status = SCPE_ARG; + for (ai = ai_host; ai != NULL; ai = ai->ai_next) { + if ((ai->ai_addrlen == ai_validate->ai_addrlen) && + (ai->ai_family == ai_validate->ai_family) && + (0 == memcmp (ai->ai_addr, ai_validate->ai_addr, ai->ai_addrlen))) { + status = SCPE_OK; + break; + } + } + p_freeaddrinfo (ai_host); + p_freeaddrinfo (ai_validate); + return status; + } +return SCPE_OK; +} + +void sim_init_sock (void) +{ +#if defined (_WIN32) +int err; +WORD wVersionRequested; +WSADATA wsaData; +wVersionRequested = MAKEWORD (2, 2); + +err = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */ +if (err != 0) + printf ("Winsock: startup error %d\n", err); +#if defined(AF_INET6) +load_ws2 (); +#endif /* endif AF_INET6 */ +#else /* Use native addrinfo APIs */ +#if defined(AF_INET6) + p_getaddrinfo = (getaddrinfo_func)getaddrinfo; + p_getnameinfo = (getnameinfo_func)getnameinfo; + p_freeaddrinfo = (freeaddrinfo_func)freeaddrinfo; +#else + /* Native APIs not available, connect stubs */ + p_getaddrinfo = (getaddrinfo_func)s_getaddrinfo; + p_getnameinfo = (getnameinfo_func)s_getnameinfo; + p_freeaddrinfo = (freeaddrinfo_func)s_freeaddrinfo; +#endif /* endif AF_INET6 */ +#endif /* endif _WIN32 */ +#if defined (SIGPIPE) +signal (SIGPIPE, SIG_IGN); /* no pipe signals */ +#endif +} + +void sim_cleanup_sock (void) +{ +#if defined (_WIN32) +WSACleanup (); +#endif +} + +#if defined (_WIN32) /* Windows */ +static int32 sim_setnonblock (SOCKET sock) +{ +unsigned long non_block = 1; + +return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */ +} + +#elif defined (VMS) /* VMS */ +static int32 sim_setnonblock (SOCKET sock) +{ +int non_block = 1; + +return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */ +} + +#else /* Mac, Unix, OS/2 */ +static int32 sim_setnonblock (SOCKET sock) +{ +int32 fl, sta; + +fl = fcntl (sock, F_GETFL,0); /* get flags */ +if (fl == -1) + return SOCKET_ERROR; +sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */ +if (sta == -1) + return SOCKET_ERROR; +#if !defined (macintosh) && !defined (__EMX__) /* Unix only */ +sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */ +if (sta == -1) + return SOCKET_ERROR; +#endif +return 0; +} + +#endif /* endif !Win32 && !VMS */ + +static SOCKET sim_create_sock (int af) { SOCKET newsock; int32 err; -#if defined (_WIN32) -WORD wVersionRequested; -WSADATA wsaData; -wVersionRequested = MAKEWORD (1, 1); - -if (sim_sock_cnt == 0) { - err = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */ - if (err != 0) { - printf ("Winsock: startup error %d\n", err); - return INVALID_SOCKET; - } - } -sim_sock_cnt = sim_sock_cnt + 1; -#endif /* endif Win32 */ -#if defined (SIGPIPE) -signal (SIGPIPE, SIG_IGN); /* no pipe signals */ -#endif - -newsock = socket (AF_INET, SOCK_STREAM, 0); /* create socket */ +newsock = socket (af, SOCK_STREAM, 0); /* create socket */ if (newsock == INVALID_SOCKET) { /* socket error? */ err = WSAGetLastError (); printf ("Sockets: socket error %d\n", err); @@ -140,21 +657,51 @@ if (newsock == INVALID_SOCKET) { /* socket error? */ return newsock; } -SOCKET sim_master_sock (int32 port) -{ -SOCKET newsock; -struct sockaddr_in name; -int32 sta; +/* + Some platforms and/or network stacks have varying support for listening on + an IPv6 socket and receiving connections from both IPv4 and IPv6 client + connections. This is known as IPv4-Mapped. Some platforms claim such + support (i.e. some Windows versions), but it doesn't work in all cases. +*/ -newsock = sim_create_sock (); /* create socket */ -if (newsock == INVALID_SOCKET) /* socket error? */ +SOCKET sim_master_sock (const char *hostport, t_stat *parse_status) +{ +SOCKET newsock = INVALID_SOCKET; +int32 sta; +char host[CBUFSIZE], port[CBUFSIZE]; +t_stat r; +struct addrinfo hints; +struct addrinfo *result = NULL; + +r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL); +if (parse_status) + *parse_status = r; +if (r != SCPE_OK) return newsock; -name.sin_family = AF_INET; /* name socket */ -name.sin_port = htons ((unsigned short) port); /* insert port */ -name.sin_addr.s_addr = htonl (INADDR_ANY); /* insert addr */ - -sta = bind (newsock, (struct sockaddr *) &name, sizeof (name)); +memset(&hints, 0, sizeof(hints)); +hints.ai_flags = AI_PASSIVE; +hints.ai_family = AF_UNSPEC; +hints.ai_protocol = IPPROTO_TCP; +hints.ai_socktype = SOCK_STREAM; +if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) { + if (parse_status) + *parse_status = SCPE_ARG; + return newsock; + } +newsock = sim_create_sock (result->ai_family); /* create socket */ +if (newsock == INVALID_SOCKET) { /* socket error? */ + p_freeaddrinfo(result); + return newsock; + } +#ifdef IPV6_V6ONLY +if (result->ai_family == AF_INET6) { + int off = FALSE; + sta = setsockopt (newsock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&off, sizeof(off)); + } +#endif +sta = bind (newsock, result->ai_addr, result->ai_addrlen); +p_freeaddrinfo(result); if (sta == SOCKET_ERROR) /* bind error? */ return sim_err_sock (newsock, "bind", 1); sta = sim_setnonblock (newsock); /* set nonblocking */ @@ -166,24 +713,38 @@ if (sta == SOCKET_ERROR) /* listen error? */ return newsock; /* got it! */ } -SOCKET sim_connect_sock (int32 ip, int32 port) +SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port) { -SOCKET newsock; -struct sockaddr_in name; +SOCKET newsock = INVALID_SOCKET; int32 sta; +char host[CBUFSIZE], port[CBUFSIZE]; +t_stat r; +struct addrinfo hints; +struct addrinfo *result = NULL; -newsock = sim_create_sock (); /* create socket */ -if (newsock == INVALID_SOCKET) /* socket error? */ +r = sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port, NULL); +if (r != SCPE_OK) return newsock; -name.sin_family = AF_INET; /* name socket */ -name.sin_port = htons ((unsigned short) port); /* insert port */ -name.sin_addr.s_addr = htonl (ip); /* insert addr */ +memset(&hints, 0, sizeof(hints)); +hints.ai_family = AF_UNSPEC; +hints.ai_protocol = IPPROTO_TCP; +hints.ai_socktype = SOCK_STREAM; +if (p_getaddrinfo(host[0] ? host : NULL, port[0] ? port : NULL, &hints, &result)) + return newsock; +newsock = sim_create_sock (result->ai_family); /* create socket */ +if (newsock == INVALID_SOCKET) { /* socket error? */ + p_freeaddrinfo (result); + return newsock; + } sta = sim_setnonblock (newsock); /* set nonblocking */ -if (sta == SOCKET_ERROR) /* fcntl error? */ +if (sta == SOCKET_ERROR) { /* fcntl error? */ + p_freeaddrinfo (result); return sim_err_sock (newsock, "fcntl", 1); -sta = connect (newsock, (struct sockaddr *) &name, sizeof (name)); + } +sta = connect (newsock, result->ai_addr, result->ai_addrlen); +p_freeaddrinfo (result); if ((sta == SOCKET_ERROR) && (WSAGetLastError () != WSAEWOULDBLOCK) && (WSAGetLastError () != WSAEINPROGRESS)) @@ -192,7 +753,7 @@ if ((sta == SOCKET_ERROR) && return newsock; /* got it! */ } -SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr) +SOCKET sim_accept_conn (SOCKET master, char **connectaddr) { int32 sta, err; #if defined (macintosh) || defined (__linux) || \ @@ -206,11 +767,12 @@ int size; size_t size; #endif SOCKET newsock; -struct sockaddr_in clientname; +struct sockaddr_storage clientname; if (master == 0) /* not attached? */ return INVALID_SOCKET; size = sizeof (clientname); +memset (&clientname, 0, sizeof(clientname)); newsock = accept (master, (struct sockaddr *) &clientname, &size); if (newsock == INVALID_SOCKET) { /* error? */ err = WSAGetLastError (); @@ -218,8 +780,16 @@ if (newsock == INVALID_SOCKET) { /* error? */ printf ("Sockets: accept error %d\n", err); return INVALID_SOCKET; } -if (ipaddr != NULL) - *ipaddr = ntohl (clientname.sin_addr.s_addr); +if (connectaddr != NULL) { + *connectaddr = calloc(1, NI_MAXHOST+1); +#ifdef AF_INET6 + p_getnameinfo((struct sockaddr *)&clientname, size, *connectaddr, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if (0 == memcmp("::ffff:", *connectaddr, 7)) /* is this a IPv4-mapped IPv6 address? */ + strcpy(*connectaddr, 7+*connectaddr); /* prefer bare IPv4 address if possible */ +#else + strcpy(*connectaddr, inet_ntoa(((struct sockaddr_in *)&connectaddr)->s_addr)); +#endif + } sta = sim_setnonblock (newsock); /* set nonblocking */ if (sta == SOCKET_ERROR) /* fcntl error? */ @@ -260,7 +830,10 @@ if (rbytes == SOCKET_ERROR) { err = WSAGetLastError (); if (err == WSAEWOULDBLOCK) /* no data */ return 0; - printf ("Sockets: read error %d\n", err); + if ((err != WSAETIMEDOUT) && /* expected errors after a connect failure */ + (err != WSAEHOSTUNREACH) && + (err != WSAECONNREFUSED)) + printf ("Sockets: read error %d\n", err); return -1; } return rbytes; @@ -273,56 +846,8 @@ return send (sock, msg, nbytes, 0); void sim_close_sock (SOCKET sock, t_bool master) { -#if defined (_WIN32) +shutdown(sock, SD_BOTH); closesocket (sock); -if (master) { - sim_sock_cnt = sim_sock_cnt - 1; - if (sim_sock_cnt <= 0) { - WSACleanup (); - sim_sock_cnt = 0; - } - } -#else -close (sock); -#endif -return; } -#if defined (_WIN32) /* Windows */ -int32 sim_setnonblock (SOCKET sock) -{ -unsigned long non_block = 1; - -return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */ -} - -#elif defined (VMS) /* VMS */ -int32 sim_setnonblock (SOCKET sock) -{ -int non_block = 1; - -return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */ -} - -#else /* Mac, Unix, OS/2 */ -int32 sim_setnonblock (SOCKET sock) -{ -int32 fl, sta; - -fl = fcntl (sock, F_GETFL,0); /* get flags */ -if (fl == -1) - return SOCKET_ERROR; -sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */ -if (sta == -1) - return SOCKET_ERROR; -#if !defined (macintosh) && !defined (__EMX__) /* Unix only */ -sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */ -if (sta == -1) - return SOCKET_ERROR; -#endif -return 0; -} - -#endif /* endif !Win32 && !VMS */ - #endif /* end else !implemented */ diff --git a/sim_sock.h b/sim_sock.h index d8531cbe..039ed019 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -23,6 +23,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 15-Oct-12 MP Added definitions needed to detect possible tcp + connect failures + 25-Sep-12 MP Reworked for RFC3493 interfaces supporting IPv6 and IPv4 04-Jun-08 RMS Addes sim_create_sock, for IBM 1130 14-Apr-05 RMS Added WSAEINPROGRESS (from Tim Riker) 20-Aug-04 HV Added missing definition for OS/2 (from Holger Veit) @@ -49,16 +52,21 @@ #elif !defined (__OS2__) || defined (__EMX__) /* VMS, Mac, Unix, OS/2 EMX */ #define WSAGetLastError() errno /* Windows macros */ +#define closesocket close #define SOCKET int32 #define WSAEWOULDBLOCK EWOULDBLOCK #define WSAEINPROGRESS EINPROGRESS -#define INVALID_SOCKET -1 +#define WSAETIMEDOUT ETIMEDOUT +#define WSAECONNREFUSED ECONNREFUSED +#define WSAEHOSTUNREACH EHOSTUNREACH +#define INVALID_SOCKET ((SOCKET)-1) #define SOCKET_ERROR -1 #include /* for fcntl, getpid */ #include /* for sockets */ #include #include #include /* for sockaddr_in */ +#include /* for inet_addr and inet_ntoa */ #include #include /* for EMX */ #endif @@ -75,14 +83,15 @@ #endif #endif -SOCKET sim_master_sock (int32 port); -SOCKET sim_connect_sock (int32 ip, int32 port); -SOCKET sim_create_sock (void); -SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr); +t_stat sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr); +SOCKET sim_master_sock (const char *hostport, t_stat *parse_status); +SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port); +SOCKET sim_accept_conn (SOCKET master, char **connectaddr); int32 sim_check_conn (SOCKET sock, t_bool rd); int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes); int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes); void sim_close_sock (SOCKET sock, t_bool master); -int32 sim_setnonblock (SOCKET sock); +void sim_init_sock (void); +void sim_cleanup_sock (void); #endif diff --git a/sim_tape.c b/sim_tape.c index 2c5b946a..e8ba9192 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -521,11 +521,11 @@ if (ctx->dptr->dctrl & reason) { if ((i > 0) && (0 == memcmp (&data[i], &data[i-16], 16))) { ++same; continue; - } + } if (same > 0) { sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), i-1); same = 0; - } + } group = (((len - i) > 16) ? 16 : (len - i)); for (sidx=oidx=0; sidxdptr->dctrl & reason) { strbuf[sidx] = data[i+sidx]; else strbuf[sidx] = '.'; - } + } outbuf[oidx] = '\0'; strbuf[sidx] = '\0'; sim_debug (reason, ctx->dptr, "%04X%-48s %s\n", i, outbuf, strbuf); - } - if (same > 0) - sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), len-1); + } + if (same > 0) { + sim_debug (reason, ctx->dptr, "%04X thru %04X same as above\n", i-(16*same), len-1); + } } } } @@ -1665,8 +1666,9 @@ t_stat sim_tape_rewind (UNIT *uptr) { struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; -if (uptr->flags & UNIT_ATT) +if (uptr->flags & UNIT_ATT) { sim_debug (ctx->dbit, ctx->dptr, "sim_tape_rewind(unit=%d)\n", uptr-ctx->dptr->units); + } uptr->pos = 0; MT_CLR_PNU (uptr); return MTSE_OK; @@ -1893,10 +1895,14 @@ t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc) if (uptr->capac) { if (uptr->capac >= (t_addr) 1000000) fprintf (st, "capacity=%dMB", (uint32) (uptr->capac / ((t_addr) 1000000))); - else if (uptr->capac >= (t_addr) 1000) - fprintf (st, "capacity=%dKB", (uint32) (uptr->capac / ((t_addr) 1000))); - else fprintf (st, "capacity=%dB", (uint32) uptr->capac); + else { + if (uptr->capac >= (t_addr) 1000) + fprintf (st, "capacity=%dKB", (uint32) (uptr->capac / ((t_addr) 1000))); + else + fprintf (st, "capacity=%dB", (uint32) uptr->capac); + } } -else fprintf (st, "unlimited capacity"); +else + fprintf (st, "unlimited capacity"); return SCPE_OK; } diff --git a/sim_timer.c b/sim_timer.c index 963c090c..60446433 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -79,8 +79,10 @@ #include "sim_defs.h" #include -t_bool sim_idle_enab = FALSE; /* global flag */ -volatile t_bool sim_idle_wait = FALSE; /* global flag */ +t_bool sim_idle_enab = FALSE; /* global flag */ +volatile t_bool sim_idle_wait = FALSE; /* global flag */ + +static int32 sim_calb_tmr = -1; /* the system calibrated timer */ static uint32 sim_idle_rate_ms = 0; static uint32 sim_os_sleep_min_ms = 0; @@ -866,3 +868,97 @@ switch (sim_throt_state) { sim_activate (uptr, sim_throt_wait); /* reschedule */ return SCPE_OK; } + +/* Instruction Execution rate. */ +/* returns a double since it is mostly used in double expressions and + to avoid overflow if/when strange timing delays might produce unexpected results */ + +double sim_timer_inst_per_sec (void) +{ +double inst_per_sec = SIM_INITIAL_IPS; + +if (sim_calb_tmr == -1) + return inst_per_sec; +inst_per_sec = ((double)rtc_currd[sim_calb_tmr])*rtc_hz[sim_calb_tmr]; +if (0 == inst_per_sec) + inst_per_sec = SIM_INITIAL_IPS; +return inst_per_sec; +} + +t_stat sim_timer_activate_after (UNIT *uptr, int32 usec_delay) +{ +int32 inst_delay; +double inst_per_sec; + +AIO_VALIDATE; +if (sim_is_active (uptr)) /* already active? */ + return SCPE_OK; +inst_per_sec = sim_timer_inst_per_sec (); +inst_delay = (int32)((inst_per_sec*usec_delay)/1000000.0); +#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_CLOCKS) +if ((sim_calb_tmr == -1) || /* if No timer initialized */ + (inst_delay < rtc_currd[sim_calb_tmr]) || /* or sooner than next clock tick? */ + (rtc_elapsed[sim_calb_tmr] < sim_idle_stable) || /* or not idle stable yet */ + (!(sim_asynch_enabled && sim_asynch_timer))) { /* or asynch disabled */ + sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after() - activating %s after %d instructions\n", + sim_uname(uptr), inst_delay); + return _sim_activate (uptr, inst_delay); /* queue it now */ + } +if (1) { + struct timespec now; + double d_now; + + clock_gettime (CLOCK_REALTIME, &now); + d_now = _timespec_to_double (&now); + /* Determine if this is a clock tick like invocation + or an ocaisional measured device delay */ + if ((uptr->a_usec_delay == usec_delay) && + (uptr->a_due_time != 0.0) && + (1)) { + double d_delay = ((double)usec_delay)/1000000.0; + + uptr->a_due_time += d_delay; + if (uptr->a_due_time < (d_now + d_delay*0.1)) { /* Accumulate lost time */ + uptr->a_skew += (d_now + d_delay*0.1) - uptr->a_due_time; + uptr->a_due_time = d_now + d_delay/10.0; + if (uptr->a_skew > 30.0) { /* Gap too big? */ + uptr->a_usec_delay = usec_delay; + uptr->a_skew = uptr->a_last_fired_time = 0.0; + uptr->a_due_time = d_now + (double)(usec_delay)/1000000.0; + } + if (uptr->a_skew > rtc_clock_skew_max[sim_calb_tmr]) + rtc_clock_skew_max[sim_calb_tmr] = uptr->a_skew; + } + else { + if (uptr->a_skew > 0.0) { /* Lost time to make up? */ + if (uptr->a_skew > d_delay*0.9) { + uptr->a_skew -= d_delay*0.9; + uptr->a_due_time -= d_delay*0.9; + } + else { + uptr->a_due_time -= uptr->a_skew; + uptr->a_skew = 0.0; + } + } + } + } + else { + uptr->a_usec_delay = usec_delay; + uptr->a_skew = uptr->a_last_fired_time = 0.0; + uptr->a_due_time = d_now + (double)(usec_delay)/1000000.0; + } + uptr->time = usec_delay; + + sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after() - queue addition %s at %.6f\n", + sim_uname(uptr), uptr->a_due_time); + } +pthread_mutex_lock (&sim_timer_lock); +sim_wallclock_entry = uptr; +pthread_mutex_unlock (&sim_timer_lock); +pthread_cond_signal (&sim_timer_wake); /* wake the timer thread to deal with it */ +return SCPE_OK; +#else +return _sim_activate (uptr, inst_delay); /* queue it now */ +#endif +} + diff --git a/sim_timer.h b/sim_timer.h index f628b2fd..166a9797 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -58,25 +58,28 @@ int clock_gettime(int clock_id, struct timespec *tp); #endif -#define SIM_NTIMERS 8 /* # timers */ -#define SIM_TMAX 500 /* max timer makeup */ +#define SIM_NTIMERS 8 /* # timers */ +#define SIM_TMAX 500 /* max timer makeup */ -#define SIM_IDLE_CAL 10 /* ms to calibrate */ -#define SIM_IDLE_MAX 10 /* max granularity idle */ -#define SIM_IDLE_STMIN 10 /* min sec for stability */ -#define SIM_IDLE_STDFLT 20 /* dft sec for stability */ -#define SIM_IDLE_STMAX 600 /* max sec for stability */ +#define SIM_INITIAL_IPS 50000 /* uncalibrated assumption */ + /* about instructions per second */ -#define SIM_THROT_WINIT 1000 /* cycles to skip */ -#define SIM_THROT_WST 10000 /* initial wait */ -#define SIM_THROT_WMUL 4 /* multiplier */ -#define SIM_THROT_WMIN 100 /* min wait */ -#define SIM_THROT_MSMIN 10 /* min for measurement */ -#define SIM_THROT_NONE 0 /* throttle parameters */ -#define SIM_THROT_MCYC 1 /* MegaCycles Per Sec */ -#define SIM_THROT_KCYC 2 /* KiloCycles Per Sec */ -#define SIM_THROT_PCT 3 /* Max Percent of host CPU */ -#define SIM_THROT_SPC 4 /* Specific periodic Delay */ +#define SIM_IDLE_CAL 10 /* ms to calibrate */ +#define SIM_IDLE_MAX 10 /* max granularity idle */ +#define SIM_IDLE_STMIN 10 /* min sec for stability */ +#define SIM_IDLE_STDFLT 20 /* dft sec for stability */ +#define SIM_IDLE_STMAX 600 /* max sec for stability */ + +#define SIM_THROT_WINIT 1000 /* cycles to skip */ +#define SIM_THROT_WST 10000 /* initial wait */ +#define SIM_THROT_WMUL 4 /* multiplier */ +#define SIM_THROT_WMIN 100 /* min wait */ +#define SIM_THROT_MSMIN 10 /* min for measurement */ +#define SIM_THROT_NONE 0 /* throttle parameters */ +#define SIM_THROT_MCYC 1 /* MegaCycles Per Sec */ +#define SIM_THROT_KCYC 2 /* KiloCycles Per Sec */ +#define SIM_THROT_PCT 3 /* Max Percent of host CPU */ +#define SIM_THROT_SPC 4 /* Specific periodic Delay */ t_bool sim_timer_init (void); void sim_timespec_diff (struct timespec *diff, struct timespec *min, struct timespec *sub); @@ -97,5 +100,7 @@ uint32 sim_os_msec (void); void sim_os_sleep (unsigned int sec); uint32 sim_os_ms_sleep (unsigned int msec); uint32 sim_os_ms_sleep_init (void); +t_stat sim_timer_activate_after (UNIT *uptr, int32 usec_delay); +double sim_timer_inst_per_sec (void); #endif diff --git a/sim_tmxr.c b/sim_tmxr.c index 4cb866de..f19d7950 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -26,11 +26,17 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 12-Oct-12 MP Revised serial port support to not require changes to + any code in TMXR library using code. Added support + for per line listener ports and outgoing tcp connections. 02-Jun-11 MP Fixed telnet option negotiation loop with some clients Added Option Negotiation and Debugging Support 17-Jan-11 MP Added Buffered line capabilities 16-Jan-11 MP Made option negotiation more reliable 20-Nov-08 RMS Added three new standardized SHOW routines + 05-Nov-08 JDB Moved logging call after connection check in tmxr_putc_ln + 03-Nov-08 JDB Added TMXR null check to tmxr_find_ldsc + 07-Oct-08 JDB Added initial serial port support 30-Sep-08 JDB Reverted tmxr_find_ldsc to original implementation 27-May-08 JDB Added line connection order to tmxr_poll_conn, added tmxr_set_lnorder and tmxr_show_lnorder @@ -57,36 +63,244 @@ This library includes: - tmxr_poll_conn - poll for connection - tmxr_reset_ln - reset line - tmxr_getc_ln - get character for line - tmxr_poll_rx - poll receive - tmxr_putc_ln - put character for line - tmxr_poll_tx - poll transmit - tmxr_open_master - open master connection - tmxr_close_master - close master connection - tmxr_attach - attach terminal multiplexor - tmxr_detach - detach terminal multiplexor - tmxr_ex - (null) examine - tmxr_dep - (null) deposit - tmxr_msg - send message to socket - tmxr_linemsg - send message to line - tmxr_fconns - output connection status - tmxr_fstats - output connection statistics - tmxr_dscln - disconnect line (SET routine) - tmxr_rqln - number of available characters for line - tmxr_tqln - number of buffered characters for line - tmxr_set_lnorder - set line connection order - tmxr_show_lnorder - show line connection order + tmxr_poll_conn - poll for connection + tmxr_reset_ln - reset line (drops Telnet/tcp and serial connections) + tmxr_getc_ln - get character for line + tmxr_poll_rx - poll receive + tmxr_putc_ln - put character for line + tmxr_poll_tx - poll transmit + tmxr_send_buffered_data - transmit buffered data + tmxr_set_modem_control_passthru - enable modem control on a multiplexer + tmxr_clear_modem_control_passthru - disable modem control on a multiplexer + tmxr_set_get_modem_bits - set and/or get a line modem bits + tmxr_set_config_line - set port speed, character size, parity and stop bits + tmxr_open_master - open master connection + tmxr_close_master - close master connection + tmxr_attach - attach terminal multiplexor to listening port + tmxr_detach - detach terminal multiplexor to listening port + tmxr_set_line_unit - set the unit which polls for input for a given line + tmxr_ex - (null) examine + tmxr_dep - (null) deposit + tmxr_msg - send message to socket + tmxr_linemsg - send message to line + tmxr_fconns - output connection status + tmxr_fstats - output connection statistics + tmxr_set_log - enable logging for line + tmxr_set_nolog - disable logging for line + tmxr_show_log - show logging status for line + tmxr_dscln - disconnect line (SET routine) + tmxr_rqln - number of available characters for line + tmxr_tqln - number of buffered characters for line + tmxr_set_lnorder - set line connection order + tmxr_show_lnorder - show line connection order + tmxr_show_summ - show connection summary + tmxr_show_cstat - show line connections or status + tmxr_show_lines - show number of lines + tmxr_show_open_devices - show info about all open tmxr devices All routines are OS-independent. + + + This library supports the simulation of multiple-line terminal multiplexers. + It may also be used to create single-line "multiplexers" to provide + additional terminals beyond the simulation console. It may also be used to + create single-line or mutlti-line simulated synchronous (BiSync) devices. + Multiplexer lines may be connected to terminal emulators supporting the + Telnet protocol via sockets, or to hardware terminals via host serial + ports. Concurrent Telnet and serial connections may be mixed on a given + multiplexer. + + When connecting via sockets, the simulated multiplexer is attached to a + listening port on the host system: + + sim> attach MUX 23 + Listening on port 23 + + Once attached, the listening port must be polled for incoming connections. + When a connection attempt is received, it will be associated with the next + multiplexer line in the user-specified line order, or with the next line in + sequence if no order has been specified. Individual lines may be connected + to serial ports or remote systems via TCP (telnet or not as desired), OR + they may have separate listening TCP ports. + + Logging of Multiplexer Line output: + + The traffic going out multiplexer lines can be logged to files. A single + line multiplexer can log it's traffic with the following command: + + sim> atta MUX 23,Log=LogFileName + sim> atta MUX Connect=ser0,Log=LogFileName + + + A Multi-Line multiplexer + + Buffered Multiplexer Line: + + + Serial Port support: + + Serial ports may be specified as an operating system specific device names + or using simh generic serial names. simh generic names are of the form + serN, where N is from 0 thru one less than the maximum number of serial + ports on the local system. The mapping of simh generic port names to OS + specific names can be displayed using the following command: + + sim> show serial + Serial devices: + ser0 COM1 (\Device\Serial0) + ser1 COM3 (Winachcf0) + + sim> attach MUX Line=2,Connect=ser0 + + or equivalently + + sim> attach MUX Line=2,Connect=COM1 + + An optional configuration string may be present after the port name. If + present, it must be separated from the port name with a semicolon and has + this form: + + - + + where: + + rate = communication rate in bits per second + charsize = character size in bits (5-8, including optional parity) + parity = parity designator (N/E/O/M/S for no/even/odd/mark/space parity) + stopbits = number of stop bits (1, 1.5, or 2) + + As an example: + + 9600-8n1 + + The supported rates, sizes, and parity options are host-specific. If + a configuration string is not supplied, then the default of 9600-8N1 + is used. + + An attachment to a serial port with the '-V' switch will cause a + connection message to be output to the connected serial port. + This will help to confirm the correct port has been connected and + that the port settings are reasonable for the connected device. + This would be done as: + + sim> attach -V MUX Connect=SerN + + + Virtual Null Modem (direct wire) support: + + Direct computer to computer virtual connections may be established using + the telnet protocol or via raw tcp sockets. + + sim> attach MUX Line=2,Connect=host:port{;notelnet} + + Optional Per line tcp listening port support: + + Line specific tcp listening ports are supported. These are configured + using commands of the form: + + sim> attach MUX Line=2,port{;notelnet} + + The command syntax for a single line device (MX) is: + + sim> attach MX port{;notelnet} + sim> attach MX Connect=serN{;config} + sim> attach MX Connect=COM9{;config} + sim> attach MX Connect=host:port{;notelnet} + + The command syntax for ANY multi-line device is: + + sim> attach MX port{;notelnet} ; Defines the master listening port for the mux and optionally allows non-telnet (i.e. raw socket) operation for all lines. + sim> attach MX Line=n,port{;notelnet} ; Defines a line specific listen port for a particular line. Each line can have a separate listen port and the mux can have its own as well. Optionally disable telnet wire protocol (i.e. raw socket) + sim> attach MX Line=n,Connect=serN{;config} ; Connects line n to simh generic serial port N (port list visible with the sim> SHOW SERIAL command), the optional ";config" data specifies the speed, parity and stop bits for the connection + ; DTR (and RTS) will be raised at attach time and will drop at detach/disconnect time + sim> attach MX Line=n,Connect=host:port{;notelnet} ; Causes a connection to be established to the designated host:port. The actual connection will happen in a non-blocking fashion and will be completed and/or re-established by the normal tmxr_poll_conn activities + + All connections configured for any multiplexer device are unconfigured by: + + sim> detach MX ; detaches ALL connections/ports/sessions on the MUX. + + Console serial connections are achieved by: + + sim> set console serial=serN{;config} + or + sim> set console serial=COM2{;config} + + A line specific listening port (12366) can be specified by the following: + + sim> attach MUX Line=2,12366 + + A line specific remote telnet (or raw tcp) destination can be specified + by the following: + + sim> attach MUX Line=2,Connect=remotehost:port + + If a connection to a remotehost:port wants a raw binary data channel + (instead of a telnet session) the following would be used: + + sim> attach MUX Line=2,Connect=remotehost:port;notelnet + + A single line multiplexor can indicate any of the above line options + without specifying a line number: + + sim> attach MUX Connect=ser0;9600-8N1 + sim> attach MUX 12366 + sim> attach MUX Connect=remotehost:port + sim> attach MUX Connect=remotehost:port;notelnet + + A multiplexor can disconnect all (telnet, serial and outgoing) previous + attachments with: + + sim> detach MUX + + A device emulation may choose to implement a command interface to + disconnect specific individual lines. This would usually be done via + a Unit Modifier table entry (MTAB) which dispatches the command + "SET dev DISCONNECT[=line]" to tmxr_dscln. This will cause a telnet + connection to be closed, but a serial port will normally have DTR + dropped for 500ms and raised again (thus hanging up a modem on that + serial port). + + sim> set MUX disconnect=2 + + A line which is connected to a serial port can be manually closed by + adding the -C switch to a disconnect command. + + sim> set -C MUX disconnect=2 + + Full Modem Control serial port support. + + This library supports devices which wish to emulate full modem + control/signalling for serial ports. Any device emulation which wishes + to support this functionality for attached serial ports must call + "tmxr_set_modem_control_passthru" before any call to tmxr_attach. + This disables automatic DTR (&RTS) manipulation by this library. + Responsibility for manipulating DTR falls on the simulated operating + system. Calling tmxr_set_modem_control_passthru would usually be in + a device reset routine. + Once support for full modem control has been declared by a device + emulation for a particular TMXR device, the this library will make no + direct effort to manipulate modem bits while connected to serial ports. + The "tmxr_set_get_modem_bits" API exists to allow the device emulation + layer to query and control modem signals. The "tmxr_set_config_line" + API exists to allow the device emulation layer to change port settings + (baud rate, parity and stop bits). A modem_control enabled line + merely passes the VM's port status bits, data and settings through to + and from the serial port. + + The "tmxr_set_get_modem_bits" and "tmxr_set_config_line" APIs will + ONLY work on a modem control enabled TMXR device. + */ + +#include + #include "sim_defs.h" +#include "sim_serial.h" #include "sim_sock.h" +#include "sim_timer.h" #include "sim_tmxr.h" #include "scp.h" -#include /* Telnet protocol constants - negatives are for init'ing signed char data */ @@ -129,14 +343,346 @@ #define TNS_DO 006 /* DO request pending rejection */ -void tmxr_rmvrc (TMLN *lp, int32 p); -int32 tmxr_send_buffered_data (TMLN *lp); -TMLN *tmxr_find_ldsc (UNIT *uptr, int32 val, TMXR *mp); + +/* External variables */ extern int32 sim_switches; extern char sim_name[]; extern FILE *sim_log; -extern uint32 sim_os_msec (void); + + + +/* Local routines */ + + +/* Initialize the line state. + + Reset the line state to represent an idle line. Note that we do not clear + all of the line structure members, so a connected line remains connected + after this call. + + Because a line break is represented by a flag in the "receive break status" + array, we must zero that array in order to clear any pending break + indications. +*/ + +static void tmxr_init_line (TMLN *lp) +{ +lp->tsta = 0; /* init telnet state */ +lp->xmte = 1; /* enable transmit */ +lp->dstb = 0; /* default bin mode */ +lp->rxbpr = lp->rxbpi = lp->rxcnt = 0; /* init receive indexes */ +if (!lp->txbfd) /* if not buffered */ + lp->txbpr = lp->txbpi = lp->txcnt = 0; /* init transmit indexes */ +memset (lp->rbr, 0, TMXR_MAXBUF); /* clear break status array */ +lp->txdrp = 0; +if (!lp->mp->buffered) { + lp->txbfd = 0; + lp->txbsz = TMXR_MAXBUF; + lp->txb = (char *)realloc (lp->txb, lp->txbsz); + } +return; +} + + +/* Report a connection to a line. + + If the indicated line (lp) is speaking the telnet wire protocol, a + notification of the form: + + Connected to the simulator device, line + + is sent to the newly connected line. If the device has only one line, the + "line " part is omitted. If the device has not been defined, the " + device" part is omitted. + +*/ + +static void tmxr_report_connection (TMXR *mp, TMLN *lp) +{ +int32 unwritten, psave; +char cmsg[80]; +char dmsg[80] = ""; +char lmsg[80] = ""; +char msgbuf[256] = ""; + +if ((!lp->notelnet) || (sim_switches & SWMASK ('V'))) { + sprintf (cmsg, "\n\r\nConnected to the %s simulator ", sim_name); + + if (mp->dptr) { /* device defined? */ + sprintf (dmsg, "%s device", /* report device name */ + sim_dname (mp->dptr)); + + if (mp->lines > 1) /* more than one line? */ + sprintf (lmsg, ", line %d", (int)(lp-mp->ldsc));/* report the line number */ + } + + sprintf (msgbuf, "%s%s%s\r\n\n", cmsg, dmsg, lmsg); + } + +if (!mp->buffered) { + lp->txbpi = 0; /* init buf pointers */ + lp->txbpr = (int32)(lp->txbsz - strlen (msgbuf)); + lp->rxcnt = lp->txcnt = lp->txdrp = 0; /* init counters */ + } +else + if (lp->txcnt > lp->txbsz) + lp->txbpr = (lp->txbpi + 1) % lp->txbsz; + else + lp->txbpr = (int32)(lp->txbsz - strlen (msgbuf)); + +psave = lp->txbpi; /* save insertion pointer */ +lp->txbpi = lp->txbpr; /* insert connection message */ +tmxr_linemsg (lp, msgbuf); /* beginning of buffer */ +lp->txbpi = psave; /* restore insertion pointer */ + +unwritten = tmxr_send_buffered_data (lp); /* send the message */ + +if (unwritten == 0) /* buffer now empty? */ + lp->xmte = 1; /* reenable transmission if paused */ + +lp->txcnt -= (int32)strlen (msgbuf); /* adjust statistics */ +return; +} + + +/* Report a disconnection to a line. + + A notification of the form: + + Disconnected from the simulator + + is sent to the line about to be disconnected. We do not flush the buffer + here, because the disconnect routines will do that just after calling us. +*/ + +static void tmxr_report_disconnection (TMLN *lp) +{ +if (lp->notelnet) + return; +tmxr_linemsg (lp, "\r\nDisconnected from the "); /* report disconnection */ +tmxr_linemsg (lp, sim_name); +tmxr_linemsg (lp, " simulator\r\n\n"); +return; +} + + +/* Read from a line. + + Up to "length" characters are read into the character buffer associated with + line "lp". The actual number of characters read is returned. If no + characters are available, 0 is returned. If an error occurred while reading, + -1 is returned. + + If a line break was detected on serial input, the associated receive break + status flag will be set. Line break indication for Telnet connections is + embedded in the Telnet protocol and must be determined externally. +*/ + +static int32 tmxr_read (TMLN *lp, int32 length) +{ +int32 i = lp->rxbpi; + +if (lp->serport) /* serial port connection? */ + return sim_read_serial (lp->serport, &(lp->rxb[i]), length, &(lp->rbr[i])); +else /* Telnet connection */ + return sim_read_sock (lp->conn, &(lp->rxb[i]), length); +} + + +/* Write to a line. + + Up to "length" characters are written from the character buffer associated + with "lp". The actual number of characters written is returned. If an error + occurred while writing, -1 is returned. +*/ + +static int32 tmxr_write (TMLN *lp, int32 length) +{ +int32 written; +int32 i = lp->txbpr; + +if (lp->serport) /* serial port connection? */ + return sim_write_serial (lp->serport, &(lp->txb[i]), length); + +else { /* Telnet connection */ + written = sim_write_sock (lp->conn, &(lp->txb[i]), length); + + if (written == SOCKET_ERROR) /* did an error occur? */ + return -1; /* return error indication */ + else + return written; + } +} + + +/* Remove a character from the read buffer. + + The character at position "p" in the read buffer associated with line "lp" is + removed by moving all of the following received characters down one position. + The receive break status array is adjusted accordingly. +*/ + +static void tmxr_rmvrc (TMLN *lp, int32 p) +{ +for ( ; p < lp->rxbpi; p++) { /* work from "p" through end of buffer */ + lp->rxb[p] = lp->rxb[p + 1]; /* slide following character down */ + lp->rbr[p] = lp->rbr[p + 1]; /* adjust break status too */ + } + +lp->rbr[p] = 0; /* clear potential break from vacated slot */ +lp->rxbpi = lp->rxbpi - 1; /* drop buffer insert index */ +return; +} + + +/* Find a line descriptor indicated by unit or number. + + If "uptr" is NULL, then the line descriptor is determined by the line number + passed in "val". If "uptr" is not NULL, then it must point to a unit + associated with a line, and the line descriptor is determined by the unit + number, which is derived by the position of the unit in the device's unit + array. + + Note: This routine may be called with a UNIT that does not belong to the + device indicated in the TMXR structure. That is, the multiplexer lines may + belong to a device other than the one attached to the socket (the HP 2100 MUX + device is one example). Therefore, we must look up the device from the unit + at each call, rather than depending on the DEVICE pointer stored in the TMXR. +*/ + +static TMLN *tmxr_find_ldsc (UNIT *uptr, int32 val, TMXR *mp) +{ +if (mp == NULL) /* invalid multiplexer descriptor? */ + return NULL; /* programming error! */ +if (uptr) { /* called from SET? */ + DEVICE *dptr = find_dev_from_unit (uptr); /* find device */ + if (dptr == NULL) /* what?? */ + return NULL; + val = (int32) (uptr - dptr->units); /* implicit line # */ + } +if ((val < 0) || (val >= mp->lines)) /* invalid line? */ + return NULL; +return mp->ldsc + val; /* line descriptor */ +} + + +/* Get a line descriptor indicated by a string or unit. + + A pointer to the line descriptor associated with multiplexer "mp" and unit + "uptr" or specified by string "cptr" is returned. If "uptr" is non-null, + then the unit number within its associated device implies the line number. + If "uptr" is null, then the string "cptr" is parsed for a decimal line + number. If the line number is missing, malformed, or outside of the range of + line numbers associated with "mp", then NULL is returned with status set to + SCPE_ARG. + + Implementation note: + + 1. A return status of SCPE_IERR implies a programming error (passing an + invalid pointer or an invalid unit). +*/ + +static TMLN *tmxr_get_ldsc (UNIT *uptr, char *cptr, TMXR *mp, t_stat *status) +{ +t_value ln; +TMLN *lp = NULL; +t_stat code = SCPE_OK; + +if (mp == NULL) /* missing mux descriptor? */ + code = SCPE_IERR; /* programming error! */ + +else if (uptr) { /* implied line form? */ + lp = tmxr_find_ldsc (uptr, mp->lines, mp); /* determine line from unit */ + + if (lp == NULL) /* invalid line number? */ + code = SCPE_IERR; /* programming error! */ + } + +else if (cptr == NULL) /* named line form, parameter supplied? */ + code = SCPE_ARG; /* no, so report missing */ + +else { + ln = get_uint (cptr, 10, mp->lines - 1, &code); /* get line number */ + + if (code == SCPE_OK) /* line number OK? */ + lp = mp->ldsc + (int32) ln; /* use as index to determine line */ + } + +if (status) /* return value pointer supplied? */ + *status = code; /* store return status value */ + +return lp; /* return pointer to line descriptor */ +} + +/* Generate the Attach string which will fully configure the multiplexer + + Inputs: + old = pointer to the original configuration string which will be replaced + *mp = pointer to multiplexer + + Output: + a complete attach string for the current state of the multiplexer + +*/ +static char *growstring(char **string, size_t growth) +{ +*string = (char *)realloc (*string, 1 + (*string ? strlen (*string) : 0) + growth); +return *string + strlen(*string); +} + +static char *_mux_attach_string(char *old, TMXR *mp) +{ +char* tptr = NULL; +int32 i; +TMLN *lp; + +free (old); +tptr = (char *) calloc (1, 1); + +if (tptr == NULL) /* no more mem? */ + return tptr; + +if (mp->port) /* copy port */ + sprintf (growstring(&tptr, 13 + strlen (mp->port)), "%s%s", mp->port, mp->notelnet ? ";notelnet" : ""); +if (mp->buffered) + sprintf (growstring(&tptr, 32), ",Buffered=%d", mp->buffered); +if (mp->logfiletmpl[0]) /* logfile info */ + sprintf (growstring(&tptr, 7 + strlen (mp->logfiletmpl)), ",Log=%s", mp->logfiletmpl); +while ((*tptr == ',') || (*tptr == ' ')) + strcpy(tptr, tptr+1); +for (i=0; ilines; ++i) { + lp = mp->ldsc + i; + if (lp->destination || lp->port) { + if (mp->lines > 1) + sprintf (growstring(&tptr, 32), "%sLine=%d", *tptr ? ",," : "", i); + else + sprintf (growstring(&tptr, 32), "%s", *tptr ? "," : ""); + if (lp->destination) { + if (lp->serport) { + char portname[CBUFSIZE]; + + get_glyph_nc (lp->destination, portname, ';'); + sprintf (growstring(&tptr, 25 + strlen (lp->destination)), ",Connect=%s%s%s", portname, strcmp("9600-8N1", lp->serconfig) ? ";" : "", strcmp("9600-8N1", lp->serconfig) ? lp->serconfig : ""); + } + else + sprintf (growstring(&tptr, 18 + strlen (lp->destination)), ",Connect=%s%s", lp->destination, lp->notelnet ? ";notelnet" : ""); + } + if (lp->port) + sprintf (growstring(&tptr, 12 + strlen (lp->port)), ",%s%s", lp->port, lp->notelnet ? ";notelnet" : ""); + } + } +if (*tptr == '\0') { + free (tptr); + tptr = NULL; + } +return tptr; +} + + + +/* Global routines */ + /* Poll for new connection @@ -150,6 +696,7 @@ extern uint32 sim_os_msec (void); If a connection order is defined for the descriptor, and the first value is not -1 (indicating default order), then the order array is used to find an open line. Otherwise, a search is made of all lines in numerical sequence. + */ int32 tmxr_poll_conn (TMXR *mp) @@ -157,12 +704,10 @@ int32 tmxr_poll_conn (TMXR *mp) SOCKET newsock; TMLN *lp; int32 *op; -int32 i, j, psave; -uint32 ipaddr; -char cmsg[80]; -char dmsg[80] = ""; -char lmsg[80] = ""; -char msgbuf[256]; +int32 i, j; +char *address; +char msg[512]; +uint32 poll_time = sim_os_msec (); static char mantra[] = { TN_IAC, TN_WILL, TN_LINE, TN_IAC, TN_WILL, TN_SGA, @@ -171,93 +716,356 @@ static char mantra[] = { TN_IAC, TN_DO, TN_BIN }; -newsock = sim_accept_conn (mp->master, &ipaddr); /* poll connect */ -if (newsock != INVALID_SOCKET) { /* got a live one? */ - op = mp->lnorder; /* get line connection order list pointer */ - i = mp->lines; /* play it safe in case lines == 0 */ +if ((poll_time - mp->last_poll_time) < TMXR_CONNECT_POLL_INTERVAL) + return -1; /* */ - for (j = 0; j < mp->lines; j++, i++) { /* find next avail line */ - if (op && (*op >= 0) && (*op < mp->lines)) /* order list present and valid? */ - i = *op++; /* get next line in list to try */ - else /* no list or not used or range error */ - i = j; /* get next sequential line */ +tmxr_debug_trace (mp, "tmxr_poll_conn()"); - lp = mp->ldsc + i; /* get pointer to line descriptor */ - if (lp->conn == 0) /* is the line available? */ - break; /* yes, so stop search */ - } +mp->last_poll_time = poll_time; - if (i >= mp->lines) { /* all busy? */ - tmxr_msg (newsock, "All connections busy\r\n"); - sim_close_sock (newsock, 0); - } - else { - lp = mp->ldsc + i; /* get line desc */ - lp->conn = newsock; /* record connection */ - lp->ipad = ipaddr; /* ip address */ - lp->mp = mp; /* save mux */ - sim_write_sock (newsock, mantra, sizeof(mantra)); - tmxr_debug (TMXR_DBG_XMT, lp, "Sending", mantra, sizeof(mantra)); - sprintf (cmsg, "\n\r\nConnected to the %s simulator ", sim_name); +/* Check for a pending Telnet connection */ - if (mp->dptr) { /* device defined? */ - sprintf (dmsg, "%s device", /* report device name */ - sim_dname (mp->dptr)); +if (mp->master) { + newsock = sim_accept_conn (mp->master, &address); /* poll connect */ - if (mp->lines > 1) /* more than one line? */ - sprintf (lmsg, ", line %d", i); /* report the line number */ + if (newsock != INVALID_SOCKET) { /* got a live one? */ + sprintf (msg, "tmxr_poll_conn() - Connection from %s", address); + tmxr_debug_trace (mp, msg); + op = mp->lnorder; /* get line connection order list pointer */ + i = mp->lines; /* play it safe in case lines == 0 */ + ++mp->sessions; /* count the new session */ + + for (j = 0; j < mp->lines; j++, i++) { /* find next avail line */ + if (op && (*op >= 0) && (*op < mp->lines)) /* order list present and valid? */ + i = *op++; /* get next line in list to try */ + else /* no list or not used or range error */ + i = j; /* get next sequential line */ + + lp = mp->ldsc + i; /* get pointer to line descriptor */ + if ((lp->conn == 0) && /* is the line available? */ + (lp->destination == NULL) && + (lp->master == 0)) + break; /* yes, so stop search */ } - sprintf (msgbuf, "%s%s%s\r\n\n", cmsg, dmsg, lmsg); - lp->cnms = sim_os_msec (); /* time of conn */ - if (!mp->buffered) { - lp->txbpi = 0; /* init buf pointers */ - lp->txbpr = (int32)(lp->txbsz - strlen (msgbuf)); - lp->rxcnt = lp->txcnt = lp->txdrp = 0; /* init counters */ + if (i >= mp->lines) { /* all busy? */ + tmxr_msg (newsock, "All connections busy\r\n"); + tmxr_debug_trace (mp, "tmxr_poll_conn() - All connections busy"); + sim_close_sock (newsock, 0); + free (address); } - else - if (lp->txcnt > lp->txbsz) - lp->txbpr = (lp->txbpi + 1) % lp->txbsz; - else - lp->txbpr = (int32)(lp->txbsz - strlen (msgbuf)); - lp->tsta = 0; /* init telnet state */ - lp->xmte = 1; /* enable transmit */ - lp->dstb = 0; /* default bin mode */ - psave = lp->txbpi; /* save insertion pointer */ - lp->txbpi = lp->txbpr; /* insert connection message */ - tmxr_linemsg (lp, msgbuf); /* beginning of buffer */ - lp->txbpi = psave; /* restore insertion pointer */ - tmxr_poll_tx (mp); /* flush output */ - lp->txcnt -= (int32)strlen (msgbuf); /* adjust statistics */ + else { + lp = mp->ldsc + i; /* get line desc */ + tmxr_init_line (lp); /* init line */ + lp->conn = newsock; /* record connection */ + lp->ipad = address; /* ip address */ + lp->notelnet = mp->notelnet; /* apply mux default telnet setting */ + if (!lp->notelnet) { + sim_write_sock (newsock, mantra, sizeof(mantra)); + tmxr_debug (TMXR_DBG_XMT, lp, "Sending", mantra, sizeof(mantra)); + } + tmxr_report_connection (mp, lp); + lp->cnms = sim_os_msec (); /* time of conn */ + return i; + } + } /* end if newsock */ + } + +/* Look for per line listeners or outbound connecting sockets */ +for (i = 0; i < mp->lines; i++) { /* check each line in sequence */ + lp = mp->ldsc + i; /* get pointer to line descriptor */ + + if (lp->connecting) { /* connecting? */ + switch (sim_check_conn(lp->connecting, FALSE)) + { + case 1: /* successful connection */ + lp->conn = lp->connecting; /* it now looks normal */ + lp->connecting = 0; + lp->cnms = sim_os_msec (); + break; + case -1: /* failed connection */ + tmxr_reset_ln (lp); /* retry */ + break; + } + } + + /* Check for a pending Telnet connection */ + + if (lp->master) { + + newsock = sim_accept_conn (lp->master, &address);/* poll connect */ + + if (newsock != INVALID_SOCKET) { /* got a live one? */ + sprintf (msg, "tmxr_poll_conn() - Line Connection from %s", address); + tmxr_debug_trace_line (lp, msg); + ++mp->sessions; /* count the new session */ + + if (lp->destination) { /* Virtual Null Modem Cable? */ + char host[CBUFSIZE]; + + if (sim_parse_addr (lp->destination, host, sizeof(host), NULL, NULL, 0, NULL, address)) { + tmxr_msg (newsock, "Rejecting connection from unexpected source\r\n"); + sprintf (msg, "tmxr_poll_conn() - Rejecting line connection from: %s, Expected: %s", address, host); + tmxr_debug_trace_line (lp, msg); + sim_close_sock (newsock, 0); + free (address); + continue; /* Move on to next line */ + } + if (lp->connecting) { + sim_close_sock (lp->connecting, 0); /* abort our as yet unconnnected socket */ + lp->connecting = 0; + } + } + if (lp->conn == 0) { /* is the line available? */ + tmxr_init_line (lp); /* init line */ + lp->conn = newsock; /* record connection */ + lp->ipad = address; /* ip address */ + if (!lp->notelnet) { + sim_write_sock (newsock, mantra, sizeof(mantra)); + tmxr_debug (TMXR_DBG_XMT, lp, "Sending", mantra, sizeof(mantra)); + } + tmxr_report_connection (mp, lp); + lp->cnms = sim_os_msec (); /* time of conn */ + return i; + } + else { + tmxr_msg (newsock, "Line connection busy\r\n"); + tmxr_debug_trace_line (lp, "tmxr_poll_conn() - Line connection busy"); + sim_close_sock (newsock, 0); + free (address); + } + } + } + + /* Check for pending serial port connection notification */ + + if (lp->ser_connect_pending) { + lp->ser_connect_pending = FALSE; return i; } - } /* end if newsock */ -return -1; + } + +return -1; /* no new connections made */ } -/* Reset line */ +/* Reset a line. -void tmxr_reset_ln (TMLN *lp) + The telnet/tcp or serial session associated with multiplexer descriptor "mp" and + line descriptor "lp" is disconnected. An associated tcp socket is + closed; a serial port is closed if the closeserial parameter is true, otherwise + for non modem control serial lines DTR is dropped and raised again after 500ms + to signal the attached serial device. +*/ + +static t_stat tmxr_reset_ln_ex (TMLN *lp, t_bool closeserial) { -if (lp->txlog) /* dump log */ - fflush (lp->txlog); -tmxr_send_buffered_data (lp); /* send buffered data */ -sim_close_sock (lp->conn, 0); /* reset conn */ -lp->conn = lp->tsta = 0; /* reset state */ -lp->rxbpr = lp->rxbpi = 0; -if (!lp->txbfd) - lp->txbpr = lp->txbpi = 0; -lp->xmte = 1; -lp->dstb = 0; -return; +if (lp->txlog) /* logging? */ + fflush (lp->txlog); /* flush log */ + +tmxr_send_buffered_data (lp); /* send any buffered data */ + +if (lp->serport) { + if (closeserial) { + sim_close_serial (lp->serport); + lp->serport = 0; + lp->ser_connect_pending = FALSE; + free (lp->destination); + lp->destination = NULL; + free (lp->serconfig); + lp->serconfig = NULL; + lp->cnms = 0; + lp->rcve = lp->xmte = 0; + } + else + if (!lp->mp->modem_control) { /* serial connection? */ + sim_control_serial (lp->serport, 0, TMXR_MDM_DTR|TMXR_MDM_RTS, NULL);/* drop DTR and RTS */ + sim_os_ms_sleep (TMXR_DTR_DROP_TIME); + sim_control_serial (lp->serport, TMXR_MDM_DTR|TMXR_MDM_RTS, 0, NULL);/* raise DTR and RTS */ + } + } +else /* Telnet connection */ + if (lp->conn) { + sim_close_sock (lp->conn, 0); /* close socket */ + lp->conn = 0; + lp->rcve = lp->xmte = 0; + } +free(lp->ipad); +lp->ipad = NULL; +if ((lp->destination) && (!lp->serport)) { + if (lp->connecting) + sim_close_sock (lp->connecting, 0); + lp->connecting = sim_connect_sock (lp->destination, "localhost", NULL); + lp->ipad = malloc (1 + strlen (lp->destination)); + strcpy (lp->ipad, lp->destination); + lp->cnms = sim_os_msec (); + } +else { + tmxr_init_line (lp); /* initialize line state */ + lp->conn = 0; /* remove socket or connection flag */ + } +/* Revise the unit's connect string to reflect the current attachments */ +lp->mp->uptr->filename = _mux_attach_string (lp->mp->uptr->filename, lp->mp); +/* No connections or listeners exist, then we're equivalent to being fully detached. We should reflect that */ +if (lp->mp->uptr->filename == NULL) + tmxr_detach (lp->mp, lp->mp->uptr); +return SCPE_OK; } +t_stat tmxr_close_ln (TMLN *lp) +{ +tmxr_debug_trace_line (lp, "tmxr_close_ln()"); +return tmxr_reset_ln_ex (lp, TRUE); +} + +t_stat tmxr_reset_ln (TMLN *lp) +{ +tmxr_debug_trace_line (lp, "tmxr_reset_ln()"); +return tmxr_reset_ln_ex (lp, FALSE); +} + +/* Enable modem control pass thru + + Inputs: + none + + Output: + none + + Implementation note: + + 1 Calling this API disables any actions on the part of this + library to directly manipulate DTR (&RTS) on serial ports. + + 2 Calling this API enables the tmxr_set_get_modem_bits and + tmxr_set_config_line APIs. + +*/ +t_stat tmxr_set_modem_control_passthru (TMXR *mp) +{ +mp->modem_control = TRUE; +return SCPE_OK; +} + +/* Disable modem control pass thru + + Inputs: + none + + Output: + none + + Implementation note: + + 1 Calling this API enables this library's direct manipulation + of DTR (&RTS) on serial ports. + + 2 Calling this API disables the tmxr_set_get_modem_bits and + tmxr_set_config_line APIs. + + 3 This API will only change the state of the modem control processing + of this library if there are no listening ports, serial ports or + outgoing connecctions associated with the specified multiplexer + +*/ +t_stat tmxr_clear_modem_control_passthru (TMXR *mp) +{ +int i; + +if (!mp->modem_control) + return SCPE_OK; +if (mp->master) + return SCPE_ALATT; +for (i=0; ilines; ++i) { + TMLN *lp; + + lp = mp->ldsc + i; + if ((lp->master) || + (lp->conn) || + (lp->connecting) || + (lp->serport)) + return SCPE_ALATT; + } +mp->modem_control = FALSE; +return SCPE_OK; +} + +/* Manipulate the modem control bits of a specific line + + Inputs: + *lp = pointer to terminal line descriptor + bits_to_set TMXR_MDM_DTR and/or TMXR_MDM_RTS as desired + bits_to_clear TMXR_MDM_DTR and/or TMXR_MDM_RTS as desired + + Output: + incoming_bits if non NULL, returns the current stat of DCD, + RNG, CTS and DSR + + Implementation note: + + If a line is connected to a serial port, then these valus affect + and reflect the state of the serial port. If the line is connected + to a network socket (or could be) then the network session state is + set, cleared and/or returned. +*/ +t_stat tmxr_set_get_modem_bits (TMLN *lp, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits) +{ +t_stat r = SCPE_OK; + +tmxr_debug_trace_line (lp, "tmxr_set_get_modem_bits()"); + +if (!lp->mp->modem_control) /* This API ONLY works on modem_control enabled multiplexers */ + return SCPE_IERR; +if ((bits_to_set & ~(TMXR_MDM_OUTGOING)) || /* Assure only settable bits */ + (bits_to_clear & ~(TMXR_MDM_OUTGOING)) || + (bits_to_set & bits_to_clear)) /* and can't set and clear the same bits */ + return SCPE_ARG; +if (lp->serport) + return sim_control_serial (lp->serport, bits_to_set, bits_to_clear, incoming_bits); +if (lp->conn) { + if (bits_to_clear&TMXR_MDM_DTR) /* drop DTR? */ + tmxr_reset_ln (lp); + } +if (incoming_bits) { + if (lp->conn) + *incoming_bits = TMXR_MDM_DCD | TMXR_MDM_CTS | TMXR_MDM_DSR; + else + *incoming_bits = lp->mp->master ? (TMXR_MDM_CTS | TMXR_MDM_DSR) : 0; + } +return r; +} + +t_stat tmxr_set_config_line (TMLN *lp, char *config) +{ +t_stat r; + +tmxr_debug_trace_line (lp, "tmxr_set_config_line()"); +if (!lp->mp->modem_control) /* This API ONLY works on modem_control enabled multiplexers */ + return SCPE_IERR; +if (lp->serport) + r = sim_config_serial (lp->serport, config); +else { + lp->serconfig = (char *)realloc (lp->serconfig, 1 + strlen (config)); + strcpy (lp->serconfig, config); + r = SCPE_OK; + } +if (r == SCPE_OK) /* Record port state for proper restore */ + lp->mp->uptr->filename = _mux_attach_string (lp->mp->uptr->filename, lp->mp); +return r; +} + + /* Get character from specific line Inputs: *lp = pointer to terminal line descriptor Output: valid + char, 0 if line + + Implementation note: + + 1. If a line break was detected coincident with the current character, the + receive break status associated with the character is cleared, and + SCPE_BREAK is ORed into the return value. */ int32 tmxr_getc_ln (TMLN *lp) @@ -265,13 +1073,16 @@ int32 tmxr_getc_ln (TMLN *lp) int32 j, val = 0; uint32 tmp; -if (lp->conn && lp->rcve) { /* conn & enb? */ +tmxr_debug_trace_line (lp, "tmxr_getc_ln()"); +if ((lp->conn || lp->serport) && lp->rcve) { /* conn & enb? */ j = lp->rxbpi - lp->rxbpr; /* # input chrs */ if (j) { /* any? */ tmp = lp->rxb[lp->rxbpr]; /* get char */ val = TMXR_VALID | (tmp & 0377); /* valid + chr */ - if (lp->rbr[lp->rxbpr]) /* break? */ - val = val | SCPE_BREAK; + if (lp->rbr[lp->rxbpr]) { /* break? */ + lp->rbr[lp->rxbpr] = 0; /* clear status */ + val = val | SCPE_BREAK; /* indicate to caller */ + } lp->rxbpr = lp->rxbpr + 1; /* adv pointer */ } } /* end if conn */ @@ -280,6 +1091,7 @@ if (lp->rxbpi == lp->rxbpr) /* empty? zero ptrs */ return val; } + /* Poll for input Inputs: @@ -292,129 +1104,134 @@ void tmxr_poll_rx (TMXR *mp) int32 i, nbytes, j; TMLN *lp; +tmxr_debug_trace (mp, "tmxr_poll_rx()"); for (i = 0; i < mp->lines; i++) { /* loop thru lines */ lp = mp->ldsc + i; /* get line desc */ - if (!lp->conn || !lp->rcve) /* skip if !conn */ + if (!(lp->conn || lp->serport) || !lp->rcve) /* skip if not connected */ continue; nbytes = 0; if (lp->rxbpi == 0) /* need input? */ - nbytes = sim_read_sock (lp->conn, /* yes, read */ - &(lp->rxb[lp->rxbpi]), /* leave spc for */ - TMXR_MAXBUF - TMXR_GUARD); /* Telnet cruft */ + nbytes = tmxr_read (lp, /* yes, read */ + TMXR_MAXBUF - TMXR_GUARD); /* leave spc for Telnet cruft */ else if (lp->tsta) /* in Telnet seq? */ - nbytes = sim_read_sock (lp->conn, /* yes, read to end */ - &(lp->rxb[lp->rxbpi]), + nbytes = tmxr_read (lp, /* yes, read to end */ TMXR_MAXBUF - lp->rxbpi); - if (nbytes < 0) /* closed? reset ln */ - tmxr_reset_ln (lp); + + if (nbytes < 0) { /* line error? */ + lp->txbpi = lp->txbpr = 0; /* Drop the data we already know we can't send */ + tmxr_close_ln (lp); /* disconnect line */ + } + else if (nbytes > 0) { /* if data rcvd */ tmxr_debug (TMXR_DBG_RCV, lp, "Received", &(lp->rxb[lp->rxbpi]), nbytes); j = lp->rxbpi; /* start of data */ - memset (&lp->rbr[j], 0, nbytes); /* clear status */ lp->rxbpi = lp->rxbpi + nbytes; /* adv pointers */ lp->rxcnt = lp->rxcnt + nbytes; /* Examine new data, remove TELNET cruft before making input available */ - for (; j < lp->rxbpi; ) { /* loop thru char */ - signed char tmp = lp->rxb[j]; /* get char */ - switch (lp->tsta) { /* case tlnt state */ + if (!lp->notelnet) { /* Are we looking for telnet interpretation? */ + for (; j < lp->rxbpi; ) { /* loop thru char */ + signed char tmp = lp->rxb[j]; /* get char */ + switch (lp->tsta) { /* case tlnt state */ - case TNS_NORM: /* normal */ - if (tmp == TN_IAC) { /* IAC? */ - lp->tsta = TNS_IAC; /* change state */ + case TNS_NORM: /* normal */ + if (tmp == TN_IAC) { /* IAC? */ + lp->tsta = TNS_IAC; /* change state */ + tmxr_rmvrc (lp, j); /* remove char */ + break; + } + if ((tmp == TN_CR) && lp->dstb) /* CR, no bin */ + lp->tsta = TNS_CRPAD; /* skip pad char */ + j = j + 1; /* advance j */ + break; + + case TNS_IAC: /* IAC prev */ + if (tmp == TN_IAC) { /* IAC + IAC */ + lp->tsta = TNS_NORM; /* treat as normal */ + j = j + 1; /* advance j */ + break; /* keep IAC */ + } + if (tmp == TN_BRK) { /* IAC + BRK? */ + lp->tsta = TNS_NORM; /* treat as normal */ + lp->rxb[j] = 0; /* char is null */ + lp->rbr[j] = 1; /* flag break */ + j = j + 1; /* advance j */ + break; + } + switch (tmp) { + case TN_WILL: /* IAC + WILL? */ + lp->tsta = TNS_WILL; + break; + case TN_WONT: /* IAC + WONT? */ + lp->tsta = TNS_WONT; + break; + case TN_DO: /* IAC + DO? */ + lp->tsta = TNS_DO; + break; + case TN_DONT: /* IAC + DONT? */ + lp->tsta = TNS_SKIP; /* IAC + other */ + break; + case TN_GA: case TN_EL: /* IAC + other 2 byte types */ + case TN_EC: case TN_AYT: + case TN_AO: case TN_IP: + case TN_NOP: + lp->tsta = TNS_NORM; /* ignore */ + break; + case TN_SB: /* IAC + SB sub-opt negotiation */ + case TN_DATAMK: /* IAC + data mark */ + case TN_SE: /* IAC + SE sub-opt end */ + lp->tsta = TNS_NORM; /* ignore */ + break; + } tmxr_rmvrc (lp, j); /* remove char */ break; - } - if ((tmp == TN_CR) && lp->dstb) /* CR, no bin */ - lp->tsta = TNS_CRPAD; /* skip pad char */ - j = j + 1; /* advance j */ - break; - case TNS_IAC: /* IAC prev */ - if (tmp == TN_IAC) { /* IAC + IAC */ - lp->tsta = TNS_NORM; /* treat as normal */ - j = j + 1; /* advance j */ - break; /* keep IAC */ - } - if (tmp == TN_BRK) { /* IAC + BRK? */ - lp->tsta = TNS_NORM; /* treat as normal */ - lp->rxb[j] = 0; /* char is null */ - lp->rbr[j] = 1; /* flag break */ - j = j + 1; /* advance j */ - break; - } - switch (tmp) { - case TN_WILL: /* IAC + WILL? */ - lp->tsta = TNS_WILL; - break; - case TN_WONT: /* IAC + WONT? */ - lp->tsta = TNS_WONT; - break; - case TN_DO: /* IAC + DO? */ - lp->tsta = TNS_DO; - break; - case TN_DONT: /* IAC + DONT? */ - lp->tsta = TNS_SKIP; /* IAC + other */ - break; - case TN_GA: case TN_EL: /* IAC + other 2 byte types */ - case TN_EC: case TN_AYT: - case TN_AO: case TN_IP: - case TN_NOP: - lp->tsta = TNS_NORM; /* ignore */ - break; - case TN_SB: /* IAC + SB sub-opt negotiation */ - case TN_DATAMK: /* IAC + data mark */ - case TN_SE: /* IAC + SE sub-opt end */ - lp->tsta = TNS_NORM; /* ignore */ - break; - } - tmxr_rmvrc (lp, j); /* remove char */ - break; - - case TNS_WILL: case TNS_WONT: /* IAC+WILL/WONT prev */ - if (tmp == TN_BIN) { /* BIN? */ - if (lp->tsta == TNS_WILL) - lp->dstb = 0; - else lp->dstb = 1; - } - tmxr_rmvrc (lp, j); /* remove it */ - lp->tsta = TNS_NORM; /* next normal */ - break; - - /* Negotiation with the HP terminal emulator "QCTerm" is not working. - QCTerm says "WONT BIN" but sends bare CRs. RFC 854 says: - - Note that "CR LF" or "CR NUL" is required in both directions - (in the default ASCII mode), to preserve the symmetry of the - NVT model. ...The protocol requires that a NUL be inserted - following a CR not followed by a LF in the data stream. - - Until full negotiation is implemented, we work around the problem - by checking the character following the CR in non-BIN mode and - strip it only if it is LF or NUL. This should not affect - conforming clients. - */ - - case TNS_CRPAD: /* only LF or NUL should follow CR */ - lp->tsta = TNS_NORM; /* next normal */ - if ((tmp == TN_LF) || /* CR + LF ? */ - (tmp == TN_NUL)) /* CR + NUL? */ + case TNS_WILL: case TNS_WONT: /* IAC+WILL/WONT prev */ + if (tmp == TN_BIN) { /* BIN? */ + if (lp->tsta == TNS_WILL) + lp->dstb = 0; + else lp->dstb = 1; + } tmxr_rmvrc (lp, j); /* remove it */ - break; + lp->tsta = TNS_NORM; /* next normal */ + break; - case TNS_DO: /* pending DO request */ - case TNS_SKIP: default: /* skip char */ - tmxr_rmvrc (lp, j); /* remove char */ - lp->tsta = TNS_NORM; /* next normal */ - break; - } /* end case state */ - } /* end for char */ - if (nbytes != (lp->rxbpi-lp->rxbpr)) + /* Negotiation with the HP terminal emulator "QCTerm" is not working. + QCTerm says "WONT BIN" but sends bare CRs. RFC 854 says: + + Note that "CR LF" or "CR NUL" is required in both directions + (in the default ASCII mode), to preserve the symmetry of the + NVT model. ...The protocol requires that a NUL be inserted + following a CR not followed by a LF in the data stream. + + Until full negotiation is implemented, we work around the problem + by checking the character following the CR in non-BIN mode and + strip it only if it is LF or NUL. This should not affect + conforming clients. + */ + + case TNS_CRPAD: /* only LF or NUL should follow CR */ + lp->tsta = TNS_NORM; /* next normal */ + if ((tmp == TN_LF) || /* CR + LF ? */ + (tmp == TN_NUL)) /* CR + NUL? */ + tmxr_rmvrc (lp, j); /* remove it */ + break; + + case TNS_DO: /* pending DO request */ + case TNS_SKIP: default: /* skip char */ + tmxr_rmvrc (lp, j); /* remove char */ + lp->tsta = TNS_NORM; /* next normal */ + break; + } /* end case state */ + } /* end for char */ + if (nbytes != (lp->rxbpi-lp->rxbpr)) { tmxr_debug (TMXR_DBG_RCV, lp, "Remaining", &(lp->rxb[lp->rxbpi]), lp->rxbpi-lp->rxbpr); + } + } } /* end else nbytes */ } /* end for lines */ for (i = 0; i < mp->lines; i++) { /* loop thru lines */ @@ -425,6 +1242,7 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */ return; } + /* Return count of available characters for line */ int32 tmxr_rqln (TMLN *lp) @@ -432,17 +1250,6 @@ int32 tmxr_rqln (TMLN *lp) return (lp->rxbpi - lp->rxbpr + ((lp->rxbpi < lp->rxbpr)? TMXR_MAXBUF: 0)); } -/* Remove character p (and matching status) from line l input buffer */ - -void tmxr_rmvrc (TMLN *lp, int32 p) -{ -for ( ; p < lp->rxbpi; p++) { - lp->rxb[p] = lp->rxb[p + 1]; - lp->rbr[p] = lp->rbr[p + 1]; - } -lp->rxbpi = lp->rxbpi - 1; -return; -} /* Store character in line buffer @@ -451,19 +1258,21 @@ return; chr = characters Outputs: status = ok, connection lost, or stall + + Implementation note: + + 1. If the line is not connected, SCPE_LOST is returned. */ t_stat tmxr_putc_ln (TMLN *lp, int32 chr) { -if (lp->txlog) /* log if available */ - fputc (chr, lp->txlog); -if ((lp->conn == 0) && (!lp->txbfd)) /* no conn & not buffered? */ - if (lp->txlog) /* if it was logged, we got it */ - return SCPE_OK; - else { - ++lp->txdrp; /* lost */ - return SCPE_LOST; - } +if ((lp->conn == 0) && /* no conn & not buffered? */ + (lp->serport == 0) && + (!lp->txbfd)) { + ++lp->txdrp; /* lost */ + return SCPE_LOST; + } +tmxr_debug_trace_line (lp, "tmxr_putc_ln()"); #define TXBUF_AVAIL(lp) (lp->txbsz - tmxr_tqln (lp)) #define TXBUF_CHAR(lp, c) { \ lp->txb[lp->txbpi++] = (char)(c); \ @@ -472,11 +1281,13 @@ if ((lp->conn == 0) && (!lp->txbfd)) /* no conn & not buffere lp->txbpr = (1+lp->txbpr)%lp->txbsz, ++lp->txdrp; \ } if ((lp->txbfd) || (TXBUF_AVAIL(lp) > 1)) { /* room for char (+ IAC)? */ - if (TN_IAC == (char) chr) /* char == IAC ? */ + if ((TN_IAC == (char) chr) && (!lp->notelnet)) /* char == IAC in telnet session? */ TXBUF_CHAR (lp, TN_IAC); /* stuff extra IAC char */ TXBUF_CHAR (lp, chr); /* buffer char & adv pointer */ if ((!lp->txbfd) && (TXBUF_AVAIL (lp) <= TMXR_GUARD))/* near full? */ lp->xmte = 0; /* disable line */ + if (lp->txlog) /* log if available */ + fputc (chr, lp->txlog); return SCPE_OK; /* char sent */ } ++lp->txdrp; lp->xmte = 0; /* no room, dsbl line */ @@ -496,17 +1307,19 @@ void tmxr_poll_tx (TMXR *mp) int32 i, nbytes; TMLN *lp; +tmxr_debug_trace (mp, "tmxr_poll_tx()"); for (i = 0; i < mp->lines; i++) { /* loop thru lines */ lp = mp->ldsc + i; /* get line desc */ - if (lp->conn == 0) /* skip if !conn */ + if ((lp->conn == 0) && (lp->serport == 0)) /* skip if !conn */ continue; - nbytes = tmxr_send_buffered_data (lp); /* buffered bytes */ - if (nbytes == 0) /* buf empty? enab line */ - lp->xmte = 1; - } /* end for */ + nbytes = tmxr_send_buffered_data (lp); /* buffered bytes */ + if (nbytes == 0) /* buf empty? enab line */ + lp->xmte = 1; + } /* end for */ return; } + /* Send buffered data across network Inputs: @@ -519,14 +1332,15 @@ int32 tmxr_send_buffered_data (TMLN *lp) { int32 nbytes, sbytes; +tmxr_debug_trace_line (lp, "tmxr_send_buffered_data()"); nbytes = tmxr_tqln(lp); /* avail bytes */ if (nbytes) { /* >0? write */ if (lp->txbpr < lp->txbpi) /* no wrap? */ - sbytes = sim_write_sock (lp->conn, /* write all data */ - &(lp->txb[lp->txbpr]), nbytes); - else sbytes = sim_write_sock (lp->conn, /* write to end buf */ - &(lp->txb[lp->txbpr]), lp->txbsz - lp->txbpr); - if (sbytes != SOCKET_ERROR) { /* ok? */ + sbytes = tmxr_write (lp, nbytes); /* write all data */ + else + sbytes = tmxr_write (lp, lp->txbsz - lp->txbpr);/* write to end buf */ + + if (sbytes >= 0) { /* ok? */ tmxr_debug (TMXR_DBG_XMT, lp, "Sent", &(lp->txb[lp->txbpr]), sbytes); lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */ if (lp->txbpr >= lp->txbsz) /* wrap? */ @@ -534,9 +1348,14 @@ if (nbytes) { /* >0? write */ lp->txcnt = lp->txcnt + sbytes; /* update counts */ nbytes = nbytes - sbytes; } + if (sbytes < 0) { /* I/O Error? */ + lp->txbpi = lp->txbpr = 0; /* Drop the data we already know we can't send */ + tmxr_close_ln (lp); /* close line/port on error */ + return nbytes; /* done now. */ + } if (nbytes && (lp->txbpr == 0)) { /* more data and wrap? */ - sbytes = sim_write_sock (lp->conn, lp->txb, nbytes); - if (sbytes != SOCKET_ERROR) { /* ok */ + sbytes = tmxr_write (lp, nbytes); + if (sbytes > 0) { /* ok */ tmxr_debug (TMXR_DBG_XMT, lp, "Sent", lp->txb, sbytes); lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */ if (lp->txbpr >= lp->txbsz) /* wrap? */ @@ -549,6 +1368,7 @@ if (nbytes) { /* >0? write */ return nbytes; } + /* Return count of buffered characters for line */ int32 tmxr_tqln (TMLN *lp) @@ -556,79 +1376,289 @@ int32 tmxr_tqln (TMLN *lp) return (lp->txbpi - lp->txbpr + ((lp->txbpi < lp->txbpr)? lp->txbsz: 0)); } -/* Open master socket */ + +/* Open a master listening socket (and all of the other variances of connections). + + A listening socket for the port number described by "cptr" is opened for the + multiplexer associated with descriptor "mp". If the open is successful, all + lines not currently otherwise connected (via serial, outgoing or direct + listener) are initialized for Telnet connections. + + Initialization for all connection styles (MUX wide listener, per line serial, + listener, outgoing, logging, buffering) are handled by this routine. + +*/ t_stat tmxr_open_master (TMXR *mp, char *cptr) { -int32 i, port; +int32 i, line = -1; +char tbuf[CBUFSIZE], listen[CBUFSIZE], destination[CBUFSIZE], + logfiletmpl[CBUFSIZE], buffered[CBUFSIZE], hostport[CBUFSIZE], + port[CBUFSIZE], option[CBUFSIZE]; SOCKET sock; +SERHANDLE serport; +char *tptr = cptr; +t_bool nolog, notelnet, listennotelnet, unbuffered; TMLN *lp; -t_stat r; +t_stat r = SCPE_ARG; -if (!isdigit(*cptr)) { - char gbuf[CBUFSIZE]; - cptr = get_glyph (cptr, gbuf, '='); - if (0 == MATCH_CMD (gbuf, "LOG")) { - if ((NULL == cptr) || ('\0' == *cptr)) - return SCPE_2FARG; - strncpy(mp->logfiletmpl, cptr, sizeof(mp->logfiletmpl)-1); - for (i = 0; i < mp->lines; i++) { - lp = mp->ldsc + i; +tmxr_debug_trace (mp, "tmxr_open_master()"); +while (*tptr) { + line = -1; + memset(logfiletmpl, '\0', sizeof(logfiletmpl)); + memset(listen, '\0', sizeof(listen)); + memset(destination, '\0', sizeof(destination)); + memset(buffered, '\0', sizeof(buffered)); + memset(port, '\0', sizeof(port)); + memset(option, '\0', sizeof(option)); + nolog = notelnet = listennotelnet = unbuffered = FALSE; + while (*tptr) { + tptr = get_glyph_nc (tptr, tbuf, ','); + if (!tbuf[0]) + break; + cptr = tbuf; + if (!isdigit(*cptr)) { + char gbuf[CBUFSIZE]; + char *init_cptr = cptr; + + cptr = get_glyph (cptr, gbuf, '='); + if (0 == MATCH_CMD (gbuf, "LINE")) { + if ((NULL == cptr) || ('\0' == *cptr)) + return SCPE_ARG; + line = (int32) get_uint (cptr, 10, mp->lines, &r); + if (r != SCPE_OK) + return SCPE_ARG; + continue; + } + if (0 == MATCH_CMD (gbuf, "LOG")) { + if ((NULL == cptr) || ('\0' == *cptr)) + return SCPE_2FARG; + strncpy(logfiletmpl, cptr, sizeof(logfiletmpl)-1); + continue; + } + if ((0 == MATCH_CMD (gbuf, "NOBUFFERED")) || + (0 == MATCH_CMD (gbuf, "UNBUFFERED"))) { + if ((NULL != cptr) && ('\0' != *cptr)) + return SCPE_2MARG; + unbuffered = TRUE; + continue; + } + if (0 == MATCH_CMD (gbuf, "BUFFERED")) { + if ((NULL == cptr) || ('\0' == *cptr)) + strcpy(buffered, "32768"); + else { + i = (int32) get_uint (cptr, 10, 1024*1024, &r); + if ((r != SCPE_OK) || (i == 0)) + return SCPE_ARG; + sprintf(buffered, "%d", i); + } + continue; + } + if (0 == MATCH_CMD (gbuf, "NOLOG")) { + if ((NULL != cptr) && ('\0' != *cptr)) + return SCPE_2MARG; + nolog = TRUE; + continue; + } + if (0 == MATCH_CMD (gbuf, "CONNECT")) { + if ((NULL == cptr) || ('\0' == *cptr)) + return SCPE_ARG; + serport = sim_open_serial (cptr, NULL, &r); + if (serport != INVALID_HANDLE) { + sim_close_serial (serport); + if (strchr (cptr, ';') && mp->modem_control) + return SCPE_ARG; + } + else { + memset (hostport, '\0', sizeof(hostport)); + strncpy (hostport, cptr, sizeof(hostport)-1); + if ((cptr = strchr (hostport, ';'))) + *(cptr++) = '\0'; + sock = sim_connect_sock (hostport, "localhost", NULL); + if (sock != INVALID_SOCKET) + sim_close_sock (sock, 0); + else + return SCPE_ARG; + if (cptr) + get_glyph (cptr, cptr, 0); /* upcase this string */ + if (0 == MATCH_CMD (cptr, "NOTELNET")) + notelnet = TRUE; + cptr = hostport; + } + strcpy(destination, cptr); + continue; + } + cptr = get_glyph (gbuf, port, ';'); + if (SCPE_OK != sim_parse_addr (port, NULL, 0, NULL, NULL, 0, NULL, NULL)) + return SCPE_ARG; + if (cptr) + get_glyph (cptr, cptr, 0); /* upcase this string */ + if (0 == MATCH_CMD (cptr, "NOTELNET")) + listennotelnet = TRUE; + cptr = init_cptr; + } + cptr = get_glyph_nc (cptr, port, ';'); + sock = sim_master_sock (port, &r); /* make master socket */ + if (r != SCPE_OK) + return r; + if (sock == INVALID_SOCKET) /* open error */ + return SCPE_OPENERR; + sim_close_sock (sock, 1); + strcpy(listen, port); + cptr = get_glyph (cptr, option, ';'); + if (0 == MATCH_CMD (option, "NOTELNET")) + listennotelnet = TRUE; + } + if (line == -1) { + if (logfiletmpl[0]) { + strncpy(mp->logfiletmpl, logfiletmpl, sizeof(mp->logfiletmpl)-1); + for (i = 0; i < mp->lines; i++) { + lp = mp->ldsc + i; + sim_close_logfile (&lp->txlogref); + lp->txlog = NULL; + lp->txlogname = (char *)realloc(lp->txlogname, CBUFSIZE); + if (mp->lines > 1) + sprintf(lp->txlogname, "%s_%d", mp->logfiletmpl, i); + else + strcpy(lp->txlogname, mp->logfiletmpl); + r = sim_open_logfile (lp->txlogname, TRUE, &lp->txlog, &lp->txlogref); + if (r == SCPE_OK) + setvbuf(lp->txlog, NULL, _IOFBF, 65536); + else { + free (lp->txlogname); + lp->txlogname = NULL; + break; + } + } + } + if (unbuffered) { + if (mp->buffered) { + mp->buffered = 0; + for (i = 0; i < mp->lines; i++) { /* default line buffers */ + lp = mp->ldsc + i; + lp->txbsz = TMXR_MAXBUF; + lp->txb = (char *)realloc(lp->txb, lp->txbsz); + lp->txbfd = lp->txbpi = lp->txbpr = 0; + } + } + } + if (buffered[0]) { + mp->buffered = atoi(buffered); + for (i = 0; i < mp->lines; i++) { /* initialize line buffers */ + lp = mp->ldsc + i; + lp->txbsz = mp->buffered; + lp->txbfd = 1; + lp->txb = (char *)realloc(lp->txb, lp->txbsz); + lp->txbpi = lp->txbpr = 0; + } + } + if (nolog) { + mp->logfiletmpl[0] = '\0'; + for (i = 0; i < mp->lines; i++) { /* close line logs */ + lp = mp->ldsc + i; + free(lp->txlogname); + lp->txlogname = NULL; + if (lp->txlog) { + sim_close_logfile (&lp->txlogref); + lp->txlog = NULL; + } + } + } + if (listen[0]) { + if (mp->port && (0 != strcmp (listen, mp->port))) { + sim_close_sock (mp->master, 1); + mp->master = 0; + free (mp->port); + mp->port = NULL; + } + sock = sim_master_sock (listen, &r); /* make master socket */ + if (r != SCPE_OK) + return r; + if (sock == INVALID_SOCKET) /* open error */ + return SCPE_OPENERR; + printf ("Listening on port %s\n", listen); + if (sim_log) + fprintf (sim_log, "Listening on port %s\n", listen); + mp->port = (char *)realloc (mp->port, 1 + strlen (listen)); + strcpy (mp->port, listen); /* save port */ + mp->master = sock; /* save master socket */ + mp->notelnet = listennotelnet; /* save desired telnet behavior flag */ + for (i = 0; i < mp->lines; i++) { /* initialize lines */ + lp = mp->ldsc + i; + + if (lp->serport == 0) { /* no serial port attached? */ + lp->mp = mp; /* set the back pointer */ + tmxr_init_line (lp); /* initialize line state */ + lp->conn = 0; /* clear the socket */ + } + } + } + if (destination[0]) { + if (mp->lines > 1) + return SCPE_ARG; /* ambiguous */ + lp = &mp->ldsc[0]; + lp->destination = malloc(1+strlen(destination)); + strcpy (lp->destination, destination); + serport = sim_open_serial (lp->destination, lp, &r); + if (serport != INVALID_HANDLE) { + lp->mp = mp; + lp->serport = serport; + lp->ser_connect_pending = TRUE; + lp->notelnet = TRUE; + tmxr_init_line (lp); /* init the line state */ + if (!lp->mp->modem_control) /* raise DTR and RTS for non modem control lines */ + sim_control_serial (lp->serport, TMXR_MDM_DTR|TMXR_MDM_RTS, 0, NULL); + lp->cnms = sim_os_msec (); /* record time of connection */ + if (sim_switches & SWMASK ('V')) { /* -V flag reports connection on port */ + sim_os_ms_sleep (TMXR_DTR_DROP_TIME); + tmxr_report_connection (mp, lp); /* report the connection to the line */ + } + } + else { + sock = sim_connect_sock (destination, "localhost", NULL); + if (sock != INVALID_SOCKET) { + lp->mp = mp; + lp->connecting = sock; + lp->ipad = malloc (1 + strlen (lp->destination)); + strcpy (lp->ipad, lp->destination); + lp->notelnet = notelnet; + lp->cnms = sim_os_msec (); /* record time of connection */ + tmxr_init_line (lp); /* init the line state */ + } + else + return SCPE_ARG; + } + } + } + else { /* line specific attach */ + lp = &mp->ldsc[line]; + lp->mp = mp; + if (logfiletmpl[0]) { sim_close_logfile (&lp->txlogref); lp->txlog = NULL; - lp->txlogname = realloc(lp->txlogname, CBUFSIZE); - if (mp->lines > 1) - sprintf(lp->txlogname, "%s_%d", mp->logfiletmpl, i); - else - strcpy(lp->txlogname, mp->logfiletmpl); + lp->txlogname = (char *)realloc (lp->txlogname, 1 + strlen (logfiletmpl)); + strcpy(lp->txlogname, mp->logfiletmpl); r = sim_open_logfile (lp->txlogname, TRUE, &lp->txlog, &lp->txlogref); if (r == SCPE_OK) setvbuf(lp->txlog, NULL, _IOFBF, 65536); else { free (lp->txlogname); lp->txlogname = NULL; - break; + return r; } } - return r; - } - if ((0 == MATCH_CMD (gbuf, "NOBUFFERED")) || - (0 == MATCH_CMD (gbuf, "UNBUFFERED"))) { - if (mp->buffered) { - mp->buffered = 0; - for (i = 0; i < mp->lines; i++) { /* default line buffers */ - lp = mp->ldsc + i; - lp->txbsz = TMXR_MAXBUF; - lp->txb = (char *)realloc(lp->txb, lp->txbsz); - lp->txbfd = lp->txbpi = lp->txbpr = 0; - } + if (unbuffered) { + lp->txbsz = TMXR_MAXBUF; + lp->txb = (char *)realloc (lp->txb, lp->txbsz); + lp->txbfd = lp->txbpi = lp->txbpr = 0; } - return SCPE_OK; - } - if (0 == MATCH_CMD (gbuf, "BUFFERED")) { - if ((NULL == cptr) || ('\0' == *cptr)) - mp->buffered = 32768; - else { - i = (int32) get_uint (cptr, 10, 1024*1024, &r); - if ((r != SCPE_OK) || (i == 0)) - return SCPE_ARG; - mp->buffered = i; - } - for (i = 0; i < mp->lines; i++) { /* initialize line buffers */ - lp = mp->ldsc + i; - lp->txbsz = mp->buffered; + if (buffered[0]) { + lp->txbsz = atoi(buffered); lp->txbfd = 1; - lp->txb = (char *)realloc(lp->txb, lp->txbsz); + lp->txb = (char *)realloc (lp->txb, lp->txbsz); lp->txbpi = lp->txbpr = 0; } - return SCPE_OK; - } - if (0 == MATCH_CMD (gbuf, "NOLOG")) { - if ((NULL != cptr) && ('\0' != *cptr)) - return SCPE_2MARG; - mp->logfiletmpl[0] = '\0'; - for (i = 0; i < mp->lines; i++) { /* close line logs */ - lp = mp->ldsc + i; + if (nolog) { free(lp->txlogname); lp->txlogname = NULL; if (lp->txlog) { @@ -636,100 +1666,404 @@ if (!isdigit(*cptr)) { lp->txlog = NULL; } } - return SCPE_OK; + if (listen[0]) { + if (lp->master) { + sim_close_sock (lp->master, 1); + lp->master = 0; + } + if (lp->conn) { + sim_close_sock (lp->conn, 1); + lp->conn = 0; + } + if (lp->connecting) { + sim_close_sock (lp->connecting, 1); + lp->connecting = 0; + } + if (lp->serport) { + sim_close_serial (lp->serport); + lp->serport = 0; + free (lp->serconfig); + lp->serconfig = NULL; + } + free (lp->destination); + lp->destination = NULL; + sock = sim_master_sock (listen, &r); /* make master socket */ + if (r != SCPE_OK) + return r; + if (sock == INVALID_SOCKET) /* open error */ + return SCPE_OPENERR; + printf ("Line %d Listening on port %s\n", line, listen); + if (sim_log) + fprintf (sim_log, "Line %d Listening on port %s\n", line, listen); + lp->port = (char *)realloc (lp->port, 1 + strlen (listen)); + strcpy(lp->port, listen); /* save port */ + lp->master = sock; /* save master socket */ + if (listennotelnet) + lp->notelnet = listennotelnet; + else + lp->notelnet = mp->notelnet; + } + if (destination[0]) { + lp->destination = malloc(1+strlen(destination)); + strcpy (lp->destination, destination); + serport = sim_open_serial (lp->destination, lp, &r); + if (serport != INVALID_HANDLE) { + lp->serport = serport; + lp->ser_connect_pending = TRUE; + lp->notelnet = TRUE; + tmxr_init_line (lp); /* init the line state */ + if (!lp->mp->modem_control) /* raise DTR and RTS for non modem control lines */ + sim_control_serial (lp->serport, TMXR_MDM_DTR|TMXR_MDM_RTS, 0, NULL); + lp->cnms = sim_os_msec (); /* record time of connection */ + if (sim_switches & SWMASK ('V')) { /* -V flag reports connection on port */ + sim_os_ms_sleep (TMXR_DTR_DROP_TIME); + tmxr_report_connection (mp, lp); /* report the connection to the line */ + } + } + else { + sock = sim_connect_sock (destination, "localhost", NULL); + if (sock != INVALID_SOCKET) { + lp->connecting = sock; + lp->ipad = malloc (1 + strlen (lp->destination)); + strcpy (lp->ipad, lp->destination); + lp->notelnet = notelnet; + lp->cnms = sim_os_msec (); /* record time of connection */ + tmxr_init_line (lp); /* init the line state */ + } + else + return SCPE_ARG; + } + } + r = SCPE_OK; } - return SCPE_ARG; } -port = (int32) get_uint (cptr, 10, 65535, &r); /* get port */ -if ((r != SCPE_OK) || (port == 0)) +return r; +} + + +/* Declare which unit polls for input + + Inputs: + *mp = the mux + line = the line number + *uptr_poll = the unit which polls + + Outputs: + none + + Implementation note: + + Only devices which poll on a unit different from the unit provided + at MUX attach time need call this function. Calling this API is + necessary for asynchronous multiplexer support and unnecessary + otherwise. + +*/ + +t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll) +{ +if ((line < 0) || (line >= mp->lines)) return SCPE_ARG; -sock = sim_master_sock (port); /* make master socket */ -if (sock == INVALID_SOCKET) /* open error */ - return SCPE_OPENERR; -printf ("Listening on port %d (socket %d)\n", port, sock); -if (sim_log) - fprintf (sim_log, "Listening on port %d (socket %d)\n", port, sock); -mp->port = port; /* save port */ -mp->master = sock; /* save master socket */ -for (i = 0; i < mp->lines; i++) { /* initialize lines */ - lp = mp->ldsc + i; - lp->conn = lp->tsta = 0; - lp->rxbpi = lp->rxbpr = 0; - lp->txbpi = lp->txbpr = 0; - if (!mp->buffered) { - lp->txbfd = lp->txbpi = lp->txbpr = 0; - lp->txbsz = TMXR_MAXBUF; - lp->txb = (char *)realloc(lp->txb, lp->txbsz); - } - lp->rxcnt = lp->txcnt = lp->txdrp = 0; - lp->xmte = 1; - lp->dstb = 0; - } +mp->ldsc[line].uptr = uptr_poll; return SCPE_OK; } +t_stat tmxr_set_console_input_unit (UNIT *uptr) +{ +extern TMLN sim_con_ldsc; + +sim_con_ldsc.uptr = uptr; +if (!(uptr->flags & UNIT_TM_POLL)) { + uptr->flags |= UNIT_TM_POLL; /* tag as polling unit */ + } +else + sim_cancel (uptr); +return SCPE_OK; +} + +/* Declare which unit polls for output + + Inputs: + *mp = the mux + line = the line number + *uptr_poll = the unit which polls for output + + Outputs: + none + + Implementation note: + + Only devices which poll on a unit different from the unit provided + at MUX attach time need call this function ABD different from the + unit which polls for input. Calling this API is necessary for + asynchronous multiplexer support and unnecessary otherwise. + +*/ + +t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll) +{ +if ((line < 0) || (line >= mp->lines)) + return SCPE_ARG; +mp->ldsc[line].o_uptr = uptr_poll; +return SCPE_OK; +} + + +static TMXR **tmxr_open_devices = NULL; +static int tmxr_open_device_count = 0; + +t_stat tmxr_start_poll (void) +{ +#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX) +pthread_mutex_lock (&sim_tmxr_poll_lock); +if ((tmxr_open_device_count > 0) && + sim_asynch_enabled && + sim_is_running && + !sim_tmxr_poll_running) { + pthread_attr_t attr; + + pthread_cond_init (&sim_tmxr_startup_cond, NULL); + pthread_attr_init (&attr); + pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); + pthread_create (&sim_tmxr_poll_thread, &attr, _tmxr_poll, NULL); + pthread_attr_destroy( &attr); + pthread_cond_wait (&sim_tmxr_startup_cond, &sim_tmxr_poll_lock); /* Wait for thread to stabilize */ + pthread_cond_destroy (&sim_tmxr_startup_cond); + sim_tmxr_poll_running = TRUE; + } +pthread_mutex_unlock (&sim_tmxr_poll_lock); +#endif +return SCPE_OK; +} + +t_stat tmxr_stop_poll (void) +{ +#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX) +pthread_mutex_lock (&sim_tmxr_poll_lock); +if (sim_tmxr_poll_running) { + pthread_cond_signal (&sim_tmxr_poll_cond); + pthread_mutex_unlock (&sim_tmxr_poll_lock); + pthread_join (sim_tmxr_poll_thread, NULL); + sim_tmxr_poll_running = FALSE; + /* Transitioning from asynch mode so kick all polling units onto the event queue */ + if (tmxr_open_device_count) { + int i, j; + + for (i=0; iuptr) + _sim_activate (mp->uptr, 0); + for (j = 0; j < mp->lines; ++j) + if (mp->ldsc[j].uptr) + _sim_activate (mp->ldsc[j].uptr, 0); + } + } + } +else + pthread_mutex_unlock (&sim_tmxr_poll_lock); +#endif +return SCPE_OK; +} + +static void _tmxr_add_to_open_list (TMXR* mux) +{ +int i; +t_bool found = FALSE; + +#if defined(SIM_ASYNCH_IO) && defined(SIM_ASYNCH_MUX) +pthread_mutex_lock (&sim_tmxr_poll_lock); +#endif +for (i=0; iport); /* copy port */ -if (mp->buffered) - sprintf (bmsg, ", buffered=%d", mp->buffered); /* buffer info */ -if (mp->logfiletmpl[0]) - sprintf (lmsg, ", log=%s", mp->logfiletmpl); /* logfile info */ -sprintf (tptr, "%s%s%s", pmsg, bmsg, lmsg); /* assemble all */ -uptr->filename = tptr; /* save */ +mp->uptr = uptr; /* save unit for polling */ +uptr->filename = _mux_attach_string (uptr->filename, mp);/* save */ uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */ +if ((mp->lines > 1) || + ((mp->master == 0) && + (mp->ldsc[0].connecting == 0) && + (mp->ldsc[0].serport == 0))) + uptr->flags = uptr->flags | UNIT_ATTMULT; /* allow multiple attach commands */ if (mp->dptr == NULL) /* has device been set? */ mp->dptr = find_dev_from_unit (uptr); /* no, so set device now */ +_tmxr_add_to_open_list (mp); return SCPE_OK; } -/* Close master socket */ + +t_stat tmxr_startup (void) +{ +return SCPE_OK; +} + +t_stat tmxr_shutdown (void) +{ +if (tmxr_open_device_count) + return SCPE_IERR; +return SCPE_OK; +} + +t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, char* desc) +{ +int i, j; + +if (0 == tmxr_open_device_count) + fprintf(st, "No Attached Multiplexer Devices\n"); +else { + for (i=0; idptr->name); + fprintf(st, ", attached to %s, ", mp->uptr->filename); + if (mp->lines > 1) { + tmxr_show_lines(st, NULL, 0, mp); + fprintf(st, ", "); + } + tmxr_show_summ(st, NULL, 0, mp); + fprintf(st, ", sessions=%d\n", mp->sessions); + for (j = 0; j < mp->lines; j++) { + lp = mp->ldsc + j; + if (mp->lines > 1) { + fprintf (st, "Line: %d", j); + if (lp->uptr && (lp->uptr != lp->mp->uptr)) + fprintf (st, " - Unit: %s\n", sim_uname (lp->uptr)); + else + fprintf (st, "\n"); + } + if ((!lp->conn) && (!lp->connecting) && (!lp->serport) && (!lp->master)) + continue; + tmxr_fconns (st, lp, -1); + tmxr_fstats (st, lp, -1); + } + } + } +return SCPE_OK; +} + + +/* Close a master listening socket. + + The listening socket associated with multiplexer descriptor "mp" is closed + and deallocated. In addition, all current Telnet sessions are disconnected. + Serial and outgoing sessions are also disconnected. +*/ t_stat tmxr_close_master (TMXR *mp) { int32 i; TMLN *lp; -for (i = 0; i < mp->lines; i++) { /* loop thru conn */ +for (i = 0; i < mp->lines; i++) { /* loop thru conn */ lp = mp->ldsc + i; - if (lp->conn) { - tmxr_linemsg (lp, "\r\nDisconnected from the "); - tmxr_linemsg (lp, sim_name); - tmxr_linemsg (lp, " simulator\r\n\n"); - tmxr_reset_ln (lp); - } /* end if conn */ - } /* end for */ -sim_close_sock (mp->master, 1); /* close master socket */ + + if (!lp->destination && lp->conn) { /* not serial and is connected? */ + tmxr_report_disconnection (lp); /* report disconnection */ + tmxr_reset_ln (lp); /* disconnect line */ + if (lp->master) + sim_close_sock (mp->master, 1); /* close master socket */ + lp->master = 0; + free (lp->port); + lp->port = NULL; + } + else { + if (lp->conn) { + tmxr_report_disconnection (lp); /* report disconnection */ + tmxr_reset_ln (lp); + } + if (lp->connecting) { + lp->conn = lp->connecting; + lp->connecting = 0; + tmxr_reset_ln (lp); + } + if (lp->serport) { + tmxr_reset_ln (lp); + sim_control_serial (lp->serport, 0, TMXR_MDM_DTR|TMXR_MDM_RTS, NULL);/* drop DTR and RTS */ + sim_close_serial (lp->serport); + lp->serport = 0; + free (lp->serconfig); + lp->serconfig = NULL; + } + free (lp->destination); + lp->destination = NULL; + } + } + +if (mp->master) + sim_close_sock (mp->master, 1); /* close master socket */ mp->master = 0; +free (mp->port); +mp->port = NULL; +_tmxr_remove_from_open_list (mp); return SCPE_OK; } -/* Detach unit from master socket */ + +/* Detach unit from master socket and close all active network connections + and/or serial ports. + + Note that we return SCPE_OK, regardless of whether a listening socket was + attached. +*/ t_stat tmxr_detach (TMXR *mp, UNIT *uptr) { if (!(uptr->flags & UNIT_ATT)) /* attached? */ return SCPE_OK; tmxr_close_master (mp); /* close master socket */ -free (uptr->filename); /* free port string */ +free (uptr->filename); /* free setup string */ uptr->filename = NULL; uptr->flags = uptr->flags & ~UNIT_ATT; /* not attached */ return SCPE_OK; @@ -747,15 +2081,19 @@ t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) return SCPE_NOFNC; } -/* Output message to socket or line descriptor */ + +/* Write a message directly to a socket */ void tmxr_msg (SOCKET sock, char *msg) { -if (sock) +if ((sock) && (sock != INVALID_SOCKET)) sim_write_sock (sock, msg, (int32)strlen (msg)); return; } + +/* Write a message to a line */ + void tmxr_linemsg (TMLN *lp, char *msg) { int32 len; @@ -765,34 +2103,49 @@ for (len = (int32)strlen (msg); len > 0; --len) return; } + /* Print connections - used only in named SHOW command */ void tmxr_fconns (FILE *st, TMLN *lp, int32 ln) { +int32 hr, mn, sc; +uint32 ctime; + if (ln >= 0) fprintf (st, "line %d: ", ln); -if (lp->conn) { - int32 o1, o2, o3, o4, hr, mn, sc; - uint32 ctime; - o1 = (lp->ipad >> 24) & 0xFF; - o2 = (lp->ipad >> 16) & 0xFF; - o3 = (lp->ipad >> 8) & 0xFF; - o4 = (lp->ipad) & 0xFF; +if ((lp->conn) || (lp->connecting)) { /* tcp connection? */ + if (lp->destination) /* remote connection? */ + fprintf (st, "Connection to remote port %s\n", lp->destination);/* print port name */ + else /* incoming connection */ + fprintf (st, "Connection from IP address %s\n", lp->ipad); + } + +if (lp->port) + fprintf (st, "Listening on port %s\n", lp->port); /* print port name */ + +if (lp->serport) /* serial connection? */ + fprintf (st, "Connected to serial port %s\n", lp->destination); /* print port name */ + +if (lp->cnms) { ctime = (sim_os_msec () - lp->cnms) / 1000; hr = ctime / 3600; mn = (ctime / 60) % 60; sc = ctime % 60; - fprintf (st, "IP address %d.%d.%d.%d", o1, o2, o3, o4); if (ctime) - fprintf (st, ", connected %02d:%02d:%02d\n", hr, mn, sc); + fprintf (st, " %s %02d:%02d:%02d\n", lp->connecting ? "Connecting for" : "Connected", hr, mn, sc); } -else fprintf (st, "line disconnected\n"); +else + fprintf (st, " Line disconnected\n"); + +if ((lp->serport == 0) && (lp->conn)) + fprintf (st, " %s\n", (lp->notelnet) ? "Telnet disabled (RAW data)" : "Telnet protocol"); if (lp->txlog) - fprintf (st, "Logging to %s\n", lp->txlogname); + fprintf (st, " Logging to %s\n", lp->txlogname); return; } + /* Print statistics - used only in named SHOW command */ void tmxr_fstats (FILE *st, TMLN *lp, int32 ln) @@ -801,17 +2154,22 @@ static const char *enab = "on"; static const char *dsab = "off"; if (ln >= 0) - fprintf (st, "line %d:\b", ln); -if (!lp->conn) - fprintf (st, "line disconnected\n"); -if (lp->rxcnt) - fprintf (st, " input (%s) queued/total = %d/%d\n", - (lp->rcve? enab: dsab), - tmxr_rqln (lp), lp->rxcnt); -if (lp->txcnt || lp->txbpi) - fprintf (st, " output (%s) queued/total = %d/%d\n", - (lp->xmte? enab: dsab), - tmxr_tqln (lp), lp->txcnt); + fprintf (st, "Line %d:", ln); +if ((!lp->conn) && (!lp->connecting) && (!lp->serport)) + fprintf (st, " not connected\n"); +else { + if (ln >= 0) + fprintf (st, "\n"); + fprintf (st, " input (%s)", (lp->rcve? enab: dsab)); + if (lp->rxcnt) + fprintf (st, " queued/total = %d/%d", + tmxr_rqln (lp), lp->rxcnt); + fprintf (st, "\n output (%s)", (lp->xmte? enab: dsab)); + if (lp->txcnt || lp->txbpi) + fprintf (st, " queued/total = %d/%d", + tmxr_tqln (lp), lp->txcnt); + fprintf (st, "\n"); + } if (lp->txbfd) fprintf (st, " output buffer size = %d\n", lp->txbsz); if (lp->txcnt || lp->txbpi) @@ -822,37 +2180,58 @@ if (lp->txdrp) return; } -/* Disconnect line */ + +/* Disconnect a line. + + Disconnect a line of the multiplexer associated with descriptor "desc" from a + tcp session or a serial port. Two calling sequences are supported: + + 1. If "val" is zero, then "uptr" is implicitly associated with the line + number corresponding to the position of the unit in the zero-based array + of units belonging to the associated device, and "cptr" is ignored. For + example, if "uptr" points to unit 3 in a given device, then line 3 will + be disconnected. + + 2. If "val" is non-zero, then "cptr" points to a string that is parsed for + an explicit line number, and "uptr" is ignored. For example, if "cptr" + points to the string "3", then line 3 will be disconnected. + + If the line was connected to a tcp session, the socket associated with the + line will be closed. If the line was connected to a serial port, the port + will NOT be closed, but DTR will be dropped. After a 500ms delay DTR will + be raised again. + + Implementation notes: + + 1. This function is usually called as an MTAB processing routine. +*/ t_stat tmxr_dscln (UNIT *uptr, int32 val, char *cptr, void *desc) { TMXR *mp = (TMXR *) desc; TMLN *lp; -int32 ln; -t_stat r; +t_stat status; -if (mp == NULL) - return SCPE_IERR; -if (val) { /* = n form */ - if (cptr == NULL) - return SCPE_ARG; - ln = (int32) get_uint (cptr, 10, mp->lines - 1, &r); - if (r != SCPE_OK) - return SCPE_ARG; - lp = mp->ldsc + ln; - } -else { - lp = tmxr_find_ldsc (uptr, 0, mp); - if (lp == NULL) - return SCPE_IERR; - } -if (lp->conn) { - tmxr_linemsg (lp, "\r\nOperator disconnected line\r\n\n"); - tmxr_reset_ln (lp); +if (val) /* explicit line? */ + uptr = NULL; /* indicate to get routine */ + +tmxr_debug_trace (mp, "tmxr_dscln()"); + +lp = tmxr_get_ldsc (uptr, cptr, mp, &status); /* get referenced line */ + +if (lp == NULL) /* bad line number? */ + return status; /* report it */ + +if ((lp->conn) || (lp->serport)) { /* connection active? */ + if (!lp->notelnet) + tmxr_linemsg (lp, "\r\nOperator disconnected line\r\n\n");/* report closure */ + tmxr_reset_ln_ex (lp, (sim_switches & SWMASK ('C'))); /* drop the line */ } + return SCPE_OK; } + /* Enable logging for line */ t_stat tmxr_set_log (UNIT *uptr, int32 val, char *cptr, void *desc) @@ -876,9 +2255,11 @@ if (lp->txlog == NULL) { /* error? */ free (lp->txlogname); /* free buffer */ return SCPE_OPENERR; } +lp->mp->uptr->filename = _mux_attach_string (lp->mp->uptr->filename, lp->mp); return SCPE_OK; } + /* Disable logging for line */ t_stat tmxr_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc) @@ -897,9 +2278,11 @@ if (lp->txlog) { /* logging? */ lp->txlog = NULL; lp->txlogname = NULL; } +lp->mp->uptr->filename = _mux_attach_string (lp->mp->uptr->filename, lp->mp); return SCPE_OK; } + /* Show logging status for line */ t_stat tmxr_show_log (FILE *st, UNIT *uptr, int32 val, void *desc) @@ -916,27 +2299,6 @@ else fprintf (st, "no logging"); return SCPE_OK; } -/* Find line descriptor. - - Note: This routine may be called with a UNIT that does not belong to the - device indicated in the TMXR structure. That is, the multiplexer lines may - belong to a device other than the one attached to the socket (the HP 2100 MUX - device is one example). Therefore, we must look up the device from the unit - at each call, rather than depending on the DPTR stored in the TMXR. -*/ - -TMLN *tmxr_find_ldsc (UNIT *uptr, int32 val, TMXR *mp) -{ -if (uptr) { /* called from SET? */ - DEVICE *dptr = find_dev_from_unit (uptr); /* find device */ - if (dptr == NULL) /* what?? */ - return NULL; - val = (int32) (uptr - dptr->units); /* implicit line # */ - } -if ((val < 0) || (val >= mp->lines)) /* invalid line? */ - return NULL; -return mp->ldsc + val; /* line descriptor */ -} /* Set the line connection order. @@ -1043,6 +2405,7 @@ free (set); /* free set allocation * return result; } + /* Show line connection order. Parameters: @@ -1118,10 +2481,12 @@ int32 i, t; if (mp == NULL) return SCPE_IERR; for (i = t = 0; i < mp->lines; i++) - t = t + (mp->ldsc[i].conn != 0); -if (t == 1) - fprintf (st, "1 connection"); -else fprintf (st, "%d connections", t); + if ((mp->ldsc[i].conn != 0) || (mp->ldsc[i].serport != 0)) + t = t + 1; +if (mp->lines > 1) + fprintf (st, "%d connection%s", t, (t != 1) ? "s" : ""); +else + fprintf (st, "%s", (t == 1) ? "connected" : "disconnected"); return SCPE_OK; } @@ -1135,7 +2500,7 @@ int32 i, any; if (mp == NULL) return SCPE_IERR; for (i = any = 0; i < mp->lines; i++) { - if (mp->ldsc[i].conn) { + if ((mp->ldsc[i].conn != 0) || (mp->ldsc[i].serport != 0)) { any++; if (val) tmxr_fconns (st, &mp->ldsc[i], i); @@ -1198,7 +2563,7 @@ static void tmxr_buf_debug_char (char value) { if (tmxr_debug_buf_used+2 > tmxr_debug_buf_size) { tmxr_debug_buf_size += 1024; - tmxr_debug_buf = realloc(tmxr_debug_buf, tmxr_debug_buf_size); + tmxr_debug_buf = (char *)realloc (tmxr_debug_buf, tmxr_debug_buf_size); } tmxr_debug_buf[tmxr_debug_buf_used++] = value; tmxr_debug_buf[tmxr_debug_buf_used] = '\0'; @@ -1210,7 +2575,7 @@ while (*string) tmxr_buf_debug_char (*string++); } -void tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize) +void _tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize) { if ((lp->mp->dptr) && (dbits & lp->mp->dptr->dctrl)) { int i, j; @@ -1235,4 +2600,3 @@ if ((lp->mp->dptr) && (dbits & lp->mp->dptr->dctrl)) { sim_debug (dbits, lp->mp->dptr, "%s %d bytes '%s'\n", msg, bufsize, tmxr_debug_buf); } } - diff --git a/sim_tmxr.h b/sim_tmxr.h index 72826a04..18c00fd5 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -26,8 +26,11 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 10-Oct-12 MP Added extended attach support for serial, per line + listener and outgoing connections 17-Jan-11 MP Added buffered line capabilities 20-Nov-08 RMS Added three new standardized SHOW routines + 07-Oct-08 JDB Added serial port support to TMXR, TMLN 27-May-08 JDB Added lnorder to TMXR structure, added tmxr_set_lnorder and tmxr_set_lnorder 14-May-08 JDB Added dptr to TMXR structure @@ -41,28 +44,60 @@ added tmxr_rqln, tmxr_tqln */ +#include "sim_serial.h" /* We need serial I/O (SERHANDLE) */ + #ifndef _SIM_TMXR_H_ #define _SIM_TMXR_H_ 0 +#include "sim_sock.h" /* We need sockets */ + #define TMXR_V_VALID 15 #define TMXR_VALID (1 << TMXR_V_VALID) #define TMXR_MAXBUF 256 /* buffer size */ #define TMXR_GUARD 12 /* buffer guard */ +#define TMXR_DTR_DROP_TIME 500 /* milliseconds to drop DTR for 'pseudo' modem control */ +#define TMXR_CONNECT_POLL_INTERVAL 1000 /* milliseconds between connection polls */ + #define TMXR_DBG_XMT 0x10000 /* Debug Transmit Data */ #define TMXR_DBG_RCV 0x20000 /* Debug Received Data */ +#define TMXR_DBG_ASY 0x40000 /* Debug Asynchronous Activities */ +#define TMXR_DBG_TRC 0x80000 /* Debug trace routine calls */ + +/* Modem Control Bits */ + +#define TMXR_MDM_DTR 0x01 /* Data Terminal Ready */ +#define TMXR_MDM_RTS 0x02 /* Request To Send */ +#define TMXR_MDM_DCD 0x04 /* Data Carrier Detect */ +#define TMXR_MDM_RNG 0x08 /* Ring Indicator */ +#define TMXR_MDM_CTS 0x10 /* Clear To Send */ +#define TMXR_MDM_DSR 0x20 /* Data Set Ready */ +#define TMXR_MDM_INCOMING (TMXR_MDM_DCD|TMXR_MDM_RNG|TMXR_MDM_CTS|TMXR_MDM_DSR) /* Settable Modem Bits */ +#define TMXR_MDM_OUTGOING (TMXR_MDM_DTR|TMXR_MDM_DTR) /* Settable Modem Bits */ + +/* Unit flags */ + +#define TMUF_V_NOASYNCH (UNIT_V_UF + 12) /* Asynch Disabled unit */ +#define TMUF_NOASYNCH (1u << TMUF_V_NOASYNCH) /* This flag can be defined */ + /* statically in a unit's flag field */ + /* This will disable the unit from */ + /* supporting asynchronmous mux behaviors */ typedef struct tmln TMLN; typedef struct tmxr TMXR; struct tmln { SOCKET conn; /* line conn */ - uint32 ipad; /* IP address */ + char *ipad; /* IP address */ + SOCKET master; /* line specific master socket */ + char *port; /* line specific listening port */ + int32 sessions; /* count of tcp connections received */ uint32 cnms; /* conn time */ int32 tsta; /* Telnet state */ int32 rcve; /* rcv enable */ int32 xmte; /* xmt enable */ int32 dstb; /* disable Tlnt bin */ + t_bool notelnet; /* raw binary data (no telnet interpretation) */ int32 rxbpr; /* rcv buf remove */ int32 rxbpi; /* rcv buf insert */ int32 rxcnt; /* rcv count */ @@ -79,29 +114,49 @@ struct tmln { char rbr[TMXR_MAXBUF]; /* rcv break */ char *txb; /* xmt buffer */ TMXR *mp; /* back pointer to mux */ + char *serconfig; /* line config */ + SERHANDLE serport; /* serial port handle */ + t_bool ser_connect_pending; /* serial connection notice pending */ + SOCKET connecting; /* Outgoing socket while connecting */ + char *destination; /* Outgoing destination address:port */ + UNIT *uptr; /* input polling unit (default to mp->uptr) */ + UNIT *o_uptr; /* output polling unit (default to lp->uptr)*/ }; struct tmxr { int32 lines; /* # lines */ - int32 port; /* listening port */ + char *port; /* listening port */ SOCKET master; /* master socket */ TMLN *ldsc; /* line descriptors */ int32 *lnorder; /* line connection order */ DEVICE *dptr; /* multiplexer device */ + UNIT *uptr; /* polling unit (connection) */ char logfiletmpl[FILENAME_MAX]; /* template logfile name */ int32 buffered; /* Buffered Line Behavior and Buffer Size Flag */ + int32 sessions; /* count of tcp connections received */ + uint32 last_poll_time; /* time of last connection poll */ + t_bool notelnet; /* default telnet capability for incoming connections */ + t_bool modem_control; /* multiplexer supports modem control behaviors */ }; int32 tmxr_poll_conn (TMXR *mp); -void tmxr_reset_ln (TMLN *lp); +t_stat tmxr_reset_ln (TMLN *lp); int32 tmxr_getc_ln (TMLN *lp); void tmxr_poll_rx (TMXR *mp); t_stat tmxr_putc_ln (TMLN *lp, int32 chr); void tmxr_poll_tx (TMXR *mp); +int32 tmxr_send_buffered_data (TMLN *lp); t_stat tmxr_open_master (TMXR *mp, char *cptr); t_stat tmxr_close_master (TMXR *mp); t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr); t_stat tmxr_detach (TMXR *mp, UNIT *uptr); +t_stat tmxr_set_modem_control_passthru (TMXR *mp); +t_stat tmxr_clear_modem_control_passthru (TMXR *mp); +t_stat tmxr_set_get_modem_bits (TMLN *lp, int32 bits_to_set, int32 bits_to_clear, int32 *incoming_bits); +t_stat tmxr_set_config_line (TMLN *lp, char *config); +t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll); +t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll); +t_stat tmxr_set_console_input_unit (UNIT *uptr); t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat tmxr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); void tmxr_msg (SOCKET sock, char *msg); @@ -119,7 +174,16 @@ t_stat tmxr_show_lnorder (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat tmxr_show_summ (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat tmxr_show_cstat (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat tmxr_show_lines (FILE *st, UNIT *uptr, int32 val, void *desc); -void tmxr_debug (uint32 dbits, TMLN *lp, const char *msg, char *buf, int bufsize); +t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, char* desc); +t_stat tmxr_startup (void); +t_stat tmxr_shutdown (void); +t_stat tmxr_start_poll (void); +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->dptr && ((dbits) & (lp)->mp->dptr->dctrl)) _tmxr_debug (dbits, lp, msg, buf, bufsize); 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, "%s\n", (msg)); else (void)0 #endif