340 lines
5.1 KiB
JavaScript
340 lines
5.1 KiB
JavaScript
"use strict";
|
|
|
|
Object.fromList = function(xs)
|
|
{
|
|
var result = {};
|
|
|
|
for(var i = 0; i < xs.length; i++)
|
|
{
|
|
result[xs[i][0]] = xs[i][1];
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
|
|
|
|
var dbg_names = Object.fromList([
|
|
[1, ""],
|
|
[LOG_CPU, "CPU"],
|
|
[LOG_DISK, "DISK"],
|
|
[LOG_FPU, "FPU"],
|
|
[LOG_MEM, "MEM"],
|
|
[LOG_DMA, "DMA"],
|
|
[LOG_IO, "IO"],
|
|
[LOG_PS2, "PS2"],
|
|
[LOG_PIC, "PIC"],
|
|
[LOG_VGA, "VGA"],
|
|
[LOG_PIT, "PIT"],
|
|
[LOG_MOUSE, "MOUS"],
|
|
[LOG_PCI, "PCI"],
|
|
[LOG_BIOS, "BIOS"],
|
|
[LOG_CD, "CD"],
|
|
[LOG_SERIAL, "SERI"],
|
|
[LOG_RTC, "RTC"],
|
|
]);
|
|
|
|
|
|
/**
|
|
* @param {number=} level
|
|
*/
|
|
function dbg_log(stuff, level)
|
|
{
|
|
if(!DEBUG) return;
|
|
|
|
level = level || 1;
|
|
|
|
if(level & LOG_LEVEL)
|
|
{
|
|
var level_name = dbg_names[level] || "";
|
|
|
|
console.log("[" + String.pads(level_name, 4) + "] " + stuff);
|
|
}
|
|
};
|
|
|
|
function dbg_trace()
|
|
{
|
|
if(!DEBUG) return;
|
|
|
|
dbg_log(Error().stack);
|
|
}
|
|
|
|
/**
|
|
* console.assert is fucking slow
|
|
* @param {string=} msg
|
|
*/
|
|
function dbg_assert(cond, msg)
|
|
{
|
|
if(!DEBUG) return;
|
|
|
|
if(!cond)
|
|
{
|
|
//dump_regs();
|
|
console.log(Error().stack);
|
|
console.trace();
|
|
if(msg)
|
|
{
|
|
throw "Assert failed: " + msg;
|
|
}
|
|
else
|
|
{
|
|
throw "Assert failed";
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
Object.extend = function(target, src)
|
|
{
|
|
var keys = Object.keys(src);
|
|
|
|
for(var i = 0; i < keys.length; i++)
|
|
{
|
|
target[keys[i]] = src[keys[i]];
|
|
}
|
|
}
|
|
|
|
|
|
// pad string with spaces on the right
|
|
String.pads = function(str, len)
|
|
{
|
|
str = str ? str + "" : "";
|
|
|
|
while(str.length < len)
|
|
{
|
|
str = str + " ";
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
// pad string with zeros on the left
|
|
String.pad0 = function(str, len)
|
|
{
|
|
str = str ? str + "" : "";
|
|
|
|
while(str.length < len)
|
|
{
|
|
str = "0" + str;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
Array.range = function(n)
|
|
{
|
|
var a = [];
|
|
|
|
for(var i = 0; i < n; i++)
|
|
{
|
|
a[i] = i;
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* number to hex
|
|
* @param {number=} len
|
|
*/
|
|
function h(n, len)
|
|
{
|
|
//dbg_assert(typeof n === "number");
|
|
|
|
if(!n) return String.pad0("", len || 1);
|
|
|
|
if(len)
|
|
{
|
|
return String.pad0(n.toString(16).toUpperCase(), len);
|
|
}
|
|
else
|
|
{
|
|
return n.toString(16).toUpperCase();
|
|
}
|
|
}
|
|
|
|
Number.bits = function(n)
|
|
{
|
|
var result = [];
|
|
|
|
for(var bit = 31; bit > -1; bit--)
|
|
{
|
|
if(n & 1 << bit)
|
|
{
|
|
result.push(bit);
|
|
}
|
|
}
|
|
|
|
return result.join(', ');
|
|
}
|
|
|
|
String.chr_repeat = function(chr, count)
|
|
{
|
|
var result = "";
|
|
|
|
while(count--)
|
|
{
|
|
result += chr;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
Math.bcd_pack = function(n)
|
|
{
|
|
var i = 0,
|
|
result = 0,
|
|
digit;
|
|
|
|
while(n)
|
|
{
|
|
digit = n % 10;
|
|
|
|
result |= digit << (4 * i);
|
|
i++;
|
|
n = (n - digit) / 10;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @param {string=} msg
|
|
* */
|
|
function unimpl(msg)
|
|
{
|
|
var s = "Unimplemented" + (msg ? ": " + msg : "");
|
|
|
|
log(s);
|
|
|
|
if(DEBUG)
|
|
{
|
|
console.trace();
|
|
return s;
|
|
}
|
|
else
|
|
{
|
|
log("Execution stopped");
|
|
return s;
|
|
}
|
|
//this.name = "Unimplemented";
|
|
}
|
|
|
|
/**
|
|
* Synchronous access to ArrayBuffer
|
|
* @constructor
|
|
*/
|
|
function SyncBuffer(buffer)
|
|
{
|
|
this.byteLength = buffer.byteLength;
|
|
|
|
// warning: fn may be called synchronously or asynchronously
|
|
this.get = function(start, len, fn)
|
|
{
|
|
fn(new Uint8Array(buffer, start, len));
|
|
};
|
|
|
|
this.set = function(start, slice, fn)
|
|
{
|
|
new Uint8Array(buffer, start, slice.byteLength).set(slice);
|
|
fn();
|
|
};
|
|
|
|
this.get_buffer = function(fn)
|
|
{
|
|
fn(buffer);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Simple circular queue for logs
|
|
*
|
|
* @param {number} size
|
|
* @param {?=} Proto
|
|
* @constructor
|
|
*/
|
|
function CircularQueue(size, Proto)
|
|
{
|
|
var data,
|
|
index;
|
|
|
|
this.add = function(item)
|
|
{
|
|
data[index] = item;
|
|
|
|
index = (index + 1) % size;
|
|
};
|
|
|
|
this.toArray = function()
|
|
{
|
|
return [].slice.call(data, index).concat([].slice.call(data, 0, index));
|
|
};
|
|
|
|
this.clear = function()
|
|
{
|
|
if(Proto)
|
|
{
|
|
data = new Proto(size);
|
|
}
|
|
else
|
|
{
|
|
data = [];
|
|
}
|
|
|
|
index = 0;
|
|
};
|
|
|
|
this.set = function(new_data)
|
|
{
|
|
data = new_data;
|
|
index = 0;
|
|
};
|
|
|
|
|
|
this.clear();
|
|
}
|
|
|
|
|
|
|
|
// switch number to big endian
|
|
Math.to_be32 = function(dword)
|
|
{
|
|
return dword >>> 24 |
|
|
dword >> 8 & 0xff00 |
|
|
dword << 8 & 0xff0000 |
|
|
dword << 24;
|
|
}
|
|
|
|
Math.to_be16 = function(word)
|
|
{
|
|
return word >>> 8 & 0xff | word << 8 & 0xff00;
|
|
}
|
|
|
|
|
|
// used in several places
|
|
// the first entry is -1
|
|
// http://jsperf.com/integer-log2/2
|
|
var log2_table = (function()
|
|
{
|
|
var t = new Int8Array(256);
|
|
|
|
for(var i = 0, b = -2; i < 256; i++)
|
|
{
|
|
if(!(i & i - 1))
|
|
b++;
|
|
|
|
t[i] = b;
|
|
}
|
|
|
|
return t;
|
|
})();
|
|
|
|
|
|
// round away from zero, opposite of truncation
|
|
Math.roundInfinity = function(x)
|
|
{
|
|
return x > 0 ? Math.ceil(x) : Math.floor(x);
|
|
};
|
|
|