1
0
mirror of https://github.com/pkimpel/retro-b5500.git synced 2026-04-25 20:01:52 +00:00

1. Release emulator version 0.07.

2. Implement interrupt and device status latching in B5500CentralControl to support better UI display.
3. Implement B5500CardPunch device.
4. Implement preliminary and experimental B5500DummyPrinter device; correct printer I/O initiation in IOUnit.
5. Correct the way that Printer Finished interrupts are handled in IOUnit and CentralControl.
6. Implement Card Load Select in B5500Console and B5500SyllableDebugger.
7. Fix lack of presence-bit detection in return ops for returned values.
8. Redesign B5500CardReader UI to show last two cards read; change method of emptying the input hopper.
9. Set CHECK option and rework SYSTEM/LOG initialization in B5500ColdLoader.html.
10. Centralize system memory cycle time setting; change from 6us to 4us memory cycle time.
11. Increase Processor timeslice to 16ms and rework Processor.schedule() internals for more accurate performance throttling in browsers with poor setTimeout() granularity.
12. Reduce Processor syllable overhead from 2 cycles to 1.
13. Change B5500SPOUnit method of output to "paper" to work better in Google Chrome.
14. Make documentation and debugging enhancements in B5500IOUnit.
15. Release initial test website HTML and Unisys license PDF.
16. Commit Mark XVI DCMCP transcription as of 2013-06-21.
This commit is contained in:
paul.kimpel@digm.com
2013-06-24 05:04:15 +00:00
parent 0071af88c8
commit 47e5d09ef7
24 changed files with 2017 additions and 392 deletions

View File

@@ -23052,3 +23052,512 @@ BEGIN REAL RCW=+0,MSCW=-2; 38001000
EXIT: 38099100
P(P&RCW[CTC],0,RDS,0,XCH,P&P[CTF],STF); 38100000
END DISKFILEOPEN; 38101000
PROCEDURE OTHERFILEOPENIN(ALPHA); AVLUE ALPHA; INTEGER ALPHA; 38102000
BEGIN REAL RCW=+0,MSCW=-2; 38102100
REAL IOM=IOMASK, IOMASK=+1; 38102200
INTEGER NBUFS=+2,FNUM=+3,RLEN=+4,TYPE=+5,IO=+6,BLEN=+7,U=+8, 38102300
KIND=+9,MODE=+10,DIREC=+11,FORMS=+12,COBOL=+13, 38102400
UNLABELED=+14,OPTIONAL=+15,CNTCTL=+16; 38102500
REAL T1=+17,T2=+18,MASK=+19,STATE=+20; 38102600
REAL MFID=+21,FID=+22; INTEGER REEL=+23,CDATE=+24,CYCLE=+25; 38102700
ARRAY FIB=+26[*],FPB=+27[*];% 38102800
INTEGER ACCESS=+28,FIB7=+29; 38102900
ARRAY HEADER=+30[*];% 38103000
REAL TOG=+31; 38103100
REAL USASI=NT1, RHEAD=HEADER; 38103200
LABEL FIND,DCN,DC19; 38103300
SUBROUTINE TYPEOPEN;% 38103400
BEGIN 38103500
T1:=(OPNMESS AND ((T1:=JAR[P1MIX,0])>0 OR 38103600
COPNMESS AND T1<0)); 38103700
$ SET OMIT = PACKETS 38103800
BEGIN NT2:=0; 38104100
IF U<16 THEN 38104200
STREAM(S:=PRNTABLE[U].[30:18], D:=[NT2]); 38104300
BEGIN SI ~ LOC S; DS ~ 8 DEC; % 38104400
DI ~ DI-7; DS ~ 6 FILL; % 38104500
END; % 38104600
FILEMESSAGE((" IN ")& 38104700
TINU[U][6:30:18], NT2, FPB[FNUM], FPB[FNUM+1], 38104800
IF KIND=2 OR KIND=9 THEN P(REEL,CDATE) ELSE 38104900
P(0,0), P, CYCLE, T1) 38105000
END; 38105100
END; 38105200
SUBROUTINE REED;% 38105300
BEGIN IF (T2~WAITIO(T1,(MASK OR @40)&@377[CTF],U) AND @367)!0 THEN38105400
IF (T2 AND NOT MASK)!0 THEN 38105500
BEGIN STOPTIMING(FNUM,1023); BLASTQ(U); SETNOTINUSE(U,0); 38105600
FILEMESS(-"PARITY ","ON ... "&TINU[U][24:30:18],% 38105700
MFID,FID,REEL,CDATE,CYCLE);% 38105800
END;% 38105900
IF TERMSET(P1MIX) THEN 38106000
BEGIN STOPTIMING(FNUM,1023); SETNOTINUSE(U,0); 38106100
GO TO INITIATE; 38106200
END; 38106300
END REED;% 38106400
REAL SUBROUTINE CNTLBITS;% 38106500
CNTLBITS~IOMASK&MODE[21:47:1]&DIREC[22:47:1]&CNTCTL[23:47:1]38106600
&IO[24:47:1]&(KIND=7 OR KIND>9 AND KIND{12)[20:47:1] 38106700
&(IF KIND=1OR KIND=7OR KIND=12THEN@20ELSE 0)[27:42:6];38106800
SUBROUTINE LABELAREA;% 38106900
M[T1:=ALPHA-2]:=M OR (GETSPACE((T1:=M[T1],SIZE)+4, %167-38107000
LABELAREAV,1)+4) & T1[SIZE] & CNTLBITS[FTF];38107100
P(ALPHA); % DETERMINE IF BRANCH TO DC19 38109000
P(RCW,MSCW,STF); 38110000
RCW:=RCW&P(XCH)[CTC]; 38110500
IF P=2 THEN GO DC19; 38111000
IF STATE.[41:1] THEN% 38111500
BEGIN U~FIB[15].[25:5];% 38112000
END ELSE% 38112500
BEGIN IF (U~FINDINPUT(MFID,FID,REEL,CDATE,CYCLE,COBOL,UNLABELED, 38113000
OPTIONAL,MODE,FNUM))<0 THEN% 38113500
BEGIN FIB[5].[39:4]~9; GO TO FIND END;% 38114000
STARTIMING(FNUM,IF U>31 THEN 18 ELSE U); 38114500
FPB:=PRT[P1MIX,3]; % STARTIMING MAY HAVE MOVED IT. 38115000
KIND:=IF U GTR 31 THEN 11 ELSE UNIT[U].[1:4]; 38115100
TYPEOPEN;% 38115500
IF U<16 THEN BEGIN RRRMECH~TWO(U) OR RRRMECH; 38116000
PRNTABLE[U].[15:15]~ALPHA;% 38116500
END;% 38117000
% TGW38117500
IF (T1~RDCTABLE[U].[14:10])!0 THEN REEL~T1; 38118000
STATE.[39:4]~0;% 38118500
END;% 38119000
IF KIND=0 THEN% 38119500
BEGIN IF U=23 THEN BEGIN T1~READERA; READERA~0 END% 38120000
ELSE BEGIN T1~READERB; READERB~0 END;% 38120500
M[ALPHA-2]:=[M[T1]]&10[8:38:10]&1[24:47:1];% 38121000
M[T1-4]:=P(DUP,LOD)&P1MIX[AREAMIXF]&LABELAREAV[AREATYPEF];% 38121500
IF MODE := (MODE=0) AND BLEN=20 THEN %301-38122000
SAVEWORD:=SAVEWORD OR TWO(U); %301-38122100
CNTCTL:=DIREC:=0;% 38122500
IF BLEN<T1~(MODE+1)|10 THEN BLEN~T1;% 38123000
END ELSE% 38123500
IF KIND=2 THEN% 38124000
BEGIN IF NOT UNLABELED THEN BEGIN% 38124500
IF DIREC AND NOT FIB[16].[22:1] THEN 38125000
BEGIN IF NOT STATE.[40:1] THEN BEGIN% 38125500
T1~5&3[23:46:2] OR M;% 38126000
MASK~0; REED;% 38126500
MASK:=@60; DO REED UNTIL T2.[42:1]; 38127000
DO REED UNTIL T2.[42:1]; 38127500
MASK~0; REED; END;% 38128000
END; 38128500
CNTCTL~1; LABELAREA;% 38129000
T1:=NFLAG(M[ALPHA-2]);% 38129500
IF DIREC THEN T1:=T1.[8:10]-1 INX T1;% 38130000
MASK:=@40; REED; 38130500
STREAM(Y:=0:X:=0,X1:=0,X2:=0,Z:=T1); 38131000
BEGIN DI:=LOC X; DS:=24 LIT "VOL1HDR1HDR2EOF1EOF2EOV1"; 38131500
DI:=LOC X; 38132000
6(TALLY:=TALLY+1; 38132500
SI:=Z; 38133000
IF 4 SC=DC THEN 38133500
JUMP OUT TO B); 38134000
TALLY:=0; 38134500
B: 38135000
Y:=TALLY; 38135500
END; 38136000
IF (USASI:=P)>0 THEN 38136500
USASITAPE(T1.[CF],USASI,4,U,DIREC) ELSE 38137000
IF M[T1 INX 6].[24:6]=1 THEN 38137500
BEGIN 38138000
REED; 38138500
MASK~@60; 38139000
T1~5&3[23:46:2] OR M; 38139500
T2~0; 38140000
END; 38140500
IF T2 NEQ @40 THEN DO REED UNTIL T2.[42:1] ELSE 38141000
FOR CNTCTL~DIREC STEP 1 UNTIL 2 DO% DIREC = 0 OR 1 %DB 38141500
P(WAITIO(@4740000005&(NOT DIREC)[22:47:1],@377,U),DEL);%DB38142000
FWD;% 38142500
CNTCTL~BLEN{1023;% 38143000
END ELSE% 38143500
IF KIND=9 THEN% 38144000
BEGIN UNLABELED~CNTCTL~1;% 38144500
DIREC~0;% 38145000
END ELSE% 38145500
IF KIND=11 THEN 38146000
BEGIN T1~CIDROW[U-32].[18:15]; 38146500
CIDROW[U-32].[18:15]~0; 38147000
M[ALPHA-2]:=[M[T1]]&10[8:38:10]&1[24:47:1];% 38147500
M[T1-4]:=P(DUP,LOD)&P1MIX[AREAMIXF]&LABELAREAV[AREATYPEF];% 38148000
MODE:=0;% 38148500
CNTCTL:=DIREC:=0;% 38149000
FIB[13].[1:9]~NBUFS~1; FIB[13].[10:9]~1; 38149500
IF BLEN<10 THEN BLEN~10; 38150000
END ELSE 38150500
DCN:: FILEMESS(-"I/O ERR",0,MFID,FID,REEL,CDATE,CYCLE);% 38151000
P(1); 38151500
IF BLEN=0 THEN GO TO DCN;% 38151800
IF NOT FIB[18].[1:1] OR P THEN 38151900
GETBUFFERS(BLEN,NBUFS,U,ALPHA); 38152000
GO FIND; 38152100
DC19: 38152250
$ SET OMIT = NOT(DATACOM AND RJE ) 38152500
FIB[14]:=NBUFS; 38156500
U:=30; KIND:=13; 38157000
FIB[13].[1:9]~ NBUFS~2; 38157500
FIB[18]:=(*P(DUP))&(BLEN:=RLEN)[3:33:15]&BLEN[CTF]; 38158000
IF MFID>0 THEN 38158500
BEGIN ; 38159000
STREAM(A~0,B~0:MFID,FID,C~0); 38159500
BEGIN 38160000
SI~ LOC MFID; DI~ LOC A; 38160500
2(C~ SI; 8(IF SC}0 THEN IF SC{9 THEN TALLY~ TALLY+1 38161000
ELSE JUMP OUT ELSE JUMP OUT; SI~ SI+1);38161500
SI~ C; C~ TALLY; DS~ C OCT; TALLY~ 0; SI~ LOC FID);38162000
END; 38162500
FID~ P; 38163000
MFID~P; 38163500
END; 38164000
M[ALPHA-2]~ 0&MFID[9:44:4]&FID[14:44:4]; 38164500
FIND:: 38191500
P(P&RCW[CTC],0,RDS,0,XCH,P&P[CTF],STF); 38192000
END OTHER FILE OPEN IN; 38192500
PROCEDURE OTHERFILEOPENOUT(ALPHA); VALUE ALPHA; INTEGER ALPHA; 38200000
BEGIN REAL RCW=+0,MSCW=-2; 38200100
REAL IOM=IOMASK, IOMASK=+1; 38200200
INTEGER NBUFS=+2,FNUM=+3,RLEN=+4,TYPE=+5,IO=+6,BLEN=+7,U=+8, 38200300
KIND=+9,MODE=+10,DIREC=+11,FORMS=+12,COBOL=+13, 38200400
UNLABELED=+14,OPTIONAL=+15,CNTCTL=+16; 38200500
REAL T1=+17,T2=+18,MASK=+19,STATE=+20; 38200600
REAL MFID=+21,FID=+22; INTEGER REEL=+23,CDATE=+24,CYCLE=+25; 38200700
ARRAY FIB=+26[*],FPB=+27[*];% 38200800
INTEGER ACCESS=+28,FIB7=+29,; 38200900
ARREAY HEADER=+30[*]; 38201000
REAL TOG=+31; 38201100
REAL USASI=NT1, RHEAD=HEADER 38201200
LABEL LPS,FIND,DNC,PBS; 38201300
SUBROUTINE TYPEOPEN;% 38201400
BEGIN 38201500
T1:=(OPNMESS AND ((T1:=JAR[P1MIX,0])>0 OR 38201600
COPNMESS AND T1<0)); 38201700
$ SET OMIT = PACKETS 38201800
BEGIN NT2:=0; 38202100
IF U<16 THEN 38202200
STREAM(S:=PRNTABLE[U].[30:18], D:=[NT2]); 38202300
BEGIN SI ~ LOC S; DS ~ 8 DEC; % 38202400
DI ~ DI-7; DS ~ 6 FILL; % 38202500
END; % 38202600
FILEMESSAGE((" OUT")& 38202700
TINU[U][6:30:18], NT2, FPB[FNUM], FPB[FNUM+1], 38202800
IF KIND=2 OR KIND=9 THEN P(REEL,CDATE) ELSE 38202900
P(0,0), P, CYCLE, T1); 38203000
END; 38203100
END; 38203200
SUBROUTINE REED;% 38203300
BEGIN IF (T2~WAITIO(T1,(MASK OR @40)&@377[CTF],U) AND @367)!0 THEN38203400
IF (T2 AND NOT MASK)!0 THEN 38203500
BEGIN STOPTIMING(FNUM,1023); BLASTQ(U); SETNOTINUSE(U,0); 38203600
FILEMESS(-"PARITY ","ON ... "&TINU[U][24:30:18],% 38203700
MFID,FID,REEL,CDATE,CYCLE);% 38203800
END;% 38203900
IF TERMSET(P1MIX) THEN 38204000
BEGIN STOPTIMING(FNUM,1023); SETNOTINUSE(U,0); 38204100
GO TO INITIATE; 38204200
END; 38204300
END REED% 38204400
REAL SUBROUTINE CNTLBITS;% 38204500
CNTLBITS~IOMASK&MODE[21:47:1]&DIREC[22:47:1]&CNTCTL[23:47:1]38204600
&[24:47:1]&(KIND=7 OR KIND>9 AND KIND{12)[20:47:1] 38204700
&(IF KIND=1OR KIND=7OR KIND=12THEN@20ELSE 0)[27:42:6];38204800
SUBROUTINE LABELAREA;% 38204900
M[T1:=ALPHA-2]:=M OR (GETSPACE((T1:=M[T1],SIZE)+4, %167-38205000
LABELAREAV,1)+4) & T1[SIZE] & CNTLBITS[FTF];38205100
P(RCW,MSCW,STF); 38210000
RCW:=RCW&P(XCH)[CTC]; 38210500
IF STATE.[41:1] THEN% 38211500
BEGIN U~FIB[15].[25:5];% 38212000
END ELSE% 38212500
BEGIN T2:=FPB[FNUM+3]; % SAVES COPIES FOR BACK UP 38213000
IF (U:=FINDOUTPUT(MFID,FID,REEL,CDATE,CYCLE,TYPE 38213500
$ SET OMIT = NOT PACKETS 38214000
&FPB[FNUM-3][1:23:1] 38214500
$ POP OMIT 38215000
,FORMS,KIND))>40 THEN 38215500
BEGIN FIB[14].[3:15]~U; 38216000
FPB[FNUM+2],[18:30]~DATE; 38216500
IF MCP!NOT(-0) THEN M[U+2]~USERCODE[P1MIX]; 38217000
M[U+3]~XCLOCK+P(RTR); 38217500
T1:=SPACE(30); 38218000
MOVE(30,U,T1); 38218500
STREAM(DATE,B:=T1+3); 38219000
BEGIN SI:=LOC DATE;DS:=8OCT;DI:=DI-8;DS:=2LIT"+2";END; 38219500
M[T1+1]~(XCLOCK+P(RTR))&(M[T1+3])[6:30:18]; 38220000
M[T1+4]:= 0&SYSNO[4:46:2]&1[2:47:1]; 38220500
M[T1+5]~(*PDUP))&1[2:47:1]; %ABORTED PBD TOG. 38221000
$ SET OMIT = RJE AND DATACOM 38221500
P(0); 38222000
$ POP OMIT 38222500
$ SET OMIT = NOT(RJE AND DATACOM) 38223000
M[T1+6]~P(XCH); 38226500
M[U-1]:=EUF(IF TYPE NEQ 0 AND TYPE LSS 20 THEN 38227000
"PRD " ELSE "PUD ",M[U+6],T1-1); 38227500
FORGETSPACE(T1); 38228000
$ SET OMIT = PACKETS 38228500
FILEMESSAGE((IF TYPE GEQ 20 OR TYPE=0 THEN "PUD...." 38230000
ELSE "PBD....")&M[U+6][24:6:24], 38230500
"OUT "&M[U+6][30:30:18], 38231000
MFID,FID,0,0,0, 38231500
(PBDREL OR OPNMESS)); 38232000
STARTIMING(FNUM,U~18); 38232500
FPB:=PRT[P1MIX,3]; % STARTIMING MAY HAVE MOVED IT. 38233000
END ELSE 38233500
IF U LSS 0 THEN %DSED 38234000
BEGIN FIB[5].[39:4]:=9; GO FIND END ELSE 38234500
BEGIN 38235000
STARTIMING(FNUM,U);% 38235500
FPB:=PRT[P1MIX,3]; % WATCH OUT FOR STARTIMING, 38236000
IF KIND=7 THEN FPB[FNUM+3] := (*P(DUP))&T2[15:15:8]; 38236010
TYPEOPEN;% 38236500
IF TYPE=5 OR TYPE=8 OR TYPE=9 THEN UNLABELED~1;% 38237000
IF U<16 THEN BEGIN RRRMECH~TWO(U) OR RRRMECH; 38237500
PRNTABLE[U].[15:15]~ALPHA;% 38238000
END; END; 38238500
END;% 38239000
IF KIND=6 THEN% 38239500
BEGIN BLEN:=10; 38240000
FIB[18]:=(*P(DUP))&BLEN[CTC]&BLEN[CTF]&BLEN[3:33:15]; 38240500
MODE~DIREC~CNTCTL~0;% 38241000
END ELSE% 38241500
IF KIND=1 THEN% 38242000
BEGIN MODE~DIREC~CNTCTL~0;% 38242500
LPS: 38243000
IF NOT COBOL THEN M[ALPHA-2]~0&15[8:38:10];% 38243500
END ELSE% 38244000
IF KIND=12 THEN 38244500
BEGIN TYPE~IF (TYPE!0 AND TYPE<20) THEN 15 ELSE 22; 38245000
PBS: MODE~DIREC~0; FIB[13].[1:9]~NBUFS~CNTCTL~1; FIB[13].[10:9]~1; 38245500
BLEN~IF TYPE}20 THEN 10 ELSE IF BLEN>17 THEN 17 ELSE BLEN; 38246000
M[T1~GETSPACE(92,3,1)+2]~M[T1-1]~[M[ALPHA]]&(T1+2)[CTF]& 38246500
U[12:42:6]; 38247000
DISKIO(RHEAD,-T1-75,11,JAR[P1MIX,6].[CF]); 38247500
M[ALPHA]:=T1+2; 38248000
FIB[14]~(*P(DUP))&(T1+2)[CTC]&(T1+56)[CTF]; 38248500
FIB[18]~(*P(DUP))&BLEN[CTC]&BLEN[CTF]&BLEN[03:33:15]; 38249000
STREAM(D~T1+1); 2(36(DS~8 LIT"0")); 38249500
FIB[5].[FF]~(M[T1+91]~FIB[5].[FF]&1[18:47:1])+1; 38250000
SLEEP([RHEAD],IOMASK); 38250500
HEADER:=[M[T1]]&92[8:38:10]; 38251000
HEADER[74]~MFID; 38251500
HEADER[75]~FID; 38252000
HEADER[87]~FORMS; 38252500
HEADER[88]:=T2.[15:8]; % COPIES 38253000
HEADER[89]:=USERCODE[P1MIX]; %132-38253100
HEADER[76]~ABS(JAR[P1MIX,0]); 38253500
HEADER[77]~ABS(JAR[P1MIX,1]); 38254000
REEL~RDCTABLE[U].[14:10]; % GET ACTUAL REEL NUMBER %745-38254100
GO TO LPS; 38254500
END ELSE 38255000
IF KIND=7 THEN% 38255500
BEGIN TYPE~IF (TYPE!0 AND TYPE<20) THEN 6 ELSE 20; 38256000
IF SVPBT THEN SAVEWORD:=TWO(U) OR SAVEWORD; 38256500
GO TO PBS; 38257000
END ELSE% 38257500
IF KIND=2 THEN% 38258000
BEGIN IF PRNTABLE[U]}0 THEN GO TO DCN;% 38258500
CNTCTL~MODE;% 38259000
END ELSE% 38259500
IF KIND=8 THEN% 38260000
BEGIN UNLABELED~CNTCTL~1;% 38260500
DIREC~0;% 38261000
END;% 38261500
IF UNLABELED THEN% 38262000
BEGIN IF COBOL THEN% 38262500
BEGIN MASK~0;% 38263000
IF KIND=1 THEN BEGIN T1~@4000100000; REED END ELSE 38263500
IF KIND=7 OR KIND=12 THEN 38264000
BEGIN 38264500
IF TYPE < 20 THEN 38265000
BEGIN 38265500
HEADER[73]~@1540176000100000&FIB[5][FTC]; 38266000
FIB[5].[FF]~FIB[5].[FF]+1; 38266500
FIB[14].[FF]:=T1+38; 38267000
END; 38267500
GO FIND; 38268000
END; 38268500
END;% 38269000
END ELSE% 38269500
BEGIN IF COBOL THEN% 38270000
BEGIN M[ALPHA-2]~P(DUP,LOD)&CNTLBITS[18:18:15];% 38270500
IF U<16 THEN% 38271000
STREAM(N~PRNTABLE[U].[30:18],D~M[ALPHA-2]);% 38271500
BEGIN SI~LOC N; DI~DI+53; DS~5 DEC END;% 38272000
END ELSE% 38272500
BEGIN IF REEL=0 THEN REEL~1;% 38273000
IF CYCLE=0 THEN CYCLE~1;% 38273500
IF CDATE=0 THEN STREAM(DATE,CD~[CDATE]);% 38274000
BEGIN SI~LOC DATE; SI~SI+3; DS~5 OCT END; 38274500
LABELAREA;% 38275000
BUILDLABEL(M[ALPHA-2],MFID,FID,REEL,CDATE,CYCLE,% 38275500
FIB[4],(IF U<16 THEN PRNTABLE[U].[30:18] 38276000
ELSE 0),STATE.[46:2],% 38276500
BLEN,RLEN);% 38277000
END;% 38277500
M[M[ALPHA-2] INX P(DUP).[8:10]]~@3700000000000000;% 38278000
IF (P(KIND,DUP)=7 OR (P(XCH,DUP)=12 OR P(XCH)=1)) THEN 38278500
IF KIND=7 AND FIB[13].[28:10]!ABS(COBOL) THEN GO FIND ELSE 38279000
BEGIN IF TYPE GEQ 20 THEN % MAKE CP BACK-UP LABEL 38279500
BEGIN M[M[ALPHA-2] INX 4]:=FLAG(NABS(JAR[P1MIX,0])); 38280000
M[M[ALPHA-2] INX 5]:=FLAG(JAR[P1MIX,1]&17[1:43:5]); 38280500
STREAM(A:=[M[M[ALPHA-2] INX 6]]); 38281000
BEGIN DS:=15 LIT" PUNCH BACK-UP "; DS:=LIT"%"; 38281500
2(DS:=8 LIT"%%%%%%%%"); 38282000
END; 38282500
END ELSE % MAKE LP LABEL 38283000
BEGIN T1:=M[M[ALPHA-2]INX 3]; 38283500
DISKIO(T2,NABS(M[ALPHA-2]INX 1),11,JAR[P1MIX,6].[CF]);38284000
M[M[ALPHA-2]INX 13]:=FLAG(NABS(JAR[P1MIX,0])); 38284500
M[M[ALPHA-2]INX 14]:=FLAG(JAR[P1MIX,1]&17[1:43:5]); 38285000
SLEEP([T2],IOMASK); 38285500
M[M[ALPHA-2] INX 3]:=T1; 38286000
END; 38286500
M[M[ALPHA02] INX 1]:=MFID; 38287000
M[M[ALPHA-2] INX 2]:=FID; 38287500
IF KIND=1 THEN M[ALPHA-2]~P(DUP,LOD) & %150-38288000
(IF SEPARATE THEN 1 ELSE @20)[27:42:6] %150-38288100
ELSE %150-38288200
BEGIN HEADER[73]~(FIB[5].[FF] OR @360170100000000)& 38288500
(TYPE<20)[32:47:1]; 38289000
IF NOT SEPARATE THEN %150-38289100
IF (TYPE<20) THEN %150-38289200
HEADER[73]~P(DUP,LOD)&(@20)[27:42:6];%150-38289300
FIB[5]~P(DUP,LOD,0,1,CFX,+); 38289500
STREAM(L~M[ALPHA-2],B~[HEADER[56]]); 38290000
BEGIN SI~L; DS~17 WDS END; 38290500
FIB[14].[FF]~[HEADER[38]]; GO FIND; 38291000
END; END; 38291500
T1~NFLAG(M[ALPHA-2]);% 38292000
MASK~0L REEDL% 38292500
IF KIND=2 THEN% 38293000
BEGIN T2~@1737000000000000;% 38293500
T1~NFLAG([T2]);% 38294000
REED;% 38294500
END;% 38295000
END;% 38295500
P(0); 38296000
IF BLEN=0 THEN 38296500
DCN:: FILEMESS(-"I/O ERR",0,MFID,FID,REEL,CDATE,CYCLE); 38296750
IF NOT FIB[18].[1:1] OR P THEN 38297000
GETBUFFERS(BLEN,NBUFS,U,ALPHA); 38297500
FIND:: 38298000
P(P&RCW[CTC],0,RDS,0,XCH,P&P[CTF],STF); 38298500
END OTHER FILE OPEN OUT; 38299000
PROCEDURE DISKCLOSE(ALPHA); VALUE ALPHA; INTEGER ALPHA;% 38355000
BEGIN REAL RCW=+0,MSCW=-2; 38356000
ARRAY FIB=+1[*],FPB=+2[*],HEADER=+3[*];% 38357000
%%% DONT ADD ANY DECLARATIONS BETWEEN "HEADER" AND "KIND" %%% WCP 38358000
INTEGER KIND=+4,NUBFS=+5,U=+6,BLEN=+7,CODE=+8, 38359000
UNLABELED=+9,COBOL=+10,I=+11,J=+12, 38360000
FNUM=+13; 38361000
REAL MID=+14,FID=+15,H=+16,D=+17,C=+18,FORMS=+19,STATE=+20; 38362000
LABEL L1,L2,L3,EOF,CLEANUP; 38363000
LABEL OBJTYPE,DUMMY; 38364000
REAL STA=+21;% 38364100
REAL T1=+22,T2=+23,T3=+24,IOD=+25;% 38365000
ARRAY SEG0=+26[*],SKEL=+27[*];% 38366000
REAL T=+28,ACCESS=+29;% 38366010
BOOLEAN COMPGO=+30; 38366020
$ SET OMIT = NOT SHAREDISK 38366099
SUBROUTINE COOLOFF; 38370700
BEGIN FOR I~0 STEP 1 UNTIL NBUFS-1 DO% 38370800
BEGIN IF NOT M[ALPHA+1].[19:1] THEN% 38371000
SLEEP([M[ALPHA=I]],IOMASK);% 38372000
IF KIND!4 THEN 38373000
IF M[ALPHA+I].[27:1] THEN GO TO EOF;% 38374000
END;% 38375000
EOF: END COOLOFF;% 38376000
% 38376500
BOOLEAN SUBROUTINE WRITTENON; % PICKS UP THE ACCESSED BITS FROM38377000
BEGIN J:=0; % THE BUFFERS. 38377200
IF (T:=FIB[10].[3:15]) NEQ 0 THEN 38377400
BEGIN 38377600
FOR I:=NBUFS-1 STEP -1 UNTIL 0 DO 38377800
IF M[T].[11:1] THEN J:=I:=-1 ELSE T:=M[T].[FF]-2; 38378000
END; 38378200
WRITTENON:=J; 38378400
END; 38378600
% 38379000
DEFINE REW=CODE.[47:1]#,% 38380000
KRUNCH=NOT CODE.[42:1]#, 38381000
REL=CODE.[46:1]#,% 38382000
TIME=CODE.[45:1]#,% 38383000
LOCK=NOT CODE.[44:1]#,% 38384000
PURGE=NOT CODE.[43:1]#,% 38385000
DEFINE TECH=STATE.[46:2]#, OPENIO=FIB[13].[22:1]#, 38385400
WRITBACK=FIB[13].[23:1]#, LASTIO=FIB[13].[46:1]#, 38385500
WRITEAFTEREOF=FIB[13].[44:2]#, INPUT=STATE.[43:1]#; 38385600
% 38386000
% START OF CODE 38386010
% 38386020
P(RCW,MSCW,STF); RCW ~ RCW & P(XCH)[CTC]; 38387000
HEADER ~ FIB[14]; ACCESS ~ FIB[4].[27:3]; 38388000
IF COBOL THEN 38389000
BEGIN IF COBOL > 0 THEN % COBOL 61 38389100
BEGIN IF WRITBACK AND TECH=0 AND LASTIO AND 38389200
(OPENIO OR NOT(INPUT)) THEN 38389300
IF ACCESS=1 AND WRITEAFTEREOF!0 THEN 38389400
BEGIN FIB[7] ~ *P(DUP) - 1; 38389500
HEADER[7] ~ *P(DUP) - 1; 38389600
END ELSE WRITEAFTEREOF ~ 0; 38389700
IF TECH=0 THEN IF WRITEAFTEREOF=2 THEN 38389800
BEGIN FIB[7] ~ *P(DUP) + 1; 38389900
HEADER[7] ~ *P(DUP) + 1; 38390000
END ELSE IF WRITEAFTEREOF=1 THEN 38390100
BEGIN FIB[7] ~ *P(DUP) - 1; 38390200
HEADER[7] ~ *P(DUP) - 1; 38390300
END; 38390400
WRITEAFTEREOF ~ 0; 38390500
END; 38391000
IF ACCESS=1 THEN % IF RANDOM 38391010
BEGIN IF COBOL > 0 THEN % COBOL61 38391020
BEGIN ACCESS ~ 4; 38391025
IF FIB[13].[10:9] = 2 THEN % SEEK IN PROCESS 38391030
BEGIN 38391035
$ SET OMIT = NOT SHAREDISK 38391039
COOLOFF; FIB[13].[10:9] ~ 1; 38391050
END 38391055
END ELSE IF FIB[17]<BLEN THEN ACCESS~4; % COBOL68 38391060
END; 38391070
IF FIB[13].[23:1] AND ACCESS=0 THEN 38391080
BEGIN FIB[7]~P(DUP,LOD)-1; 38391090
ACCESS~4; 38391100
END; END; 38391110
IF NOT STATE.[41:1] THEN% 38392000
BEGIN IF ACCESS=1 THEN% 38393000
BEGIN 38394000
$ SET OMIT = NOT SHAREDISK 38394099
COOLOFF; 38394300
END ELSE% 38395000
IF ACCESS=0 THEN% 38396000
BEGIN COOLOFF; IF NOT STATE.[43:1] THEN% 38397000
IF FIB[17]<BLEN AND STATE.[46:2]!0 THEN% 38398000
BEGIN R:=SPACE(((BLEN+29) DIV 30)|30+1); 38399000
IF (M[R]~M[FIB[16]]~% 38400000
DISKADDRESS(MID,FID,FPB[FNUM+3],FIB[7]-1,HEADER,0)) NEQ 0 THEN % (SHM)38401000
BEGIN 38401100
P(WAITIO(FIB[16]&1[24:47:1]&R[33:33{15],% 38402000
0,U(,DEL);% 38403000
MOVE(FIB[17],R+BLEN-FIB[17]+1,% 38404000
FIB[16] INX BLEN-FIB[17]+1);% 38405000
P(WIATIO(FIB[16],0,U),DEL);% 38406000
IF NOT FIB[16].[24:1] THEN HEADER[4].[11:1]~1; 38406500
END; 38407000
FORGETSPACE(R);% 38408000
END;% 38409000
END ELSE% 38410000
BEGIN 38411000
$ SET OMIT = NOT SHAREDISK 38411009
COOLOFF; 38411030
IF (FIB[17]LSS BLEN AND STATE.[46:2]NEQ 0)OR ACCESS=4 THEN38411100
BEGIN IF ACCESS=4 THEN 38411200
IF FIB[13].[23:1] OR NOT STATE.[43:1] THEN 38411300
ACCESS:=2; 38411400
IF (M[FIB[16]]:=DISKADDRESS(MID,FID,FPB[FNUM+3], % (SHM)38411500
FIB[7],HEADER,0))=0 THEN ACCESS:=4; 38411600
IF ACCESS!4 THEN 38411700
BEGIN P(WAITIO(FIB[16]&0[24:24:1],0,U),DEL); 38411750
HEADER[4].[11:1]~1; END; 38411800
END; IF ACCESS = 4 THEN ACCESS := 2; 38411900
END;% 38412000

Binary file not shown.

View File

@@ -42,8 +42,8 @@ function B5500CentralControl() {
// Instance variables and flags
this.poweredUp = 0; // System power indicator
this.unitStatusMask = 0; // Peripheral unit ready-status bitmask
this.unitBusyMask = 0; // Peripheral unit busy-status bitmask
this.PB1L = 0; // 0=> PA is P1, 1=> PB is P1
this.inhCCI03F = 0; // 0=> allow timer interrupts; 1=> inhibit 'em
@@ -51,7 +51,6 @@ function B5500CentralControl() {
this.nextTimeStamp = 0; // Next actual Date.getTime() for timer tick
this.timer = null; // Reference to the RTC setTimeout id.
this.loadTimer = null; // Reference to the load setTimeout id.
// Establish contexts for asynchronously-called methods
this.boundTock = B5500CentralControl.bindMethod(this.tock, this);
@@ -62,9 +61,10 @@ function B5500CentralControl() {
/**************************************/
/* Global constants */
B5500CentralControl.version = "0.06";
B5500CentralControl.version = "0.07";
B5500CentralControl.rtcTick = 1000/60; // Real-time clock period, milliseconds
B5500CentralControl.memCycles = 4; // assume 4 µs memory 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
0x1, 0x2, 0x4, 0x8,
@@ -121,9 +121,9 @@ B5500CentralControl.unitSpecs = {
DKB: {unitIndex: 28, designate: 12, unitClass: B5500DiskUnit},
CRA: {unitIndex: 24, designate: 10, unitClass: B5500CardReader},
CRB: {unitIndex: 23, designate: 14, unitClass: B5500CardReader},
CPA: {unitIndex: 25, designate: 10, unitClass: null},
LPA: {unitIndex: 27, designate: 22, unitClass: null},
LPB: {unitIndex: 26, designate: 26, unitClass: null},
CPA: {unitIndex: 25, designate: 10, unitClass: B5500CardPunch},
LPA: {unitIndex: 27, designate: 22, unitClass: B5500DummyPrinter},
LPB: {unitIndex: 26, designate: 26, unitClass: B5500DummyPrinter},
PRA: {unitIndex: 20, designate: 18, unitClass: null},
PRB: {unitIndex: 19, designate: 20, unitClass: null},
PPA: {unitIndex: 21, designate: 18, unitClass: null},
@@ -204,6 +204,13 @@ B5500CentralControl.prototype.clear = function clear() {
this.P2BF = 0; // Processor 2 busy FF
this.HP2F = 1; // Halt processor 2 FF
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
if (this.PA) {
this.PA.clear();
}
@@ -427,6 +434,11 @@ B5500CentralControl.prototype.signalInterrupt = function signalInterrupt() {
: 0
)
: 0; // no interrupt set
if (this.IAR) {
this.interruptMask = this.bitSet(this.interruptMask, 65-this.IAR);
this.interruptLatch = this.bitSet(this.interruptLatch, 65-this.IAR);
}
};
/**************************************/
@@ -437,100 +449,107 @@ B5500CentralControl.prototype.clearInterrupt = function clearInterrupt() {
var p1 = this.P1;
var p2 = this.P2;
switch (this.IAR) {
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
break;
case 0x18: // @30: I/O 2 finished
this.CCI09F = 0;
this.AD2F = 0; // make unit non-busy
break;
case 0x19: // @31: I/O 3 finished
this.CCI10F = 0;
this.AD3F = 0; // make unit non-busy
break;
case 0x1A: // @32: I/O 4 finished
this.CCI11F = 0;
this.AD4F = 0; // make unit non-busy
break;
case 0x1B: // @33: P2 busy
this.CCI12F = 0;
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;
break;
if (this.IAR) {
this.interruptMask = this.bitReset(this.interruptMask, 65-this.IAR)
switch (this.IAR) {
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
this.iouMask &= 0xE;
break;
case 0x18: // @30: I/O 2 finished
this.CCI09F = 0;
this.AD2F = 0; // make unit non-busy
this.iouMask &= 0xD;
break;
case 0x19: // @31: I/O 3 finished
this.CCI10F = 0;
this.AD3F = 0; // make unit non-busy
this.iouMask &= 0xB;
break;
case 0x1A: // @32: I/O 4 finished
this.CCI11F = 0;
this.AD4F = 0; // make unit non-busy
this.iouMask &= 0x7;
break;
case 0x1B: // @33: P2 busy
this.CCI12F = 0;
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;
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:
case 0x27:
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
case 0x2D:
if (p2) {p2.I &= 0x0F}
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:
case 0x27:
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
case 0x2D:
if (p2) {p2.I &= 0x0F}
break;
case 0x30: // @60: P1 memory parity error
p1.I &= 0xFE;
break;
case 0x31: // @61: P1 invalid address error
p1.I &= 0xFD;
break;
case 0x32: // @62: P1 stack overflow
p1.I &= 0x0B;
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 0x30: // @60: P1 memory parity error
p1.I &= 0xFE;
break;
case 0x31: // @61: P1 invalid address error
p1.I &= 0xFD;
break;
case 0x32: // @62: P1 stack overflow
p1.I &= 0x0B;
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;
default: // no interrupt vector was set
break;
default: // no interrupt vector was set
break;
}
}
this.signalInterrupt();
};
@@ -551,7 +570,7 @@ B5500CentralControl.prototype.tock = function tock() {
}
}
interval = (this.nextTimeStamp += B5500CentralControl.rtcTick) - thisTime;
this.timer = setTimeout(this.boundTock, (interval < 0 ? 1 : interval));
this.timer = setTimeout(this.boundTock, (interval < 1 ? 1 : interval));
};
/**************************************/
@@ -588,15 +607,23 @@ B5500CentralControl.prototype.initiateIO = function initiateIO() {
if (this.IO1 && this.IO1.REMF && !this.AD1F) {
this.AD1F = 1;
this.iouMask |= 0x1;
this.iouLatch |= 0x1;
this.IO1.initiate();
} else if (this.IO2 && this.IO2.REMF && !this.AD2F) {
this.AD2F = 1;
this.iouMask |= 0x2;
this.iouLatch |= 0x2;
this.IO2.initiate();
} else if (this.IO3 && this.IO3.REMF && !this.AD3F) {
this.AD3F = 1;
this.iouMask |= 0x4;
this.iouLatch |= 0x4;
this.IO3.initiate();
} else if (this.IO4 && this.IO4.REMF && !this.AD4F) {
this.AD4F = 1;
this.iouMask |= 0x8;
this.iouLatch |= 0x8;
this.IO4.initiate();
} else {
this.CCI04F = 1; // set I/O busy interrupt
@@ -651,11 +678,42 @@ B5500CentralControl.prototype.setUnitBusy = function setUnitBusy(index, busy) {
/* Sets or resets the unit-busy mask bit for unit index "index" */
if (index) {
this.unitBusyMask = (busy ? this.bitSet(this.unitBusyMask, index)
: this.bitReset(this.unitBusyMask, index));
if (busy) {
this.unitBusyMask = this.bitSet(this.unitBusyMask, index);
this.unitBusyLatch = this.bitSet(this.unitBusyLatch, index);
} else {
this.unitBusyMask = this.bitReset(this.unitBusyMask, index);
}
}
};
/**************************************/
B5500CentralControl.prototype.fetchInterruptLatch = function fetchInterruptLatch() {
/* Returns and resets this.interruptLatch; used by console UI */
var latch = 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;
this.unitBusyLatch = this.unitBusyMask;
return latch;
};
/**************************************/
B5500CentralControl.prototype.halt = function halt() {
/* Halts the processors. Any in-process I/Os are allowed to complete */
@@ -664,10 +722,6 @@ B5500CentralControl.prototype.halt = function halt() {
clearTimeout(this.timer);
this.timer = null;
}
if (this.loadTimer) {
clearTimeout(this.loadTimer);
this.loadTimer = null;
}
if (this.PA && this.PA.busy) {
this.PA.busy = 0;
@@ -698,22 +752,25 @@ B5500CentralControl.prototype.loadComplete = function loadComplete(dontStart) {
completed = true;
this.CCI08F = 0;
this.AD1F = 0;
this.iouMask &= 0xE;
} else if (this.CCI09F) { // I/O Unit 2 finished
completed = true;
this.CCI09F = 0;
this.AD2F = 0;
this.iouMask &= 0xD;
} else if (this.CCI10F) { // I/O Unit 3 finished
completed = true;
this.CCI10F = 0;
this.AD3F = 0;
this.iouMask &= 0xB;
} else if (this.CCI11F) { // I/O Unit 4 finished
completed = true;
this.CCI11F = 0;
this.AD4F = 0;
this.iouMask &= 0x7;
}
if (completed) {
this.loadTimer = null;
this.LOFF = 0;
this.P1.preset(0x10); // start execution at C=@20
if (!dontStart) {
@@ -737,15 +794,23 @@ B5500CentralControl.prototype.load = function load(dontStart) {
this.LOFF = 1;
if (this.IO1 && this.IO1.REMF && !this.AD1F) {
this.AD1F = 1;
this.iouMask |= 0x1;
this.iouLatch |= 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.IO2.initiateLoad(this.cardLoadSelect, boundLoadComplete);
} else if (this.IO3 && this.IO3.REMF && !this.AD3F) {
this.AD3F = 1;
this.iouMask |= 0x4;
this.iouLatch |= 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.IO4.initiateLoad(this.cardLoadSelect, boundLoadComplete);
} else {
this.CCI04F = 1; // set I/O busy interrupt
@@ -815,7 +880,6 @@ B5500CentralControl.prototype.runTest = function runTest(runAddr) {
(typically 0x10 [octal 20]) */
this.clear();
this.loadTimer = null;
this.LOFF = 0;
this.P1.preset(runAddr);
this.P1.start();
@@ -850,28 +914,26 @@ B5500CentralControl.prototype.configureSystem = function configureSystem() {
break;
case "LPA":
return function signalLPA() {
cc.setUnitBusy(27, 0);
cc.CCI06F = 1;
cc.signalInterrupt();
};
break;
case "LPB":
return function signalLPB() {
cc.setUnitBusy(26, 0);
cc.CCI07F = 1;
cc.signalInterrupt();
};
break;
case "DKA":
return function signalDKA() {
cc.setUnitBusy(29, 0);
cc.setUnitBusy(29, 0); // Is this needed here ??
cc.CCI15F = 1;
cc.signalInterrupt();
};
break;
case "DKB":
return function signalDKB() {
cc.setUnitBusy(28, 0);
cc.setUnitBusy(28, 0); // Is this needed here ??
cc.CCI16F = 1;
cc.signalInterrupt();
};

View File

@@ -73,9 +73,6 @@ function B5500IOUnit(ioUnitID, cc) {
/**************************************/
B5500IOUnit.timeSlice = 5000; // Standard run() timeslice, about 5ms (we hope)
B5500IOUnit.memCycles = 6; // assume 6 us memory cycle time (the other option was 4 usec)
B5500IOUnit.BICtoANSI = [ // Index by 6-bit BIC to get 8-bit ANSI code
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, // 00-07, @00-07
0x38,0x39,0x23,0x40,0x3F,0x3A,0x3E,0x7D, // 08-1F, @10-17
@@ -219,7 +216,7 @@ B5500IOUnit.prototype.fetch = function fetch(addr) {
this.cc.fetch(acc);
this.W = acc.word;
this.cycleCount += B5500IOUnit.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED) {
this.D26F = 1; // set memory address error
return 1;
@@ -241,7 +238,7 @@ B5500IOUnit.prototype.store = function store(addr) {
acc.word = this.W;
this.cc.store(acc);
this.cycleCount += B5500IOUnit.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED) {
this.D26F = 1; // set memory address error
return 1;
@@ -699,12 +696,18 @@ B5500IOUnit.prototype.initiatePrinterIO = function initiatePrinterIO(u) {
this.D30F = 1; // can't read from the printer
this.finish();
} else {
memWords = this.DwordCount;
if (memWords > 0) {
chars = memWords*8;
if (this.D18F) {
chars = memWords = 0;
} else {
memWords = 17; // assume a 132-character printer
chars = 132;
memWords = (this.D23F ? this.DwordCount : 0);
if (memWords > 0) {
chars = memWords*8;
} else {
memWords = 17; // assume a 132-character printer
chars = 132;
}
this.fetchBuffer(1, memWords);
this.Daddress = (addr-1) & 0x7FFF; // printer accesses memory backwards, so final address is initial-1
}
cc = this.LP;
if (cc & 0x0F) {
@@ -716,10 +719,8 @@ B5500IOUnit.prototype.initiatePrinterIO = function initiatePrinterIO(u) {
} else {
cc = 0; // zero space after print
}
this.fetchBuffer(1, memWords);
this.DwordCount = memWords*32; // actual word count in D.[8:5], D.[13:5]=0
this.Daddress = addr-1; // printer accesses memory backwards, so final address is initial-1
u.write(this.boundFinishBusy, this.buffer, chars, 0, cc);
u.write(this.boundFinishGeneric, this.buffer, chars, 0, cc);
}
};
@@ -779,8 +780,11 @@ B5500IOUnit.prototype.forkIO = function forkIO() {
if (this.D24F) { // CRA
u.read(this.boundFinishGenericRead, this.buffer, (this.D21F ? 160 : 80), this.D21F, 0);
} else { // CPA
this.D30F = 1; // >>> temp until CPA implemented <<<
this.finish();
this.fetchBuffer(1, 10);
this.D21F = 0; // force alpha mode
this.DwordCount = 10; // word count to 10
x = (this.D % 0x10000) >>> 15; // D32F = select alternate stacker
u.write(this.boundFinishGeneric, this.buffer, 80, 0, x);
}
break;
@@ -893,7 +897,7 @@ B5500IOUnit.prototype.initiateLoad = function initiateLoad(cardLoadSelect, loadC
if (cardLoadSelect) {
this.D = 0x0A0004800010; // unit 10, read, binary mode, addr @00020
this.Dunit = 10; // 10=CRA
this.D24F = 1; // read
this.D21F = 1; // binary mode
chars = 20*8;
} else {
this.D = 0x0600009F8010; // unit 6, read, alpha mode, 63 segs, addr @00020

View File

@@ -52,8 +52,7 @@ function B5500Processor(procID, cc) {
/**************************************/
B5500Processor.timeSlice = 5000; // Standard run() timeslice, about 5ms (we hope)
B5500Processor.memCycles = 6; // assume 6 us memory cycle time (the other option was 4 usec)
B5500Processor.timeSlice = 16000; // Standard run() timeslice in clocks (about 16ms, we hope)
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
@@ -112,9 +111,9 @@ B5500Processor.prototype.clear = function clear() {
this.cycleCount = 0; // Current cycle count for this.run()
this.cycleLimit = 0; // Cycle limit for this.run()
this.totalCycles = 0; // Total cycles executed on this processor
this.procStart = 0; // Javascript time that the processor started running, µs
this.procTime = 0; // Total processor running time, based on cycles executed, µs
this.procSlack = 0; // Total processor throttling delay, µs
this.procStart = 0; // Javascript time that the processor started running, ms
this.procTime = 0; // Total processor running time, ms
this.procSlack = 0; // Total processor throttling delay, ms
this.busy = 0; // Processor is running, not idle or halted
};
@@ -144,7 +143,7 @@ B5500Processor.prototype.loadAviaS = function loadAviaS() {
acc.addr = this.S;
acc.MAIL = (this.S < 0x0200 && this.NCSF);
this.cc.fetch(acc);
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
} else {
@@ -162,7 +161,7 @@ B5500Processor.prototype.loadBviaS = function loadBviaS() {
acc.addr = this.S;
acc.MAIL = (this.S < 0x0200 && this.NCSF);
this.cc.fetch(acc);
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
} else {
@@ -180,7 +179,7 @@ B5500Processor.prototype.loadAviaM = function loadAviaM() {
acc.addr = this.M;
acc.MAIL = (this.M < 0x0200 && this.NCSF);
this.cc.fetch(acc);
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
} else {
@@ -198,7 +197,7 @@ B5500Processor.prototype.loadBviaM = function loadBviaM() {
acc.addr = this.M;
acc.MAIL = (this.M < 0x0200 && this.NCSF);
this.cc.fetch(acc);
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
} else {
@@ -216,7 +215,7 @@ B5500Processor.prototype.loadMviaM = function loadMviaM() {
acc.addr = this.M;
acc.MAIL = (this.M < 0x0200 && this.NCSF);
this.cc.fetch(acc);
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
} else {
@@ -234,7 +233,7 @@ B5500Processor.prototype.loadPviaC = function loadPviaC() {
acc.MAIL = (this.C < 0x0200 && this.NCSF);
this.cc.fetch(acc);
this.PROF = 1; // PROF gets set even for invalid address
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
} else {
@@ -252,7 +251,7 @@ B5500Processor.prototype.storeAviaS = function storeAviaS() {
acc.MAIL = (this.S < 0x0200 && this.NCSF);
acc.word = this.A;
this.cc.store(acc);
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
}
@@ -268,7 +267,7 @@ B5500Processor.prototype.storeBviaS = function storeBviaS() {
acc.MAIL = (this.S < 0x0200 && this.NCSF);
acc.word = this.B;
this.cc.store(acc);
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
}
@@ -284,7 +283,7 @@ B5500Processor.prototype.storeAviaM = function storeAviaM() {
acc.MAIL = (this.M < 0x0200 && this.NCSF);
acc.word = this.A;
this.cc.store(acc);
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
}
@@ -300,7 +299,7 @@ B5500Processor.prototype.storeBviaM = function storeBviaM() {
acc.MAIL = (this.M < 0x0200 && this.NCSF);
acc.word = this.B;
this.cc.store(acc);
this.cycleCount += B5500Processor.memCycles;
this.cycleCount += B5500CentralControl.memCycles;
if (acc.MAED || acc.MPED) {
this.accessError();
}
@@ -1344,7 +1343,7 @@ B5500Processor.prototype.start = function start() {
/* Initiates the processor by scheduling it on the Javascript thread */
this.busy = 1;
this.procTime = this.procStart = new Date().getTime()*1000;
this.procStart = new Date().getTime();
this.scheduler = setTimeout(this.boundSchedule, 0);
};
@@ -2136,7 +2135,7 @@ B5500Processor.prototype.doublePrecisionAdd = function doublePrecisionAdd(adding
var xb; // extended mantissa for B
// Estimate some general overhead and account for stack manipulation we don't do
this.cycleCount += B5500Processor.memCycles*4 + 8;
this.cycleCount += B5500CentralControl.memCycles*4 + 8;
this.adjustABFull(); // extract the top (A) operand fields:
ma = this.A % 0x8000000000; // extract the A mantissa
@@ -2363,8 +2362,9 @@ B5500Processor.prototype.computeRelativeAddr = function computeRelativeAddr(offs
/**************************************/
B5500Processor.prototype.presenceTest = function presenceTest(word) {
/* Tests and returns the presence bit [2:1] of the "word" parameter. If
0, the p-bit interrupt is set; otherwise no further action */
/* Tests and returns the presence bit [2:1] of the "word" parameter,
which it assumes is a control word. If [2:1] is 0, the p-bit interrupt
is set; otherwise no further action */
if (word % 0x400000000000 >= 0x200000000000) {
return 1;
@@ -2629,11 +2629,11 @@ B5500Processor.prototype.enterCharModeInline = function enterCharModeInline() {
// execute the portion of CM XX04=RDA operator starting at J=2
this.S = bw % 0x8000;
if (bw >= 0x800000000000) { // if it's a descriptor,
this.K = 0; // force K to zero and
this.presenceTest(bw); // just take the side effect of any p-bit interrupt
if (bw < 0x800000000000) { // if it's an operand
this.K = (bw % 0x40000) >>> 15; // set K from [30:3]
} else {
this.K = (bw % 0x40000) >>> 15;
this.K = 0; // otherwise, force K to zero and
this.presenceTest(bw); // just take the side effect of any p-bit interrupt
}
};
@@ -2726,7 +2726,7 @@ B5500Processor.prototype.exitSubroutine = function exitSubroutine(inline) {
do {
this.S = (this.B % 0x40000000) >>> 15;
this.loadBviaS(); // B = [S], fetch prior MSCW
} while ((this.B % 0x100000000 - this.B % 0x80000000)/0x80000000 == 1); // MSFF
} while ((this.B % 0x100000000 - this.B % 0x80000000)/0x80000000); // MSFF
this.S = this.R*64 + 7;
this.storeBviaS(); // [S] = B, store last MSCW at [R]+7
}
@@ -2916,11 +2916,11 @@ B5500Processor.prototype.run = function run() {
this.loadBviaS(); // B = [S]
this.BROF = 0;
this.S = (t1 = this.B) % 0x8000;
if (t1 >= 0x800000000000) { // if it's a descriptor,
this.K = 0; // force K to zero and
this.presenceTest(t1); // just take the side effect of any p-bit interrupt
if (t1 < 0x800000000000) { // if it's an operand,
this.K = (t1 % 0x40000) >>> 15;// set K from [30:3]
} else {
this.K = (t1 % 0x40000) >>> 15;
this.K = 0; // otherwise, force K to zero and
this.presenceTest(t1); // just take the side effect of any p-bit interrupt
}
break;
@@ -3300,15 +3300,16 @@ B5500Processor.prototype.run = function run() {
this.S = this.F - variant;
this.loadBviaS(); // B = [S]
this.S = t1;
if (this.B >= 0x800000000000) { // if it's a descriptor,
if (this.presenceTest(this.B)) {// if present, initiate a fetch to P
t2 = this.B;
if (t2 >= 0x800000000000) { // if it's a descriptor,
if (this.presenceTest(t2)) { // if present, initiate a fetch to P
this.C = this.B % 0x8000; // get the word address,
this.L = 0; // force L to zero and
this.PROF = 0; // require fetch at SECL
}
} else {
this.C = this.B % 0x8000;
t1 = (this.B % 0x4000000000 - this.B % 0x1000000000)/0x1000000000;
this.C = t2 % 0x8000;
t1 = (t2 % 0x4000000000 - t2 % 0x1000000000)/0x1000000000;
if (t1 < 3) { // if not a descriptor, increment the address
this.L = t1+1;
} else {
@@ -3370,12 +3371,13 @@ B5500Processor.prototype.run = function run() {
this.H = 0;
this.M = this.F - variant;
this.loadBviaM(); // B = [M]
this.M = this.B % 0x8000;
if (this.B >= 0x800000000000) { // if it's a descriptor,
this.G = 0; // force G to zero and
this.presenceTest(this.B); // just take the side effect of any p-bit interrupt
} else { // it's an operand
this.G = (this.B % 0x40000) >>> 15;
t1 = this.B;
this.M = t1 % 0x8000;
if (t1 < 0x800000000000) { // if it's an operand,
this.G = (t1 % 0x40000) >>> 15; // set G from [30:3]
} else { //
this.G = 0; // otherwise, force G to zero and
this.presenceTest(t1); // just take the side effect of any p-bit interrupt
}
this.B = this.A; // restore B from A
this.BROF = this.AROF;
@@ -4211,20 +4213,24 @@ B5500Processor.prototype.run = function run() {
case 0x02: // 0235: RTN=return normal
this.adjustAFull();
this.S = this.F;
this.loadBviaS(); // B = [S], fetch the RCW
switch (this.exitSubroutine(0)) {
case 0:
this.X = 0;
this.operandCall();
break;
case 1:
this.Q |= 0x10; // set Q05F, for display only
this.X = 0;
this.descriptorCall();
break;
case 2: // flag-bit interrupt occurred, do nothing
break;
// If A is an operand or a present descriptor, proceed with the return,
// otherwise throw a p-bit interrupt (this isn't well-documented)
if (this.A < 0x800000000000 || this.presenceTest(this.A)) {
this.S = this.F;
this.loadBviaS(); // B = [S], fetch the RCW
switch (this.exitSubroutine(0)) {
case 0:
this.X = 0;
this.operandCall();
break;
case 1:
this.Q |= 0x10; // set Q05F, for display only
this.X = 0;
this.descriptorCall();
break;
case 2: // flag-bit interrupt occurred, do nothing
break;
}
}
break;
@@ -4237,20 +4243,24 @@ B5500Processor.prototype.run = function run() {
case 0x0A: // 1235: RTS=return special
this.adjustAFull();
// Note that RTS assumes the RCW is pointed to by S, not F
this.loadBviaS(); // B = [S], fetch the RCW
switch (this.exitSubroutine(0)) {
case 0:
this.X = 0;
this.operandCall();
break;
case 1:
this.Q |= 0x10; // set Q05F, for display only
this.X = 0;
this.descriptorCall();
break;
case 2: // flag-bit interrupt occurred, do nothing
break;
// If A is an operand or a present descriptor, proceed with the return,
// otherwise throw a p-bit interrupt (this isn't well-documented)
if (this.A < 0x800000000000 || this.presenceTest(this.A)) {
// Note that RTS assumes the RCW is pointed to by S, not F
this.loadBviaS(); // B = [S], fetch the RCW
switch (this.exitSubroutine(0)) {
case 0:
this.X = 0;
this.operandCall();
break;
case 1:
this.Q |= 0x10; // set Q05F, for display only
this.X = 0;
this.descriptorCall();
break;
case 2: // flag-bit interrupt occurred, do nothing
break;
}
}
break;
}
@@ -4536,7 +4546,7 @@ B5500Processor.prototype.run = function run() {
break;
}
}
} while ((this.cycleCount += 2) < this.cycleLimit);
} while ((this.cycleCount += 1) < this.cycleLimit);
};
/**************************************/
@@ -4548,10 +4558,13 @@ B5500Processor.prototype.schedule = function schedule() {
each and calls run() to execute at most that number of cycles. run()
counts up cycles until it reaches this limit or some terminating event
(such as a halt), then exits back here. If the processor remains active,
this routine will reschedule itself for an appropriate later time, thereby
this routine will reschedule itself after an appropriate delay, thereby
throttling the performance and allowing other modules a chance at the
Javascript execution thread. */
var delayTime;
Javascript execution thread */
var delayTime; // delay until next run() for this processor, ms
var elapsedTime; // elapsed real time for this run() call, ms
var startTime = new Date().getTime(); // starting time for this run() call, ms
var stopTime; // ending time for this run() call, ms
this.scheduler = null;
this.cycleLimit = B5500Processor.timeSlice;
@@ -4559,12 +4572,14 @@ B5500Processor.prototype.schedule = function schedule() {
this.run(); // execute syllables for the timeslice
stopTime = new Date().getTime();
elapsedTime = stopTime - startTime;
this.procTime += elapsedTime;
this.totalCycles += this.cycleCount;
this.procTime += this.cycleCount;
if (this.busy) {
delayTime = this.procTime - new Date().getTime()*1000;
delayTime = this.cycleCount/1000 - elapsedTime;
this.procSlack += delayTime;
this.scheduler = setTimeout(this.boundSchedule, (delayTime > 0 ? delayTime/1000 : 1));
this.scheduler = setTimeout(this.boundSchedule, (delayTime > 0 ? delayTime : 1));
}
};

View File

@@ -43,8 +43,8 @@ var B5500SystemConfiguration = {
DKB: false, // Disk File Control B
CRA: true, // Card Reader A
CRB: false, // Card Reader B
CPA: false, // Card Punch A
LPA: false, // Line Printer A
CPA: true, // Card Punch A
LPA: true, // Line Printer A
LPB: false, // Line Printer B
PRA: false, // Paper Tape Reader A
PRB: false, // Paper Tape Reader B

59
index.css Normal file
View File

@@ -0,0 +1,59 @@
/***********************************************************************
* retro-b5500/emulator index.css
************************************************************************
* Copyright (c) 2013, Nigel Williams and Paul Kimpel.
* Licensed under the MIT License, see http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B5500 emulator test site home page style sheet.
************************************************************************
* 2013-06-18 P.Kimpel
* Original version, from B5500Console.css.
***********************************************************************/
BODY {
position: relative;
max-width: 80ex;
font-family: Arial, Helvetica, sans-serif;
font-size: medium;
margin: 4px}
H1 {
margin-top: 18pt;
margin-bottom: 6pt;
vertical-align: middle;
font-size: larger;
font-weight: bold}
H2 {
margin-top: 12pt;
margin-bottom: 0;
font-size: medium;
font-weight: bold}
UL {
margin-top: 6pt;
margin-bottom: 6pt}
UL LI {
margin-top: 3pt;
margin-bottom: 3pt}
.center {
text-align: center}
.data {
font-family: Courier New, Courier, monospace;
text-align: left}
.number {
font-family: Courier New, Courier, monospace;
text-align: right}
IMG#retroButton {
float: right}
DIV#footerDiv {
position: fixed;
bottom: 1ex;
width: 100%;
text-align: center;
font-size: xx-small}

45
index.html Normal file
View File

@@ -0,0 +1,45 @@
<!DOCTYPE html>
<head>
<title>retro-B5500 Emulator Test Site</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Nigel Williams & Paul Kimpel">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="index.css">
</head>
<body>
<img id=retroButton src="./webUI/retro-Button-Logo.png" alt="retro yellow button logo">
<h1><img src="./webUI/retro-B5500-Logo.png" alt="retro logo">
<hr>
Burroughs B5500 Emulator Test Site
</h1>
<p>This site hosts the current test version of the retro-B5500 emulator, a web-browser based emulator for the legendary Burroughs B5500 system of the 1960s.
<h2>Main Links</h2>
<ul>
<li><a href="./webUI/B5500Console.html">B5500 Console</a>
<br>Opens the B5500 operations console to run the emulator
<li><a href="./SoftwareRequest.html">B5500 Mark-XIII System Software</a>
<br>Provides access to tape images of B5500 system software for the Mark-XIII (1971) software release.
<li><a href="./HelpMenu.html">Help</a>
<br>Opens a menu for information resources to assist you in setting up and operating the emulator.
<li><a href="https://code.google.com/p/retro-b5500/">Open Source Project</a>
<br>Source code, downloads, and other developer resources for the project on Google Code.
<li><a href="http://retro-b5500.blogspot.com/">Project Blog</a>
<br>Opens a menu for information resources to assist you in setting up and operating the emulator.
</ul>
<div id=footerDiv>
Copyright (c) 2013, Nigel Williams and Paul Kimpel &bull; Licensed under the MIT License
</div>
</body>
</html>

139
webUI/B5500CardPunch.css Normal file
View File

@@ -0,0 +1,139 @@
/***********************************************************************
* retro-b5500/emulator B5500CardPunch.css
************************************************************************
* Copyright (c) 2013, Nigel Williams and Paul Kimpel.
* Licensed under the MIT License, see http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B5500 emulator Card Punch web interface style sheet.
************************************************************************
* 2013-06-16 P.Kimpel
* Original version, from B5500CardReader.css.
***********************************************************************/
BODY {
position: relative;
color: white;
background-color: black;
font-family: Arial, Helventica, sans-serif;
font-size: 9pt;
margin: 4px}
PRE {
font-family: Lucida Sans Typewriter, Courier New, Courier, monospace}
DIV#CPDiv {
position: relative;
color: white;
background-color: #666;
width: 700px;
height: 300px;
border: 1px solid black;
border-radius: 8px;
padding: 0;
vertical-align: top}
BUTTON.greenButton {
background-color: #060;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: bold;
width: 60px;
height: 40px;
border: 1px solid #DDD;
border-radius: 4px}
BUTTON.blackButton {
background-color: black;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: bold;
width: 60px;
height: 40px;
border: 1px solid #DDD;
border-radius: 4px}
BUTTON.redButton {
background-color: #900;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: bold;
width: 60px;
height: 40px;
border: 1px solid #DDD;
border-radius: 4px}
BUTTON.greenLit {
background-color: green}
BUTTON.redLit {
background-color: #F00}
#CPNotReadyLight {
position: absolute;
top: 8px;
left: 8px}
#CPRunoutBtn {
position: absolute;
top: 8px;
left: 76px}
#CPStopBtn {
position: absolute;
top: 8px;
left: 144px}
#CPStartBtn {
position: absolute;
top: 8px;
left: 212px;}
#CPStacker1Div {
position: absolute;
top: 56px;
left: 8px;
right: 8px;
height: 160px;
font-weight: bold}
#CPStacker1Bar {
border: 1px solid white;
width: 610px}
#CPStacker1Frame {
width: 100%;
height: 140px;
margin-top: 1px;
border: 1px solid white;
color: black;
background-color: white;
font-family: Lucida Sans Typewriter, Courier New, Courier, monospace;
font-size: 10pt;
font-weight: normal}
#CPStacker2Div {
position: absolute;
top: 220px;
left: 8px;
right: 8px;
height: 70px;
font-weight: bold}
#CPStacker2Bar {
border: 1px solid white;
width: 610px}
#CPStacker2Frame {
width: 100%;
height: 50px;
margin-top: 1px;
border: 1px solid white;
color: black;
background-color: white;
font-family: Lucida Sans Typewriter, Courier New, Courier, monospace;
font-size: 10pt;
font-weight: normal}

32
webUI/B5500CardPunch.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<head>
<title>B5500 Emulator Card Punch</title>
<meta name="Author" content="Nigel Williams & Paul Kimpel">
<!-- 2013-06-16 Original version, cloned from B5500CardReader.html -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500CardPunch.css">
</head>
<body>
<div id=CPDiv>
<button id=CPNotReadyLight class="redButton redLit">NOT READY</button>
<button id=CPRunoutBtn class="redButton">RUNOUT</button>
<button id=CPStopBtn class="redButton">STOP</button>
<button id=CPStartBtn class="greenButton">START</button>
<div id=CPStacker1Div>
Stacker 1 <progress id=CPStacker1Bar min=0 max=100 value=0></progress>
<iframe id=CPStacker1Frame scrolling=auto></iframe>
</div>
<div id=CPStacker2Div>
Stacker 2 <progress id=CPStacker2Bar min=0 max=100 value=0></progress>
<iframe id=CPStacker2Frame scrolling=auto></iframe>
</div>
</div>
</body>
</html>

322
webUI/B5500CardPunch.js Normal file
View File

@@ -0,0 +1,322 @@
/***********************************************************************
* retro-b5500/emulator B5500CardPunch.js
************************************************************************
* Copyright (c) 2013, Nigel Williams and Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B5500 Card Punch Peripheral Unit module.
*
* Defines a card punch peripheral unit type.
*
************************************************************************
* 2013-06-16 P.Kimpel
* Original version, from B5500CardReader.js & B5500DummyPrinter.js.
***********************************************************************/
"use strict";
/**************************************/
function B5500CardPunch(mnemonic, unitIndex, designate, statusChange, signal) {
/* Constructor for the CardPunch object */
var that = this;
this.mnemonic = mnemonic; // Unit mnemonic
this.unitIndex = unitIndex; // Ready-mask bit number
this.designate = designate; // IOD unit designate number
this.statusChange = statusChange; // external function to call for ready-status change
this.signal = signal; // external function to call for special signals (not used here)
this.clear();
this.window = window.open("", mnemonic);
if (this.window) {
this.window.close(); // destroy the previously-existing window
this.window = null;
}
this.doc = null;
this.stacker1 = null;
this.endOfStacker1 = null;
this.stacker2 = null;
this.endOfStacker2 = null;
this.window = window.open("/B5500/webUI/B5500CardPunch.html", mnemonic,
"scrollbars=no,resizable,width=700,height=500");
this.window.addEventListener("load", function() {
that.punchOnload();
}, false);
}
B5500CardPunch.prototype.cardsPerMinute = 300; // Punch speed
B5500CardPunch.prototype.maxScrollLines = 800; // Maximum punch stacker scrollback (stacker capacity)
/**************************************/
B5500CardPunch.prototype.$$ = function $$(e) {
return this.doc.getElementById(e);
};
/**************************************/
B5500CardPunch.prototype.clear = function clear() {
/* Initializes (and if necessary, creates) the punch unit state */
this.ready = false; // ready status
this.busy = false; // busy status
this.activeIOUnit = 0; // I/O unit currently using this device
this.errorMask = 0; // error mask for finish()
this.finish = null; // external function to call for I/O completion
this.runoutArmed = false; // EOF button: armed state
this.stopCount = 0; // stopCount for clearing the input buffer
this.stacker1Count = 0; // cards in stacker #1
this.stacker2Count = 0; // cards in stacker #2
};
/**************************************/
B5500CardPunch.prototype.hasClass = function hasClass(e, name) {
/* returns true if element "e" has class "name" in its class list */
var classes = e.className;
if (!e) {
return false;
} else if (classes == name) {
return true;
} else {
return (classes.search("\\b" + name + "\\b") >= 0);
}
};
/**************************************/
B5500CardPunch.prototype.addClass = function addClass(e, name) {
/* Adds a class "name" to the element "e"s class list */
if (!this.hasClass(e, name)) {
e.className += (" " + name);
}
};
/**************************************/
B5500CardPunch.prototype.removeClass = function removeClass(e, name) {
/* Removes the class "name" from the element "e"s class list */
e.className = e.className.replace(new RegExp("\\b" + name + "\\b\\s*", "g"), "");
};
/**************************************/
B5500CardPunch.prototype.setPunchReady = function setPunchReady(ready) {
/* Controls the ready-state of the card punch */
if (ready && !this.ready) {
this.statusChange(1);
this.removeClass(this.$$("CPNotReadyLight"), "redLit");
this.ready = true;
if (this.runoutArmed) {
if (this.stacker1Count || this.stacker2Count) {
if (this.window.confirm("Empty both " + this.mnemonic + " stackers?")) {
this.stacker1Count = this.stacker2Count = 0;
this.$$("CPStacker1Bar").value = 0;
this.$$("CPStacker2Bar").value = 0;
while (this.stacker1.firstChild) {
this.stacker1.removeChild(this.stacker1.firstChild);
}
while (this.stacker2.firstChild) {
this.stacker2.removeChild(this.stacker2.firstChild);
}
}
}
this.armRunout(false);
}
} else if (!ready && this.ready) {
this.statusChange(0);
this.addClass(this.$$("CPNotReadyLight"), "redLit");
this.ready = false;
}
};
/**************************************/
B5500CardPunch.prototype.armRunout = function armRunout(armed) {
/* Controls the arming/disarming of the EOF signal when starting with
an empty input stacker */
if (armed && !this.ready) {
this.addClass(this.$$("CPRunoutBtn"), "redLit");
this.runoutArmed = true;
} else {
this.removeClass(this.$$("CPRunoutBtn"), "redLit");
this.runoutArmed = false;
}
};
/**************************************/
B5500CardPunch.prototype.CPStartBtn_onclick = function CPStartBtn_onclick(ev) {
/* Handle the click event for the START button */
var that = this;
if (!this.ready) {
this.stopCount = 0;
if (this.bufIndex < this.bufLength) {
}
this.setPunchReady(true);
}
};
/**************************************/
B5500CardPunch.prototype.CPStopBtn_onclick = function CPStopBtn_onclick(ev) {
/* Handle the click event for the STOP button */
if (this.ready) {
this.setPunchReady(false);
} else if (this.runoutArmed) {
this.armRunout(false);
}
};
/**************************************/
B5500CardPunch.prototype.CPRunoutBtn_onclick = function CPRunoutBtn_onclick(ev) {
/* Handle the click event for the EOF button */
this.armRunout(!this.runoutArmed);
};
/**************************************/
B5500CardPunch.prototype.punchOnload = function punchOnload() {
/* Initializes the punch window and user interface */
var that = this;
this.doc = this.window.document;
this.doc.title = "retro-B5500 " + this.mnemonic;
this.stacker1Frame = this.$$("CPStacker1Frame");
this.stacker1Frame.contentDocument.head.innerHTML += "<style>" +
"BODY {background-color: #F0DCB0; margin: 2px} " +
"PRE {margin: 0; font-size: 9pt; font-family: Lucida Sans Typewriter, Courier New, Courier, monospace}" +
"</style>";
this.stacker1 = this.doc.createElement("pre");
this.stacker1Frame.contentDocument.body.appendChild(this.stacker1);
this.endOfStacker1 = this.doc.createElement("div");
this.stacker1Frame.contentDocument.body.appendChild(this.endOfStacker1);
this.stacker2Frame = this.$$("CPStacker2Frame");
this.stacker2Frame.contentDocument.head.innerHTML += "<style>" +
"BODY {background-color: #F0DCB0; margin: 2px} " +
"PRE {margin: 0; font-size: 9pt; font-family: Lucida Sans Typewriter, Courier New, Courier, monospace}" +
"</style>";
this.stacker2 = this.doc.createElement("pre");
this.stacker2Frame.contentDocument.body.appendChild(this.stacker2);
this.endOfStacker2 = this.doc.createElement("div");
this.stacker2Frame.contentDocument.body.appendChild(this.endOfStacker2);
this.window.moveTo(0, 180);
this.window.resizeTo(this.window.outerWidth+this.$$("CPDiv").scrollWidth-this.window.innerWidth+12,
this.window.outerHeight+this.$$("CPDiv").scrollHeight-this.window.innerHeight+12);
this.armRunout(false);
this.setPunchReady(true);
this.$$("CPStartBtn").addEventListener("click", function(ev) {
that.CPStartBtn_onclick(ev);
}, false);
this.$$("CPStopBtn").addEventListener("click", function(ev) {
that.CPStopBtn_onclick(ev);
}, false);
this.$$("CPRunoutBtn").addEventListener("click", function(ev) {
that.CPRunoutBtn_onclick(ev);
}, false);
this.$$("CPStacker1Bar").max = this.maxScrollLines;
this.$$("CPStacker2Bar").max = this.maxScrollLines;
};
/**************************************/
B5500CardPunch.prototype.appendLine = function appendLine(stacker, text) {
/* Removes excess lines already printed, then appends a new <pre> element
to the <iframe>, creating an empty text node inside the new element */
var count = stacker.childNodes.length;
var line = this.doc.createTextNode(text || "");
//while (count-- > this.maxScrollLines) {
// stacker.removeChild(stacker.firstChild);
//}
stacker.appendChild(line);
};
/**************************************/
B5500CardPunch.prototype.read = function read(finish, buffer, length, mode, control) {
/* Initiates a read operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardPunch.prototype.space = function space(finish, length, control) {
/* Initiates a space operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardPunch.prototype.write = function write(finish, buffer, length, mode, control) {
/* Initiates a write operation on the unit */
var text;
var that = this;
this.errorMask = 0;
this.busy = true;
text = String.fromCharCode.apply(null, buffer.subarray(0, length));
//console.log("WRITE: L=" + length + ", M=" + mode + ", C=" + control + " : " + text);
if (control) {
this.appendLine(this.stacker2, text + "\n");
this.endOfStacker2.scrollIntoView();
this.$$("CPStacker2Bar").value = (++this.stacker2Count);
if (this.stacker2Count >= this.maxScrollLines) {
this.setPunchReady(false);
}
} else {
this.appendLine(this.stacker1, text + "\n");
this.endOfStacker1.scrollIntoView();
this.$$("CPStacker1Bar").value = (++this.stacker1Count);
if (this.stacker1Count >= this.maxScrollLines) {
this.setPunchReady(false);
}
}
setTimeout(function() {
that.busy = false;
finish(that.errorMask, length);
}, 60000/this.cardsPerMinute);
};
/**************************************/
B5500CardPunch.prototype.erase = function erase(finish, length) {
/* Initiates an erase operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardPunch.prototype.rewind = function rewind(finish) {
/* Initiates a rewind operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardPunch.prototype.readCheck = function readCheck(finish, length, control) {
/* Initiates a read check operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardPunch.prototype.readInterrogate = function readInterrogate(finish, control) {
/* Initiates a read interrogate operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500CardPunch.prototype.writeInterrogate = function writeInterrogate(finish, control) {
/* Initiates a write interrogate operation on the unit */
finish(0x04, 0); // report unit not ready
};

View File

@@ -18,8 +18,8 @@ BODY {
DIV#CRDiv {
position: relative;
background-color: #666;
width: 280px;
height: 112px;
width: 700px;
height: 150px;
border: 1px solid black;
border-radius: 8px;
padding: 0;
@@ -94,6 +94,19 @@ BUTTON.redLit {
#CRProgressBar {
position: absolute;
border: 1px solid white;
top: 84px;
top: 82px;
left: 8px;
width: 262px}
width: 680px}
#CROutHopperFrame {
position: absolute;
top: 104px;
left: 8px;
width: 680px;
height: 35px;
border: 1px solid white;
color: black;
background-color: white;
font-family: Lucida Sans Typewriter, Courier New, Courier, monospace;
font-size: 8pt;
font-weight: normal}

View File

@@ -17,9 +17,11 @@
<button id=CREOFBtn class="redButton">EOF</button>
<button id=CRStopBtn class="redButton">STOP</button>
<input id=CRFileSelector type=file size=29>
<input id=CRFileSelector type=file size=90>
<progress id=CRProgressBar min=0 max=100 value=0>
<progress id=CRProgressBar min=0 max=100 value=0 title="Click to clear input hopper"></progress>
<iframe id=CROutHopperFrame scrolling=no></iframe>
</div>
</body>

View File

@@ -24,7 +24,7 @@ function B5500CardReader(mnemonic, unitIndex, designate, statusChange, signal) {
this.unitIndex = unitIndex; // Ready-mask bit number
this.designate = designate; // IOD unit designate number
this.statusChange = statusChange; // external function to call for ready-status change
this.signal = signal; // external function to call for special signals (e.g,. SPO input request)
this.signal = signal; // external function to call for special signals (not used here)
this.clear();
@@ -35,11 +35,15 @@ function B5500CardReader(mnemonic, unitIndex, designate, statusChange, signal) {
}
this.doc = null;
this.window = window.open("/B5500/webUI/B5500CardReader.html", mnemonic,
"scrollbars=no,resizable,width=200,height=200");
this.window.onload = function() {
"scrollbars=no,resizable,width=700,height=150");
this.window.addEventListener("load", function() {
that.readerOnload();
};
}, false);
this.outHopperFrame = null;
this.outHopper = null;
}
B5500CardReader.prototype.eolRex = /([^\n\r\f]*)((:?\r[\n\f]?)|\n|\f)?/g;
B5500CardReader.prototype.cardsPerMinute = 800;
@@ -74,7 +78,6 @@ B5500CardReader.prototype.clear = function clear() {
this.bufLength = 0; // Current input buffer length (characters)
this.bufIndex = 0; // 0-relative offset to next "card" to be read
this.eofArmed = false; // EOF button: armed state
this.stopCount = 0; // stopCount for clearing the input buffer
};
/**************************************/
@@ -141,7 +144,6 @@ B5500CardReader.prototype.CRStartBtn_onclick = function CRStartBtn_onclick(ev) {
var that = this;
if (!this.ready) {
this.stopCount = 0;
if (this.bufIndex < this.bufLength) {
this.setReaderReady(true);
}
@@ -156,18 +158,6 @@ B5500CardReader.prototype.CRStopBtn_onclick = function CRStopBtn_onclick(ev) {
this.setReaderReady(false);
} else if (this.eofArmed) {
this.armEOF(false);
} else if (this.bufIndex < this.bufLength) {
if (this.stopCount < 3) {
this.stopCount++;
} else {
if (confirm("Empty the " + this.mnemonic + " input hopper?")) {
this.stopCount = 0;
this.buffer = "";
this.bufLength = 0;
this.bufIndex = 0;
this.$$("CRProgressBar").value = 0;
}
}
}
};
@@ -178,6 +168,21 @@ B5500CardReader.prototype.CREOFBtn_onclick = function CREOFBtn_onclick(ev) {
this.armEOF(!this.eofArmed);
};
/**************************************/
B5500CardReader.prototype.CRProgressBar_onclick = function CRProgressBar_onclick(ev) {
/* Handle the click event for the "input hopper" progress bar */
if (this.bufIndex < this.bufLength && !this.ready) {
if (confirm((this.bufLength-this.bufIndex).toString() + " of " + this.bufLength.toString() +
" characters remaining to read.\nDo you want to clear the reader input hopper?")) {
this.buffer = "";
this.bufLength = 0;
this.bufIndex = 0;
this.$$("CRProgressBar").value = 0;
}
}
};
/**************************************/
B5500CardReader.prototype.fileSelector_onChange = function fileSelector_onChange(ev) {
/* Handle the <input type=file> onchange event when a file is selected */
@@ -200,12 +205,6 @@ B5500CardReader.prototype.fileSelector_onChange = function fileSelector_onChange
that.$$("CRProgressBar").max = that.bufLength;
}
/********************
alert("File selected: " + f.name +
"\nModified " + f.lastModifiedDate +
"\nType=" + f.type + ", Size=" + f.size + " octets");
********************/
reader.onload = fileLoader_onLoad;
reader.readAsText(f);
};
@@ -214,7 +213,8 @@ B5500CardReader.prototype.fileSelector_onChange = function fileSelector_onChange
B5500CardReader.prototype.readCardAlpha = function readCardAlpha(buffer, length) {
/* Reads one card image from the buffer in alpha mode; pads or trims the
image as necessary to the I/O buffer length. Invalid BCL characters are
translated to ASCII "?" and the invalid character bit is set in the errorMask */
translated to ASCII "?" and the invalid character bit is set in the errorMask.
Returns the raw card image as a string */
var card; // card image
var cardLength; // length of card image
var match; // result of eolRex.exec()
@@ -223,6 +223,7 @@ B5500CardReader.prototype.readCardAlpha = function readCardAlpha(buffer, length)
this.eolRex.lastIndex = this.bufIndex;
match = this.eolRex.exec(this.buffer);
if (!match) {
card = "";
cardLength = 0;
} else {
this.bufIndex += match[0].length;
@@ -241,13 +242,16 @@ B5500CardReader.prototype.readCardAlpha = function readCardAlpha(buffer, length)
while (cardLength < length) {
buffer[cardLength++] = 0x20; // pad with spaces
}
return card;
};
/**************************************/
B5500CardReader.prototype.readCardBinary = function readCardBinary(buffer, length) {
/* Reads one card image from the buffer in binary mode; pads or trims the
image as necessary to the I/O buffer length. Invalid BCL characters are
translated to ASCII "?", but are not reported in the errorMask */
translated to ASCII "?", but are not reported in the errorMask.
Returns the raw card image as a string */
var card; // card image
var cardLength; // length of card image
var match; // result of eolRex.exec()
@@ -256,6 +260,7 @@ B5500CardReader.prototype.readCardBinary = function readCardBinary(buffer, lengt
this.eolRex.lastIndex = this.bufIndex;
match = this.eolRex.exec(this.buffer);
if (!match) {
card = "";
cardLength = 0;
} else {
this.bufIndex += match[0].length;
@@ -272,6 +277,8 @@ B5500CardReader.prototype.readCardBinary = function readCardBinary(buffer, lengt
while (cardLength < length) {
buffer[cardLength++] = 0x30; // pad with ASCII zeroes
}
return card;
};
/**************************************/
@@ -280,12 +287,20 @@ B5500CardReader.prototype.readerOnload = function readerOnload() {
var that = this;
var x = (this.mnemonic == "CRA" ? 0 : this.window.outerWidth + 16);
this.doc = this.window.document;
this.doc.title = "retro-B5500 " + this.mnemonic;
this.window.moveTo(x, 0);
this.window.resizeTo(this.window.outerWidth+this.$$("CRDiv").scrollWidth-this.window.innerWidth+8,
this.window.outerHeight+this.$$("CRDiv").scrollHeight-this.window.innerHeight+8);
this.window.resizeTo(this.window.outerWidth+this.$$("CRDiv").scrollWidth-this.window.innerWidth+12,
this.window.outerHeight+this.$$("CRDiv").scrollHeight-this.window.innerHeight+12);
this.outHopperFrame = this.$$("CROutHopperFrame");
this.outHopperFrame.contentDocument.head.innerHTML += "<style>" +
"BODY {background-color: #F0DCB0; margin: 2px} " +
"PRE {margin: 0; font-size: 9pt; font-family: Lucida Sans Typewriter, Courier New, Courier, monospace}" +
"</style>";
this.outHopper = this.doc.createElement("pre");
this.outHopperFrame.contentDocument.body.appendChild(this.outHopper);
this.armEOF(false);
this.setReaderReady(false);
@@ -305,13 +320,18 @@ B5500CardReader.prototype.readerOnload = function readerOnload() {
this.$$("CREOFBtn").addEventListener("click", function(ev) {
that.CREOFBtn_onclick(ev);
}, false);
this.$$("CRProgressBar").addEventListener("click", function(ev) {
that.CRProgressBar_onclick(ev);
}, false);
};
/**************************************/
B5500CardReader.prototype.read = function read(finish, buffer, length, mode, control) {
/* Initiates a read operation on the unit. If the reader is not ready and the input
buffer is empty and EOF is armed , returns EOF; otherwise if not ready,
buffer is empty and EOF is armed, returns EOF; otherwise if not ready,
returns Not Ready */
var card;
var that = this;
this.errorMask = 0;
@@ -327,9 +347,9 @@ B5500CardReader.prototype.read = function read(finish, buffer, length, mode, con
} else {
this.busy = true;
if (mode == 0) {
this.readCardAlpha(buffer, length);
card = this.readCardAlpha(buffer, length);
} else {
this.readCardBinary(buffer, length);
card = this.readCardBinary(buffer, length);
}
if (this.bufIndex < this.bufLength) {
this.$$("CRProgressBar").value = this.bufLength-this.bufIndex;
@@ -345,6 +365,12 @@ B5500CardReader.prototype.read = function read(finish, buffer, length, mode, con
that.busy = false;
finish(that.errorMask, length);
}, 60000/this.cardsPerMinute);
while (this.outHopper.childNodes.length > 1) {
this.outHopper.removeChild(this.outHopper.firstChild);
}
this.outHopper.appendChild(this.doc.createTextNode("\n"));
this.outHopper.appendChild(this.doc.createTextNode(card));
}
};
@@ -359,7 +385,7 @@ B5500CardReader.prototype.space = function space(finish, length, control) {
B5500CardReader.prototype.write = function write(finish, buffer, length, mode, control) {
/* Initiates a write operation on the unit */
finish(0x04); // report unit not ready
finish(0x04, 0); // report unit not ready
};
/**************************************/

View File

@@ -1685,15 +1685,14 @@ window.onload = function() {
stringToANSI("0000001?", fileLabels, labelx-16); // @114, last-entry marker
stringToANSI("00000000", fileLabels, labelx-8);
}
header[0] = 0x0141; // BIC "51" = @0501 = 1 rec/block, 1 seg/block
header[3] = 0x1001200; // Date: BIC "00010180" = 1980-01-01
header[0] = 0x0181; // BIC "61" = @0601 = 6 rec/block, 1 seg/block
header[3] = (365*0x40000 + 10180) * 0x40000 + 10180; // save=365, create+update=1980-01-01
header[7] = -1; // currently has no records
header[8] = areasize;
header[9] = 1; // number of areas
header[10] = 0; // row address unallocated
wordsToANSI(header, 0, 30, buffer, 0);
eu.put(buffer, directoryTop + 18 - fileNr);
fileNr++;
}
@@ -1756,7 +1755,7 @@ window.onload = function() {
pow2[47-28] + // 28: prevent I/O below user disk area
pow2[47-27] + // 27: prevent disk RELEASE statement
pow2[47-26] + // 26: printer backup disk release
// 25: check memory links
pow2[47-25] + // 25: check memory links
pow2[47-24] + // 24: type disk error messages
pow2[47-23] + // 23: disk logging
pow2[47-22] + // 22: suppress library error messages

View File

@@ -16,7 +16,7 @@ BODY {
DIV#consoleDiv {
position: relative;
width: 1052px;
width: 1052px;
height: 72px;
padding: 32px;
background-color: #666}
@@ -42,6 +42,16 @@ DIV#B5500Logo {
right: 32px;
z-index: 15}
DIV#RetroVersion {
display: none; /***** TEMPORARY *****/
position: absolute;
top: 80px;
right: 170px;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: x-small;
font-weight: bold}
IMG#BurroughsLogoImage {
width: 150px;
text-align: center;
@@ -56,7 +66,7 @@ BUTTON.whiteButton {
background-color: #CCC;
color: black;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-size: x-small;
font-weight: bold;
width: 60px;
height: 40px;
@@ -68,7 +78,7 @@ BUTTON.blackButton {
background-color: black;
color: white;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-size: x-small;
font-weight: bold;
width: 60px;
height: 40px;
@@ -80,7 +90,7 @@ BUTTON.yellowButton {
background-color: #990;
color: black;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-size: x-small;
font-weight: bold;
width: 60px;
height: 40px;
@@ -92,72 +102,81 @@ BUTTON.whiteLit {
BUTTON.yellowLit {
background-color: #FFFF00}
BUTTON.blackBorder {
border: 1px solid black}
BUTTON.yellowBorder {
border: 2px solid yellow}
BUTTON.silverBorder {
border: 1px solid #DDD}
BUTTON#HaltBtn {
top: 31px;
left: 32px}
BUTTON#NotReadyBtn {
top: 31px;
left: 132px}
BUTTON#LoadSelectBtn {
top: 31px;
left: 202px}
BUTTON#LoadBtn {
top: 31px;
left: 272px}
BUTTON#MemoryCheckBtn {
top: 31px;
left: 372px}
BUTTON#ANormalBtn {
top: 31px;
left: 442px}
BUTTON#AControlBtn {
top: 31px;
left: 512px}
BUTTON#BNormalBtn {
top: 31px;
left: 582px}
BUTTON#BControlBtn {
top: 31px;
left: 652px}
BUTTON#PowerOnBtn {
top: 31px;
left: 752px}
BUTTON#PowerOffBtn {
top: 31px;
left: 822px}
TABLE#CentralControl {
position: absolute;
bottom: 0;
color: #666;
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
font-size: 10px;
font-size: x-small;
font-weight: bold}
COL.AnnunciatorCol {
width: 2.9%}
TD#procRate, TD#procSlack {
color: white;
text-align: right}
.busy {
color: white}
.idle {
color: #666}
.center {
text-align: center}

View File

@@ -1,6 +1,6 @@
<!DOCTYPE html>
<head>
<title>B5500 Emulator Operator Console</title>
<title>retro-B5500 Emulator Operator Console</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta name="Author" content="Nigel Williams & Paul Kimpel">
<meta http-equiv="Content-Script-Type" content="text/javascript">
@@ -11,6 +11,8 @@
<script src="./B5500SPOUnit.js"></script>
<script src="./B5500DiskUnit.js"></script>
<script src="./B5500CardReader.js"></script>
<script src="./B5500CardPunch.js"></script>
<script src="./B5500DummyPrinter.js"></script>
<script src="../emulator/B5500SystemConfiguration.js"></script>
<script src="../emulator/B5500CentralControl.js"></script>
@@ -18,15 +20,22 @@
<script src="../emulator/B5500IOUnit.js"></script>
<script>
window.onload = function() {
window.addEventListener("load", function() {
var aControl;
var aNormal;
var bControl;
var bNormal;
var boundBlinkenlicht;
var cc = new B5500CentralControl();
var lastBusyMask = 0;
var procRate;
var intLightsMap = new Array(48);
var iouLightsMap = new Array(4);
var lastInterruptMask = 0;
var lastIOUMask = 0;
var lastUnitBusyMask = 0;
var lastPAState = -1;
var lastPBState = -1;
var perLightsMap = new Array(48);
var procRate;
var procSlack;
var timer;
var timerInterval = 50; // milliseconds
@@ -43,7 +52,11 @@ window.onload = function() {
$$("PowerOnBtn").className = "whiteButton whiteLit";
$$("AControlBtn").className = "yellowButton yellowLit";
cc.powerOn();
$$("PowerOnBtn").disabled = true;
$$("PowerOffBtn").disabled = false;
$$("LoadBtn").disabled = false;
$$("HaltBtn").disabled = true;
window.focus();
return true;
}
@@ -53,6 +66,8 @@ window.onload = function() {
$$("AControlBtn").className = "yellowButton";
$$("BNormalBtn").className = "yellowButton";
cc.powerOff();
$$("PowerOnBtn").disabled = false;
$$("PowerOffBtn").disabled = true;
$$("HaltBtn").disabled = true;
$$("LoadBtn").disabled = true;
if (timer) {
@@ -69,40 +84,70 @@ window.onload = function() {
}
function LoadBtn_Click(ev) {
cc.load();
cc.load(false);
$$("HaltBtn").disabled = false;
$$("LoadBtn").disabled = true;
boundBlinkenlicht();
}
function LoadSelectBtn_Click(ev) {
if (cc.cardLoadSelect) {
cc.cardLoadSelect = 0;
$$("LoadSelectBtn").className = "blackButton silverBorder";
} else {
cc.cardLoadSelect = 1;
$$("LoadSelectBtn").className = "blackButton yellowBorder";
}
}
function displayCentralControl() {
/* Displays the I/O and interrupt status in Central Control */
var cells;
var s;
var busyMask = cc.unitBusyMask;
var busyChange = lastBusyMask ^ busyMask;
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 x;
lastBusyMask = busyMask;
lastInterruptMask = interruptMask;
lastIOUMask = iouMask;
lastUnitBusyMask = unitBusyMask;
$$("AD1F").className = (cc.AD1F ? "busy" : "");
$$("AD2F").className = (cc.AD2F ? "busy" : "");
$$("AD3F").className = (cc.AD3F ? "busy" : "");
$$("AD4F").className = (cc.AD4F ? "busy" : "");
for (x=3; x<=16; x++) {
s = "CCI" + (x+100).toString().substring(1) + "F";
$$(s).className = (cc[s] ? "busy" : "");
x = 0;
while (iouChange) {
if (iouChange & 0x01) {
iouLightsMap[x].className = (iouMask & 0x01 ? "busy" : "");
}
iouMask >>>= 1;
iouChange >>>= 1;
x++;
}
cells = $$("CCPeripheralRow").cells;
x = 47;
while (busyChange) {
if (busyChange & 0x01) {
cells[x-17].className = (busyMask & 0x01 ? "busy" : "");
while (interruptChange) {
if (interruptChange & 0x01) {
intLightsMap[x].className = (interruptMask & 0x01 ? "busy" : "");
}
busyMask >>>= 1;
busyChange >>>= 1;
interruptMask >>>= 1;
interruptChange >>>= 1;
x--;
}
x = 47;
while (unitBusyChange) {
if (unitBusyChange & 0x01) {
perLightsMap[x].className = (unitBusyMask & 0x01 ? "busy" : "");
}
unitBusyMask >>>= 1;
unitBusyChange >>>= 1;
x--;
}
}
@@ -114,32 +159,44 @@ window.onload = function() {
if (pa) {
if (!pa.busy) {
aControl.className = "yellowButton";
aNormal.className = "yellowButton";
} else if (pa.NCSF) {
aControl.className = "yellowButton";
aNormal.className = "yellowButton yellowLit";
} else {
aNormal.className = "yellowButton";
if (pa === cc.P1) {
aControl.className = "yellowButton yellowLit";
if (lastPAState != -1) {
aControl.className = "yellowButton";
aNormal.className = "yellowButton";
lastPAState = -1;
}
} else if (pa.NCSF != lastPAState) {
lastPAState = pa.NCSF;
if (lastPAState) {
aControl.className = "yellowButton";
aNormal.className = "yellowButton yellowLit";
} else {
aNormal.className = "yellowButton";
if (pa === cc.P1) {
aControl.className = "yellowButton yellowLit";
}
}
et = new Date().getTime() - pa.procStart;
procRate.innerHTML = (pa.procTime/et*100).toFixed(1) + "%";
procSlack.innerHTML = (pa.procSlack/et*100).toFixed(1) + "%";
}
et = new Date().getTime()*1000 - pa.procStart;
procRate.innerHTML = ((pa.procTime - pa.procStart)/et*100).toFixed(1) + "%";
//procSlack.innerHTML = (pa.procSlack/et*100).toFixed(1) + "%";
}
}
if (pb) {
if (!pb.busy) {
bControl.className = "yellowButton";
bNormal.className = "yellowButton";
} else if (pb.NCSF) {
bControl.className = "yellowButton";
bNormal.className = "yellowButton yellowLit";
} else {
bNormal.className = "yellowButton";
if (pb === cc.P1) {
bControl.className = "yellowButton yellowLit";
if (lastPBState != -1) {
bControl.className = "yellowButton";
bNormal.className = "yellowButton";
lastPBState = -1;
}
} else if (pb.NCSF != lastPBState) {
lastPBState = pb.NCSF;
if (lastPBState) {
bControl.className = "yellowButton";
bNormal.className = "yellowButton yellowLit";
} else {
bNormal.className = "yellowButton";
if (pb === cc.P1) {
bControl.className = "yellowButton yellowLit";
}
}
}
}
@@ -168,13 +225,36 @@ window.onload = function() {
}
}
function buildLightMaps() {
/* Builds tables of the DOM entries for the annunciator lights, for efficient access */
var mnem;
var spec;
var x;
iouLightsMap[0] = $$("AD1F");
iouLightsMap[1] = $$("AD2F");
iouLightsMap[2] = $$("AD3F");
iouLightsMap[3] = $$("AD4F");
for (x=3; x<=16; x++) {
intLightsMap[50-x] = $$("CCI" + (x+100).toString().substring(1) + "F");
}
for (mnem in B5500CentralControl.unitSpecs) {
spec = B5500CentralControl.unitSpecs[mnem];
perLightsMap[spec.unitIndex] = $$(mnem);
}
}
/***** window.onload() outer block *****/
$$("RetroVersion").innerHTML = B5500CentralControl.version;
if (!checkBrowser()) {
$$("PowerOnBtn").addEventListener("click", PowerOnBtn_Click);
$$("PowerOffBtn").addEventListener("click", PowerOffBtn_Click);
$$("HaltBtn").addEventListener("click", HaltBtn_Click);
$$("LoadBtn").addEventListener("click", LoadBtn_Click);
$$("LoadSelectBtn").addEventListener("click", LoadSelectBtn_Click);
aControl = $$("AControlBtn");
aNormal = $$("ANormalBtn");
@@ -183,8 +263,9 @@ window.onload = function() {
procRate = $$("procRate");
procSlack = $$("procSlack");
boundBlinkenlicht = bindMethod(dasBlinkenlicht, this);
buildLightMaps();
}
};
}, false);
</script>
</head>
@@ -194,7 +275,7 @@ window.onload = function() {
<button id=HaltBtn class=blackButton DISABLED>HALT</button>
<button id=NotReadyBtn class=yellowButton>NOT READY</button>
<button id=LoadSelectBtn class=blackButton>LOAD SELECT</button>
<button id=LoadSelectBtn class="blackButton silverBorder">LOAD SELECT</button>
<button id=LoadBtn class=blackButton DISABLED>LOAD</button>
<button id=MemoryCheckBtn class=yellowButton>MEMORY CHECK</button>
@@ -204,18 +285,24 @@ window.onload = function() {
<button id=BControlBtn class=yellowButton>B CONTROL</button>
<button id=PowerOnBtn class=whiteButton>POWER<br>ON</button>
<button id=PowerOffBtn class=blackButton>POWER OFF</button>
<button id=PowerOffBtn class=blackButton DISABLED>POWER OFF</button>
<div id=BurroughsLogo>
<img id=BurroughsLogoImage src="Burroughs-Logo-Neg.jpg">
<img id=BurroughsLogoImage src="Burroughs-Logo-Neg.jpg" alt="Burroughs logo">
</div>
<div id=RetroVersion>
?.??
</div>
<div id=B5500Logo>
<img src="retro-B5500-Logo.png" alt="retro-B5500 logo"><!-- B 5500 -->
</div>
<div id=B5500Logo><img src="retro-B5500-Logo.png" alt="retro-B5500 logo"><!-- B 5500 --></div>
<table id=CentralControl>
<colgroup>
<col span=32 style="width:3%">
<col span=32 class=AnnunciatorCol>
<col>
</colgroup>
<thead>
<tbody>
<tr id=CCInterruptRow>
<td id=AD1F>IOU1 <!-- I/O unit 1 busy -->
<td id=AD2F>IOU2 <!-- I/O unit 2 busy -->
@@ -237,6 +324,7 @@ window.onload = function() {
<td id=CCI16F>DK2F <!-- Disk file #2 read check finished -->
<td colspan=13>
<td id=procSlack>
<td class=busy>PA Slack
<tr id=CCPeripheralRow>
<td id=DCA>DCA <!-- 17 -->
<td id=PPB>PPB <!-- 18 -->
@@ -253,23 +341,24 @@ window.onload = function() {
<td id=DKA>DKA <!-- 29 -->
<td id=DRB>DRB <!-- 30 -->
<td id=DRA>DRA <!-- 31 -->
<td id=MTT>MTT <!-- 32 -->
<td id=MTS>MTS <!-- 33 -->
<td id=MTR>MTR <!-- 34 -->
<td id=MTP>MTP <!-- 35 -->
<td id=MTN>MTN <!-- 36 -->
<td id=MTM>MTM <!-- 37 -->
<td id=MTL>MTL <!-- 38 -->
<td id=MTK>MTK <!-- 39 -->
<td id=MTJ>MTJ <!-- 40 -->
<td id=MTH>MTH <!-- 41 -->
<td id=MTF>MTF <!-- 42 -->
<td id=MTE>MTE <!-- 43 -->
<td id=MTD>MTD <!-- 44 -->
<td id=MTC>MTC <!-- 45 -->
<td id=MTB>MTB <!-- 46 -->
<td id=MTA>MTA <!-- 47 -->
<td id=MTB>MTB <!-- 46 -->
<td id=MTC>MTC <!-- 45 -->
<td id=MTD>MTD <!-- 44 -->
<td id=MTE>MTE <!-- 43 -->
<td id=MTF>MTF <!-- 42 -->
<td id=MTH>MTH <!-- 41 -->
<td id=MTJ>MTJ <!-- 40 -->
<td id=MTK>MTK <!-- 39 -->
<td id=MTL>MTL <!-- 38 -->
<td id=MTM>MTM <!-- 37 -->
<td id=MTN>MTN <!-- 36 -->
<td id=MTP>MTP <!-- 35 -->
<td id=MTR>MTR <!-- 34 -->
<td id=MTS>MTS <!-- 33 -->
<td id=MTT>MTT <!-- 32 -->
<td id=procRate>
<td class=busy>PA Rate
</table>
</div>

View File

@@ -18,16 +18,17 @@
*
* The database consists of a CONFIG object store and some number of EUn object
* stores, where n is in 0..9. The CONFIG store contains an "eus" member that
* specifies the total number of EU objects, plus an "EUn" member that specicies
* specifies the total number of EU objects, plus an "EUn" member that specifies
* the size of that EU in 240-character segments. There may be gaps in the EU
* numbering.
* numbering, but the EU sizes should be specified in increments of 40,000 up to
* a maximum of 200,000 (for Model I) or 400,000 (for Model IB "slow" disks).
*
* Within an EU, segments are represented in the database as 240-byte Uint8Array
* objects, each with a database key corresponding to its numeric segment address.
* The segments are an EU are not pre-allocated, but are created as they are
* The segments in an EU are not pre-allocated, but are created as they are
* written to by IDB put() methods. When reading, any unallocated segments are
* returned with their bytes set to binary zero, which will be translated to
* BIC "?" by the IOU for both binary and alpha modes.
* returned with their bytes set to 0x23 (#), which will be translated by the
* IOU to BIC "0" for alpha mode and BIC "#" for binary mode.
*
* At present, disk write lockout is not supported. When there are two DFCUs in
* the system, the presence of a Disk File Exchange is assumed, allowing either
@@ -88,7 +89,7 @@ B5500DiskUnit.prototype.charXferRate = 96000; // avg. transfer rate, char
B5500DiskUnit.prototype.maxLatency = 0.040; // max rotational latency, sec (Model I SU)
/**************************************/
B5500DiskUnit.prototype.clear = function() {
B5500DiskUnit.prototype.clear = function clear() {
/* Initializes (and if necessary, creates) the processor state */
this.ready = false; // ready status
@@ -106,7 +107,7 @@ B5500DiskUnit.prototype.clear = function() {
};
/**************************************/
B5500DiskUnit.genericDBError = function(ev) {
B5500DiskUnit.genericDBError = function genericDBError(ev) {
/* Formats a generic alert when otherwise-unhandled database errors occur */
var disk = ev.currentTarget.result;
@@ -117,7 +118,7 @@ B5500DiskUnit.genericDBError = function(ev) {
};
/**************************************/
B5500DiskUnit.prototype.copySegment = function(seg, buffer, offset) {
B5500DiskUnit.prototype.copySegment = function copySegment(seg, buffer, offset) {
/* Copies the bytes from a single segment Uint8Array object to "buffer" starting
at "offset" for 240 bytes. If "seg" is undefined, copies zero bytes instead */
var x;
@@ -134,7 +135,7 @@ B5500DiskUnit.prototype.copySegment = function(seg, buffer, offset) {
};
/**************************************/
B5500DiskUnit.prototype.openDatabase = function() {
B5500DiskUnit.prototype.openDatabase = function openDataBase() {
/* Attempts to open the disk subsystem database specified by this.dbName and
this.dbVersion. If successful, sets this.disk to the IDB object and sets the
DFCU to ready status */
@@ -143,31 +144,31 @@ B5500DiskUnit.prototype.openDatabase = function() {
var that = this;
that.statusChange(0); // initially force DFCU status to not ready
req = window.indexedDB.open(that.dbName, that.dbVersion);
req = indexedDB.open(that.dbName, that.dbVersion);
req.onerror = function(ev) {
req.onerror = function idbOpenOnerror(ev) {
alert("Cannot open " + that.mnemonic + " database: " + ev.target.error);
};
req.onblocked = function(ev) {
req.onblocked = function idbOpenOnblocked(ev) {
alert("Database.open is blocked -- cannot continue");
};
req.onupgradeneeded = function(ev) {
req.onupgradeneeded = function idbOpenOnupgradeneeded(ev) {
alert("Database requires version upgrade -- cannot continue");
};
req.onsuccess = function(ev) {
req.onsuccess = function idbOpenOnsuccess(ev) {
that.disk = ev.target.result; // save the object reference globally for later use
that.disk.onerror = function(ev) {
alert("Database for \"" + this.mnemonic + "\" open error: " + ev.target.result.error);
that.disk.onerror = function idbCONFIGGetOnerror(ev) {
alert("Database for \"" + that.mnemonic + "\" CONFIG get error: " + ev.target.result.error);
};
that.disk.transaction("CONFIG").objectStore("CONFIG").get(0).onsuccess = function(ev) {
that.disk.transaction("CONFIG").objectStore("CONFIG").get(0).onsuccess = function idbCONFIGGetOnsuccess(ev) {
that.config = ev.target.result;
that.statusChange(1); // report the DFCU as ready to Central Control
// Set up the generic error handler
that.disk.onerror = function(ev) {
that.disk.onerror = function idbGenericOnError(ev) {
that.genericIDBError(ev);
};
};
@@ -175,7 +176,7 @@ B5500DiskUnit.prototype.openDatabase = function() {
};
/**************************************/
B5500DiskUnit.prototype.read = function(finish, buffer, length, mode, control) {
B5500DiskUnit.prototype.read = function read(finish, buffer, length, mode, control) {
/* Initiates a read operation on the unit. "length" is in characters; segment address
is in "control". "mode" is ignored (any translation would have been done by IOU) */
var bx = 0; // current buffer offset
@@ -215,19 +216,19 @@ B5500DiskUnit.prototype.read = function(finish, buffer, length, mode, control) {
this.errorMask = 0;
} else if (segs < 2) { // A single-segment read
req = this.disk.transaction(euName).objectStore(euName).get(segAddr);
req.onsuccess = function(ev) {
req.onsuccess = function singleReadOnsuccess(ev) {
that.copySegment(ev.target.result, buffer, 0);
setTimeout(function() {
setTimeout(function singleReadTimeout() {
finish(that.errorMask, length);
that.errorMask = 0;
}, finishTime - new Date().getTime());
}
} else { // A multi-segment read
range = window.IDBKeyRange.bound(segAddr, endAddr);
range = IDBKeyRange.bound(segAddr, endAddr);
txn = this.disk.transaction(euName);
req = txn.objectStore(euName).openCursor(range);
req.onsuccess = function(ev) {
req.onsuccess = function rangeReadOnsuccess(ev) {
var cursor = ev.target.result;
if (cursor) { // found a segment at some address in range
@@ -249,7 +250,7 @@ B5500DiskUnit.prototype.read = function(finish, buffer, length, mode, control) {
bx += 240;
segAddr++;
}
setTimeout(function() {
setTimeout(function rangeReadTimeout() {
finish(that.errorMask, length);
that.errorMask = 0;
}, finishTime - new Date().getTime());
@@ -260,14 +261,14 @@ B5500DiskUnit.prototype.read = function(finish, buffer, length, mode, control) {
};
/**************************************/
B5500DiskUnit.prototype.space = function(finish, length, control) {
B5500DiskUnit.prototype.space = function space(finish, length, control) {
/* Initiates a space operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DiskUnit.prototype.write = function(finish, buffer, length, mode, control) {
B5500DiskUnit.prototype.write = function write(finish, buffer, length, mode, control) {
/* Initiates a write operation on the unit. "length" is in characters; segment address
is in "control". "mode" is ignored (any translation will done by the IOU) */
var bx = 0; // current buffer offset
@@ -310,8 +311,8 @@ B5500DiskUnit.prototype.write = function(finish, buffer, length, mode, control)
// Do the write
} else {
txn = this.disk.transaction(euName, "readwrite")
txn.oncomplete = function(ev) {
setTimeout(function() {
txn.oncomplete = function writeComplete(ev) {
setTimeout(function writeTimeout() {
finish(that.errorMask, length);
that.errorMask = 0;
}, finishTime - new Date().getTime());
@@ -326,21 +327,21 @@ B5500DiskUnit.prototype.write = function(finish, buffer, length, mode, control)
};
/**************************************/
B5500DiskUnit.prototype.erase = function(finish, length) {
B5500DiskUnit.prototype.erase = function erase(finish, length) {
/* Initiates an erase operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DiskUnit.prototype.rewind = function(finish) {
B5500DiskUnit.prototype.rewind = function rewind(finish) {
/* Initiates a rewind operation on the unit */
finish(0x04, 0); // report unit not ready
};
/**************************************/
B5500DiskUnit.prototype.readCheck = function(finish, length, control) {
B5500DiskUnit.prototype.readCheck = function readCheck(finish, length, control) {
/* Initiates a read check operation on the unit. "length" is in characters;
segment address is in "control". "mode" is ignored. This is essentially a
read without any data transfer to memory. Note that the errorMask is NOT
@@ -384,18 +385,18 @@ B5500DiskUnit.prototype.readCheck = function(finish, length, control) {
this.signal();
// DO NOT clear the error mask -- will return it on the next interrogate
} else { // A multi-segment read
range = window.IDBKeyRange.bound(segAddr, endAddr);
range = IDBKeyRange.bound(segAddr, endAddr);
txn = this.disk.transaction(euName);
finish(that.errorMask, length); // post I/O complete now -- DFCU will signal when check finished
req = txn.objectStore(euName).openCursor(range);
req.onsuccess = function(ev) {
req.onsuccess = function readCheckOnsuccess(ev) {
var cursor = ev.target.result;
if (cursor) { // found a segment at some address in range
cursor.continue();
} else { // at end of range
setTimeout(function() {
setTimeout(function readCheckTimeout() {
that.signal();
// DO NOT clear the error mask
}, finishTime - new Date().getTime());
@@ -406,7 +407,7 @@ B5500DiskUnit.prototype.readCheck = function(finish, length, control) {
};
/**************************************/
B5500DiskUnit.prototype.readInterrogate = function(finish, control) {
B5500DiskUnit.prototype.readInterrogate = function readInterrogate(finish, control) {
/* Initiates a read interrogate operation on the unit. This serves only to
check the addresss for validity and to return any errorMask from a prior
read check operation. This implementation assumes completion will be delayed
@@ -427,7 +428,7 @@ B5500DiskUnit.prototype.readInterrogate = function(finish, control) {
if (segAddr < 0 || segAddr >= euSize) { // if read is past end of disk
this.errorMask |= 0x20; // set D27F for invalid seg address
}
setTimeout(function() {
setTimeout(function readInterrogateTimeout() {
finish(that.errorMask, length);
that.errorMask = 0;
}, Math.random()*this.maxLatency*1000);
@@ -435,7 +436,7 @@ B5500DiskUnit.prototype.readInterrogate = function(finish, control) {
};
/**************************************/
B5500DiskUnit.prototype.writeInterrogate = function (finish, control) {
B5500DiskUnit.prototype.writeInterrogate = function writeInterrogate(finish, control) {
/* Initiates a write interrogate operation on the unit. This serves only to
check the addresss for validity and to return any errorMask from a prior
read check operation. This implementation assumes completion will be delayed
@@ -460,7 +461,7 @@ B5500DiskUnit.prototype.writeInterrogate = function (finish, control) {
if (segAddr < 0 || segAddr >= euSize) { // if read is past end of disk
this.errorMask |= 0x20; // set D27F for invalid seg address
}
setTimeout(function() {
setTimeout(function writeInterrogateTimeout() {
finish(that.errorMask, length);
that.errorMask = 0;
}, Math.random()*this.maxLatency*1000);

View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<head>
<title>B5500 Emulator SPO Unit</title>
<meta name="Author" content="Nigel Williams & Paul Kimpel">
<!-- 2012-12-16 Original version, cloned from SPO prototype script -->
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<meta http-equiv="Content-Style-Type" content="text/css">
<link id=defaultStyleSheet rel=stylesheet type="text/css" href="B5500SPOUnit.css">
</head>
<body>
<div id=SPODiv>
<iframe id=SPOUT scrolling=auto></iframe>
<div id=SPOControlsDiv>
<img id=TeletypeLogo src="TeletypeLogo.gif">
<button id=SPOReadyBtn class="yellowButton blackBorder">READY</button>
<button id=SPOPowerBtn class="blackButton blackBorder">POWER</button>
<button id=SPORemoteBtn class="yellowButton blackBorder">REMOTE</button>
<button id=SPOLocalBtn class="yellowButton blackBorder">LOCAL</button>
<button id=SPOInputRequestBtn class="yellowButton blackBorder">INPUT REQUEST</button>
<button id=SPOEndOfMessageBtn class="yellowButton blackBorder">END OF MESSAGE</button>
<button id=SPOBlank1Btn class="yellowButton blackBorder"></button>
<button id=SPOErrorBtn class="yellowButton blackBorder">ERROR</button>
<button id=SPOBlank2Btn class="yellowButton blackBorder"></button>
<button id=SPOBlank3Btn class="yellowButton blackBorder"></button>
</div>
</div>
</body>
</html>

180
webUI/B5500DummyPrinter.js Normal file
View File

@@ -0,0 +1,180 @@
/***********************************************************************
* retro-b5500/emulator B5500DummyPrinter.js
************************************************************************
* Copyright (c) 2013, Nigel Williams and Paul Kimpel.
* Licensed under the MIT License, see
* http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B5500 (DUMMY) Line Printer Peripheral Unit module.
*
* Defines a Line Printer peripheral unit type. Journals all output to
* console.log() as well as the pritner window.
*
************************************************************************
* 2013-06-11 P.Kimpel
* Original version, from B5500SPOUnit.js.
***********************************************************************/
"use strict";
/**************************************/
function B5500DummyPrinter(mnemonic, unitIndex, designate, statusChange, signal) {
/* Constructor for the DummyPrinter object */
var that = this;
this.mnemonic = mnemonic; // Unit mnemonic
this.unitIndex = unitIndex; // Ready-mask bit number
this.designate = designate; // IOD unit designate number
this.statusChange = statusChange; // external function to call for ready-status change
this.signal = signal; // external function to call for special signals (e.g,. Printer Finished)
this.clear();
this.window = window.open("", mnemonic);
if (this.window) {
this.window.close(); // destroy the previously-existing window
this.window = null;
}
this.doc = null;
this.paper = null;
this.endOfPaper = null;
this.window = window.open("/B5500/webUI/B5500DummyPrinter.html", mnemonic,
"scrollbars,resizable,width=600,height=500");
this.window.addEventListener("load", function() {
that.printerOnload();
}, false);
}
B5500DummyPrinter.prototype.linesPerMinute = 800; // Printer speed
B5500DummyPrinter.maxScrollLines = 150000; // Maximum printer scrollback (about a box of paper)
/**************************************/
B5500DummyPrinter.prototype.$$ = function $$(e) {
return this.doc.getElementById(e);
};
/**************************************/
B5500DummyPrinter.prototype.clear = function clear() {
/* Initializes (and if necessary, creates) the printer unit state */
this.ready = false; // ready status
this.busy = false; // busy status
this.activeIOUnit = 0; // I/O unit currently using this device
this.errorMask = 0; // error mask for finish()
this.finish = null; // external function to call for I/O completion
};
/**************************************/
B5500DummyPrinter.prototype.printerOnload = function printerOnload() {
/* Initializes the line printer window and user interface */
var that = this;
this.doc = this.window.document;
this.doc.title = "retro-B5500 " + this.mnemonic;
this.paper = this.doc.createElement("pre");
this.doc.body.appendChild(this.paper);
this.endOfPaper = this.doc.createElement("div");
this.doc.body.appendChild(this.endOfPaper);
this.window.moveTo(40, 40);
this.window.resizeTo(1000, screen.availHeight*0.80);
this.statusChange(1);
};
/**************************************/
B5500DummyPrinter.prototype.appendLine = function appendLine(text) {
/* Removes excess lines already printed, then appends a new <pre> element
to the <iframe>, creating an empty text node inside the new element */
var count = this.paper.childNodes.length;
var line = this.doc.createTextNode(text || "");
while (count-- > this.maxScrollLines) {
this.paper.removeChild(this.paper.firstChild);
}
this.paper.appendChild(line);
};
/**************************************/
B5500DummyPrinter.prototype.read = function read(finish, buffer, length, mode, control) {
/* Initiates a read operation on the unit */
console.log("READ: L=" + length + ", M=" + mode + ", C=" + control + " : " +
String.fromCharCode.apply(null, buffer.subarray(0, length)));
finish(0x04, 0);
};
/**************************************/
B5500DummyPrinter.prototype.space = function space(finish, length, control) {
/* Initiates a space operation on the unit */
console.log("SPACE: L=" + length + ", M=" + mode + ", C=" + control + " : " +
String.fromCharCode.apply(null, buffer.subarray(0, length)));
finish(0x04, 0);
};
/**************************************/
B5500DummyPrinter.prototype.write = function write(finish, buffer, length, mode, control) {
/* Initiates a write operation on the unit */
var text;
var that = this;
this.errorMask = 0;
text = String.fromCharCode.apply(null, buffer.subarray(0, length));
//console.log("WRITE: L=" + length + ", M=" + mode + ", C=" + control + " : " + text);
this.appendLine(text + "\n");
if (control > 1) {
this.appendLine("\n");
} else if (control < 0) {
this.paper.appendChild(this.doc.createElement("hr"));
}
setTimeout(this.signal, 60000/this.linesPerMinute);
finish(0, 0);
this.endOfPaper.scrollIntoView();
};
/**************************************/
B5500DummyPrinter.prototype.erase = function erase(finish, length) {
/* Initiates an erase operation on the unit */
console.log("ERASE: L=" + length + ", M=" + mode + ", C=" + control + " : " +
String.fromCharCode.apply(null, buffer.subarray(0, length)));
finish(0x04, 0);
};
/**************************************/
B5500DummyPrinter.prototype.rewind = function rewind(finish) {
/* Initiates a rewind operation on the unit */
console.log("REWIND: L=" + length + ", M=" + mode + ", C=" + control + " : " +
String.fromCharCode.apply(null, buffer.subarray(0, length)));
finish(0x04, 0);
};
/**************************************/
B5500DummyPrinter.prototype.readCheck = function readCheck(finish, length, control) {
/* Initiates a read check operation on the unit */
console.log("READCK: L=" + length + ", M=" + mode + ", C=" + control + " : " +
String.fromCharCode.apply(null, buffer.subarray(0, length)));
finish(0x04, 0);
};
/**************************************/
B5500DummyPrinter.prototype.readInterrogate = function readInterrogate(finish, control) {
/* Initiates a read interrogate operation on the unit */
console.log("READIG: L=" + length + ", M=" + mode + ", C=" + control + " : " +
String.fromCharCode.apply(null, buffer.subarray(0, length)));
finish(0x04, 0);
};
/**************************************/
B5500DummyPrinter.prototype.writeInterrogate = function writeInterrogate(finish, control) {
/* Initiates a write interrogate operation on the unit */
console.log("WRITEG: L=" + length + ", M=" + mode + ", C=" + control + " : " +
String.fromCharCode.apply(null, buffer.subarray(0, length)));
finish(0x04, 0);
};

View File

@@ -24,7 +24,7 @@ PRE {
DIV#SPODiv {
position: relative;
width: 800px;
background-color: #FDA;
background-color: #F0D0A0;
border-radius: 32px;
padding: 2em;
text-align: left}

View File

@@ -42,10 +42,13 @@ function B5500SPOUnit(mnemonic, unitIndex, designate, statusChange, signal) {
this.window = null;
}
this.doc = null;
this.window = window.open("/B5500/webUI/B5500SPOUnit.html", mnemonic, "scrollbars,resizable,width=600,height=500");
this.window.onload = function() {
this.paper = null;
this.endOfPaper = null;
this.window = window.open("/B5500/webUI/B5500SPOUnit.html", mnemonic,
"scrollbars,resizable,width=600,height=500");
this.window.addEventListener("load", function() {
that.spoOnload();
};
}, false);
}
// this.spoState enumerations
@@ -178,21 +181,20 @@ B5500SPOUnit.prototype.appendEmptyLine = function appendEmptyLine() {
/* Removes excess lines already printed, then appends a new <pre> element
to the <iframe>, creating an empty text node inside the new element */
var count = this.paper.childNodes.length;
var line = document.createElement("pre");
var line = this.doc.createTextNode("");
this.printChar(0x0A); // newline
while (count-- > this.maxScrollLines) {
this.paper.removeChild(this.paper.firstChild);
}
line.appendChild(document.createTextNode(""));
this.paper.appendChild(line);
line.scrollIntoView();
};
/**************************************/
B5500SPOUnit.prototype.backspaceChar = function backspaceChar() {
/* Handles backspace for SPO input */
var that = backspaceChar.that;
var line = that.paper.lastChild.lastChild;
var line = that.paper.lastChild;
if (that.bufLength > 0) {
that.bufIndex--;
@@ -209,9 +211,13 @@ B5500SPOUnit.prototype.backspaceChar = function backspaceChar() {
B5500SPOUnit.prototype.printChar = function printChar(c) {
/* Echoes the character code "c" to the SPO printer */
var that = printChar.that;
var line = that.paper.lastChild.lastChild;
var line = that.paper.lastChild;
var len = line.nodeValue.length;
if (line.nodeValue.length < 72) {
if (len < 1) {
line.nodeValue = String.fromCharCode(c);
that.endOfPaper.scrollIntoView();
} else if (len < 72) {
line.nodeValue += String.fromCharCode(c);
} else {
line.nodeValue = line.nodeValue.substring(0, 71) + String.fromCharCode(c);
@@ -422,7 +428,12 @@ B5500SPOUnit.prototype.spoOnload = function spoOnload() {
this.doc = this.window.document;
this.doc.title = "retro-B5500 " + this.mnemonic;
this.paper = this.$$("SPOUT").contentDocument.body;
this.paper = this.doc.createElement("pre");
this.paper.appendChild(this.doc.createTextNode(""));
this.$$("SPOUT").contentDocument.body.appendChild(this.paper);
this.endOfPaper = this.doc.createElement("div");
//this.endOfPaper.appendChild(this.doc.createTextNode("\xA0"));
this.$$("SPOUT").contentDocument.body.appendChild(this.endOfPaper);
this.$$("SPOUT").contentDocument.head.innerHTML += "<style>" +
"BODY {background-color: #FFE} " +
"PRE {margin: 0; font-size: 10pt; font-family: Lucida Sans Typewriter, Courier New, Courier, monospace}" +
@@ -475,6 +486,7 @@ B5500SPOUnit.prototype.spoOnload = function spoOnload() {
this.appendEmptyLine();
}
this.setReady();
this.window.focus();
this.printText("retro-B5500 Emulator Version " + B5500CentralControl.version, function() {
that.setRemote();
that.appendEmptyLine();

View File

@@ -10,7 +10,9 @@
<script src="/B5500/webUI/B5500DummyUnit.js"></script>
<script src="/B5500/webUI/B5500SPOUnit.js"></script>
<script src="/B5500/webUI/B5500DiskUnit.js"></script>
<script src="./B5500CardReader.js"></script>
<script src="/B5500/webUI/B5500CardReader.js"></script>
<script src="/B5500/webUI/B5500CardPunch.js"></script>
<script src="/B5500/webUI/B5500DummyPrinter.js"></script>
<script src="/B5500/emulator/B5500SystemConfiguration.js"></script>
<script src="/B5500/emulator/B5500CentralControl.js"></script>
@@ -876,6 +878,7 @@ function hardwareLoad_onClick(ev) {
cc.clear();
cc.P1.clear();
cc.cardLoadSelect = $$("CardLoadSelect").checked;
cc.load(true);
}
@@ -1101,6 +1104,8 @@ window.onload = function() {
<input id=FileSelector type=file size=60>
&nbsp;&nbsp;
<input id=HardwareLoad type=button value="Hardware Load">
<input id=CardLoadSelect type=checkbox value="CardLoadSelect">
<label for=CardLoadSelect>Card Load Select</label>
</p>
<table id=RegisterBank1 class="normal border">

View File

@@ -9,6 +9,10 @@
<style>
BODY {
position: relative;
margin: 1ex}
BUTTON.greenButton {
background-color: #060;
color: white;
@@ -49,10 +53,13 @@ BUTTON.redLit {
background-color: #F00}
#CardReaderPanel {
position: relative;
position: absolute;
top: 30px;
left: 1ex;
color: white;
background-color: #666;
width: 280px;
height: 112px;
width: 700px;
height: 150px;
border: 1px solid black;
border-radius: 8px;
padding: 0;
@@ -82,24 +89,43 @@ BUTTON.redLit {
position: absolute;
top: 56px;
left: 8px;
width: 120px}
width: 100%;
border: 1px solid white}
#CRProgressBar {
position: absolute;
top: 84px;
left: 8px;
width: 262px}
width: 680px;
border: 1px solid white}
#CROutHopperFrame {
position: absolute;
top: 106px;
left: 8px;
width: 680px;
height: 32px;
margin-top: 1px;
border: 1px solid white;
color: black;
background-color: white;
font-family: Lucida Sans Typewriter, Courier New, Courier, monospace;
font-size: 8pt;
font-weight: normal}
</style>
<script>
"use strict";
window.onload = function() {
window.addEventListener("load", function() {
var buffer = "";
var bufferLength = 0;
var bufferOffset = 0;
var eofArmed = 0;
var panel = $$("TextPanel");
var outHopperFrame = $$("CROutHopperFrame");
var outHopper;
//var endOfOutHopper;
var eolRex = /([^\n\r\f]*)((:?\r[\n\f]?)|\n|\f)?/g;
var blankCard = " "; // 80 spaces
@@ -141,14 +167,14 @@ window.onload = function() {
e.className = e.className.replace(new RegExp("\\b" + name + "\\b\\s*", "g"), "");
}
function appendLine(panel, text) {
function appendLine(text) {
/* Appends "text"+NL as a new text node to the panel DOM element */
var e = document.createTextNode(text + "\n");
panel.appendChild(e);
}
function clearPanel(panel) {
function clearPanel() {
/* Clears the text panel */
var kid;
@@ -189,6 +215,7 @@ window.onload = function() {
var bx = bufferOffset;
var card;
var cardLength;
var line;
var match;
if (bx >= bufferLength) {
@@ -199,19 +226,26 @@ window.onload = function() {
match = eolRex.exec(buffer);
if (!match) {
card = blankCard;
line = "";
} else {
bx += match[0].length;
card = match[1];
cardLength = card.length;
if (cardLength < 80) {
line = card;
card += blankCard.substring(0, 80-cardLength);
} else if (cardLength > 80) {
card = card.substring(0, 80);
line = card = card.substring(0, 80);
}
}
$$("CRProgressBar").value = bufferLength-bx;
appendLine(panel, card);
//appendLine(card);
while (outHopper.childNodes.length > 1) {
outHopper.removeChild(outHopper.firstChild);
}
outHopper.appendChild(document.createTextNode("\n"));
outHopper.appendChild(document.createTextNode(line));
if (readerState == readerReady) {
setTimeout(readACard, 60000/cardsPerMinute);
@@ -228,7 +262,7 @@ window.onload = function() {
if (bufferOffset >= bufferLength) {
//alert("Empty hopper.");
if (eofArmed) {
appendLine(panel, "\\\\\\\\\\ [EOF] /////");
appendLine("\\\\\\\\\\ [EOF] /////");
armEOF(false);
}
} else {
@@ -254,13 +288,26 @@ window.onload = function() {
armEOF(!eofArmed);
}
function CRProgressBar_onclick(ev) {
/* Handle the click event for the "input hopper" progress bar */
if (bufferOffset < bufferLength && readerState == readerNotReady) {
if (confirm("Do you want to clear the reader input hopper?")) {
buffer = "";
bufferLength = 0;
bufferOffset = 0;
$$("CRProgressBar").value = 0;
}
}
}
function fileLoader_onLoad(ev) {
/* Handle the onload event for a Text FileReader */
if (bufferOffset < bufferLength) {
buffer = buffer.substring(bufferOffset);
} else {
clearPanel(panel);
clearPanel();
buffer = "";
}
@@ -317,7 +364,18 @@ window.onload = function() {
$$("CRStartBtn").addEventListener("click", CRStartBtn_onclick, false);
$$("CRStopBtn").addEventListener("click", CRStopBtn_onclick, false);
$$("CREOFBtn").addEventListener("click", CREOFBtn_onclick, false);
}
$$("CRProgressBar").addEventListener("click", CRProgressBar_onclick, false);
outHopperFrame.contentDocument.head.innerHTML += "<style>" +
"BODY {background-color: #F0DCB0} " +
"PRE {margin: 0; font-size: 8pt; font-family: Lucida Sans Typewriter, Courier New, Courier, monospace}" +
"</style>";
outHopper = document.createElement("pre");
outHopperFrame.contentDocument.body.appendChild(outHopper);
//endOfOutHopper = document.createElement("div");
//endOfOutHopper.appendChild(document.createTextNode("\xA0"));
//outHopperFrame.contentDocument.body.appendChild(endOfOutHopper);
}, false);
</script>
</head>
@@ -332,9 +390,11 @@ window.onload = function() {
<button id=CREOFBtn class="redButton">EOF</button>
<button id=CRStopBtn class="redButton">STOP</button>
<input id=CRFileSelector type=file size=29>
<input id=CRFileSelector type=file size=90>
<progress id=CRProgressBar min=0 max=100 value=0>
<progress id=CRProgressBar min=0 max=100 value=0 title="Click to clear input hopper"></progress>
<iframe id=CROutHopperFrame scrolling=auto></iframe>
</div>
<pre id=TextPanel>