Source code for /engineering/bos/BOS.COriginal file BOS.C
   1 /*
   2 	BattleOS : Engage battling programs.
   3 
   4 	Copyright (C) 1993 Erich P Gatejen    ALL RIGHTS RESERVED
   5 
   6 	Version  : 1.0
   7 
   8 	File     : BOS.C
   9 	Purpose  : Program code for the Battle Operating System
  10 
  11 */
  12 
  13 
  14 /* -------- INCLUDE Files ------------------------------------------------*/
  15 #include<stdlib.h>
  16 #include<stdio.h>
  17 #include<conio.h>
  18 #include<alloc.h>
  19 #include<time.h>
  20 #include<string.h>
  21 #include<bios.h>
  22 #include<dos.h>
  23 #include<dir.h>
  24 #include"bos.h"
  25 #include"bosmsg.h"
  26 
  27 
  28 /* -------- DEFINES ------------------------------------------------------*/
  29 #define   CTOKENHI			256  /* MMI Token defines 			  */
  30 #define   NOCMDTOKEN		  0
  31 
  32 
  33 /* -------- COMMAND TOKENS -----------------------------------------------*/
  34 #define   CEXIT		    ( 'e' * CTOKENHI ) + 'x'  /* EXit		    */
  35 #define   CLOAD		    ( 'l' * CTOKENHI ) + 'o'  /* LOad program    */
  36 #define   CLIST		    ( 'l' * CTOKENHI ) + 'i'  /* LIst progs      */
  37 #define   CSLIST             ( 's' * CTOKENHI ) + 'l'  /* System List     */
  38 #define   CSET               ( 's' * CTOKENHI ) + 'e'  /* SEt system pars */
  39 #define   CCORE              ( 'c' * CTOKENHI ) + 'o'  /* COre listing    */
  40 #define   CSPAWN		    ( 's' * CTOKENHI ) + 'p'  /* Spawn a program */
  41 #define   CHOLD              ( 'h' * CTOKENHI ) + 'o'  /* HOld a program  */ 
  42 #define   CRELEASE           ( 'r' * CTOKENHI ) + 'e'  /* RElease program */
  43 #define   CSHOLD             ( 's' * CTOKENHI ) + 'h'  /* SHold program   */
  44 #define   CCHECKP	         ( 'c' * CTOKENHI ) + 'h'  /* CHeck point     */
  45 #define   CCRESTORE          ( 'c' * CTOKENHI ) + 'r'  /* Check pnt restore */
  46 #define   CCLEAR             ( 'c' * CTOKENHI ) + 'l'  /* CLear programs  */
  47 #define   CDISK              ( 'd' * CTOKENHI ) + 'i'  /* DIsk prog list  */
  48 
  49 /* -------- GLOBALS ------------------------------------------------------*/
  50    struct Instr	far *Core;	/* Pointer to main core */
  51 
  52    unsigned int    	CoreSize;		/* Core size in instructions      */
  53 
  54    struct PCB		PCBList[MAXPCB];	 /* Program Control Block list     */
  55    char			MMICmnd[MAXCMDSIZE]; /* User input command	    */
  56    unsigned char    MMICmndPtr;		 /* Pointer into ^		    */
  57    unsigned char    MMICmndArgs;		 /* Number of arguments to a
  58 								    MMI command		    */
  59    ArgText		MMIList[MAXARGS];    /* Parsed MMI arguments	    */
  60 
  61    unsigned int     MemoryUsed;	/* RAM needed to build core	    */
  62 
  63    int			NumProgScheduled = 0, /* Number of programs scheduled  */
  64 				NumProgHeld      = 0, /* Number of programs held       */
  65 				NumProgWait      = 0, /* Number of programs waiting    */
  66 				TimersActive     = 0; /* Number of timers active       */
  67 
  68    int			WaitPending	  = NOHANDLE,
  69 				WaitPending2     = NOHANDLE; /* Wait trip pending flag */
  70 
  71    /* -- The following are changable system settings			 -- */
  72     
  73    int 		ProgDistance   = 100;   /* Minimum distance between progs*/
  74    int		DistanceTrys   = 5;     /* Max tries to find region	  */
  75    int         MsgMode        = TIMEM; /* Message format type to use    */
  76 
  77    long		TotalClocks    = 0;	    /* Number of clocks so far executed */
  78 
  79    int		CriticalError  = NOERROR; /* Flag for critical error     */
  80    int         DisplayTaunts  = TRUE;  /* Flag if to display taunts     */
  81 
  82    #include "instname.h" /* Includes the instruction name table (array) */
  83 
  84    /* -- Log file variables 									  */
  85    FILE		*LogFile		= NULL;
  86    int		LogActive		= FALSE;
  87 
  88 
  89 /* -------- FUNCTION prototypes  -----------------------------------------*/
  90 char	 *FindWS( char  *String );
  91 char  *FindNonWS( char  *String );
  92 unsigned int  CalcAddr( unsigned int  Addr, int  Offset );
  93 struct Instr   far *CoreAddr( unsigned int  Offset );
  94 struct Instr   far *CoreAddrC( unsigned int  Offset );
  95 void   ClearCore( void );
  96 int	  FindProg( char *String );
  97 int    ParseCommand( void );
  98 unsigned char  LoadProgram( unsigned char  *String );
  99 void   SimpleList( void );
 100 void   NormalList( void );
 101 void   SystemList( void );
 102 void   CoreList(  void );
 103 void   SetSystem( void );
 104 void   Spawn(       char  *Name  );
 105 void   HoldProg(    char  *Name  );
 106 void   ReleaseProg( char  *Name  );
 107 struct Instr  GetValue( int  PCB, unsigned char  OpToken, int  Operand );
 108 unsigned int   GetAddr( int  PCB, unsigned char  OpToken, int  Operand,
 109 				    int  IFlag );
 110 void  LoadRegister( int  PCB, struct Instr  Value, int Register );
 111 void  KillProgram( int PCB );
 112 unsigned int  CreateCore ( char *Size );
 113 int	 DoCommand( unsigned int	Token );
 114 int   CritCmndEntry( void );
 115 int   DoKeyPress( void );
 116 void  ExecInstruction ( int	PCB );
 117 void  Scheduler ( void );
 118 void  Master    ( void );
 119 int   CheckPoint( char  *File );
 120 int   RestoreCP(  char  *File );
 121 void  ClearProgram( char*  Name );
 122 void  DiskList ( void );
 123 
 124 
 125 /* -------- COMMON Routines ----------------------------------------------*/
 126 
 127 
 128 
 129 /* --- FindWS -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  */
 130 /* Return pointer to first whitespace in string passed */
 131 char	 *FindWS( char  *String ) {
 132 
 133    while ( (*String != 32)&&(*String != 9)&&(*String != NULL)&&
 134 		 (*String != '\n' ) ) {
 135 
 136 	    String++;
 137 
 138    }; /* end while */
 139 
 140    return( String );
 141 
 142 }; /* end FindWS */
 143 
 144 
 145 /* --- FindNonWS -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  */
 146 /* Return pointer to first non-whitespace in string passed */
 147 char  *FindNonWS( char  *String ) {
 148 
 149    while ( (*String == 32)||(*String == 9) ) {
 150 
 151 	 String++;
 152 
 153    }; /* end while */
 154 
 155    return( String );
 156 
 157 }; /* end FindNonWS */
 158 
 159 
 160 /* --- CalcAddr  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
 161 /* Will calculate an address doing any neccessary wraping			   */
 162 unsigned int  CalcAddr( unsigned int  Addr, int  Offset ) {
 163 
 164    long	EAddr;
 165 
 166    /* Add the offset to address and put in long */
 167    EAddr = Addr + Offset;
 168 
 169    /* While it is negative, add coresize to wrap */
 170    while ( EAddr < 0 ) {
 171 	 EAddr = CoreSize + EAddr;
 172    };
 173 
 174    /* While it is over coresize, subtract coresize to wrap */
 175    while ( EAddr >= CoreSize ) {
 176 	 EAddr = EAddr - CoreSize;
 177    };
 178 
 179    /* Move EAddr into the Addr */
 180    Addr = EAddr;
 181 
 182    /* Return */
 183    return( Addr );
 184 
 185 }; /* end CalcAddr */
 186 
 187 
 188 /* --- CoreAddr  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
 189 /* Will convert an integer address into a core memory address            */
 190 struct Instr   far *CoreAddr( unsigned int  Offset ) {
 191 
 192    struct Instr  far *CoreAddr;
 193 
 194    CoreAddr = Core + Offset; 
 195 
 196    return( CoreAddr );
 197 
 198 }; /* end CoreAddr */                                                      
 199 
 200 
 201 /* --- CoreAddrC    -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  - */
 202 /* Will convert an integer address into a core memory address and will check
 203    for a wait set on that address.  If it does, it will set the wait
 204    pending for a PCB										   */
 205 struct Instr   far *CoreAddrC( unsigned int  Offset ) {
 206 
 207    struct Instr  far *CoreAddr;
 208 
 209    CoreAddr = Core + Offset; 
 210 
 211    /* Check for a wait */
 212    if ( CoreAddr->OwnerHandl >= WAITFLAG ) {
 213 
 214 	 /* Yes!!, Clear the wait */
 215 	 CoreAddr->OwnerHandl = CoreAddr->OwnerHandl - WAITFLAG;
 216 
 217 	 /* See if WaitPending is in use, if so use WaitPending2 */
 218 	 if ( WaitPending == NOHANDLE )
 219 
 220 	    /* Set the flag with the owner handle */
 221 	    WaitPending = CoreAddr->OwnerHandl;
 222 
 223 	 else
 224 
 225 	    /* Set the flag with the owner handle, use second flag */
 226 	    WaitPending2 = CoreAddr->OwnerHandl;
 227 
 228       /* end if */
 229 
 230    }; /* end if */
 231 
 232    return( CoreAddr );
 233 
 234 }; /* end CoreAddrC */
 235 
 236 
 237 /* --- ClearCore -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  */
 238 void  ClearCore() {
 239 
 240    unsigned int  Step;
 241 
 242    struct Instr  far *Temp,
 243 				 Dummy;
 244 
 245    /* Build dummy */
 246    Dummy.Token      = DAT;
 247    Dummy.OpToken    = 0;
 248    Dummy.Operand1   = 0;
 249    Dummy.Operand2   = 0;
 250    Dummy.OwnerHandl = NOHANDLE;
 251 
 252    /* Loop through entire core.  Make all 0 data instructions and
 253 	 give no owner											    */
 254    for ( Step = 0; Step < CoreSize; Step++ ) {
 255 
 256 	 Temp  = CoreAddr( Step );
 257 	 *Temp = Dummy;
 258 
 259    }; /* end for */
 260 
 261 }; /* end ClearCore */
 262 
 263 
 264 /* --- FindProg  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  */
 265 int	FindProg( char *String ) {
 266 
 267    int    Step;
 268    char   BufferI[30],
 269 		BufferL[15];
 270 
 271 
 272    /* Load the in buffer and insure lower case */
 273    Step = 0;
 274    while( *String != NULL ) {
 275 	 BufferI[Step] = *String;
 276 	 String++;
 277 	 Step++;
 278    };
 279 
 280    BufferI[Step] = NULL;
 281    strlwr( BufferI );
 282 
 283    /* Find program by name */
 284    for ( Step = MINPCB; Step < MAXPCB; Step++ ) {
 285 
 286 	 /* Move name into buffer */
 287 	 strcpy( BufferL, PCBList[Step].ProgramName );
 288 
 289 	 /* Lowercase the buffer */
 290 	 strlwr( BufferL );
 291 
 292 	 /* Does this PCB name match?  */
 293 	 if ( strcmp( BufferL, BufferI ) == 0 )
 294 
 295 	    /* Found */
 296 	    return( Step);
 297 
 298    }; /* end FindProg */
 299 
 300    /* Never found */
 301    return( NOHANDLE );
 302 
 303 }; /* end FindProg */
 304 
 305 
 306 /* -------- COMMAND Routines ---------------------------------------------*/
 307 
 308 /* --- ParseCommand ------------------------------------------------------*/
 309 /* This function will parse the MMI command string.  If it finds an error
 310    it will return NOCMDTOKEN.									    */
 311 int  ParseCommand() {
 312 
 313    #define	FIRSTCHAR		0
 314    #define     SECONDCHAR     1
 315 
 316 
 317    int	Step = 0;			/* Used to walk the MMI command text	    */
 318    int    Arg  = 0;			/* Current Arg                              */
 319    int    ArgS = 0; 		/* Used to move data into arg list		    */
 320 
 321    unsigned int	Token;    /* Command token					    */
 322 
 323 
 324    /* Check for a null in first two characters */
 325    if ( (MMICmnd[FIRSTCHAR] == NULL)||(MMICmnd[SECONDCHAR] == NULL) ) {
 326 
 327 	 /* if so, the no command was entered */
 328 	 BOSMsg("No command entered\n\r");
 329 	 return( NOCMDTOKEN );
 330 
 331    }; /* end if */
 332 
 333    /* Now, lower case the mmi command text */
 334    strlwr( MMICmnd );
 335 
 336    /* Create value to commpare with command token. */
 337    Token = ( MMICmnd[FIRSTCHAR] * CTOKENHI ) + MMICmnd[SECONDCHAR];
 338 
 339    /* Find the end(NULL) or whitespace */
 340    while  ( (MMICmnd[Step] != ' ') && (MMICmnd[Step] != '\t') &&
 341 		  (MMICmnd[Step] != NULL ) ) {
 342 	 Step++;
 343    }; /* end while */
 344 
 345    /* Find the first non whitespace    */
 346    while  ( ((MMICmnd[Step] == ' ')||(MMICmnd[Step] == '\t'))&&
 347 		   (MMICmnd[Step] != NULL ) ) {
 348 	 Step++;
 349    }; /* end while */
 350 
 351    /* Peal off the arguments. If maxargs of first char is null, end */
 352    while ( (Arg < MAXARGS) && (MMICmnd[Step] != NULL ) ) {
 353 
 354 	 ArgS = 0;
 355 	 /* Move data into arg, move until limit, ws, or null */
 356 	 while ( (MMICmnd[Step] != ' ') &&(MMICmnd[Step] != '\t')&&
 357 		    (MMICmnd[Step] != NULL) ) {
 358 
 359 	    /* Move the character */
 360 	    MMIList[Arg][ArgS] = MMICmnd[Step];
 361 
 362 	    /* Increment indexes */
 363 	    Step++;
 364 	    ArgS++;
 365 
 366 	    /* If the maximum argument size has been reached, then find next
 367 		  whitespace or null in command and break out of while			*/
 368 	    if ( ArgS ==  MAXARGSIZE ) {
 369 
 370 		  /* Find NULL or whitespace */
 371 		  while  ( (MMICmnd[Step] != ' ') && (MMICmnd[Step] != '\t') &&
 372 		           (MMICmnd[Step] != NULL ) ) {
 373 	       Step++;
 374             }; /* end while */
 375 
 376 		  /* break out of while */
 377 		  break;
 378 
 379          }; /* end if */
 380 
 381       }; /* end while */
 382 
 383 	 /* NULL terminate argument text */
 384 	 MMIList[Arg][ArgS] = NULL;
 385 
 386 	 /* Find next non whitespace */
 387 	 while  ( ((MMICmnd[Step] == ' ')||(MMICmnd[Step] == '\t'))&&
 388 			(MMICmnd[Step] != NULL) ) {
 389 	    Step++;
 390 	 }; /* end while */
 391 
 392 	 /* Goto next argument */
 393 	 Arg++;
 394 
 395    }; /* end while */
 396 
 397    /* Save number of arguments */
 398    MMICmndArgs = Arg;
 399 
 400    /* Return the token */
 401    return( Token );
 402 
 403 }; /* end ParseCommand */
 404 
 405 
 406 /* --- LoadProgram -------------------------------------------------------*/
 407 /* This func will load a program into core. It returns the handle assigned
 408    the program.  Note if a prior instence of the program is loaded then
 409    it's text name will be appended with it's instance number (CFZ).  No
 410    more then 10 instances of the same program may be loaded			    */
 411 unsigned char  LoadProgram( unsigned char  *String ) {
 412 
 413    char	FileName[14];  /* Programs file name */
 414    int	Step, Step1;
 415 
 416    FILE   *InFile;		/* File struct */
 417 
 418    char	Temp;		/* Temp character */
 419    int    ProgSize;      /* Program size   */
 420    char	ProgName[PROGNAMESIZE];      /* Program name */
 421    char   HandleText[PNameHandle + 1]; /* Program handle text */
 422 
 423    int    Handle = NOHANDLE;		
 424    unsigned int	Region, RegionT,	/* Location to place program */
 425                     FrontT, EndT;		/* Test locations		    */
 426 
 427    int    Found;                        /* Region found flag */
 428 
 429    struct Instr  far *CorePtr;          /* Pointer into the core     */
 430 
 431 
 432    /* If string points to an eoln or NULL then no filename, ERROR */
 433    if ( (*String == '\n') || (*String == NULL) ) {
 434 
 435 	 /* Error message */
 436 	 BOSMsg("'LOad program' ERROR: No filename specified.\n\r");
 437 
 438 	 /* Return no handle, indicating an error */
 439 	 return( NOHANDLE );
 440 
 441    }; /* end if */
 442 
 443    /* See if there is a PCB available */
 444    Step = 0;
 445    while ( Step < MAXPCB ) {
 446 
 447 	 /* See if space available */
 448 	 if ( PCBList[Step].State == UNUSED ) {
 449 	    Handle = Step;
 450 	    break;
 451 
 452 	 };
 453 
 454 	 /* Inc step */
 455 	 Step++;
 456 
 457    }; /* end while */
 458 
 459    /* Was no place found, error if so */
 460    if ( Handle == NOHANDLE ) {
 461 
 462 	 /* Send error message */
 463 	 BOSMsg("'LOad program' ERROR: maximum programs already loaded.\n\r");
 464 
 465 	 /* return no handle */
 466 	 return( NOHANDLE );
 467 
 468    }; /* end if */
 469 
 470    /* Peal off the file name */
 471    Step = 0;
 472    while( (*String != '\n') && (*String != NULL) && (*String != '.') &&
 473 		(Step < 8) ) {
 474 
 475 		/* Tranfer char */
 476 		FileName[Step] = *String;
 477 
 478 		/* Increment character pointers */
 479 		String++;
 480 		Step++;
 481 
 482    }; /* end while */
 483 
 484    /* Add extention and NULL to file name */
 485    FileName[Step]   = '.';
 486    FileName[Step+1] = 'B';
 487    FileName[Step+2] = 'O';
 488    FileName[Step+3] = 'S';
 489    FileName[Step+4] = NULL;
 490 
 491    /* Open the file, if error then report and return */
 492    if (( InFile = fopen( FileName, "rb" ) ) == NULL ) {
 493 
 494 	 /* Can't open file */
 495 	 BOSMsg("'LOad program' ERROR: Bad filename\n\r");
 496 
 497 	 /* Return no handle, indicating an error */
 498 	 return( NOHANDLE );
 499 
 500    }; /* end if */
 501 
 502    /* Read the version discriptor byte.  If newer version then error */
 503    Temp = fgetc(InFile);
 504    if ( Temp > VERSIONDISC ) {
 505 
 506 	 /* Can't open file */
 507 	 BOSMsg("'LOad program' ERROR: Program needs newer version of BOS\n\r");
 508 
 509 	 /* Close file */
 510 	 fclose( InFile );
 511 
 512 	 /* Return no handle, indicating an error */
 513 	 return( NOHANDLE );
 514 
 515    }; /* end if */
 516 
 517    /* Move past copyright notice in file, check for error */
 518    if ( fseek( InFile, NOTICESIZE, SEEK_CUR ) ) {
 519 
 520 	 /* Can't open file */
 521 	 BOSMsg("'LOad program' ERROR: Program file is corrupted\n\r");
 522 
 523 	 /* Close file */
 524 	 fclose( InFile );
 525 
 526 	 /* Return no handle, indicating an error */
 527 	 return( NOHANDLE );
 528 
 529    }; /* end if */
 530 
 531    /* Get the program size */
 532    fread(&ProgSize, sizeof(int), 1, InFile );
 533 
 534    /* See if we can find a suitable region, pick a random spot and
 535 	 make sure it isnt within ProgDistance of another program.  Try
 536 	 this for DistanceTrys times before returning no can do	    */
 537 
 538    for ( Step = 0; Step < DistanceTrys; Step++ ) {
 539 
 540 	 /* Assume it will be found */
 541 	 Found = TRUE;
 542 
 543 	 /* Get a random number */
 544 	 Region  = random( CoreSize );
 545 	 RegionT = CalcAddr( Region, ProgSize ); /* find end of program */
 546 
 547 	 /* Loop and check against all other PCBs */
 548 	 for ( Step1 = 0; Step1 < MAXPCB; Step1++ ) {
 549 
 550 	    /* Only do for PCBs in use */
 551 	    if ( PCBList[Step1].State != UNUSED ) {
 552 
 553 	       /* Calculate this PCBs bounds */
 554 	       FrontT = CalcAddr(  PCBList[Step1].InstrPointer,
 555 					      -PCBList[Step1].ProgSize     );
 556 		  FrontT = CalcAddr(  FrontT, -ProgDistance      );
 557 		  EndT   = CalcAddr(  PCBList[Step1].InstrPointer,
 558 						  PCBList[Step1].ProgSize     );
 559 		  EndT   = CalcAddr(  EndT, ProgDistance         );
 560 
 561 		  /* Which range check is neccessary?  */
 562 		  if ( EndT > FrontT ) {
 563 
 564 			/* Normal check */
 565 			if ( ((Region  <= EndT)&&(Region >= FrontT))||
 566 				((RegionT <= EndT)&&(RegionT >= FrontT)) ) {
 567 
 568 				/* A conflict! */
 569 				Found = FALSE;
 570 
 571 				/* Break out of this loop */
 572 				break;
 573 
 574 			}; /* end if */
 575 
 576 
 577 		  } else
 578 
 579 			/* Program stratles the core boundries, check this way */
 580 			if ( (Region  <= EndT) || (Region >= FrontT) ) {
 581 
 582 				/* A conflict! */
 583 				Found = FALSE;
 584 
 585 				/* Break out of this loop */
 586 				break;
 587 
 588 			}; /* end if */
 589 
 590 		  /* end if ( which check ) */
 591 
 592 	    }; /* end if ( PCB in use? ) */
 593 
 594 	 }; /* end for */
 595 
 596 	 /* if Found is still TRUE, then we have found an appriate spot */
 597 	 if ( Found == TRUE ) break;
 598 
 599    }; /* end for */
 600 
 601    /* Was region finally found? */
 602    if ( Found == FALSE ) {
 603 
 604 	 /* Close file */
 605 	 fclose( InFile );
 606 
 607 	 /* Not found, send error message and return */
 608 	 BOSMsg("'LOad program' ERROR: Unable to secure memory region.\n\r");
 609 	 BOSMsg("'                   : Program '");
 610 	 BOSMsgC( FileName );
 611 	 BOSMsgC( "' not loaded.\n\r");
 612 	 return( NOHANDLE );
 613 
 614    }; /* end if */
 615 
 616    /* Read the program name and taunt list */
 617    fread( &ProgName, sizeof( char ), PROGNAMESIZE, InFile );
 618    fread( &(PCBList[Handle].TauntList), TAUNTSIZE,  TAUNTSNUMBER, InFile );
 619 
 620   /* - Add handle to program name */
 621    Step = 0;
 622    while( (ProgName[Step] != NULL)&&(Step < PNameText) ) {
 623 
 624 	 /* Find place to put handle text */
 625 	 Step++;
 626 
 627    }; /* end while */
 628 
 629    /* Generate handle text and tack it to end of name text */
 630    itoa( Handle, &(ProgName[Step]), 10 );
 631 
 632    /* PutText into PCB */
 633    strcpy( PCBList[Handle].ProgramName, ProgName );
 634 
 635    /* Start setting the other values in the PCB */
 636    PCBList[Handle].InstrPointer = Region;
 637    PCBList[Handle].ProgSize     = ProgSize;
 638    PCBList[Handle].State        = NEW;
 639    PCBList[Handle].WaitPointer  = CoreSize; /* If it equils coresize,     */
 640    PCBList[Handle].TimerPointer = CoreSize; /* it is not in use           */
 641    PCBList[Handle].TickCount    = 0;
 642    PCBList[Handle].TotalClocks  = 0;
 643    PCBList[Handle].WhosCode     = Handle;   /* It's running it's own code */
 644    PCBList[Handle].CoreHeld     = ProgSize;
 645 
 646    /* Do the load of instructions */
 647    for ( Step = 0; Step < ProgSize; Step++ ) {
 648 
 649       /* Get the Address into the core */
 650 	 CorePtr = CoreAddr( Region );
 651 
 652 	 /* Did this location belong to another program? */
 653 	 if ( CorePtr->OwnerHandl != NOHANDLE ) {
 654 
 655 	    /* Yes!  Then decrement the previous owners CoreHeld */
 656 	    PCBList[(CorePtr->OwnerHandl & 0x0f)].CoreHeld--;
 657 
 658 	 }; /* end if */
 659 
 660 	 /* Read instruction into core */
 661 	 fread ( CorePtr, sizeof( struct Instr ), 1, InFile );
 662 	 
 663 	 /* Set owner of core location */
 664 	 CorePtr->OwnerHandl = Handle;
 665 	 
 666 	 /* Increment region address for next read */
 667 	 Region = CalcAddr( Region, 1 );  
 668 
 669    }; /* end for */
 670 
 671    /* Close file */
 672    fclose( InFile );
 673 
 674    /* No apparent problems doing the load! msg and return valid handle */
 675    BOSMsg("Program '");
 676    BOSMsgC( FileName );
 677    BOSMsgC( "' successfully loaded!\n\r");
 678    BOSMsg("Program '");
 679    BOSMsgC( FileName );
 680    BOSMsgC( "' assigned name : ");
 681    BOSMsgC( ProgName );
 682    BOSMsgC("\n\r");
 683 
 684    return( Handle );
 685 
 686 
 687 }; /* end LoadProgram */
 688 
 689 
 690 /* --- SimpleList -------------------------------------------------------*/
 691 /* This function will produce a simple list of all programs loaded       */
 692 void  SimpleList() {
 693 
 694    int	Step;
 695 
 696 
 697    /* Print the BOS ack to the command */
 698    BOSMsg("LIst programs : Simple list processed.\n\r\n\r");
 699 
 700    /* Print simple list header */
 701    BOSMsgC(">>> Simple list of programs loaded.\n\r");
 702    BOSMsgC("|Name         |State   |Next Instruction Addr\n\r");
 703 
 704    /* Go through PBC list and put info for each program */
 705    for ( Step = 0; Step < MAXPCB; Step++ ) {
 706 
 707 	 /* Do only for loaded PCBs */
 708 	 if ( PCBList[Step].State != UNUSED ) {
 709 
 710 	    /* Name */
 711 	    BOSMsgST(" %-13s ", PCBList[Step].ProgramName );
 712 
 713 	    /* Call routine to display the state */
 714 	    DisplayState( PCBList[Step].State );
 715 
 716 	    /* Put next instruction */
 717 	    BOSMsgU(" %u\r\n", PCBList[Step].InstrPointer);
 718 
 719 	 }; /* end if */
 720 
 721    }; /* end for */
 722 
 723    /* Put character pads */
 724    cputs("\n\r");
 725 
 726 }; /* end SimpleList */
 727 
 728 
 729 /* --- NormalList -------------------------------------------------------*/
 730 /* This function will produce a normal list of all programs loaded       */
 731 void  NormalList() {
 732 
 733    int	Step;
 734    int    Items = 0;
 735 
 736 
 737    /* Print the BOS ack to the command */
 738    BOSMsg("LIst programs : Normal list processed.\n\r\n\r");
 739 
 740    /* Print list header */
 741    BOSMsgC(">>> List of programs loaded.\n\r");
 742 
 743    /* Go through PCB list and put info for each program */
 744    for ( Step = 0; Step < MAXPCB; Step++ ) {
 745 
 746 	 /* Do only for loaded PCBs */
 747 	 if ( PCBList[Step].State != UNUSED ) {
 748 
 749 	    /* Name and size */
 750 	    BOSMsgST(" Program Name  : %-13s   ", PCBList[Step].ProgramName );
 751 	    BOSMsgU ("Load size: %u\n\r",		  PCBList[Step].ProgSize    );
 752 
 753 	    /* Instruction pointer and State */
 754 	    BOSMsgU(" Instr Pointer : %-5u           State : ",
 755 			  PCBList[Step].InstrPointer );
 756 	    DisplayState( PCBList[Step].State );
 757 	    BOSMsgC("\n\r");
 758 
 759 	    /* Clock timer pointer and tick count, if active */
 760 	    if ( PCBList[Step].TimerPointer != CoreSize ) {
 761 		  BOSMsgU(" Timer Pointer : %-5u", PCBList[Step].TimerPointer );
 762 		  BOSMsgU(" TickCount : %u\r\n", 	PCBList[Step].TickCount );
 763 
 764 	    } else
 765 		  /* no timer */
 766 		  BOSMsgC(" Timer Pointer : Timer not being used.\n\r");
 767 
 768 	    /* end if */
 769 
 770 	    /* Wait pointer and wait site, if active */
 771 	    if ( PCBList[Step].WaitPointer != CoreSize ) {
 772 		  BOSMsgU(" Wait Pointer  : %-5u", PCBList[Step].WaitPointer );
 773 		  BOSMsgU("   Wait Site : %-5u\r\n",	PCBList[Step].WaitSite );
 774 
 775 	    } else
 776 		  /* no timer */
 777 		  BOSMsgC(" Wait Pointer  : Wait not being used.\n\r");
 778 
 779 	    /* end if */
 780          
 781 	    /* Amount of core held */
 782 	    BOSMsgU(" Core owned    : %-5u\n\r", PCBList[Step].CoreHeld );
 783 
 784 	    /* Total clocks for this program */
 785 	    BOSMsgL(" Total clocks  : %lu\n\r\n\r", PCBList[Step].TotalClocks );
 786 
 787 	    /* See if we need to stop and let the user read */
 788 	    Items++;
 789 	    if ( Items == 3 ) {
 790 		  Items = 0;
 791 		  Continue();
 792 	    }; /* end if */
 793 
 794 	 }; /* end if */
 795 
 796    }; /* end for */
 797 
 798    /* Put line pads */
 799    BOSMsgC("\n\r");
 800 
 801 }; /* end NormalList */
 802 
 803 
 804 /* --- SystemList -------------------------------------------------------*/
 805 /* Lists all the system settings								   */
 806 void  SystemList() {
 807 
 808    /* Print the BOS ack to the command */
 809    BOSMsg("SList : System settings list processed.\n\n\r");
 810 
 811    /* Print simple list header */
 812 
 813    BOSMsgC(">>> BOS system settings.\n\r");
 814 
 815    /* Put core size */
 816    BOSMsgU(" Core Size                     : %u\n\r", CoreSize );
 817 
 818    /* Put minimum program load distance */
 819    BOSMsgS(" Minimum program load distance : %d\r\n", ProgDistance );
 820 
 821    /* Put maximum load trys */
 822    BOSMsgS(" Maximum program load tries    : %d\n\r", DistanceTrys );
 823 
 824    /* System clocks */
 825    BOSMsgL(" Total clocks executed         : %ld\n\n\r", TotalClocks );
 826 
 827 }; /* end SystemList */
 828 
 829 
 830 /* --- CoreList -----------------------------------------------------------*/
 831 /* Do a list of core contents.  Arg0 will have the first location to list
 832    from.  Arg1 ( def 16 ) can have the number of addresses to display      */
 833 void  CoreList() {
 834 
 835    long	 	  GetAddr;
 836    unsigned int  BaseAddr,	/* Base Addr to look at        */
 837 			  Number;		/* Number of addresses to list */
 838    int		  Lines;		/* Number off lines displayed  */
 839 
 840    struct Instr  far *Addr;   /* Pointer into core           */
 841    unsigned char Byte, Byte2;
 842 
 843 
 844    /* Get the base address */
 845    GetAddr = atol( MMIList[0] );
 846 
 847    /* If the base address is outsize core range, ERROR! */
 848    if ( (GetAddr < 0 )||(GetAddr >= CoreSize) ) {
 849    
 850 	 /* Not in range, Error */
 851 	 BOSMsg("'COre list' ERROR: Invalid core address!\n\r");
 852 
 853 	 /* DONE!, return. */
 854 	 return;
 855    
 856    }; /* end if */
 857 
 858    /* Transfer to base address var */
 859    BaseAddr = GetAddr;
 860 
 861    /* Get the list length ( use GetAddr long ) */
 862    GetAddr  = atol( MMIList[1] );
 863 
 864    /* If it is 0, then default to 16.  Move it into Number var  */
 865    if ( GetAddr == 0 )
 866 	 
 867 	 /* Default to 16 */
 868 	 Number = 16;
 869 
 870    else
 871 
 872 	 /* Good number   */
 873 	 Number = GetAddr;
 874 
 875    /* end if */
 876 
 877 
 878    /* Put the header writes */
 879    BOSMsg( "'COre list' : List processed.\n\r");
 880    BOSMsgC("\n\rADDR   | TYPE |OPTYPES|  OP1  |  OP2  |T|W| OWNER\n\r");
 881 
 882    /* Init lines number to 16 */
 883    Lines = 16;
 884 
 885    /* OK, ready to loop through */
 886    while( Number > 0 ) {
 887 
 888 	/* -- Put the core address */
 889 	 BOSMsgU( "%07u  ", BaseAddr );
 890 
 891 	 /* Get the core pointer */
 892 	 Addr = CoreAddr( BaseAddr );
 893 
 894 	 /* Get the token */
 895 	 Byte = Addr->Token;
 896 
 897 	 /* Mask all but instruction */
 898 	 Byte = Byte & 0x0F;
 899 
 900 	/* -- Put the instruction type (token, name, whatever ) */
 901 	 BOSMsgC( InstNames[Byte] );
 902 	 BOSMsgC("    ");
 903 
 904 	 /* Get the op token */
 905 	 Byte = Addr->OpToken;
 906 
 907 	 /* Shift down the first token and diplay it */
 908 	 Byte = Byte >> 4;
 909 	 DisplayOpToken( Byte );
 910 
 911 	 /* Put the pad char */
 912 	 BOSMsgC("-");
 913 
 914 	 /* Get the op token */
 915 	 Byte2 = Addr->OpToken;
 916 
 917 	 /* Mask out the second token  and display it */
 918 	 Byte2 = Byte2 & 0x0F;
 919 	 DisplayOpToken( Byte2 );
 920 
 921 	/* -- Put the first operand, if register, indicate that -- */
 922 	 if ( Byte == REG ) {
 923 
 924 	    switch( Addr->Operand1 ) {
 925 
 926 		  case AREGISTER : BOSMsgC("    REG A  ");
 927 					    break;
 928 		  case BREGISTER : BOSMsgC("    REG B  ");
 929 					    break;
 930 		  case CREGISTER : BOSMsgC("    REG C  ");
 931 					    break;
 932 		  case AREGPTR   : BOSMsgC("    REG ^A ");
 933 					    break;
 934 		  case BREGPTR   : BOSMsgC("    REG ^B ");
 935 					    break;
 936 		  case CREGPTR   : BOSMsgC("    REG ^C ");
 937 					    break;
 938 	    }; /* end case */
 939 
 940 	 } else
 941 
 942 	    BOSMsgU( "   %6u  ", Addr->Operand1 );
 943 
 944 	 /* end if */
 945 
 946 	/* -- Put the second operand, if register, indicate that -- */
 947 	 if ( Byte2 == REG ) {
 948 
 949 	    switch( Addr->Operand2 ) {
 950 
 951 		  case AREGISTER : BOSMsgC(" REG A  ");
 952 					    break;
 953 		  case BREGISTER : BOSMsgC(" REG B  ");
 954 					    break;
 955 		  case CREGISTER : BOSMsgC(" REG C  ");
 956 					    break;
 957 		  case AREGPTR   : BOSMsgC(" REG ^A ");
 958 					    break;
 959 		  case BREGPTR   : BOSMsgC(" REG ^B ");
 960 					    break;
 961 		  case CREGPTR   : BOSMsgC("REG ^C  ");
 962 					    break;
 963 	    }; /* end case */
 964 
 965 	 } else
 966 
 967 	    BOSMsgU( "%6u  ", Addr->Operand2 );
 968 
 969 	 /* end if */
 970 
 971 	/* -- If the instruction has a taunt put an X, otherwise a space */
 972 	 if ( Addr->Token >= TauntPresent )
 973 
 974 	    /* Yes, taunt */
 975 	    BOSMsgC("X ");
 976 
 977 	 else
 978 
 979 	    /* No taunt!  */
 980 	    BOSMsgC("  ");
 981 
 982 	 /* end if */
 983 
 984 	 /* Get the owner handle. */
 985 	 Byte = Addr->OwnerHandl;
 986 
 987 	/* -- If there is a wait flag, put X, otherwise space */
 988 	 if ( Byte >= WAITFLAG ) 
 989 	 
 990 	    /* Yes, wait */
 991 	    BOSMsgC("X  ");
 992 
 993 	 else
 994 
 995 	    /* No wait!  */
 996 	    BOSMsgC("   ");
 997 
 998 	 /* end if */
 999 
1000 	 /* Clear off any possible wait flag */
1001 	 Byte = Byte & ( 0xFF - WAITFLAG );
1002 
1003 	/* -- If no handle put BOS, otherwise the owner name */
1004 	 if ( Byte == NOHANDLE )
1005 	 
1006 	    /* No owner */
1007 	    BOSMsgC("BOS");
1008 
1009 	 else
1010 
1011 	    /* Put owners name */
1012 	    BOSMsgC(PCBList[Byte].ProgramName);
1013 
1014 	/* -- Put return */
1015 	 BOSMsgC("\n\r");
1016 
1017 	 /* Next address */
1018 	 BaseAddr = CalcAddr( BaseAddr, 1 );
1019 	 
1020 	 /* Decrement number lines left to do */
1021 	 Number--;
1022 
1023 	 /* Decrement number of lines done */
1024 	 Lines--;
1025 
1026 	 /* See if we need to put pause in */
1027 	 if ( Lines == 0 ) {
1028 
1029 	    /* Yes.  If Continue returns an [ESC] then abort rest of list */
1030 	    if ( Continue() == 27 ) Number = 0;
1031 
1032 	    /* Reset the lines count */
1033 	    Lines = 16;
1034 
1035 	    /* Put the header line again */
1036 	    BOSMsgC("ADDR   | TYPE |OPTYPES|  OP1  |  OP2  |T|W| OWNER\n\r");
1037 
1038 
1039 	 }; /* end if */
1040 
1041    }; /* end while */
1042 
1043    /* Done with list */
1044    BOSMsgC("\n\r");
1045 
1046 }; /* end CoreList */
1047 
1048 
1049 /* --- SetSystem -----------------------------------------------------------*/
1050 /* Sets a variaty of system settings and parameters					 */
1051 void  SetSystem() {
1052 
1053    int	SToken;	/* Setting type token */
1054    int	Temp;
1055 
1056    /* Its own token list for all the possible settings it can do         */
1057    #define   STAUNT	 ( 't' * CTOKENHI ) + 'a'  /* TAunt display          */
1058    #define   SSTAMP  ( 's' * CTOKENHI ) + 't'  /* STamp type for BOSMsg  */
1059    #define   SCLOCK  ( 'c' * CTOKENHI ) + 'l'  /* CLock count 		   */
1060    #define   SDIST   ( 'd' * CTOKENHI ) + 'i'  /* program DIstance       */
1061    #define   STRYS   ( 't' * CTOKENHI ) + 'r'  /* load TRys			   */
1062    #define   SLOG	 ( 'l' * CTOKENHI ) + 'o'  /* set LOg file options   */
1063 
1064    /* Create the setting type token */
1065    SToken = (MMIList[0][0] * CTOKENHI) + MMIList[0][1];
1066 
1067    /* Case through the possible setting types */
1068    switch ( SToken ) {
1069 
1070     case STAUNT  : /* Set whether to display the taunts or not */
1071 			    /* Base on second character of second arg   */
1072 			    switch( MMIList[1][1] ) {
1073 
1074 				 case 'n' :
1075 				 case 'N' : /* Turn them on */
1076 						  BOSMsg("SET TAUNTS : Taunts set ON.\n\r");
1077 						  DisplayTaunts = TRUE;
1078 						  break;
1079 
1080 				 case 'f' :
1081 				 case 'F' : /* Turn them off */
1082 						  BOSMsg("SET TAUNTS : Taunts set OFF.\n\r");
1083 						  DisplayTaunts = FALSE;
1084 						  break;
1085 
1086 				 default  : /* What? */
1087 						   BOSMsg("SET TAUNTS : Must be 'ON' or 'OFF'.\n\r");
1088 						   break;
1089 
1090 			    }; /* end case */
1091 			    break;
1092 
1093 
1094     case SSTAMP  : /* Set which type of stamp to use for BOS messages */
1095 			    /* base on first character of second arg           */
1096 			    switch( MMIList[1][0] ) {
1097 
1098 				 case 'b' :
1099 				 case 'B' : /* Bare. No stamp */
1100 						  MsgMode = BAREM;
1101 						  BOSMsg("SET STAMP : Stamp is bare.\n\r");
1102 						  break;
1103 
1104 				 case 't' :
1105 				 case 'T' : /* Put the time stamp */
1106 						  MsgMode = TIMEM;
1107 						  BOSMsg("SET STAMP : Stamp set to time.\n\r");
1108 						  break;
1109 
1110 				 case 's' :
1111 				 case 'S' : /* Put the system count stamp */
1112 						  MsgMode = SYSCNTM;
1113 					BOSMsg("SET STAMP : Stamp set to system count.\n\r");
1114 						  break;
1115 
1116 				 default  : /* What? */
1117 						   BOSMsg("SET STAMP : Unknown type!\n\r");
1118 						   break;
1119 
1120 			    }; /* end case */
1121 			    break;
1122 
1123 
1124     case SCLOCK  : /* Clock set based on first character of second arg           */
1125 			    switch( MMIList[1][0] ) {
1126 
1127 				 case 'r' :
1128 				 case 'R' : /* Reset the clock */
1129 						  TotalClocks = 0;
1130 						  BOSMsg("SET CLOCK : Clock reset to 0.\n\r");
1131 						  break;
1132 
1133 				 default  : /* What? */
1134 						  BOSMsg("SET CLOCK : Unknown type!\n\r");
1135 						  break;
1136 
1137 			    }; /* end case */
1138 			    break;
1139 
1140     case SDIST  : /* Set program load distance      */
1141 			    Temp = atoi(MMIList[1]);	/* Get the size */
1142 
1143 			   /* Is it valid? */
1144 			   if ( (Temp < 20) || (Temp > (CoreSize/2)) )
1145 
1146 				 /* No!, let the user know. */
1147 				 BOSMsg("SET LOAD DISTANCE : Invalid distance!\n\r");
1148 
1149 			   else {
1150 
1151 				 /* Yes, change it and let user know */
1152 				 ProgDistance = Temp;
1153 				 BOSMsg("SET DISTANCE : Distance set.\r\n");
1154 
1155 			   }; /* end if */
1156 			   break;
1157 
1158     case STRYS  : /* Set program load trys      */
1159 			    Temp = atoi(MMIList[1]);	/* Get the size */
1160 
1161 			   /* Is it valid? */
1162 			   if ( (Temp < 1) || (Temp > 100) )
1163 
1164 				 /* No!, let the user know. */
1165 				 BOSMsg("SET LOAD TRYS : Invalid number of trys!\n\r");
1166 
1167 			   else {
1168 
1169 				 /* Yes, change it and let user know */
1170 				 DistanceTrys = Temp;
1171 				 BOSMsg("SET LOAD TRYS : Number of trys set.\r\n");
1172 
1173 			   }; /* end if */
1174 			   break;
1175 
1176     case SLOG    : /* Set log options					   */
1177 			    /* Base on second character of second arg   */
1178 			    switch( MMIList[1][1] ) {
1179 
1180 				 case 'n' :
1181 				 case 'N' : /* Turn the log on.  Log must be opened */
1182 						  if ( LogFile == NULL ) {
1183 							/* Not open. Error */
1184 							BOSMsg("SET LOG ON : Error! Log not open.\n\r");
1185 						  } else {
1186 							BOSMsg("SET LOG ON : Log set ON.\n\r");
1187 							LogActive = TRUE;
1188 						  };
1189 						  break;
1190 
1191 				 case 'f' :
1192 				 case 'F' : /* Turn the log off.  Log must be on */
1193 						  if ( LogActive == NULL ) {
1194 							/* Not on. Error */
1195 							BOSMsg("SET LOG OFF : Error! Log not on.\n\r");
1196 						  } else {
1197 							BOSMsg("SET LOG OFF : Log set OFF.\n\r");
1198 							LogActive = FALSE;
1199 						  };
1200 						  break;
1201 
1202 				 case 'p' :
1203 				 case 'P' : /* Open a log file.   */
1204 						  fopen;
1205 						  DisplayTaunts = FALSE;
1206 						  break;
1207 
1208 
1209 				 default  : /* What? */
1210 						   BOSMsg("SET TAUNTS : Must be 'ON' or 'OFF'.\n\r");
1211 						   break;
1212 
1213 			    }; /* end case */
1214 			    break;
1215 
1216     default      : /*  Unknown set command */
1217 			    BOSMsg("!ERROR! in SET command : Unknown set type!\n\r");
1218 
1219 
1220    }; /* end case */
1221 
1222 }; /* end SetSystem */
1223 
1224 
1225 /* NOTE: Addresses in registers are absolute!         */
1226 /*       Addresses as memory pointers are relitive!   */
1227 
1228 
1229 /* --- Spawn ---------------------------------------------------------------*/
1230 /* Spawn program 											      */
1231 void  Spawn( char  *Name  ) {
1232 
1233    int	PCB;
1234 
1235    unsigned int  Address,
1236 			  Step;
1237    struct Instr  far *CAddr;
1238 
1239 
1240    /* Call routine to find the PCB, if no PCB, then error */
1241    PCB = FindProg( Name );
1242 
1243    /* If PCB = NOHANLDE then program is not loaded */
1244    if ( PCB == NOHANDLE ) {
1245 
1246 	 /* Error */
1247 	 BOSMsg("'SPawn' ERROR: Program ");
1248 	 BOSMsgC(Name);
1249 	 BOSMsgC(" not loaded!\n\r");
1250 
1251 	 return;
1252 
1253    }; /* end if */
1254 
1255    /* Do different things for different states */
1256    switch( PCBList[PCB].State ) {
1257 
1258 	 case  READY_RUN  : /* Program already spawned */
1259 					BOSMsg("SPawn : Program ");
1260 					BOSMsgC(Name);
1261 					BOSMsgC(" already running.\r\n");
1262 					break;
1263 
1264 	 case  HELD       : /* Program held            */
1265 					BOSMsg("SPawn : Program ");
1266 					BOSMsgC(Name);
1267 					BOSMsgC(" already spawned, but now HELD.\r\n");
1268 					break;
1269 
1270 	 case  WAIT	   : /* Program Waiting         */
1271 					BOSMsg("SPawn : Program ");
1272 					BOSMsgC(Name);
1273 					BOSMsgC(" already spawned, but now WAITing.\r\n");
1274 					break;
1275 
1276 	 case  NEW        : /* Program can be spawned  */
1277 					BOSMsg("SPawn : Program ");
1278 					BOSMsgC(Name);
1279 					BOSMsgC(" running.\r\n");
1280 					PCBList[PCB].State = READY_RUN;
1281 					NumProgScheduled++;
1282 					break;
1283 
1284 	 case  KILLED     : /* Program cannot be spawned */
1285 					BOSMsg("SPawn : Program ");
1286 					BOSMsgC(Name);
1287 					BOSMsgC(" was KILLED.  Cannot be spawned\r\n");
1288 
1289    }; /* end case */
1290 
1291 }; /* end Spawn */
1292 
1293 
1294 
1295 /* --- HoldProg ------------------------------------------------------------*/
1296 /* Hold program 											      */
1297 void  HoldProg( char  *Name  ) {
1298 
1299    int	PCB;
1300 
1301    /* Call routine to find the PCB, if no PCB, then error */
1302    PCB = FindProg( Name );
1303 
1304    /* If PCB = NOHANLDE then program is not loaded */
1305    if ( PCB == NOHANDLE ) {
1306 
1307 	 /* Error */
1308 	 BOSMsgI("'HOld' ERROR: Program ");
1309 	 BOSMsgC( Name );
1310 	 BOSMsgC(" not loaded!\n\r");
1311 	 BOSMsgIDone();
1312 
1313 	 return;
1314 
1315    }; /* end if */
1316 
1317    /* Do different things for different states */
1318    switch( PCBList[PCB].State ) {
1319 
1320 
1321 	 case  WAIT       : /* Do the hold, but for this dec number waiting */
1322 					NumProgWait--;
1323 
1324 	 case  READY_RUN  : /* OK. Hold it */
1325 					BOSMsgI( "HOld : Program ");
1326 					BOSMsgC(Name);
1327 					BOSMsgC(" is held.");
1328 					BOSMsgIDone();
1329 					PCBList[PCB].State = HELD;
1330 
1331 					/* Adjust the counts */
1332 					NumProgScheduled--;
1333 					NumProgHeld++;
1334 
1335 					break;
1336 
1337 	 case  HELD       : /* Program already held            */
1338 					BOSMsgI( "HOld : Program ");
1339 					BOSMsgC(Name);
1340 					BOSMsgC(" is already HELD.");
1341 					BOSMsgIDone();
1342 					break;
1343 
1344 	 case  KILLED     :
1345 	 case  NEW        : /* Program not held  */
1346 					BOSMsgI( "HOld : Program ");
1347 					BOSMsgC(Name);
1348 					BOSMsgC(" is not spawned.  Cannot hold it.");
1349 					BOSMsgIDone();
1350 					break;
1351 
1352    }; /* end case */
1353 
1354 }; /* end HoldProg */
1355 
1356 
1357 /* --- ReleaseProg ---------------------------------------------------------*/
1358 /* Release program 											      */
1359 void  ReleaseProg( char  *Name  ) {
1360 
1361    int	PCB;
1362 
1363    /* Call routine to find the PCB, if no PCB, then error */
1364    PCB = FindProg( Name );
1365 
1366    /* If PCB = NOHANLDE then program is not loaded */
1367    if ( PCB == NOHANDLE ) {
1368 
1369 	 /* Error */
1370 	 BOSMsg("'RElease' ERROR: Program ");
1371 	 BOSMsgC( Name );
1372 	 BOSMsgC(" not loaded!\n\r");
1373 
1374 	 return;
1375 
1376    }; /* end if */
1377 
1378    /* If held, release it. */
1379    if ( PCBList[PCB].State == HELD ) {
1380 
1381 	 /* Yes, it is held */
1382 	 BOSMsg( "RElease : Program ");
1383 	 BOSMsgC(Name);
1384 	 BOSMsgC(" is released.\n\r");
1385 
1386 	 /* Release it */
1387 	 PCBList[PCB].State = READY_RUN;
1388 	 NumProgScheduled++;
1389 	 NumProgHeld--;
1390 
1391    } else {
1392 	 
1393 	 /* Otherwise, cant release it */
1394 	 BOSMsg( "HOld : Program ");
1395 	 BOSMsgC(Name);
1396 	 BOSMsgC(" is not held.  It cannot be released.\n\r");
1397 
1398    }; /* end if */
1399 
1400 }; /* end ReleaseProg */
1401 
1402 
1403 /* --- CheckPoint ----------------------------------------------------------*/
1404 /* Checkpoint the system.  Return TRUE on failure.					 */
1405 int  CheckPoint( char  *String ) {
1406 
1407    FILE	  *CFile;
1408    char     FileName[13];
1409 
1410    int	  Step;
1411 
1412 
1413    /* Peal off the file name */
1414    Step = 0;
1415    while( (*String != '\n') && (*String != NULL) && (*String != '.') &&
1416 		(Step < 8) ) {
1417 
1418 		/* Tranfer char */
1419 		FileName[Step++] = *String++;
1420 
1421    }; /* end while */
1422 
1423    /* Add extention and NULL to file name */
1424    FileName[Step]   = '.';
1425    FileName[Step+1] = 'C';
1426    FileName[Step+2] = 'H';
1427    FileName[Step+3] = 'K';
1428    FileName[Step+4] = NULL;
1429 
1430    /* Open the file, if error then report and return */
1431    if (( CFile = fopen( FileName, "wb" ) ) == NULL ) {
1432 
1433 	 /* Can't open file */
1434 	 BOSMsg("'CHeck point' ERROR: Cannot open file\n\r");
1435 
1436 	 /* Return no handle, indicating an error */
1437 	 return( TRUE );
1438 
1439    }; /* end if */
1440 
1441    /* Write BOS version discriptor and copyright */
1442    fputc( VERSIONDISC,     CFile );
1443    fputs( COPYRIGHTNOTICE, CFile );
1444 
1445    /* Save system variables */
1446    fwrite( &CoreSize,   sizeof( unsigned int ), 1, CFile );
1447    fwrite( &NumProgScheduled, sizeof( int ), 1, CFile );
1448    fwrite( &NumProgHeld, 	sizeof( int ), 1, CFile );
1449    fwrite( &NumProgWait,	     sizeof( int ), 1, CFile );
1450    fwrite( &TimersActive,     sizeof( int ), 1, CFile );
1451    fwrite( &WaitPending,      sizeof( int ), 1, CFile );
1452    fwrite( &WaitPending2,     sizeof( int ), 1, CFile );
1453 
1454    /* Save system settings */
1455    fwrite( &ProgDistance,  sizeof( int ), 1, CFile );
1456    fwrite( &DistanceTrys,  sizeof( int ), 1, CFile );
1457    fwrite( &MsgMode,       sizeof( int ), 1, CFile );
1458    fwrite( &TotalClocks,  sizeof( long ), 1, CFile );
1459    fwrite( &CriticalError, sizeof( int ), 1, CFile );
1460    fwrite( &DisplayTaunts, sizeof( int ), 1, CFile );
1461 
1462    /* Save all PCB that are not UNUSED.  Tag byte for position */
1463    for ( Step = MINPCB; Step < MAXPCB; Step++ )
1464 
1465 	 if ( PCBList[Step].State != UNUSED ) {
1466 
1467 		fputc( Step, CFile);
1468 		fwrite( &(PCBList[Step]), sizeof( struct PCB ), 1, CFile );
1469 
1470 	 }; /* end if */
1471 
1472    /* end for */
1473 
1474    /* Tag end of PCB list */
1475    fputc( MAXPCB, CFile);
1476 
1477    /* Write the core! */
1478    fwrite( Core, sizeof( struct Instr ), CoreSize, CFile );
1479 
1480    /* Close */
1481    fclose( CFile );
1482 
1483    /* Done! */
1484    return( FALSE );
1485 
1486 }; /* end CheckPoint */
1487 
1488 /* --- RestoreCP  ----------------------------------------------------------*/
1489 /* Restore a checkpoint.  Return TRUE on failure.					      */
1490 int  RestoreCP( char  *String ) {
1491 
1492    FILE	  *CFile;
1493    char     FileName[13];
1494 
1495    int	  Step;
1496 
1497 
1498    /* Peal off the file name */
1499    Step = 0;
1500    while( (*String != '\n') && (*String != NULL) && (*String != '.') &&
1501 		(Step < 8) ) {
1502 
1503 		/* Tranfer char */
1504 		FileName[Step++] = *String++;
1505 
1506    }; /* end while */
1507 
1508    /* Add extention and NULL to file name */
1509    FileName[Step]   = '.';
1510    FileName[Step+1] = 'C';
1511    FileName[Step+2] = 'H';
1512    FileName[Step+3] = 'K';
1513    FileName[Step+4] = NULL;
1514 
1515    /* Open the file, if error then report and return */
1516    if (( CFile = fopen( FileName, "rb" ) ) == NULL ) {
1517 
1518 	 /* Can't open file */
1519 	 BOSMsg("'Check point Restore' ERROR: Cannot open file\n\r");
1520 
1521 	 /* Return no handle, indicating an error */
1522 	 return( TRUE );
1523 
1524    }; /* end if */
1525 
1526    Step = fgetc(CFile);
1527    if ( Step > VERSIONDISC ) {
1528 
1529 	 /* Can't open file */
1530 	 BOSMsg("'Check point Restore' ERROR: Incompatable checkpoint file.\n\r");
1531 
1532 	 /* Close file */
1533 	 fclose( CFile );
1534 
1535 	 /* Return no handle, indicating an error */
1536 	 return( TRUE );
1537 
1538    }; /* end if */
1539 
1540    /* Move past copyright notice in file, check for error */
1541    if ( fseek( CFile, NOTICESIZE, SEEK_CUR ) ) {  /* 1 is for the NULL */
1542 
1543 	 /* Can't open file */
1544 	 BOSMsg("'Check point Restore' ERROR: checkpoint file is corrupted\n\r");
1545 
1546 	 /* Close file */
1547 	 fclose( CFile );
1548 
1549 	 /* Return no handle, indicating an error */
1550 	 return( TRUE );
1551 
1552    };  /* end if */
1553 
1554 
1555    /* Kill the previous core */
1556    farfree( Core );
1557 
1558    /* Load system variables */
1559    fread( &CoreSize,   sizeof( unsigned int ), 1, CFile );
1560    fread( &NumProgScheduled, sizeof( int ), 1, CFile );
1561    fread( &NumProgHeld, 	    sizeof( int ), 1, CFile );
1562    fread( &NumProgWait,	    sizeof( int ), 1, CFile );
1563    fread( &TimersActive,     sizeof( int ), 1, CFile );
1564    fread( &WaitPending,      sizeof( int ), 1, CFile );
1565    fread( &WaitPending2,     sizeof( int ), 1, CFile );
1566 
1567    /* Save system settings */
1568    fread( &ProgDistance,  sizeof( int ), 1, CFile );
1569    fread( &DistanceTrys,  sizeof( int ), 1, CFile );
1570    fread( &MsgMode,       sizeof( int ), 1, CFile );
1571    fread( &TotalClocks,  sizeof( long ), 1, CFile );
1572    fread( &CriticalError, sizeof( int ), 1, CFile );
1573    fread( &DisplayTaunts, sizeof( int ), 1, CFile );
1574 
1575 
1576    /* While still PCBs, read them */
1577    Step = fgetc( CFile );
1578    while ( Step != MAXPCB ) {
1579 
1580 	 fread( &(PCBList[Step]), sizeof( struct PCB ), 1, CFile );
1581 	 Step = fgetc( CFile );
1582 
1583    }; /* end while */
1584 
1585    /* Build the new core.  If error, CRITICAL, KILL system! */
1586    Core = ( struct Instr  far * ) farcalloc( CoreSize, sizeof(struct Instr));
1587    if ( Core == NULL ) {
1588 
1589 	 BOSMsg("!!!CRITICAL BOS ERROR!!!  Unable to allocate core memory!\n\r");
1590 	 BOSMsg("BOS Aborted!\n\n\r");
1591 	 exit(0);
1592 
1593    }; /* end if */
1594 
1595    /* Read the core! */
1596    fread( Core, sizeof( struct Instr ), CoreSize, CFile );
1597 
1598    /* Close the file */
1599    fclose( CFile );
1600 
1601    /* Done! */
1602    return( FALSE );
1603 
1604 }; /* end RestoreCP */
1605 
1606 
1607 /* --- GetValue ------------------------------------------------------------*/
1608 /* Get the value of an operand and put it into pointer area */
1609 struct Instr  GetValue( int  PCB, unsigned char  OpToken, int  Operand ) {
1610 
1611    struct Instr  Value,
1612 			  *CAddr;
1613 
1614    int	Address;
1615 
1616 
1617    /* Case through the operand token options */
1618    switch ( OpToken ) {
1619 
1620 	 case  REG	: /* Get it from register or where the register points */
1621 				  /* Case through the different registers */
1622 				  switch( Operand ) {
1623 				  
1624 					case AREGISTER : Value = PCBList[PCB].A;
1625 								  return(Value);
1626 					case BREGISTER : Value = PCBList[PCB].B;
1627 								  return(Value);
1628 					case CREGISTER : Value = PCBList[PCB].C;
1629 								  return(Value);
1630 
1631 					/* Indexed forms */
1632 					case AREGPTR  : Address = PCBList[PCB].A.Operand1;
1633 								 break;
1634 					case BREGPTR  : Address = PCBList[PCB].B.Operand1;
1635 								 break;
1636 					case CREGPTR  : Address = PCBList[PCB].C.Operand1;
1637 								 break;
1638 
1639 				  }; /* end reg case */
1640 
1641 				  /* If we are here, then it must be a ptr */
1642 				  CAddr = CoreAddrC( Address );
1643 				  Value = *CAddr;
1644 
1645 				  break;
1646 
1647 				  
1648 	 case  PTR     : /* It's a pointer					  		    */
1649 				  /* Get what is being pointed at				    */
1650 				  Address = CalcAddr( PCBList[PCB].InstrPointer,
1651 								  Operand );
1652 
1653  				  /* Get the Core Address and move data into value */
1654 				  CAddr = CoreAddrC( Address );
1655 				  Value = *CAddr;
1656 
1657 				  break;
1658 
1659 
1660 	 case  MEM     : /* Memory address */
1661 				  /* Build a data instruction	with an operand of the */
1662 				  /* memory address							   */
1663 
1664 				  /* The memory address is the current address modified
1665 					by the operand							     */
1666 				  Address = CalcAddr( PCBList[PCB].InstrPointer,
1667 								  Operand );
1668 
1669 				  /* Build the instruction */
1670 				    Value.Token      =  DAT;
1671 				    Value.OpToken    =  0;
1672 				    Value.Operand1	 =  Address;
1673 				    Value.Operand2   =  Address;
1674 				    Value.OwnerHandl =  PCB;
1675 
1676 				  break;
1677 
1678 
1679 	 case  IMMEDIATE : /* Build a data instruction, and make it the value */
1680 				    Value.Token      =  DAT;
1681 				    Value.OpToken    =  0;
1682 				    Value.Operand1	 =  Operand;
1683 				    Value.Operand2   =  Operand;
1684 				    Value.OwnerHandl =  PCB;
1685 
1686 				    break;
1687 
1688    }; /* end options */
1689 
1690    /* return the value */
1691    return( Value );
1692 
1693 }; /* end GetValue */
1694 
1695 
1696 /* --- GetAddr ------------------------------------------------------------*/
1697 unsigned int   GetAddr( int  PCB, unsigned char  OpToken, int  Operand,
1698 				    int  IFlag ) {
1699 /* Extract an core address from the operand					*/
1700 
1701    struct Instr  *CAddr;
1702 
1703    int	Address,  /* will contain the final address when case is left */
1704 		Offset;
1705 
1706    /* Case through the operand token options */
1707    switch ( OpToken ) {
1708 
1709 	 case  REG	: /* Get it from register */
1710 				  /* Results will only be valid if the register is an
1711 					index type								*/
1712 				  switch( Operand ) {
1713 				  
1714 					case AREGPTR : Address = PCBList[PCB].A.Operand1;
1715 								break;
1716 					case BREGPTR : Address = PCBList[PCB].B.Operand1;
1717 								break;
1718 					case CREGPTR : Address = PCBList[PCB].C.Operand1;
1719 								break;
1720 
1721 				  }; /* end reg case */
1722 				  break;
1723 				  
1724 	 case  PTR     : /* Pointer 		   					 */
1725 				  /* Get the address from the memory location */
1726 				  Address = CalcAddr( PCBList[PCB].InstrPointer, Operand );
1727 
1728 				  /* if IFlag is TRUE, do indirection */
1729 				  if ( IFlag == TRUE ) {
1730 
1731 				     CAddr   = CoreAddrC( Address );
1732 					Address = CAddr->Operand1;
1733 
1734 				  }; /* end if */
1735 
1736 				  break;
1737 
1738 	 case  MEM     : /* Memory address */
1739 				  /* Address is the value in the operand modified by
1740 				     the current address                              */  
1741 				  /* Get the address  */
1742 				  Address = CalcAddr( PCBList[PCB].InstrPointer, Operand );
1743 				  break;
1744 
1745 
1746 	 case  IMMEDIATE : /* Immediate offset */
1747 				    /* Address is the current instruction modified
1748 					  by the offset in the operand.  This is not technically
1749 					  valid, but we will allow it here. 			 */
1750 
1751 				    Address = CalcAddr( PCBList[PCB].InstrPointer, Operand);
1752 				    break;
1753 
1754    }; /* end options */
1755 
1756    /* return the value */
1757    return( Address );
1758 
1759 }; /* end GetAddr */
1760 
1761 
1762 /* --- LoadRegister ------------------------------------------------------*/
1763 void  LoadRegister( int  PCB, struct Instr  Value, int Register ) {
1764 /* Put the value into a register					*/
1765 
1766    /* case through the registers */
1767    switch( Register ) {
1768 
1769 	 case 'A' : /* A register */
1770 			  PCBList[PCB].A = Value;
1771 			  break;
1772 
1773 	 case 'B' : /* B register */
1774 			  PCBList[PCB].B = Value;
1775 			  break;
1776 
1777 	 case 'C' : /* C register */
1778 			  PCBList[PCB].C = Value;
1779 
1780    }; /* end case */
1781 
1782 }; /* end LoadRegister */
1783 
1784 
1785 /* --- KillProgram ------------------------------------------------------*/
1786 /* Do the neccesary steps to kill a program */
1787 void  KillProgram( int PCB ) {
1788 
1789    struct Instr  *PutAddr;
1790    int 		  Step;
1791 
1792 
1793    /* Adjust counts as appropriate */
1794    if ( PCBList[PCB].State == WAIT ) --NumProgWait;
1795    if ( PCBList[PCB].State == HELD ) --NumProgHeld;
1796    if ( PCBList[PCB].State == READY_RUN ) --NumProgScheduled;
1797 
1798    /* OK, kill the program. */
1799    PCBList[PCB].State = KILLED;
1800 
1801    /* If a timer is set, adjust that count */
1802    if ( PCBList[PCB].TimerPointer != CoreSize ) --TimersActive;
1803 
1804    /* Clear any timer */
1805    PCBList[PCB].TickCount    = 0;
1806    PCBList[PCB].TimerPointer = CoreSize;
1807 
1808    /* Clear a wait, if there is one */
1809    if ( PCBList[PCB].WaitPointer != CoreSize ) {
1810 
1811    /* Yes, there is a wait.  Clear the flag from the size */
1812 	 PutAddr = CoreAddr( PCBList[PCB].WaitPointer );
1813 	 PutAddr->OwnerHandl = PutAddr->OwnerHandl && (0xFF - WAITFLAG);
1814 
1815 	 /* Clear the pointer */
1816 	 PCBList[PCB].WaitPointer = CoreSize;
1817 
1818    }; /* end if */
1819 
1820    /* Message the program's demise. Interupt */
1821    BOSMsgI("Program :");
1822    BOSMsgC( PCBList[PCB].ProgramName );
1823    BOSMsgC(" KILLED by BOS.");
1824    BOSMsgIDone();
1825 
1826    /* OK, is there only one active ( run or wait ) battle program */
1827    if ( (NumProgScheduled + NumProgWait) == 1 ) {
1828 
1829 	 /* Yes, find who it is */
1830 	 Step = 0;
1831 	 while ((PCBList[Step].State != READY_RUN)&&
1832 		   (PCBList[Step].State != WAIT)        ) {
1833 	    Step++;
1834 	 };
1835 
1836 	 /* Now, is this an outright win, or are other programs held */
1837 	 if ( NumProgHeld ) {
1838 
1839 	    /* Other programs are held, so just hold this one */
1840 	    BOSMsgI("Program :");
1841 	    BOSMsgC( PCBList[Step].ProgramName );
1842 	    BOSMsgC(" is the only RUNNING or WAITING program.");
1843 	    BOSMsgIDone();
1844 
1845 	 } else {
1846 
1847 	    /* Out right win! */
1848 	    BOSMsgI("Program :");
1849 	    BOSMsgC( PCBList[Step].ProgramName );
1850 	    BOSMsgC(" is the only surviving program!");
1851 	    BOSMsgIDone();
1852 
1853 	 }; /* end if */
1854 
1855 	 /* Hold it, no matter what. */
1856 	 HoldProg( PCBList[Step].ProgramName );
1857 
1858    }; /* end if */
1859 
1860 }; /* end if */
1861 
1862 /* --- ClearProgram ------------------------------------------------------*/
1863 /* Clear a program from memory */
1864 void  ClearProgram( char*  Name ) {
1865 
1866    int  			PCB;
1867    unsigned int     Address;
1868    struct Instr    *CAddr,
1869 				Dummy;
1870 
1871    /* First find the name */
1872    PCB = FindProg( Name );
1873 
1874    /* Is it a valid program? */
1875    if ( PCB == NOHANDLE ) {
1876 
1877 	 /* NO, error! */
1878 	 BOSMsg("'CLear' ERROR: Program ");
1879 	 BOSMsgC( Name );
1880 	 BOSMsgC(" not loaded!\n\r");
1881 
1882 	 return;
1883 
1884 
1885    }; /* end if */
1886 
1887    /* Build dummy */
1888    Dummy.Token      = DAT;
1889    Dummy.OpToken    = 0;
1890    Dummy.Operand1   = 0;
1891    Dummy.Operand2   = 0;
1892    Dummy.OwnerHandl = NOHANDLE;
1893 
1894    /* It must be new or killed */
1895    if ( (PCBList[PCB].State != NEW)&&(PCBList[PCB].State != KILLED) ) {
1896 
1897 	 /* It is NOT, error! */
1898 	 BOSMsg("'CLear' ERROR: Program ");
1899 	 BOSMsgC( PCBList[PCB].ProgramName );
1900 	 BOSMsgC(" not NEW or KILLED!\n\r");
1901 
1902 	 return;
1903 
1904    }; /* end if */
1905 
1906    /* Build dummy */
1907    Dummy.Token      = DAT;
1908    Dummy.OpToken    = 0;
1909    Dummy.Operand1   = 0;
1910    Dummy.Operand2   = 0;
1911    Dummy.OwnerHandl = NOHANDLE;
1912 
1913    /* OK, mark its PCB as UNUSED */
1914    PCBList[PCB].State = UNUSED;
1915 
1916    /* OK, run the core and clear all it's memory */
1917    for ( Address = 0; Address < CoreSize; ++Address ) {
1918 
1919 	 /* Get the address */
1920 	 CAddr = CoreAddr( Address );
1921 
1922 	 /* Does it belong to this PCB */
1923 	 if ( CAddr->OwnerHandl == PCB )
1924 
1925 	    /* Yes!, then return it to BOS */
1926 	    *CAddr = Dummy;
1927 
1928 	 /* end if */
1929 
1930    }; /* end for */
1931 
1932 }; /* end ClearProgram */
1933 
1934 
1935 /* --- DiskList --------------------------------------------------*/
1936 /* Do an undetailed list of BOS programs on disk */
1937 void  DiskList ( void ) {
1938 
1939    struct ffblk  fb;
1940    int           done;
1941    unsigned int  play;
1942 
1943    /* Put the processing header */
1944    BOSMsg("'DIsk list' : List processed.\n\n\r");
1945    BOSMsgC(" |- File Name -|-  Size  -|-   Date   -\n\r");
1946 
1947    /* Find the first */
1948    done = findfirst( "*.BOS", &fb, 0 );
1949    while( !done ) {
1950 
1951 	 BOSMsgST( " %13s ", fb.ff_name );
1952 	 BOSMsgL(  "%9ld    ", fb.ff_fsize   );
1953 
1954 	 /* Do the date and time */
1955 	 play =  (fb.ff_fdate >> 5) & 15;  /* Get the Month */
1956 	 BOSMsgU( "%02u/", play );
1957 	 play =  fb.ff_fdate & 31;  		/* Get the DAY */
1958 	 BOSMsgU( "%02u/", play );
1959 	 play =  fb.ff_fdate >> 9;         /* Get the Year 	 */
1960 	 play += 1980;					/* Add the base year */
1961 	 BOSMsgU( "%4u|", play );
1962 
1963 	 play =  fb.ff_ftime >> 11;        /* Get the Hour 	 */
1964 	 BOSMsgU( "%02u:", play );
1965 	 play =  (fb.ff_ftime >> 5) & 63;  /* Get the Min */
1966 	 BOSMsgU( "%02u\n\r", play );
1967 
1968 	 done = findnext( &fb );
1969 
1970    }; /* end while */
1971 
1972 
1973 }; /* end DiskList */
1974 
1975 
1976 /* -------- MASTER Routines ----------------------------------------------*/
1977 
1978 /* --- CreateCore --------------------------------------------------*/
1979 /* This func will allocate the BOS core and store it in the global
1980    pointer.  It return the memory used to create the core			   */
1981 unsigned int  CreateCore ( char *Size ) {
1982 
1983    unsigned int  SizeI;
1984    unsigned int  SizeB;
1985 
1986    SizeI = atoi( Size );	/* Get the size in instructions */
1987 
1988    /* Determine if Size is to long or to small*/
1989    if ( (SizeI < MINCORESPEC) || (SizeI > MAXCORESPEC) ) {
1990 	 MsgBadCoreSpec();
1991 	 exit(0);
1992    };
1993 
1994    /* Determine the number of bytes that will be needed and allocate it */
1995    SizeB = SizeI * sizeof( struct Instr );
1996    Core  = ( struct Instr  * ) farmalloc( SizeB );
1997 
1998    /* If Core is null, notify user and exit */
1999    if ( Core == NULL ) {
2000 	 MsgNoCore();
2001 	 exit(0);
2002    };
2003 
2004    /* Remember core size in instructions */
2005    CoreSize = SizeI;
2006 
2007    /* return bytes used */
2008    return ( SizeB );
2009 
2010 }; /* end CreateCore */
2011 
2012 
2013 /* -------- DoCommand ----------------------------------------------------*/
2014 /* This function will interpret and dispatch a MMI command.			    */
2015 int	DoCommand( unsigned int	Token ) {
2016 
2017 int  Step;
2018 
2019 
2020 /* --- Commands implemented ---
2021 
2022   COMMAND  CHARS TOKEN      DISCRIPTION
2023 
2024   exit     ex    CEXIT      Exit BOS
2025 
2026   disk	 di	  CDISK	   List available .BOS programs.
2027 
2028   load	 lo	  CLOAD	   Load a program.  Do not spawn.
2029 
2030   list     li    CLIST      List programs in core
2031 
2032   slist    sl    CSLIST     List system settings.
2033 
2034   set      se    CSET       Set system paramaters
2035 
2036   core     co    CCORE      Look into the core.  Undetailed list.
2037 
2038   spawn    sp    CSPAWN     Spawn a program ( run it ).
2039 
2040   hold     ho    CHOLD      Hold a program.  Put it in HELD state.
2041 
2042   release  re    CRELEASE   Release a program from a held state.
2043   
2044   check    ch    CCHECKP    Checkpoint the the system.
2045 
2046   crestore cr    CCRESTORE  Checkpoint restore.
2047 
2048   clear    cl    CCLEAR     Clear a program or the entire core
2049 
2050 */
2051 
2052    /* Case through possible tokens */
2053    switch ( Token ) {
2054 
2055 	 case  CEXIT   : /* Exit BOS, return FALSE */
2056 				  return( FALSE );
2057 
2058 
2059 	 case  CLOAD   : /* Load each program on arg list */
2060 				  for ( Step = 0; Step < MMICmndArgs; Step++ ) {
2061 
2062 					LoadProgram( MMIList[Step] );
2063 
2064 				  }; /* end for */
2065 				  break;
2066 
2067 	 case  CLIST   : /* List programs loaded.  's' in the first arg
2068 					means a simple list is desired			*/
2069 				  if ( MMIList[0][0] == 's' )
2070 
2071 					/* Quick list */
2072 					SimpleList();
2073 
2074 				  else
2075 
2076 					/* Normal list */
2077                          NormalList();
2078 
2079 
2080 				  /* end if */
2081 				  break;
2082 
2083 	 case  CSLIST  : /* List the system definitions */
2084 				  SystemList();
2085 				  break;
2086 
2087 	 case  CSET    : /* Do the set */
2088 				  SetSystem();
2089 				  break;
2090 
2091 	 case  CCORE   : /* Do a simple core list */
2092 				  CoreList();
2093 				  break;
2094 
2095 	 case  CSPAWN  : /* Spawn program  */
2096 
2097 				  /* First, is it an '-a' command */
2098 				  if ((MMIList[0][0] == '-')&&(MMIList[0][1] == 'a')) {
2099 
2100 					/* Yes, loop and do all new */
2101 					for ( Step = 0; Step < MAXPCB; Step ++ )
2102 					   if ( PCBList[Step].State == NEW )
2103 					      Spawn( PCBList[Step].ProgramName ); 
2104 
2105 				  } else
2106 
2107 					/* No, then do all on the list */
2108 					for ( Step = 0; Step < MMICmndArgs; Step++ )
2109 					   Spawn( MMIList[Step] );
2110 
2111 				  break;
2112 
2113 	 case  CHOLD   : /* Hold program */
2114 
2115 				  /* First, is it an '-a' command */
2116 				  if ((MMIList[0][0] == '-')&&(MMIList[0][1] == 'a')) {
2117                       
2118 					/* Yes, loop and do all new */
2119 					for ( Step = 0; Step < MAXPCB; Step ++ )
2120 					   if ( PCBList[Step].State == READY_RUN )
2121 					      HoldProg( PCBList[Step].ProgramName ); 
2122 
2123 				  } else
2124 
2125                          /* No, then do all on the list */
2126 					for ( Step = 0; Step < MMICmndArgs; Step++ )
2127 					   HoldProg( MMIList[Step] );
2128 
2129 				  /* Clean the BOS input line */
2130 				  BOSMsgClean();
2131 
2132 				  break;
2133 
2134 	 case  CRELEASE  : /* Release program */
2135 
2136 				  /* First, is it an '-a' command */
2137 				  if ((MMIList[0][0] == '-')&&(MMIList[0][1] == 'a')) {
2138 
2139 					/* Yes, loop and do all new */
2140 					for ( Step = 0; Step < MAXPCB; Step ++ )
2141 					   if ( PCBList[Step].State == HELD )
2142 						 ReleaseProg( PCBList[Step].ProgramName );
2143 
2144 				  } else
2145 
2146 					/* No, then do all on the list */
2147 					for ( Step = 0; Step < MMICmndArgs; Step++ )
2148 					   ReleaseProg( MMIList[Step] );
2149 
2150 				  break;
2151 
2152 	 case  CSHOLD  : /* Spawn the hold each program on arg list */
2153 				  for ( Step = 0; Step < MMICmndArgs; Step++ ) {
2154 
2155 					Spawn( MMIList[Step] );
2156 					HoldProg( MMIList[Step] );
2157 
2158 				  }; /* end for */
2159 				  break;
2160 
2161 	 case  CCHECKP : /* Check point the program.  TRUE is error */
2162 				  if ( CheckPoint( MMIList[0] ) )
2163 
2164 					BOSMsg("Unable to perform checkpoint.\n\r");
2165 
2166 				  else
2167 
2168 					BOSMsg("Checkpoint successfull.\n\r");
2169 
2170 				  /* end if */
2171 				  break;
2172 
2173 
2174 	 case  CCRESTORE : /* Restore checkpoint.  TRUE is error */
2175 				  if ( RestoreCP( MMIList[0] ) )
2176 
2177 					BOSMsg("Unable to restore checkpoint.\n\r");
2178 
2179 				  else
2180 
2181 					BOSMsg("Checkpoint restore successfull.\n\r");
2182 
2183 				  /* end if */
2184 				  break;
2185 
2186 
2187 	 case  CCLEAR    : /* Clear programs */
2188 
2189 				  /* First, is it an '-a' command */
2190 				  if ((MMIList[0][0] == '-')&&(MMIList[0][1] == 'a')) {
2191 
2192 					/* Yes, then clear the entire core and PCBList */
2193 					for ( Step = 0; Step < MAXPCB; Step ++ )
2194 					   PCBList[Step].State = UNUSED;
2195 					ClearCore();
2196 
2197 				  } else
2198 
2199 					/* No, then clear all programs on the list */
2200 					for ( Step = 0; Step < MMICmndArgs; Step++ )
2201 					   ClearProgram( MMIList[Step] );
2202 
2203 				  break;
2204 
2205 	 case  CDISK     : /* Disk list. */
2206 				    DiskList();
2207 
2208 				    break;
2209 
2210 
2211 	 default       : /* All other tokens all errors */
2212 				  MsgBadCommand();
2213 
2214    }; /* end switch */
2215 
2216    /* return under normal conditions */
2217    return ( TRUE );
2218 
2219 }; /* end DoCommand */
2220 
2221 
2222 /* -------- --------------------------------------------------*/
2223 /* Get and implement critical command */
2224 int  CritCmndEntry( void ) {
2225 
2226    char	Buffer[MAXCMDSIZE + 2];
2227    int    Step,
2228 		Continue = TRUE;
2229    unsigned int	CommandToken;
2230 
2231    cputs("\n\r");	/* Go to next line */
2232    MMICmndPtr = 0;	/* Kill previous entry 		 */
2233 
2234    /* Set the max chars */
2235    Buffer[0] = MAXCMDSIZE;
2236 
2237    /* Get the Buffer */
2238    cputs("!BOS!>>");
2239    cgets( Buffer );
2240    cputs("\n\r");
2241 
2242    /* Stuff into the MMI Command */
2243    Step = 0;
2244    while ( Buffer[Step+2] != NULL ) {
2245 	 MMICmnd[Step] = Buffer[Step+2];
2246 	 ++Step;
2247    };
2248    MMICmnd[Step] = NULL;
2249 
2250   /* -- Do the command */
2251 
2252    /* if the command parses w/o error(TRUE), then do  */
2253    CommandToken = ParseCommand();
2254    if ( CommandToken != NOCMDTOKEN )
2255 	 Continue = DoCommand( CommandToken );
2256 
2257    /* Clear old command and put new prompt */
2258    MMICmndPtr = 0;
2259    BOSPrompt();
2260 
2261    /* NULL the MMIList */
2262    for ( Step = 0; Step < MAXARGS; Step++ )
2263 	 MMIList[Step][0] = NULL;
2264 
2265    /* Return the Continue state */
2266    return Continue;
2267 
2268 }; /* end CritCmndEntry */
2269 
2270 
2271 /* -------- DoKeyPress ---------------------------------------------------*/
2272 /* This function processes a key press.  If [ENTER] has been pressed then
2273    it sends the command string to DoCommand						    */
2274 int  DoKeyPress() {
2275 
2276    /* defines used by this function */
2277    #define  ENTER   	13	/* The [ENTER] key     				*/
2278    #define  BACKSPACE    8    /* The [BACKSPACE] key 				*/
2279    #define  FUNCTIONKEY  0    /* For when function keys are pressed   */
2280    #define  ESCAPE		27   /* The [ESC] key					*/
2281    #define  ABORT		'`'  /* The abort key 					*/
2282 
2283 
2284    char			InKey, Continue = TRUE;
2285    unsigned int	CommandToken, Step;
2286 
2287    /* Get the key from BIOS */
2288    InKey = getch();
2289 
2290    /* case for significant keystrokes */
2291    switch( InKey ) {
2292 
2293     case ENTER 	: /* NULL terminate the command string and execute */
2294 				  cputs("\n\r");
2295 				  MMICmnd[MMICmndPtr] = NULL;
2296 
2297 				  /* if the command parses w/o error(TRUE), then do  */
2298 				  CommandToken = ParseCommand();
2299 				  if ( CommandToken != NOCMDTOKEN )
2300 					Continue = DoCommand( CommandToken );
2301 
2302 				  /* Clear old command and put new prompt */
2303 				  MMICmndPtr = 0;
2304 				  BOSPrompt();
2305 
2306 				  /* NULL the MMIList */
2307 				  for ( Step = 0; Step < MAXARGS; Step++ )
2308 					MMIList[Step][0] = NULL;
2309 				  break;
2310 
2311     case BACKSPACE  : /* If we can move back, do so */
2312 				  if ( MMICmndPtr > 0 ) {
2313 					/* Process for a destructive backspace */
2314 					MMICmnd[MMICmndPtr] = NULL;
2315 					MMICmndPtr--;		/* Kill last char in buffer */
2316 
2317 					putchar( InKey );	/* Move cursor back one	   */
2318 					putchar( ' ' );	/* Destroy char on screen   */
2319 					putchar( InKey );   /* Move back again		   */
2320 				  };
2321 				  break;
2322 
2323     case FUNCTIONKEY : /* Currently no function key processing, so just
2324 					burn the key							   */
2325 				   InKey = getch();
2326 				   break;
2327 
2328     case ESCAPE	 : /*  Abort current command and do critical command */
2329 				   Continue = CritCmndEntry();
2330 				   break;
2331 
2332 
2333     case ABORT		 : /*  Abort current command  */
2334 				   cputs("\n\r");	/* Go to next line */
2335 				   BOSMsg("Command entry aborted.\n\r");
2336 				   MMICmndPtr = 0;	/* Kill previous entry 		 */
2337 				   BOSPrompt();     /* Put the prompt for the next */
2338 				   break;
2339 
2340 
2341 		   default : /* Add the key to the Command if it will fit */
2342 				   if ( MMICmndPtr < MAXCMDSIZE ) {
2343 
2344 					 /* It will fit */
2345 					 MMICmnd[MMICmndPtr] = InKey;
2346 					 MMICmndPtr++;
2347 					 putch( InKey );	/* Echo the key */
2348 
2349 				   };
2350 				   break;
2351 
2352 
2353    }; /* end case */
2354 
2355    return( Continue );
2356 
2357 }; /* end DoKeyPress */
2358 
2359 
2360 /* -------- ExecInstruction  ---------------------------------------------*/
2361 /* This executes an instruction for a particular PCB				    */
2362 void  ExecInstruction ( int	PCB ) {
2363 
2364    struct Instr     far  *Instruction,
2365 				far  *PutAddr,
2366 				ValueR,		/* Value Right and Left ( Operands ) */
2367 				ValueL;
2368 
2369    unsigned char	OpToken1, OpToken2, Handle, Token;
2370    unsigned int     Address, AddressV;
2371 
2372 
2373 
2374    /* Clear critical error flag */
2375    CriticalError = NOERROR;
2376 
2377    /* First, get the pointer to the instruction */
2378    Instruction = CoreAddrC( PCBList[PCB].InstrPointer );
2379 
2380    /* Get the token */
2381    Token = Instruction->Token;
2382 
2383    /* Does this instruction have a taunt */
2384    if ( Token >= TauntPresent ) {
2385 
2386 	/* Yes, then put it and clean the token */
2387 
2388 	 /* Mask out the Taunt number and shift it down */
2389 	 Token = Token & 0x70;   /* Taunt number is in bits 64, 32, and 16 */
2390 	 Token = Token >> 4;     /* Shift it to bits 4, 2, and 1           */
2391 
2392 	 /* Print the taunt, if taunt diplaying is active */
2393 	 if ( DisplayTaunts == TRUE )
2394 	   BOSMsgTaunt( PCBList[PCB].ProgramName, PCBList[PCB].TauntList[Token] );
2395 
2396 	 /* Load and clean the Token */
2397 	 Token = Instruction->Token;
2398 	 Token = Token & 0x0F;       /* 4 LSBs contain the actual token */
2399 
2400    }; /* end if */
2401 
2402    /* Are we running a different program's code? */
2403    if ( (Instruction->OwnerHandl != PCBList[PCB].WhosCode)&&
2404 	   (Token != DAT) ) {    /* Don't worry about DAT instructions */
2405 
2406 	 /* Yes, well log whos, and let the user know. */
2407 	 BOSMsgI("Program :");
2408 	 BOSMsgC(PCBList[PCB].ProgramName );
2409 	 BOSMsgC(": is running the code of program ");
2410 	 BOSMsgC(PCBList[Instruction->OwnerHandl].ProgramName);
2411 	 BOSMsgIDone();
2412 
2413 	 PCBList[PCB].WhosCode = Instruction->OwnerHandl;
2414 
2415    }; /* end if */
2416    /* NOTE: Running someone elses code does not transfer owner ship of that
2417 		  code to the current PCB								*/
2418 
2419    /* Case through all instructions and act on them */
2420    switch( Token ) {
2421 
2422    /* -   -   -   -   -   -  MOV  -   -   -   -   -   -   -   -   -   -  */
2423 	 case MOV : /* Do the move instruction */
2424 
2425 			  /* Extract the value and address */
2426 			  OpToken2    = Instruction->OpToken & 0x0F;
2427 			  ValueR      = GetValue( PCB, OpToken2, Instruction->Operand2 );
2428    			  OpToken1    = Instruction->OpToken >> 4;
2429 
2430 			  /* See if ValueR belonged to someone else */
2431 			  if ( ValueR.OwnerHandl != PCB )
2432 
2433 				/* if so, make this PCB the owner */
2434 				ValueR.OwnerHandl = PCB;
2435 
2436 			  /* Are we moving into a pure register? */
2437 			  if ( (OpToken1 == REG)&&(Instruction->Operand1 < REGPTRBIT) )
2438 
2439 				/* Ok, then do it.  */
2440 				LoadRegister( PCB, ValueR, Instruction->Operand1);
2441 
2442 			  else {
2443 
2444 				/* Otherwise, we need to find the address to put it */
2445 				Address     = GetAddr( PCB, OpToken1, Instruction->Operand1,
2446 								   FALSE );
2447 
2448 				/* Calcutate the memory address  */
2449 				PutAddr     = CoreAddrC( Address );
2450 
2451 				/* See if we are putting this Value on someone elses spot */
2452 				if (PutAddr->OwnerHandl != PCB) {
2453 
2454 				   /* Are we taking BOSs memory? */
2455 				   if (PutAddr->OwnerHandl == NOHANDLE) 
2456 
2457 					 /* Yes!, then give it to this pcb */
2458 					 PCBList[PCB].CoreHeld++;
2459 
2460 				   else {
2461 				   
2462 					 /* Otherwise, give credit to this PCB and take
2463 					    credit from old owner					 */
2464 					 PCBList[PCB].CoreHeld++;
2465 					 PCBList[PutAddr->OwnerHandl].CoreHeld--;
2466 
2467 				   }; /* end if */
2468 
2469  				}; /* end if */
2470 
2471 
2472 				/* Move the value */
2473 				*PutAddr    = ValueR;
2474 
2475 			  }; /* end if */
2476 
2477 			  /* Next instruction */
2478 			  PCBList[PCB].InstrPointer =
2479 			     CalcAddr(PCBList[PCB].InstrPointer, 1 );
2480 
2481                  break;
2482 
2483 
2484    /* -   -   -   -   -   -  CMP  -   -   -   -   -   -   -   -   -   -  */
2485 	 case CMP : /* Do a compare instruction */
2486 
2487 			  /* Extract the value of both sides */
2488 			  OpToken2    = Instruction->OpToken & 0x0F;
2489 			  ValueR      = GetValue( PCB, OpToken2, Instruction->Operand2 );
2490 			  OpToken1    = Instruction->OpToken >> 4;
2491 			  ValueL      = GetValue( PCB, OpToken1, Instruction->Operand1 );
2492 
2493 			  /* If both are code then do straight compare, otherwise
2494 				compare just the first operand					*/
2495 			  if ( (ValueR.Token != DAT)&&(ValueL.Token != DAT) )
2496 
2497 				/* -- Both code, do straight compare */
2498 				PCBList[PCB].CMPResult =
2499 				   memcmp( &ValueL, &ValueR, sizeof( struct Instr ) );
2500 
2501 			  else
2502 
2503 				/* -- One is data, compare the first operand by subtracting
2504 					 the left from the right		  */
2505 				PCBList[PCB].CMPResult =
2506 				   ValueL.Operand1 - ValueR.Operand1;
2507 
2508 			  /* end if */
2509 
2510 			  /* Next instruction */
2511 			  PCBList[PCB].InstrPointer =
2512 			     CalcAddr(PCBList[PCB].InstrPointer, 1 );
2513 
2514                  break;
2515 
2516 
2517    /* -   -   -   -   -   -  JE   -   -   -   -   -   -   -   -   -   -  */
2518 	 case JE  : /* Do a jump on equil instruction */
2519 
2520 			  /* We will take this jump if this PCBs compare result is 0 */
2521 			  if ( PCBList[PCB].CMPResult == 0 ) {
2522 
2523 				/* -- Take jump */
2524 
2525 				/* Extract the address from left sides */
2526 				OpToken1  = Instruction->OpToken >> 4;
2527 				Address   = GetAddr( PCB, OpToken1, Instruction->Operand1,
2528 								 TRUE );
2529 
2530 				/* Update the instruction pointer */
2531 				PCBList[PCB].InstrPointer = Address;
2532 
2533 			  } else
2534 
2535 				/* Otherwise just go to the next instruction */
2536 				PCBList[PCB].InstrPointer =
2537 				   CalcAddr(PCBList[PCB].InstrPointer, 1 );
2538 
2539                  break;
2540 
2541    /* -   -   -   -   -   -  JB   -   -   -   -   -   -   -   -   -   -  */
2542 	 case JB  : /* Do a jump on below instruction */
2543 
2544 			  /* We will take this jump if this PCBs compare result is - */
2545 			  if ( PCBList[PCB].CMPResult < 0 ) {
2546 
2547 				/* -- Take jump */
2548 
2549 				/* Extract the address from left sides */
2550 				OpToken1  = Instruction->OpToken >> 4;
2551 				Address   = GetAddr( PCB, OpToken1, Instruction->Operand1,
2552 								 TRUE );
2553 
2554 				/* Update the instruction pointer */
2555 				PCBList[PCB].InstrPointer = Address;
2556 
2557 			  } else
2558 
2559 				/* Otherwise just go to the next instruction */
2560 				PCBList[PCB].InstrPointer =
2561 				   CalcAddr(PCBList[PCB].InstrPointer, 1 );
2562 
2563                  break;
2564 
2565    /* -   -   -   -   -   -  JA   -   -   -   -   -   -   -   -   -   -  */
2566 	 case JA  : /* Do a jump on above instruction */
2567 
2568 			  /* We will take this jump if this PCBs compare result is + */
2569 			  if ( PCBList[PCB].CMPResult > 0 ) {
2570 
2571 				/* -- Take jump */
2572 
2573 				/* Extract the address from left sides */
2574 				OpToken1  = Instruction->OpToken >> 4;
2575 				Address   = GetAddr( PCB, OpToken1, Instruction->Operand1,
2576 								 TRUE );
2577 
2578 				/* Update the instruction pointer */
2579 				PCBList[PCB].InstrPointer = Address;
2580 
2581 			  } else
2582 
2583 				/* Otherwise just go to the next instruction */
2584 				PCBList[PCB].InstrPointer =
2585 				   CalcAddr(PCBList[PCB].InstrPointer, 1 );
2586 
2587                  break;
2588 
2589 
2590    /* -   -   -   -   -   -  JMP  -   -   -   -   -   -   -   -   -   -  */
2591 	 case JMP : /* Do an unconditional jump */
2592 
2593 			  /* Extract the address from left sides */
2594 			  OpToken1  = Instruction->OpToken >> 4;
2595 			  Address   = GetAddr( PCB, OpToken1, Instruction->Operand1,
2596 							   TRUE );
2597 
2598 			  /* Update the instruction pointer */
2599 			  PCBList[PCB].InstrPointer = Address;
2600 
2601                  break;
2602 
2603 
2604    /* -   -   -   -   -   -  INC  -   -   -   -   -   -   -   -   -   -  */
2605 	 case INC : /* Increment the first operand */
2606 
2607 			  /* Extract the value and the address of the first operand */
2608 			  OpToken1  = Instruction->OpToken >> 4;
2609 			  Address   = GetAddr( PCB, OpToken1, Instruction->Operand1,
2610 							   FALSE );
2611 			  ValueL    = GetValue( PCB, OpToken1, Instruction->Operand1 );
2612 
2613 			  /* Treat the value as an address and increment it */
2614 			  ValueL.Operand1 = CalcAddr( ValueL.Operand1, 1 );
2615 
2616 			  /* See if ValueR belonged to someone else */
2617 			  if ( ValueR.OwnerHandl != PCB )
2618 
2619 				/* if so, make this PCB the owner */
2620 				ValueR.OwnerHandl = PCB;
2621 
2622 			  /* -- Put the value back */
2623 			  /* Are we moving into a pure register? */
2624 			  if ( ( OpToken1 == REG )&&(Instruction->Operand1 < REGPTRBIT) )
2625 
2626 				/* Ok, then do it.  */
2627 				LoadRegister( PCB, ValueL, Instruction->Operand1);
2628 
2629 			  else {
2630 
2631 				/* Calcutate the memory address  */
2632 				PutAddr     = CoreAddrC( Address );
2633 
2634 				/* See if we are putting this Value on someone elses spot */
2635 				if (PutAddr->OwnerHandl != PCB) {
2636 
2637 				   /* Are we taking BOSs memory? */
2638 				   if (PutAddr->OwnerHandl == NOHANDLE) 
2639 
2640 					 /* Yes!, then give it to this pcb */
2641 					 PCBList[PCB].CoreHeld++;
2642 
2643 				   else {
2644 				   
2645 					 /* Otherwise, give credit to this PCB and take
2646 					    credit from old owner					 */
2647 					 PCBList[PCB].CoreHeld++;
2648 					 PCBList[PutAddr->OwnerHandl].CoreHeld--;
2649 
2650 				   }; /* end if */
2651 
2652  				}; /* end if */
2653 
2654 				/* Move the value */
2655 				*PutAddr    = ValueL;
2656 
2657 			  }; /* end if */
2658 
2659 			  break;
2660 
2661 
2662    /* -   -   -   -   -   -  DEC  -   -   -   -   -   -   -   -   -   -  */
2663 	 case DEC : /* Decrement the first operand */
2664 
2665 			  /* Extract the value and the address of the first operand */
2666 			  OpToken1  = Instruction->OpToken >> 4;
2667 			  Address   = GetAddr( PCB, OpToken1, Instruction->Operand1,
2668 							   FALSE );
2669 			  ValueL    = GetValue( PCB, OpToken1, Instruction->Operand1 );
2670 
2671 			  /* See if ValueR belonged to someone else */
2672 			  if ( ValueR.OwnerHandl != PCB )
2673 
2674 				/* if so, make this PCB the owner */
2675 				ValueR.OwnerHandl = PCB;
2676 
2677 			  /* Treat the value as an address and decrement it */
2678 			  ValueL.Operand1 = CalcAddr( ValueL.Operand1, -1 );
2679 
2680 			  /* -- Put the value back */
2681 			  /* Are we moving into a pure register? */
2682 			  if ( ( OpToken1 == REG )&&(Instruction->Operand1 < REGPTRBIT) )
2683 
2684 				/* Ok, then do it.  */
2685 				LoadRegister( PCB, ValueL, Instruction->Operand1);
2686 
2687 			  else {
2688 
2689 				/* Calcutate the memory address  */
2690 				PutAddr     = CoreAddrC( Address );
2691 
2692 				/* See if we are putting this Value on someone elses spot */
2693 				if (PutAddr->OwnerHandl != PCB) {
2694 
2695 				   /* Are we taking BOSs memory? */
2696 				   if (PutAddr->OwnerHandl == NOHANDLE) 
2697 
2698 					 /* Yes!, then give it to this pcb */
2699 					 PCBList[PCB].CoreHeld++;
2700 
2701 				   else {
2702 				   
2703 					 /* Otherwise, give credit to this PCB and take
2704 					    credit from old owner					 */
2705 					 PCBList[PCB].CoreHeld++;
2706 					 PCBList[PutAddr->OwnerHandl].CoreHeld--;
2707 
2708 				   }; /* end if */
2709 
2710  				}; /* end if */
2711 
2712 				/* Move the value */
2713 				*PutAddr    = ValueL;
2714 
2715 			  }; /* end if */
2716 
2717 			  break;
2718 
2719 
2720    /* -   -   -   -   -   -  ADD  -   -   -   -   -   -   -   -   -   -  */
2721 	 case ADD : /* Do an add instruction */
2722 
2723 			  /* Extract the value of both sides and the address
2724 				of the left side							*/
2725 			  OpToken2    = Instruction->OpToken & 0x0F;
2726 			  ValueR      = GetValue( PCB, OpToken2, Instruction->Operand2 );
2727 			  OpToken1    = Instruction->OpToken >> 4;
2728 			  ValueL      = GetValue( PCB, OpToken1, Instruction->Operand1 );
2729 			  Address     = GetAddr(  PCB, OpToken1, Instruction->Operand1,
2730 								 FALSE );
2731 
2732 			  /* See if ValueR belonged to someone else */
2733 			  if ( ValueR.OwnerHandl != PCB )
2734 
2735 				/* if so, make this PCB the owner */
2736 				ValueR.OwnerHandl = PCB;
2737 
2738 			  /* Treat the values as addresses and add them */
2739 			  ValueL.Operand1 = CalcAddr( ValueL.Operand1, ValueR.Operand1 );
2740 
2741 			  /* Put into the compare result */
2742 			  PCBList[PCB].CMPResult = ValueL.Operand1;
2743 
2744 			  /* -- Put the left value back */
2745 			  /* Are we moving into a pure register? */
2746 			  if ( ( OpToken1 == REG )&&(Instruction->Operand1 < REGPTRBIT) )
2747 
2748 				/* Ok, then do it.  */
2749 				LoadRegister( PCB, ValueL, Instruction->Operand1);
2750 
2751 			  else {
2752 
2753 				/* See if we are putting this Value on someone elses spot */
2754 				if (PutAddr->OwnerHandl != PCB) {
2755 
2756 				   /* Are we taking BOSs memory? */
2757 				   if (PutAddr->OwnerHandl == NOHANDLE) 
2758 
2759 					 /* Yes!, then give it to this pcb */
2760 					 PCBList[PCB].CoreHeld++;
2761 
2762 				   else {
2763 				   
2764 					 /* Otherwise, give credit to this PCB and take
2765 					    credit from old owner					 */
2766 					 PCBList[PCB].CoreHeld++;
2767 					 PCBList[PutAddr->OwnerHandl].CoreHeld--;
2768 
2769 				   }; /* end if */
2770 
2771  				}; /* end if */
2772 
2773 				/* Calcutate the memory address  */
2774 				PutAddr     = CoreAddrC( Address );
2775 
2776 				/* Move the value */
2777 				*PutAddr    = ValueL;
2778 
2779 			  }; /* end if */
2780 
2781 			  /* Next instruction */
2782 			  PCBList[PCB].InstrPointer =
2783 			     CalcAddr(PCBList[PCB].InstrPointer, 1 );
2784 
2785                  break;
2786 
2787 
2788    /* -   -   -   -   -   -  SUB  -   -   -   -   -   -   -   -   -   -  */
2789 	 case SUB : /* Do a subtract instruction */
2790 
2791 			  /* Extract the value of both sides and the address
2792 				of the left side							*/
2793 			  OpToken2    = Instruction->OpToken & 0x0F;
2794 			  ValueR      = GetValue( PCB, OpToken2, Instruction->Operand2 );
2795 			  OpToken1    = Instruction->OpToken >> 4;
2796 			  ValueL      = GetValue( PCB, OpToken1, Instruction->Operand1 );
2797 			  Address     = GetAddr(  PCB, OpToken1, Instruction->Operand1,
2798 								 FALSE );
2799 
2800 			  /* See if ValueR belonged to someone else */
2801 			  if ( ValueR.OwnerHandl != PCB )
2802 
2803 				/* if so, make this PCB the owner */
2804 				ValueR.OwnerHandl = PCB;
2805 
2806 			  /* Treat the values as addresses and subtract right
2807 				from left */
2808 			  ValueL.Operand1 = CalcAddr(  ValueL.Operand1,
2809 								    -(ValueR.Operand1) );
2810 
2811 			  /* Put into the compare result */
2812 			  PCBList[PCB].CMPResult = ValueL.Operand1;
2813 
2814 			  /* -- Put the left value back */
2815 			  /* Are we moving into a pure register? */
2816 			  if ( ( OpToken1 == REG )&&(Instruction->Operand1 < REGPTRBIT) )
2817 
2818 				/* Ok, then do it.  */
2819 				LoadRegister( PCB, ValueL, Instruction->Operand1);
2820 
2821 			  else {
2822 
2823 				/* Calcutate the memory address  */
2824 				PutAddr     = CoreAddrC( Address );
2825 
2826 				/* See if we are putting this Value on someone elses spot */
2827 				if (PutAddr->OwnerHandl != PCB) {
2828 
2829 				   /* Are we taking BOSs memory? */
2830 				   if (PutAddr->OwnerHandl == NOHANDLE) 
2831 
2832 					 /* Yes!, then give it to this pcb */
2833 					 PCBList[PCB].CoreHeld++;
2834 
2835 				   else {
2836 				   
2837 					 /* Otherwise, give credit to this PCB and take
2838 					    credit from old owner					 */
2839 					 PCBList[PCB].CoreHeld++;
2840 					 PCBList[PutAddr->OwnerHandl].CoreHeld--;
2841 
2842 				   }; /* end if */
2843 
2844  				}; /* end if */
2845 
2846 				/* Move the value */
2847 				*PutAddr    = ValueL;
2848 
2849 			  }; /* end if */
2850 
2851 			  /* Next instruction */
2852 			  PCBList[PCB].InstrPointer =
2853 				CalcAddr(PCBList[PCB].InstrPointer, 1 );
2854 
2855 			  break;
2856 
2857 
2858    /* -   -   -   -   -   -  LOP  -   -   -   -   -   -   -   -   -   -  */
2859 	 case LOP : /* Do a loop instruction */
2860 			  /* Decrement REG C.  If 0 or negative, then jump to
2861 				operand1									   */
2862 
2863 
2864 			  /* Do the decrement, and see if greater than 0 */
2865 			  if ( (PCBList[PCB].C.Operand1-- ) > 0 ) {
2866 
2867 				/* -- Yes, do loop */
2868 
2869 				/* Extract the address */
2870 				OpToken1    = Instruction->OpToken >> 4;
2871 				Address     = GetAddr( PCB, OpToken1, Instruction->Operand1,
2872 								   TRUE );
2873 
2874 				/* Update the instruction pointer */
2875 				PCBList[PCB].InstrPointer = Address;
2876 
2877 			  } else
2878 
2879 				/* -- No, then fall out of loop.  Go to next instruction */
2880 			     PCBList[PCB].InstrPointer =
2881 			        CalcAddr(PCBList[PCB].InstrPointer, 1 );
2882 
2883 			  /* end if */
2884 			  break;
2885 
2886 
2887    /* -   -   -   -   -   -  RND  -   -   -   -   -   -   -   -   -   -  */
2888 	 case RND : /* Do a random gereration instruction */
2889 			  /* Generate a random number between 0 and coresize-1.   */
2890 
2891 			  /* Build the right value */
2892 			  ValueR.Token    = DAT;
2893 			  ValueR.OpToken  = 0;	/* Doesnt matter, it's data. */
2894 			  ValueR.Operand1 = random( CoreSize );
2895 			  ValueR.Operand2 = ValueR.Operand1;
2896 			  ValueR.OwnerHandl = PCB;
2897 
2898 			  /* Now, find out where it will go */
2899  			  OpToken1  = Instruction->OpToken >> 4;
2900 			  Address   = GetAddr( PCB, OpToken1, Instruction->Operand1,
2901 							   FALSE );
2902 			  ValueL    = GetValue( PCB, OpToken1, Instruction->Operand1 );
2903 
2904 			  /* See if ValueR belonged to someone else */
2905 			  if ( ValueR.OwnerHandl != PCB )
2906 
2907 				/* if so, make this PCB the owner */
2908 				ValueR.OwnerHandl = PCB;
2909 
2910 			  /* -- Put the value into it */
2911 			  /* Are we moving into a pure register? */
2912 			  if ( ( OpToken1 == REG )&&(Instruction->Operand1 < REGPTRBIT) )
2913 
2914 				/* Ok, then do it.  */
2915 				LoadRegister( PCB, ValueR, Instruction->Operand1);
2916 
2917 			  else {
2918 
2919 				/* Calcutate the memory address  */
2920 				PutAddr     = CoreAddrC( Address );
2921 
2922 				/* See if we are putting this Value on someone elses spot */
2923 				if (PutAddr->OwnerHandl != PCB) {
2924 
2925 				   /* Are we taking BOSs memory? */
2926 				   if (PutAddr->OwnerHandl == NOHANDLE) 
2927 
2928 					 /* Yes!, then give it to this pcb */
2929 					 PCBList[PCB].CoreHeld++;
2930 
2931 				   else {
2932 				   
2933 					 /* Otherwise, give credit to this PCB and take
2934 					    credit from old owner					 */
2935 					 PCBList[PCB].CoreHeld++;
2936 					 PCBList[PutAddr->OwnerHandl].CoreHeld--;
2937 
2938 				   }; /* end if */
2939 
2940  				}; /* end if */
2941 
2942 				/* Move the value */
2943 				*PutAddr    = ValueR;
2944 
2945 			  }; /* end if */
2946                  break;
2947 
2948 
2949    /* -   -   -   -   -   -  WT  -   -   -   -   -   -   -   -   -   -  */
2950 	 case WT  : /* Do a wait set instruction */
2951 			  /* First operand is the wait site, second is jump loc  */
2952 
2953 			  /* Get the value and address of the location we will be
2954 				putting the wait at							  */
2955 			  OpToken1  = Instruction->OpToken >> 4;
2956 			  OpToken2  = Instruction->OpToken & 0x0F;
2957 			  Address   = GetAddr(  PCB, OpToken1, Instruction->Operand1,
2958 							    TRUE  );
2959 			  PutAddr   = CoreAddrC( Address );
2960 			  ValueL    = *PutAddr;
2961 
2962 			  /* See if this spot belonged to someone else */
2963 			  if (ValueL.OwnerHandl != PCB) {
2964 
2965 				/* Are we taking BOSs memory? */
2966 				if (ValueL.OwnerHandl == NOHANDLE)
2967 
2968 				   /* Yes!, then give it to this pcb */
2969 				   PCBList[PCB].CoreHeld++;
2970 
2971 				else {
2972     
2973 				   /* Otherwise, give credit to this PCB and take
2974 				   credit from old owner					 */
2975 				   PCBList[PCB].CoreHeld++;
2976 				   PCBList[ValueL.OwnerHandl].CoreHeld--;
2977 
2978 				}; /* end if */
2979 
2980 				/* But this PCBs handle into it */
2981 				ValueL.OwnerHandl = PCB;
2982 
2983 			  }; /* end if */
2984 
2985 			  /* Add wait flag to it */
2986 			  ValueL.OwnerHandl += WAITFLAG;
2987 
2988 			  /* OK, put it back. */
2989 			  *PutAddr = ValueL;
2990 
2991 			  /* Put the wait address into the PCB */
2992 			  PCBList[PCB].WaitSite = Address;
2993 
2994 			  /* Now get the jump location */
2995 			  Address   = GetAddr(  PCB, OpToken2, Instruction->Operand2,
2996 							    TRUE );
2997 
2998 			  /* Put the jump location into the PCB */
2999 			  PCBList[PCB].WaitPointer = Address;
3000 
3001 			  /* Next instruction */
3002 			  PCBList[PCB].InstrPointer =
3003 				CalcAddr(PCBList[PCB].InstrPointer, 1 );
3004 
3005 			  /* DONE! */
3006 			  break;
3007 
3008 
3009    /* -   -   -   -   -   -  TMR  -   -   -   -   -   -   -   -   -   -  */
3010 	 case TMR : /* Set a timer instruction */
3011 			  /* First operand is the timer length, second operand is
3012 				the jump loc								   */
3013 
3014 			  /* Extract the value from the left and the address
3015 				from the right								   */
3016 			  OpToken1    = Instruction->OpToken >> 4;
3017 			  ValueL      = GetValue( PCB, OpToken1, Instruction->Operand1 );
3018 			  OpToken2    = Instruction->OpToken & 0x0F;
3019 			  Address     = GetAddr(  PCB, OpToken2, Instruction->Operand2,
3020 								 TRUE );
3021 
3022 			  /* Put the tick count in the PCB */
3023 			  PCBList[PCB].TickCount = ValueL.Operand1;
3024 
3025 			  /* OK, if the TickCount is 0 or negative, there is a
3026 				critical error								*/
3027 			  if ( ValueL.Operand1 < 1 ) {
3028 
3029 				/* Set the critical error flag */
3030 				CriticalError = ERROR;
3031 
3032 				/* Message the error */
3033 				BOSMsgI("Program :");
3034 				BOSMsgC( PCBList[PCB].ProgramName );
3035 				BOSMsgC(".  TMR instruction Critial Error!");
3036 				BOSMsgIDone();
3037 
3038 			  }; /* end if */
3039 
3040 			  /* Put the jump location intot the PCB */
3041 			  PCBList[PCB].TimerPointer = Address;
3042 
3043 			  /* Indicate a timer is active */
3044 			  ++TimersActive;
3045 
3046 			  /* Next instruction */
3047 			  PCBList[PCB].InstrPointer =
3048 				CalcAddr(PCBList[PCB].InstrPointer, 1 );
3049 
3050 			  break;
3051 
3052 
3053    /* -   -   -   -   -   -  HLT  -   -   -   -   -   -   -   -   -   -  */
3054 	 case HLT : /* Halt program instruction */
3055 
3056 			  /* Set the state of this PCB to WAIT */
3057 			  PCBList[PCB].State = WAIT;
3058 			  NumProgScheduled--;
3059 			  NumProgWait++;
3060 
3061 			  /* Check for endlesss loop, ie no timer or wait */
3062 			  if ( (PCBList[PCB].WaitPointer == CoreSize )&&
3063 				  (PCBList[PCB].TimerPointer == CoreSize )  ) {
3064 
3065 				/* Yes! then it's a critical error! */
3066 				/* Set the critical error flag */
3067 				CriticalError = ERROR;
3068 
3069 				/* Message the error */
3070 				BOSMsgI("Program :");
3071 				BOSMsgC( PCBList[PCB].ProgramName );
3072 				BOSMsgC(".  Is in an endless loop. !Critial Error!");
3073 				BOSMsgIDone();
3074 
3075 				/* Compensate for critical error and reschedule this
3076 				   program								  */
3077 				NumProgScheduled++;
3078 				NumProgWait--;
3079 
3080 			  }; /* end if */
3081 
3082 			  break;
3083 
3084    /* -   -   -   -   -   -  default  -   -   -   -   -   -   -   -   -   -  */
3085 	 default : /* Default, must have been a data instruction */
3086 			 /* Kill the program */
3087 
3088 			 /* Set the critical error flag */
3089 			 CriticalError = ERROR;
3090 
3091 			 /* Message the error */
3092 			 BOSMsgI("Program :");
3093 			 BOSMsgC( PCBList[PCB].ProgramName );
3094 			 BOSMsgC(".  Executed a DAT. !Critial Error!");
3095 			 BOSMsgIDone();
3096 
3097    }; /* end Case */
3098 
3099 
3100    /* Increment total clocks of program */
3101    PCBList[PCB].TotalClocks++;
3102 
3103    /* Was there a critical error? If so, kill the program */
3104    if ( CriticalError != NOERROR ) KillProgram(PCB);
3105 
3106    /* Was a wait crossed? */
3107    if ( WaitPending != NOHANDLE ) {
3108 
3109 	 /* YES! Ok, trip wait mechinism */
3110 	 PCBList[WaitPending].InstrPointer = PCBList[WaitPending].WaitPointer;
3111 
3112 	 /* Clear wait site */
3113 	 PCBList[WaitPending].WaitPointer = CoreSize;
3114 
3115 	 /* If the waiting program is in WAIT state, then READY it. */
3116 	 if ( PCBList[WaitPending].State == WAIT ) {
3117 	    PCBList[WaitPending].State = READY_RUN;
3118 	    NumProgScheduled++;
3119 	    NumProgWait--;
3120 
3121       }; /* end if */
3122 
3123 	 /* Message a wait has been tripped */
3124 	 BOSMsgI("Wait tripped for program ");
3125 	 BOSMsgC( PCBList[WaitPending].ProgramName );
3126 	 BOSMsgC(".");
3127 	 BOSMsgIDone();
3128 
3129 	 /* Clear this pending wait */
3130 	 WaitPending = NOHANDLE;
3131 
3132 	 /* Was a second wait crossed? */
3133 	 if ( WaitPending2 != NOHANDLE ) {
3134 
3135 	    /* YES! Ok, trip wait mechinism */
3136 	    PCBList[WaitPending2].InstrPointer = PCBList[WaitPending2].WaitPointer;
3137 
3138 	    /* Clear wait site */
3139 	    PCBList[WaitPending2].WaitPointer = CoreSize;
3140 
3141 	    /* If the waiting program is in WAIT state, then READY it. */
3142 	    if ( PCBList[WaitPending2].State == WAIT ) {
3143 	       PCBList[WaitPending2].State = READY_RUN;
3144 	       NumProgScheduled++;
3145 	       NumProgWait--;
3146 
3147          }; /* end if */
3148 
3149 	    /* Message a wait has been tripped */
3150 	    BOSMsgI("Wait tripped for program ");
3151 	    BOSMsgC( PCBList[WaitPending2].ProgramName );
3152 	    BOSMsgC(".");
3153 	    BOSMsgIDone();
3154 
3155 	    /* Clear this pending wait */
3156 	    WaitPending2 = NOHANDLE;
3157 
3158 	 }; /* end if, second wait */
3159 
3160    }; /* end if */
3161 
3162 
3163 }; /* end ExecInstruction */
3164 
3165 
3166 /* -------- Scheduler ----------------------------------------------------*/
3167 /* This performs the program instruction execution				    */
3168 void  Scheduler () {
3169 
3170    int  Step;
3171 
3172 
3173    /* Go through each PCB and execute an instruction for each one that
3174 	 is ready.  Also check for timers  							*/
3175    for ( Step = MINPCB; Step < MAXPCB; Step++ ) {
3176 
3177 	 /* Is this PCB ready? */
3178 	 if ( PCBList[Step].State == READY_RUN ) 
3179 	    ExecInstruction( Step );
3180 
3181 	 /* Does this PCB have a timer set? */
3182 	 if ( PCBList[Step].TimerPointer != CoreSize ) {
3183 
3184 	    /* Yes, the decrement the counter */
3185 	    PCBList[Step].TickCount--;
3186 
3187 	    /* Is it now Zero?, if so then trip the timer */
3188 	    if (PCBList[Step].TickCount == 0) {
3189 
3190 		  /* Next instruction */
3191 		  PCBList[Step].InstrPointer = PCBList[Step].TimerPointer;
3192 
3193 		  /* Clear timer */
3194 		  PCBList[Step].TimerPointer = CoreSize;
3195 		  TimersActive--;
3196 
3197 		  /* Insure the program is ready run, if it is waiting */
3198 		  if (PCBList[Step].State == WAIT) {
3199 
3200 			PCBList[Step].State = READY_RUN;
3201                NumProgScheduled++;
3202 			NumProgWait--;
3203 
3204 		  }; /* end if */
3205 
3206 	    }; /* end if */
3207 
3208 	 }; /* end if */
3209 
3210    }; /* end while */
3211 
3212 
3213    /* Increment total clocks run */
3214    TotalClocks++;
3215 
3216 }; /* end Scheduler */
3217 
3218 
3219 /* -------- Master -------------------------------------------------------*/
3220 /* This fuction accepts key input, executes instructions of spawned
3221    programs, and dispatchs MMI commands on [ENTER]				    */
3222 void  Master () {
3223 
3224    unsigned char	Continue;	/* Keep track of when to quit */
3225 
3226 
3227    /* -- Put the first prompt to the screen -- */
3228    BOSPrompt();
3229 
3230    /* -- Loop until quit BOS -- */
3231    do {
3232 
3233 	    /* If there are programs ready to run OR timer(s) are active,
3234 		  then call scheduler. */
3235 	    if ( NumProgScheduled + TimersActive ) Scheduler();
3236 
3237 	    /* See if keypress from the user, if so, process it */
3238 	    if ( bioskey(1) ) Continue = DoKeyPress();
3239 
3240    } while ( Continue );
3241 
3242 }; /* end Master */
3243 
3244 
3245 /* -------- MAIN ---------------------------------------------------------*/
3246 
3247 void main ( int argc, char *argv[] ) {
3248 
3249    int		  Step;
3250 
3251 
3252    /* Initialize any globals */
3253    for ( Step = BASEPCB; Step < MAXPCB; Step++ ) { /* Clear the PCB List */
3254 	 PCBList[Step].State = UNUSED;
3255    }; /* end for */
3256 
3257    /* Seed random number generator */
3258    randomize();
3259 
3260    memset( MMICmnd, MAXCMDSIZE, sizeof( char ) );  /* Clear command line */
3261    MMICmndPtr = 0;							 /* Empty line         */
3262 
3263 
3264    /* Determine if core size might be specified in command line */
3265    if ( argc < 2 ) {
3266 	 /* if only 1 entry on command line then core size was definitly not
3267 	    specified.  Message user that the core size must be specified and
3268 	    exit													*/
3269 	 MsgNoCoreSpec();
3270 	 exit(0);
3271    };
3272 
3273    /* Allocate core memory, success will hold memory needed for core */
3274    MemoryUsed = CreateCore( argv[1] );
3275 
3276    /* Clear the core */
3277    ClearCore();
3278 
3279    /* Message battleos init */
3280    MsgInitBOS(); 
3281 
3282    /* Call Master */
3283    Master();
3284 
3285 }; /* end main */