diff --git a/emulator/Pow2.html b/emulator/Pow2.html new file mode 100644 index 0000000..449a01a --- /dev/null +++ b/emulator/Pow2.html @@ -0,0 +1,23 @@ + + + + + \ No newline at end of file diff --git a/emulator/Register-CrockfordStyle.js b/emulator/Register-CrockfordStyle.js new file mode 100644 index 0000000..1e0407f --- /dev/null +++ b/emulator/Register-CrockfordStyle.js @@ -0,0 +1,102 @@ +/*********************************************************************** +* retro-b5500/emulator Register.js +* Copyright (c) 2005, Paradigm Corporation, All Rights Reserved. +************************************************************************ +* JavaScript object definition for the generalized Register prototype. +* Maximum register length is 52 bits, since Javascript stores numbers +* internally as 64-bit IEEE 754 floating point numbers. All registers +* implement unsigned arithmetic modulo their bit length. +* +* Constructor spec members: +* length: size of the register in bits. +* value: initial register value (defaults to 0). +* +* This constructor follows the pattern described by Douglas Crockford in +* chapter 5 of "Javascript: the Good Parts", O'Reilly Media Inc., 2008, +* ISBN 978-0-596-51774-8. +************************************************************************ +* Modification Log. +* 2012-04-28 P.Kimpel +* Original version, from many frustrating attempts to wrap my head +* around this technique. +***********************************************************************/ + +var Register = function(spec, shared) { + var that = {}; // inherits from Object. + + // Additional private members are declared here. + var length = // register size + (spec.length > Register.maxBits ? Register.maxBits : spec.length); + var modulus = Register.pow2[length]; + + var isolate = function(start, count) { + var ue = length-start; // upper power exponent + var le = ue-count; // lower power exponent + + return (le > 0 ? + Math.floor(bits/Register.pow2[lw]) % Register.pow2[count] : + bits % Register.pow2[count]); + } + + var insert = function(start, count, value) { + var ue = length-start; // upper power exponent + var le = ue-count; // lower power exponent + var tpower; // top portion power of 2 + var bpower = Register.pow2[le]; // bottom portion power of 2 + var top; // unaffected top portion of register + var bottom; // unaffected bottom portion of register + + if (start < 1) { + top = 0; + } else { + tpower = Register.pow2[start]; + top = Math.floor(bits/tpower)*bpower; + } + if (le < 1) { + bottom = 0; + } else { + bottom = bits % bpower; + + bits = (value % Register.pow2[count])*bpower + top + bottom; + } + + var bitSet = function(bit) { + insert(bit, 1, 1); + } + + var bitReset = function(bit) { + insert(bit, 1, 0); + } + + var add = function(value) { + bits = (bits + value) % modulus; + } + + var sub = function(value) { + bits = (bits - value) % modulus; + if (bits < 0) { + bits = modulus-bits; + } + } + + // Add any items to the shared-secrets object. + shared = shared || {}; // create it if necessary + + // Add public members to "that". + that.bits = (spec.value % modulus) || 0; // register value + + return that; +} + +// Class constant: register maximum size +Register.maxBits = 52; + +// Class constant: Powers of two from 0-52 +Register.pow2 = [ + 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, + 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, + 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592, + 17179869184, 34359738368, 68719476736, 137438953472, 274877906944, 549755813888, + 1099511627776, 2199023255552, 4398046511104, 8796093022208, 17592186044416, + 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, + 1125899906842624, 2251799813685248, 4503599627370496]; diff --git a/emulator/Register.js b/emulator/Register.js new file mode 100644 index 0000000..45007d6 --- /dev/null +++ b/emulator/Register.js @@ -0,0 +1,191 @@ +/*********************************************************************** +* retro-b5500/emulator Register.js +************************************************************************ +* Copyright (c) 2012, Nigel Williams and Paul Kimpel. +* Licensed under the MIT Licensed, see http://www.opensource.org/licenses/mit-license.php +************************************************************************ +* JavaScript object definition for the generalized Register prototype. +* Maximum register width is 52 bits, since Javascript stores numbers +* internally as 64-bit IEEE 754 floating point numbers. All registers +* implement unsigned arithmetic modulo their bit width. +* +* Constructor spec members: +* width: size of the register in bits. +* value: initial register value (defaults to 0). +************************************************************************ +* Modification Log. +* 2012-04-28 P.Kimpel +* Original version, from many frustrating attempts to wrap my head +* around this technique. +***********************************************************************/ + +define(["exports", "emu/compose"], function(exports, Compose) { + +/*********************************************************************** +* Register() supports binary registers up to 31 bits in width. Where +* applicable, this constructor is more efficient than LongRegister(), +* since it can use Javascript bitmask operators, which are limited to +* operating on 32-bit SIGNED integers. +***********************************************************************/ +var Register = Compose(function(width, value) { + this.width = (width > this.maxBits ? this.maxBits : width); + this.mask = Register.mask2[this.width]; + this.modulus = Register.pow2[this.width]; + this.bits = (value ? value % this.modulus : 0); // initial register value +},{ + maxBits: 31, // maximum register size + + isolate: function(start, width) { + var ue = this.width-start; // upper power exponent + var le = ue-width; // lower power exponent + + return (le > 0 ? this.bits >>> le : this.bits) & Register.mask2[width]; + }, + + bit: function(bit) { + var e = this.width - bit - 1; + + return (e > 0 ? this.bits >>> e : this.bits) & 1; + }, + + insert: function(start, width, value) { + var ue = this.width-start; // upper power exponent + var le = ue-width; // lower power exponent + + this.bits = (this.bits & ((this.mask & ~Register.mask2[ue]) | Register.mask2[le])) | + ((value & Register.mask2[width]) << le); + }, + + bitSet: function(bit) { + this.bits |= Register.pow2[bit]; + }, + + bitReset: function(bit) { + this.bits &= ~Register.pow2[bit]; + }, + + add: function(value) { + var temp = this.bits + value; + + this.bits = (temp < 0 ? (this.modulus + temp) : temp) & this.mask; + }, + + sub: function(value) { + var temp = this.bits - value; + + this.bits = (temp < 0 ? (this.modulus + temp) : temp) & this.mask; + }, + + set: function(value) { + this.bits = (value < 0 ? -value : value) & this.mask; + }, + + valueOf: function() { + return this.bits; + }, + + toString: function(radix) { + return this.bits.toString(radix) + } +}); + +Register.pow2 = [ // powers of 2 from 0 to 52 + 1, 2, 4, 8, + 16, 32, 64, 128, + 256, 512, 1024, 2048, + 4096, 8192, 16384, 32768, + 65536, 131072, 262144, 524288, + 1048576, 2097152, 4194304, 8388608, + 16777216, 33554432, 67108864, 134217728, + 268435456, 536870912, 1073741824, 2147483648, + 4294967296, 8589934592, 17179869184, 34359738368, + 68719476736, 137438953472, 274877906944, 549755813888, + 1099511627776, 2199023255552, 4398046511104, 8796093022208, + 17592186044416, 35184372088832, 70368744177664, 140737488355328, + 281474976710656, 562949953421312, 1125899906842624, 2251799813685248, + 4503599627370496]; + +Register.mask2 = [ // (2**n)-1 for n from 0 to 52 + 0, 1, 3, 7, + 15, 31, 63, 127, + 255, 511, 1023, 2047, + 4095, 8191, 16383, 32767, + 65535, 131071, 262143, 524287, + 1048575, 2097151, 4194303, 8388607, + 16777215, 33554431, 67108863, 134217727, + 268435455, 536870911, 1073741823, 2147483647, + 4294967295, 8589934591, 17179869183, 34359738367, + 68719476735, 137438953471, 274877906943, 549755813887, + 1099511627775, 2199023255551, 4398046511103, 8796093022207, + 17592186044415, 35184372088831, 70368744177663, 140737488355327, + 281474976710655, 562949953421311, 1125899906842623, 2251799813685247, + 4503599627370495]; + + +/*********************************************************************** +* LongRegister() supports binary registers up to 52 bits in width. +* Since Javascript bitmask operators only with up to 32 bits, this +* contructor must use div/mod operations to manipulate the bit fields. +***********************************************************************/ +var LongRegister = Compose(Register, { + maxBits: 52, // maximum register size + + isolate: function(start, width) { + var ue = this.width-start; // upper power exponent + var le = ue-width; // lower power exponent + + return (le > 0 ? Math.floor(this.bits/Register.pow2[le]) : this.bits) % Register.pow2[width]; + }, + + bit: function(bit) { + var e = this.width - bit - 1; + + return (e > 0 ? Math.floor(this.bits/Register.pow2[e]) : this.bits) % 2; + }, + + insert: function(start, width, value) { + var ue = this.width-start; // upper power exponent + var le = ue-width; // lower power exponent + var tpower; // top portion power of 2 + var bpower = Register.pow2[le]; // bottom portion power of 2 + var top = 0; // unaffected top portion of register + var bottom = 0; // unaffected bottom portion of register + + if (start > 0) { + tpower = Register.pow2[ue]; + top = Math.floor(this.bits/tpower)*tpower; + } + if (le > 0) { + bottom = this.bits % bpower; + } + this.bits = (value % Register.pow2[width])*bpower + top + bottom; + }, + + bitSet: function(bit) { + this.insert(bit, 1, 1); + }, + + bitReset: function(bit) { + this.insert(bit, 1, 0); + }, + + add: function(value) { + var temp = this.bits + value; + + this.bits = (temp < 0 ? (this.modulus + temp) : temp) % this.modulus; + }, + + sub: function(value) { + var temp = this.bits - value; + + this.bits = (temp < 0 ? (this.modulus + temp) : temp) % this.modulus; + }, + + set: function(value) { + this.bits = (value < 0 ? -value : value) % this.modulus; + } +}); + +exports.Register = Register; +exports.LongRegister = LongRegister; +}); \ No newline at end of file diff --git a/emulator/RegisterTest.html b/emulator/RegisterTest.html new file mode 100644 index 0000000..9bf41e5 --- /dev/null +++ b/emulator/RegisterTest.html @@ -0,0 +1,51 @@ + + + Register Module tests + + + + + + + +
+
+ + + \ No newline at end of file diff --git a/emulator/compose.js b/emulator/compose.js new file mode 100644 index 0000000..ed91916 --- /dev/null +++ b/emulator/compose.js @@ -0,0 +1,290 @@ +/* + * ComposeJS, object composition for JavaScript, featuring +* JavaScript-style prototype inheritance and composition, multiple inheritance, +* mixin and traits-inspired conflict resolution and composition + */ +(function(define){ +"use strict"; +define([], function(){ + // function for creating instances from a prototype + function Create(){ + } + var delegate = Object.create ? + function(proto){ + return Object.create(typeof proto == "function" ? proto.prototype : proto || Object.prototype); + } : + function(proto){ + Create.prototype = typeof proto == "function" ? proto.prototype : proto; + var instance = new Create(); + Create.prototype = null; + return instance; + }; + function validArg(arg){ + if(!arg){ + throw new Error("Compose arguments must be functions or objects"); + } + return arg; + } + // this does the work of combining mixins/prototypes + function mixin(instance, args, i){ + // use prototype inheritance for first arg + var value, argsLength = args.length; + for(; i < argsLength; i++){ + var arg = args[i]; + if(typeof arg == "function"){ + // the arg is a function, use the prototype for the properties + var prototype = arg.prototype; + for(var key in prototype){ + value = prototype[key]; + var own = prototype.hasOwnProperty(key); + if(typeof value == "function" && key in instance && value !== instance[key]){ + var existing = instance[key]; + if(value == required){ + // it is a required value, and we have satisfied it + value = existing; + } + else if(!own){ + // if it is own property, it is considered an explicit override + // TODO: make faster calls on this, perhaps passing indices and caching + if(isInMethodChain(value, key, getBases([].slice.call(args, 0, i), true))){ + // this value is in the existing method's override chain, we can use the existing method + value = existing; + }else if(!isInMethodChain(existing, key, getBases([arg], true))){ + // the existing method is not in the current override chain, so we are left with a conflict + console.error("Conflicted method " + key + ", final composer must explicitly override with correct method."); + } + } + } + if(value && value.install && own && !isInMethodChain(existing, key, getBases([arg], true))){ + // apply modifier + value.install.call(instance, key); + }else{ + instance[key] = value; + } + } + }else{ + // it is an object, copy properties, looking for modifiers + for(var key in validArg(arg)){ + var value = arg[key]; + if(typeof value == "function"){ + if(value.install){ + // apply modifier + value.install.call(instance, key); + continue; + } + if(key in instance){ + if(value == required){ + // required requirement met + continue; + } + } + } + // add it to the instance + instance[key] = value; + } + } + } + return instance; + } + // allow for override (by es5 module) + Compose._setMixin = function(newMixin){ + mixin = newMixin; + }; + function isInMethodChain(method, name, prototypes){ + // searches for a method in the given prototype hierarchy + for(var i = 0; i < prototypes.length;i++){ + var prototype = prototypes[i]; + if(prototype[name] == method){ + // found it + return true; + } + } + } + // Decorator branding + function Decorator(install, direct){ + function Decorator(){ + if(direct){ + return direct.apply(this, arguments); + } + throw new Error("Decorator not applied"); + } + Decorator.install = install; + return Decorator; + } + Compose.Decorator = Decorator; + // aspect applier + function aspect(handler){ + return function(advice){ + return Decorator(function install(key){ + var baseMethod = this[key]; + (advice = this[key] = baseMethod ? handler(this, baseMethod, advice) : advice).install = install; + }, advice); + }; + }; + // around advice, useful for calling super methods too + Compose.around = aspect(function(target, base, advice){ + return advice.call(target, base); + }); + Compose.before = aspect(function(target, base, advice){ + return function(){ + var results = advice.apply(this, arguments); + if(results !== stop){ + return base.apply(this, results || arguments); + } + }; + }); + var stop = Compose.stop = {}; + var undefined; + Compose.after = aspect(function(target, base, advice){ + return function(){ + var results = base.apply(this, arguments); + var adviceResults = advice.apply(this, arguments); + return adviceResults === undefined ? results : adviceResults; + }; + }); + + // rename Decorator for calling super methods + Compose.from = function(trait, fromKey){ + if(fromKey){ + return (typeof trait == "function" ? trait.prototype : trait)[fromKey]; + } + return Decorator(function(key){ + if(!(this[key] = (typeof trait == "string" ? this[trait] : + (typeof trait == "function" ? trait.prototype : trait)[fromKey || key]))){ + throw new Error("Source method " + fromKey + " was not available to be renamed to " + key); + } + }); + }; + + // Composes an instance + Compose.create = function(base){ + // create the instance + var instance = mixin(delegate(base), arguments, 1); + var argsLength = arguments.length; + // for go through the arguments and call the constructors (with no args) + for(var i = 0; i < argsLength; i++){ + var arg = arguments[i]; + if(typeof arg == "function"){ + instance = arg.call(instance) || instance; + } + } + return instance; + } + // The required function, just throws an error if not overriden + function required(){ + throw new Error("This method is required and no implementation has been provided"); + }; + Compose.required = required; + // get the value of |this| for direct function calls for this mode (strict in ES5) + + function extend(){ + var args = [this]; + args.push.apply(args, arguments); + return Compose.apply(0, args); + } + // Compose a constructor + function Compose(base){ + var args = arguments; + var prototype = (args.length < 2 && typeof args[0] != "function") ? + args[0] : // if there is just a single argument object, just use that as the prototype + mixin(delegate(validArg(base)), args, 1); // normally create a delegate to start with + function Constructor(){ + var instance; + if(this instanceof Constructor){ + // called with new operator, can proceed as is + instance = this; + }else{ + // we allow for direct calls without a new operator, in this case we need to + // create the instance ourself. + Create.prototype = prototype; + instance = new Create(); + } + // call all the constructors with the given arguments + for(var i = 0; i < constructorsLength; i++){ + var constructor = constructors[i]; + var result = constructor.apply(instance, arguments); + if(typeof result == "object"){ + if(result instanceof Constructor){ + instance = result; + }else{ + for(var j in result){ + if(result.hasOwnProperty(j)){ + instance[j] = result[j]; + } + } + } + } + } + return instance; + } + // create a function that can retrieve the bases (constructors or prototypes) + Constructor._getBases = function(prototype){ + return prototype ? prototypes : constructors; + }; + // now get the prototypes and the constructors + var constructors = getBases(args), + constructorsLength = constructors.length; + if(typeof args[args.length - 1] == "object"){ + args[args.length - 1] = prototype; + } + var prototypes = getBases(args, true); + Constructor.extend = extend; + if(!Compose.secure){ + prototype.constructor = Constructor; + } + Constructor.prototype = prototype; + return Constructor; + }; + + Compose.apply = function(thisObject, args){ + // apply to the target + return thisObject ? + mixin(thisObject, args, 0) : // called with a target object, apply the supplied arguments as mixins to the target object + extend.apply.call(Compose, 0, args); // get the Function.prototype apply function, call() it to apply arguments to Compose (the extend doesn't matter, just a handle way to grab apply, since we can't get it off of Compose) + }; + Compose.call = function(thisObject){ + // call() should correspond with apply behavior + return mixin(thisObject, arguments, 1); + }; + + function getBases(args, prototype){ + // this function registers a set of constructors for a class, eliminating duplicate + // constructors that may result from diamond construction for classes (B->A, C->A, D->B&C, then D() should only call A() once) + var bases = []; + function iterate(args, checkChildren){ + outer: + for(var i = 0; i < args.length; i++){ + var arg = args[i]; + var target = prototype && typeof arg == "function" ? + arg.prototype : arg; + if(prototype || typeof arg == "function"){ + var argGetBases = checkChildren && arg._getBases; + if(argGetBases){ + iterate(argGetBases(prototype)); // don't need to check children for these, this should be pre-flattened + }else{ + for(var j = 0; j < bases.length; j++){ + if(target == bases[j]){ + continue outer; + } + } + bases.push(target); + } + } + } + } + iterate(args, true); + return bases; + } + // returning the export of the module + return Compose; +}); +})(typeof define != "undefined" ? + define: // AMD/RequireJS format if available + function(deps, factory){ + if(typeof module !="undefined"){ + module.exports = factory(); // CommonJS environment, like NodeJS + // require("./configure"); + }else{ + Compose = factory(); // raw script, assign to Compose global + } + });