1
0
mirror of https://github.com/pkimpel/retro-b5500.git synced 2026-04-14 17:05:41 +00:00

1. Finalize and release emulator version 0.05.

2. Fix (we hope) the nasty problem that was causing Invalid Address out of COM5 after large compiles -- bug in MSCW/MSFF tracing in Processor.exitSubroutine().
3. Implement ability to do a hardware load without initiating P1 in CentralControl (used by SyllableDebugger).
4. De-anonymize object prototype method functions in Processor as an aid when using JS debuggers.
5. Rework storeForInterrupt() and initiate() in Processor.
6. Replace bitmask "AND"s with power-of-two "MOD"s in many places in Processor.
7. Replace many bit(), fieldIsolate(), fieldInsert() calls with mod/div expressions in Processor.
8. Fix a problem existing normalization when an Integer Overflow occurs in Integer Store syllables.
9. Fix missing and superfluous break statements in Processor.run() switch statements.
10. Fix incorrect C-register restoration in Character Mode RCA syllable.
11. Correct test for continuity bit in Processor PRL syllable coding.
12. Correct missing "this." in Processor BRT syllable coding.
13. Change way that delayTime and Processor.procSlack is computed in Processor.run().
14. Correct BCL translation bug and directory EOF detection in B5500ColdLoader.
15. Attempt to initialize SYSTEM/LOG in B5500ColdLoader (not working yet).
16. Implement new retro-B5500-Logo.png.
17. Implement Hardware Load button in SyllableDebugger.
18. Release tools/B5500DiskDirList.html utility.
19. Release tools/B5500DiskFileList.html utility with PBD file special formattring.
20. Restrict directory complement to EU0 in B5500ColdLoader.html.
21. Miscellaneous improvements to comments and cosmetics.
This commit is contained in:
paul.kimpel@digm.com
2013-05-27 04:08:34 +00:00
parent e4f208fcb8
commit 15fc6c5a0b
15 changed files with 1852 additions and 230 deletions

View File

@@ -22886,3 +22886,169 @@ BEGIN REAL RCW=+0,MSCW=-2; 38001000
FPB[FNUM ]:=MFID:=FID; %126-38013030
FPB[FNUM+1]:=FID :=USERCODE[P1MIX]; %126-38013040
END; %126-38013050
IF NFLAG(FIX[14]~FLAG(FILEHEADER(MFID 38013100
$ SET OMIT = NOT SHAREDISK 38013199
,FID&FIB[5][1:45:1],FIB[8].[20:5] 38013300
,FIB[8].[25:23],BLEN,RLEN,STATE)))<6 THEN 38013400
BEGIN P(DEL); 38013500
TOG:= 1; 38013510
$ SET OMIT = NOT SHAREDISK 38013519
GO TO EXIT; 38013600
END; 38013700
IF FIB[8].[20:28]!0 THEN FPB[FNUM+2].[18:30]~DATE ELSE 38013900
BEGIN% OLD FILE,VERIFY LABEL EQUATION DATE IF ANY 38014000
HEADER := FIB[14];% 38014100
STREAM(H:=HEADER[3].[30:18],B:=[T2]); 38014200
BEGIN SI:=LOC H; DS:=8 DEC; END;% 38014300
AGN: IF CDATE NEQ 0 AND CDATE NEQ HEADER[3].[30:18] THEN38014400
BEGIN% WRITE DATE CHECK MESSAGE 38014500
DOLITTLE(FALSE, 38014600
VWY&VOF[36:42:6]&VOK[30:42:6], 38014610
"#DAT CK"," =00000"&T2[18:18:30],MFID); 38014620
IF TERMSET(P1MIX) THEN 38014700
BEGIN 38014800
FORGETSPACE(DIRECTORYSEARCH(MFID,FID, 38014900
$ SET OMIT = NOT SHAREDISK 38014949
FIB[5].[13:3]+10)); 38015000
GO TO INITIATE; 38015100
END;% 38015200
IF P(NT6,DUP)=VOK OR P(XCH)=VOF THEN CDATE~0; 38015400
GO AGN 38015500
END;% VERIFICATION 38015600
FPB[FNUM+2].[18:30]:=T2;% BCL DATE 38015700
END OLD FILES;% 38015800
STARTIMING(FNUM,18);% 38015900
FPB:=PRT[P1MIX,3]; % STARTIMING MOVES THE FPB 38015950
END;% 38016000
HEADER~FIB[14];% 38020000
KIND~4; U~18;% 38021000
MODE~0;% 38022000
IF NOT COBOL THEN UNLABELED~1;% 38023000
CNTCTL~BLEN{1023;% 38024000
$ SET OMIT = NOT SHAREDISK 38024004
IF COBOL>0 AND (FIB[13].[22:1] OR TYPE=10 OR TYPE=26) THEN 38024100
BEGIN COBOL:=3; %IF COBOL-IO OR COBOL-RANDOM 38024200
BLEN := BLEN + RLEN; % THEN CHANGE BUFFSIZE TO 38024300
END; % BUFFSIZE + RECSIZE 38024400
GETBUFFERS((IF CNTCTL THEN BLEN% 38025000
ELSE ((BLEN+29) DIV 30)|30)+1,% 38026000
NBUFS,U,ALPHA);% 38027000
IF COBOL = 3 THEN %IF COBOL-IO OR COBOL-RANDOM 38027100
BEGIN COBOL := 1; % THEN CHANGE BUFFSIZE TO 38027200
BLEN := BLEN - RLEN; % BUFFSIZE - RECSIZE 38027300
END; % (SEE ABOVE 38027400
FIB[16]~M[ALPHA]&CNTCTL[23:47:1]&10[24:47:1]% 38028000
&((BLEN+29) DIV 30)[27:42:6]% 38029000
&(IF CNTCTL THEN BLEN ELSE 1023)[8:38:10]% 38030000
&TINU[18][3:3:5] OR M OR IOMASK;% 38031000
FIB[16].[2:1]:=(HEADER.[31:2] AND (IO+1))!0; 38032000
FIB[5].[1:1]:= NOT FIB[16].[2:1]; 38033000
IF FIB[5].[1:1] THEN 38034000
FOR MASK:=10 STEP 1 UNTIL 29 DO HEADER[MASK]:=0; 38035000
FIB[19]~(IF DIREC THEN BLEN-RLEN+1 ELSE 1) 38036000
INX FIB[16]&0[27:27:6]; 38037000
IF STATE.[46:2]!0 THEN FIB[19].[8:10]~RLEN;% 38038000
FS[P1MIX,(T2:=(FNUM DIV ETRLNG)).[40:4]]~(*P(DUP)) OR 38039000
(TWO(0&T2[43:44:4])|((NOT HEADER).[31:2])); 38040000
T2~IF COBOL THEN 0 ELSE FIB[19].[33:15]-FIB[16].[33:15]; 38041000
FIB[10].[3:15]:=M[ALPHA]-2; %HEAD OF BUFFER RING 38041100
FOR MASK~0 STEP 1 UNTIL NBUFS-1 DO% 38042000
M[ALPHA+MASK]~(P(DUP,LOD)+T2)% 38043000
&P(FLAG(FIB[19-ABS(3|COBOL)]),XCH)[CTC]; 38044000
FIB[16]:=FIB[16] OR M; 38045000
FIB[5].[45:1]~0; 38045100
IF P([FIB[14]],LOD).[FF]=2 THEN FIB[5].[11:2]~1;%INPUT ONLY.38045105
IF HEADER[4].[10:1] AND NOT IO THEN 38045110
FILEMESS(-"CODE ","FILE ",MFID,FID,0,0,0); 38045120
$ SET OMIT = NOT(PACKETS) 38045149
IF PSEUDOMIX[P1MIX]!0 THEN 38045150
IF NOT FIB[5].[41:1] THEN 38045155
FILEMESSAGE((IF IO THEN " IN " ELSE "OUT") 38045160
&TINU[U][6:30:18], IF ACCESS=0 THEN " SER " 38045200
ELSE IF ACCESS=1 THEN IF TYPE=26 THEN " PRO " 38045300
ELSE " RDM " ELSE " UPD ", 38045310
MFID,FID,0,0,0,64); 38045400
$ POP OMIT 38045501
END DISKSETUP;% 38046000
P(RCW,MSCW,STF); 38047000
RCW:=RCW&P(XCH)[CTC]; 38048000
DISKSETUP; 38049000
IF COBOL<0 THEN % ADJUST UPPER BOUND FOR COBOL 68 38049200
BEGIN MASK ~ (IF IO AND NOT FIB[13].[22:1] 38049300
THEN HEADER[7] 38049400
ELSE (((HEADER[9] | HEADER[1]) DIV 38049500
HEADER[0].[42:6]) | HEADER[0].[30:12]) - 1);38049600
IF FIB[3]=0 OR FIB[3]>MASK THEN FIB[3]~MASK; %LESSOR OF 2 EVILS38049700
END; 38049800
IF P(TYPE,DUP)=10 OR P(XCH)=26 THEN 38050000
BEGIN 38051000
IF COBOL<1 THEN % ALGOL OR COBOL 68 38052000
FOR MASK ~ 0 STEP 1 UNTIL NBUFS-1 DO 38053000
IF COBOL THEN M[M[ALPHA+MASK] INX NOT 2] ~ NOT 0 38053500
ELSE M[ALPHA+MASK]~P(DUP,LOD)&1[27:47:1]; 38054000
FIB[6]~FIB[7]~0;% 38055000
FIB[17]~IF IO THEN 0 ELSE BLEN;% 38056000
END ELSE 38057000
BEGIN 38058000
T2~(MFID~FIB[16).[33:15];% 38059000
FIV7~FIB[7]; 38060000
IF COBOL THEN% 38061000
BEGIN IF COBOL>0 THEN 38062000
IF NOT (FIB7=0 OR FIB[13].[22:1]) THEN 38062500
BEGIN FIB7 ~ FIB7 - 1; 38063000
OPTIONAL ~ NBUFS - 1; 38063500
END ELSE OPTIONAL ~ NBUFS - 2 38064000
ELSE BEGIN % COBOL 68 38064200
OPTIONAL ~ NBUFS - 1; 38064400
IF DIREC THEN FIB7 ~ FIB[7] ~ FIB[3]; 38064600
END; 38065000
FID~FIB[16];% 38066000
MASK~0;% 38067000
END ELSE% 38068000
BEGIN OPTIONAL~NBUFS-1;% 38069000
MASK~(FID~FIB[19]).[33:15]-T2;% 38070000
END;% 38071000
IF (STATE.[46:2]!0 AND NOT COBOL) OR IO THEN 38072000
IF M[ALPHA].]2:1] THEN 38073000
FOR T1~0 STEP 1 UNTIL OPTIONAL DO% 38074000
BEGIN IF (M[T2]:= 38074500
DISKADDRESS(FPB[FNUM], FPB[FNUM+1], FPB[FNUM+3], 38075000
FORMS:=((HEADER[0].[30:12]|T1)&DIREC[1:47:1])+FIB7,38075500
HEADER, IO&(NOT HEADER[4])[46:47:1])) > 1 THEN 38076000
BEGIN 38076500
IF (USERCODE[P1MIX] EQV MCP)!NOT 0 THEN 38077000
IF P(M[MFID],DUP).[3:6]=0 AND 38077500
P(XCH)<DIRDSK|DSKTOG THEN 38078000
BEGIN 38078500
TERMINATE(P1MIX); 38079000
TERMINALMESSAGE(30); 38079500
END; 38080000
IOREQUEST(FLAG(FID),MFID&1[24:47:1],M[T2-2]); 38080500
M[ALPHA]:=FLAG(MFID)&0[26:26:7] AND NOT 38081000
(M OR IOMASK); 38081250
END ELSE 38081500
IF M[T2]=0 THEN % EOF IF INPUT, FULL HDR IF OUTPT38081750
M[ALPHA]:=P(DUP,LOD)&1[27:47:1] AND NOT M; 38082000
IF COBOL<0 THEN M[M[ALPHA] INX NOT 2] ~ 38082400
(IF FORMS}0 THEN FORMS DIV FIB[11] ELSE NOT 0); 38082500
STREAM(N~NBUFS-1,T~M[ALPHA],ALPHA);% 38083000
BEGIN SI~ALPHA; SI~SI+8; DS~N WDS;% 38084000
SI~LOC T; DS~WDS;% 38085000
END;% 38086000
MFID.[33:15]~T2~M[T2-2].[18:15];% 38087000
FID.[33:15]~T2+MASK;% 38088000
END;% 38089000
IF (NBUFS-1)!OPTIONAL THEN FIB[16].[33:15]~M[ALPHA] ;% 38090000
FORMS~(FORMS~FIB7 MOD HEADER[0].[30:12])|RLEN; 38091000
SLEEP([M[ALPHA]],IOMASK);% 38092000
IF COBOL } 0 THEN % NOT COBOL 68 38092900
IF FIB[13].[22:1]THEN M[ALPHA].[33:15]~FIB[16]INX 1 ELSE 38093000
M[ALPHA].[33:15]~FIB[16].[33:15]+FORMS+1;% 38094000
IF (NBUFS-1)!OPTIONAL AND IO AND NOT FIB[13].[22:1] THEN 38095000
FIB[ 17 ]~0 ELSE 38096000
FIB[17]~IF DIREC THEN FORMS~RLEN% 38097000
ELSE BLEN-FORMS;% 38098000
END; 38099000
EXIT: 38099100
P(P&RCW[CTC],0,RDS,0,XCH,P&P[CTF],STF); 38100000
END DISKFILEOPEN; 38101000

View File

@@ -55,7 +55,6 @@ function B5500CentralControl() {
// Establish contexts for asynchronously-called methods
this.boundTock = B5500CentralControl.bindMethod(this.tock, this);
this.boundLoadComplete = B5500CentralControl.bindMethod(this.loadComplete, this);
this.clear(); // Create and initialize the Central Control state
}
@@ -63,7 +62,7 @@ function B5500CentralControl() {
/**************************************/
/* Global constants */
B5500CentralControl.version = "0.04";
B5500CentralControl.version = "0.05";
B5500CentralControl.rtcTick = 1000/60; // Real-time clock period, milliseconds
@@ -156,7 +155,7 @@ B5500CentralControl.bindMethod = function(f, context) {
Note that this is a constructor property function, NOT an instance method of
the CC object */
return (function() {f.apply(context, arguments)});
return function() {f.apply(context, arguments)};
};
/**************************************/
@@ -420,7 +419,7 @@ B5500CentralControl.prototype.signalInterrupt = function() {
: this.CCI16F ? 0x1F // @37: Disk file 2 read check finished
: p1.I & 0x04 ? 0x32 // @62: P1 stack overflow
: p1.I & 0xF0 ? (p1.I >>> 4) + 0x30 // @64-75: P1 syllable-dependent
: (p2 = this.P2) ?
: (p2 = this.P2) ? // Yes, Virginia, this should actually be an assignment...
( p2.I & 0x01 ? 0x20 // @40: P2 memory parity error
: p2.I & 0x02 ? 0x21 // @41: P2 invalid address error
: p2.I & 0x04 ? 0x22 // @42: P2 stack overflow
@@ -690,7 +689,7 @@ B5500CentralControl.prototype.halt = function() {
};
/**************************************/
B5500CentralControl.prototype.loadComplete = function loadComplete() {
B5500CentralControl.prototype.loadComplete = function loadComplete(dontStart) {
/* Monitors an initial load I/O operation for complete status.
When complete, initiates P1 */
var completed = false; // true if some I/O Unit finished
@@ -711,21 +710,25 @@ B5500CentralControl.prototype.loadComplete = function loadComplete() {
completed = true;
this.CCI11F = 0;
this.AD4F = 0;
//} else { // Nothing finished yet (or there was an error)
// this.loadTimer = setTimeout(this.boundLoadComplete, 1000);
}
if (completed) {
this.loadTimer = null;
this.LOFF = 0;
this.P1.preset(0x10); // start execution at C=@20
this.P1.start(); // let'er rip
if (!dontStart) {
this.P1.start(); // let'er rip
}
}
};
/**************************************/
B5500CentralControl.prototype.load = function() {
/* Initiates a Load operation to start the system */
B5500CentralControl.prototype.load = function(dontStart) {
/* Initiates a Load operation to start the system. If "dontStart" is truthy, then
only the MCP bootstrap is loaded into memory -- P1 is not started */
var boundLoadComplete = (function(that, dontStart) {
return function() {return that.loadComplete(dontStart)}
})(this, dontStart);
if (this.P1 && !this.P1.busy) {
this.clear();
@@ -734,18 +737,18 @@ B5500CentralControl.prototype.load = function() {
this.LOFF = 1;
if (this.IO1 && this.IO1.REMF && !this.AD1F) {
this.AD1F = 1;
this.IO1.initiateLoad(this.cardLoadSelect, this.boundLoadComplete);
this.IO1.initiateLoad(this.cardLoadSelect, boundLoadComplete);
} else if (this.IO2 && this.IO2.REMF && !this.AD2F) {
this.AD2F = 1;
this.IO2.initiateLoad(this.cardLoadSelect, this.boundLoadComplete);
this.IO2.initiateLoad(this.cardLoadSelect, boundLoadComplete);
} else if (this.IO3 && this.IO3.REMF && !this.AD3F) {
this.AD3F = 1;
this.IO3.initiateLoad(this.cardLoadSelect, this.boundLoadComplete);
this.IO3.initiateLoad(this.cardLoadSelect, boundLoadComplete);
} else if (this.IO4 && this.IO4.REMF && !this.AD4F) {
this.AD4F = 1;
this.IO4.initiateLoad(this.cardLoadSelect, this.boundLoadComplete);
this.IO4.initiateLoad(this.cardLoadSelect, boundLoadComplete);
} else {
this.CCI04F = 1; // set I/O busy interrupt
this.CCI04F = 1; // set I/O busy interrupt
}
}
};
@@ -777,7 +780,7 @@ B5500CentralControl.prototype.loadTest = function(buf, loadAddr) {
}
if (!this.poweredUp) {
throw "cc.loadTest: Cannot load with system powered off"
throw "cc.loadTest: Cannot load with system powered off";
} else {
while (bytes > 6) {
word = data.getUint8(x)* 0x10000000000 +
@@ -876,23 +879,23 @@ B5500CentralControl.prototype.configureSystem = function() {
default:
return function() {};
break;
};
}
}
// ***** !! inhibit for now ***** // this.DD = new B5500DistributionAndDisplay(this);
// Configure the processors
if (cfg.PA) {this.PA = new B5500Processor("A", this)};
if (cfg.PB) {this.PB = new B5500Processor("B", this)};
if (cfg.PA) {this.PA = new B5500Processor("A", this)}
if (cfg.PB) {this.PB = new B5500Processor("B", this)}
// Determine P1/P2
this.PB1L = (cfg.PB1L ? 1 : 0);
// Configure the I/O Units
if (cfg.IO1) {this.IO1 = new B5500IOUnit("1", this)};
if (cfg.IO2) {this.IO2 = new B5500IOUnit("2", this)};
if (cfg.IO3) {this.IO3 = new B5500IOUnit("3", this)};
if (cfg.IO4) {this.IO4 = new B5500IOUnit("4", this)};
if (cfg.IO1) {this.IO1 = new B5500IOUnit("1", this)}
if (cfg.IO2) {this.IO2 = new B5500IOUnit("2", this)}
if (cfg.IO3) {this.IO3 = new B5500IOUnit("3", this)}
if (cfg.IO4) {this.IO4 = new B5500IOUnit("4", this)}
// Configure memory
for (x=0; x<8; x++) {

View File

@@ -644,7 +644,7 @@ B5500IOUnit.prototype.initiateDiskIO = function(u) {
} else {
this.Daddress++; // bump memory address past the seg address word
w = this.W; // convert address word to binary
for (x=0; x<7; x++) {
for (x=0; x<7; x++) { // 7 decimal digits: 1 for EU, 6 for EU-relative address
c = w % 0x40; // get low-order six bits of word
segAddr += (c % 0x10)*p; // isolate the numeric portion and accumulate
w = (w-c)/0x40; // shift word right six bits
@@ -716,7 +716,6 @@ B5500IOUnit.prototype.initiatePrinterIO = function(u) {
/**************************************/
B5500IOUnit.prototype.forkIO = function forkIO() {
/* Asynchronously initiates an I/O operation on this I/O Unit for a peripheral device */
var addr; // memory address
var chars; // I/O memory transfer length
var index; // unit index
var u; // peripheral unit object
@@ -746,6 +745,7 @@ B5500IOUnit.prototype.forkIO = function forkIO() {
} else {
this.cc.setUnitBusy(index, 1);
u = this.cc.unit[index];
switch(this.Dunit) {
// disk designates
case 6:

File diff suppressed because it is too large Load Diff

605
tools/B5500DiskDirList.html Normal file
View File

@@ -0,0 +1,605 @@
<!DOCTYPE html>
<head>
<title>B5500 Disk Directory List Utility</title>
<meta name="Author" content="Paul Kimpel">
<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">
<script>
/***********************************************************************
* retro-b5500/tools B5500DiskDirList.html
************************************************************************
* Copyright (c) 2013, Paul Kimpel.
* Licensed under the MIT License,
* see http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B5500 Disk Directory List Utility.
*
* This script opens an IndexedDB database in the browser and attempts to
* treat it as a B5500 disk image, listing all of the files and their attributes
* in the disk directory.
************************************************************************
* 2013-04-16 P.Kimpel
* Original version, from B5500ColdLoader.html.
***********************************************************************/
"use strict";
window.onload = function() {
var configName = "CONFIG"; // database configuration store name
var dbName = "B5500DiskUnit"; // IDB database name
var dbVersion = 1; // current IDB database version
var directoryTop; // start of directory area
var directoryEnd; // end of directory area
var euPrefix = "EU"; // prefix for EU object store names
var config = null; // copy of CONFIG store contents
var disk = null; // the IDB database object
var panel = $$("TextPanel");
var 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
0x2B,0x41,0x42,0x43,0x44,0x45,0x46,0x47, // 10-17, @20-27
0x48,0x49,0x2E,0x5B,0x26,0x28,0x3C,0x7E, // 18-1F, @30-37
0x7C,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50, // 20-27, @40-47
0x51,0x52,0x24,0x2A,0x2D,0x29,0x3B,0x7B, // 28-2F, @50-57
0x20,0x2F,0x53,0x54,0x55,0x56,0x57,0x58, // 30-37, @60-67
0x59,0x5A,0x2C,0x25,0x21,0x3D,0x5D,0x22]; // 38-3F, @70-77
var BICtoBCLANSI = [ // Index by 6-bit BIC to get 8-bit BCL-as-ANSI code
0x23,0x31,0x32,0x33,0x34,0x35,0x36,0x37, // 00-07, @00-07
0x38,0x39,0x40,0x3F,0x30,0x3A,0x3E,0x7D, // 08-1F, @10-17
0x2C,0x2F,0x53,0x54,0x55,0x56,0x57,0x58, // 10-17, @20-27
0x59,0x5A,0x25,0x21,0x20,0x3D,0x5D,0x22, // 18-1F, @30-37
0x24,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50, // 20-27, @40-47
0x51,0x52,0x2A,0x2D,0x7C,0x29,0x3B,0x7B, // 28-2F, @50-57
0x2B,0x41,0x42,0x43,0x44,0x45,0x46,0x47, // 30-37, @60-67
0x48,0x49,0x5B,0x26,0x2E,0x28,0x3C,0x7E]; // 38-3F, @70-77
var ANSItoBIC = [ // Index by 8-bit ANSI to get 6-bit BIC (upcased, invalid=>"?")
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 00-0F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 10-1F
0x30,0x3C,0x3F,0x0A,0x2A,0x3B,0x1C,0x0C,0x1D,0x2D,0x2B,0x10,0x3A,0x2C,0x1A,0x31, // 20-2F
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0D,0x2E,0x1E,0x3D,0x0E,0x0C, // 30-3F
0x0B,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x21,0x22,0x23,0x24,0x25,0x26, // 40-4F
0x27,0x28,0x29,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x1B,0x0C,0x3E,0x0C,0x0C, // 50-5F
0x0C,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x21,0x22,0x23,0x24,0x25,0x26, // 60-6F
0x27,0x28,0x29,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x2F,0x20,0x0F,0x1F,0x0C, // 70-7F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 80-8F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 90-9F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // A0-AF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // B0-BF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // C0-CF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // D0-DF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // E0-EF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C]; // F0-FF
var BCLANSItoBIC = [ // Index by 8-bit BCL-as-ANSI to get 6-bit BIC (upcased, invalid=>"?")
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 00-0F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 10-1F
0x1C,0x1B,0x1F,0x00,0x20,0x1A,0x3B,0x0C,0x3D,0x2D,0x2A,0x30,0x10,0x2B,0x3C,0x11, // 20-2F
0x0C,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0D,0x2E,0x3E,0x1D,0x0E,0x0B, // 30-3F
0x0A,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x21,0x22,0x23,0x24,0x25,0x26, // 40-4F
0x27,0x28,0x29,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x3A,0x0C,0x1E,0x0C,0x0C, // 50-5F
0x0C,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x21,0x22,0x23,0x24,0x25,0x26, // 60-6F
0x27,0x28,0x29,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x2F,0x2C,0x0F,0x3F,0x0C, // 70-7F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 80-8F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 90-9F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // A0-AF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // B0-BF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // C0-CF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // D0-DF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // E0-EF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C]; // F0-FF
var pow2 = [ // powers of 2 from 0 to 52
0x1, 0x2, 0x4, 0x8,
0x10, 0x20, 0x40, 0x80,
0x100, 0x200, 0x400, 0x800,
0x1000, 0x2000, 0x4000, 0x8000,
0x10000, 0x20000, 0x40000, 0x80000,
0x100000, 0x200000, 0x400000, 0x800000,
0x1000000, 0x2000000, 0x4000000, 0x8000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x100000000, 0x200000000, 0x400000000, 0x800000000,
0x1000000000, 0x2000000000, 0x4000000000, 0x8000000000,
0x10000000000, 0x20000000000, 0x40000000000, 0x80000000000,
0x100000000000, 0x200000000000, 0x400000000000, 0x800000000000,
0x1000000000000, 0x2000000000000, 0x4000000000000, 0x8000000000000,
0x10000000000000];
/**************************************/
function $$(id) {
return document.getElementById(id);
}
/**************************************/
function bit(word, bit) {
/* Extracts and returns the specified bit from the word */
var e = 47-bit; // word lower power exponent
var p; // bottom portion of word power of 2
if (e > 0) {
return ((word - word % (p = pow2[e]))/p) % 2;
} else {
return word % 2;
}
};
/**************************************/
function fieldIsolate(word, start, width) {
/* Extracts a bit field [start:width] from word and returns the field */
var le = 48-start-width; // lower power exponent
var p; // bottom portion of word power of 2
return (le == 0 ? word : (word - word % (p = pow2[le]))/p) % pow2[width];
};
/**************************************/
function spout(text) {
/* Appends "text"+NL as a new text node to the panel DOM element */
var e = document.createTextNode(text + "\n");
panel.appendChild(e);
$$("PageBottom").scrollIntoView();
}
/**************************************/
function clearPanel() {
/* Clears the text panel */
var kid;
while (kid = panel.firstChild) {
panel.removeChild(kid);
}
}
/**************************************/
function rtrim(s) {
/* Trims trailing spaces from "s" and returns the resulting string */
var m = s.match(/^(.*?) *$/);
return m[1];
}
/**************************************/
function padToLength(text, len) {
/* Converts the input string "text" to exactly "len" characters,
truncating or padding on the right with spaces as necessary */
var x = text.length;
if (x > len) {
return text.substring(0, len);
} else {
x = len-x;
while (x-- > 0) {
text += " ";
}
return text;
}
}
/**************************************/
function stringToANSI(text, bytes, bx, asBinary) {
/* Translates the characters in a string to upper case, and then to ANSI
byte-array format. "text" is the input string, "bytes" is the Uint8Array
output buffer, and "bx" is the offset into that output buffer. If "asBinary" is
truthy, the translation is binary, otherwise it is done as BCLANSI */
var len = text.length;
var table1 = (asBinary ? BICtoANSI : BICtoBCLANSI);
var utxt = text.toUpperCase();
var x;
bx = bx || 0;
for (x=0; x<len; x++) {
bytes[bx++] = table1[ANSItoBIC[utxt.charCodeAt(x) & 0xFF]];
}
}
/**************************************/
function wordsToANSI(words, wx, wLength, bytes, bx, asBinary) {
/* Translates an array of B5500 words to ANSI byte-array format.
"words" = the array of words
"wx" = the starting index in "words"
"wLength" = the number of words to translate
"bytes" = a Uint8Array array
"bx" = the starting index in "bytes" to store the translated data
"asBinary" = if truthy, then binary translation is done; otherwise
B5500 BCLANSI translation is done */
var c;
var table = (asBinary ? BICtoANSI : BICtoBCLANSI);
var w;
var x;
var y;
var z;
bx = bx || 0;
if (wLength < 0) {
wLength = -wLength;
}
for (x=0; x<wLength; x++) {
w = words[wx+x] || 0;
for (y=0; y<8; y++) {
z = w % 0x40000000000;
c = (w-z)/0x40000000000;
bytes[bx++] = table[c];
w = z*64;
}
}
}
/**************************************/
function wordsToString(words, wx, wLength, asBinary) {
/* Translates an array of B5500 words to a string and returns the string.
"words" = the array of words
"wx" = the starting index in "words"
"wLength" = the number of words to translate
"asBinary" = if truthy, then binary translation is done; otherwise
B5500 BCLANSI translation is done */
var c;
var table = (asBinary ? BICtoANSI : BICtoBCLANSI);
var text = "";
var w;
var x;
var y;
var z;
if (wLength < 0) {
wLength = -wLength;
}
for (x=0; x<wLength; x++) {
w = words[wx+x] || 0;
for (y=0; y<8; y++) {
z = w % 0x40000000000;
c = (w-z)/0x40000000000;
text += String.fromCharCode(table[c]);
w = z*64;
}
}
return text;
}
/**************************************/
function ANSItoWords(bytes, bx, bLength, words, wx, asBinary) {
/* Translates a portion of an ANSI byte array to a sequence of B5500 words.
"bytes" = the Uint8Array byte array
"bx" = 0-relative offset into "bytes"
"bLength" = number of bytes to translate
"words" = the word array
"wx" = 0-relative offset into "words" to store the translated data
"asBinary" = if truthy, then binary translation is done; otherwise
B5500 BCLANSI translation is done */
var cx = 0;
var w = 0;
var table = (asBinary ? ANSItoBIC : BCLANSItoBIC);
var x;
wx = wx || 0;
if (bLength < 0) {
bLength = -bLength;
}
for (x=0; x<bLength; x++) {
if (cx >= 8) {
words[wx++] = w;
w = cx = 0;
}
w = w*64 + table[bytes[bx+x]];
cx++;
}
while (cx++ < 8) {
w *= 64;
}
words[wx++] = w;
}
/**************************************/
function readDiskBlock(addr, segs, block, callback) {
/* Reads a block from the disk "eu" at "addr" for "segs" segments, translates
it to words in the "block" array, then calls "callback" passing the address
and block */
var bx = 0;
var eu;
var euAddr = addr % 1000000;
var euNr = (addr % 10000000 - euAddr)/1000000;
var euName = euPrefix + euNr.toString();
var endAddr = euAddr + segs - 1;
var nextAddr = euAddr;
var range = IDBKeyRange.bound(euAddr, endAddr);
var req;
var txn;
var x;
txn = disk.transaction(euName);
eu = txn.objectStore(euName);
req = eu.openCursor(range);
req.onsuccess = function(ev) {
var cursor = ev.target.result;
if (cursor) {
while (cursor.key > nextAddr) {
for (x=0; x<30; x++) {
block[bx++] = 0;
}
nextAddr++;
}
ANSItoWords(cursor.value, 0, 240, block, bx);
bx += 30;
nextAddr++;
cursor.continue();
} else {
while (nextAddr <= endAddr) {
for (x=0; x<30; x++) {
block[bx++] = 0;
}
nextAddr++;
}
callback(addr, block);
}
};
}
/**************************************/
function readDiskHeader(block) {
/* Decodes "block" as a B5500 disk header, returning the header object */
var header = {
recordLength: 0,
blockLength: 0,
recordsPerBlock: 0,
segmentsPerBlock: 0,
logCreationDate: 0,
logCreationTime: 0,
lastAccessDate: 0,
creationDate: 0,
fileClass: 0,
fileType: 0,
recordCount: 0,
segmentsPerRow: 0,
maxRows: 0,
rowAddress: [],
words: []};
header.recordLength = fieldIsolate(block[0], 0, 15);
header.blockLength = fieldIsolate(block[0], 15, 15);
header.recordsPerBlock = fieldIsolate(block[0], 30, 12);
header.segmentsPerBlock = fieldIsolate(block[0], 42, 6);
header.logCreationDate = fieldIsolate(block[1], 6, 18);
header.logCreationTime = fieldIsolate(block[1], 25, 23);
header.lastAccessDate = fieldIsolate(block[3], 12, 18);
header.creationDate = fieldIsolate(block[3], 30, 18);
header.fileClass = fieldIsolate(block[4], 9, 2);
header.fileType = fieldIsolate(block[4], 36, 6);
header.recordCount = block[7];
header.segmentsPerRow = block[8];
header.maxRows = fieldIsolate(block[9], 43, 5);
header.rowAddress = block.slice(10);
header.words = block; // save the raw header words
return header;
}
/**************************************/
function formatDirectoryEntry(body, mfid, fid, header) {
/* Formats the disk header for a file */
var row = document.createElement("tr");
var rx;
var text = "";
function appendCell(row, v, className) {
var cell = document.createElement("td");
if (className && className.search(/\S/) >= 0) {
cell.className = className;
}
cell.appendChild(document.createTextNode(v.toString()));
row.appendChild(cell);
}
appendCell(row, mfid.substring(1));
appendCell(row, fid.substring(1));
appendCell(row, header.recordLength, "rj");
appendCell(row, header.blockLength, "rj");
appendCell(row, header.recordsPerBlock, "rj");
appendCell(row, header.segmentsPerBlock, "rj");
appendCell(row, header.logCreationDate);
appendCell(row, header.logCreationTime);
appendCell(row, header.lastAccessDate);
appendCell(row, header.creationDate);
appendCell(row, header.fileClass, "rj");
appendCell(row, header.fileType, "rj");
appendCell(row, header.recordCount, "rj");
appendCell(row, header.segmentsPerRow, "rj");
appendCell(row, header.maxRows, "rj");
for (rx=0; rx<header.maxRows; rx++) {
text += header.rowAddress[rx].toFixed(0) + " ";
}
appendCell(row, text);
body.appendChild(row);
}
/**************************************/
function directoryList(successor) {
/* Reads the existing directory structure to generate a list of the files
in the directory. When finished, calls the "successor" function */
var block = new Array(480);
var body = $$("DirListBody");
function reportDirBlock(addr, block) {
/* Lists the entries in the resulting block; if not the last block,
advances to the next block */
var atEnd = false;
var bx;
var fid;
var mfid;
var namex;
// Step through the file name entries backwards
for (namex=14; namex>=0; namex--) {
bx = namex*2 + 450;
if (block[bx] == 0x4C) { // 0x4C=@114, end-of-directory marker
atEnd = true;
break;
} else if (block[bx] != 0x0C) { // 0x0C=@14, available directory slot
// Got a live one -- format its header
mfid = wordsToString(block, bx, 1, true);
fid = wordsToString(block, bx+1, 1, true);
bx = namex*30;
formatDirectoryEntry(body, mfid, fid, readDiskHeader(block.slice(bx, bx+30)));
}
}
if (atEnd) {
successor();
} else {
readDiskBlock(addr+16, 16, block, reportDirBlock);
}
}
/***** outer block of directoryList *****/
while (body.firstChild) {
body.removeChild(body.firstChild);
}
if (!config.EU0) {
alert("No EU0 in disk configuration -- cannot load");
} else {
readDiskBlock(directoryTop+4, 16, block, reportDirBlock);
}
}
/**************************************/
function genericDBError(ev) {
/* Formats a generic alert when otherwise-unhandled database errors occur */
var disk = ev.currentTarget.result;
alert("Database \"" + disk.name + "\" error: " + ev.target.result.error);
}
/**************************************/
function openDatabase(name, version, successor) {
/* Attempts to open the disk subsystem database for the specified "name"
and "version". Stores the IDB database object in "disk" if successful, or
stores null if unsuccessful. Also gets directoryTop from seg 0 */
var block = new Array(30);
var db = null;
var req;
req = window.indexedDB.open(name, version);
req.onerror = function(ev) {
alert("Cannot open disk database: " + ev.target.error);
};
req.onblocked = function(ev) {
alert("Database.open is blocked -- cannot continue");
};
req.onsuccess = function(ev) {
disk = ev.target.result; // save the object reference globally for later use
disk.onerror = genericDBError;
// alert("Disk database opened: " + name + " #" + disk.version);
disk.transaction("CONFIG").objectStore("CONFIG").get(0).onsuccess = function(ev) {
config = ev.target.result;
readDiskBlock(0, 1, block, function(addr, block) {
directoryTop = block[1];
directoryEnd = block[4];
successor();
});
};
};
}
/**************************************/
function checkBrowser() {
/* Checks whether this browser can support the necessary stuff */
var missing = "";
if (!window.File) {missing += ", File"}
if (!window.FileReader) {missing += ", FileReader"}
if (!window.FileList) {missing += ", FileList"}
if (!window.Blob) {missing += ", Blob"}
if (!window.ArrayBuffer) {missing += ", ArrayBuffer"}
if (!window.DataView) {missing += ", DataView"}
if (!window.indexedDB) {missing += ", IndexedDB"}
if (missing.length == 0) {
return false;
} else {
alert("No can do... your browser does not support the following features:\n" +
missing.substring(2));
return true;
}
}
/********** Start of window.onload() **********/
if (!checkBrowser()) {
openDatabase(dbName, dbVersion, function() {
directoryList(function() {});
});
}
}
</script>
<style>
BODY {
font-family: Arial, Helvetica, sans-serif;
font-size: small}
TABLE {
border-collapse: collapse}
TH {
vertical-align: bottom}
.center {
text-align: center}
.rj {
text-align: right}
.mono {
font-family: Courier New, Courier, monospace}
</style>
</head>
<body>
<div style="position:relative; width:100%; height:3em">
<div style="position:absolute; left:0; top:0; width:auto">
<img src="../webUI/retro-B5500-Logo.png" alt="retro-B5500 Logo" style="float:left">
&nbsp;Disk Directory List Utility
</div>
</div>
<table id=DirListTable border=1 cellspacing=0 cellpadding=1>
<thead>
<tr>
<th>MFID
<th>FID
<th>REC
<th>BLK
<th>RPB
<th>SPB
<th>LCD
<th>LCT
<th>LAD
<th>CRD
<th>FCL
<th>FTY
<th>CNT
<th>SPR
<th>MXR
<th>Row Addresses
<tbody id=DirListBody>
</table>
<pre id=TextPanel>
</pre>
<div id=PageBottom>
</div>
</body>
</html>

View File

@@ -0,0 +1,772 @@
<!DOCTYPE html>
<head>
<title>B5500 Disk File List Utility</title>
<meta name="Author" content="Paul Kimpel">
<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">
<script>
/***********************************************************************
* retro-b5500/tools B5500DiskFileList.html
************************************************************************
* Copyright (c) 2013, Paul Kimpel.
* Licensed under the MIT License,
* see http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B5500 Disk File List Utility.
*
* This script opens an IndexedDB database in the browser and attempts to
* treat it as a B5500 disk image, listing all of the files and their attributes
* in the disk directory, and allowing you to select a specific file and list
* it to a sub-window.
************************************************************************
* 2013-04-17 P.Kimpel
* Original version, from B5500DiskDirList.html.
***********************************************************************/
"use strict";
window.onload = function() {
var configName = "CONFIG"; // database configuration store name
var dbName = "B5500DiskUnit"; // IDB database name
var dbVersion = 1; // current IDB database version
var directoryTop; // start of directory area
var directoryEnd; // end of directory area
var euPrefix = "EU"; // prefix for EU object store names
var headers = {};
var config = null; // copy of CONFIG store contents
var disk = null; // the IDB database object
var panel = $$("TextPanel");
var BICtoANSIChar = [ // Index by 6-bit BIC to get ANSI character
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "#", "@", "?", ":", ">", "}",
"+", "A", "B", "C", "D", "E", "F", "G",
"H", "I", ".", "[", "&", "(", "<", "~",
"|", "J", "K", "L", "M", "N", "O", "P",
"Q", "R", "$", "*", "-", ")", ";", "{",
" ", "/", "S", "T", "U", "V", "W", "X",
"Y", "Z", ",", "%", "!", "=", "]", "\""];
var 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
0x2B,0x41,0x42,0x43,0x44,0x45,0x46,0x47, // 10-17, @20-27
0x48,0x49,0x2E,0x5B,0x26,0x28,0x3C,0x7E, // 18-1F, @30-37
0x7C,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50, // 20-27, @40-47
0x51,0x52,0x24,0x2A,0x2D,0x29,0x3B,0x7B, // 28-2F, @50-57
0x20,0x2F,0x53,0x54,0x55,0x56,0x57,0x58, // 30-37, @60-67
0x59,0x5A,0x2C,0x25,0x21,0x3D,0x5D,0x22]; // 38-3F, @70-77
var BICtoBCLANSI = [ // Index by 6-bit BIC to get 8-bit BCL-as-ANSI code
0x23,0x31,0x32,0x33,0x34,0x35,0x36,0x37, // 00-07, @00-07
0x38,0x39,0x40,0x3F,0x30,0x3A,0x3E,0x7D, // 08-1F, @10-17
0x2C,0x2F,0x53,0x54,0x55,0x56,0x57,0x58, // 10-17, @20-27
0x59,0x5A,0x25,0x21,0x20,0x3D,0x5D,0x22, // 18-1F, @30-37
0x24,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50, // 20-27, @40-47
0x51,0x52,0x2A,0x2D,0x7C,0x29,0x3B,0x7B, // 28-2F, @50-57
0x2B,0x41,0x42,0x43,0x44,0x45,0x46,0x47, // 30-37, @60-67
0x48,0x49,0x5B,0x26,0x2E,0x28,0x3C,0x7E]; // 38-3F, @70-77
var ANSItoBIC = [ // Index by 8-bit ANSI to get 6-bit BIC (upcased, invalid=>"?")
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 00-0F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 10-1F
0x30,0x3C,0x3F,0x0A,0x2A,0x3B,0x1C,0x0C,0x1D,0x2D,0x2B,0x10,0x3A,0x2C,0x1A,0x31, // 20-2F
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0D,0x2E,0x1E,0x3D,0x0E,0x0C, // 30-3F
0x0B,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x21,0x22,0x23,0x24,0x25,0x26, // 40-4F
0x27,0x28,0x29,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x1B,0x0C,0x3E,0x0C,0x0C, // 50-5F
0x0C,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x21,0x22,0x23,0x24,0x25,0x26, // 60-6F
0x27,0x28,0x29,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x2F,0x20,0x0F,0x1F,0x0C, // 70-7F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 80-8F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 90-9F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // A0-AF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // B0-BF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // C0-CF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // D0-DF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // E0-EF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C]; // F0-FF
var BCLANSItoBIC = [ // Index by 8-bit BCL-as-ANSI to get 6-bit BIC (upcased, invalid=>"?")
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 00-0F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 10-1F
0x1C,0x1B,0x1F,0x00,0x20,0x1A,0x3B,0x0C,0x3D,0x2D,0x2A,0x30,0x10,0x2B,0x3C,0x11, // 20-2F
0x0C,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0D,0x2E,0x3E,0x1D,0x0E,0x0B, // 30-3F
0x0A,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x21,0x22,0x23,0x24,0x25,0x26, // 40-4F
0x27,0x28,0x29,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x3A,0x0C,0x1E,0x0C,0x0C, // 50-5F
0x0C,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x21,0x22,0x23,0x24,0x25,0x26, // 60-6F
0x27,0x28,0x29,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x2F,0x2C,0x0F,0x3F,0x0C, // 70-7F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 80-8F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // 90-9F
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // A0-AF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // B0-BF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // C0-CF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // D0-DF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C, // E0-EF
0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C]; // F0-FF
var pow2 = [ // powers of 2 from 0 to 52
0x1, 0x2, 0x4, 0x8,
0x10, 0x20, 0x40, 0x80,
0x100, 0x200, 0x400, 0x800,
0x1000, 0x2000, 0x4000, 0x8000,
0x10000, 0x20000, 0x40000, 0x80000,
0x100000, 0x200000, 0x400000, 0x800000,
0x1000000, 0x2000000, 0x4000000, 0x8000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x100000000, 0x200000000, 0x400000000, 0x800000000,
0x1000000000, 0x2000000000, 0x4000000000, 0x8000000000,
0x10000000000, 0x20000000000, 0x40000000000, 0x80000000000,
0x100000000000, 0x200000000000, 0x400000000000, 0x800000000000,
0x1000000000000, 0x2000000000000, 0x4000000000000, 0x8000000000000,
0x10000000000000];
/**************************************/
function $$(id) {
return document.getElementById(id);
}
/**************************************/
function bit(word, bit) {
/* Extracts and returns the specified bit from the word */
var e = 47-bit; // word lower power exponent
var p; // bottom portion of word power of 2
if (e > 0) {
return ((word - word % (p = pow2[e]))/p) % 2;
} else {
return word % 2;
}
};
/**************************************/
function fieldIsolate(word, start, width) {
/* Extracts a bit field [start:width] from word and returns the field */
var le = 48-start-width; // lower power exponent
var p; // bottom portion of word power of 2
return (le == 0 ? word : (word - word % (p = pow2[le]))/p) % pow2[width];
};
/**************************************/
function spout(text) {
/* Appends "text"+NL as a new text node to the panel DOM element */
var e = document.createTextNode(text + "\n");
panel.appendChild(e);
$$("PageBottom").scrollIntoView();
}
/**************************************/
function clearPanel() {
/* Clears the text panel */
var kid;
while (kid = panel.firstChild) {
panel.removeChild(kid);
}
}
/**************************************/
function rtrim(s) {
/* Trims trailing spaces from "s" and returns the resulting string */
var m = s.match(/^(.*?) *$/);
return m[1];
}
/**************************************/
function padToLength(text, len) {
/* Converts the input string "text" to exactly "len" characters,
truncating or padding on the right with spaces as necessary */
var x = text.length;
if (x > len) {
return text.substring(0, len);
} else {
x = len-x;
while (x-- > 0) {
text += " ";
}
return text;
}
}
/**************************************/
function stringToANSI(text, bytes, bx, asBinary) {
/* Translates the characters in a string to upper case, and then to ANSI
byte-array format. "text" is the input string, "bytes" is the Uint8Array
output buffer, and "bx" is the offset into that output buffer. If "asBinary" is
truthy, the translation is binary, otherwise it is done as BCLANSI */
var len = text.length;
var table1 = (asBinary ? BICtoANSI : BICtoBCLANSI);
var utxt = text.toUpperCase();
var x;
bx = bx || 0;
for (x=0; x<len; x++) {
bytes[bx++] = table1[ANSItoBIC[utxt.charCodeAt(x) & 0xFF]];
}
}
/**************************************/
function wordsToANSI(words, wx, wLength, bytes, bx, asBinary) {
/* Translates an array of B5500 words to ANSI byte-array format.
"words" = the array of words
"wx" = the starting index in "words"
"wLength" = the number of words to translate
"bytes" = a Uint8Array array
"bx" = the starting index in "bytes" to store the translated data
"asBinary" = if truthy, then binary translation is done; otherwise
B5500 BCLANSI translation is done */
var c;
var table = (asBinary ? BICtoANSI : BICtoBCLANSI);
var w;
var x;
var y;
var z;
bx = bx || 0;
if (wLength < 0) {
wLength = -wLength;
}
for (x=0; x<wLength; x++) {
w = words[wx+x] || 0;
for (y=0; y<8; y++) {
z = w % 0x40000000000;
c = (w-z)/0x40000000000;
bytes[bx++] = table[c];
w = z*64;
}
}
}
/**************************************/
function wordsToString(words, wx, wLength, asBinary) {
/* Translates an array of B5500 words to a string and returns the string.
"words" = the array of words
"wx" = the starting index in "words"
"wLength" = the number of words to translate
"asBinary" = if truthy, then binary translation is done; otherwise
B5500 BCLANSI translation is done */
var c;
var table = (asBinary ? BICtoANSI : BICtoBCLANSI);
var text = "";
var w;
var x;
var y;
var z;
if (wLength < 0) {
wLength = -wLength;
}
for (x=0; x<wLength; x++) {
w = words[wx+x] || 0;
for (y=0; y<8; y++) {
z = w % 0x40000000000;
c = (w-z)/0x40000000000;
text += String.fromCharCode(table[c]);
w = z*64;
}
}
return text;
}
/**************************************/
function ANSItoWords(bytes, bx, bLength, words, wx, asBinary) {
/* Translates a portion of an ANSI byte array to a sequence of B5500 words.
"bytes" = the Uint8Array byte array
"bx" = 0-relative offset into "bytes"
"bLength" = number of bytes to translate
"words" = the word array
"wx" = 0-relative offset into "words" to store the translated data
"asBinary" = if truthy, then binary translation is done; otherwise
B5500 BCLANSI translation is done */
var cx = 0;
var w = 0;
var table = (asBinary ? ANSItoBIC : BCLANSItoBIC);
var x;
wx = wx || 0;
if (bLength < 0) {
bLength = -bLength;
}
for (x=0; x<bLength; x++) {
if (cx >= 8) {
words[wx++] = w;
w = cx = 0;
}
w = w*64 + table[bytes[bx+x]];
cx++;
}
while (cx++ < 8) {
w *= 64;
}
words[wx++] = w;
}
/**************************************/
function readDiskBlock(addr, segs, block, callback) {
/* Reads a block from the disk "eu" at "addr" for "segs" segments, translates
it to words in the "block" array, then calls "callback" passing the address
and block */
var bx = 0;
var eu;
var euAddr = addr % 1000000;
var euNr = (addr % 10000000 - euAddr)/1000000;
var euName = euPrefix + euNr.toString();
var endAddr = euAddr + segs - 1;
var nextAddr = euAddr;
var range = IDBKeyRange.bound(euAddr, endAddr);
var req;
var txn;
var x;
txn = disk.transaction(euName);
eu = txn.objectStore(euName);
req = eu.openCursor(range);
req.onsuccess = function(ev) {
var cursor = ev.target.result;
if (cursor) {
while (cursor.key > nextAddr) {
for (x=0; x<30; x++) {
block[bx++] = 0;
}
nextAddr++;
}
ANSItoWords(cursor.value, 0, 240, block, bx);
bx += 30;
nextAddr++;
cursor.continue();
} else {
while (nextAddr <= endAddr) {
for (x=0; x<30; x++) {
block[bx++] = 0;
}
nextAddr++;
}
callback(addr, block);
}
};
}
/**************************************/
function readDiskHeader(block) {
/* Decodes "block" as a B5500 disk header, returning the header object */
var header = {
recordLength: 0,
blockLength: 0,
recordsPerBlock: 0,
segmentsPerBlock: 0,
logCreationDate: 0,
logCreationTime: 0,
lastAccessDate: 0,
creationDate: 0,
fileClass: 0,
fileType: 0,
recordCount: 0,
segmentsPerRow: 0,
maxRows: 0,
rowAddress: [],
words: []};
header.recordLength = fieldIsolate(block[0], 0, 15);
header.blockLength = fieldIsolate(block[0], 15, 15);
header.recordsPerBlock = fieldIsolate(block[0], 30, 12);
header.segmentsPerBlock = fieldIsolate(block[0], 42, 6);
header.logCreationDate = fieldIsolate(block[1], 6, 18);
header.logCreationTime = fieldIsolate(block[1], 25, 23);
header.lastAccessDate = fieldIsolate(block[3], 12, 18);
header.creationDate = fieldIsolate(block[3], 30, 18);
header.fileClass = fieldIsolate(block[4], 9, 2);
header.fileType = fieldIsolate(block[4], 36, 6);
header.recordCount = block[7];
header.segmentsPerRow = block[8];
header.maxRows = fieldIsolate(block[9], 43, 5);
header.rowAddress = block.slice(10);
header.words = block; // save the raw header words
return header;
}
/**************************************/
function listFile(fileName) {
/* Opens a sub-window and lists the specified file as text to that window */
var block;
var doc;
var header = headers[fileName];
var htmlMatch = /[<>&"]/g;
var recNr = 0;
var rowAddr;
var rowNr = 0;
var rowEnd;
var win;
function htmlFilter(char) {
/* Used to escape HTML-sensitive characters in a string */
switch (char) {
case "&":
return "&amp;";
case "<":
return "&lt;";
case ">":
return "&gt;";
case "\"":
return "&quot;";
default:
return char;
}
}
function listFileBlock(addr, block) {
/* Lists a block of a file, and if appropriate, calls itself for the next block */
var text;
var x;
for (x=0; x<header.blockLength; x+=header.recordLength) {
text = wordsToString(block, x, header.recordLength, true);
text = text.replace(htmlMatch, htmlFilter);
doc.writeln(text);
if (++recNr > header.recordCount) {
break;
}
}
rowAddr += header.segmentsPerBlock;
if (recNr > header.recordCount) {
rowNr = header.maxRows;
listFileRow(listFileBlock);
} else {
if (rowAddr < rowEnd) {
readDiskBlock(rowAddr, header.segmentsPerBlock, block, listFileBlock);
} else {
rowNr++;
listFileRow(listFileBlock);
}
}
}
function listPBDBlock(addr, block) {
/* Lists a block of a printer-backup file, and if appropriate, calls itself for the next block */
var ctl;
var eof;
var memInhibit;
var logicalRecNr;
var skip;
var space;
var text;
var wordCount;
var x;
for (x=header.blockLength-1; x>0; x-=18) {
ctl = block[x];
logicalRecNr = ctl % 0x8000;
skip = (ctl % 0x80000 - ctl % 0x8000)/0x8000;
space = (ctl % 0x200000 - ctl % 0x80000)/0x80000;
eof = (ctl % 0x10000000 - ctl % 0x8000000)/0x8000000;
memInhibit = (ctl % 0x40000000 - ctl % 0x20000000)/0x20000000;
wordCount = (ctl % 0x8000000000 - ctl % 0x40000000)/0x40000000;
if (memInhibit) {
text = "";
} else {
text = rtrim(wordsToString(block, x-17, wordCount, true));
text = text.replace(htmlMatch, htmlFilter);
}
doc.writeln(text); // can't handle space==0 overprinting yet
if (skip > 0) {
doc.writeln("<hr>");
} else if (space & 0x01) {
doc.writeln(); // double space after print
}
if (eof) {
break;
}
}
rowAddr += header.segmentsPerBlock;
recNr++;
if (eof || recNr > header.recordCount) {
rowNr = header.maxRows;
listFileRow(listPBDBlock);
} else {
if (rowAddr < rowEnd) {
readDiskBlock(rowAddr, header.segmentsPerBlock, block, listPBDBlock);
} else {
rowNr++;
listFileRow(listPBDBlock);
}
}
}
function listFileRow(lister) {
/* Drives the listing of one row of the file */
if (rowNr >= header.maxRows) {
doc.writeln("</pre>");
doc.close();
} else {
rowAddr = header.rowAddress[rowNr];
if (rowAddr) {
rowEnd = rowAddr + header.segmentsPerRow - 1;
readDiskBlock(rowAddr, header.segmentsPerBlock, block, lister);
} else {
rowNr++;
listFileRow(lister);
}
}
}
win = window.open("", "FileListWin", "resizable,scrollbars," +
",left=" + screen.availWidth*0.10 + ",top=" + screen.availHeight*0.10 +
",width=" + screen.availWidth*0.90 + ",height=" + screen.availHeight*0.90);
win.focus();
doc = win.document;
doc.open();
doc.writeln(fileName);
doc.writeln("<br><pre>");
doc.title = fileName;
block = new Array(header.blockLength);
if (fileName.indexOf("PBD/") == 0 & header.recordLength == 90 && header.blockLength == 90) {
listFileRow(listPBDBlock);
} else {
listFileRow(listFileBlock);
}
}
/**************************************/
function formatDirectoryEntry(body, mfid, fid, header) {
/* Formats the disk header for a file */
var cell;
var e;
var fileName;
var row = document.createElement("tr");
var rx;
var text = "";
function appendCell(row, v, className) {
var cell = document.createElement("td");
if (className && className.search(/\S/) >= 0) {
cell.className = className;
}
cell.appendChild(document.createTextNode(v.toString()));
row.appendChild(cell);
}
fileName = rtrim(mfid.substring(1)) + "/" + rtrim(fid.substring(1));
cell = document.createElement("td");
cell.className = "mono";
e = document.createElement("a");
e.appendChild(document.createTextNode(fileName));
e.href = "#";
e.addEventListener("click", (function(name) {
return function(ev) {ev.preventDefault(); listFile(name)};
})(fileName));
cell.appendChild(e);
row.appendChild(cell);
appendCell(row, header.recordLength, "rj");
appendCell(row, header.blockLength, "rj");
appendCell(row, header.recordsPerBlock, "rj");
appendCell(row, header.segmentsPerBlock, "rj");
appendCell(row, header.logCreationDate);
appendCell(row, header.logCreationTime);
appendCell(row, header.lastAccessDate);
appendCell(row, header.creationDate);
appendCell(row, header.fileClass, "rj");
appendCell(row, header.fileType, "rj");
appendCell(row, header.recordCount, "rj");
appendCell(row, header.segmentsPerRow, "rj");
appendCell(row, header.maxRows, "rj");
body.appendChild(row);
headers[fileName] = header;
}
/**************************************/
function directoryList(successor) {
/* Reads the existing directory structure to generate a list of the files
in the directory. When finished, calls the "successor" function */
var block = new Array(480);
var body = $$("DirListBody");
function reportDirBlock(addr, block) {
/* Lists the entries in the resulting block; if not the last block,
advances to the next block */
var atEnd = false;
var bx;
var fid;
var mfid;
var namex;
// Step through the file name entries backwards
for (namex=14; namex>=0; namex--) {
bx = namex*2 + 450;
if (block[bx] == 0x4C) { // 0x4C=@114, end-of-directory marker
atEnd = true;
break;
} else if (block[bx] != 0x0C) { // 0x0C=@14, available directory slot
// Got a live one -- format its header
mfid = wordsToString(block, bx, 1, true);
fid = wordsToString(block, bx+1, 1, true);
bx = namex*30;
formatDirectoryEntry(body, mfid, fid, readDiskHeader(block.slice(bx, bx+30)));
}
}
if (atEnd) {
successor();
} else {
readDiskBlock(addr+16, 16, block, reportDirBlock);
}
}
/***** outer block of directoryList *****/
while (body.firstChild) {
body.removeChild(body.firstChild);
}
if (!config.EU0) {
alert("No EU0 in disk configuration -- cannot load");
} else {
readDiskBlock(directoryTop+4, 16, block, reportDirBlock);
}
}
/**************************************/
function genericDBError(ev) {
/* Formats a generic alert when otherwise-unhandled database errors occur */
var disk = ev.currentTarget.result;
alert("Database \"" + disk.name + "\" error: " + ev.target.result.error);
}
/**************************************/
function openDatabase(name, version, successor) {
/* Attempts to open the disk subsystem database for the specified "name"
and "version". Stores the IDB database object in "disk" if successful, or
stores null if unsuccessful. Also gets directoryTop from seg 0 */
var block = new Array(30);
var db = null;
var req;
req = window.indexedDB.open(name, version);
req.onerror = function(ev) {
alert("Cannot open disk database: " + ev.target.error);
};
req.onblocked = function(ev) {
alert("Database.open is blocked -- cannot continue");
};
req.onsuccess = function(ev) {
disk = ev.target.result; // save the object reference globally for later use
disk.onerror = genericDBError;
// alert("Disk database opened: " + name + " #" + disk.version);
disk.transaction("CONFIG").objectStore("CONFIG").get(0).onsuccess = function(ev) {
config = ev.target.result;
readDiskBlock(0, 1, block, function(addr, block) {
directoryTop = block[1];
directoryEnd = block[4];
successor();
});
};
};
}
/**************************************/
function checkBrowser() {
/* Checks whether this browser can support the necessary stuff */
var missing = "";
if (!window.File) {missing += ", File"}
if (!window.FileReader) {missing += ", FileReader"}
if (!window.FileList) {missing += ", FileList"}
if (!window.Blob) {missing += ", Blob"}
if (!window.ArrayBuffer) {missing += ", ArrayBuffer"}
if (!window.DataView) {missing += ", DataView"}
if (!window.indexedDB) {missing += ", IndexedDB"}
if (missing.length == 0) {
return false;
} else {
alert("No can do... your browser does not support the following features:\n" +
missing.substring(2));
return true;
}
}
/********** Start of window.onload() **********/
if (!checkBrowser()) {
openDatabase(dbName, dbVersion, function() {
directoryList(function() {});
});
}
}
</script>
<style>
BODY {
font-family: Arial, Helvetica, sans-serif;
font-size: small}
TABLE {
border-collapse: collapse}
TH {
vertical-align: bottom}
.center {
text-align: center}
.rj {
text-align: right}
.mono {
font-family: Courier New, Courier, monospace}
</style>
</head>
<body>
<div style="position:relative; width:100%; height:3em">
<div style="position:absolute; left:0; top:0; width:auto">
<img src="../webUI/retro-B5500-Logo.png" alt="retro-B5500 Logo" style="float:left">
&nbsp;Disk File List Utility
</div>
</div>
<table id=DirListTable border=1 cellspacing=0 cellpadding=1>
<thead>
<tr>
<th>File Name
<th>REC
<th>BLK
<th>RPB
<th>SPB
<th>LCD
<th>LCT
<th>LAD
<th>CRD
<th>FCL
<th>FTY
<th>CNT
<th>SPR
<th>MXR
<tbody id=DirListBody>
</table>
<pre id=TextPanel>
</pre>
<div id=PageBottom>
</div>
</body>
</html>

View File

@@ -180,6 +180,7 @@ WHILE NOT READ(SOURCE, 15, REC) DO 00900900
00903200
SCANNER; 00903300
IF TOKEN ^= 48"01""$" THEN 00903400
BEGIN 00903402
IF POPCOUNT > 0 THEN 00903405
BEGIN 00903410
REPLACE PREC BY " " FOR 72, THISSEQNR-1 FOR 8 DIGITS, " " FOR 10; 00903415
@@ -191,6 +192,7 @@ WHILE NOT READ(SOURCE, 15, REC) DO 00900900
END WHILE; 00903445
WRITE(PATCH, 15, PREC); 00903450
END; 00903455
END 00903456
ELSE 00903460
BEGIN 00903500
SCANNER; 00903600

View File

@@ -1,6 +1,6 @@
<!DOCTYPE html>
<head>
<title>B5500 Coldstart Disk Subsystem Loader</title>
<title>B5500 Disk Subsystem Coldstart Loader</title>
<meta name="Author" content="Paul Kimpel">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Content-Script-Type" content="text/javascript">
@@ -8,13 +8,13 @@
<script>
/***********************************************************************
* retro-b5500/tools B5500ColdLoader.html
* retro-b5500/webUI B5500ColdLoader.html
************************************************************************
* Copyright (c) 2012, Paul Kimpel.
* Licensed under the MIT License,
* see http://www.opensource.org/licenses/mit-license.php
************************************************************************
* B5500 Coldstart Disk Subsystem Loader.
* B5500 Disk Subsystem Coldstart Loader.
*
* This script opens an IndexedDB database in the browser (creating it first, if
* necessary) and initializes it as a B5500 Head-per-Track disk file subsystem.
@@ -108,7 +108,7 @@ window.onload = function() {
0x7C,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50, // 20-27, @40-47
0x51,0x52,0x24,0x2A,0x2D,0x29,0x3B,0x7B, // 28-2F, @50-57
0x20,0x2F,0x53,0x54,0x55,0x56,0x57,0x58, // 30-37, @60-67
0x59,0x5A,0x2C,0x25,0x21,0x3D,0x5D,0x23]; // 38-3F, @70-77
0x59,0x5A,0x2C,0x25,0x21,0x3D,0x5D,0x22]; // 38-3F, @70-77
var BICtoBCLANSI = [ // Index by 6-bit BIC to get 8-bit BCL-as-ANSI code
0x23,0x31,0x32,0x33,0x34,0x35,0x36,0x37, // 00-07, @00-07
@@ -268,6 +268,27 @@ window.onload = function() {
}
}
/**************************************/
function ANSItoString(bytes, bx, bLength, asBinary) {
/* Translates a portion of an ANSI byte array to a string and returns it.
"bytes" = the Uint8Array byte array
"bx" = 0-relative offset into "bytes"
"bLength" = number of bytes to translate
"asBinary" = if truthy, then binary translation is done; otherwise
B5500 BCLANSI translation is done */
var table = (asBinary ? ANSItoBIC : BCLANSItoBIC);
var text = "";
var x;
if (bLength < 0) {
bLength = -bLength;
}
for (x=0; x<bLength; x++) {
text += BICtoANSIChar[table[bytes[bx+x]]];
}
return text;
}
/**************************************/
function wordsToANSI(words, wx, wLength, bytes, bx, asBinary) {
/* Translates an array of B5500 words to ANSI byte-array format.
@@ -925,7 +946,7 @@ window.onload = function() {
availBlock = block;
}
break;
} else if (block[bx] == 0x12) { // 0x12=@14, available directory slot
} else if (block[bx] == 0x0C) { // 0x0C=@14, available directory slot
if (availAddr < 0) {
availAddr = addr;
availSlot = namex;
@@ -1114,6 +1135,7 @@ window.onload = function() {
var atEnd = false;
var bx;
var namex;
var rowAddr;
var rowMax;
var rowSize;
var rx;
@@ -1124,14 +1146,15 @@ window.onload = function() {
if (block[bx] == 0x4C) { // 0x4C=@114, end-of-directory marker
atEnd = true;
break;
} else if (block[bx] != 0x12) { // 0x12=@14, available directory slot
} else if (block[bx] != 0x0C) { // 0x0C=@14, available directory slot
// Got a live one -- complement its in-use space
bx = namex*30;
rowSize = block[bx+8];
rowMax = fieldIsolate(block[bx+9], 43, 5);
for (rx=0; rx<rowMax; rx++) {
if (block[bx+10+rx] > 0) {
removeAvailable(block[bx+10+rx], rowSize);
rowAddr = block[bx+10+rx];
if (rowAddr > 0 && rowAddr < 1000000) { // ignore rows not on EU0
removeAvailable(rowAddr, rowSize);
}
}
}
@@ -1650,6 +1673,30 @@ window.onload = function() {
fileNr++;
}
function createSystemLog(areasize) {
/* Creates an empty SYSTEM/LOG file. This uses the same mechanism as enterFile(),
so do not call this plus enterFile() more than 15 times */
var header = [];
var labelx = 240-(fileNr+1)*16;
stringToANSI(padToLength("SYSTEM", 7), fileLabels, labelx+1);
stringToANSI(padToLength("LOG", 7), fileLabels, labelx+9);
if (labelx > 15) {
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[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++;
}
function initializeDirectory(config) {
/* Initializes the directory structure on EU0. "config" is the
database CONFIG structure */
@@ -1721,7 +1768,7 @@ window.onload = function() {
// 16: olay core to ECM(AUXMEM)
pow2[47-15] + // 15: job core estimates(STATISTICS)
// 14: olay data to ECM(AUXMEM)
pow2[47-13] + // 13: makes system hang on-should HL msg
pow2[47-13] + // 13: makes system hang on should-HL msg
// 12: enables datacom(TSS, if not DCP)
pow2[47-11] + // 11: library messages for CANDE
pow2[47-10] + // 10: ZIP decks to run on batch(SHAREDISK)
@@ -1768,7 +1815,8 @@ window.onload = function() {
eu.put(buffer, directoryTop);
// Create a file entry for the system log
enterFile("SYSTEM", "LOG", 1, 20000);
createSystemLog(20000);
/** enterFile("SYSTEM", "LOG", 1, 20000); **/
// Store the directory labels segment
eu.put(fileLabels, directoryTop + 19); // write the directory block file labels
@@ -1871,7 +1919,7 @@ window.onload = function() {
if (cursor.key-lastKey > 1) {
spout("----- " + (cursor.key-lastKey-1) + " unallocated segments -----");
}
spout(cursor.key + ": " + String.fromCharCode.apply(null, cursor.value));
spout(cursor.key + ": " + ANSItoString(cursor.value, 0, cursor.value.length));
lastKey = cursor.key;
cursor.continue();
} else {
@@ -1960,6 +2008,8 @@ window.onload = function() {
BODY {
font-family: Arial, Helvetica, sans-serif;
font-size: small}
TABLE {
border-collapse: collapse}
TH {
vertical-align: bottom}
DIV#TapeDirDiv {
@@ -1977,7 +2027,8 @@ TBODY#TapeDirBody {
<div style="position:relative; width:100%; height:3em">
<div style="position:absolute; left:0; top:0; width:auto">
retro-B5500 Coldstart Disk SubSystem Loader
<img src="../webUI/retro-B5500-Logo.png" alt="retro-B5500 Logo" style="float:left">
&nbsp;Disk SubSystem Coldstart Loader
</div>
<div style="text-align:center">
<input id=ColdstartBtn type=button value="Cold Start" DISABLED>

View File

@@ -148,6 +148,10 @@ TABLE#CentralControl {
font-size: 10px;
font-weight: bold}
TD#procRate, TD#procSlack {
color: white;
text-align: right}
.busy {
color: white}

View File

@@ -25,6 +25,8 @@ window.onload = function() {
var boundBlinkenlicht;
var cc = new B5500CentralControl();
var lastBusyMask = 0;
var procRate;
var procSlack;
var timer;
var timerInterval = 50; // milliseconds
@@ -63,12 +65,6 @@ window.onload = function() {
cc.halt();
$$("HaltBtn").disabled = true;
$$("LoadBtn").disabled = false;
/*****
if (timer) {
clearTimeout(timer);
timer = null;
}
*****/
}
function LoadBtn_Click(ev) {
@@ -111,6 +107,7 @@ window.onload = function() {
}
function dasBlinkenlicht() {
var et;
var pa = cc.PA;
var pb = cc.PB;
@@ -127,6 +124,9 @@ window.onload = function() {
aControl.className = "yellowButton yellowLit";
}
}
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) {
@@ -179,6 +179,8 @@ window.onload = function() {
aNormal = $$("ANormalBtn");
bControl = $$("BControlBtn");
bNormal = $$("BNormalBtn");
procRate = $$("procRate");
procSlack = $$("procSlack");
boundBlinkenlicht = bindMethod(dasBlinkenlicht, this);
}
};
@@ -206,7 +208,7 @@ window.onload = function() {
<div id=BurroughsLogo>
<img id=BurroughsLogoImage src="Burroughs-Logo-Neg.jpg">
</div>
<div id=B5500Logo> B 5500 </div>
<div id=B5500Logo><img src="retro-B5500-Logo.png" alt="retro-B5500 logo"><!-- B 5500 --></div>
<table id=CentralControl>
<colgroup>
@@ -233,6 +235,7 @@ window.onload = function() {
<td id=CCI15F>DK1F <!-- Disk file #1 read check finished -->
<td id=CCI16F>DK2F <!-- Disk file #2 read check finished -->
<td colspan=13>
<td id=procSlack>
<tr id=CCPeripheralRow>
<td id=DCA>DCA <!-- 17 -->
<td id=PPB>PPB <!-- 18 -->
@@ -265,6 +268,7 @@ window.onload = function() {
<td id=MTC>MTC <!-- 45 -->
<td id=MTB>MTB <!-- 46 -->
<td id=MTA>MTA <!-- 47 -->
<td id=procRate>
</table>
</div>

View File

@@ -195,7 +195,7 @@ B5500DiskUnit.prototype.read = function(finish, buffer, length, mode, control) {
euSize = this.config[euName];
if (!euSize) { // EU does not exist
finish(this.errorMask | 0x20, 0); // set D27F for EU not ready
finish(this.errorMask | 0x20, 0); // set D27F for EU not ready/not present
this.errorMask = 0;
} else if (segAddr < 0) {
finish(this.errorMask | 0x20, 0); // set D27F for invalid starting seg address

View File

@@ -365,7 +365,7 @@ B5500SPOUnit.prototype.keyDown = function(ev) {
result = false;
break;
case 8: // Backspace
setTimeout(that.backspaceChar(), nextTime-stamp);
setTimeout(this.backspaceChar, nextTime-stamp);
result = false;
break;
case 13: // Enter

View File

@@ -712,9 +712,16 @@ function runIt(ev) {
stopAddress = 0;
}
/***************************
if (cc.P1.R != 0) {
alert("P1.R not zero");
stopAddress = 0;
if (cc.P1.C < 0x40) {
// There is an interrupt
switch (cc.P1.C) {
case 0x31: // P1 invalid address
case 0x32: // P1 stack overflow
case 0x3C: // P1 integer overflow
alert("Unexpected Processor Interrupt occurred");
stopAddress = 0;
break;
}
}
***************************/
if (--count <= 0) {
@@ -865,6 +872,10 @@ function fileSelector_onChange(ev) {
function hardwareLoad_onClick(ev) {
/* Handle the "Hardware Load" button click */
cc.clear();
cc.P1.clear();
cc.load(true);
}
function checkBrowser() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
webUI/retro-B5500-Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B