1
0
mirror of https://github.com/pkimpel/retro-b5500.git synced 2026-02-11 19:05:01 +00:00

Commit initial emulator register class mockup as of 2012-04-27.

This commit is contained in:
paul
2012-05-04 03:00:37 +00:00
parent cb0620a802
commit 01aeb782e5
5 changed files with 657 additions and 0 deletions

23
emulator/Pow2.html Normal file
View File

@@ -0,0 +1,23 @@
<html>
<body>
<script>
var x;
var p=1;
document.write("pow2 = [1");
for (x=1; x<=52; x++) {
p += p;
document.write(", " + p);
}
document.writeln("]");
p = 1;
document.write("mask2 = [0");
for (x=1; x<=52; x++) {
p += p;
document.write(", " + (p-1));
}
document.writeln("]");
</script>
</body>
</html>

View File

@@ -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];

191
emulator/Register.js Normal file
View File

@@ -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;
});

View File

@@ -0,0 +1,51 @@
<html>
<head>
<title>Register Module tests</title>
<!-- Configure Dojo first -->
<script>
dojoConfig = {
parseOnLoad: false,
packages: [
{name: "emu", location: "http://localhost/b5500"
}
],
cacheBust: false
};
</script>
<!-- Load Dojo, Dijit, and DojoX resources from Google CDN -->
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.js"></script>
<body>
<pre id=pad>
</pre>
<script>
require(["emu/Register", "dojo/dom", "dojo/domReady!"], function(reg) {
var pad = document.getElementById("pad");
var S = new reg.Register(15, 256);
var A = new reg.LongRegister(48);
pad.innerHTML += "S=" + S.toString(8) + "\n";
pad.innerHTML += "S.6=" + S.bit(6) + "\n";
S.bitReset(8);
pad.innerHTML += "S=" + S.toString(8) + "\n";
S.insert(0, 9, 7);
pad.innerHTML += "S=" + S.toString(8) + "\n";
pad.innerHTML += "S.[6:3]=" + S.isolate(6, 3) + "\n";
S.sub(449); // @701
pad.innerHTML += "S=" + S.toString(8) + "\n";
pad.innerHTML += "A=" + A.toString(8) + "\n";
A.bitSet(45);
pad.innerHTML += "A=" + A.toString(8) + "\n";
pad.innerHTML += "A.45=" + A.bit(45) + "\n";
A.insert(18, 15, 0x7fff);
pad.innerHTML += "A=" + A.toString(8) + "\n";
pad.innerHTML += "A.[30:4]=" + A.isolate(30,4) + "\n";
A.sub(A.bits+1);
pad.innerHTML += "A=" + A.toString(8) + "\n";
});
</script>
</body>
</html>

290
emulator/compose.js Normal file
View File

@@ -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
}
});