From 2dadec8b8b6dfbb981205f4cb1fd25ae915d2288 Mon Sep 17 00:00:00 2001 From: "paul.kimpel@digm.com" Date: Mon, 16 Dec 2013 04:52:03 +0000 Subject: [PATCH] Release emulator version 0.17: 1. Enable (finally!) functioning of P2, the second processor, in CentralControl and Processor. 2. Fix bugs in Character Mode syllables FAD, FSU: initial compare of operands was alphanumeric instead of numeric. 3. Fix bugs in Character Mode syllables TRN, TRZ, TBN: non-boundary destination words were not being fetched into the B register. 4. Enable configuration of additional tape drives (up to the maximum of 16). 5. Implement new flip-flop latching mechanism in CentralControl for use by B5500Console. 6. Optimize clearing of interrupts in Central Control. 7. Implement preliminary mechanism to allow P2 to be added to the configuration temporarily without altering B5500SystemConfiguration.js. 8. Implement new average slack and delay algorithms in Processor.schedule(). 9. Optimize some Character Mode syllables by substituting local variables for "this" properties. 10. Fix bugs in Processor single-precision divide syllables leaving the stack in an incorrect state after a divide by zero in Control State. 11. Further minor tweaks to performance throttling. 12. Optimize references to this.cc in Processor.run(). 13. Minor improvements to B5500MagTapeDrive: eliminate oscillation at load point, improve timing of rewind operations. 14. Implement build-release.cmd script to generate emulator release archive files. 15. Commit initial Mark-XVI TSSINT transcription from Fausto Saporito. --- Mark-XVI/SYMBOL/DCMCP.esp_m | 188 +++++ Mark-XVI/SYMBOL/TSSINT.esp_m | 690 ++++++++++++++++++ build-release.cmd | 1 + emulator/B5500CentralControl.js | 192 +++-- emulator/B5500Processor.js | 419 +++++++---- webUI/B5500ColdLoader.html | 1 - webUI/B5500Console.html | 92 ++- webUI/B5500MagTapeDrive.js | 79 +- {tools => webUI/prototypes}/Pow2.html | 0 .../prototypes}/Register-CrockfordStyle.js | 0 {tools => webUI/prototypes}/Register.js | 0 {tools => webUI/prototypes}/RegisterTest.html | 0 .../prototypes}/webkitFileSystemTest.html | 0 13 files changed, 1344 insertions(+), 318 deletions(-) create mode 100644 Mark-XVI/SYMBOL/TSSINT.esp_m create mode 100644 build-release.cmd rename {tools => webUI/prototypes}/Pow2.html (100%) rename {tools => webUI/prototypes}/Register-CrockfordStyle.js (100%) rename {tools => webUI/prototypes}/Register.js (100%) rename {tools => webUI/prototypes}/RegisterTest.html (100%) rename {tools => webUI/prototypes}/webkitFileSystemTest.html (100%) diff --git a/Mark-XVI/SYMBOL/DCMCP.esp_m b/Mark-XVI/SYMBOL/DCMCP.esp_m index 6a11437..26bd85a 100644 --- a/Mark-XVI/SYMBOL/DCMCP.esp_m +++ b/Mark-XVI/SYMBOL/DCMCP.esp_m @@ -23927,3 +23927,191 @@ ONE: BEGIN STREAM(I: F~"ENDPACK", D~M[ALPHA-2]);% 38711000 I~TALLY;% 38716000 END;% 38717000 IF NOT P THEN% 38718000 + BEGIN BLASTQ(U);% 38719000 + DO UNTIL WAITIO(M[ALPHA-2],@40,U)!0;% 38720000 + GO TO ONE;% 38721000 + END;% 38722000 + END;% 38723000 + BLASTQ(U); 38724000 +CC:: 38725000 + M[M[ALPHA-2] INX NOT 3].[9:6]:=0; 38726000 + LABELTABLE[U]~-@14; 38730000 + RDCTABLE[U]~0; 38731000 + IF 32{U AND U{63 THEN PSEUDOCOPY~PSEUDOCOPY+1; 38732000 + INDEPENDENTRUNNER(P(..CONTROLCARD),(M[ALPHA-2].[CF])& 38732100 + $ SET OMIT = NOT(DATACOM AND RJE ) 38732199 + U[2:42:6]&JAR[P1MIX,6][1:1:1], 38732300 + 192); 38732400 + GO CLOSEOUT;% 38733000 +CP: EMPTY;% 38735000 + IF NOT UNLABELED THEN P(WAITIO(M[ALPHA-2],0,U),DEL);% 38736000 + SETNOTINUSE(U,FORMS OR PUNCHLCK); 38737000 + GO CLOSEOUT;% 38738000 +LP: EMPTY;% 38740000 + IF SEPARATE THEN P(WAITIO(@4000100000,0,U),DEL) %150-38741000 + ELSE P(WAITIO(@4002000000,0,U),DEL); %150-38741100 + IF NOT UNLABELED THEN P(WAITIO(M[ALPHA-2],0,U),DEL);% 38742000 + IF NOT SEPARATE THEN P(WAITIO(@4000100000,0,U),DEL); %150-38742100 + SETNOTINUSE(U,FORMS); 38743000 + GO CLOSEOUT;% 38744000 +SP: IF STATE.[43:1] THEN COOLOFF ELSE EMPTY;% 38746000 + GO CLOSEOUT;% 38747000 +MT: IF NOT STATE.[41:1] THEN% 38749000 + BEGIN IF STATE.[43:1] THEN% 38750000 + BEGIN COOLOFF; BLASTQ(U);% 38751000 + IF NOT REW THEN 38752000 + BEGIN T~@1000000140000005&STATE[22:44:1];% 38753000 + IF I}NBUFS THEN DO UNTIL WAITIO(T,@377,U).[42:1]; 38754000 + IF NOT UNLABELED THEN 38754100 + P(WAITIO(T,@377,U),DEL); 38755000 + END;% 38756000 + END ELSE% 38757000 + BEGIN EMPTY;% 38758000 + EOFIT: T~@1737000000000000;% 38759000 + P(WAITIO([T],@40,U),DEL);% 38760000 + IF NOT UNLABELED THEN% 38761000 + BEGIN;STREAM(BC~FIB[6],RC~FIB[7],D~M[ALPHA-2]);% 38762000 + BEGIN SI~LOC BC; DI~DI+40;% 38763000 + DS~5 dec; DS~7 DEC;% 38764000 + END;% 38765000 + P(WAITIO(M[ALPHA-2],@40,U),DEL);% 38766000 + P(WAITIO([T],@40,U),DEL);% 38767000 + T~@1000000340000005;% 38768000 + P(WAITIO(T,@40,U) ,DEL);% 38769000 + END;% 38770000 + END;% 38771000 + END ELSE% 38772000 + IF FIB[18].[1:1]THEN BEGIN FIB[18].[1:1]~FIB[16]~0; 38773000 + FIB[10].[3:15]:=0; GO EOFIT END; 38773100 + IF REW THEN% 38774000 + BEGIN P(WAITIO(@4200000000,@377,U),DEL);% 38775000 + STATE.[40:1]~0;% 38776000 + END ELSE STATE.[40:1]~NOT STATE.[44:1];% 38777000 +PX: IF REL THEN% 38778000 + BEGIN SETNOTINUSE(U,0); 38779000 + STATE.[41:2]~1;% 38780000 + END ELSE STATE.[41:2]~2;% 38781000 + IF LOCK THEN% 38782000 + BEGIN SETNOTINUSE(U,1); 38783000 + STATE.[41:2]~1;% 38784000 + END;% 38785000 + IF U LSS 16 THEN 38786000 + IF PURGE THEN% 38787000 + BEGIN IF PRNTABLE[U]<0 THEN% 38788000 + BEGIN RDCTABLE[U].[8:6]~0; %538-38788500 + INDEPENDENTRUNNER(P(.PURGEID),U,64) 38789000 + END %538-38789050 + ELSE SETNOTINUSE(U,0); 38789100 + STATE.[41:2]~2;% 38790000 + END;% 38791000 + GO TO CLEANUP;% 38792000 +PP:: IF NOT STATE.[41:1] THEN% 38794000 + BEGIN EMPTY; P(WAITIO(@2004500000000,@40,U),DEL) END;% 38795000 + GO TO PX; 38796000 +PR:: IF NOT STATE.[41:1] THEN BEGIN COOLOFF; BLASTQ(U) END;% 38798000 + IF REW THEN P(WAITIO(@10340000000,@377,U),DEL);% 38799000 + GO TO PX;% 38800000 +CD:: 38802000 + IF M[ALPHA].[27:1] THEN MOVE(10,FIB[16].[33:15],M[ALPHA-2]) ELSE 38803000 +EOD: DO UNTIL READMEFROMDISK(CIDROW[U-32],M[ALPHA-2]); 38804000 + $ SET OMIT = PACKETS 38804999 + IF JAR[P1MIX,0]<0 AND PRT[P1MIX,21]!0 OR JAR[P1MIX,1]<0 THEN 38806000 + BEGIN 38806050 + $ SET OMIT = NOT(PACKETS) 38806099 + PACKETERR[U-32]:=TRUE; 38806200 + IF CIDTABLE[U-32,3] LEQ CIDTABLE[U-32,7] THEN 38806300 + $ POP OMIT 38806301 + BEGIN STREAM(E~"ENDWAIT": Q~@14, D~M[ALPHA-2]); 38807000 + BEGIN SI~LOC Q; SI~SI+7; IF SC!DC THEN DI~DI+1; Q~DI; SI~Q; 38808000 + L: IF SC=" " THEN BEGIN SI~SI+1; GO TO L END; 38809000 + DI~LOC E; DI~DI+1; IF 3 SC!DC THEN TALLY~1; 38810000 + $ SET OMIT = NOT(PACKETS) 38810099 + IF TOGGLE THEN 38810100 + BEGIN SI~SI-3; IF 4 SC=DC THEN TALLY~0; END; 38810200 + $ POP OMIT 38810201 + E~TALLY; 38810500 + END; 38811000 + IF P THEN GO TO EOD; 38812000 + END; 38813000 + END; 38813100 + KIND~0; 38814000 + GO TO CC; 38815000 +CLOSEOUT:: STATE.[39:4]~1; TIME~1; 38817000 +CLEANUP:: CLOSED: DK: BKUP: DC: 38818000 + P(P&RCW[CTC],0,RDS,0,XCH,P&P[CTF],STF); 38819000 +END OTHER CLOSE; 38820000 +PROCEDURE FILEOPEN(XTRA,ALPHA); 39000000 + VALUE ALPHA,XTRA; INTEGER ALPHA,XTRA; 39000100 +BEGIN REAL RCW=+0;% 39001000 + REAL IOM=IOMASK, IOMASK; 39001100 + REAL XTRAR=-4,XTRAC=-6; 39001200 + INTEGER NBUFS,FNUM,RLEN,TYPE,IO,BLEN,U,KIND, 39002000 + MODE,DIREC,FORMS,COBOL,UNLABELED,OPTIONAL,CNTCTL; 39003000 + REAL T1,T2,MASK,STATE; 39004000 + REAL MFID,FID; INTEGER REEL,CDATE,CYCLE; %KEEP THESE TOGETHER 39004100 + ARRAY FIB[*],FPB[*];% 39005000 + INTEGER ACCESS,FIB7; 39006000 + LABEL DCIN,PBS; 39006100 + LABEL DC19; 39006800 + LABEL DKRN,SPN,DKSN,DKUN,DKPN,DCN; 39007000 + SWITCH INSW~DKRN,SPN,DKSN,DKUN,DCIN; 39008000 + LABEL LOOK,EXIT,LOOKOUT,LPS,FINALIN,FINALOUT,SPDC;% 39009000 + REAL SUBROUTINE DSED; DSED:=TERMSET(P1MIX); 39009050 + REAL SUBROUTINE CNTLBITS;% 39026000 + CNTLBITS~IOMASK&MODE[21:47:1]&DIREC[22:47:1]&CNTCTL[23:47:1]39027000 + &IO[24:47:1]&(KIND=7 OR KIND>9 AND KIND{12)[20:47:1] 39028000 + &(IF KIND=1OR KIND=7OR KIND=12THEN@20ELSE 0)[27:42:6];39029000 + SUBROUTINE MAKEIODS;% 39031000 + BEGIN FIB[16]~T1~((BLEN-1)|DIREC+M[ALPHA])&CNTLBITS[18:18:15]% 39032000 + &(IF BLEN{1023 THEN BLEN ELSE 1023)[838:10]% 39033000 + &TINU[IF (KIND=7 OR KIND=12) THEN IF TYPE<20 39034000 + THEN 20 ELSE 22 ELSE 39034050 + IF KIND=11 THEN 23 ELSE U][3:3:5] OR M; 39034100 + FIB[19]~(IF STATE.[46:2]=0 THEN (DIREC INX T1)% 39035000 + &(2|DIREC+(BLEN>1023)+1)[3:43:5] ELSE% 39036000 + IF STATE.[46:2]=1 THEN ((NOT RLEN INX 2)|DIREC INX T1)39037000 + &RLEN[8:38:10]&(3|DIREC+2)[3:43:5] ELSE% 39038000 + (1-DIREC INX T1)&RLEN[8:38:10]&(DIREC+6)[3:43:5])% 39039000 + &IO[25:47:1];% 39040000 + IF NOT (IO OR COBOL)THEN% 39041000 + T1~FIB[19]&T1[3:3:5]&0[25:25:1];% 39042000 + FIB[10],[3:15]~M[ALPHA]-2; %HEAD OF BUFFER RING 39042100 + T2~T1.[33:15]-M[ALPHA];% 39043000 + FOR MASK~0 STEP 1 UNTIL NBUFS-1 DO% 39044000 + BEGIN %P 39045000 + M[ALPHA+MASK]~FLAG((P(DUP,LOD)+T2)&P(T1,XCH)[33:33:15]);% 39046000 + END;% 39047000 + END MAKEIODS;% 39048000 + LABEL DKR0,SPO,DKS0,DKU0,DKP0,DC0; 39049000 + SWITCH OUTSW~DKR0,SPO,DKS0,DKU0,DC0;% 39050000 + LABEL FIXFIB,FIND,SPACER;% 39054000 + LABEL PREFINAL,DK1;% 39055000 + ARRAY HEADER[*];% 39056000 + REAL TOG; 39056100 + LABEL AGN; 39056500 + FIB~M[ALPHA-3]; FPB~PRT[P1MIX,3];% 39083000 + IOMASK:=IOM; 39083100 + NBUFS~FIB[13].[1:9]; FNUM~FIB[4].[13:11]; BLEN~FIB[18].[3:15];% 39084000 + TYPE~FPB[FNUM+3].[43;5];% 39085000 + STREAM(S ~ [FPB[FNUM+2]], D ~ [REEL]);% 39086000 + BEGIN SI:=S;DS:=3OCT;DS:=5OCT;DS:=OCT END;% 39087000 + P(CDATE, RSB, .CDATE,~); 39087100 + IF FPB[FNUM+4]>0 THEN REEL ~ CDATE ~ CYCLE ~ 0; 39087500 + MODE~FIB[13].[24:1]; IO~FIB[13].[27:1]; RLEN~FIB[18].[33:15];% 39088000 + DIREC~FIB[13].[25:1]; FORMS~FPB[FNUM+3].[42:1];% 39089000 + STATE~FIB[5]; UNLABELED~FIB[4].[2:1]; 39090000 + MFID~FPB[FNUM]; FOD~FPB[FNUM+1]; OPTIONAL~FIB[4].[5:1];% 39091000 + COBOL~(FIB[13] AND 1)&([FIB].[8:10]=22)[1:47:1]; % COBOL 60 & 68 39091100 + KIND~FIB[4].[8:4]; IF FIB[13].[28:10]!0 THEN REEL~FIB[13].[28:10]; 39092000 + IF COBOL>0 OR FIB[4].[7:1] THEN % COBOL 60 OR SORT 39092010 + M[FIB INX NOT 1].[3:6]~2 39092020 + ELSE M[ALPHA-7].[3:6]~2; 39092030 + $ SET OMIT = NOT(DATACOM AND RJE ) 39092039 + IF TYPE=19 THEN GO TO DC19 ELSE 39092045 + IF TYPE=26 THEN GO TO DKPN ELSE 39092050 + IF TYPE>26 THEN GO TO DCN; 39092055 + IF (TYPE=0 AND NOT IO) OR TYPE GTR 20 THEN 39092060 + BEGIN IF USEPBD 39092070 + $ SET OMIT = NOT(DATACOM AND RJE ) 39092074 + THEN TYPE:=22; GO TO LOOKOUT; 39092080 + END; 39092090 diff --git a/Mark-XVI/SYMBOL/TSSINT.esp_m b/Mark-XVI/SYMBOL/TSSINT.esp_m new file mode 100644 index 0000000..14914d9 --- /dev/null +++ b/Mark-XVI/SYMBOL/TSSINT.esp_m @@ -0,0 +1,690 @@ +% I N T R I N S I C S M A R K XVI.0.00 10/01/74 + COMMENT: * TITLE: B5500/B5700 MARK XVI SYSTEM RELEASE * + * FILE ID: SYMBOL/INTRINS TAPE ID: SYMBOL1/FILE000 * + * THIS MATERIAL IS PROPRIETARY TO BURROUGHS CORPORATION * + * AND IS NOT TO BE REPRODUCED, USED, OR DISCLOSED * + * EXCEPT IN ACCORDANCE WITH PROGRAM LICENSE OR UPON * + * WRITTEN AUTHORIZATION OF THE PATENT DIVISION OF * + * BURROUGHS CORPORATION, DETROIT, MICHIGAN 48232 * + * * + * COPYRIGHT (C) 1971, 1972, 1974 * + * BURROUGHS CORPORATION * + * AA320206 AA393180 AA332366 *; + BEGIN + DEFINE ETRLNG = 5#, + INTDESC(INTDESC1) = FLAG(INTDESC1 & 85[1:41:7]) #, + INTCALL(INTCALL1,INTCALL2) = P(INTCALL2 & 85[1:41:7], + INTCALL1,COC) #, + CALLINT(CALLINT1) = P(CALLINT1 & 85[1:41:7],XCH,COC) #, + COBOLDCI= @167 #, + FORTERRI= @134 #, + EXPI = @20 #, + LNI = @17 #, + DEXPI = @77 #, + DLOGI = @101 #, + CABSI = @53 #, + SINI = @14 #, + SQRTI = @13 #, + ATAN2I = @114 #, + DMODI = @65 #, + DSINI = @105 #, + DSQRTI = @123 #, + XTOII = @6 #, + CXTOII = @56 #, + COSI = @15 #, + TANI = @111 #, + ARCTANI = @16 #, + DATANI = @113 #, + ARSINI = @116 #, + GAMMAI = @126 #, + EDITIT(EDITIT1,EDITIT2,EDITIT3,EDITIT4,EDITIT5) = P(MKS, + EDITIT1,EDITIT2,EDITIT3,(-1),(EDITIT4),(EDITIT5), + @153&85[1:41:7],XCH,COC) #, + % EDITIT(BUFFADDRESS,FIELDWIDTH(W),TYPE,LOWPART,HIGHPART) + % WILL EDIT THE VALUE (LOWPART,HIGHPART) INTO A FIELD + % STARTING AT BUFFADDRESS. EDITIT RETURNS THE ENDING + % ADDRESS. THE WIDTH OF THE EDITED FIELD IS CONSTRAINED + % TO W CHARACTERS (EDITED VALUE IS RIGHT JUSTIFIED WITH + % LEADING BLANKS IF W IS LARGER THAN NEEDED) -- BUT IF + % W=0, THEN EDITIT WILL ADJUST THE FIELD WIDTH TO + % ACCOMODATE FULL NUMERICAL SIGNIFICANCE. TYPE=2 => EDITIT + % WILL CHOOSE BETWEEN REAL, INTEGER, AND DOUBLEPRECISION + % EDITING (DOUBLEPRECISION IS USED IF LOWPART!0). + % TYPE=1 => USE ONLY INTEGER, TYPE=3 => USE ONLY REAL, + % TYPE=4 => USE ONLY LOGICAL, TYPE=5 => USE ONLY DOUBLE- + % PRECISION. + CTC = 33:33:15#, + CTF = 18:33:15#, + FTC = 33:18:15#, + FTF = 18:18:15#, + CF = 33:15#, + FF = 18:15#; + REAL JUNK = 5; + NAME MEM=2, M=2, MEMORY=2 ; + REAL BLKCNTRL = 5; + DEFINE DUMPNOW(DUMPNOW1)=P(DUMPNOW1,0,48,COM,DEL,DEL)#, + TRACENOW(TRACENOW1,TRACENOW2)= + P(TRACENOW1,1,TRACENOW2 ,+ ,48,COM,DEL,DEL)#; + PROCEDURE OUTPUTINT(TEN, FILX, CHSKP, LNSKP, FI, FRMT, LISX);% %WF + VALUE CHSKP, LNSKP, FI, LISX;% %WF + NAME FILX;% %WF + ARRAY TEN[*], FRMT[*];% %WF + REAL LISX;% %WF + INTEGER CHSKP, LNSKP, FI;% %WF + FORWARD;% CODE=00200000, INTRINSIC NUMBER=@ 1 %WF + PROCEDURE INTRINSIC(DUPE, D, NUMDIM, SIZE, TYPE);% %WF + VALUE DUPE, D, NUMDIM, SIZE, TYPE;% %WF + NAME D;% %WF + ARRAY DUPE[*];% %WF + INTEGER NUMDIM, SIZE, TYPE;% %WF + FORWARD;% CODE=00400000, INTRINSIC NUMBER=@ 2 %WF + PROCEDURE INPUTINT(TEN, FILX, DKADR, ACT,% %WF + FI, FRMT, LISX, EOFL, PARL);% %WF + VALUE ACT, FI;% %WF + NAME FILX, LISX;% %WF + ARRAY TEN[*], FRMT[*];% %WF + REAL EOFL, PARL;% %WF + INTEGER DKADR, ACT, FI;% %WF + FORWARD;% CODE=00600000, INTRINSIC NUMBER=@ 3 %WF + PROCEDURE DISKSORT(T1, T2, RELA, ENDQ, BINGO, IPFIDX,% %WF + OUTPRO, INPRO, OUTF, INF, OPTOG, IPTOG, DKO, DKI,% %WF + TP1, TP2, TP3, TP4, TP5, NT, HIVALU, EQUALS,% %WF + R, ALFA, CORESIZE, DISKSIZE);% %WF + VALUE OPTOG, IPTOG, NT, HIVALU, EQUALS, R, ALFA,% %WF + CORESIZE, DISKSIZE;% %WF + NAME TP1, TP2, TP3, TP4, TP5;% %WF + REAL T1, T2, RELA, ENDQ, BINGO, IPFIDX, OUTPRO, INPRO,% %WF + OUTF, INF, DKO, DKI, NT, HIVALU, EQUALS, CORESIZE;% %WF + BOOLEAN OPTOG, IPTOG, ALFA;% %WF + INTEGER R, DISKSIZE;% %WF + FORWARD;% CODE=00700000, INTRINSIC NUMBER=@ 4 %WF + REAL PROCEDURE DUMPINT(SN, CV, BV, TIPE,% %WF + TENS, ALFA, CHAR, FIEL, FORMT);% %WF + VALUE SN, CV, BV, TIPE, TENS, ALFA, CHAR, FORMT;% %WF + NAME FIEL;% %WF + REAL SN, CV, BV, TIPE, TENS, ALFA, CHAR, FORMT;% %WF + FORWARD;% CODE=42000000, INTRINSIC NUMBER=@ 5 %WF + PROCEDURE XTOTHEIINT(BASE, EXPON, M, LOG, EXP);% %WF + VALUE BASE, EXPON, M, LOG, EXP;% %WF + REAL BASE, EXPON, M, LOG, EXP;% + FORWARD;% CODE=42254000, INTRINSIC NUMBER=@ 6 + REAL PROCEDURE ABSINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@ 7 + REAL PROCEDURE SIGNINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@10 + INTEGER PROCEDURE ENTIERINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@11 + REAL PROCEDURE TIMEINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@12 + PROCEDURE SQRTINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@13 + PROCEDURE SININT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@14 + PROCEDURE COSINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@15 + REAL PROCEDURE ARCTANINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@16 + PROCEDURE LNINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@17 + REAL PROCEDURE EXPINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@20 + REAL PROCEDURE GOTOSOLVERINT(L, X, F, B);% + VALUE L, X, F, B;% + ARRAY F[*];% + REAL L, X, B;% + FORWARD;% CODE= INTRINSIC NUMBER=@21 + PROCEDURE ALGOLWRITE(TEN, FILX, CHSKP, LNSKP, FI, AEXP,% + ARRY, LINESKIP, CHANSKIP, SUPRS, NUMWDS, TANK);% + VALUE CHSKP, LNSKP, FI, AEXP, LINESKIP,% + CHANSKIP, SUPRS, NUMWDS, TANK;% + NAME FILX, TANK;% + ARRAY TEN[*], ARRY[*];% + INTEGER CHSKP, LNSKP, FI, AEXP, LINESKIP,% + CHANSKIP, SUPRS, NUMWDS;% + FORWARD;% CODE=00100100, INTRINSIC NUMBER=@22 + PROCEDURE ALGOLREAD(TEN, FILX, DKADD, ACT, FI, AEXP,% + ARRY, EOFL, PARL, DKADR, CODE, TANK);% + VALUE ACT, FI, AEXP, DKADR, CODE, TANK;% + NAME FILX, TANK;% + ARRAY TEN[*], ARRY[*];% + REAL DKADD, EOFL, PARL, DKADR, CODE;% + INTEGER ACT, FI, AEXP;% + FORWARD;% CODE=00500000, INTRINSIC NUMBER=@23 + PROCEDURE ALGOLSELECT(ACT1, ACT2, TANK, I);% + VALUE ACT1, ACT2, TANK, I;% + NAME TANK;% + INTEGER ACT1, ACT2, I;% + FORWARD;% CODE= INTRINSIC NUMBER=@24 + PROCEDURE COBOLFCR;% + FORWARD;% CODE=43000000, INTRINSIC NUMBER=@25 +PROCEDURE COBOLID;% % GO TO 02700000 + FORWARD;% CODE=43230000, INTRINSIC NUMBER=@26 + PROCEDURE POLYMERGE(T1, T2, T3, ENDQ, BINGO, IPFIDX,% + OUTPRO, INPRO, OUTF, INF, OPTOG, IPTOG, DKO, DKI,% + TP1, TP2, TP3, TP4, TP5, NT, HIVALU, EQUALS,% + R, ALFA, CORESIZE, DISKSIZE);% + VALUE OPTOG, IPTOG, NT, HIVALU, EQUALS, R, ALFA,% + CORESIZE, DISKSIZE;% + NAME TP1, TP2, TP3, TP4, TP5;% + REAL T1, T2, T3, ENDQ, BINGO, IPFIDX, OUTPRO, INPRO,% + OUTF, INF, DKO, DKI, NT, HIVALU, EQUALS, R, CORESIZE; + BOOLEAN OPTOG, IPTOG, ALFA;% + INTEGER DISKSIZE;% + FORWARD;% CODE=40140000, INTRINSIC NUMBER=@27 + PROCEDURE STATUSINT(T, C);% + VALUE T, C;% + REAL T;% + INTEGER C;% + FORWARD;% CODE= INTRINSIC NUMBER=@30 + REAL PROCEDURE MAXINT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@31 + REAL PROCEDURE MININT(X);% + VALUE X;% + REAL X;% + FORWARD;% CODE= INTRINSIC NUMBER=@32 + PROCEDURE DELAYINT(ARRY, MASK, TIME);% + VALUE ARRY, MASK, TIME;% + ARRAY ARRY[*];% + REAL MASK;% + INTEGER TIME;% + FORWARD;% CODE= INTRINSIC NUMBER=@33 + PROCEDURE SUPERMOVERINT(SORCE, DEST, AEXP);% + VALUE AEXP;% + ARRAY SORCE[*], DEST[*];% + INTEGER AEXP;% + FORWARD;% CODE= INTRINSIC NUMBER=@34 + PROCEDURE SISO; FORWARD; %INT#35,SEQ#08400000 + INTEGER PROCEDURE DELTA(P1,P2);%INT#36,SEQ#00022300 + VALUE P1,P2; INTEGER P1,P2; FORWARD; + PROCEDURE ICVD; FORWARD; %INT#37,SEQ#00022500 +PROCEDURE DYNAMICDIALER(B, A, X, F); +VALUE B, A, X, F; +INTEGER B, A, X; BOOLEAN F; + FORWARD;% CODE=00022700, INTRINSIC NUMBER=@40 + PROCEDURE SCAN(UPDPDD,PRT,UPDCDD,HISCOUNT,CASECODE,CHAR); + VALUE PTR, HISCOUNT, CASECODE, CHAR; + NAME UPDPDD, UPDCDD; + INTEGER PTR, HISCOUNT, CASECODE, CHAR; + FORWARD; + PROCEDURE REPL; FORWARD; %INT#42,SEQ#08420000 + PROCEDURE COMPARE;FORWARD; %INT#43,SEQ#08430000 + PROCEDURE BASICPRINT(TYPE); + VALUE TYPE; + REAL TYPE; + FORWARD; CODE=08500000, INTRINSIC NUMBER=@44 + PROCEDURE SWAP; FORWARD; %INT#45,SEQ#00023700 + PROCEDURE BASICINPUT(TYPES); + VALUE TYPES; + REAL TYPES; + FORWARD;% CODE=08700000, INTRINSIC NUMBER=@46 + PROCEDURE READATA(TYPE); + VALUE TYPE; + REAL TYPE; + FORWARD;% CODE=08600000, INTRINSIC NUMBER=@47 + PROCEDURE FTINT ; FORWARD; % 050 + PROCEDURE FTOUT ; FORWARD; % 051 + PROCEDURE DABS ; FORWARD; % 052 + PROCEDURE CABS ; FORWARD; % 053 + PROCEDURE AINT ; FORWARD; % 054 + PROCEDURE MATH ; FORWARD; % 055 + PROCEDURE XTOI ; FORWARD; % 056 + PROCEDURE IDINT ; FORWARD; % 057 + PROCEDURE FLOAT ; FORWARD; % 060 + PROCEDURE SNGL ; FORWARD; % 061 + PROCEDURE DBLE ; FORWARD; % 062 + PROCEDURE AMOD ; FORWARD; % 063 + PROCEDURE TIME ; FORWARD; % 064 + PROCEDURE DMOD ; FORWARD; % 065 + PROCEDURE DMAX1 ; FORWARD; % 066 + PROCEDURE DMIN1 ; FORWARD; % 067 + PROCEDURE SIGNV ; FORWARD; % 070 + PROCEDURE DSIGN ; FORWARD; % 071 + PROCEDURE DIIM ; FORWARD; % 072 + PROCEDURE REALP ; FORWARD; % 073 + PROCEDURE AIMAG ; FORWARD; % 074 + PROCEDURE CMPLX ; FORWARD; % 075 + PROCEDURE CONJG ; FORWARD; % 076 + PROCEDURE DEXP ; FORWARD; % 077 + PROCEDURE CEXP ; FORWARD; % 100 + PROCEDURE DLOG ; FORWARD; % 101 + PROCEDURE CLOG ; FORWARD; % 102 + PROCEDURE ALOG10; FORWARD; % 103 + PROCEDURE DLOG10; FORWARD; % 104 + PROCEDURE DSIN ; FORWARD; % 105 + PROCEDURE CSIN ; FORWARD; % 106 + PROCEDURE DCOS ; FORWARD; % 107 + PROCEDURE CCOS ; FORWARD; % 110 + PROCEDURE TANF ; FORWARD; % 111 + PROCEDURE COTAN ; FORWARD; % 112 + PROCEDURE DATAN ; FORWARD; % 113 + PROCEDURE ATAN2 ; FORWARD; % 114 + PROCEDURE DATAN2; FORWARD; % 115 + PROCEDURE ARSIN ; FORWARD; % 116 + PROCEDURE ARCOS ; FORWARD; % 117 + PROCEDURE SINH ; FORWARD; % 120 + PROCEDURE COSH ; FORWARD; % 121 + PROCEDURE TANH ; FORWARD; % 122 + PROCEDURE DSQRT ; FORWARD; % 123 + PROCEDURE CSQRT ; FORWARD; % 124 + PROCEDURE ERF ; FORWARD; % 125 + PROCEDURE GAMMA ; FORWARD; % 126 + PROCEDURE ALGAMA; FORWARD; % 127 + PROCEDURE ANDI ; FORWARD; % 130 + PROCEDURE ORI ; FORWARD; % 131 + PROCEDURE CMPL ; FORWARD; % 132 + PROCEDURE EQUIVP; FORWARD; % 133 + PROCEDURE FORTERR;FORWARD; % 134 + PROCEDURE MAX; FORWARD; % 135 + PROCEDURE MIN; FORWARD; % 136 + PROCEDURE IMOD; FORWARD; % 137 + PROCEDURE CONCAT; FORWARD; % 140 + PROCEDURE CONCAT; + FORWARD;% CODE=08400000, INTRINSIC NUMBER=@140 + PROCEDURE MATRIXDIDDLER(A, B, C, TYPE); + VALUE A, B, C, TYPE; + ARRAY A[*], B[*], C[*]; + INTEGER TYPE; + FORWARD;% CODE=08800000, INTRINSIC NUMBER=@~4~ + PROCEDURE INVERT(A, B); + VALUE A, B; + ARRAY A[*], B[*]; + FORWARD;% CODE=09100000, INTRINSIC NUMBER=@142 + PROCEDURE TRANSPOSE(A, B); + VALUE A, B; + ARRAY A[*], B[*]; + FORWARD;% CODE=08900000, INTRINSIC NUMBER=@143 + PROCEDURE MATRIXMULTIPLY(A, B, C); + VALUE A, B, C; + ARRAY A[*], B[*], C[*]; + FOWARD;% CODE=09000000, INTRINSIC NUMBER=@144 + PROCEDURE RANDOM(NUMBER, BASE); + VALUE NUMBER; + REAL NUMBER; + INTEGER BASE; + FORWARD;% CODE=00022900, INTRINSIC NUMBER=@145 + PROCEDURE FORTRANFREEREAD; + FORWARD;% CODE=09200000, INTRINSIC NUMBER=@146 + PROCEDURE BASICLOSE(FILX); + VALUE FILX; NAME FILX; + BEGIN REAL SELECT=14, ALGOLWRITE=12; ARRAY AIT=6[*]; + REAL T,I; ARRAY FIB[*]; NAME M=2; + SUBROUTINE MAYBEPRINT; + BEGIN FIB:=FILX[NOT 2]; + IF FIB[5].[41:3]=0 THEN %NOT CLOSED-NOT INPUT + IF FIB[4].[8:4] NEQ 10 THEN %NOT DATA COM + IF FIB[20].[3:15]!0 THEN % DATA LEFT + P(MKS,1,0,0,(FIB[20].[18:10]+1),FILX,ALGOLWRITE); + END; + IF P(.FILX,LOD)=0 THEN %EOJ FILE CLOSE + BEGIN I:=AIT[0]+1; WHILE (T:=AIT[I:=I-1]).[8:10] NEQ 0 + DO IF T.[1:1] THEN + BEGIN FILX:=M[M[T.[18:15]] INX 4]; MAYBEPRINT END; + END ELSE %FILE RESTORE + BEGIN MAYBEPRINT; + P(MKS,2,0,[FILX[NOT 2]],4,SELECT); + FIB[0]:=FIB[8]:=FIB[20]:=FIB[21]:=0; + END; + END BASIC FILE RESTORE; +PROCEDURE FILEATTRIBUTES(T,E,D,V,G,I,TN); VALUE T,I,V,D,G; REAL D,G,I,E; +INTEGER V; ARRAY TN[*]; NAME T; FORWARD; % CODE @ 0043000, INT # @150 +PROCEDURE COBOLDECIMALTOOCTALCONVERT(A); % INT #=@151, CODE=09300000 +VALUE A; NAME A; FORWARD ; +PROCEDURE COBOLOCTOLTODECIMALCONVERT(A,L,H,R,N,S,T); % INT #=@152 +VALUE L,H,R,N,S,T; REAL L,H,R,N,S,T; NAME A; FORWARD; % CODE=09400000 +PROCEDURE FORTRANFREEWRITE(F,D,R,W,L,I,N,S); VALUE I,D,R,W,L; INTEGER R, +W; REAL I,D,L; NAME F; ARRAY S[*],N[*]; FORWARD ;%COD @02976019.INT@153 +PROCEDURE FINNAME; FORWARD; +PROCEDURE FOUTNAME; FORWARD; +PROCEDURE FTINTFIX(F1,D2,F2,F3,L1,E1,E2,P1); VALUE D1,F2,L1,E1,E2,P1 ; +REAL D1,F2,L1,E1,E2,P1; ARRAY F3[*]; NAME F1; FORWARD; % INTRINSIC @156 +PROCEDURE FTOUTFIX(F,D,R,Q,L,E,EL,PL); VALUE D,R,L,E,EL,PL; REAL D,R,L,E +,EL,PL; NAME F; ARRAY Q[*]; FORWARD ; % CODE AT SEQ # 02886040, INT@157 +PROCEDURE FBINBACKBLOCK(F1,D,F2,F3,L,E1,E2,P1); VALUE D,F2,L,E1,E2,P1 ; +REAL D,F2,L,E1,E2,P1; ARRAY F3[*]; NAME F1; FORWARD; % INT # @160. +PROCEDURE COBOLVARSZ; FORWARD;% CODE=09500000 INT #=@161 +PROCEDURE COBOLIONONDSK; FORWARD;% CODE=096000000 INT #=@162 +PROCEDURE COBOLIODSK; FORWARD;% CODE=09700000 INT #=@163 +PROCEDURE FORTRANMEMHANDLER(A,H);VALUE H;REAL H;ARRAY A[*];FORWARD;%164 +PROCEDURE COBOLATT; FORWARD; % CODE = 02650000 INT # = @165 %CJC 103I +PROCEDURE INTERRUPTER; FORWARD; % CODE=09800000; INT #=@166 +PROCEDURE COBOLDC; FORWARD; % CODE = 02690000 INT #=@167 +INTEGER PROCEDURE DELTA(P1,P2); VALUE P1,P2; REAL P1,P2; %@036 +BEGIN + DEFINE + DOT=[18:13]#, AMPER=[18:35:13]#; + COMMENT @4000000=2|20, WHICH IS 1 LARGER THAN ANY 6500 COUNT.; + COMMENT DELTA=2|20 IF DESC(P1)!DESC(P2) OR CSIZE-S ARE !; + IF (P2-P1).[31:17]!0 THEN DELTA~@4000000 ELSE + DELTA~P2.DOT-P1.DOT; +END DELTA; + +PROCEDURE ICVD; %37 +BEGIN + DEFINE DOT=[18:13]#, AMPER=[18:35:13]#, CSIZE=[31:02]#,SIX=0#; + ARRAY STRING[*]; + NAME M = 2; + REAL PTR=-3; INTEGER N=-1; + IF PTR.CSIZE!SIX THEN POLISH(M&1[17:47:01],9999,CDC,DEL); + STRING ~ M[PTR]; + N~N; COMMENT MAKE SURE N IS INTEGERIZED; + IF N>8 THEN POLISH(M&1[14:47:01],N,CDC,DEL); + POLISH([STRING[(PTR.DOT+N-1).[35:10]]], DEL); + STREAM(RESULT~0:S~[STRING[PTR.[18:10]]], N, + SKS~PTR.[28:03]); + BEGIN + DI ~ LOC RESULT; + SI ~ S; SI ~ SI+SKS + DS ~ N OCT; + END; + PTR ~ P; +END ICVD; +PROCEDURE DYNAMICDIALER(A,B,X,F) ; +VALUE B, A, X, F; +INTEGER B, A, X; BOOLEAN F; + BEGIN % A,B,X,Y,Z ARE AS IN Y&Z[A:B:X]. + % F=TRUE => X WAS LITERAL, AND TRB WILL BE DONE AFTER XITING. + REAL Y=-7, Z=-6, C=+1 ; + DEFINE Q= @3403007777777777 #, % MASK FOR ZERO-ING OUT THE G,H,K&V- + % REGISTER PARTS OF THE ROW. + R= @0055005500610065 #, % NOP,DIA,DIB,TRB. + S= @0055703404210435 #; % NOP,LITC Y,STD,XIT. + IF (A~A)<1 OR (B~B)<1 OR (X~X)<1 OR X+A>48 OR X+B>48 + THEN P((-63),26,COM) ; + IF F THEN P(Q,AND,0&(B MOD 6)[4:9:3],A MOD 6,DIB 7,TRB 3, + P&(B DIV 6)[12:45:3],A DIV 6,DIB 15,TRB 3,OR,0,0,XIT) ; + GO P(P(R)&(B DIV 6)[12:45:3],A DIV 6,DIB 24,TRB 3,P&(B MOD 6) + [15:9:3],A MOD 6,DIB 27,TRB 3,P&X[36:42:6],.A,~,S,.B,~,Y,Z,[A]); +END DYNAMICDIALER; + + +PROCEDURE RANDOM(NUMBER, BASE); + VALUE NUMBER; + REAL NUMBER; + INTEGER BASE; + BEGIN INTEGER N; + REAL T; + IF (T := NUMBER MOD 1.0)>0 THEN + BEGIN BASE := T.[9:38]; P(RTN); END; + IF NUMBER!0 THEN + BEGIN T := POLISH(1, 1, COM); + N := 0 & T[10:36:6] & T[16:42:6] & T[22:30:6] + & ((T.[30:18])|P(DUP))[28:22:20]; + END ELSE IF (N := BASE)=0 THEN N := @2631353020000; + T := 3 & (N.[10:26]|6137 + 2197513)[10:12:36]; + POLISH((((BASE := T) OR 0.5) - 0.5) + P(DUP), RTN); +END RANDOM; + + +PROCEDURE SWAP; % 045 +BEGIN + ARRAY A = -2 [*,*], B = -1 [*,*]; + STREAM(A, B, CA~0, CB~0, FA~A.[18:15], FB~B.[18:15]); + BEGIN + SI ~ A; CA ~ SI; + SI ~ B; CB ~ SI; + DI ~ LOC B; DI ~ DI+5; SKIP 3 DB; + SI ~ LOC CA; SI ~ SI+5; SKIP 3 SB; + 3(IF SB THEN DS ~ SET ELSE DS ~ RESET; SKIP SB); DS ~ 2 CHR; + DI ~ DB; SI ~ LOC B; DS ~ WDS; + DI ~ LOC A; DI ~ DI+5; SKIP 3 DB; + SI ~ LOC CB; SI ~ SI+5; SKIP 2 SB; + 3(IF SB THEN DS ~ SET ELSE DS ~ RESET; SKIP SB); DS ~ 2 CHR; + DI ~ FA; SI ~ LOC A; DS ~ WDS; + END; +END SWAP; + + + + +COMMENT ALGOL WRITE INTRINSIC;% +PROCEDURE ALGOLWRITE(TEN, FILX, CHSKP, LNSKP, FI, AEXP, + ARRY, LINESKIP, CHANSKIP, SUPRS, NUMWDS, TANK); + VALUE LINESKIP, CHANSKIP, SUPRS, NUMWDS, TANK, + CHSKP, LNSKP, FI, ARRY; + INTEGER CHSKP, LNSKP, FI, AEXP, + LINESKIP, CHANSKIP, NUMWDS, SUPRS; + NAME FILX, TANK; + ARRAY ARRY[*], TEN[*]; +BEGIN REAL SELECT=14,REED=13,ADDRESS;% + NAME MEM=2;% + LABEL AB,ACTION; + LABEL DS,WINDUP1; + ARRAY FPB=3[*],FIB[*],HEADER[*];% + INTEGER I,RSIZE;% + INTEGER SPOUT; + ARRAY TINK=TANK[*]; + REAL CHNSKP=CHANSKIP; + REAL ALGOLWRITE=12; + DEFINE FNUM = FIB[4].[11:31] #; + $ SET OMIT = NOT(TIMESHARING) +SUBROUTINE WAIT; POLISH(TANK, @2000000000, 36, COM, DEL DEL); + $ POP OMIT + $ SET OMIT = TIMESHARING + LABEL ERR,LP1,MT1,CLOSED,DK1,SP1,CP1,DC1,PP1;% + LABEL DCN1,DCN2,SPIN; + $ SET OMIT = NOT SHAREDISK + SWITCH SW1~ ERR,LP1,MT1,CLOSED,DK1,SP1,CP1,LP1,PP1,ERR,DC1, + ERR,LP1,DCN1; + LABEL LP2,MT2,DK2,SP2,CP2,DC2,PP2;% + SWITCH SW2~ ERR,LP2,MT2,ERR,DK2,SP2,CP2,LP2,PP2,ERR,DC2,ERR, + LP2,DCN2; + LABEL DS1,DR1,DU1;% + SWITCH DSW1~DS1,DR1,DU1,CLOSED; + LABEL UT,PBIT,DWT,D19,RELEASE,STA,EXIT,L1,WINDUP,DBIT;% + LABEL TYPEU,TYPEA,TYPEC;% + SWITCH TYPE~TYPEU,TYPEA,ERR,TYPEC;% + LABEL DS2,DR2,DU2;% + SWITCH DSW2~DS2,DR2,DU2;% + SUBROUTINE BLOCK;% + BEGIN GO TO TYPE[I~FIB[5].[46:2]];% +TYPEC: STREAM(D1~IOD,S~(NUMWDS~NUMWDS+1)|8,% + D2~(TANK[0]~NUMWDS INX IOD));% + BEGIN SI~LOC S; DI~DI-8; DS~4 DEC; DI~D1;% + SI~D2; SI~SI-8; DI~DI-4; DS~4 CHR;% + END;% + IF (FIB[17]~FIB[17]-NUMWDS)>RSIZE+1 THEN BEGIN% +OWT: FIB[7]~FIB[7]+1; P(XIT);% +TYPEA: IF (FIB[17]~FIB[17]-RSIZE)}RSIZE THEN% + BEGIN TANK[0]~RSIZE INX IOD; GO OWT END END;% + NUMWDS~FIB[18].[18:5]-FIB[17]+(I=3);% +TYPEU: END BLOCK;% + REAL SUBROUTINE DISKADDRESS;% + BEGIN% + ADDRESS~(CHANSKIP DIV HEADER[0].[30:12])|HEADER[0].[42:6];% + IF (SUPRS~ADDRESS DIV HEADER[1]+10)}30 THEN + BEGIN P(0); GO TO EXIT END; + IF HEADER[SUPRS]=0 THEN + IF HEADER[9]>(SUPRS-10) THEN% + P(FPB[FNUM+3],FPB[FNUM],FPB[FNUM+1],SUPRS,HEADER, + 4,11,COM,DEL,DEL,DEL,DEL,DEL,DEL) ELSE + BEGIN P(0); GO TO EXIT END;% + ADDRESS~HEADER[SUPRS]+SUPRS+ADDRESS MOD HEADER[1];% + STREAM(D~[ADDRESS]); BEGIN SI~D; DS~8 DEC END; P(1);% + EXIT: DISKADDRESS~P;% + END DISKADDRESS;% + IF TINK=0 THEN %WF + BEGIN FIB ~ FILX[NOT 2]; %WF + IF FIB[5].[11:2]<2 THEN P(MKS,"WRITING",FILX,7,SELECT) ; + IF FIB[5].[43:1] THEN + P(MKS, CHSKP, 0, FILX, 1, SELECT); + IF LNSKP>1 AND ARRY{0 AND (I~FIB[4].[8:4])!1 + $ SET OMIT = NOT(TIMESHARING) + AND I!7 AND I!12 AND I!10 THEN + $ SET OMIT = TIMESHARING + P(XIT);%CARRIAGE CONTROL ON NON-PRINTER FILE + + + RSIZE ~ P(MKS, LNSKP, CHSKP, SUPRS, %WF + (-1), FILX, ALGOLWRITE); %WF + IF ARRY{0 THEN SUPRS ~ 1 ELSE %WF + BEGIN % 11/24/72 - CORRECTED 10/3/73 + IF ARRY.[8:10]=P(DUP,0) THEN % INDEXED WRITE + P(DEL,AEXP) % WRITE MIN(AEXP,RSIZE) WORDS + ELSE % WRITE MIN(ARRY, SIZE,AEXP,RSIZE) WORDS + IF P GTR P(DUP,AEXP) % + THEN P(DEL,AEXP); %WF + IF P(DUP)}RSIZE THEN P(DEL) ELSE RSIZE ~ P; %WF + STREAM(P4 ~ [ARRY[0]], P3 ~ RSIZE, %WF + P2 ~ P(DUP).[36:6], P1 ~ *FILX); %WF + END; %WF + END; %WF + IF RSIZE>0 THEN P(MKS, LNSKP, %WF + CHSKP, SUPRS, RSIZE, FILX, ALGOLWRITE); %WF + FILX[NOT 4] ~ FILX[NOT 3] ~ 0; %WF + P(XIT); %WF + END; %WF + FIB~TANK[NOT 2];% +UT: I~FIB[4].[8:4]; RSIZE~FIB[18].[33:15];% + SPOUT:=(I=5); + $ SET OMIT = TIMESHARING + IF CHNSKP.[4:1] THEN + BEGIN CHNSKP.[4:1]~0; + $ SET OMIT = NOT SHAREDISK + END; + IF NUMWDS<0 THEN GO TO SW1[I]; GO TO SW2[I];% + LP1: MT1: SP1: CP1: PP1: +% +D19: IF IOD.[19:1] THEN% +PBIT: IF IOD.[2:1] THEN P(RSIZE,RTN) ELSE% + IF IOD.[25:1] THEN% +CLOSED: BEGIN + FIB[13].[27:1]~0; + IF (I~(FPB[FNUM+3] AND 31)!10 AND I!12 + AND I!13 AND I!26 THEN FIB[5].[45:1]~0 ELSE + FIB[5].[45:1]~P(TANK[NOT 3],DUP)!0 AND P(XCH)!15; + P(TANK,0,11,COM,DEL,DEL) ; + IF NOT FIB[5].[45:1] THEN GO UT ; + P(TANK[NOT 3]); TANK[NOT 3]~TANK[NOT 4]~0 ; + P(MKS,9,BLKCNTRL,DEL) ;% TAKE PARITY ACTION LBL BRNCH. + P(1); GO TO DS; + END ELSE + IF IOD.[27:1] AND (I=2 OR I=7 OR I=8) THEN% + BEGIN IF NOT FIB[4].[2:1] THEN% + BEGIN HEADER~TANK[NOT 1];HEADER[4].[42:6]~1 END; + IF I=7 THEN FIB[9].[1:1]~1; % MULTI-REEL PBT FILE + I~FIB[13].[28:10]+1;% + P(MKS,6,0,(NOT 2) INX TANK,4,SELECT);% + FIB[13].[28:10]~I; GO TO CLOSED;% + END ELSE% + BEGIN +ERR: P(3); +DS: P(TANK,XCH,11,COM); + END; + WAIT; GO TO PBIT;% +DK1: HEADER~*[FIB[14]]; GO TO DSW1[FIB[4].[27:3]];% +DK2: HEADER~*[FIB[14]]; GO TO DSW2[FIB[4].[27:3]];% +CP2: BLOCK; TANK[0]~FLAG(FIB[16])&CHANSKIP[32:47:1]; GO TO RELEASE;% +LP2: IF SUPRS THEN STREAM(RSIZE,D~IOD); BEGIN RSIZE(DS~8 LIT " ") END; + CHANSKIP~CHANSKIP+LINESKIP.[45:1]; + IF CHANSKIP!0 THEN% + BEGIN IF (I~FIB[17]-RSIZE)>0 THEN% + STREAM(I,D~RSIZE INX IOD); BEGIN I(DS~8 LIT " ") END;% + END ELSE BLOCK;% + TANK[0]~FLAG(FIB[16])&LINESKIP[27:47:1]&LINESKIP[28:46:1]% + &CHANSKIP[29:44:4]&NUMWDS[8:38:10];% + GO TO RELEASE;% +SP2: PP2:% +MT2: BLOCK;% + P(TANK[0]~FLAG(FIB[16])&NUMWDS[8:38:10],NUMWDS,XCH,INX,% + @3700000000000000,XCH,~);% + IF SPOUT THEN % SPO OUTPUT + IF FPB[FNUM+3].[42:6]=43 THEN P(XIT) ELSE %DUMMY + P(0,0,NOT,IOD,INX,15,COM,XIT) + ELSE +RELEASE: P(FLAG(FIB[19])&IOD[3:3:5],TANK,PRL,DEL);% +WINDUP: I~FIB[19].[33:15]-FIB[16].[33:15];% + FIB[16].[33:15]~SUPRS~MEM[P(DUP) INX NOT 1].[18:15];% + FIB[19].[33:15]~SUPRS+I;% + WINDUP1: + FIB[6]~FIB[6]+1; FIB[7]~FIB[7]+1; FIB[17]~FIB[18].[18:15];% + P(XIT);% +DU1:% +DS1: IF LINESKIP!0 THEN% + BEGIN IF IOD.[27:1] AND IOD.[19:1] THEN GO AB; + IF FIB[17]=FIB[18].[18:15] THEN + BEGIN CHANSKIP~FIB[7];% +L1: IF DISKADDRESS THEN% + IF IOD.[19:1] THEN DBIT: IF IOD.[2:1] THEN% + BEGIN + $ SET OMIT = NOT SHAREDISK + MEM[FIB[16]]~ADDRESS; + P(RSIZE,RTN); + END ELSE + IF IOD.[25:1] THEN GO TO CLOSED ELSE + $ SET OMIT = NOT SHAREDISK + BEGIN + $ SET OMIT = NOT SHAREDISK + GO TO AB; + END ELSE + BEGIN WAIT; GO TO DBIT; END ELSE + BEGIN + $ SET OMIT = NOT SHAREDISK + GO TO AB; + END; + END; P(RSIZE,RTN);% + END;% + P(MKS,CHANSKIP,4,TANK,1,SELECT); GO TO L1; +DS2: IF FIB[7]>HEADER[7] THEN HEADER[7]~FIB[7];% + BLOCK; TANK[0]~FLAG(FIB[16]); GO RELEASE;% +DR1: IF LINESKIP!0 THEN CHANSKIP~FIB[7] ELSE FIB[7]~CHANSKIP;% + IF HEADER[7]HEADER[7] THEN HEADER[7]~FIB[7];% + BLOCK;% + CHANSKIP~FIB[7]+FIB[13].[10:9]|HEADER[0].[30:12];% + IF DISKADDRESS THEN% + BEGIN P(TANK[0]~FLAG(FIB[16])&0[24:24:1],(NOT 0),XCH,INX,% + ADDRESS,XCH,~);% + P(FLAG(FIB[19])&1[24:47:1],TANK,PRL,DEL);% + END ELSE% + BEGIN TANK[0]~FLAG(FIB[16])&0[24:24:1];% + P(FLAG(FIB[19]&1[24:44:4],TANK,PRL,DEL);% + END;% + GO TO WINDUP;% + $ SET OMIT = NOT(TIMESHARING) + DC1:: P(RSIZE, RTN); + $ SET OMIT = TIMESHARING + AB:: BEGIN IF(ADDRESS~TANK[NOT 4])=0 THEN GO ERR; + ACTION:: TANK[NOT 3]~TANK[NOT 4] ~0; + TANK[0] := IOD OR MEM; + P(ADDRESS,MKS,9,JUNK); GO TO ERR; + \ No newline at end of file diff --git a/build-release.cmd b/build-release.cmd new file mode 100644 index 0000000..297dbc1 --- /dev/null +++ b/build-release.cmd @@ -0,0 +1 @@ +"%ProgramFiles%\7-Zip\7z.exe" a -tzip releases\retro-b5500-%1.zip build-release.cmd emulator\ webui\ -x!webui\tools\* -x!webui\prototypes\* tools\*.html tools\*.job \ No newline at end of file diff --git a/emulator/B5500CentralControl.js b/emulator/B5500CentralControl.js index 1885255..873d853 100644 --- a/emulator/B5500CentralControl.js +++ b/emulator/B5500CentralControl.js @@ -55,19 +55,16 @@ function B5500CentralControl(global) { this.nextTimeStamp = 0; // Next actual Date.getTime() for timer tick this.timer = null; // Reference to the RTC setCallback id. - // Establish contexts for asynchronously-called methods - this.boundTock = B5500CentralControl.bindMethod(this.tock, this); - this.clear(); // Create and initialize the Central Control state } /**************************************/ /* Global constants */ -B5500CentralControl.version = "0.16"; +B5500CentralControl.version = "0.17"; B5500CentralControl.memReadCycles = 2; // assume 2 µs memory read cycle time (the other option was 3 µs) -B5500CentralControl.memWriteCycles = 3; // assume 4 µs memory write cycle time (the other option was 6 µs) +B5500CentralControl.memWriteCycles = 4; // assume 4 µs memory write cycle time (the other option was 6 µs) B5500CentralControl.rtcTick = 1000/60; // Real-time clock period, milliseconds B5500CentralControl.pow2 = [ // powers of 2 from 0 to 52 @@ -135,21 +132,21 @@ B5500CentralControl.unitSpecs = { DKA: {unitIndex: 29, designate: 6, unitClass: "B5500DiskUnit"}, DRB: {unitIndex: 30, designate: 8, unitClass: null}, DRA: {unitIndex: 31, designate: 4, unitClass: null}, - MTT: {unitIndex: 32, designate: 31, unitClass: null}, - MTS: {unitIndex: 33, designate: 29, unitClass: null}, - MTR: {unitIndex: 34, designate: 27, unitClass: null}, - MTP: {unitIndex: 35, designate: 25, unitClass: null}, - MTN: {unitIndex: 36, designate: 23, unitClass: null}, - MTM: {unitIndex: 37, designate: 21, unitClass: null}, - MTL: {unitIndex: 38, designate: 19, unitClass: null}, - MTK: {unitIndex: 39, designate: 17, unitClass: null}, - MTJ: {unitIndex: 40, designate: 15, unitClass: null}, - MTH: {unitIndex: 41, designate: 13, unitClass: null}, - MTF: {unitIndex: 42, designate: 11, unitClass: null}, - MTE: {unitIndex: 43, designate: 9, unitClass: null}, - MTD: {unitIndex: 44, designate: 7, unitClass: null}, - MTC: {unitIndex: 45, designate: 5, unitClass: null}, - MTB: {unitIndex: 46, designate: 3, unitClass: null}, + MTT: {unitIndex: 32, designate: 31, unitClass: "B5500MagTapeDrive"}, + MTS: {unitIndex: 33, designate: 29, unitClass: "B5500MagTapeDrive"}, + MTR: {unitIndex: 34, designate: 27, unitClass: "B5500MagTapeDrive"}, + MTP: {unitIndex: 35, designate: 25, unitClass: "B5500MagTapeDrive"}, + MTN: {unitIndex: 36, designate: 23, unitClass: "B5500MagTapeDrive"}, + MTM: {unitIndex: 37, designate: 21, unitClass: "B5500MagTapeDrive"}, + MTL: {unitIndex: 38, designate: 19, unitClass: "B5500MagTapeDrive"}, + MTK: {unitIndex: 39, designate: 17, unitClass: "B5500MagTapeDrive"}, + MTJ: {unitIndex: 40, designate: 15, unitClass: "B5500MagTapeDrive"}, + MTH: {unitIndex: 41, designate: 13, unitClass: "B5500MagTapeDrive"}, + MTF: {unitIndex: 42, designate: 11, unitClass: "B5500MagTapeDrive"}, + MTE: {unitIndex: 43, designate: 9, unitClass: "B5500MagTapeDrive"}, + MTD: {unitIndex: 44, designate: 7, unitClass: "B5500MagTapeDrive"}, + MTC: {unitIndex: 45, designate: 5, unitClass: "B5500MagTapeDrive"}, + MTB: {unitIndex: 46, designate: 3, unitClass: "B5500MagTapeDrive"}, MTA: {unitIndex: 47, designate: 1, unitClass: "B5500MagTapeDrive"}}; @@ -206,12 +203,12 @@ B5500CentralControl.prototype.clear = function clear() { this.LOFF = 0; // Load button pressed on console this.CTMF = 0; // Commence timing FF this.P2BF = 0; // Processor 2 busy FF - this.HP2F = 1; // Halt processor 2 FF + this.HP2F = 0; // Halt processor 2 FF + this.ccLatch = 0x20; // I/O Unit busy & P2 latched status (reset by console UI) this.interruptMask = 0; // Interrupt status mask this.interruptLatch = 0; // Interrupt latched status (reset by console UI) this.iouMask = 0; // I/O Unit busy status mask - this.iouLatch = 0; // I/O Unit busy latched status (reset by console UI) this.unitBusyLatch = 0; // Peripheral unit latched status (reset by console UI) this.unitBusyMask = 0; // Peripheral unit busy-status bitmask @@ -225,6 +222,7 @@ B5500CentralControl.prototype.clear = function clear() { this.P2 = (this.PB1L ? this.PA : this.PB); if (!this.P2) { this.P2BF = 1; // mark non-existent P2 as busy + this.ccLatch |= 0x10; } }; @@ -459,18 +457,6 @@ B5500CentralControl.prototype.clearInterrupt = function clearInterrupt() { case 0x12: // @22: Time interval this.CCI03F = 0; break; - case 0x13: // @23: I/O busy - this.CCI04F = 0; - break; - case 0x14: // @24: Keyboard request - this.CCI05F = 0; - break; - case 0x15: // @25: Printer 1 finished - this.CCI06F = 0; - break; - case 0x16: // @26: Printer 2 finished - this.CCI07F = 0; - break; case 0x17: // @27: I/O 1 finished this.CCI08F = 0; this.AD1F = 0; // make unit non-busy @@ -491,31 +477,33 @@ B5500CentralControl.prototype.clearInterrupt = function clearInterrupt() { this.AD4F = 0; // make unit non-busy this.iouMask &= 0x7; break; - case 0x1B: // @33: P2 busy - this.CCI12F = 0; + case 0x15: // @25: Printer 1 finished + this.CCI06F = 0; break; + case 0x16: // @26: Printer 2 finished + this.CCI07F = 0; + break; + + case 0x34: // @64-75: P1 syllable-dependent + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + p1.I &= 0x0F; + break; + case 0x1C: // @34: Inquiry request this.CCI13F = 0; break; - case 0x1D: // @35: Special interrupt 1 - this.CCI14F = 0; - break; - case 0x1E: // @36: Disk file 1 read check finished - this.CCI15F = 0; - break; - case 0x1F: // @37: Disk file 2 read check finished - this.CCI16F = 0; + case 0x14: // @24: Keyboard request + this.CCI05F = 0; break; - case 0x20: // @40: P2 memory parity error - if (p2) {p2.I &= 0xFE} - break; - case 0x21: // @41: P2 invalid address error - if (p2) {p2.I &= 0xFD} - break; - case 0x22: // @42: P2 stack overflow - if (p2) {p2.I &= 0xFB} - break; case 0x24: // @44-55: P2 syllable-dependent case 0x25: case 0x26: @@ -538,19 +526,32 @@ B5500CentralControl.prototype.clearInterrupt = function clearInterrupt() { case 0x32: // @62: P1 stack overflow p1.I &= 0xFB; break; - case 0x34: // @64-75: P1 syllable-dependent - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - p1.I &= 0x0F; + + case 0x20: // @40: P2 memory parity error + if (p2) {p2.I &= 0xFE} + break; + case 0x21: // @41: P2 invalid address error + if (p2) {p2.I &= 0xFD} + break; + case 0x22: // @42: P2 stack overflow + if (p2) {p2.I &= 0xFB} break; + case 0x1E: // @36: Disk file 1 read check finished + this.CCI15F = 0; + break; + case 0x1F: // @37: Disk file 2 read check finished + this.CCI16F = 0; + break; + case 0x13: // @23: I/O busy + this.CCI04F = 0; + break; + case 0x1B: // @33: P2 busy + this.CCI12F = 0; + break; + case 0x1D: // @35: Special interrupt 1 + this.CCI14F = 0; + break; default: // no interrupt vector was set break; } @@ -574,7 +575,7 @@ B5500CentralControl.prototype.tock = function tock() { } } interval = (this.nextTimeStamp += B5500CentralControl.rtcTick) - thisTime; - this.timer = setCallback(this.boundTock, this, interval); + this.timer = setCallback(tock, this, interval); }; /**************************************/ @@ -587,12 +588,18 @@ B5500CentralControl.prototype.readTimer = function readTimer() { /**************************************/ B5500CentralControl.prototype.haltP2 = function haltP2() { - /* Called by P1 to halt P2. storeForInterrupt() will set P2BF=0 */ + /* Called by P1 to halt P2. We know that P2 is not currently running on this + thread, so check to see if it's running at all and has a callback scheduled. + If so, cancel the existing callback and schedule a new one for immediate + execution. With HP2F set, P2 will store its registers and stop at next SECL */ this.HP2F = 1; - // We know P2 is not currently running on this thread, so save its registers - if (this.P2 && this.P2.busy) { - this.P2.storeForInterrupt(1, 0); + this.ccLatch |= 0x20; + if (this.P2 && this.P2BF) { + if (this.P2.scheduler) { + clearCallback(this.P2.scheduler); + } + this.P2.scheduler = setCallback(this.P2.schedule, this.P2, 0); } }; @@ -608,6 +615,7 @@ B5500CentralControl.prototype.initiateP2 = function initiateP2() { this.signalInterrupt(); } else { this.P2BF = 1; + this.ccLatch |= 0x10; this.HP2F = 0; this.P2.initiateAsP2(); } @@ -620,22 +628,22 @@ B5500CentralControl.prototype.initiateIO = function initiateIO() { if (this.IO1 && this.IO1.REMF && !this.AD1F) { this.AD1F = 1; this.iouMask |= 0x1; - this.iouLatch |= 0x1; + this.ccLatch |= 0x1; this.IO1.initiate(); } else if (this.IO2 && this.IO2.REMF && !this.AD2F) { this.AD2F = 1; this.iouMask |= 0x2; - this.iouLatch |= 0x2; + this.ccLatch |= 0x2; this.IO2.initiate(); } else if (this.IO3 && this.IO3.REMF && !this.AD3F) { this.AD3F = 1; this.iouMask |= 0x4; - this.iouLatch |= 0x4; + this.ccLatch |= 0x4; this.IO3.initiate(); } else if (this.IO4 && this.IO4.REMF && !this.AD4F) { this.AD4F = 1; this.iouMask |= 0x8; - this.iouLatch |= 0x8; + this.ccLatch |= 0x8; this.IO4.initiate(); } else { this.CCI04F = 1; // set I/O busy interrupt @@ -700,30 +708,16 @@ B5500CentralControl.prototype.setUnitBusy = function setUnitBusy(index, busy) { }; /**************************************/ -B5500CentralControl.prototype.fetchInterruptLatch = function fetchInterruptLatch() { - /* Returns and resets this.interruptLatch; used by console UI */ - var latch = this.interruptLatch; +B5500CentralControl.prototype.fetchCCLatches = function fetchCCLatches(latches) { + /* Returns the current latches in the "latches" array and and resets them. + Used by the Console UI */ + latches[0] = this.ccLatch; + this.ccLatch = this.iouMask | (this.P2BF << 4) | (this.HP2F << 5); + latches[1] = this.interruptLatch; this.interruptLatch = this.interruptMask; - return latch; -}; - -/**************************************/ -B5500CentralControl.prototype.fetchIOUnitLatch = function fetchIOUnitLatch() { - /* Returns and resets this.iouLatch; used by console UI */ - var latch = this.iouLatch; - - this.iouLatch = this.iouMask; - return latch; -}; - -/**************************************/ -B5500CentralControl.prototype.fetchUnitBusyLatch = function fetchUnitBusyLatch() { - /* Returns and resets this.unitBusyLatch; used by console UI */ - var latch = this.unitBusyLatch; - + latches[2] = this.unitBusyLatch; this.unitBusyLatch = this.unitBusyMask; - return latch; }; /**************************************/ @@ -791,6 +785,7 @@ B5500CentralControl.prototype.load = function load(dontStart) { return function boundLoadCompleteAnon() {return that.loadComplete(dontStart)} }(this, dontStart)); + this.clear(); // initialize P1/P2 configuration if (!this.P1 || this.P1.busy) { // P1 is busy or not available result = 1; } else if (!this.testUnitReady(22)) { // SPO not ready @@ -798,29 +793,28 @@ B5500CentralControl.prototype.load = function load(dontStart) { } else if (this.testUnitBusy(22)) { // SPO is busy result = 3; } else { // ready to rock 'n roll - this.clear(); this.nextTimeStamp = new Date().getTime(); this.tock(); this.LOFF = 1; if (this.IO1 && this.IO1.REMF && !this.AD1F) { this.AD1F = 1; this.iouMask |= 0x1; - this.iouLatch |= 0x1; + this.ccLatch |= 0x1; this.IO1.initiateLoad(this.cardLoadSelect, boundLoadComplete); } else if (this.IO2 && this.IO2.REMF && !this.AD2F) { this.AD2F = 1; this.iouMask |= 0x2; - this.iouLatch |= 0x2; + this.ccLatch |= 0x2; this.IO2.initiateLoad(this.cardLoadSelect, boundLoadComplete); } else if (this.IO3 && this.IO3.REMF && !this.AD3F) { this.AD3F = 1; this.iouMask |= 0x4; - this.iouLatch |= 0x4; + this.ccLatch |= 0x4; this.IO3.initiateLoad(this.cardLoadSelect, boundLoadComplete); } else if (this.IO4 && this.IO4.REMF && !this.AD4F) { this.AD4F = 1; this.iouMask |= 0x8; - this.iouLatch |= 0x8; + this.ccLatch |= 0x8; this.IO4.initiateLoad(this.cardLoadSelect, boundLoadComplete); } else { this.CCI04F = 1; // set I/O busy interrupt diff --git a/emulator/B5500Processor.js b/emulator/B5500Processor.js index 36b906e..547ccf6 100644 --- a/emulator/B5500Processor.js +++ b/emulator/B5500Processor.js @@ -34,13 +34,13 @@ function B5500Processor(procID, cc) { this.processorID = procID; // Processor ID ("A" or "B") this.mnemonic = "P" + procID; // Unit mnemonic - this.cc = cc; // Reference back to Central Control module + this.cc = cc; // Reference back to CentralControl module this.scheduler = null; // Reference to current setCallback token this.accessor = { // Memory access control block requestorID: procID, // Memory requestor ID addr: 0, // Memory address word: 0, // 48-bit data word - MAIL: 0, // Truthy if attempt to access @000-@777 in normal state + MAIL: 0, // Truthy if attempt to access @000-@777 in Normal State MPED: 0, // Truthy if memory parity error MAED: 0 // Truthy if memory address/inhibit error }; @@ -54,9 +54,10 @@ function B5500Processor(procID, cc) { /**************************************/ -B5500Processor.cyclesPerMilli = 1000; // clock cycles per millisecond (1000 = 1.0 MHz) +B5500Processor.cyclesPerMilli = 1000; // clock cycles per millisecond (1000 => 1.0 MHz) B5500Processor.timeSlice = 4000; // this.run() timeslice, clocks -B5500Processor.delaySamples = 1000; // this.delayDeltaAvg sampling average basis +B5500Processor.delayAlpha = 0.999; // decay factor for exponential weighted average delay +B5500Processor.slackAlpha = 0.9999; // decay factor for exponential weighted average slack B5500Processor.collation = [ // index by BIC to get collation value 53, 54, 55, 56, 57, 58, 59, 60, // @00: 0 1 2 3 4 5 6 7 @@ -94,7 +95,7 @@ B5500Processor.prototype.clear = function clear() { this.MSFF = 0; // Mark-stack FF (word mode: MSCW is pending RCW, physically also TFFF & Q12F) this.MWOF = 0; // Memory write obtained FF this.N = 0; // Octal shift counter for B - this.NCSF = 0; // Normal/control state FF (1=normal) + this.NCSF = 0; // Normal/Control State FF (1=normal) this.P = 0; // Current program instruction word register this.PROF = 0; // P contents valid this.Q = 0; // Misc. FFs (bits 1-9 only: Q07F=hardware-induced interrupt, Q09F=enable parallel adder for R-relative addressing) @@ -123,6 +124,8 @@ B5500Processor.prototype.clear = function clear() { this.procStart = 0; // Javascript time that the processor started running, ms this.procTime = 0.001; // Total processor running time, ms this.procSlack = 0; // Total processor throttling delay, ms + this.procSlackAvg = 0; // Average slack time per time slice, ms + this.procRunAvg = 0; // Average run time per time slice, ms }; /**************************************/ @@ -136,7 +139,7 @@ B5500Processor.prototype.accessError = function accessError() { this.I |= 0x01; // set I01F: memory parity error this.cc.signalInterrupt(); if (this.isP1 && !this.NCSF) { - this.stop(); // P1 memory parity in control state stops the proc + this.stop(); // P1 memory parity in Control State stops the proc } } }; @@ -326,10 +329,11 @@ B5500Processor.prototype.adjustAEmpty = function adjustAEmpty() { this.S++; this.storeBviaS(); // [S] = B } + } else { + this.BROF = 1; } this.B = this.A; this.AROF = 0; - this.BROF = 1; // else we're done -- A is already empty } }; @@ -388,23 +392,23 @@ B5500Processor.prototype.adjustABEmpty = function adjustABEmpty() { prior contents into memory, as necessary. */ if (this.BROF) { - this.BROF = 0; if ((this.S >>> 6) == this.R && this.NCSF) { this.I |= 0x04; // set I03F: stack overflow this.cc.signalInterrupt(); } else { this.S++; this.storeBviaS(); // [S] = B + this.BROF = 0; } } if (this.AROF) { - this.AROF = 0; if ((this.S >>> 6) == this.R && this.NCSF) { this.I |= 0x04; // set I03F: stack overflow this.cc.signalInterrupt(); } else { this.S++; this.storeAviaS(); // [S] = A + this.AROF = 0; } } }; @@ -558,7 +562,7 @@ B5500Processor.prototype.streamAdjustDestChar = function streamAdjustDestChar() }; /**************************************/ -B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest(count) { +B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest(count, numeric) { /* Compares source characters to destination characters according to the processor collating sequence. "count" is the number of source characters to process. @@ -574,7 +578,11 @@ B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest( may be required only for the first word in the destination string, if B may have been left in an updated state by a prior syllable */ var aBit; // A register bit nr + var aw; // current A register word var bBit; // B register bit nr + var bw; // current B register word + var Q03F = (this.Q & 0x04) >>> 2; // local copy of Q03F: inequality detected + var Q04F = (this.Q & 0x08) >>> 3; // local copy of Q04F: B not dirty var yc = 0; // local Y register var zc = 0; // local Z register @@ -584,11 +592,11 @@ B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest( if (count) { if (this.BROF) { if (this.K == 0) { - this.Q |= 0x08; // set Q04F -- at start of word, no need to store B later + Q04F = 1; // set Q04F -- at start of word, no need to store B later } } else { this.loadBviaS(); // B = [S] - this.Q |= 0x08; // set Q04F -- just loaded B, no need to store it later + Q04F = 1; // set Q04F -- just loaded B, no need to store it later } if (!this.AROF) { this.loadAviaM(); // A = [M] @@ -601,15 +609,17 @@ B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest( this.V = count & 0x07; aBit = this.G*6; // A-bit number + aw = this.A; bBit = this.K*6; // B-bit number + bw = this.B; do { this.cycleCount++; // approximate the timing - if (this.Q & 0x04) { // inequality already detected -- just count down + if (Q03F) { // inequality already detected -- just count down if (count >= 8) { count -= 8; - if (!(this.Q & 0x08)) { // test Q04F to see if B may be dirty + if (!Q04F) { // test Q04F to see if B may be dirty this.storeBviaS(); // [S] = B - this.Q |= 0x08; // set Q04F so we won't store B anymore + Q04F = 1; // set Q04F so we won't store B anymore } this.BROF = 0; this.S++; @@ -620,9 +630,9 @@ B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest( if (this.K < 7) { this.K++; } else { - if (!(this.Q & 0x08)) { // test Q04F to see if B may be dirty + if (!Q04F) { // test Q04F to see if B may be dirty this.storeBviaS(); // [S] = B - this.Q |= 0x08; // set Q04F so we won't store B anymore + Q04F = 1; // set Q04F so we won't store B anymore } this.K = 0; this.BROF = 0; @@ -637,9 +647,20 @@ B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest( } } } else { // strings still equal -- check this character - if ((yc = this.cc.fieldIsolate(this.A, aBit, 6)) != (zc = this.cc.fieldIsolate(this.B, bBit, 6))) { - this.Q |= 0x04; // set Q03F to stop further comparison - this.MSFF = (B5500Processor.collation[yc] > B5500Processor.collation[zc] ? 1 : 0); + if (numeric) { + yc = this.cc.fieldIsolate(aw, aBit+2, 4); + zc = this.cc.fieldIsolate(bw, bBit+2, 4); + } else { + yc = this.cc.fieldIsolate(aw, aBit, 6); + zc = this.cc.fieldIsolate(bw, bBit, 6); + } + if (yc != zc) { + Q03F = 1; // set Q03F to stop further comparison + if (numeric) { + this.MSFF = (yc > zc ? 1 : 0); + } else { + this.MSFF = (B5500Processor.collation[yc] > B5500Processor.collation[zc] ? 1 : 0); + } } else { // strings still equal -- advance to next character count--; if (bBit < 42) { @@ -648,13 +669,14 @@ B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest( } else { bBit = 0; this.K = 0; - if (!(this.Q & 0x08)) { // test Q04F to see if B may be dirty + if (!Q04F) { // test Q04F to see if B may be dirty this.storeBviaS(); // [S] = B - this.Q |= 0x08; // set Q04F so we won't store B anymore + Q04F = 1; // set Q04F so we won't store B anymore } this.S++; if (count > 0) { this.loadBviaS(); // B = [S] + bw = this.B; } else { this.BROF = 0; } @@ -668,6 +690,7 @@ B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest( this.M++; if (count > 0) { this.loadAviaM(); // A = [M] + aw = this.A; } else { this.AROF = 0; } @@ -676,6 +699,7 @@ B5500Processor.prototype.compareSourceWithDest = function compareSourceWithDest( } } while (count); + this.Q |= (Q03F << 2) | (Q04F << 3); this.Y = yc; // for display only this.Z = zc; // for display only } @@ -687,7 +711,9 @@ B5500Processor.prototype.fieldArithmetic = function fieldArithmetic(count, addin "count" indicates the length of the fields to be operated upon. "adding" will be false if this call is for FSU, otherwise it's for FAD */ var aBit; // A register bit nr + var aw; // current A register word var bBit; // B register bit nr + var bw; // current B register word var carry = 0; // carry/borrow bit var compl = false; // complement addition (i.e., subtract the digits) var TFFF; // local copy of MSFF/TFFF @@ -699,7 +725,7 @@ B5500Processor.prototype.fieldArithmetic = function fieldArithmetic(count, addin var zcompl = false; // complement destination digits var zd; // destination digit - this.compareSourceWithDest(count); + this.compareSourceWithDest(count, true); this.cycleCount += 2; // approximate the timing thus far if (this.Q & 0x20) { // Q06F => count > 0, so there's characters to add this.Q &= ~(0x28); // reset Q06F and Q04F @@ -731,9 +757,11 @@ B5500Processor.prototype.fieldArithmetic = function fieldArithmetic(count, addin this.Q |= 0x80; // set Q08F (for display only) aBit = this.G*6; // A-bit number + aw = this.A; bBit = this.K*6; // B-bit number - yd = (this.cc.fieldIsolate(this.A, aBit, 2) == 2 ? 2 : 0); // source sign - zd = (this.cc.fieldIsolate(this.B, bBit, 2) == 2 ? 2 : 0); // dest sign + bw = this.B; + yd = (this.cc.fieldIsolate(aw, aBit, 2) == 2 ? 2 : 0); // source sign + zd = (this.cc.fieldIsolate(bw, bBit, 2) == 2 ? 2 : 0); // dest sign compl = (yd == zd ? !adding : adding); // determine if complement needed resultNegative = !( // determine sign of result (zd == 0 && !compl) || @@ -755,8 +783,8 @@ B5500Processor.prototype.fieldArithmetic = function fieldArithmetic(count, addin do { count--; this.cycleCount += 2; - yd = this.cc.fieldIsolate(this.A, aBit+2, 4); // get the source digit - zd = this.cc.fieldIsolate(this.B, bBit+2, 4); // get the dest digit + yd = this.cc.fieldIsolate(aw, aBit+2, 4); // get the source digit + zd = this.cc.fieldIsolate(bw, bBit+2, 4); // get the dest digit sd = (ycompl ? 9-yd : yd) + (zcompl ? 9-zd : zd) + carry; // develop binary digit sum if (sd <= 9) { carry = 0; @@ -769,9 +797,10 @@ B5500Processor.prototype.fieldArithmetic = function fieldArithmetic(count, addin resultNegative = false; } - this.B = this.cc.fieldInsert(this.B, bBit, 6, sd); + bw = this.cc.fieldInsert(bw, bBit, 6, sd); if (count == 0) { + this.B = bw; this.storeBviaS(); // [S] = B, store final dest word } else { if (bBit > 0) { @@ -780,9 +809,11 @@ B5500Processor.prototype.fieldArithmetic = function fieldArithmetic(count, addin } else { bBit = 42; this.K = 7; + this.B = bw; this.storeBviaS(); // [S] = B this.S--; this.loadBviaS(); // B = [S] + bw = this.B; } if (aBit > 0) { aBit -= 6; @@ -792,6 +823,7 @@ B5500Processor.prototype.fieldArithmetic = function fieldArithmetic(count, addin this.G = 7; this.M--; this.loadAviaM(); // A = [M] + aw = this.A; } } } while (count); @@ -820,6 +852,8 @@ B5500Processor.prototype.fieldArithmetic = function fieldArithmetic(count, addin this.M++; } } + this.A = aw; + this.B = bw; this.AROF = this.BROF = 0; this.H = this.V = this.N = 0; this.MSFF = (compl ? 1-carry : carry); // MSFF/TFFF = overflow indicator @@ -932,15 +966,13 @@ B5500Processor.prototype.streamProgramToDest = function streamProgramToDest(coun }; /**************************************/ -B5500Processor.prototype.streamSourceToDest = function streamSourceToDest(count, transform) { - /* General driver for character-mode character transfers from source to - destination, such as TRS or TRZ. - "count" is the number of source characters to transfer. - "transform" is a function(bBit, c, count) that determines how the characters - are transferred from the source (A) to destination (B) */ +B5500Processor.prototype.streamCharacterToDest = function streamCharacterToDest(count) { + /* Transfers character transfers from source to destination for the TRS syllable. + "count" is the number of source characters to transfer */ var aBit; // A register bit nr var aw; // current A register word var bBit; // B register bit nr + var bw; // current B register word var c; // current character this.streamAdjustSourceChar(); @@ -952,13 +984,14 @@ B5500Processor.prototype.streamSourceToDest = function streamSourceToDest(count, if (!this.AROF) { this.loadAviaM(); // A = [M] } - this.cycleCount += count*2; // approximate the timing + this.cycleCount += 10 + count*2;// approximate the timing aBit = this.G*6; // A-bit number aw = this.A; bBit = this.K*6; // B-bit number + bw = this.B; do { c = this.cc.fieldIsolate(aw, aBit, 6); - transform.call(this, bBit, c, count) + bw = this.cc.fieldInsert(bw, bBit, 6, c); count--; if (bBit < 42) { bBit += 6; @@ -966,10 +999,12 @@ B5500Processor.prototype.streamSourceToDest = function streamSourceToDest(count, } else { bBit = 0; this.K = 0; + this.B = bw; this.storeBviaS(); // [S] = B this.S++; if (count > 0 && count < 8) { // only need to load B if a partial word is left this.loadBviaS(); // B = [S] + bw = this.B; } else { this.BROF = 0; } @@ -989,31 +1024,115 @@ B5500Processor.prototype.streamSourceToDest = function streamSourceToDest(count, } } } while (count); + this.B = bw; this.Y = c; // for display purposes only } }; /**************************************/ -B5500Processor.prototype.streamToDest = function streamToDest(count, transform) { - /* General driver for character-mode character operations on the destination - from a non-A register source, such as TBN. - "count" is the number of characters to transfer. - "transform" is a function(bBit, count) that determines how the characters - are stored to the destination (B). Returning truthy terminates the process - without incrementing the destination address */ +B5500Processor.prototype.streamNumericToDest = function streamNumericToDest(count, zones) { + /* Transfers character transfers from source to destination for the TRS syllable. + "count" is the number of source characters to transfer */ + var aBit; // A register bit nr + var aw; // current A register word var bBit; // B register bit nr + var bw; // current B register word + var c; // current character + this.streamAdjustSourceChar(); this.streamAdjustDestChar(); if (count) { if (!this.BROF) { this.loadBviaS(); // B = [S] } - this.cycleCount += count*2; // approximate the timing + if (!this.AROF) { + this.loadAviaM(); // A = [M] + } + if (zones) { // approximate the timing + this.cycleCount += 5 + count*4; + } else { + this.cycleCount += 10 + count*3; + } + + aBit = this.G*6; // A-bit number + aw = this.A; bBit = this.K*6; // B-bit number + bw = this.B; do { - if (transform.call(this, bBit, count)) { - count = 0; + c = this.cc.fieldIsolate(aw, aBit, 6); + if (zones) { // transfer only the zone portion of the char + bw = this.cc.fieldInsert(bw, bBit, 2, c >>> 4); + } else { // transfer only the numeric portion of the char + bw = this.cc.fieldInsert(bw, bBit+2, 4, c); + if (count == 1 && (c & 0x30) == 0x20) { + this.MSFF = 1; // neg. sign + } + } + count--; + if (bBit < 42) { + bBit += 6; + this.K++; } else { + bBit = 0; + this.K = 0; + this.B = bw; + this.storeBviaS(); // [S] = B + this.S++; + if (count > 0) { + this.loadBviaS(); // B = [S] + bw = this.B; + } else { + this.BROF = 0; + } + } + if (aBit < 42) { + aBit += 6; + this.G++; + } else { + aBit = 0; + this.G = 0; + this.M++; + if (count > 0) { // only need to load A if there's more to do + this.loadAviaM(); // A = [M] + aw = this.A; + } else { + this.AROF = 0; + } + } + } while (count); + this.B = bw; + this.Y = c; // for display purposes only + } +}; + +/**************************************/ +B5500Processor.prototype.streamBlankForNonNumeric = function streamBlankForNonNumeric(count) { + /* Implements the TBN (Transfer Blanks for Non-Numeric) syllable, which is + generally used to suppress leading zeroes in numeric strings. Transfers blanks + to the destination under control of the count as long as the destination characters + are not in the range "1"-"9". Sets MSFF (TFFF) true if the count is exhausted. + "count" is the maximum number of characters to blank */ + var bBit; // B register bit nr + var bw; // current B register word + var c; // current destination character + + this.MSFF = 1; // assume the count will be exhausted + this.streamAdjustDestChar(); + if (count) { + if (!this.BROF) { + this.loadBviaS(); // B = [S] + } + bBit = this.K*6; // B-bit number + bw = this.B; + do { + this.cycleCount += 2; // approximate the timing + c = this.cc.fieldIsolate(bw, bBit, 6); + if (c > 0 && c <= 9) { + this.MSFF = 0; // is numeric and non-zero: stop blanking + this.Q |= 0x04; // set Q03F (display only) + break; // terminate, pointing at this char + } else { + bw = this.cc.fieldInsert(bw, bBit, 6, 0x30); // replace with blank count--; if (bBit < 42) { bBit += 6; @@ -1021,16 +1140,20 @@ B5500Processor.prototype.streamToDest = function streamToDest(count, transform) } else { bBit = 0; this.K = 0; - this.storeBviaS(); // [S] = B + this.B = bw; + this.storeBviaS(); // [S] = B this.S++; - if (count > 0 && count < 8) { // only need to load B if a partial word is left - this.loadBviaS(); // B = [S] + if (count > 0) { + this.loadBviaS(); // B = [S] + bw = this.B; } else { this.BROF = 0; } } } } while (count); + this.B = bw; + this.Z = c; // for display purposes only } }; @@ -1200,7 +1323,7 @@ B5500Processor.prototype.storeForInterrupt = function storeForInterrupt(forced, var temp; if (forced || forTest) { - this.NCSF = 0; // switch to control state + this.NCSF = 0; // switch to Control State } if (this.CWMF) { @@ -1470,7 +1593,7 @@ B5500Processor.prototype.initiate = function initiate(forTest) { /**************************************/ B5500Processor.prototype.initiateAsP2 = function initiateAsP2() { - /* Called from Central Control to initiate the processor as P2. Fetches the + /* Called from CentralControl to initiate the processor as P2. Fetches the INCW from @10, injects an initiate P2 syllable into T, and calls start() */ this.NCSF = 0; // make sure P2 is in Control State to execute the IP1 & access low mem @@ -1573,7 +1696,7 @@ B5500Processor.prototype.singlePrecisionAdd = function singlePrecisionAdd(adding var xa = 0; // extension to A for scaling (pseudo X) var xb = 0; // extension to B for scaling (pseudo X) - this.cycleCount += 4; // estimate some general overhead + this.cycleCount += 2; // estimate some general overhead this.adjustABFull(); this.AROF = 0; // A is unconditionally marked empty ma = this.A % 0x8000000000; // extract the A mantissa @@ -1731,7 +1854,7 @@ B5500Processor.prototype.singlePrecisionMultiply = function singlePrecisionMulti var sb; // mantissa sign of B (ditto) var xx; // local copy of X for multiplier - this.cycleCount += 4; // estimate some general overhead + this.cycleCount += 2; // estimate some general overhead this.adjustABFull(); this.AROF = 0; // A is unconditionally marked empty ma = this.A % 0x8000000000; // extract the A mantissa @@ -1863,15 +1986,14 @@ B5500Processor.prototype.singlePrecisionDivide = function singlePrecisionDivide( var sb; // mantissa sign of B (ditto) var xx = 0; // local copy of X for quotient development - this.cycleCount += 4; // estimate some general overhead + this.cycleCount += 2; // estimate some general overhead this.adjustABFull(); this.AROF = 0; // A is unconditionally marked empty ma = this.A % 0x8000000000; // extract the A mantissa mb = this.B % 0x8000000000; // extract the B mantissa if (ma == 0) { // if A mantissa is zero - this.A = this.B = 0; // result is all zeroes - if (this.NCSF) { + if (this.NCSF) { // and we're in Normal State this.I = (this.I & 0x0F) | 0xD0; // set I05/7/8: divide by zero this.cc.signalInterrupt(); } @@ -1889,13 +2011,13 @@ B5500Processor.prototype.singlePrecisionDivide = function singlePrecisionDivide( // Normalize A for 39 bits (13 octades) while (ma < 0x1000000000) { this.cycleCount++; - ma *= 8; // shift left + ma *= 8; // shift left ea--; } // Normalize B for 39 bits (13 octades) while (mb < 0x1000000000) { this.cycleCount++; - mb *= 8; // shift left + mb *= 8; // shift left eb--; } @@ -1977,8 +2099,7 @@ B5500Processor.prototype.integerDivide = function integerDivide() { mb = this.B % 0x8000000000; // extract the B mantissa if (ma == 0) { // if A mantissa is zero - this.A = this.B = 0; // result is all zeroes - if (this.NCSF) { + if (this.NCSF) { // and we're in Normal State this.I = (this.I & 0x0F) | 0xD0; // set I05/7/8: divide by zero this.cc.signalInterrupt(); } @@ -2077,8 +2198,7 @@ B5500Processor.prototype.remainderDivide = function remainderDivide() { mb = this.B % 0x8000000000; // extract the B mantissa if (ma == 0) { // if A mantissa is zero - this.A = this.B = 0; // result is all zeroes - if (this.NCSF) { + if (this.NCSF) { // and we're in Normal State this.I = (this.I & 0x0F) | 0xD0; // set I05/7/8: divide by zero this.cc.signalInterrupt(); } @@ -2795,7 +2915,7 @@ B5500Processor.prototype.operandCall = function operandCall() { if (this.NCSF) { this.I = (this.I & 0x0F) | 0x70; // set I05/6/7: p-bit this.cc.signalInterrupt(); - // else if control state, we're done + // else if Control State, we're done } break; @@ -2843,7 +2963,7 @@ B5500Processor.prototype.descriptorCall = function descriptorCall() { if (this.NCSF) { this.I = (this.I & 0x0F) | 0x70; // set I05/6/7: p-bit this.cc.signalInterrupt(); - // else if control state, we're done + // else if Control State, we're done } break; @@ -2864,6 +2984,7 @@ B5500Processor.prototype.run = function run() { current program word must be in P with PROF set, and the C & L registers must point to the next syllable to be executed. This routine will continue to run while this.runCycles < this.cycleLimit */ + var cc = this.cc; // optimize local reference to CentralControl var noSECL = 0; // to support char mode dynamic count from CRF syllable var opcode; // copy of T register var t1; // scratch variable for internal instruction use @@ -2998,7 +3119,7 @@ B5500Processor.prototype.run = function run() { } for (variant=3; variant>0; variant--) { this.B = (this.B % 0x40000000000)*0x40 + - (this.Y = this.cc.fieldIsolate(this.A, this.G*6, 6)); + (this.Y = cc.fieldIsolate(this.A, this.G*6, 6)); if (this.G < 7) { this.G++; } else { @@ -3014,7 +3135,7 @@ B5500Processor.prototype.run = function run() { this.AROF = this.BROF = 0; // invalidate A & B break; - case 0x09: // XX11: control state ops + case 0x09: // XX11: Control State ops switch (variant) { case 0x14: // 2411: ZPI=Conditional Halt if (this.US14X) { // STOP OPERATOR switch on @@ -3035,21 +3156,8 @@ B5500Processor.prototype.run = function run() { } // end switch for XX11 ops break; - case 0x0A: // XX12: TBN=Transfer blank for numeric - this.MSFF = 1; // initialize true-false FF - this.streamToDest(variant, function TBN(bb, count) { - var c = this.Z = this.cc.fieldIsolate(this.B, bb, 6); - var result = 0; - - if (c > 0 && c <= 9) { - this.MSFF = 0; // numeric, non-zero: stop blanking - this.Q |= 0x04; // set Q03F (display only) - result = 1; // terminate, pointing at this char - } else { - this.B = this.cc.fieldInsert(this.B, bb, 6, 0x30); // replace with blank - } - return result; - }); + case 0x0A: // XX12: TBN=Transfer blanks for non-numeric + this.streamBlankForNonNumeric(variant); break; case 0x0C: // XX14: SDA=Store destination address @@ -3118,7 +3226,7 @@ B5500Processor.prototype.run = function run() { if (!this.AROF) { this.loadAviaM(); // A = [M] } - t1 = this.cc.fieldIsolate(this.A, this.G*6, 6); + t1 = cc.fieldIsolate(this.A, this.G*6, 6); this.MSFF = (t1 == variant ? 1 : 0); break; @@ -3127,7 +3235,7 @@ B5500Processor.prototype.run = function run() { if (!this.AROF) { this.loadAviaM(); // A = [M] } - t1 = this.cc.fieldIsolate(this.A, this.G*6, 6); + t1 = cc.fieldIsolate(this.A, this.G*6, 6); this.MSFF = (t1 != variant ? 1 : 0); break; @@ -3136,7 +3244,7 @@ B5500Processor.prototype.run = function run() { if (!this.AROF) { this.loadAviaM(); // A = [M] } - t1 = B5500Processor.collation[this.cc.fieldIsolate(this.A, this.G*6, 6)]; + t1 = B5500Processor.collation[cc.fieldIsolate(this.A, this.G*6, 6)]; t2 = B5500Processor.collation[variant]; this.MSFF = (t1 >= t2 ? 1 : 0); break; @@ -3146,7 +3254,7 @@ B5500Processor.prototype.run = function run() { if (!this.AROF) { this.loadAviaM(); // A = [M] } - t1 = B5500Processor.collation[this.cc.fieldIsolate(this.A, this.G*6, 6)]; + t1 = B5500Processor.collation[cc.fieldIsolate(this.A, this.G*6, 6)]; t2 = B5500Processor.collation[variant]; this.MSFF = (t1 > t2 ? 1 : 0); break; @@ -3186,7 +3294,7 @@ B5500Processor.prototype.run = function run() { if (!this.AROF) { this.loadAviaM(); // A = [M] } - t1 = B5500Processor.collation[this.cc.fieldIsolate(this.A, this.G*6, 6)]; + t1 = B5500Processor.collation[cc.fieldIsolate(this.A, this.G*6, 6)]; t2 = B5500Processor.collation[variant]; this.MSFF = (t1 <= t2 ? 1 : 0); break; @@ -3196,7 +3304,7 @@ B5500Processor.prototype.run = function run() { if (!this.AROF) { this.loadAviaM(); // A = [M] } - t1 = B5500Processor.collation[this.cc.fieldIsolate(this.A, this.G*6, 6)]; + t1 = B5500Processor.collation[cc.fieldIsolate(this.A, this.G*6, 6)]; t2 = B5500Processor.collation[variant]; this.MSFF = (t1 < t2 ? 1 : 0); break; @@ -3206,7 +3314,7 @@ B5500Processor.prototype.run = function run() { if (!this.AROF) { this.loadAviaM(); // A = [M] } - this.Y = t1 = this.cc.fieldIsolate(this.A, this.G*6, 6); + this.Y = t1 = cc.fieldIsolate(this.A, this.G*6, 6); this.Z = variant; // for display only if (B5500Processor.collation[t1] > B5500Processor.collation[variant]) { this.MSFF = (t1 == 0x20 ? 0 : (t1 == 0x3C ? 0 : 1)); // alphanumeric unless | or ! @@ -3220,7 +3328,7 @@ B5500Processor.prototype.run = function run() { if (!this.AROF) { this.loadAviaM(); // A = [M] } - t1 = (this.Y = this.cc.fieldIsolate(this.A, this.G*6, 6)) >>> (5-this.H); + t1 = (this.Y = cc.fieldIsolate(this.A, this.G*6, 6)) >>> (5-this.H); this.MSFF = ((t1 & 0x01) == (variant & 0x01) ? 1 : 0); break; @@ -3269,7 +3377,7 @@ B5500Processor.prototype.run = function run() { if (!this.PROF) { this.loadPviaC(); // fetch the program word, if necessary } - opcode = this.cc.fieldIsolate(this.P, this.L*12, 12); + opcode = cc.fieldIsolate(this.P, this.L*12, 12); if (variant) { // if repeat count from parameter > 0, apply it to the next syllable this.T = opcode = (opcode & 0x3F) + variant*0x40; @@ -3347,18 +3455,18 @@ B5500Processor.prototype.run = function run() { this.A = this.B; // save B in A this.AROF = this.BROF; t1 = this.X; - variant = this.cc.fieldIsolate(t1, 12, 6); // get repeat count + variant = cc.fieldIsolate(t1, 12, 6); // get repeat count if (variant) { // loop count exhausted? - this.C = this.cc.fieldIsolate(t1, 33, 15); // no, restore C, L, and P to loop again - this.L = this.cc.fieldIsolate(t1, 10, 2); + this.C = cc.fieldIsolate(t1, 33, 15); // no, restore C, L, and P to loop again + this.L = cc.fieldIsolate(t1, 10, 2); this.PROF = 0; // require fetch at SECL - this.X = this.cc.fieldInsert(t1, 12, 6, variant-1); // store decremented count in X + this.X = cc.fieldInsert(t1, 12, 6, variant-1); // store decremented count in X } else { t2 = this.S; // save S (not the way the hardware did it) - this.S = this.cc.fieldIsolate(t1, 18, 15); // get prior LCW addr from X value + this.S = cc.fieldIsolate(t1, 18, 15); // get prior LCW addr from X value this.loadBviaS(); // B = [S], fetch prior LCW from stack this.S = t2; // restore S - this.X = this.cc.fieldIsolate(this.B, 9, 39); // store prior LCW (less control bits) in X + this.X = cc.fieldIsolate(this.B, 9, 39); // store prior LCW (less control bits) in X } this.B = this.A; // restore B this.BROF = this.AROF; @@ -3368,16 +3476,16 @@ B5500Processor.prototype.run = function run() { case 0x2A: // XX52: BNS=Begin loop this.cycleCount += 4; this.A = this.B; // save B in A (note that BROF is not altered) - t1 = this.cc.fieldInsert( // construct new LCW: insert repeat count - this.cc.fieldInsert( // insert L - this.cc.fieldInsert(this.X, 33, 15, this.C), // insert C + t1 = cc.fieldInsert( // construct new LCW: insert repeat count + cc.fieldInsert( // insert L + cc.fieldInsert(this.X, 33, 15, this.C), // insert C 10, 2, this.L), - 12, 6, (variant ? variant-1 : 0)); // decrement count for first iteration - this.B = this.cc.fieldInsert(this.X, 0, 2, 3); // set control bits [0:2]=3 + 12, 6, (variant ? variant-1 : 0)); // decrement count for first iteration + this.B = cc.fieldInsert(this.X, 0, 2, 3); // set control bits [0:2]=3 t2 = this.S; // save S (not the way the hardware did it) - this.S = this.cc.fieldIsolate(t1, 18, 15)+1; // get F value from X value and ++ + this.S = cc.fieldIsolate(t1, 18, 15)+1; // get F value from X value and ++ this.storeBviaS(); // [S] = B, save prior LCW in stack - this.X = this.cc.fieldInsert(t1, 18, 15, this.S); // update F value in X + this.X = cc.fieldInsert(t1, 18, 15, this.S); // update F value in X this.S = t2; // restore S this.B = this.A; // restore B (note that BROF is still relevant) this.AROF = 0; // invalidate A @@ -3437,7 +3545,7 @@ B5500Processor.prototype.run = function run() { } for (variant=3; variant>0; variant--) { this.B = (this.B % 0x40000000000)*0x40 + - (this.Y = this.cc.fieldIsolate(this.A, this.G*6, 6)); + (this.Y = cc.fieldIsolate(this.A, this.G*6, 6)); if (this.G < 7) { this.G++; } else { @@ -3457,25 +3565,25 @@ B5500Processor.prototype.run = function run() { break; case 0x30: // XX60: CEQ=Compare equal - this.compareSourceWithDest(variant); + this.compareSourceWithDest(variant, false); this.H = this.V = 0; this.MSFF = (this.Q & 0x04 ? 0 : 1); // if !Q03F, S=D break; case 0x31: // XX61: CNE=Compare not equal - this.compareSourceWithDest(variant); + this.compareSourceWithDest(variant, false); this.H = this.V = 0; this.MSFF = (this.Q & 0x04 ? 1 : 0); // if Q03F, S!=D break; case 0x32: // XX62: CEG=Compare greater or equal - this.compareSourceWithDest(variant); + this.compareSourceWithDest(variant, false); this.H = this.V = 0; this.MSFF = (this.Q & 0x04 ? this.MSFF : 1); // if Q03F&MSFF, S>D; if !Q03F, S=D break; case 0x33: // XX63: CGR=Compare greater - this.compareSourceWithDest(variant); + this.compareSourceWithDest(variant, false); this.H = this.V = 0; this.MSFF = (this.Q & 0x04 ? this.MSFF : 0); // if Q03F&MSFF, S>D break; @@ -3497,13 +3605,13 @@ B5500Processor.prototype.run = function run() { break; case 0x38: // XX70: CEL=Compare equal or less - this.compareSourceWithDest(variant); + this.compareSourceWithDest(variant, false); this.H = this.V = 0; this.MSFF = (this.Q & 0x04 ? 1-this.MSFF : 1); // if Q03F&!MSFF, S>> 4); - }); + this.streamNumericToDest(variant, true); break; case 0x3F: // XX77: TRS=Transfer source characters - this.streamSourceToDest(variant, function TRS(bb, c, count) { - this.B = this.cc.fieldInsert(this.B, bb, 6, c); - }); + this.streamCharacterToDest(variant); break; default: // everything else is a no-op @@ -3644,7 +3742,7 @@ B5500Processor.prototype.run = function run() { } break; - case 0x09: // XX11: control state and communication ops + case 0x09: // XX11: Control State and communication ops switch (variant) { case 0x01: // 0111: PRL=Program Release this.adjustAFull(); @@ -3666,12 +3764,12 @@ B5500Processor.prototype.run = function run() { } else { this.I = (this.I & 0x0F) | 0x60; // set I07/6: continuity bit } - this.cc.signalInterrupt(); + cc.signalInterrupt(); this.A = this.M; this.M = this.R*64 + 9; // store IOD address in PRT[9] this.storeAviaM(); } else { - this.A = this.cc.bitReset(this.A, 2); + this.A = cc.bitReset(this.A, 2); this.storeAviaM(); } this.AROF = 0; @@ -3679,11 +3777,11 @@ B5500Processor.prototype.run = function run() { break; case 0x02: // 0211: ITI=Interrogate Interrupt - if (this.cc.IAR && !this.NCSF) { // control-state only - this.C = this.cc.IAR; + if (cc.IAR && !this.NCSF) { // control-state only + this.C = cc.IAR; this.L = 0; this.S = 0x40; // stack address @100 - this.cc.clearInterrupt(); + cc.clearInterrupt(); this.PROF = 0; // require fetch at SECL } break; @@ -3691,29 +3789,32 @@ B5500Processor.prototype.run = function run() { case 0x04: // 0411: RTR=Read Timer if (!this.NCSF) { // control-state only this.adjustAEmpty(); - this.A = this.cc.readTimer(); + this.A = cc.readTimer(); this.AROF = 1; } break; case 0x08: // 1011: COM=Communicate - if (this.NCSF) { // no-op in control state + if (this.NCSF) { // no-op in Control State this.M = this.R*64 + 9; // address = R+@11 if (this.AROF) { this.storeAviaM(); // [M] = A this.AROF = 0; + } else if (this.BROF) { + this.storeBviaM(); // [M] = B + this.BROF = 0; } else { this.adjustBFull(); this.storeBviaM(); // [M] = B this.BROF = 0; } this.I = (this.I & 0x0F) | 0x40; // set I07: communicate - this.cc.signalInterrupt(); + cc.signalInterrupt(); } break; case 0x11: // 2111: IOR=I/O Release - if (!this.NCSF) { // no-op in normal state + if (!this.NCSF) { // no-op in Normal State this.adjustAFull(); t1 = this.A; if (t1 < 0x800000000000) { // it's an operand @@ -3728,7 +3829,7 @@ B5500Processor.prototype.run = function run() { } if (t2) { this.loadAviaM(); - this.A = this.cc.bitSet(this.A, 2); + this.A = cc.bitSet(this.A, 2); this.storeAviaM(); this.AROF = 0; } @@ -3736,8 +3837,9 @@ B5500Processor.prototype.run = function run() { break; case 0x12: // 2211: HP2=Halt Processor 2 - if (!(this.NCSF || this.cc.HP2F)) { // control-state only - this.cc.haltP2(); + if (!(this.NCSF || cc.HP2F)) { // control-state only + cc.haltP2(); + this.cycleLimit = 0; // give P2 a chance to stop } break; @@ -3775,7 +3877,7 @@ B5500Processor.prototype.run = function run() { this.storeAviaM(); // [M] = A this.AROF = 0; } - this.cc.initiateP2(); + cc.initiateP2(); this.cycleLimit = 0; // give P2 a chance to run } break; @@ -3794,7 +3896,7 @@ B5500Processor.prototype.run = function run() { this.storeAviaM(); // [M] = A this.AROF = 0; } - this.cc.initiateIO(); // let CentralControl choose the I/O Unit + cc.initiateIO(); // let CentralControl choose the I/O Unit this.cycleLimit = 0; // give the I/O a chance to start } break; @@ -4109,7 +4211,7 @@ B5500Processor.prototype.run = function run() { case 0x14: // 2431: TUS=interrogate peripheral status this.adjustAEmpty(); - this.A = this.cc.interrogateUnitStatus(); + this.A = cc.interrogateUnitStatus(); this.AROF = 1; break; @@ -4194,7 +4296,7 @@ B5500Processor.prototype.run = function run() { case 0x34: // 6431: TIO=interrogate I/O channel this.adjustAEmpty(); - this.A = this.cc.interrogateIOChannel(); + this.A = cc.interrogateIOChannel(); this.AROF = 1; break; @@ -4379,11 +4481,11 @@ B5500Processor.prototype.run = function run() { t1 = this.G*6 + this.H; // starting source bit position t2 = t2*6 - (variant & 7) - this.H; // number of bits if (t1+t2 <= 48) { - this.A = this.cc.fieldIsolate(this.A, t1, t2); + this.A = cc.fieldIsolate(this.A, t1, t2); } else { // handle wrap-around in the source value - this.A = this.cc.fieldInsert( - this.cc.fieldIsolate(this.A, 0, t2-48+t1, t1+t2-48), 48-t2, 48-t1, - this.cc.fieldIsolate(this.A, t1, 48-t1)); + this.A = cc.fieldInsert( + cc.fieldIsolate(this.A, 0, t2-48+t1, t1+t2-48), 48-t2, 48-t1, + cc.fieldIsolate(this.A, t1, 48-t1)); } // approximate the shift cycle counts this.cycleCount += (variant >>> 3) + (variant & 7) + this.G + this.H; @@ -4404,7 +4506,7 @@ B5500Processor.prototype.run = function run() { } else { this.adjustABFull(); t2 = variant >>> 2; // field length (1-15 bits) - t1 = this.cc.fieldIsolate(this.B, this.G*6+this.H, t2); + t1 = cc.fieldIsolate(this.B, this.G*6+this.H, t2); this.cycleCount += this.G + this.H + (t2 >>> 1); // approximate the shift counts this.AROF = 0; // A is unconditionally empty at end @@ -4481,7 +4583,7 @@ B5500Processor.prototype.run = function run() { if (t2+variant > 48) { variant = 48-t2; } - this.B = this.cc.fieldTransfer(this.B, t2, variant, this.A, t1); + this.B = cc.fieldTransfer(this.B, t2, variant, this.A, t1); } this.AROF = 0; this.cycleCount += variant + this.G + this.K; // approximate the shift counts @@ -4499,7 +4601,7 @@ B5500Processor.prototype.run = function run() { } if (variant == 0) { this.A = 1; - } else if (this.cc.fieldIsolate(this.B, t2, variant) < this.cc.fieldIsolate(this.A, t1, variant)) { + } else if (cc.fieldIsolate(this.B, t2, variant) < cc.fieldIsolate(this.A, t1, variant)) { this.A = 1; } else { this.A = 0; @@ -4519,7 +4621,7 @@ B5500Processor.prototype.run = function run() { } if (variant == 0) { this.A = 1; - } else if (this.cc.fieldIsolate(this.B, t2, variant) == this.cc.fieldIsolate(this.A, t1, variant)) { + } else if (cc.fieldIsolate(this.B, t2, variant) == cc.fieldIsolate(this.A, t1, variant)) { this.A = 1; } else { this.A = 0; @@ -4538,10 +4640,10 @@ B5500Processor.prototype.run = function run() { * SECL: Syllable Execution Complete Level * ***************************************************************/ - if ((this.isP1 ? this.cc.IAR : this.I) && this.NCSF) { - // there's an interrupt and we're in normal state + if ((this.isP1 ? cc.IAR : (this.I || cc.HP2F)) && this.NCSF) { + // there's an interrupt and we're in Normal State // reset Q09F (R-relative adder mode) and set Q07F (hardware-induced SFI) (for display only) - this.Q = (this.Q & 0xFFFEFF) & 0x40; + this.Q = (this.Q & 0xFFFEFF) | 0x40; this.T = 0x0609; // inject 3011=SFI into T this.storeForInterrupt(1, 0); // call directly to avoid resetting registers at top of loop } else { @@ -4571,7 +4673,7 @@ B5500Processor.prototype.run = function run() { } } - // Accumulate Normal and Control State cycles for use by the Console in + // Accumulate Normal and Control State cycles for use by Console in // making the pretty lights blink. If the processor is no longer busy, // accumulate the cycles as Normal State, as we probably just did SFI. if (this.NCSF || !this.busy) { @@ -4601,15 +4703,22 @@ B5500Processor.prototype.schedule = function schedule() { this.scheduler = null; delayTime = clockOff - this.delayLastStamp; this.procSlack += delayTime; - this.delayDeltaAvg = (this.delayDeltaAvg*(B5500Processor.delaySamples-1) + - delayTime - this.delayRequested)/B5500Processor.delaySamples; + + // Compute the exponential weighted average of scheduling delay + this.delayDeltaAvg = (1-B5500Processor.delayAlpha)*(delayTime - this.delayRequested) + + B5500Processor.delayAlpha*this.delayDeltaAvg; + this.procSlackAvg = (1-B5500Processor.slackAlpha)*delayTime + + B5500Processor.slackAlpha*this.procSlackAvg; if (this.busy) { this.cycleLimit = B5500Processor.timeSlice; this.run(); // execute syllables for the timeslice - this.delayLastStamp = clockOff = new Date().getTime(); + clockOff = new Date().getTime(); + this.procRunAvg = (1-B5500Processor.slackAlpha)*(clockOff - this.delayLastStamp) + + B5500Processor.slackAlpha*this.procRunAvg; + this.delayLastStamp = clockOff; this.totalCycles += this.runCycles; if (!this.busy) { this.delayRequested = 0; diff --git a/webUI/B5500ColdLoader.html b/webUI/B5500ColdLoader.html index ed75a8e..e70440b 100644 --- a/webUI/B5500ColdLoader.html +++ b/webUI/B5500ColdLoader.html @@ -1854,7 +1854,6 @@ window.addEventListener("load", function() { // Create a file entry for the system log createSystemLog(10000); - /** enterFile("SYSTEM", "LOG", 1, 20000); **/ // Store the directory labels segment eu.put(fileLabels, directoryTop + 19); // write the directory block file labels diff --git a/webUI/B5500Console.html b/webUI/B5500Console.html index 1ac561c..ab735a0 100644 --- a/webUI/B5500Console.html +++ b/webUI/B5500Console.html @@ -37,10 +37,13 @@ window.addEventListener("load", function() { var bNormal; var boundBlinkenlicht; var cc = new B5500CentralControl(this); + var ccLatches = [0, 0, 0]; + var ccLightsMap = new Array(6); + var elapsedAverage = 0; + var elapsedLast = 0; var intLightsMap = new Array(48); - var iouLightsMap = new Array(4); var lastInterruptMask = 0; - var lastIOUMask = 0; + var lastCCMask = 0; var lastUnitBusyMask = 0; var lastPANormalRate = -1; var lastPAControlRate = -1; @@ -50,6 +53,9 @@ window.addEventListener("load", function() { var procDelay; var procSlack; var showAnnunciators = true; + var slackAlpha = 0.990; // decay factor for exponential weighted avg. + var slackAverage = 0; // average P1 slack time + var slackLast = 0; // last P1 total slack time var timer; var timerInterval = 50; // milliseconds @@ -78,7 +84,6 @@ window.addEventListener("load", function() { $$("LoadSelectBtn").disabled = false; $$("LoadBtn").disabled = false; $$("HaltBtn").disabled = true; - boundBlinkenlicht(); window.focus(); if (showAnnunciators) { $$("CentralControl").style.visibility = "visible"; @@ -115,17 +120,25 @@ window.addEventListener("load", function() { cc.halt(); $$("HaltBtn").disabled = true; $$("LoadBtn").disabled = false; + if (timer) { + clearTimeout(timer); + timer = null; + } } function LoadBtn_Click(ev) { var result; + window.open("", "SPO").focus(); // re-focus the SPO window result = cc.load(false); switch (result) { case 0: // load initiated successfully $$("HaltBtn").className = "redButton"; $$("HaltBtn").disabled = false; $$("LoadBtn").disabled = true; + elapsedLast = 0; + slackLast = slackAverage = 0; + boundBlinkenlicht(); break; case 1: alert("P1 busy or not available"); @@ -189,41 +202,42 @@ window.addEventListener("load", function() { } function displayCentralControl() { - /* Displays the I/O and interrupt status in Central Control */ + /* Displays the I/O and interrupt status in CentralControl */ var cells; var s; - var interruptMask = cc.fetchInterruptLatch() % 0x4000; - var interruptChange = lastInterruptMask ^ interruptMask; - var iouMask = cc.fetchIOUnitLatch(); - var iouChange = lastIOUMask ^ iouMask; - var unitBusyMask = cc.fetchUnitBusyLatch(); - var unitBusyChange = lastUnitBusyMask ^ unitBusyMask; + var interruptMask; + var interruptChange; + var ccMask; + var ccChange; + var unitBusyMask; + var unitBusyChange; var x; + cc.fetchCCLatches(ccLatches); + ccMask = ccLatches[0]; + ccChange = lastCCMask ^ ccMask; + lastCCMask = ccMask; + + interruptMask = ccLatches[1] % 0x4000; + interruptChange = lastInterruptMask ^ interruptMask; lastInterruptMask = interruptMask; - lastIOUMask = iouMask; + + unitBusyMask = ccLatches[2]; + unitBusyChange = lastUnitBusyMask ^ unitBusyMask; lastUnitBusyMask = unitBusyMask; - $$("AD1F").className = (cc.AD1F ? "busy" : ""); - $$("AD2F").className = (cc.AD2F ? "busy" : ""); - $$("AD3F").className = (cc.AD3F ? "busy" : ""); - $$("AD4F").className = (cc.AD4F ? "busy" : ""); - /********** for P2 debugging ********** - $$("P2BF").className = (cc.P2BF ? "busy" : ""); - $$("HP2F").className = (cc.HP2F ? "busy" : ""); - $$("PABZ").className = (cc.PA && cc.PA.busy ? "busy" : ""); $$("PBBZ").className = (cc.PB && cc.PB.busy ? "busy" : ""); **********/ x = 0; - while (iouChange) { - if (iouChange & 0x01) { - iouLightsMap[x].className = (iouMask & 0x01 ? "busy" : ""); + while (ccChange) { + if (ccChange & 0x01) { + ccLightsMap[x].className = (ccMask & 0x01 ? "busy" : ""); } - iouMask >>>= 1; - iouChange >>>= 1; + ccMask >>>= 1; + ccChange >>>= 1; x++; } @@ -296,7 +310,7 @@ window.addEventListener("load", function() { } } - stateRate = 6 - stateRate; + stateRate = Math.round(pa.controlCycles/cycles*6 + 0.49); if (stateRate != lastPAControlRate) { lastPAControlRate = stateRate; switch (stateRate) { @@ -364,7 +378,7 @@ window.addEventListener("load", function() { } } - stateRate = 6 - stateRate; + stateRate = Math.round(pb.controlCycles/cycles*6 + 0.49); if (stateRate != lastPBControlRate) { lastPBControlRate = stateRate; switch (stateRate) { @@ -400,8 +414,14 @@ window.addEventListener("load", function() { while (et < 0) { et += stamp; } + /************** + elapsedAverage = (et-elapsedLast)*(1-slackAlpha) + elapsedAverage*slackAlpha; + slackAverage = (p1.procSlack-slackLast)*(1-slackAlpha) + slackAverage*slackAlpha; + elapsedLast = et; + slackLast = p1.procSlack; + **************/ procDelay.innerHTML = p1.delayDeltaAvg.toFixed(1); - procSlack.innerHTML = (p1.procSlack/et*100).toFixed(1) + "%"; + procSlack.innerHTML = (p1.procSlackAvg/p1.procRunAvg*100).toFixed(1) + "%"; if (showAnnunciators) { displayCentralControl(); @@ -415,10 +435,12 @@ window.addEventListener("load", function() { var spec; var x; - iouLightsMap[0] = $$("AD1F"); - iouLightsMap[1] = $$("AD2F"); - iouLightsMap[2] = $$("AD3F"); - iouLightsMap[3] = $$("AD4F"); + ccLightsMap[0] = $$("AD1F"); + ccLightsMap[1] = $$("AD2F"); + ccLightsMap[2] = $$("AD3F"); + ccLightsMap[3] = $$("AD4F"); + ccLightsMap[4] = $$("P2BF"); + ccLightsMap[5] = $$("HP2F"); for (x=3; x<=16; x++) { intLightsMap[50-x] = $$("CCI" + (x+100).toString().substring(1) + "F"); @@ -463,6 +485,12 @@ window.addEventListener("load", function() { $$("LoadBtn").addEventListener("click", LoadBtn_Click, false); $$("LoadSelectBtn").addEventListener("click", LoadSelectBtn_Click, false); + // A kludge, for sure + $$("NotReadyBtn").addEventListener("click", function(ev) { + B5500SystemConfiguration.PB ^= true; + $$("RetroVersion").style.color = (B5500SystemConfiguration.PB ? "yellow" : "white"); + }); + aControl = $$("AControlBtn"); aNormal = $$("ANormalBtn"); bControl = $$("BControlBtn"); @@ -531,11 +559,11 @@ window.addEventListener("load", function() { SPEC DK1F DK2F + P2BF HP2F PABZ PBBZ - P1 Slack diff --git a/webUI/B5500MagTapeDrive.js b/webUI/B5500MagTapeDrive.js index f09c12c..34808c4 100644 --- a/webUI/B5500MagTapeDrive.js +++ b/webUI/B5500MagTapeDrive.js @@ -21,7 +21,7 @@ function B5500MagTapeDrive(mnemonic, unitIndex, designate, statusChange, signal) { /* Constructor for the MagTapeDrive object */ var that = this; - var x = (mnemonic == "MTA" ? 30 : 60); + var x = ((mnemonic.charCodeAt(2) - "A".charCodeAt(0) + 1)*30); this.mnemonic = mnemonic; // Unit mnemonic this.unitIndex = unitIndex; // Ready-mask bit number @@ -127,7 +127,7 @@ B5500MagTapeDrive.prototype.clear = function clear() { this.angle = 0; // current rotation angle of reel image [degrees] this.tapeInches = 0; // number of inches up-tape this.writeRing = false; // true if write ring is present and tape is writable - this.atBOT = false; // true if tape at BOT + this.atBOT = true; // true if tape at BOT this.atEOT = false; // true if tape at EOT this.buffer = null; // IOUnit buffer @@ -168,7 +168,8 @@ B5500MagTapeDrive.prototype.removeClass = function removeClass(e, name) { /**************************************/ B5500MagTapeDrive.prototype.spinReel = function spinReel(inches) { /* Rotates the reel image icon an appropriate amount based on the number of - inches of tape movement */ + inches of tape movement. The rotation is limited to 33 degrees in either + direction so that movement remains apparent to the viewer */ var circumference = this.reelCircumference*(1 - this.tapeInches/this.maxTapeLength/2); var angle = inches/circumference*360; @@ -192,6 +193,7 @@ B5500MagTapeDrive.prototype.setAtBOT = function setAtBOT(atBOT) { this.imgIndex = 0; this.tapeInches = 0; this.addClass(this.$$("MTAtBOTLight"), "whiteLit"); + this.progressBar.value = this.imgLength; this.reelIcon.style.transform = "rotate(0deg)"; } else { this.removeClass(this.$$("MTAtBOTLight"), "whiteLit"); @@ -208,6 +210,7 @@ B5500MagTapeDrive.prototype.setAtEOT = function setAtEOT(atEOT) { if (atEOT) { this.imgIndex = this.imgLength; this.addClass(this.$$("MTAtEOTLight"), "whiteLit"); + this.progressBar.value = 0; } else { this.removeClass(this.$$("MTAtEOTLight"), "whiteLit"); } @@ -237,10 +240,14 @@ B5500MagTapeDrive.prototype.setTapeUnloaded = function setTapeUnloaded() { this.addClass(this.$$("MTLocalBtn"), "yellowLit"); this.removeClass(this.$$("MTWriteRingBtn"), "redLit"); this.addClass(this.$$("MTUnloadedLight"), "whiteLit"); - this.progressBar.value = 0; this.setAtBOT(false); this.setAtEOT(false); + this.progressBar.value = 0; this.reelIcon.style.visibility = "hidden"; + if (this.timer) { + clearCallback(this.timer); + this.timer = null; + } } }; @@ -267,6 +274,10 @@ B5500MagTapeDrive.prototype.setTapeRemote = function setTapeRemote(ready) { this.statusChange(0); this.removeClass(this.$$("MTRemoteBtn"), "yellowLit"); this.addClass(this.$$("MTLocalBtn"), "yellowLit"); + if (this.timer) { + clearCallback(this.timer); + this.timer = null; + } } } }; @@ -297,19 +308,29 @@ B5500MagTapeDrive.prototype.setWriteRing = function setWriteRing(writeRing) { /**************************************/ B5500MagTapeDrive.prototype.tapeRewind = function tapeRewind(makeReady) { /* Rewinds the tape. Makes the drive not-ready and delays for an appropriate amount - of time depending on how far up-tape we are. If makeReady is true, then readies - the unit again when the rewind is complete [valid only when called from - this.rewind()] */ + of time depending on how far up-tape we are. If makeReady is true [valid only when + called from this.rewind()], then readies the unit again when the rewind is complete */ var inches; var inchFactor = this.imgIndex/this.tapeInches; var lastStamp = new Date().getTime(); + var updateInterval = 30; // ms + + function rewindFinish() { + this.timer = null; + this.busy = false; + this.removeClass(this.$$("MTRewindingLight"), "whiteLit"); + if (makeReady) { + this.ready = true; + this.statusChange(1); + } + } function rewindDelay() { var stamp = new Date().getTime(); var interval = stamp - lastStamp; if (interval <= 0) { - interval = 1; + interval = updateInterval/2; } if (this.tapeInches > 0) { inches = interval/1000*this.rewindSpeed; @@ -317,27 +338,25 @@ B5500MagTapeDrive.prototype.tapeRewind = function tapeRewind(makeReady) { this.spinReel(-inches); this.progressBar.value = this.imgLength - this.tapeInches*inchFactor; lastStamp = stamp; - this.timer = setCallback(rewindDelay, this, 30); + this.timer = setCallback(rewindDelay, this, updateInterval); } else { - this.busy = false; + this.spinReel(6); this.setAtBOT(true); - this.progressBar.value = this.imgLength; - this.removeClass(this.$$("MTRewindingLight"), "whiteLit"); - if (makeReady) { - this.ready = true; - this.statusChange(1); - } + this.timer = setCallback(rewindFinish, this, 2000); } } - if (this.tapeState != this.tapeUnloaded) { + if (this.timer) { + clearCallback(this.timer); + this.timer = null; + } + if (this.tapeState != this.tapeUnloaded && !this.atBOT) { this.busy = true; this.ready = false; this.statusChange(0); this.setAtEOT(false); this.addClass(this.$$("MTRewindingLight"), "whiteLit"); - this.timer = setCallback(rewindDelay, this, - this.startStopTime*1000 + this.initiateStamp - lastStamp); + this.timer = setCallback(rewindDelay, this, 1000); } }; @@ -399,12 +418,11 @@ B5500MagTapeDrive.prototype.fileSelector_onChange = function fileSelector_onChan that.image = new Uint8Array(ev.target.result); that.imgIndex = 0; that.imgLength = that.image.length; - that.progressBar.value = that.imgLength; that.progressBar.max = that.imgLength; that.removeClass(that.$$("MTUnloadedLight"), "whiteLit"); that.tapeState = that.tapeLocal;// setTapeRemote() requires it not to be unloaded - that.setAtBOT(true); that.setAtEOT(false); + that.setAtBOT(true); that.setTapeRemote(false); that.setWriteRing(false); // read-only for now... that.reelIcon.style.visibility = "visible"; @@ -446,7 +464,9 @@ B5500MagTapeDrive.prototype.bcdSpaceForward = function bcdSpaceForward(checkEOF) var imgLength = this.imgLength; // tape image length var imgIndex = this.imgIndex; // current tape image offset - if (imgIndex < imgLength) { + if (imgIndex >= imgLength) { + this.errorMask |= 0x10; // report parity error if beyond end of tape + } else { if (this.atBOT) { this.setAtBOT(false); } @@ -520,9 +540,6 @@ B5500MagTapeDrive.prototype.bcdSpaceBackward = function bcdSpaceBackward(checkEO } } while (c < 0x80); } - if (imgIndex <= 0) { - this.setAtBOT(true); - } } this.imgIndex = imgIndex; }; @@ -550,7 +567,9 @@ B5500MagTapeDrive.prototype.bcdReadForward = function bcdReadForward(oddParity) var imgIndex = this.imgIndex; // current tape image offset var xlate = (oddParity ? this.bcdXlateInOdd : this.bcdXlateInEven); - if (imgIndex < imgLength) { + if (imgIndex >= imgLength) { + this.errorMask |= 0x10; // report parity error if beyond end of tape + } else { if (this.atBOT) { this.setAtBOT(false); } @@ -681,9 +700,6 @@ B5500MagTapeDrive.prototype.bcdReadBackward = function bcdReadBackward(oddParity } } while (true); } - if (imgIndex <= 0) { - this.setAtBOT(true); - } } this.imgIndex = imgIndex; this.bufIndex = bufIndex; @@ -713,7 +729,8 @@ B5500MagTapeDrive.prototype.tapeDriveOnLoad = function tapeDriveOnLoad() { this.window.addEventListener("beforeunload", this.beforeUnload, false); - this.tapeState = this.tapeLocal; // setTapeUnloaded() requires it not to be unloaded + this.tapeState = this.tapeLocal; // setTapeUnloaded() requires it to be in local + this.atBOT = true; // and also at BOT this.setTapeUnloaded(); this.$$("MTUnloadBtn").addEventListener("click", function startClick(ev) { @@ -849,7 +866,7 @@ B5500MagTapeDrive.prototype.space = function space(finish, length, control) { this.progressBar.value = 0; } } - //console.log(this.mnemonic + " space: c=" + control + ", length=" + length + + //console.log(this.mnemonic + " space: c=" + control + ", length=" + length + // ", count=" + imgCount + ", inches=" + this.tapeInches + // ", index=" + this.imgIndex + ", mask=" + this.errorMask.toString(8)); }; diff --git a/tools/Pow2.html b/webUI/prototypes/Pow2.html similarity index 100% rename from tools/Pow2.html rename to webUI/prototypes/Pow2.html diff --git a/tools/Register-CrockfordStyle.js b/webUI/prototypes/Register-CrockfordStyle.js similarity index 100% rename from tools/Register-CrockfordStyle.js rename to webUI/prototypes/Register-CrockfordStyle.js diff --git a/tools/Register.js b/webUI/prototypes/Register.js similarity index 100% rename from tools/Register.js rename to webUI/prototypes/Register.js diff --git a/tools/RegisterTest.html b/webUI/prototypes/RegisterTest.html similarity index 100% rename from tools/RegisterTest.html rename to webUI/prototypes/RegisterTest.html diff --git a/tools/webkitFileSystemTest.html b/webUI/prototypes/webkitFileSystemTest.html similarity index 100% rename from tools/webkitFileSystemTest.html rename to webUI/prototypes/webkitFileSystemTest.html