mirror of
https://github.com/pkimpel/retro-b5500.git
synced 2026-04-25 20:01:52 +00:00
1. Release emulator version 0.09.
2. Implement differential read vs. write memory cycle timing (2us vs 4us). 3. Implement setImmediate() instead of SetTimeout() for I/O forking in IOUnit. 4. Time I/Os from initiation in IOUnit instead of peripheral device driver. 5. Accumulate Control and Normal state clocks separately for use in UI displays. 6. Rework Processor.schedule() delay management for use with setImmediate() 7. Accumulate average processor delay delta for use in UI displays. 8. Enable third I/O unit and all eight memory modules in B5500SystemConfiguration. 9. Clone B5500LibMaintDir.html from B5500LibMaintMapper.html to list files on a tape image. 10. Implement multiple-file selection in B5500CardReader; fix markup for Firefox 22. 11. Implement more granular Control/Normal State light intensity and PA Delay delta in B5500Console. 12. Attempt (again) to fix creation of SYSTEM/LOG file in B5500ColdLoader. 13. Create tools/LOG-MAKER.job deck to create SYSTEM/LOG on a running emulator instance.
This commit is contained in:
Binary file not shown.
@@ -61,9 +61,11 @@ function B5500CentralControl() {
|
||||
/**************************************/
|
||||
/* Global constants */
|
||||
|
||||
B5500CentralControl.version = "0.08";
|
||||
B5500CentralControl.version = "0.09";
|
||||
|
||||
B5500CentralControl.memCycles = 4; // assume 4 µs memory cycle time (the other option was 6 µs)
|
||||
B5500CentralControl.memReadCycles = 2; // assume 2 µs memory read cycle time (the other option was 3 µs)
|
||||
B5500CentralControl.memWriteCycles = 4; // assume 4 µs memory write cycle time (the other option was 6 µs)
|
||||
B5500CentralControl.minDelay = 4; // minimum setTimeout() delay, ms
|
||||
B5500CentralControl.rtcTick = 1000/60; // Real-time clock period, milliseconds
|
||||
|
||||
B5500CentralControl.pow2 = [ // powers of 2 from 0 to 52
|
||||
@@ -570,7 +572,12 @@ B5500CentralControl.prototype.tock = function tock() {
|
||||
}
|
||||
}
|
||||
interval = (this.nextTimeStamp += B5500CentralControl.rtcTick) - thisTime;
|
||||
this.timer = setTimeout(this.boundTock, (interval < 1 ? 1 : interval));
|
||||
if (interval >= B5500CentralControl.minDelay) {
|
||||
this.timer = setTimeout(this.boundTock, interval);
|
||||
} else {
|
||||
this.timer = null;
|
||||
setImmediate(this.boundTock);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -732,11 +739,11 @@ B5500CentralControl.prototype.halt = function halt() {
|
||||
}
|
||||
|
||||
if (this.PA && this.PA.busy) {
|
||||
this.PA.halt();
|
||||
this.PA.stop();
|
||||
}
|
||||
|
||||
if (this.PB && this.PB.busy) {
|
||||
this.PB.halt();
|
||||
this.PB.stop();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -787,8 +794,8 @@ B5500CentralControl.prototype.load = function load(dontStart) {
|
||||
|
||||
if (this.P1 && !this.P1.busy) {
|
||||
this.clear();
|
||||
this.nextTimeStamp = new Date().getTime() + B5500CentralControl.rtcTick;
|
||||
this.timer = setTimeout(this.boundTock, B5500CentralControl.rtcTick);
|
||||
this.nextTimeStamp = new Date().getTime();
|
||||
this.tock();
|
||||
this.LOFF = 1;
|
||||
if (this.IO1 && this.IO1.REMF && !this.AD1F) {
|
||||
this.AD1F = 1;
|
||||
|
||||
@@ -45,7 +45,7 @@ function B5500IOUnit(ioUnitID, cc) {
|
||||
this.ioUnitID = ioUnitID; // I/O Unit ID ("1", "2", "3", or "4")
|
||||
this.cc = cc; // Reference back to Central Control module
|
||||
|
||||
this.forkHandle = null; // Reference to current setTimeout id
|
||||
this.forkHandle = null; // Reference to current setImmediate id
|
||||
this.accessor = { // Memory access control block
|
||||
requestorID: ioUnitID, // Memory requestor ID
|
||||
addr: 0, // Memory address
|
||||
@@ -68,6 +68,8 @@ function B5500IOUnit(ioUnitID, cc) {
|
||||
this.boundFinishDiskRead = this.makeFinish(this.finishDiskRead);
|
||||
this.boundFinishSPORead = this.makeFinish(this.finishSPORead);
|
||||
|
||||
this.initiateStamp = 0; // Timestamp of last I/O initiation on this unit
|
||||
|
||||
this.clear(); // Create and initialize the processor state
|
||||
}
|
||||
|
||||
@@ -173,14 +175,13 @@ B5500IOUnit.prototype.clear = function clear() {
|
||||
this.busy = 0; // I/O Unit is busy
|
||||
this.busyUnit = 0; // Peripheral unit index currently assigned to the I/O Unit
|
||||
|
||||
this.cycleCount = 0; // Current cycle count for this.run()
|
||||
this.cycleLimit = 0; // Cycle limit for this.run()
|
||||
this.cycleCount = 0; // Current cycle count for this I/O unit
|
||||
this.totalCycles = 0; // Total cycles executed on this I/O Unit
|
||||
this.ioUnitTime = 0; // Total I/O Unit running time, based on cycles executed
|
||||
this.ioUnitSlack = 0; // Total I/O Unit throttling delay, milliseconds
|
||||
|
||||
if (this.forkHandle) {
|
||||
clearTimeout(this.forkHandle);
|
||||
clearImmediate(this.forkHandle);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -216,7 +217,7 @@ B5500IOUnit.prototype.fetch = function fetch(addr) {
|
||||
this.cc.fetch(acc);
|
||||
this.W = acc.word;
|
||||
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memReadCycles;
|
||||
if (acc.MAED) {
|
||||
this.D26F = 1; // set memory address error
|
||||
return 1;
|
||||
@@ -238,7 +239,7 @@ B5500IOUnit.prototype.store = function store(addr) {
|
||||
acc.word = this.W;
|
||||
this.cc.store(acc);
|
||||
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memWriteCycles;
|
||||
if (acc.MAED) {
|
||||
this.D26F = 1; // set memory address error
|
||||
return 1;
|
||||
@@ -732,7 +733,7 @@ B5500IOUnit.prototype.forkIO = function forkIO() {
|
||||
var u; // peripheral unit object
|
||||
var x; // temp number variable
|
||||
|
||||
this.forkHandle = null; // clear the setTimeout() handle
|
||||
this.forkHandle = null; // clear the setImmediate() handle
|
||||
|
||||
x = this.D; // explode the D-register into its fields
|
||||
this.Dunit = (x%0x200000000000 - x%0x10000000000)/0x10000000000; // [3:5]
|
||||
@@ -756,6 +757,7 @@ B5500IOUnit.prototype.forkIO = function forkIO() {
|
||||
} else {
|
||||
this.cc.setUnitBusy(index, 1);
|
||||
u = this.cc.unit[index];
|
||||
u.initiateStamp = this.initiateStamp;
|
||||
|
||||
switch(this.Dunit) {
|
||||
// disk designates
|
||||
@@ -846,6 +848,7 @@ B5500IOUnit.prototype.initiate = function initiate() {
|
||||
environment, all of the Javascript action occurs on one thread, so this allows us to
|
||||
multiplex what are supposed to be asynchronous operations on that thread */
|
||||
|
||||
this.initiateStamp = new Date().getTime();
|
||||
this.clearD();
|
||||
this.AOFF = 0;
|
||||
this.EXNF = 0;
|
||||
@@ -860,7 +863,7 @@ B5500IOUnit.prototype.initiate = function initiate() {
|
||||
} else {
|
||||
this.D31F = 0; // reset the IOD-fetch error condition
|
||||
this.D = this.W;
|
||||
this.forkHandle = setTimeout(this.boundForkIO, 0);
|
||||
this.forkHandle = setImmediate(this.boundForkIO);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -893,6 +896,7 @@ B5500IOUnit.prototype.initiateLoad = function initiateLoad(cardLoadSelect, loadC
|
||||
loadComplete();
|
||||
}
|
||||
|
||||
this.initiateStamp = new Date().getTime();
|
||||
this.clearD();
|
||||
if (cardLoadSelect) {
|
||||
this.D = 0x0A0004800010; // unit 10, read, binary mode, addr @00020
|
||||
@@ -917,6 +921,7 @@ B5500IOUnit.prototype.initiateLoad = function initiateLoad(cardLoadSelect, loadC
|
||||
} else {
|
||||
this.cc.setUnitBusy(index, 1);
|
||||
u = this.cc.unit[index];
|
||||
u.initiateStamp = this.initiateStamp;
|
||||
u.read(this.makeFinish(finishLoad), this.buffer, chars, this.D21F, 1);
|
||||
}
|
||||
};
|
||||
@@ -48,13 +48,16 @@ function B5500Processor(procID, cc) {
|
||||
this.boundSchedule = B5500CentralControl.bindMethod(this.schedule, this);
|
||||
|
||||
this.clear(); // Create and initialize the processor state
|
||||
|
||||
this.delayDeltaAvg = 0; // Average difference between requested and actual setTimeout() delays, ms
|
||||
this.delayLastStamp = 0; // Timestamp of last setTimeout() delay, ms
|
||||
this.delayRequested = 0; // Last requested setTimeout() delay, ms
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
|
||||
B5500Processor.timeSlice = 4000; // this.run() timeslice, clocks
|
||||
B5500Processor.minDelay = 4; // minimum schedule() delay, ms
|
||||
B5500Processor.maxDelay = 20; // maximum schedule() delay, ms
|
||||
B5500Processor.delaySamples = 1000; // this.delayThreshold sampling average basis
|
||||
|
||||
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
|
||||
@@ -111,8 +114,11 @@ B5500Processor.prototype.clear = function clear() {
|
||||
this.US14X = 0; // STOP OPERATOR switch
|
||||
|
||||
this.busy = 0; // Processor is running, not idle or halted
|
||||
this.cycleCount = 0; // Current cycle count for this.run()
|
||||
this.controlCycles = 0; // Current control-state cycle count (for UI display)
|
||||
this.cycleCount = 0; // Cycle count for current syllable
|
||||
this.cycleLimit = 0; // Cycle limit for this.run()
|
||||
this.normalCycles = 0; // Current normal-state cycle count (for UI display)
|
||||
this.runCycles = 0; // Current cycle cound for this.run()
|
||||
this.totalCycles = 0; // Total cycles executed on this processor
|
||||
this.procStart = 0; // Javascript time that the processor started running, ms
|
||||
this.procTime = 0.001; // Total processor running time, ms
|
||||
@@ -145,7 +151,7 @@ B5500Processor.prototype.loadAviaS = function loadAviaS() {
|
||||
acc.addr = this.S;
|
||||
acc.MAIL = (this.S < 0x0200 && this.NCSF);
|
||||
this.cc.fetch(acc);
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memReadCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
} else {
|
||||
@@ -163,7 +169,7 @@ B5500Processor.prototype.loadBviaS = function loadBviaS() {
|
||||
acc.addr = this.S;
|
||||
acc.MAIL = (this.S < 0x0200 && this.NCSF);
|
||||
this.cc.fetch(acc);
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memReadCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
} else {
|
||||
@@ -181,7 +187,7 @@ B5500Processor.prototype.loadAviaM = function loadAviaM() {
|
||||
acc.addr = this.M;
|
||||
acc.MAIL = (this.M < 0x0200 && this.NCSF);
|
||||
this.cc.fetch(acc);
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memReadCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
} else {
|
||||
@@ -199,7 +205,7 @@ B5500Processor.prototype.loadBviaM = function loadBviaM() {
|
||||
acc.addr = this.M;
|
||||
acc.MAIL = (this.M < 0x0200 && this.NCSF);
|
||||
this.cc.fetch(acc);
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memReadCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
} else {
|
||||
@@ -217,7 +223,7 @@ B5500Processor.prototype.loadMviaM = function loadMviaM() {
|
||||
acc.addr = this.M;
|
||||
acc.MAIL = (this.M < 0x0200 && this.NCSF);
|
||||
this.cc.fetch(acc);
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memReadCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
} else {
|
||||
@@ -235,7 +241,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 += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memReadCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
} else {
|
||||
@@ -253,7 +259,7 @@ B5500Processor.prototype.storeAviaS = function storeAviaS() {
|
||||
acc.MAIL = (this.S < 0x0200 && this.NCSF);
|
||||
acc.word = this.A;
|
||||
this.cc.store(acc);
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memWriteCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
}
|
||||
@@ -269,7 +275,7 @@ B5500Processor.prototype.storeBviaS = function storeBviaS() {
|
||||
acc.MAIL = (this.S < 0x0200 && this.NCSF);
|
||||
acc.word = this.B;
|
||||
this.cc.store(acc);
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memWriteCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
}
|
||||
@@ -285,7 +291,7 @@ B5500Processor.prototype.storeAviaM = function storeAviaM() {
|
||||
acc.MAIL = (this.M < 0x0200 && this.NCSF);
|
||||
acc.word = this.A;
|
||||
this.cc.store(acc);
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memWriteCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
}
|
||||
@@ -301,7 +307,7 @@ B5500Processor.prototype.storeBviaM = function storeBviaM() {
|
||||
acc.MAIL = (this.M < 0x0200 && this.NCSF);
|
||||
acc.word = this.B;
|
||||
this.cc.store(acc);
|
||||
this.cycleCount += B5500CentralControl.memCycles;
|
||||
this.cycleCount += B5500CentralControl.memWriteCycles;
|
||||
if (acc.MAED || acc.MPED) {
|
||||
this.accessError();
|
||||
}
|
||||
@@ -1340,7 +1346,9 @@ B5500Processor.prototype.start = function start() {
|
||||
this.busy = 1;
|
||||
this.procStart = stamp;
|
||||
this.procTime -= stamp;
|
||||
this.scheduler = setTimeout(this.boundSchedule, 0);
|
||||
this.delayLastStamp = stamp;
|
||||
this.delayRequested = 0;
|
||||
setImmediate(this.boundSchedule);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -2176,7 +2184,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 += B5500CentralControl.memCycles*4 + 8;
|
||||
this.cycleCount += B5500CentralControl.memWriteCycles*4 + 8;
|
||||
|
||||
this.adjustABFull(); // extract the top (A) operand fields:
|
||||
ma = this.A % 0x8000000000; // extract the A mantissa
|
||||
@@ -2873,6 +2881,7 @@ B5500Processor.prototype.run = function run() {
|
||||
this.Y = 0;
|
||||
this.Z = 0;
|
||||
opcode = this.T;
|
||||
this.cycleCount = 1; // general syllable execution overhead
|
||||
|
||||
if (this.CWMF) {
|
||||
/***********************************************************
|
||||
@@ -4560,7 +4569,13 @@ B5500Processor.prototype.run = function run() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while ((this.cycleCount += 1) < this.cycleLimit);
|
||||
|
||||
if (this.NCSF) {
|
||||
this.normalCycles += this.cycleCount;
|
||||
} else {
|
||||
this.controlCycles += this.cycleCount;
|
||||
}
|
||||
} while ((this.runCycles += this.cycleCount) < this.cycleLimit);
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -4577,33 +4592,40 @@ B5500Processor.prototype.schedule = function schedule() {
|
||||
Javascript execution thread */
|
||||
var clockOff; // ending time for this run() call, ms
|
||||
var delayTime; // delay until next run() for this processor, ms
|
||||
var runTime = this.procTime; // real-world processor running time, ms
|
||||
var runTime; // real-world processor running time, ms
|
||||
|
||||
this.scheduler = null;
|
||||
this.cycleLimit = B5500Processor.timeSlice;
|
||||
this.cycleCount = 0;
|
||||
this.runCycles = 0;
|
||||
|
||||
this.run(); // execute syllables for the timeslice
|
||||
|
||||
clockOff = new Date().getTime();
|
||||
runTime = this.procTime;
|
||||
while (runTime < 0) {
|
||||
runTime += clockOff;
|
||||
}
|
||||
this.totalCycles += this.cycleCount;
|
||||
this.totalCycles += this.runCycles;
|
||||
if (this.delayRequested) {
|
||||
delayTime = clockOff - this.delayLastStamp - this.delayRequested;
|
||||
this.delayDeltaAvg = (this.delayDeltaAvg*(B5500Processor.delaySamples-1) +
|
||||
delayTime)/B5500Processor.delaySamples;
|
||||
}
|
||||
|
||||
if (this.busy) {
|
||||
// delayTime is the number of milliseconds the processor is running ahead of
|
||||
// real-world time. Web browsers have a certain minimum delay. If the delay
|
||||
// is less than that, we yield to the event loop, but otherwise continue (real
|
||||
// time should eventually catch up -- we hope)
|
||||
delayTime = this.totalCycles/1000 - runTime;
|
||||
if (delayTime < B5500Processor.minDelay) {
|
||||
this.delayLastStamp = clockOff;
|
||||
if (delayTime < B5500CentralControl.minDelay) {
|
||||
this.delayRequested = 0;
|
||||
setImmediate(this.boundSchedule); // just execute pending events
|
||||
} else {
|
||||
if (delayTime > B5500Processor.maxDelay) {
|
||||
delayTime = B5500Processor.maxDelay;
|
||||
}
|
||||
this.procSlack += delayTime;
|
||||
this.scheduler = setTimeout(this.boundSchedule, delayTime);
|
||||
this.delayRequested = delayTime;
|
||||
this.procSlack += delayTime;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -4615,10 +4637,9 @@ B5500Processor.prototype.step = function step() {
|
||||
or two injected instructions (e.g., SFI followed by ITI) could also be executed */
|
||||
|
||||
this.cycleLimit = 1;
|
||||
this.cycleCount = 0;
|
||||
this.runCycles = 0;
|
||||
|
||||
this.run();
|
||||
|
||||
this.totalCycles += this.cycleCount;
|
||||
this.procTime += this.cycleCount;
|
||||
this.totalCycles += this.runCycles;
|
||||
};
|
||||
|
||||
@@ -24,14 +24,14 @@ var B5500SystemConfiguration = {
|
||||
|
||||
IO1: true, // I/O Unit 1 available
|
||||
IO2: true, // I/O Unit 2 available
|
||||
IO3: false, // I/O Unit 3 available
|
||||
IO3: true, // I/O Unit 3 available
|
||||
IO4: false, // I/O Unit 4 available
|
||||
|
||||
memMod: [
|
||||
true, // Memory module 0 available (4KW)
|
||||
true, // Memory module 1 available (4KW)
|
||||
false, // Memory module 2 available (4KW)
|
||||
false, // Memory module 3 available (4KW)
|
||||
true, // Memory module 2 available (4KW)
|
||||
true, // Memory module 3 available (4KW)
|
||||
true, // Memory module 4 available (4KW)
|
||||
true, // Memory module 5 available (4KW)
|
||||
true, // Memory module 6 available (4KW)
|
||||
|
||||
59
index.css
59
index.css
@@ -1,59 +0,0 @@
|
||||
/***********************************************************************
|
||||
* 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
45
index.html
@@ -1,45 +0,0 @@
|
||||
<!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 • Licensed under the MIT License
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
617
tools/B5500LibMaintDir.html
Normal file
617
tools/B5500LibMaintDir.html
Normal file
@@ -0,0 +1,617 @@
|
||||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>B5500 LibMaint Directory</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 B5500LibMaintDir.html
|
||||
************************************************************************
|
||||
* Copyright (c) 2013, Paul Kimpel.
|
||||
* Licensed under the MIT License,
|
||||
* see http://www.opensource.org/licenses/mit-license.php
|
||||
************************************************************************
|
||||
* B5500 Library Maintenance tape file direectory list.
|
||||
*
|
||||
* This script reads a Burroughs B5500 Library/Maintenance tape as one
|
||||
* large blob and outputs directory information for all files.
|
||||
*
|
||||
* The blob is assumed to be in the so-called ".bcd" format. Each 7-bit frame
|
||||
* from the tape is represented as one 8-bit unsigned byte. The low-order six
|
||||
* bits (mask 0x3F) contain the character value. The next bit (mask 0x40) is
|
||||
* the parity bit, and the high-order bit (mask 0x80) indicates the byte is
|
||||
* at the start of a physical tape block. Tape marks (EOF) are indicated by a
|
||||
* block containing a single 0x8F byte.
|
||||
*
|
||||
* The mapping process is driven by the tape directory at the beginning of
|
||||
* the tape volume. Continuation "reels" are not currently supported.
|
||||
*
|
||||
* To use, select the .bcd file using the file selection control on the page.
|
||||
* The script writes a log of activity to the web page.
|
||||
************************************************************************
|
||||
* 2013-06-06 P.Kimpel
|
||||
* Original version, from B5500LibMaintMapper.html and B5500DiskDirList.html.
|
||||
***********************************************************************/
|
||||
"use strict";
|
||||
|
||||
window.onload = function() {
|
||||
var panel = document.getElementById("TextPanel");
|
||||
var tapeMark = 0x8F;
|
||||
var tapeDir = [];
|
||||
|
||||
var tapeCtl = {
|
||||
data: null,
|
||||
offset: 0,
|
||||
dataLength: -1,
|
||||
eof: false,
|
||||
eot: false,
|
||||
blockCount: 0,
|
||||
blockLength: 0};
|
||||
|
||||
var BICtoANSI = [
|
||||
"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 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);
|
||||
}
|
||||
|
||||
function clearPanel() {
|
||||
/* Clears the text panel */
|
||||
var kid;
|
||||
|
||||
while (kid = panel.firstChild) {
|
||||
panel.removeChild(kid);
|
||||
}
|
||||
}
|
||||
|
||||
function parseNumber(s) {
|
||||
/* Parses the string "s" as a base-10 number. Returns 0 if it is not a number */
|
||||
var n = parseInt(s, 10);
|
||||
|
||||
return (isNaN(n) ? 0 : n);
|
||||
}
|
||||
|
||||
function rtrim(s) {
|
||||
/* Trims trailing spaces from "s" and returns the resulting string */
|
||||
var m = s.match(/^(.*?) *$/);
|
||||
|
||||
return m[1];
|
||||
}
|
||||
|
||||
function readTextBlock(ctl) {
|
||||
/* Reads the next block from the tape, translating the character frames to ANSI
|
||||
character codes and returning the data as a string. A block is terminated when
|
||||
the next frame has its high-order bit set, or the end of the data is reached.
|
||||
The string returned is always at least one character in length, unless the block
|
||||
is a tapeMark (in which case the "eof" property is set) or the end of the data
|
||||
has been reached (in which case the "eof" and "eot" properties are set) */
|
||||
var c;
|
||||
var data = ctl.data;
|
||||
var limit = ctl.dataLength;
|
||||
var text = "";
|
||||
var x = ctl.offset;
|
||||
|
||||
if (x >= limit) {
|
||||
ctl.eof = true;
|
||||
ctl.eot = true;
|
||||
ctl.blockLength = 0;
|
||||
} else {
|
||||
c = data.getUint8(x);
|
||||
if (c == tapeMark) {
|
||||
ctl.eof = true;
|
||||
ctl.offset = x+1;
|
||||
ctl.blockLength = 0;
|
||||
} else {
|
||||
do {
|
||||
text += BICtoANSI[c & 0x3F];
|
||||
if (++x < limit) {
|
||||
c = data.getUint8(x);
|
||||
} else {
|
||||
c = tapeMark; // to kill the loop
|
||||
}
|
||||
} while (c < 128);
|
||||
ctl.eof = false;
|
||||
ctl.blockLength = x - ctl.offset;
|
||||
ctl.offset = x;
|
||||
ctl.blockCount++;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function readWordBlock(ctl) {
|
||||
/* Reads the next block from the tape, translating the character frames to an array
|
||||
of B5500 binary words and returning the array. A block is terminated when
|
||||
the next frame has its high-order bit set, or the end of the data is reached.
|
||||
The array returned is always at least one element in length, unless the block
|
||||
is a tapeMark (in which case the "eof" property is set) or the end of the data
|
||||
has been reached (in which case the "eof" and "eot" properties are set) */
|
||||
var c;
|
||||
var data = ctl.data;
|
||||
var limit = ctl.dataLength;
|
||||
var w = 0;
|
||||
var words = [];
|
||||
var wx = 0;
|
||||
var x = ctl.offset;
|
||||
|
||||
if (x >= limit) {
|
||||
ctl.eof = true;
|
||||
ctl.eot = true;
|
||||
ctl.blockLength = 0;
|
||||
} else {
|
||||
c = data.getUint8(x);
|
||||
if (c == tapeMark) {
|
||||
ctl.eof = true;
|
||||
ctl.offset = x+1;
|
||||
ctl.blockLength = 0;
|
||||
} else {
|
||||
do {
|
||||
if (wx < 8) {
|
||||
w = w*64 + (c & 0x3F);
|
||||
wx++;
|
||||
} else {
|
||||
words.push(w);
|
||||
w = c & 0x3F;
|
||||
wx = 1;
|
||||
}
|
||||
if (++x < limit) {
|
||||
c = data.getUint8(x);
|
||||
} else {
|
||||
c = tapeMark; // to kill the loop
|
||||
}
|
||||
} while (c < 128);
|
||||
|
||||
// Right-justify the last word as necessary
|
||||
while (wx++ < 8) {
|
||||
w *= 64;
|
||||
}
|
||||
words.push(w);
|
||||
ctl.eof = false;
|
||||
ctl.blockLength = x - ctl.offset;
|
||||
ctl.offset = x;
|
||||
ctl.blockCount++;
|
||||
}
|
||||
}
|
||||
return words;
|
||||
}
|
||||
|
||||
function readTapeLabel(ctl) {
|
||||
/* Reads the next block from the tape and determines if it is a B5500 tape label.
|
||||
If so, decodes the label into a label object and returns the object */
|
||||
var rec;
|
||||
var s;
|
||||
|
||||
var lab = {
|
||||
isLabel: false,
|
||||
text: "",
|
||||
heading: "",
|
||||
mfid: "",
|
||||
fid: "",
|
||||
reel: 0,
|
||||
dateWritten:0,
|
||||
cycle: 0,
|
||||
datePurge: 0,
|
||||
sentinel: 0,
|
||||
blockCount: 0,
|
||||
recordCount:0,
|
||||
memdumpKey: 0,
|
||||
tapeNumber: ""};
|
||||
|
||||
rec = readTextBlock(ctl);
|
||||
if (!ctl.eof) {
|
||||
lab.text = rec;
|
||||
if (ctl.blockLength == 80 && (s = rec.substring(0, 8)) == " LABEL ") {
|
||||
lab.isLabel = true;
|
||||
lab.heading = s;
|
||||
lab.mfid = rec.substring(9, 16);
|
||||
lab.fid = rec.substring(17, 24);
|
||||
lab.reel = parseNumber(rec.substring(24, 27));
|
||||
lab.dateWritten = parseNumber(rec.substring(27, 32));
|
||||
lab.cycle = parseNumber(rec.substring(32, 34));
|
||||
lab.datePurge = parseNumber(rec.substring(34, 39));
|
||||
lab.sentinel = parseNumber(rec.substring(39, 40));
|
||||
lab.blockCount = parseNumber(rec.substring(40, 45));
|
||||
lab.recordCount = parseNumber(rec.substring(45, 52));
|
||||
lab.memdumpKey = parseNumber(rec.substring(52, 53));
|
||||
lab.tapeNumber = rec.substring(53, 58);
|
||||
}
|
||||
}
|
||||
return lab;
|
||||
}
|
||||
|
||||
function readTapeDirectory(ctl) {
|
||||
/* Reads the Lib/Maint tape directory and returns and array of file names, indexed
|
||||
starting at 1. If the directory is invalid, returns an empty array */
|
||||
var dir = [];
|
||||
var done;
|
||||
var fid;
|
||||
var lab;
|
||||
var lab2;
|
||||
var mfid;
|
||||
var rec;
|
||||
var w;
|
||||
var x;
|
||||
|
||||
lab = readTapeLabel(ctl);
|
||||
if (ctl.eof) {
|
||||
spout("TapeDir: EOF encountered when tape label expected, block=" + ctl.blockCount);
|
||||
} else if (!lab.isLabel) {
|
||||
spout(lab.text);
|
||||
spout("TapeDir: Above block encountered when a tape label was expected, block=" + ctl.blockCount);
|
||||
} else {
|
||||
dir.push(rtrim(lab.mfid) + "/" + rtrim(lab.fid)); // store the tape name in dir[0]
|
||||
rec = readTextBlock(ctl);
|
||||
if (!ctl.eof) {
|
||||
spout("TapeDir: EOF expected after starting label, block=" + ctl.blockCount);
|
||||
}
|
||||
|
||||
do {
|
||||
rec = readTextBlock(ctl);
|
||||
if (!ctl.eof) {
|
||||
x = 0;
|
||||
done = false;
|
||||
do {
|
||||
if (x+8 > rec.length) {
|
||||
spout("TapeDir: No terminating entry, block=" + ctl.blockCount + ", x=" + x);
|
||||
done = true;
|
||||
} else if (rec.substring(x, x+8) == "0000000?") {
|
||||
done = true;
|
||||
} else if (x+16 > rec.length) {
|
||||
spout("TapeDir: Truncated directory entry, block=" + ctl.blockCount + ", x=" + x);
|
||||
done = true;
|
||||
} else {
|
||||
mfid = rec.substring(x+1, x+8);
|
||||
fid = rec.substring(x+9, x+16);
|
||||
dir.push(rtrim(mfid) + "/" + rtrim(fid));
|
||||
x += 16;
|
||||
}
|
||||
} while (!done);
|
||||
}
|
||||
} while (!ctl.eof);
|
||||
|
||||
lab2 = readTapeLabel(ctl);
|
||||
if (!lab2.isLabel) {
|
||||
spout("TapeDir: Tape label expected after directory, block=" + ctl.blockCount);
|
||||
} else if (lab2.mfid != lab.mfid || lab2.fid != lab.fid) {
|
||||
spout("TapeDir: Directory ending label mismatch, block=" + ctl.blockCount);
|
||||
}
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
function readDiskHeader(ctl) {
|
||||
/* Reads the next block from the tape blob and (partially) decodes it as a B5500
|
||||
disk header, returning the header object */
|
||||
var block;
|
||||
|
||||
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: []};
|
||||
|
||||
block = readWordBlock(ctl);
|
||||
if (ctl.eof) {
|
||||
spout("DiskHeader: EOF encountered reading header, block=" + ctl.blockCount);
|
||||
} else if (block.length < 11) {
|
||||
spout("DiskHeader: header too short, got " + block.length + ", block=" + ctl.blockCount);
|
||||
} else {
|
||||
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.newFormat = fieldIsolate(block[3], 1, 1);
|
||||
header.saveFactor = fieldIsolate(block[3], 2, 10);
|
||||
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);
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
function formatJulianDate(d) {
|
||||
/* Formats an integer Julian date as 19YY-MM-DD */
|
||||
var dd = d % 1000;
|
||||
var yy = (d-dd)/1000;
|
||||
var dt = new Date(yy+1900, 0, 1);
|
||||
|
||||
dt.setTime(dt.getTime() + (dd-1)*86400000);
|
||||
return dt.getFullYear().toString() + "-" +
|
||||
(dt.getMonth()+101).toString().substring(1) + "-" +
|
||||
(dt.getDate()+100).toString().substring(1);
|
||||
}
|
||||
|
||||
function formatB5500Time(t) {
|
||||
/* Formats a time in 1/60 seconds as HH:MM:SS */
|
||||
var hh;
|
||||
var mm;
|
||||
var ss;
|
||||
|
||||
ss = t % 3600;
|
||||
mm = ((t-ss)/3600) % 60;
|
||||
hh = (t - mm*3600 - ss)/3600/60;
|
||||
return hh.toString() + ":" + (mm+100).toString().substring(1) + ":" +
|
||||
(ss/60+100).toFixed(0).substring(1);
|
||||
}
|
||||
|
||||
function formatDirectoryEntry(body, lmFile, fileName, 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, lmFile, "data");
|
||||
appendCell(row, fileName, "data");
|
||||
appendCell(row, header.fileClass, "rj");
|
||||
appendCell(row, header.fileType, "rj");
|
||||
appendCell(row, header.recordLength, "rj");
|
||||
appendCell(row, header.blockLength, "rj");
|
||||
appendCell(row, header.recordsPerBlock, "rj");
|
||||
appendCell(row, header.segmentsPerBlock, "rj");
|
||||
appendCell(row, header.segmentsPerRow, "rj");
|
||||
appendCell(row, header.maxRows, "rj");
|
||||
appendCell(row, header.recordCount, "rj");
|
||||
appendCell(row, header.saveFactor, "rj");
|
||||
appendCell(row, formatJulianDate(header.creationDate), "rj");
|
||||
appendCell(row, formatJulianDate(header.lastAccessDate), "rj");
|
||||
appendCell(row, formatJulianDate(header.logCreationDate), "rj");
|
||||
appendCell(row, formatB5500Time(header.logCreationTime), "rj");
|
||||
|
||||
text = "";
|
||||
for (rx=header.maxRows-1; rx>=0; rx--) {
|
||||
if (text || header.rowAddress[rx]) {
|
||||
text = header.rowAddress[rx].toFixed(0) + " " + text;
|
||||
}
|
||||
}
|
||||
|
||||
appendCell(row, text);
|
||||
body.appendChild(row);
|
||||
}
|
||||
|
||||
function extractFile(ctl, fileNr, fileName) {
|
||||
/* Extracts the next file in sequence from the tape blob, converts the data
|
||||
from BIC to ASCII, and writes it to a new window object within the browser.
|
||||
Returns true if no more files should be converted */
|
||||
var block;
|
||||
var body = $$("DirListBody");
|
||||
var box;
|
||||
var header;
|
||||
var lab;
|
||||
var lab2;
|
||||
var recs = 0;
|
||||
var result = false;
|
||||
var rowCount = 0;
|
||||
var text;
|
||||
var win;
|
||||
var x;
|
||||
|
||||
//spout(" ");
|
||||
//spout("File #" + fileNr + ": " + fileName);
|
||||
lab = readTapeLabel(ctl);
|
||||
if (ctl.eof) {
|
||||
spout("Extract: EOF encountered when tape label expected, block=" + ctl.blockCount);
|
||||
} else if (!lab.isLabel) {
|
||||
spout(lab.text);
|
||||
spout("Extract: Above block encountered when a tape label was expected, block=" + ctl.blockCount);
|
||||
} else {
|
||||
block = readWordBlock(ctl);
|
||||
if (!ctl.eof) {
|
||||
spout("Extract: EOF expected after starting label, block=" + ctl.blockCount);
|
||||
}
|
||||
header = readDiskHeader(ctl);
|
||||
formatDirectoryEntry(body, lab.fid, fileName, header);
|
||||
|
||||
while (!ctl.eof) {
|
||||
text = readTextBlock(ctl);
|
||||
}
|
||||
|
||||
lab2 = readTapeLabel(ctl);
|
||||
if (!lab2.isLabel) {
|
||||
spout("Extract: Tape label expected after file data, block=" + ctl.blockCount);
|
||||
} else if (lab2.mfid != lab.mfid || lab2.fid != lab.fid) {
|
||||
spout("Extract: File ending label mismatch, block=" + ctl.blockCount);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function fileLoader_onLoad(ev) {
|
||||
/* Handle the onload event for an ArrayBuffer FileReader */
|
||||
var buf = ev.target.result;
|
||||
var data = new DataView(buf); // use DataView() to avoid problems with littleendians.
|
||||
var tapeDir;
|
||||
var text = "";
|
||||
var x = 0;
|
||||
|
||||
clearPanel();
|
||||
tapeCtl.data = data;
|
||||
tapeCtl.offset = 0;
|
||||
tapeCtl.dataLength = buf.byteLength;
|
||||
tapeCtl.eof = false;
|
||||
tapeCtl.eot = false;
|
||||
tapeCtl.blockCount = 0;
|
||||
|
||||
tapeDir = readTapeDirectory(tapeCtl);
|
||||
spout("Files on tape: " + tapeDir[0]);
|
||||
spout("");
|
||||
|
||||
for (x=1; x<tapeDir.length; x++) {
|
||||
if (extractFile(tapeCtl, x, tapeDir[x])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fileSelector_onChange(ev) {
|
||||
/* Handle the <input type=file> onchange event when a file is selected */
|
||||
var f = ev.target.files[0];
|
||||
var reader = new FileReader();
|
||||
|
||||
//alert("File selected: " + f.name +
|
||||
// "\nModified " + f.lastModifiedDate +
|
||||
// "\nType=" + f.type + ", Size=" + f.size + " octets");
|
||||
|
||||
reader.onload = fileLoader_onLoad;
|
||||
reader.readAsArrayBuffer(f);
|
||||
}
|
||||
|
||||
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 (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()) {
|
||||
return;
|
||||
}
|
||||
document.getElementById("FileSelector").addEventListener("change", fileSelector_onChange, false);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
TR {
|
||||
vertical-align: top}
|
||||
TR TH {
|
||||
vertical-align: bottom}
|
||||
.data {
|
||||
font-family: Courier New, Courier, monospace;
|
||||
white-space: nowrap}
|
||||
.rj {
|
||||
text-align: right}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div style="position:relative; width:100%; height:3em">
|
||||
<div style="position:absolute; left:0; top:0; width:auto">
|
||||
retro-B5500 LibMaint Tape Extract Utility
|
||||
</div>
|
||||
<div style="position:absolute; top:0; right:0; width:auto">
|
||||
<input id=FileSelector type=file size=60>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<pre id=TextPanel>
|
||||
</pre>
|
||||
|
||||
<table id=DirListTable border=1 cellspacing=0 cellpadding=1>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tape File
|
||||
<th>Disk Name
|
||||
<th>Class
|
||||
<th>Type
|
||||
<th>Words<br>/Rec
|
||||
<th>Words<br>/Block
|
||||
<th>Rec/<br>Block
|
||||
<th>Seg/<br>Block
|
||||
<th>Seg/<br>Row
|
||||
<th>Max Rows
|
||||
<th>Records
|
||||
<th>Save Factor
|
||||
<th>Create Date
|
||||
<th>Last Access
|
||||
<th>Log Date
|
||||
<th>Log Time
|
||||
<th>Row Addresses
|
||||
<tbody id=DirListBody>
|
||||
</table>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
35
tools/LOG-MAKER.job
Normal file
35
tools/LOG-MAKER.job
Normal file
@@ -0,0 +1,35 @@
|
||||
?COMPILE LOG/MAKER ALGOL GO
|
||||
?DATA CARD
|
||||
$ CARD LIST SINGLE
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% LOG/MAKER %%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% THIS PROGRAM WILL INITIALIZE THE B5500 MCP SYSTEM/LOG FILE.
|
||||
% CAUTION: THIS PROGRAM SHOULD NOT BE USED IF THE LOG ALREADY EXISTS.
|
||||
% IT MAY REMOVE THE EXISTING LOG. YOU MAY WISH TO USE AN
|
||||
% "LN" MESSAGE FIRST.
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% 2013-07-05 P.KIMPEL
|
||||
% ORIGINAL VERSION.
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
BEGIN
|
||||
DEFINE
|
||||
LOGSEGS = 20000 #;
|
||||
SAVE FILE OUT
|
||||
LOG DISK SERIAL [1:LOGSEGS] "SYSTEM" "LOG" (1, 5, 30, SAVE 365);
|
||||
ARRAY
|
||||
BUF [0:29];
|
||||
|
||||
BUF[0] ~ 0;
|
||||
BUF[1] ~ LOGSEGS;
|
||||
BUF[4] ~ "DISKLOG";
|
||||
WRITE(LOG, 5, BUF[*]);
|
||||
|
||||
BUF[0] ~ 4;
|
||||
BUF[1] ~ BUF[4] ~ 0;
|
||||
WRITE(LOG, 5, BUF[*]);
|
||||
|
||||
LOCK(LOG);
|
||||
END.
|
||||
?END
|
||||
BIN
webUI/A-CONTROL.png
Normal file
BIN
webUI/A-CONTROL.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 728 B |
@@ -26,6 +26,8 @@ function B5500CardPunch(mnemonic, unitIndex, designate, statusChange, signal) {
|
||||
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.initiateStamp = 0; // timestamp of last initiation (set by IOUnit)
|
||||
|
||||
this.clear();
|
||||
|
||||
this.window = window.open("", mnemonic);
|
||||
@@ -283,7 +285,7 @@ B5500CardPunch.prototype.write = function write(finish, buffer, length, mode, co
|
||||
setTimeout(function() {
|
||||
that.busy = false;
|
||||
finish(that.errorMask, length);
|
||||
}, 60000/this.cardsPerMinute);
|
||||
}, 60000/this.cardsPerMinute + this.initiateStamp - new Date().getTime());
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
|
||||
@@ -87,20 +87,21 @@ BUTTON.redLit {
|
||||
#CRFileSelector {
|
||||
position: absolute;
|
||||
border: 1px solid white;
|
||||
top: 56px;
|
||||
left: 8px;
|
||||
width: 120px}
|
||||
color: white;
|
||||
width: 680px;
|
||||
top: 54px;
|
||||
left: 8px}
|
||||
|
||||
#CRProgressBar {
|
||||
position: absolute;
|
||||
border: 1px solid white;
|
||||
top: 82px;
|
||||
left: 8px;
|
||||
width: 680px}
|
||||
width: 680px;
|
||||
top: 84px;
|
||||
left: 8px}
|
||||
|
||||
#CROutHopperFrame {
|
||||
position: absolute;
|
||||
top: 104px;
|
||||
top: 106px;
|
||||
left: 8px;
|
||||
width: 680px;
|
||||
height: 35px;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<button id=CREOFBtn class="redButton">EOF</button>
|
||||
<button id=CRStopBtn class="redButton">STOP</button>
|
||||
|
||||
<input id=CRFileSelector type=file size=90>
|
||||
<input id=CRFileSelector type=file size=60 multiple>
|
||||
|
||||
<progress id=CRProgressBar min=0 max=100 value=0 title="Click to clear input hopper"></progress>
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ function B5500CardReader(mnemonic, unitIndex, designate, statusChange, signal) {
|
||||
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.initiateStamp = 0; // timestamp of last initiation (set by IOUnit)
|
||||
|
||||
this.clear();
|
||||
|
||||
this.window = window.open("", mnemonic);
|
||||
@@ -185,10 +187,12 @@ B5500CardReader.prototype.CRProgressBar_onclick = function CRProgressBar_onclick
|
||||
|
||||
/**************************************/
|
||||
B5500CardReader.prototype.fileSelector_onChange = function fileSelector_onChange(ev) {
|
||||
/* Handle the <input type=file> onchange event when a file is selected */
|
||||
var f = ev.target.files[0];
|
||||
var reader = new FileReader();
|
||||
/* Handle the <input type=file> onchange event when files are selected. For each
|
||||
file, load it and add it to the "input hopper" of the reader */
|
||||
var deck;
|
||||
var f = ev.target.files;
|
||||
var that = this;
|
||||
var x;
|
||||
|
||||
function fileLoader_onLoad(ev) {
|
||||
/* Handle the onload event for a Text FileReader */
|
||||
@@ -214,8 +218,11 @@ B5500CardReader.prototype.fileSelector_onChange = function fileSelector_onChange
|
||||
that.$$("CRProgressBar").max = that.bufLength;
|
||||
}
|
||||
|
||||
reader.onload = fileLoader_onLoad;
|
||||
reader.readAsText(f);
|
||||
for (x=f.length-1; x>=0; x--) {
|
||||
deck = new FileReader();
|
||||
deck.onload = fileLoader_onLoad;
|
||||
deck.readAsText(f[x]);
|
||||
}
|
||||
};
|
||||
|
||||
/**************************************/
|
||||
@@ -379,7 +386,7 @@ B5500CardReader.prototype.read = function read(finish, buffer, length, mode, con
|
||||
setTimeout(function() {
|
||||
that.busy = false;
|
||||
finish(that.errorMask, length);
|
||||
}, 60000/this.cardsPerMinute);
|
||||
}, 60000/this.cardsPerMinute + this.initiateStamp - new Date().getTime());
|
||||
|
||||
while (this.outHopper.childNodes.length > 1) {
|
||||
this.outHopper.removeChild(this.outHopper.firstChild);
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
***********************************************************************/
|
||||
"use strict";
|
||||
|
||||
window.onload = function() {
|
||||
window.addEventListener("load", function() {
|
||||
var configName = "CONFIG"; // database configuration store name
|
||||
var dbName = "B5500DiskUnit"; // IDB database name
|
||||
var dbVersion = 1; // current IDB database version
|
||||
@@ -1685,8 +1685,9 @@ window.onload = function() {
|
||||
stringToANSI("0000001?", fileLabels, labelx-16); // @114, last-entry marker
|
||||
stringToANSI("00000000", fileLabels, labelx-8);
|
||||
}
|
||||
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[0] = ((5*0x8000 + 30)*0x8000 + 6)*0x1000 + 1;
|
||||
// 5 words/rec, 30 words/block, 6 rec/block, 1 seg/block
|
||||
header[3] = (365*0x40000 + 80001) * 0x40000 + 80001; // save=365, create+update=1980-01-01
|
||||
header[7] = -1; // currently has no records
|
||||
header[8] = areasize;
|
||||
header[9] = 1; // number of areas
|
||||
@@ -2000,7 +2001,7 @@ window.onload = function() {
|
||||
$$("LoadBtn").addEventListener("click", loadFromTape);
|
||||
openDatabase(dbName, dbVersion);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -76,7 +76,7 @@ BUTTON.whiteButton {
|
||||
BUTTON.blackButton {
|
||||
position: absolute;
|
||||
background-color: black;
|
||||
color: white;
|
||||
color: #999;
|
||||
font-family: Arial Rounded, Arial, Helvetica, sans-serif;
|
||||
font-size: x-small;
|
||||
font-weight: bold;
|
||||
@@ -98,10 +98,23 @@ BUTTON.yellowButton {
|
||||
border-radius: 4px}
|
||||
|
||||
BUTTON.whiteLit {
|
||||
background-color: white}
|
||||
background-color: #FFF}
|
||||
|
||||
BUTTON.blackLit {
|
||||
color: #FFF}
|
||||
|
||||
BUTTON.yellowLit {
|
||||
background-color: #FFFF00}
|
||||
background-color: #FF0}
|
||||
BUTTON.yellowLit5 {
|
||||
background-color: #EE0}
|
||||
BUTTON.yellowLit4 {
|
||||
background-color: #DD0}
|
||||
BUTTON.yellowLit3 {
|
||||
background-color: #CC0}
|
||||
BUTTON.yellowLit2 {
|
||||
background-color: #BB0}
|
||||
BUTTON.yellowLit1 {
|
||||
background-color: #AA0}
|
||||
|
||||
BUTTON.blackBorder {
|
||||
border: 1px solid black}
|
||||
@@ -167,7 +180,7 @@ TABLE#CentralControl {
|
||||
COL.AnnunciatorCol {
|
||||
width: 2.9%}
|
||||
|
||||
TD#procRate, TD#procSlack {
|
||||
TD#procDelay, TD#procSlack {
|
||||
color: white;
|
||||
text-align: right}
|
||||
|
||||
|
||||
@@ -34,10 +34,12 @@ window.addEventListener("load", function() {
|
||||
var lastInterruptMask = 0;
|
||||
var lastIOUMask = 0;
|
||||
var lastUnitBusyMask = 0;
|
||||
var lastPAState = -1;
|
||||
var lastPBState = -1;
|
||||
var lastPANormalRate = -1;
|
||||
var lastPAControlRate = -1;
|
||||
var lastPBNormalRate = -1;
|
||||
var lastPBControlRate = -1;
|
||||
var perLightsMap = new Array(48);
|
||||
var procRate;
|
||||
var procDelay;
|
||||
var procSlack;
|
||||
var timer;
|
||||
var timerInterval = 50; // milliseconds
|
||||
@@ -58,6 +60,7 @@ window.addEventListener("load", function() {
|
||||
$$("PowerOffBtn").disabled = false;
|
||||
$$("LoadBtn").disabled = false;
|
||||
$$("HaltBtn").disabled = true;
|
||||
boundBlinkenlicht();
|
||||
window.focus();
|
||||
return true;
|
||||
}
|
||||
@@ -89,16 +92,15 @@ window.addEventListener("load", function() {
|
||||
cc.load(false);
|
||||
$$("HaltBtn").disabled = false;
|
||||
$$("LoadBtn").disabled = true;
|
||||
boundBlinkenlicht();
|
||||
}
|
||||
|
||||
function LoadSelectBtn_Click(ev) {
|
||||
if (cc.cardLoadSelect) {
|
||||
cc.cardLoadSelect = 0;
|
||||
$$("LoadSelectBtn").className = "blackButton silverBorder";
|
||||
$$("LoadSelectBtn").className = "blackButton blackLit silverBorder";
|
||||
} else {
|
||||
cc.cardLoadSelect = 1;
|
||||
$$("LoadSelectBtn").className = "blackButton yellowBorder";
|
||||
$$("LoadSelectBtn").className = "blackButton blackLit yellowBorder";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,53 +160,152 @@ window.addEventListener("load", function() {
|
||||
var et;
|
||||
var pa = cc.PA;
|
||||
var pb = cc.PB;
|
||||
var stamp = new Date().getTime();
|
||||
var stateRate;
|
||||
|
||||
if (pa) {
|
||||
if (!pa.busy) {
|
||||
if (lastPAState != -1) {
|
||||
if (lastPAControlRate != -1) {
|
||||
lastPAControlRate = -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";
|
||||
} else {
|
||||
stateRate = Math.round(pa.normalCycles/(pa.normalCycles+pa.controlCycles)*7 + 0.49);
|
||||
if (stateRate != lastPANormalRate) {
|
||||
lastPANormalRate = stateRate;
|
||||
switch (stateRate) {
|
||||
case 0:
|
||||
aNormal.className = "yellowButton";
|
||||
break;
|
||||
case 1:
|
||||
aNormal.className = "yellowButton yellowLit1";
|
||||
break;
|
||||
case 2:
|
||||
aNormal.className = "yellowButton yellowLit2";
|
||||
break;
|
||||
case 0:
|
||||
aNormal.className = "yellowButton yellowLit3";
|
||||
break;
|
||||
case 1:
|
||||
aNormal.className = "yellowButton yellowLit4";
|
||||
break;
|
||||
case 2:
|
||||
aNormal.className = "yellowButton yellowLit5";
|
||||
break;
|
||||
default:
|
||||
aNormal.className = "yellowButton yellowLit";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stateRate = 7 - stateRate;
|
||||
if (stateRate != lastPAControlRate) {
|
||||
lastPAControlRate = stateRate;
|
||||
switch (stateRate) {
|
||||
case 0:
|
||||
aControl.className = "yellowButton";
|
||||
break;
|
||||
case 1:
|
||||
aControl.className = "yellowButton yellowLit1";
|
||||
break;
|
||||
case 2:
|
||||
aControl.className = "yellowButton yellowLit2";
|
||||
break;
|
||||
case 3:
|
||||
aControl.className = "yellowButton yellowLit3";
|
||||
break;
|
||||
case 4:
|
||||
aControl.className = "yellowButton yellowLit4";
|
||||
break;
|
||||
case 5:
|
||||
aControl.className = "yellowButton yellowLit5";
|
||||
break;
|
||||
default:
|
||||
aControl.className = "yellowButton yellowLit";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pa.controlCycles = pa.normalCycles = 0;
|
||||
|
||||
et = pa.procTime;
|
||||
while (et < 0) {
|
||||
et += new Date().getTime();
|
||||
et += stamp;
|
||||
}
|
||||
procRate.innerHTML = (pa.totalCycles/1000/et*100).toFixed(1) + "%";
|
||||
procDelay.innerHTML = pa.delayDeltaAvg.toFixed(3);
|
||||
procSlack.innerHTML = (pa.procSlack/et*100).toFixed(1) + "%";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pb) {
|
||||
if (!pb.busy) {
|
||||
if (lastPBState != -1) {
|
||||
if (lastPBControlRate != -1) {
|
||||
bControl.className = "yellowButton";
|
||||
bNormal.className = "yellowButton";
|
||||
lastPBState = -1;
|
||||
lastPBControlRate = -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";
|
||||
} else {
|
||||
stateRate = Math.round(pb.normalCycles/(pb.normalCycles+pb.controlCycles)*7 + 0.49);
|
||||
if (stateRate != lastPBNormalRate) {
|
||||
lastPBNormalRate = stateRate;
|
||||
switch (stateRate) {
|
||||
case 0:
|
||||
bNormal.className = "yellowButton";
|
||||
break;
|
||||
case 1:
|
||||
bNormal.className = "yellowButton yellowLit1";
|
||||
break;
|
||||
case 2:
|
||||
bNormal.className = "yellowButton yellowLit2";
|
||||
break;
|
||||
case 0:
|
||||
bNormal.className = "yellowButton yellowLit3";
|
||||
break;
|
||||
case 1:
|
||||
bNormal.className = "yellowButton yellowLit4";
|
||||
break;
|
||||
case 2:
|
||||
bNormal.className = "yellowButton yellowLit5";
|
||||
break;
|
||||
default:
|
||||
bNormal.className = "yellowButton yellowLit";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
stateRate = 7 - stateRate;
|
||||
if (stateRate != lastPBControlRate) {
|
||||
lastPBControlRate = stateRate;
|
||||
switch (stateRate) {
|
||||
case 0:
|
||||
bControl.className = "yellowButton";
|
||||
break;
|
||||
case 1:
|
||||
bControl.className = "yellowButton yellowLit1";
|
||||
break;
|
||||
case 2:
|
||||
bControl.className = "yellowButton yellowLit2";
|
||||
break;
|
||||
case 3:
|
||||
bControl.className = "yellowButton yellowLit3";
|
||||
break;
|
||||
case 4:
|
||||
bControl.className = "yellowButton yellowLit4";
|
||||
break;
|
||||
case 5:
|
||||
bControl.className = "yellowButton yellowLit5";
|
||||
break;
|
||||
default:
|
||||
bControl.className = "yellowButton yellowLit";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pb.controlCycles = pb.normalCycles = 0;
|
||||
}
|
||||
}
|
||||
|
||||
displayCentralControl();
|
||||
timer = setTimeout(boundBlinkenlicht, timerInterval);
|
||||
}
|
||||
@@ -265,7 +366,7 @@ window.addEventListener("load", function() {
|
||||
aNormal = $$("ANormalBtn");
|
||||
bControl = $$("BControlBtn");
|
||||
bNormal = $$("BNormalBtn");
|
||||
procRate = $$("procRate");
|
||||
procDelay = $$("procDelay");
|
||||
procSlack = $$("procSlack");
|
||||
boundBlinkenlicht = bindMethod(dasBlinkenlicht, this);
|
||||
buildLightMaps();
|
||||
@@ -277,11 +378,11 @@ window.addEventListener("load", function() {
|
||||
<body>
|
||||
|
||||
<div id=consoleDiv>
|
||||
<button id=HaltBtn class=blackButton DISABLED>HALT</button>
|
||||
<button id=HaltBtn class="blackButton blackLit" DISABLED>HALT</button>
|
||||
|
||||
<button id=NotReadyBtn class=yellowButton>NOT READY</button>
|
||||
<button id=LoadSelectBtn class="blackButton silverBorder">LOAD SELECT</button>
|
||||
<button id=LoadBtn class=blackButton DISABLED>LOAD</button>
|
||||
<button id=LoadSelectBtn class="blackButton blackLit silverBorder">LOAD SELECT</button>
|
||||
<button id=LoadBtn class="blackButton blackLit" DISABLED>LOAD</button>
|
||||
|
||||
<button id=MemoryCheckBtn class=yellowButton>MEMORY CHECK</button>
|
||||
<button id=ANormalBtn class=yellowButton>A NORMAL</button>
|
||||
@@ -290,7 +391,7 @@ window.addEventListener("load", function() {
|
||||
<button id=BControlBtn class=yellowButton>B CONTROL</button>
|
||||
|
||||
<button id=PowerOnBtn class=whiteButton>POWER<br>ON</button>
|
||||
<button id=PowerOffBtn class=blackButton DISABLED>POWER OFF</button>
|
||||
<button id=PowerOffBtn class="blackButton blackLit" DISABLED>POWER OFF</button>
|
||||
|
||||
<div id=BurroughsLogo>
|
||||
<img id=BurroughsLogoImage src="Burroughs-Logo-Neg.jpg" alt="Burroughs logo">
|
||||
@@ -362,8 +463,8 @@ window.addEventListener("load", function() {
|
||||
<td id=MTR>MTR <!-- 34 -->
|
||||
<td id=MTS>MTS <!-- 33 -->
|
||||
<td id=MTT>MTT <!-- 32 -->
|
||||
<td id=procRate>
|
||||
<td class=busy>PA Rate
|
||||
<td id=procDelay>
|
||||
<td class=busy>PA Delay
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -78,6 +78,8 @@ function B5500DiskUnit(mnemonic, index, designate, statusChange, signal) {
|
||||
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.initiateStamp = 0; // timestamp of last initiation (set by IOUnit)
|
||||
|
||||
this.clear();
|
||||
}
|
||||
|
||||
@@ -208,7 +210,7 @@ B5500DiskUnit.prototype.read = function read(finish, buffer, length, mode, contr
|
||||
length = segs*240; // recompute length and ending seg address
|
||||
endAddr = euSize-1;
|
||||
}
|
||||
finishTime = new Date().getTime() +
|
||||
finishTime = this.initiateStamp +
|
||||
(Math.random()*this.maxLatency + segs*240/this.charXferRate)*1000;
|
||||
|
||||
if (segs < 1) { // No length specified, so just finish the I/O
|
||||
@@ -300,7 +302,7 @@ B5500DiskUnit.prototype.write = function write(finish, buffer, length, mode, con
|
||||
length = segs*240; // recompute length and ending seg address
|
||||
endAddr = euSize-1;
|
||||
}
|
||||
finishTime = new Date().getTime() +
|
||||
finishTime = this.initiateStamp +
|
||||
(Math.random()*this.maxLatency + segs*240/this.charXferRate)*1000;
|
||||
|
||||
// No length specified, so just finish the I/O
|
||||
@@ -377,7 +379,7 @@ B5500DiskUnit.prototype.readCheck = function readCheck(finish, length, control)
|
||||
length = segs*240; // recompute length and ending seg address
|
||||
endAddr = euSize-1;
|
||||
}
|
||||
finishTime = new Date().getTime() +
|
||||
finishTime = this.initiateStamp +
|
||||
(Math.random()*this.maxLatency + segs*240/this.charXferRate)*1000;
|
||||
|
||||
if (segs < 1) { // No length specified, so just finish the I/O
|
||||
@@ -431,7 +433,7 @@ B5500DiskUnit.prototype.readInterrogate = function readInterrogate(finish, contr
|
||||
setTimeout(function readInterrogateTimeout() {
|
||||
finish(that.errorMask, length);
|
||||
that.errorMask = 0;
|
||||
}, Math.random()*this.maxLatency*1000);
|
||||
}, Math.random()*this.maxLatency*1000 + this.initiateStamp - new Date().getTime());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -464,6 +466,6 @@ B5500DiskUnit.prototype.writeInterrogate = function writeInterrogate(finish, con
|
||||
setTimeout(function writeInterrogateTimeout() {
|
||||
finish(that.errorMask, length);
|
||||
that.errorMask = 0;
|
||||
}, Math.random()*this.maxLatency*1000);
|
||||
}, Math.random()*this.maxLatency*1000 + this.initiateStamp - new Date().getTime());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,6 +27,8 @@ function B5500DummyPrinter(mnemonic, unitIndex, designate, statusChange, signal)
|
||||
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.initiateStamp = 0; // timestamp of last initiation (set by IOUnit)
|
||||
|
||||
this.clear();
|
||||
|
||||
this.window = window.open("", mnemonic);
|
||||
@@ -154,7 +156,7 @@ B5500DummyPrinter.prototype.write = function write(finish, buffer, length, mode,
|
||||
this.paper.appendChild(this.doc.createElement("hr"));
|
||||
}
|
||||
|
||||
setTimeout(this.signal, 60000/this.linesPerMinute);
|
||||
setTimeout(this.signal, 60000/this.linesPerMinute + this.initiateStamp - new Date().getTime());
|
||||
finish(0, 0);
|
||||
this.endOfPaper.scrollIntoView();
|
||||
};
|
||||
|
||||
@@ -28,6 +28,8 @@ function B5500DummyUnit(mnemonic, index, designate, statusChange, signal) {
|
||||
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.initiateStamp = 0; // timestamp of last initiation (set by IOUnit)
|
||||
|
||||
this.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ function B5500SPOUnit(mnemonic, unitIndex, designate, statusChange, signal) {
|
||||
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.initiateStamp = 0; // timestamp of last initiation (set by IOUnit)
|
||||
|
||||
this.clear();
|
||||
|
||||
this.backspaceChar.that = this; // Store object context for these functions
|
||||
|
||||
@@ -736,7 +736,7 @@ function runIt(ev) {
|
||||
} while (runSilently && stopAddress && cc.P1.C != stopAddress);
|
||||
|
||||
if (stopAddress && cc.P1.C != stopAddress) {
|
||||
setTimeout(syllabicate, 0);
|
||||
setImmediate(syllabicate);
|
||||
if (!runSilently) {
|
||||
displaySystemState();
|
||||
}
|
||||
|
||||
58
webUI/prototypes/SetTimeoutTest.html
Normal file
58
webUI/prototypes/SetTimeoutTest.html
Normal file
@@ -0,0 +1,58 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>B5500 setTimeout() tests</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<style>
|
||||
BODY {
|
||||
background-color: white}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
var lastStamp = new Date().getTime();
|
||||
var cycle = 1;
|
||||
var delay = 0;
|
||||
var delays = new Array(30);
|
||||
|
||||
function timeIt() {
|
||||
var lastDelay;
|
||||
var stamp = new Date().getTime();
|
||||
|
||||
lastDelay = stamp - lastStamp;
|
||||
delays[delay] = (delays[delay]*(cycle-1) + lastDelay)/cycle;
|
||||
|
||||
delay++;
|
||||
if (delay >= delays.length) {
|
||||
delay = 0;
|
||||
cycle++;
|
||||
}
|
||||
|
||||
if (cycle < 10) {
|
||||
lastStamp = stamp;
|
||||
setTimeout(timeIt, delay);
|
||||
} else {
|
||||
for (delay=0; delay<delays.length; delay++) {
|
||||
document.getElementById("panel").appendChild(
|
||||
document.createTextNode("[" + delay + "] = " + delays[delay].toFixed(3) + "\r\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
var x;
|
||||
|
||||
for (x=delays.length-1; x>=0; x--) {
|
||||
delays[x] = 0;
|
||||
}
|
||||
setTimeout(timeIt, delay);
|
||||
};
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<pre id=panel>
|
||||
</pre>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user