mirror of
https://github.com/pkimpel/retro-b5500.git
synced 2026-02-11 19:05:01 +00:00
191 lines
7.8 KiB
JavaScript
191 lines
7.8 KiB
JavaScript
/***********************************************************************
|
|
* retro-b5500/emulator Register.js
|
|
************************************************************************
|
|
* Copyright (c) 2012, Nigel Williams and Paul Kimpel.
|
|
* Licensed under the MIT License, 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;
|
|
}); |