4040#define UNIT_M_DTYPE 3
4141#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
4242#define GET_DTYPE (x ) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
43+ #define UNIT_V_NCP (UNIT_V_UF + 3) /* NCP flag */
44+ #define UNIT_NCP (1 << UNIT_V_NCP)
4345
4446#define TYPE_MIT 0 /* MIT Style KAIMP ITS */
4547#define TYPE_BBN 1 /* BBN style interface TENEX */
@@ -475,13 +477,15 @@ struct imp_device {
475477 struct imp_stats stats ;
476478 uint8 sbuffer [ETH_FRAME_SIZE ]; /* Temp send buffer */
477479 uint8 rbuffer [ETH_FRAME_SIZE ]; /* Temp receive buffer */
480+ int rpos ;
478481 ETH_DEV etherface ;
479482 ETH_QUE ReadQ ;
480483 int imp_error ;
481484 int host_error ;
482485 int rfnm_count ; /* Number of pending RFNM packets */
483486 int pia ; /* PIA channels */
484487 struct arp_entry arp_table [IMP_ARPTAB_SIZE ];
488+ int32 link ; /* Link for UDP. */
485489} imp_data ;
486490
487491extern int32 tmxr_poll ;
@@ -541,6 +545,16 @@ const char *imp_description (DEVICE *dptr);
541545static char * ipv4_inet_ntoa (struct in_addr ip );
542546static int ipv4_inet_aton (const char * str , struct in_addr * inp );
543547
548+ #define MAXDATA 16348
549+ extern t_stat udp_create (DEVICE * dptr , const char * premote , int32 * pln );
550+ extern t_stat udp_release (DEVICE * dptr , int32 link );
551+ extern t_stat udp_send (DEVICE * dptr , int32 link , uint16 * pdata , uint16 count );
552+ extern int32 udp_receive (DEVICE * dptr , int32 link , uint16 * pdata , uint16 maxbuf );
553+ // Last-IMP-Bit is implemented as an out-of-band flag in UDP_PACKET
554+ #define PFLG_FINAL 00001
555+ // Host or IMP Ready bit.
556+ #define PFLG_READY 00002
557+
544558#if KS
545559uint16 imp_icsr ;
546560uint16 imp_idb ;
@@ -595,6 +609,10 @@ MTAB imp_mod[] = {
595609 "Use DHCP to set IP address" },
596610 { MTAB_XTD |MTAB_VDV , 0 , "DHCPIP" , NULL ,
597611 NULL , & imp_show_dhcpip , NULL , "DHCP info" },
612+ { UNIT_NCP , 0 , NULL , "TCP" , NULL , NULL , NULL ,
613+ "Use TCP/IP protocol" },
614+ { UNIT_NCP , UNIT_NCP , "NCP" , "NCP" , NULL , NULL , NULL ,
615+ "Use NCP protocol" },
598616#if KS
599617 { UNIT_DTYPE , (TYPE_UNI << UNIT_V_DTYPE ), "UNI" , "UNI" , NULL , NULL , NULL ,
600618 "Standard Unibus transfers" },
@@ -860,6 +878,13 @@ static void check_interrupts (UNIT *uptr)
860878 set_interrupt_mpx (DEVNUM , imp_data .pia >> 3 , imp_mpx_lvl + 1 );
861879}
862880
881+ static void imp_send_host_ready (DEVICE * dptr , struct imp_device * imp )
882+ {
883+ t_stat r ;
884+ uint16 data = PFLG_READY ;
885+ r = udp_send (dptr , imp -> link , & data , 1 );
886+ }
887+
863888t_stat imp_devio (uint32 dev , uint64 * data )
864889{
865890 DEVICE * dptr = & imp_dev ;
@@ -893,8 +918,12 @@ t_stat imp_devio(uint32 dev, uint64 *data)
893918 }
894919 if (* data & IMPHEC ) { /* Clear host error. */
895920 /* Only if there has been a CONI lately. */
896- if (last_coni - sim_gtime () < CONI_TIMEOUT )
921+ if (last_coni - sim_gtime () < CONI_TIMEOUT ) {
897922 uptr -> STATUS &= ~IMPHER ;
923+ uptr -> STATUS |= IMPHR ;
924+ if (uptr -> flags & UNIT_NCP )
925+ imp_send_host_ready (dptr , & imp_data );
926+ }
898927 }
899928 if (* data & IMIIHE ) /* Inhibit interrupt on host error. */
900929 uptr -> STATUS |= IMPIHE ;
@@ -1380,6 +1409,35 @@ t_stat imp_tim_srv(UNIT * uptr)
13801409 return SCPE_OK ;
13811410}
13821411
1412+ void
1413+ imp_receive_udp (DEVICE * dev , struct imp_device * imp )
1414+ {
1415+ static uint16 data [MAXDATA ];
1416+ int i ;
1417+ int32 count ;
1418+
1419+ count = udp_receive (dev , imp -> link , data , MAXDATA );
1420+ if (count == 0 )
1421+ return ;
1422+ if (data [0 ] & PFLG_READY )
1423+ imp_unit [0 ].STATUS |= IMPR ;
1424+ else
1425+ imp_unit [0 ].STATUS &= IMPR ;
1426+ for (i = 1 ; i < count ; i ++ ) {
1427+ imp -> rbuffer [imp -> rpos ++ ] = data [i ] >> 8 ;
1428+ imp -> rbuffer [imp -> rpos ++ ] = data [i ] & 0xFF ;
1429+ }
1430+ if ((data [0 ] & PFLG_FINAL ) == 0 || imp -> rpos == 0 )
1431+ return ;
1432+ imp_unit [0 ].STATUS |= IMPIB ;
1433+ imp_unit [0 ].IPOS = 0 ;
1434+ imp_unit [0 ].ILEN = 8 * imp -> rpos ;
1435+ imp -> rpos = 0 ;
1436+ if (!sim_is_active (& imp_unit [0 ]))
1437+ sim_activate (& imp_unit [0 ], 100 );
1438+ return ;
1439+ }
1440+
13831441void
13841442imp_packet_in (struct imp_device * imp )
13851443{
@@ -1389,6 +1447,11 @@ imp_packet_in(struct imp_device *imp)
13891447 int n ;
13901448 int pad ;
13911449
1450+ if (imp_unit [0 ].flags & UNIT_NCP ) {
1451+ imp_receive_udp (& imp_dev , imp );
1452+ return ;
1453+ }
1454+
13921455 if (eth_read (& imp_data .etherface , & read_buffer , NULL ) <= 0 ) {
13931456 /* Any pending packet notifications? */
13941457 if (imp -> rfnm_count != 0 ) {
@@ -1608,6 +1671,24 @@ imp_packet_in(struct imp_device *imp)
16081671 }
16091672}
16101673
1674+ void
1675+ imp_send_udp (struct imp_device * imp , int len )
1676+ {
1677+ static uint16 data [MAXDATA ];
1678+ t_stat r ;
1679+ int i , j ;
1680+
1681+ data [0 ] = PFLG_FINAL ;
1682+ if ((imp_unit [0 ].STATUS & IMPHER ) == 0 )
1683+ data [0 ] |= PFLG_READY ;
1684+
1685+ for (i = 0 , j = 0 ; i < len /2 ; i ++ , j += 2 )
1686+ data [i + 1 ] = (imp -> sbuffer [j ] << 8 ) + imp -> sbuffer [j + 1 ];
1687+ if (len & 1 )
1688+ data [i + 1 ] = imp -> sbuffer [j ] << 8 ;
1689+ r = udp_send (& imp_dev , imp -> link , data , ((uint16 )len + 3 )/2 );
1690+ }
1691+
16111692void
16121693imp_send_packet (struct imp_device * imp , int len )
16131694{
@@ -1619,6 +1700,12 @@ imp_send_packet (struct imp_device *imp, int len)
16191700 int lk ;
16201701 int mt ;
16211702
1703+ if (imp_unit [0 ].flags & UNIT_NCP ) {
1704+ imp_send_udp (imp , len );
1705+ sim_activate (uptr , tmxr_poll );
1706+ return ;
1707+ }
1708+
16221709 lk = 0 ;
16231710 n = len ;
16241711 switch (imp -> sbuffer [0 ] & 0xF ) {
@@ -3132,6 +3219,16 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr)
31323219 char * tptr ;
31333220 char buf [32 ];
31343221
3222+ if (cptr == NULL || * cptr == 0 )
3223+ return SCPE_ARG ;
3224+
3225+ if (uptr -> flags & UNIT_NCP ) {
3226+ status = udp_create (& imp_dev , cptr , & imp_data .link );
3227+ if (status != SCPE_OK )
3228+ return status ;
3229+ imp_data .rpos = 0 ;
3230+ }
3231+
31353232#if !KS
31363233 /* Set to correct device number */
31373234 switch (GET_DTYPE (imp_unit [0 ].flags )) {
@@ -3146,6 +3243,16 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr)
31463243 break ;
31473244 }
31483245#endif
3246+
3247+ /* Start out in a "host not ready" state. */
3248+ uptr -> STATUS &= ~IMPHR ;
3249+
3250+ if (uptr -> flags & UNIT_NCP ) {
3251+ /* Don't do the Ethernet stuff below. */
3252+ uptr -> flags |= UNIT_ATT ;
3253+ return SCPE_OK ;
3254+ }
3255+
31493256 if (!(uptr -> flags & UNIT_DHCP ) && imp_data .ip == 0 )
31503257 return sim_messagef (SCPE_NOATT , "%s: An IP Address must be specified when DHCP is disabled\n" ,
31513258 imp_dev .name );
@@ -3227,17 +3334,20 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr)
32273334
32283335t_stat imp_detach (UNIT * uptr )
32293336{
3230-
32313337 if (uptr -> flags & UNIT_ATT ) {
3338+ if (uptr -> flags & UNIT_NCP )
3339+ udp_release (& imp_dev , imp_data .link );
32323340 /* If DHCP, release our IP address */
3233- if (uptr -> flags & UNIT_DHCP ) {
3341+ else if (uptr -> flags & UNIT_DHCP ) {
32343342 imp_dhcp_release (& imp_data );
32353343 }
32363344 sim_cancel (uptr + 1 ); /* stop the packet timing services */
32373345 sim_cancel (uptr + 2 ); /* stop the clock timer services */
3238- eth_close (& imp_data .etherface );
3239- free (uptr -> filename );
3240- uptr -> filename = NULL ;
3346+ if (!(uptr -> flags & UNIT_NCP )) {
3347+ eth_close (& imp_data .etherface );
3348+ free (uptr -> filename );
3349+ uptr -> filename = NULL ;
3350+ }
32413351 uptr -> flags &= ~UNIT_ATT ;
32423352 }
32433353 return SCPE_OK ;
@@ -3260,6 +3370,13 @@ fprintf (st, "GW points to the default\nrouter. If DHCP is enabled these ");
32603370fprintf (st , "will be set from DHCP when the IMP is attached.\nIf IP is set " );
32613371fprintf (st , "and DHCP is enabled, when the IMP is attached it will inform\n" );
32623372fprintf (st , "the local DHCP server of it's address.\n\n" );
3373+ fprintf (st , "There is a second way to interact with a network.\n" );
3374+ fprintf (st , "If the NCP modifier is enabled, you must ATTACH\n" );
3375+ fprintf (st , "the IMP device to <local port>:<host>:<remote port>\n" );
3376+ fprintf (st , "It is expected that there is an IMP emulator at <host>\n" );
3377+ fprintf (st , "listening to <remote port> and talking to the PDP-10\n" );
3378+ fprintf (st , "at <local port>. This network will only accept the NCP\n" );
3379+ fprintf (st , "protocol that existed before TCP/IP.\n" );
32633380fprint_set_help (st , dptr );
32643381fprint_show_help (st , dptr );
32653382eth_attach_help (st , dptr , uptr , flag , cptr );
0 commit comments