Initial cleanup

This commit is contained in:
Jeff Parsons 2014-09-28 09:22:41 -07:00 committed by jeffpar
commit efab8c7147
12 changed files with 0 additions and 1906 deletions

View file

@ -1,327 +0,0 @@
/*
* parallelAdder.js
* by Jeff Parsons, May 11, 2012
*/
/*
* Creation of a ParallelAdder object is controlled by the following properties of the
* parmsAdder object:
*
* idResident: ID of the resident register
* idIncident: ID of the incident register
* idCarries: ID of the carries register
*
* However, by the time we're called, initParallelAdders() has already looked up the
* corresponding Register components by the above IDs (so that we don't have to be
* involved in the "wiring" process) and passes them to us as:
*
* regResident
* regIncident
* regCarries
*
* Our constructor also creates an internal Register object (regScratch) that's used
* to make a copy of the carry bits in the "carries" register after each internal add cycle.
*/
function ParallelAdder(parmsAdder, regResident, regIncident, regCarries)
{
Component.call(this, "ParallelAdder", parmsAdder);
this.regResident = regResident;
this.regIncident = regIncident;
this.regCarries = regCarries;
this.aBitsResident = regResident.getBits();
this.aBitsIncident = regIncident.getBits();
this.aBitsCarries = regCarries.getBits();
this.regScratch = new Register({nBits:regCarries.count()});
this.aBitsScratch = this.regScratch.getBits();
}
Component.subclass(Component, ParallelAdder, {
/*
* These functions implement the necessary Register interfaces that other components,
* like the Selector, expect us to support.
*/
count: function() {
return this.regResident.count();
},
readBit: function(iBit) {
return this.regResident.readBit(iBit);
},
writeBit: function(iBit, b) {
this.regResident.writeBit(iBit, b);
},
/*
* These are the functions unique to ParallelAdder.
*/
add: function(fnNotify) {
this.stopSteps();
this.cCarryCycles = 0;
this.regResident.writeUndefined(false);
this.regResident.updateAll();
this.regIncident.writeUndefined(false);
this.regIncident.updateAll();
this.firstStep(this.stepAddRegisters, fnNotify);
},
stop: function() {
this.stopSteps();
this.regResident.stopSteps();
this.regIncident.stopSteps();
},
stepAddRegisters: function(n) {
this.cCarryCycles++;
/*
* We call the next step directly, to give this step something concrete to do;
* we could have incorporated that code into this step, but it seems cleaner this way.
*/
this.stepClearCarries(n);
if (this.cCarryCycles == 1)
this.addStep(this.stepAddIncidentBits);
else
this.addStep(this.stepAddScratchBits);
this.addStep(this.stepCheckCarries);
return true;
},
stepClearCarries: function(n) {
this.printStep(n, "Clearing carry bits");
this.regCarries.writeAll(false);
if (n !== undefined)
this.regCarries.updateAll();
return true;
},
stepCheckCarries: function(n) {
if (!this.cCarries) {
this.printStep(n, "No carries, addition complete");
return false;
}
this.printStep(n, "Copying carry bits to scratch");
this.regScratch.copyAll(this.regCarries);
return true;
},
stepAddIncidentBits: function(n) {
this.cCarries = 0;
/*
* The following table describes the 4 possible cases of resident(i) and incident(i) bits,
* and what result(i) and carry(i+1) bits must be generated in each of those cases to simulate
* the addition of a resident and incident bit:
*
* case resident(i) incident(i) result(i) carry(i+1)
* ---- ----------- ----------- --------- ----------
* 1 false "+" false "=" false false
* 2 false "+" true "=" true false
* 3 true "+" false "=" true false
* 4 true "+" true "=" false true
*
* Prior to adding the incident bits, we cleared all the carry bits, so we only have to *set* carry bits,
* never *clear* them. As for the result bits, they must be written back to the resident bits register,
* so we must always write the resident result bit -- which you can tell from the table above is equivalent
* to an XOR operation (ie, true if only ONE of either the resident or incident bits is true, false if BOTH
* are false or true).
*/
this.printStep(n, "Adding incident bits");
for (var i=0; i < this.aBitsIncident.length; i++) {
bIncident = this.aBitsIncident[i];
bResident = this.aBitsResident[i];
if (bResident && bIncident) {
if (i+1 < this.aBitsCarries.length) {
this.aBitsCarries[i+1] = true;
this.cCarries++;
}
}
this.aBitsResident[i] = (bResident? !bIncident : bIncident); // the closest thing we have to a logical XOR operation
}
if (n !== undefined) {
this.regResident.updateAll();
this.regCarries.updateAll();
}
return true;
},
stepAddScratchBits: function(n) {
this.cCarries = 0;
/*
* We take advantage of the fact that on iteration i, all scratch bits below bit index i must be zero,
* so we can start checking scratch bits (ie, the carry bits from the previous iteration) at bit index "cCarryCycles".
*
* NOTE: We should assert that all bits below that index are indeed zero, and that we never end up here when
* cCarryCycles == aBitsScratch.length (because there shouldn't have been any saved carries from the length-1 iteration).
*/
this.printStep(n, "Adding previous carry bits");
for (var i=this.cCarryCycles; i < this.aBitsScratch.length; i++) {
bScratch = this.aBitsScratch[i];
bResident = this.aBitsResident[i];
if (bResident && bScratch) {
if (i+1 < this.aBitsCarries.length) {
this.aBitsCarries[i+1] = true;
this.cCarries++;
}
}
this.aBitsResident[i] = (bResident? !bScratch : bScratch); // the closest thing we have to a logical XOR operation
}
if (n !== undefined) {
this.regResident.updateAll();
this.regCarries.updateAll();
}
return true;
}
});
/*
* initParallelAdders()
*
* Initializes all the necessary HTML to construct the component as spec'ed.
*
* Note that each element (e) of class "parallelAdder" is expected to have a "data-value"
* attribute containing the same JSON-encoded parameters that the ParallelAdder constructor
* expects; specifically:
*
* idResident: ID of register containing "resident" binary digits
* idIncident: ID of register containing "incident" binary digits
* idCarries: ID of register used for recording resulting carries
*/
function initParallelAdders()
{
var aeAdders = Component.getElementsByClass(window.document, "parallelAdder");
for (var iAdder=0; iAdder < aeAdders.length; iAdder++) {
var eAdder = aeAdders[iAdder];
var parmsAdder = Component.getComponentParms(eAdder);
//
// Let's find all the prerequisite register components next....
//
var regResident = Component.getComponentByID(parmsAdder.idResident);
var regIncident = Component.getComponentByID(parmsAdder.idIncident);
var regCarries = Component.getComponentByID(parmsAdder.idCarries);
if (!regResident) regResident = new Register();
if (!regIncident) regIncident = new Register();
if (!regCarries) regCarries = new Register();
//
// Now we can create the ParallelAdder object, record it, and wire it up to the associated document elements.
//
var adder = new ParallelAdder(parmsAdder, regResident, regIncident, regCarries);
initParallelAdderControls(adder, eAdder);
}
}
/*
* initParallelAdderControls(reg, eReg)
*
* For each Adder object created by initParallelAdders(), this function looks for any controls that have been defined
* along with the adder element in the current document, and "wires" them as needed.
*
* The following controls are supported:
*
* One optional 'output' control of class "status"
* One optional 'button' control of class "add"
* One optional 'button' control of class "test"
* One optional 'button' control of class "step" (if this exists, it will override any "step" setting above)
*/
function initParallelAdderControls(adder, eAdder)
{
adder.eAdder = eAdder;
var aeControls = Component.getElementsByClass(eAdder.parentNode, "controls");
for (var iControl = 0; iControl < aeControls.length; iControl++) {
var aeChildren = aeControls[iControl].childNodes;
for (var i=0; i < aeChildren.length; i++) {
var e = aeChildren[i];
if (e.nodeType != document.ELEMENT_NODE)
continue;
var sClass = e.getAttribute("class");
if (e.nodeName == "BUTTON" && sClass == "add") {
e.onclick = function() {
adder.stop();
addParallelValues(adder);
};
continue;
}
if (e.nodeName == "BUTTON" && sClass == "test") {
adder.eTest = e;
e.onclick = function() {addStartParallelTest(adder);};
continue;
}
if (e.nodeName == "BUTTON" && sClass == "step") {
adder.setStep(e);
continue;
}
if (e.nodeName == "DIV" && sClass == "status") {
adder.setStatusUpdate(
function(e) {
return function(s) {
e.innerHTML = (s? "<span>"+s+"</span>" : "");
};
}(e)
);
continue;
}
}
}
}
/*
* Function called by the anonymous click handler for the "Add" button.
*/
function addParallelValues(adder)
{
adder.stop();
var vResident = adder.regResident.getValue();
// adder.printStatus("Resident register loaded: " + vResident);
var vIncident = adder.regIncident.getValue();
// adder.printStatus("Incident register loaded: " + vIncident);
adder.add(function() {
var s1 = "Success", s2 = "==";
var vResult = adder.regResident.getValue();
if (vResult != vResident + vIncident) {s1 = "Error"; s2 = "!=";}
adder.printStatus(s1 + ": result (" + vResult + ") " + s2 + " resident (" + vResident + ") + incident (" + vIncident + ")");
});
}
/*
* Function called by the anonymous click handler for the "Test" button.
*/
function addParallelTestValues(adder)
{
adder.cTests++;
var vResident = Math.random() * 0.5;
var vIncident = Math.random() * 0.5;
adder.regResident.writeValue(vResident, function() {
vResident = adder.regResident.getValue();
// adder.printStatus("Resident register loaded: " + vResident);
adder.regIncident.writeValue(vIncident, function() {
vIncident = adder.regIncident.getValue();
// adder.printStatus("Incident register loaded: " + vIncident);
adder.add(function() {
var vResult = adder.regResident.getValue();
adder.cTotalCycles += adder.cCarryCycles - 1; // we don't want to count the initial addition, just the addition of carries
adder.printStatus("Addition complete: " + vResult + " (" + adder.cCarryCycles + " carry cycles, " + (adder.cTotalCycles/adder.cTests) + " average)");
if (vResult != vResident + vIncident)
adder.printStatus("Error: result (" + vResult + ") != resident (" + vResident + ") + incident (" + vIncident + "): " + (vResident + vIncident));
else
if (adder.cTests < 1000) {
addParallelTestValues(adder);
return;
}
addStopParallelTest(adder);
});
});
});
}
function addStartParallelTest(adder)
{
adder.stop();
adder.eTest.innerHTML = "Stop";
adder.eTest.onclick = function() {addStopParallelTest(adder);};
adder.cTests = 0;
adder.cTotalCycles = 0;
addParallelTestValues(adder);
}
function addStopParallelTest(adder)
{
adder.stop();
adder.eTest.innerHTML = "Test";
adder.eTest.onclick = function() {addStartParallelTest(adder);};
}
/*
* Initialize all the components on the page.
*/
web.onInit(initParallelAdders);

View file

@ -1,583 +0,0 @@
/*
* register.js
* by Jeff Parsons, May 7, 2012
*/
/*
* Creation of a Register object is controlled by the following properties of the
* parmsReg object:
*
* nBits: number of bits
* signed: true if signed (default), false otherwise
* bit0Exp: the power-of-two for bit 0 (default is zero)
* labels: true for labels, false otherwise (default)
*
* A Register object can be as small as a single bit, and in fact, a 1-bit Register
* is exactly how you would create the equivalent of a Bit object. However, the more
* common use of this class is to create a bit array.
*
* Internally, the bit indexes of a register correspond to the array indexes of aBits
* (ie, aBits[0] contains the value for bit 0, aBits[1] is bit 1, etc). And the lowest
* bit index represents the lowest power-of-two of the value represented by the register.
*
* The display of a Register object "cell" is handled by the given updateBit() function:
*
* updateBit(iBit, f)
*
* If f is undefined, the cell will be blanked; otherwise, either a "0" or a "1" will be
* displayed. However, that's just the standard implementation; the caller is free to
* define any other behavior (Remember: a register shouldn't care what it looks like).
*
* Internally, there are also "helper" properties (eg, decimalValue) and methods
* (eg, writeValue()) used, for example, to help write data into the register.
* Here's a list of some of them (it's difficult to promise that this list will be kept
* up-to-date):
*
* decimalValue: a decimal floating-point value being written to the register
* decimalPower: a power-of-two used to help convert decimalValue to binary
* decimalBit: a bit index used to help convert decimalValue to binary
* decimalSave: saves the initial decimal value, for visual comparison purposes
*/
var MAX_FRACTIONAL_DIGITS = 12;
function Register(parmsReg, updateBit) {
Component.call(this, "Reg", parmsReg);
if (parmsReg === undefined) {
parmsReg = {nBits:40, signed:true, bit0Exp:0, labels:true};
}
this.aBits = new Array(parmsReg.nBits);
this.signed = parmsReg.signed;
this.bit0Exp = parmsReg.bit0Exp;
this.labels = parmsReg.labels;
/*
* BUGBUG: Compute a reasonable value for this based on how many significant decimal digits
* (ie, to the right of the decimal point) correspond to the smallest given negative power-of-two.
*/
this.fixedDigits = (this.bit0Exp < 0? MAX_FRACTIONAL_DIGITS : 0);
this.upperBound = Math.pow(2, this.bit0Exp + this.aBits.length - (this.signed? 1 : 0));
this.lowerBound = (this.signed? -this.upperBound : 0);
this.updateBit = (updateBit === undefined? function(iBit, f) {} : updateBit);
}
Component.subclass(Component, Register, {
/*
* getBits() is used for "direct" access to the bits; use readBit() and writeBit() to
* access and change individual bits when speed isn't important. Note that changing bits
* directly, as well as calling the write or copy functions, bypasses display updates, so
* use updateBit() or updateAll() to update the display of one bit or the entire register
* as needed. Alternatively, use modifyBit() or modifyAll() to both change and display a
* single bit or the entire register.
*/
count: function() {
return this.aBits.length;
},
getBits: function() {
return this.aBits;
},
readBit: function(iBit) {
return this.aBits[iBit];
},
writeBit: function(iBit, b) {
this.aBits[iBit] = b;
},
writeAll: function(b) {
for (var iBit=0; iBit < this.aBits.length; iBit++)
this.aBits[iBit] = b;
},
writeUndefined: function(b) {
for (var iBit=0; iBit < this.aBits.length; iBit++)
if (this.aBits[iBit] === undefined)
this.aBits[iBit] = b;
},
notBit: function(iBit) {
this.aBits[iBit] = !this.aBits[iBit];
},
notAll: function() {
for (var iBit=0; iBit < this.aBits.length; iBit++)
this.aBits[iBit] = !this.aBits[iBit];
},
copyAll: function(reg) {
for (var iBit=0; iBit < this.aBits.length; iBit++)
this.aBits[iBit] = reg.aBits[iBit];
},
updateAll: function() {
for (var iBit=0; iBit < this.aBits.length; iBit++)
this.updateBit(iBit, this.aBits[iBit]);
this.refreshLiveValue();
},
modifyBit: function(iBit, b) {
this.writeBit(iBit, b);
this.updateBit(iBit, b);
this.refreshLiveValue();
},
modifyAll: function(b) {
this.writeAll(b);
this.updateAll();
},
readValue: function() {
this.stopSteps();
this.printDecimal();
this.writeUndefined(false);
this.updateAll();
this.fPostOp = 0;
this.decimalSave = undefined;
this.decimalValue = 0;
this.decimalBit = this.aBits.length - 1;
if (this.signed && this.aBits[this.decimalBit]) {
this.fPostOp = -1;
}
this.decimalExp = this.bit0Exp + this.decimalBit;
this.decimalPower = Math.pow(2, this.decimalExp);
this.firstStep(this.stepCompareBitToPower);
return this.decimalValue; // NOTE: this return value is valid ONLY if single-stepping has been disabled
},
writeValue: function(v, fnNotify) {
this.stopSteps();
this.modifyAll(undefined);
/*
* There are two obvious ways to handle negative values: one is to negate at the beginning,
* producing a positive value, and convert as we would any other positive value; when done,
* flip all the bits and add a bit at index 0 (ie, a traditional two's-complement conversion).
*
* However, this variation is better: make the value positive, subtract a bit at index 0,
* convert as before, and then flip all the bits. It doesn't matter what order we perform the
* two's-complement conversion steps, and performing a "pre-subtraction" against the input value
* is cheaper for us than performing a "post-addition" on the output value (because we can
* use internal math operations on the input value, whereas the output value is stored only as
* an array of bits).
*
* One downside: when stepping through the conversion process, it may seem odd to see the
* initial value modified ever so slightly (eg, -0.5 converted to 0.499999999998181). We could
* add an additional explicit step to clear up any potential confusion.
*/
this.fPostOp = 0;
this.decimalSave = v;
if (v < 0) {
v = -v;
v -= Math.pow(2, this.bit0Exp);
// BUGBUG: Assert that v is still positive (for tiny negative values of v, this will be a concern)
this.fPostOp = 1;
}
this.decimalValue = v;
this.decimalBit = this.aBits.length - 1;
if (this.signed) {
this.modifyBit(this.decimalBit, 0);
this.decimalBit--;
}
this.decimalExp = this.bit0Exp + this.decimalBit;
this.decimalPower = Math.pow(2, this.decimalExp);
this.firstStep(this.stepCompareDecimalToPower, fnNotify);
},
getValue: function() {
var decimalValue = 0;
var decimalBit = this.aBits.length - 1;
var fPostNegate = this.signed && this.aBits[decimalBit];
var decimalExp = this.bit0Exp + decimalBit;
var decimalPower = Math.pow(2, decimalExp);
do {
if (this.aBits[decimalBit])
decimalValue += decimalPower;
if (decimalBit == 0) break;
decimalBit--;
decimalPower /= 2;
} while (true);
if (fPostNegate) {
decimalValue = -(Math.pow(2, this.bit0Exp + this.aBits.length) - decimalValue);
}
return decimalValue;
},
setLiveUpdate: function(updateLiveValue) {
this.updateLiveValue = updateLiveValue;
this.refreshLiveValue();
},
refreshLiveValue: function() {
if (this.updateLiveValue) {
this.updateLiveValue(this.getValue());
}
},
printDecimal: function(v) {
if (this.updateDecimal !== undefined) {
/*
* We allow v to be undefined, as way as signalling that we are beginning a fresh
* conversion; we will be calling printDecimal() again at the completion of the conversion,
* and v will be defined at that point.
*/
this.updateDecimal(v);
if (v !== undefined && this.log)
console.log(this.toString() + ": updated decimal value to " + v.toFixed(this.fixedDigits));
}
},
setDecimalUpdate: function(updateDecimal) {
this.updateDecimal = updateDecimal;
},
/*
* The following "step" functions implement writeValue().
*
* Once writeValue() has initialized all the internal decimal variables, it calls
* the first step indirectly, via firstStep(), which in turns invokes other
* steps, based on whether the current decimal power is greater than or equal to
* the current decimal value.
*/
stepCompareDecimalToPower: function(n) {
this.printStep(n, "Comparing decimal value (" + this.decimalValue + ") to 2<sup>" + this.decimalExp + "</sup> (" + this.decimalPower.toFixed(20) + ")");
if (this.decimalValue >= this.decimalPower) {
this.addStep(this.stepSetDecimalBit);
this.addStep(this.stepReduceDecimalValue);
}
else {
this.addStep(this.stepClearDecimalBit);
}
if (!this.addStep(this.stepReduceDecimalPower))
return false;
return true;
},
stepSetDecimalBit: function(n) {
this.printStep(n, "Setting bit " + this.decimalBit);
this.writeBit(this.decimalBit, true);
if (n !== undefined) {
this.updateBit(this.decimalBit, true);
this.refreshLiveValue();
}
return true;
},
stepClearDecimalBit: function(n) {
this.printStep(n, "Clearing bit " + this.decimalBit);
this.writeBit(this.decimalBit, false);
if (n !== undefined) {
this.updateBit(this.decimalBit, false);
this.refreshLiveValue();
}
return true;
},
stepReduceDecimalValue: function(n) {
this.printStep(n, "Reducing decimal value by 2<sup>" + this.decimalExp + "</sup> (" + this.decimalPower.toFixed(20) + ")"); // this.decimalPower.toFixed(this.fixedDigits));
this.decimalValue -= this.decimalPower;
if (n !== undefined) this.printDecimal(this.decimalValue);
return true;
},
stepReduceDecimalPower: function(n) {
if (this.decimalBit == 0) {
var sStep = "Processed bit 0";
if (this.fPostOp > 0) {
sStep = "Inverting all bits";
this.notAll();
this.updateAll();
}
else if (this.fPostOp < 0) {
sStep = "Negating result";
this.decimalValue = -(Math.pow(2, this.bit0Exp + this.aBits.length) - this.decimalValue);
}
this.printStep(n, sStep + ", conversion" + (this.decimalSave !== undefined? " of " + this.decimalSave.toFixed(this.fixedDigits) : "") + " complete");
if (n === undefined) {
/*
* Since the conversion was performed without single-stepping, we need to update the register via
* updateAll() if this was a writeValue() operation (ie, decimalSave is defined); similarly, we need
* to update the decimal value via printDecimal() if this was a readValue() operation.
*/
if (this.decimalSave !== undefined)
this.updateAll();
}
/*
* printDecimal() may have never been called during the conversion, since we only call it when the value has been
* reduced. So we always print at the end.
*/
this.printDecimal(this.decimalValue);
return false;
}
this.printStep(n, "Reducing power-of-two");
this.decimalBit--;
this.decimalExp--;
this.decimalPower /= 2;
return true;
},
/*
* The following "step" functions implement readValue().
*
* Because we take the same "top-down" approach that writeValue() took (ie, from highest power/left-most bit down to
* lowest power/right-most bit), we can use the same stepReduceDecimalPower step function that writeValue() used; both
* procedures stop after they've processed bit 0.
*/
stepCompareBitToPower: function(n) {
this.printStep(n, "Testing bit " + this.decimalBit);
if (this.aBits[this.decimalBit])
this.addStep(this.stepIncreaseDecimalValue);
if (!this.addStep(this.stepReduceDecimalPower))
return false;
return true;
},
stepIncreaseDecimalValue: function(n) {
this.printStep(n, "Increasing decimal value by 2<sup>" + this.decimalExp + "</sup> (" + this.decimalPower.toFixed(20) + ")"); // this.decimalPower.toFixed(this.fixedDigits));
this.decimalValue += this.decimalPower;
if (n !== undefined) this.printDecimal(this.decimalValue);
return true;
}
});
/*
* initRegisters()
*
* Initializes all the necessary HTML to construct every register as spec'ed.
*
* This function operates on every element (e) of class "register" and inserts
* the appropriate HTML child elements of class "bitCell".
*
* Note that each element (e) of class "register" is expected to have a "data-value"
* attribute containing the same JSON-encoded parameters that the Register constructor
* expects.
*/
function initRegisters()
{
var aeRegs = Component.getElementsByClass(window.document, "register");
for (var iReg=0; iReg < aeRegs.length; iReg++) {
var eReg = aeRegs[iReg];
var parmsReg = Component.getComponentParms(eReg);
var sHTML = "";
var nExp = parmsReg.bit0Exp + parmsReg.nBits - 1;
for (var iCell=0; iCell < parmsReg.nBits; iCell++,nExp--) {
var sLabel = "";
sBitClass = "bitCell";
if (iCell == 0) {
sBitClass += " bitCellLeft";
if (parmsReg.signed) sLabel = "+/-";
}
var sCellID = "r" + iReg + "c" + iCell;
var sCell = "<div id=\"" + sCellID + "\" class=\"" + sBitClass + "\"></div>\n";
if (!parmsReg.labels) {
sHTML += sCell;
}
else {
if (!sLabel) sLabel = "2<sup>" + nExp + "</sup>";
sHTML += "<div class=\"bitBucket\">\n" + sCell + "<div class=\"bitLabel\">" + sLabel + "</div>\n</div>\n";
}
}
eReg.innerHTML = sHTML;
if (parmsReg.id) {
eReg.setAttribute("id", "reg" + parmsReg.id);
}
//
// Now that all the document elements have been defined, create an array that refers
// to all "bitCell" elements in bit index order (ie, reverse of display order).
//
var aeBits = [];
var aeCells = Component.getElementsByClass(eReg, "bitCell");
for (var i=aeCells.length-1; i >= 0; i--) {
aeBits.push(aeCells[i]);
}
//
// Now we can create the Register object, record it, and wire it up to the associated document elements.
//
var reg = new Register(parmsReg, function(aeBitsParm) {
return function(iBit, f) {
var s = (f===undefined? " " : (f? "1":"0"));
aeBitsParm[iBit].innerHTML = s;
};
}(aeBits)
);
for (var i=0; i < aeBits.length; i++) {
aeBits[i].onclick = function(regParm, iParm) {
//
// If we defined the onclick handler below as "function(e)" instead of simply "function()", then we could
// also receive an event object (e); however, IE reportedly requires that we examine a global (window.event)
// instead. If that's true, and if we ever care to get more details about the click event, then we might
// have to worry about that (eg, define a local var: "var event = window.event || e").
//
return function() {
toggleRegisterBit(regParm, iParm);
};
}(reg, i);
}
initRegisterControls(reg, eReg);
//
// For testing purposes, we could tweak a few of the bits, just to see if all the "wiring" works.
//
// reg.modifyBit(7, true);
// reg.modifyBit(9, false);
//
}
}
/*
* initRegisterControls(reg, eReg)
*
* For each Register object created by initRegisters(), this function looks for any controls that have been defined
* along with the register element in the current document, and "wires" them as needed.
*
* The following controls are supported:
*
* One optional 'input' control of class "value"
* One optional 'output' control of class "value"
* One optional 'output' control of class "status"
* One optional 'button' control of class "random"
* One optional 'button' control of class "write"
* One optional 'button' control of class "read"
* One optional 'button' control of class "clear"
* One optional 'button' control of class "step" (if this exists, it will override any "step" setting above)
*/
function initRegisterControls(reg, eReg)
{
var aeControls = Component.getElementsByClass(eReg.parentNode, "controls");
for (var iControl = 0; iControl < aeControls.length; iControl++) {
var aeChildren = aeControls[iControl].childNodes;
var eDecimal = null, eRandom = null, eWrite = null, eRead = null;
for (var i=0; i < aeChildren.length; i++) {
var e = aeChildren[i];
if (e.nodeType != document.ELEMENT_NODE)
continue;
var sClass = e.getAttribute("class");
if (e.nodeName == "INPUT" && sClass == "value") {
eDecimal = e;
reg.setDecimalUpdate(
function(e) {
return function(v) {
e.value = (v !== undefined? v.toFixed(reg.fixedDigits) : "");
};
}(e)
);
continue;
}
if (e.nodeName == "DIV" && sClass == "value") {
reg.setLiveUpdate(
function(e) {
return function(v) {
e.innerHTML = (v !== undefined? "<span>Live value: " + v.toFixed(reg.fixedDigits) + "</span>" : "");
};
}(e)
);
continue;
}
if (e.nodeName == "DIV" && sClass == "status") {
reg.setStatusUpdate(
function(e) {
return function(s) {
e.innerHTML = (s? "<span>" + s + "</span>" : "");
};
}(e)
);
continue;
}
if (e.nodeName == "BUTTON" && sClass == "random") {
eRandom = e;
continue;
}
if (e.nodeName == "BUTTON" && sClass == "write") {
eWrite = e;
continue;
}
if (e.nodeName == "BUTTON" && sClass == "read") {
eRead = e;
continue;
}
if (e.nodeName == "BUTTON" && sClass == "clear") {
e.onclick = function() { clearRegisterValue(reg); };
continue;
}
if (e.nodeName == "BUTTON" && sClass == "step") {
reg.setStep(e);
continue;
}
}
if (eRandom && eDecimal) {
eRandom.onclick = function(eDecimal) {
return function() { randomizeRegisterValue(reg, eDecimal); };
}(eDecimal);
}
if (eWrite && eDecimal) {
eWrite.onclick = function(eDecimal) {
return function() { writeRegisterValue(reg, eDecimal); };
}(eDecimal);
}
if (eRead) {
eRead.onclick = function(eDecimal) {
return function() { readRegisterValue(reg, eDecimal); };
}(eDecimal);
}
}
}
/*
* Function called by the anonymous click handler for all of the individual register "bitCell" elements.
*/
function toggleRegisterBit(reg, iBit)
{
reg.modifyBit(iBit, reg.readBit(iBit) === false);
}
/*
* Function called by the anonymous click handler for the "Random" button.
*
* It calls reg.stopSteps() to stop any internal operation currently in progress (eg,
* a previous writeValue() or readValue() operation), but it doesn't attempt to write the new value into
* the register; that's the "Write" button's job, once the user chooses to accept the new value.
*/
function randomizeRegisterValue(reg, eDecimal)
{
/*
* NOTE: eDecimal is an <input> element, so set the "value" property rather than the "innerHTML" property.
*/
reg.stopSteps();
eDecimal.value = Math.random().toFixed(reg.fixedDigits);
}
/*
* Function called by the anonymous click handler for the "Write" button.
*
* This takes whatever input value the user has entered (either manually or by clicking the "Random" button)
* and calls reg.writeValue() to begin the process of converting the decimal floating-point value to binary and
* writing the result to the register.
*
* If we ever add a user control (eg, a drop-down list) to select a step delay, then we can call setStep()
* to change the delay from whatever default delay was selected. Note that a setStep() delay of 0 disables all
* single-step output, allowing the operation to run at full speed.
*/
function writeRegisterValue(reg, eDecimal)
{
reg.stopSteps();
var v = parseFloat(eDecimal.value);
if (isNaN(v))
v = 0;
if (v >= reg.lowerBound && v < reg.upperBound) {
reg.writeValue(v);
}
else {
reg.printStatus("Error: decimal value " + v + " out of bounds (" + reg.lowerBound + " <= v < " + reg.upperBound + ")");
}
}
/*
* Function called by the anonymous click handler for the "Read" button.
*
* This starts the reg.readValue() procedure, which does return a value, but it's meaningful only if
* single-stepping has been disabled. It doesn't matter, because either way, reg.readValue() insures that
* that the decimal field is zeroed at the beginning of the procedure and updated at the end (not to mention
* intermediate intervals if single-stepping is enabled), so there's no need to update the field here.
*
* If we ever add a user control (eg, a drop-down list) to select a step delay, then we can call setStep()
* to change the delay from whatever default delay was selected. Note that a setStep() delay of 0 disables all
* single-step output, allowing the operation to run at full speed.
*/
function readRegisterValue(reg, eDecimal)
{
reg.stopSteps();
reg.readValue();
}
/*
* Function called by the anonymous click handler for the "Clear" button.
*/
function clearRegisterValue(reg)
{
reg.stopSteps();
reg.modifyAll(false);
reg.printDecimal();
reg.printStatus();
}
/*
* Initialize all the registers on the page.
*/
web.onInit(initRegisters);

View file

@ -1,228 +0,0 @@
/*
* selector.js
* by Jeff Parsons, May 24, 2012
*/
/*
* Creation of a Selector object is controlled by the following properties of the
* parmsSel object:
*
* nGates: number of gates
* color: color of the gate(s)
* single: true if single gate image to be used, false otherwise (default)
* idSource: ID of the source (eg, component with matching number of bits)
* idTarget: ID of the target (eg, component with matching number of bits)
* sourceStart: starting bit index of source corresponding to gate index 0
* targetStart: starting bit index of target corresponding to gate index 0
*
* However, by the time we're called, initSelectors() has already looked up the
* corresponding source and target components by the above IDs (so that we don't
* have to be involved in the "wiring" process) and passes them to us as:
*
* regSource
* regTarget
*
* A Selector object can be a single gate or an array of gates. The behavior of
* these gates is extensible, but by default, gates do nothing more than propagate
* bits from a "source" input to a "target" output whenever they are "selected".
*
* Internally, the gate indexes of a Selector correspond to the array indexes of
* aGates (ie, aGates[0] contains the [source, target, selected] triplet for gate
* index 0). The source, target and selected values for each gate triplet are stored
* at positions GATE_SOURCE, GATE_TARGET, and GATE_SELECTED.
*
* The display of individual gates is handled by the given updateGate() function:
*
* updateGate(iGate, f)
*
* If f is true, the gate should be displayed in an "selected" state, otherwise it
* should be displayed in a "deselected" state.
*/
function Selector(parmsSel, regSource, regTarget, updateGate) {
Component.call(this, "Sel", parmsSel);
this.aGates = new Array(parmsSel.nGates);
this.selected = false; // the selected state of the entire selector
this.single = (parmsSel.single === true);
this.source = regSource;
this.target = regTarget;
var sourceIndex = (parmsSel.sourceStart? parmsSel.sourceStart : 0);
var targetIndex = (parmsSel.targetStart? parmsSel.targetStart : 0);
var sourceCount = (this.source? this.source.count() : -1); // bit index limit for the given source
var targetCount = (this.target? this.target.count() : -1); // bit index limit for the given target
for (var iGate=0; iGate < this.aGates.length; iGate++) {
var s = sourceIndex;
var t = targetIndex;
if (sourceIndex < 0 || sourceIndex >= sourceCount) s = -1;
if (targetIndex < 0 || targetIndex >= targetCount) t = -1;
this.aGates[iGate] = [s, t, false];
sourceIndex++;
targetIndex++;
}
this.updateGate = (updateGate === undefined? function(iGate, f) {} : updateGate);
this.updateAll();
}
var GATE_SOURCE = 0;
var GATE_TARGET = 1;
var GATE_SELECTED = 2;
Component.subclass(Component, Selector, {
count: function() {
return this.aGates.length;
},
selectGate: function(iGate, f) {
this.aGates[iGate][GATE_SELECTED] = f;
if (f) {
var sourceIndex = this.aGates[iGate][GATE_SOURCE];
var targetIndex = this.aGates[iGate][GATE_TARGET];
if (sourceIndex >= 0 && targetIndex >= 0)
this.target.writeBit(targetIndex, this.source.readBit(sourceIndex));
}
},
selectAll: function(f) {
this.selected = f;
for (var iGate=0; iGate < this.aGates.length; iGate++) {
this.selectGate(iGate, f);
}
},
updateAll: function() {
for (var iGate=0; iGate < this.aGates.length; iGate++)
this.updateGate(iGate, this.aGates[iGate][GATE_SELECTED]);
this.target.updateAll();
}
});
/*
* initSelectors()
*
* Initializes all the necessary HTML to construct every Selector gate or
* gate-array as spec'ed.
*
* This function operates on every element (e) of class "selector" and inserts
* the appropriate HTML child elements of class "gate".
*
* Note that each element (e) of class "selector" is expected to have a "data-value"
* attribute containing the same JSON-encoded parameters that the Selector constructor
* expects.
*/
function initSelectors()
{
var aeSels = Component.getElementsByClass(window.document, "selector");
for (var iSel=0; iSel < aeSels.length; iSel++) {
var eSel = aeSels[iSel];
var parmsSel = Component.getComponentParms(eSel);
//
// Let's find the specified source/target components next, because if nGates isn't defined,
// then we will set a default value equal to the number of bits in the source component, if any.
//
var regSource = Component.getComponentByID(parmsSel.idSource);
var regTarget = Component.getComponentByID(parmsSel.idTarget);
if (parmsSel.nGates === undefined) {
parmsSel.nGates = (regSource? regSource.count() : 1);
}
var nGate = 1;
var sHTML = "";
if (parmsSel.single) {
sHTML += "<div class=\"gate gateLarge\"><img src=\"/my_modules/shared/images/selector.png\"/></div>\n";
}
else {
for (var iGate=0; iGate < parmsSel.nGates; iGate++,nGate++) {
sHTML += "<div class=\"gate gateSmall\"><img src=\"/my_modules/shared/images/selector.png\"/></div>\n";
}
}
eSel.innerHTML = sHTML;
if (parmsSel.id) {
eSel.setAttribute("id", "sel" + parmsSel.id);
}
//
// Now that all the document elements have been defined, we can
// create an array that refers to all "gate" elements in bit index order
// (ie, reverse of display order).
//
var aeGates = [];
var aeCells = Component.getElementsByClass(eSel, "gate");
for (var i=aeCells.length-1; i >= 0; i--) {
aeGates.push(aeCells[i]);
}
//
// Now we can create the Selector object, record it, and wire it up to the associated document elements.
//
var sel = new Selector(parmsSel, regSource, regTarget, function(ae, color, single) {
return function(iGate, f) {
var s = (f===true? "white": color);
ae[single?0:iGate].style.backgroundColor = s;
};
}(aeGates, parmsSel.color, parmsSel.single)
);
for (var i=0; i < aeGates.length; i++) {
aeGates[i].onclick = function (selParm) {
return function() {
selectSelector(selParm);
};
}(sel);
}
initSelectorControls(sel, eSel);
//
// For testing purposes, we could tweak a few of the gates, just to see if all the "wiring" works.
//
// sel.selectGate(7, true);
// sel.selectGate(9, false);
//
}
if (aeSels.length == 0)
console.log("warning: no selectors on page");
}
/*
* initSelectorControls(sel, eSel)
*
* For each Selector object created by initSelectors(), this function looks for any controls that have been defined
* along with the selector element in the current document, and "wires" them as needed.
*
* The following controls are supported:
*
* One optional 'button' control of class "select"
*/
function initSelectorControls(sel, eSel)
{
var aeControls = Component.getElementsByClass(eSel.parentNode, "controls");
for (var iControl = 0; iControl < aeControls.length; iControl++) {
var aeChildren = aeControls[iControl].childNodes;
for (var i=0; i < aeChildren.length; i++) {
var e = aeChildren[i];
if (e.nodeType != document.ELEMENT_NODE)
continue;
var sClass = e.getAttribute("class");
if (e.nodeName == "BUTTON" && sClass == "select") {
e.onclick = function(e) {
return function() { selectSelector(sel, e); };
}(e);
continue;
}
}
}
}
/*
* Function called by the anonymous click handlers for the "Select" button.
*/
function selectSelector(sel, e)
{
sel.selectAll(!sel.selected);
sel.updateAll();
if (e !== undefined) {
e.innerHTML = (f? "Deselect" : "Select");
}
}
/*
* Initialize all the selectors on the page.
*/
web.onInit(initSelectors);

View file

@ -1,207 +0,0 @@
/*
* stepper.js
* by Jeff Parsons, June 24, 2012
*
* Stepper methods extracted from the original Component class.
*/
/*
* The Stepper class defines a set of stepping functions used to help drive multi-step
* operations that a component may want to "single-step." The setStep() function determines
* the delay, if any, between the steps. If there is no delay, then all the supplied
* "step" functions are called directly. Otherwise, any delay (even a minimal delay of 0ms)
* results in the creation and queuing of step objects. Every step object contains:
*
* fn: step function pointer
* n: step number
*
* and is stored in a simple array (aStep) used to enqueue/dequeue the step objects.
*
* firstStep() gets the ball rolling by queuing the first "step" function. That initial
* "step" function, as well as any or all subsequent "step" functions, call addStep()
* to add more steps to the queue as needed. As each "step" function successfully finishes
* (by returning true), the next "step" function is dequeued and called. As soon as a
* "step" function returns false, the dequeuing process stops, and any remaining steps
* in the queue are ignored. If the queue empties before that happens, then we essentially
* repeat firstStep(), and the process continues.
*
* If a negative millisecond delay (-1) has been set via setStep(), then both firstStep()
* and addStep() call their respective "step" functions directly, instead of queuing them.
* That option should be used only for very brief steps, otherwise the browser will appear
* to hang if the stepping functions never yield.
*
* Also, when "step" functions are called directly, the step number (n) is omitted from the
* calls, so that the "step" function can quickly determine whether to bypass its internal print
* operations. printStep() will automatically bypass, since it has access to the step number,
* but if you want to maximize speed, then either always check for an undefined step number, or
* use separate "step" functions that omit both the step number and the print operations altogether.
*
* NOTE: the stepping functions use printStatus() indirectly, via printStep(). However,
* there may be times when a component wants to reserve its "status" control for more pertinent
* messages. In those cases, the component can pass a "quiet" setting to setStep().
*/
function Stepper() {
}
Stepper.prototype = {
/*
* initStep(parms) accepts any or all of the following parameter (parms) properties:
*
* step: millisecond step setting (0 for minimum delay when single-stepping, -1 for direct calls instead of steps)
*/
initStep: function(parms) {
this.msStep = parms.step;
this.quiet = (this.msStep == 0);
},
/*
* setStep(ms, quiet)
*
* ms can be any of:
*
* 1) non-negative number of milliseconds
* 2) -1 to call all step functions directly without delay
* 3) an HTML element (eg, a button) that will control stepping via its "onclick" handler
*
* Note that even 0 is a supported millisecond delay, albeit a minimal one, insuring that scripts
* don't run too long without yielding.
*
* If quiet, then printStep() messages will not be passed to printStatus(); however, if logging is
* enabled (refer to this.fLog), printStep() messages will still be logged.
*/
setStep: function(ms, quiet) {
this.msStep = ms;
this.quiet = quiet;
},
stopSteps: function() {
if (this.timerSteps !== undefined)
clearTimeout(this.timerSteps);
if (this.timerNotify !== undefined)
clearTimeout(this.timerNotify);
this.aSteps = [];
this.cSteps = 0;
this.timerSteps = undefined;
this.fnNotify = undefined;
this.timerNotify = undefined;
if (!this.quiet) this.printStatus(); // "clear" the status field, if any, as well
},
firstStep: function(fn, fnNotify) {
this.fnNotify = fnNotify;
this.timerNotify = undefined;
if (this.msStep == -1) {
while (fn.call(this))
;
if (this.fnNotify) this.timerNotify = setTimeout(this.fnNotify, 0);
return;
}
this.kickStep(fn);
this.nextStep(0);
},
kickStep: function(fn) {
this.addStep(function(n) {
// this.log(this.toString() + ": Step " + n + ": automatic kickStep");
if (!fn.call(this, n))
return false;
return this.kickStep(fn);
});
return true;
},
addStep: function(fn) {
if (this.msStep == -1) {
return fn.call(this);
}
var step = {fn:fn, n:++this.cSteps};
this.aSteps.push(step);
return true;
},
removeStep: function($this) {
$this.timerSteps = undefined;
if (typeof $this.msStep == "object")
$this.msStep.onclick = null;
var step = $this.aSteps.shift();
if (step === undefined)
return false;
return $this.doStep(step);
},
doStep: function(step) {
if (!step.fn.call(this, step.n)) {
if (this.fnNotify) this.timerNotify = setTimeout(this.fnNotify, 0);
return false;
}
return this.nextStep(this.msStep);
},
nextStep: function(ms) {
if (this.aSteps.length == 0) {
console.warn("Component.nextStep(): unexpected end of steps");
return false;
}
if (typeof ms == "number") {
/*
* IE doesn't support:
*
* setTimeout(this.removeStep, ms, this);
*
* so we're forced to do this instead:
*
* var thisParm = this;
* setTimeout(function() {thisParm.removeStep(thisParm);}, ms);
*/
var thisParm = this;
this.timerSteps = setTimeout(function() {thisParm.removeStep(thisParm);}, ms);
}
else
if (typeof ms == "object") {
ms.onclick = function(regParm) {
/*
* If we defined the onclick handler below as "function(e)" instead of simply "function()", then we could
* also receive an event object (e); however, IE reportedly requires that we examine a global (window.event)
* instead. If that's true, and if we ever care to get more details about the click event, then we might
* have to worry about that (eg, define a local var: "var event = window.event || e").
*/
return function() {
return regParm.removeStep(regParm);
};
}(this);
}
else
alert("unexpected step parameter (" + ms + ")");
return true;
},
printStep: function(n, s) {
if (n !== undefined) {
if (!this.quiet)
this.printStatus("Step " + n + ": " + s);
else if (this.fLog)
this.log(this.toString() + ": Step " + n + ": " + s);
}
},
/*
* printStatus(s)
*
* Passes any string (s) to the associated HTML element of class "status", if any;
* pass a blank string, or nothing at all, to clear the contents of the associated
* "status" element.
*
* If there's no "status" element associated with this component, then status messages
* are simply thrown away. However, if logging is enabled (ie, parms.log was true),
* all status messages are still logged.
*/
printStatus: function(s) {
if (this.updateStatus !== undefined) {
this.updateStatus(s);
}
if (this.fLog && s) {
this.log(this.toString() + ": " + s);
}
},
/*
* setStatusUpdate(s)
*
* Sets the "updateStatus" handler that printStatus() uses to display any status messages.
*/
setStatusUpdate: function(updateStatus) {
this.updateStatus = updateStatus;
}
};
Component.extend(Component.prototype, Stepper.prototype);

View file

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- author="Jeff Parsons (@jeffpar)" website="http://www.pcjs.org/" created="2012-05-05" modified="2012-08-28" license="http://www.gnu.org/licenses/gpl.html" -->
<!DOCTYPE xsl:stylesheet [
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other useful entities are defined below (see entities.dtd). -->
<!ENTITY nbsp "&#160;"> <!ENTITY sect "&#167;"> <!ENTITY copy "&#169;"> <!ENTITY para "&#182;"> <!ENTITY ndash "&#8211;"> <!ENTITY mdash "&#8212;">
<!ENTITY lsquo "&#8216;"> <!ENTITY rsquo "&#8217;"> <!ENTITY ldquo "&#8220;"> <!ENTITY rdquo "&#8221;"> <!ENTITY dagger "&#8224;"> <!ENTITY Dagger "&#8225;">
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="rootDir" select="''"/>
<xsl:param name="generator" select="'client'"/>
<xsl:output doctype-system="about:legacy-compat"/>
<xsl:include href="../../../my_modules/shared/templates/common.xsl"/>
<xsl:include href="components.xsl"/>
<xsl:include href="register.xsl"/>
<xsl:template match="/">
<html lang="en">
<head>
<title>jsmachines.net</title>
<xsl:call-template name="commonStyles"/>
<xsl:call-template name="componentIncludes"><xsl:with-param name="component" select="'components'"/></xsl:call-template>
<xsl:if test="//register">
<xsl:call-template name="registerIncludes"/>
</xsl:if>
</head>
<body>
<div class="page justified">
<xsl:apply-templates/>
<h4>Return to <a href="/outline.xml">Outline</a></h4>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View file

@ -1,79 +0,0 @@
.component:before, .component:after {
content:"";
display:table;
}
.component:after {
clear:both;
}
.component {
zoom:1; /* For IE 6/7 (trigger hasLayout) */
font-size: medium;
}
.component .label {
margin-bottom: 2px;
}
.label.left {
float: left;
margin-right: 1em;
width: 2em;
}
.component .container {
display: inline-block;
}
.controls, .controls div, .controls input, .controls button {
float: left;
margin: 2px;
margin-left: 0px;
}
input.value {
width: 16em;
height: 1em;
font-size: medium;
border: 1px solid black;
line-height: 1em; /* the equivalent of "vertical-align: middle" for single-line elements */
text-align: right;
}
.status, .value {
vertical-align: middle;
}
.status span, .value span {
font-size: small;
vertical-align: 10%;
}
.status sup {
vertical-align: baseline;
position: relative;
bottom: .33em;
}
.status sub {
vertical-align: baseline;
position: relative;
bottom: -.33em;
}
.selector {
float: left;
border: 1px solid black;
background-color: white;
}
.selector:before, .selector:after {
content:"";
display:table;
}
.selector:after {
clear:both;
}
/* For IE 6/7 (trigger hasLayout) */
.selector {
zoom:1;
}
.gateSmall, .gateLarge {
float: left;
}
.gateSmall, .gateSmall img {
width: 19px;
height: 19px;
}
.gateLarge, .gateLarge img {
width: 38px;
height: 38px;
}

View file

@ -1,143 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- author="Jeff Parsons (@jeffpar)" website="http://www.pcjs.org/" created="2012-05-05" modified="2014-03-28" license="http://www.gnu.org/licenses/gpl.html" -->
<!DOCTYPE xsl:stylesheet [
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other required entities may be defined below (see entities.dtd). -->
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="componentStyles">
<xsl:param name="component"></xsl:param>
<link rel="stylesheet" type="text/css" href="/my_modules/ecpjs-client/templates/{$component}.css"/>
</xsl:template>
<xsl:template name="componentScripts">
<xsl:param name="component"></xsl:param>
<xsl:choose>
<xsl:when test="$component = 'components'">
<script type="text/javascript" src="/my_modules/shared/lib/component.js"></script>
<script type="text/javascript" src="/my_modules/ecpjs-client/lib/stepper.js"></script>
</xsl:when>
<xsl:otherwise>
<script type="text/javascript" src="/my_modules/ecpjs-client/lib/{$component}.js"></script>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="componentIncludes">
<xsl:param name="component"></xsl:param>
<xsl:call-template name="componentStyles"><xsl:with-param name="component" select="$component"/></xsl:call-template>
<xsl:call-template name="componentScripts"><xsl:with-param name="component" select="$component"/></xsl:call-template>
</xsl:template>
<xsl:template match="component[@ref]">
<xsl:variable name="component" select="name(.)"/>
<xsl:variable name="componentFile"><xsl:value-of select="$rootDir"/><xsl:value-of select="@ref"/></xsl:variable>
<xsl:apply-templates select="document($componentFile)"/>
</xsl:template>
<xsl:template match="component[not(@ref)]">
<xsl:call-template name="component">
<xsl:with-param name="class" select="@class"/>
<xsl:with-param name="parms" select="@parms"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="component">
<xsl:param name="class"></xsl:param>
<xsl:param name="parms">none:null</xsl:param>
<xsl:variable name="id">
<!-- Values allowed: ID of component, blank if none (default) -->
<xsl:choose>
<xsl:when test="@id"><xsl:value-of select="@id"/></xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="name">
<!-- Values allowed: name of component, blank if none (default) -->
<xsl:choose>
<xsl:when test="name"><xsl:value-of select="name"/></xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="pos">
<!-- Values allowed: left (default), center, or blank for no relative positional preference -->
<xsl:choose>
<xsl:when test="@pos"><xsl:value-of select="@pos"/></xsl:when>
<xsl:otherwise>left</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="step">
<!-- Values allowed: number of milliseconds per step, 0 for quick/quiet stepping with yields (default), -1 for no yields -->
<xsl:choose>
<xsl:when test="@step"><xsl:value-of select="@step"/></xsl:when>
<xsl:otherwise>0</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="log">
<!-- Values allowed: true to enable console logging, false to disable (default) -->
<xsl:choose>
<xsl:when test="@log"><xsl:value-of select="@log"/></xsl:when>
<xsl:otherwise>false</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<div class="component {$pos}">
<xsl:apply-templates select="name"/>
<div class="container">
<xsl:if test="control[@pos = 'top']">
<div class="controls">
<xsl:apply-templates select="control[@pos = 'top']" mode="component"/>
</div>
<div style="clear:both"></div>
</xsl:if>
<xsl:if test="control[@pos = 'left']">
<div class="controls">
<xsl:apply-templates select="control[@pos = 'left']" mode="component"/>
</div>
</xsl:if>
<div class="{$class}" data-value="id:'{$id}',name:'{$name}',step:{$step},log:{$log},{$parms}"></div>
<xsl:if test="control[@pos = 'right']">
<div class="controls">
<xsl:apply-templates select="control[@pos = 'right']" mode="component"/>
</div>
</xsl:if>
<xsl:if test="control[not(@pos)]">
<div style="clear:both"></div>
<div class="controls">
<xsl:apply-templates select="control[not(@pos)]" mode="component"/>
</div>
</xsl:if>
<xsl:if test="control[@pos = 'bottom']">
<div style="clear:both"></div>
<div class="controls">
<xsl:apply-templates select="control[@pos = 'bottom']" mode="component"/>
</div>
</xsl:if>
</div>
</div>
</xsl:template>
<xsl:template match="name">
<xsl:variable name="pos">
<xsl:choose>
<xsl:when test="@pos"><xsl:value-of select="@pos"/></xsl:when>
<xsl:otherwise></xsl:otherwise>
</xsl:choose>
</xsl:variable>
<div class="label {$pos}"><xsl:apply-templates/></div>
</xsl:template>
<xsl:template match="control" mode="component">
<xsl:choose>
<xsl:when test="@type = 'input'">
<input class="{@class}" type="text" value=""/>
</xsl:when>
<xsl:when test="@type = 'output'">
<div class="{@class}"></div>
</xsl:when>
<xsl:when test="@type = 'button'">
<button class="{@class}"><xsl:value-of select="."/></button>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

View file

@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- author="Jeff Parsons (@jeffpar)" website="http://www.pcjs.org/" created="2012-05-05" modified="2012-08-28" license="http://www.gnu.org/licenses/gpl.html" -->
<!DOCTYPE xsl:stylesheet [
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other useful entities are defined below (see entities.dtd). -->
<!ENTITY nbsp "&#160;"> <!ENTITY sect "&#167;"> <!ENTITY copy "&#169;"> <!ENTITY para "&#182;"> <!ENTITY ndash "&#8211;"> <!ENTITY mdash "&#8212;">
<!ENTITY lsquo "&#8216;"> <!ENTITY rsquo "&#8217;"> <!ENTITY ldquo "&#8220;"> <!ENTITY rdquo "&#8221;"> <!ENTITY dagger "&#8224;"> <!ENTITY Dagger "&#8225;">
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="rootDir" select="''"/>
<xsl:param name="generator" select="'client'"/>
<xsl:output doctype-system="about:legacy-compat"/>
<xsl:include href="../../../my_modules/shared/templates/common.xsl"/>
<xsl:include href="components.xsl"/>
<xsl:include href="register.xsl"/>
<xsl:template match="/device">
<html lang="en">
<head>
<title>jsmachines.net</title>
<xsl:call-template name="commonStyles"/>
<xsl:call-template name="componentIncludes"><xsl:with-param name="component" select="'components'"/></xsl:call-template>
<xsl:if test="//register">
<xsl:call-template name="registerIncludes"/>
</xsl:if>
<xsl:if test="//component[@class='parallelAdder']">
<xsl:call-template name="componentScripts"><xsl:with-param name="component" select="'parallelAdder'"/></xsl:call-template>
</xsl:if>
<xsl:if test="//component[@class='selector']">
<xsl:call-template name="componentScripts"><xsl:with-param name="component" select="'selector'"/></xsl:call-template>
</xsl:if>
</head>
<body>
<div class="page justified">
<xsl:apply-templates/>
<h4>Return to <a href="/outline.xml">Outline</a></h4>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View file

@ -1,149 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- author="Jeff Parsons" creator="http://www.pcjs.org/" created="2012-05-05T19:53:00" modified="2012-05-05T19:53:00" license="http://creativecommons.org/licenses/by-nc-sa/3.0/us/" -->
<!DOCTYPE xsl:stylesheet [
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other useful entities are defined below (see entities.dtd). -->
<!ENTITY nbsp "&#160;"> <!ENTITY sect "&#167;"> <!ENTITY copy "&#169;"> <!ENTITY para "&#182;"> <!ENTITY ndash "&#8211;"> <!ENTITY mdash "&#8212;">
<!ENTITY lsquo "&#8216;"> <!ENTITY rsquo "&#8217;"> <!ENTITY ldquo "&#8220;"> <!ENTITY rdquo "&#8221;"> <!ENTITY dagger "&#8224;"> <!ENTITY Dagger "&#8225;">
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="rootDir" select="''"/>
<xsl:param name="generator" select="'client'"/>
<xsl:output doctype-system="about:legacy-compat"/>
<xsl:include href="../../../my_modules/shared/templates/common.xsl"/>
<!-- The next two lines were added to support embedding components in documents -->
<xsl:include href="components.xsl"/>
<xsl:include href="register.xsl"/>
<xsl:template match="/document">
<html lang="en">
<head>
<title><xsl:value-of select="title"/><xsl:text> | jsmachines.net</xsl:text></title>
<xsl:call-template name="commonStyles"/>
<!-- The next two lines were added to support embedding components in documents -->
<xsl:call-template name="componentIncludes"><xsl:with-param name="component" select="'components'"/></xsl:call-template>
<xsl:call-template name="registerIncludes"/>
</head>
<body>
<div class="page justified">
<h4 style="float:right">Return to <a href="/manuals/ecp/outline.xml">Outline</a></h4>
<xsl:call-template name="document"><xsl:with-param name="parent" select="'true'"/></xsl:call-template>
<h4>Return to <a href="/manuals/ecp/outline.xml">Outline</a></h4>
</div>
</body>
</html>
</xsl:template>
<xsl:template name="document">
<xsl:param name="parent">false</xsl:param>
<xsl:param name="ref"></xsl:param>
<xsl:if test="not(parent)">
<h1><xsl:value-of select="title"/><xsl:apply-templates select="title/footlink"/></h1>
<xsl:if test="author"><p><xsl:text>By </xsl:text><xsl:call-template name="authors"/></p></xsl:if>
<xsl:apply-templates select="date"/>
<xsl:apply-templates select="synopsis"/>
</xsl:if>
<xsl:if test="parent">
<xsl:choose>
<xsl:when test="$parent = 'true'">
<h2><xsl:apply-templates select="parent"/></h2>
<h3><xsl:apply-templates select="title"/></h3>
</xsl:when>
<xsl:otherwise>
<h2>
<xsl:choose>
<xsl:when test="$ref = ''"><xsl:apply-templates select="title"/></xsl:when>
<xsl:otherwise><a href="{$ref}"><xsl:apply-templates select="title"/></a></xsl:otherwise>
</xsl:choose>
</h2>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:if test="excerpt">
<h4><xsl:apply-templates select="excerpt"/></h4>
</xsl:if>
<xsl:if test="@ref">
<xsl:choose>
<xsl:when test="contains(@ref,'.pdf')">
<a href="{@ref}"><img src="/my_modules/shared/images/pdf-192.jpg"/></a>
</xsl:when>
<xsl:otherwise>
<p>[<a href="{@ref}">Link</a>]</p>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:if test="content">
<xsl:if test="content/p[@name]">
<h4><xsl:text>Discusses: </xsl:text>
<xsl:for-each select="content/p[@name]">
<xsl:if test="position() != 1"><xsl:text>, </xsl:text></xsl:if>
<a href="#{@id}"><xsl:value-of select="@name"/></a>
</xsl:for-each>
</h4>
</xsl:if>
<xsl:apply-templates select="content"/>
</xsl:if>
<xsl:apply-templates select="include"/>
<xsl:apply-templates select="video"/>
</xsl:template>
<xsl:template match="date">
<p><xsl:call-template name="formatDate"><xsl:with-param name="date" select="."/></xsl:call-template></p>
</xsl:template>
<xsl:template match="author">
<p><xsl:text>By </xsl:text><xsl:value-of select="."/></p>
</xsl:template>
<xsl:template match="synopsis">
<p><xsl:text>Synopsis: </xsl:text><em><xsl:value-of select="."/></em></p>
</xsl:template>
<xsl:template match="content">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="video">
<xsl:variable name="controls"><xsl:if test="@controls">controls</xsl:if></xsl:variable>
<div class="center">
<video width="{@width}" height="{@height}" controls="{$controls}">
<xsl:apply-templates select="source"/>
Your browser does not support HTML5 video play-back.
</video>
</div>
</xsl:template>
<xsl:template match="source">
<source src="{@src}" type="{@type}"/>
</xsl:template>
<xsl:template match="include">
<xsl:if test="@ref">
<xsl:variable name="documentFile"><xsl:value-of select="$rootDir"/><xsl:value-of select="@ref"/></xsl:variable>
<xsl:apply-templates select="document($documentFile)/document" mode="include">
<xsl:with-param name="parent" select="@parent"/>
<xsl:with-param name="link" select="@link"/>
<xsl:with-param name="ref" select="@ref"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template match="document" mode="include">
<xsl:param name="parent">false</xsl:param>
<xsl:param name="link">false</xsl:param>
<xsl:param name="ref"></xsl:param>
<xsl:choose>
<xsl:when test="$link = 'true'">
<xsl:if test="$parent = 'true'">
<h2><xsl:apply-templates select="parent"/></h2>
</xsl:if>
<h3><a href="{$ref}"><xsl:value-of select="title"/></a></h3>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="document"><xsl:with-param name="parent" select="$parent"/><xsl:with-param name="ref" select="$ref"/></xsl:call-template>
</xsl:otherwise>
</xsl:choose>
<hr/>
</xsl:template>
</xsl:stylesheet>

View file

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- author="Jeff Parsons" creator="http://www.pcjs.org/" created="2012-05-05T19:53:00" modified="2012-05-05T19:53:00" license="http://creativecommons.org/licenses/by-nc-sa/3.0/us/" -->
<!DOCTYPE xsl:stylesheet [
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other useful entities are defined below (see entities.dtd). -->
<!ENTITY nbsp "&#160;"> <!ENTITY sect "&#167;"> <!ENTITY copy "&#169;"> <!ENTITY para "&#182;"> <!ENTITY ndash "&#8211;"> <!ENTITY mdash "&#8212;">
<!ENTITY lsquo "&#8216;"> <!ENTITY rsquo "&#8217;"> <!ENTITY ldquo "&#8220;"> <!ENTITY rdquo "&#8221;"> <!ENTITY dagger "&#8224;"> <!ENTITY Dagger "&#8225;">
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="rootDir" select="''"/>
<xsl:param name="generator" select="'client'"/>
<xsl:output doctype-system="about:legacy-compat"/>
<xsl:include href="../../../my_modules/shared/templates/common.xsl"/>
<xsl:template match="/outline">
<html lang="en">
<head>
<title><xsl:value-of select="title"/><xsl:text> | jsmachines.net</xsl:text></title>
<xsl:call-template name="commonStyles"/>
</head>
<body>
<div class="page">
<xsl:apply-templates/>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View file

@ -1,25 +0,0 @@
.register {
float: left;
}
.bitBucket {
float: left;
width: 19px;
height: 38px;
}
.bitCell {
float: left;
width: 19px;
height: 19px;
margin-right: -1px;
margin-bottom: -1px;
border: 1px solid black;
text-align: center;
line-height: 19px; /* the equivalent of "vertical-align: middle" for single-line elements */
}
.bitCellLeft {
border-left: 1px solid black;
}
.bitLabel {
font-size: xx-small;
text-align: center;
}

View file

@ -1,58 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- author="Jeff Parsons (@jeffpar)" website="http://www.pcjs.org/" created="2012-05-05" modified="2014-03-28" license="http://www.gnu.org/licenses/gpl.html" -->
<!DOCTYPE xsl:stylesheet [
<!-- XSLT understands these entities only: lt, gt, apos, quot, and amp. Other required entities may be defined below (see entities.dtd). -->
]>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="registerIncludes">
<link rel="stylesheet" type="text/css" href="/my_modules/ecpjs-client/templates/register.css"/>
<script type="text/javascript" src="/my_modules/ecpjs-client/lib/register.js"></script>
</xsl:template>
<xsl:template match="register[@ref]">
<xsl:variable name="component" select="name(.)"/>
<xsl:variable name="componentFile"><xsl:value-of select="$rootDir"/><xsl:value-of select="@ref"/></xsl:variable>
<xsl:apply-templates select="document($componentFile)"/>
</xsl:template>
<xsl:template match="register[not(@ref)]">
<xsl:variable name="nBits">
<!-- Values allowed: positive integer defining number of bits, default of 40 (ECP default) -->
<xsl:choose>
<xsl:when test="nBits"><xsl:value-of select="nBits"/></xsl:when>
<xsl:when test="@nBits"><xsl:value-of select="@nBits"/></xsl:when>
<xsl:otherwise>40</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="signed">
<!-- Values allowed: true if left-most bit is sign bit (ECP default), false if not -->
<xsl:choose>
<xsl:when test="signed"><xsl:value-of select="signed"/></xsl:when>
<xsl:when test="@signed"><xsl:value-of select="@signed"/></xsl:when>
<xsl:otherwise>true</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="bit0Exp">
<!-- Values allowed: integer power of two corresponding to right-most bit, default of -39 (ECP default) -->
<xsl:choose>
<xsl:when test="bit0Exp"><xsl:value-of select="bit0Exp"/></xsl:when>
<xsl:when test="@bit0Exp"><xsl:value-of select="@bit0Exp"/></xsl:when>
<xsl:otherwise>-39</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="labels">
<!-- Values allowed: true if bits should be labeled, false if not (default)-->
<xsl:choose>
<xsl:when test="labels"><xsl:value-of select="labels"/></xsl:when>
<xsl:when test="@labels"><xsl:value-of select="@labels"/></xsl:when>
<xsl:otherwise>false</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:call-template name="component">
<xsl:with-param name="class">register</xsl:with-param>
<xsl:with-param name="parms">nBits:<xsl:value-of select="$nBits"/>,signed:<xsl:value-of select="$signed"/>,bit0Exp:<xsl:value-of select="$bit0Exp"/>,labels:<xsl:value-of select="$labels"/></xsl:with-param>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>