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 */
|