blob: ca8e6a9a33876be800ffb42082222b94c340df74 [file] [log] [blame] [raw]
"use strict";
var v86util = v86util || {};
// pad string with spaces on the right
v86util.pads = function(str, len)
{
str = str ? str + "" : "";
while(str.length < len)
{
str = str + " ";
}
return str;
};
// pad string with zeros on the left
v86util.pad0 = function(str, len)
{
str = str ? str + "" : "";
while(str.length < len)
{
str = "0" + str;
}
return str;
};
/**
* number to hex
* @param {number} n
* @param {number=} len
* @return {string}
*/
function h(n, len)
{
if(!n)
{
var str = "";
}
else
{
var str = n.toString(16);
}
return "0x" + v86util.pad0(str.toUpperCase(), len || 1);
}
if(typeof window !== "undefined" && window.crypto && window.crypto.getRandomValues)
{
let rand_data = new Int32Array(1);
v86util.has_rand_int = function()
{
return true;
};
v86util.get_rand_int = function()
{
window.crypto.getRandomValues(rand_data);
return rand_data[0];
};
}
else
{
v86util.has_rand_int = function()
{
return false;
};
v86util.get_rand_int = function()
{
console.assert(false);
};
}
/**
* Synchronous access to ArrayBuffer
* @constructor
*/
function SyncBuffer(buffer)
{
this.buffer = buffer;
this.byteLength = buffer.byteLength;
this.onload = undefined;
this.onprogress = undefined;
}
SyncBuffer.prototype.load = function()
{
this.onload && this.onload({ buffer: this.buffer });
};
/**
* @param {number} start
* @param {number} len
* @param {function(!Uint8Array)} fn
*/
SyncBuffer.prototype.get = function(start, len, fn)
{
dbg_assert(start + len <= this.byteLength);
fn(new Uint8Array(this.buffer, start, len));
};
/**
* @param {number} start
* @param {!Uint8Array} slice
* @param {function()} fn
*/
SyncBuffer.prototype.set = function(start, slice, fn)
{
dbg_assert(start + slice.byteLength <= this.byteLength);
new Uint8Array(this.buffer, start, slice.byteLength).set(slice);
fn();
};
/**
* @param {function(!ArrayBuffer)} fn
*/
SyncBuffer.prototype.get_buffer = function(fn)
{
fn(this.buffer);
};
(function()
{
var int_log2_table = new Int8Array(256);
for(var i = 0, b = -2; i < 256; i++)
{
if(!(i & i - 1))
b++;
int_log2_table[i] = b;
}
/**
* calculate the integer logarithm base 2 of a byte
* @param {number} x
* @return {number}
*/
v86util.int_log2_byte = function(x)
{
dbg_assert(x > 0);
dbg_assert(x < 0x100);
return int_log2_table[x];
};
/**
* calculate the integer logarithm base 2
* @param {number} x
* @return {number}
*/
v86util.int_log2 = function(x)
{
dbg_assert(x > 0);
// http://jsperf.com/integer-log2/6
var tt = x >>> 16;
if(tt)
{
var t = tt >>> 8;
if(t)
{
return 24 + int_log2_table[t];
}
else
{
return 16 + int_log2_table[tt];
}
}
else
{
var t = x >>> 8;
if(t)
{
return 8 + int_log2_table[t];
}
else
{
return int_log2_table[x];
}
}
};
})();
/**
* @constructor
*
* Queue wrapper around Uint8Array
* Used by devices such as the PS2 controller
*/
function ByteQueue(size)
{
var data = new Uint8Array(size),
start,
end;
dbg_assert((size & size - 1) === 0);
this.length = 0;
this.push = function(item)
{
if(this.length === size)
{
// intentional overwrite
}
else
{
this.length++;
}
data[end] = item;
end = end + 1 & size - 1;
};
this.shift = function()
{
if(!this.length)
{
return -1;
}
else
{
var item = data[start];
start = start + 1 & size - 1;
this.length--;
return item;
}
};
this.peek = function()
{
if(!this.length)
{
return -1;
}
else
{
return data[start];
}
};
this.clear = function()
{
start = 0;
end = 0;
this.length = 0;
};
this.clear();
}
/**
* @constructor
*
* Queue wrapper around Float32Array
* Used by devices such as the sound blaster sound card
*/
function FloatQueue(size)
{
this.size = size;
this.data = new Float32Array(size);
this.start = 0;
this.end = 0;
this.length = 0;
dbg_assert((size & size - 1) === 0);
}
FloatQueue.prototype.push = function(item)
{
if(this.length === this.size)
{
// intentional overwrite
this.start = this.start + 1 & this.size - 1;
}
else
{
this.length++;
}
this.data[this.end] = item;
this.end = this.end + 1 & this.size - 1;
};
FloatQueue.prototype.shift = function()
{
if(!this.length)
{
return undefined;
}
else
{
var item = this.data[this.start];
this.start = this.start + 1 & this.size - 1;
this.length--;
return item;
}
};
FloatQueue.prototype.shift_block = function(count)
{
var slice = new Float32Array(count);
if(count > this.length)
{
count = this.length;
}
var slice_end = this.start + count;
var partial = this.data.subarray(this.start, slice_end);
slice.set(partial);
if(slice_end >= this.size)
{
slice_end -= this.size;
slice.set(this.data.subarray(0, slice_end), partial.length);
}
this.start = slice_end;
this.length -= count;
return slice;
};
FloatQueue.prototype.peek = function()
{
if(!this.length)
{
return undefined;
}
else
{
return this.data[this.start];
}
};
FloatQueue.prototype.clear = function()
{
this.start = 0;
this.end = 0;
this.length = 0;
};
/**
* Simple circular queue for logs
*
* @param {number} size
* @constructor
*/
function CircularQueue(size)
{
this.data = [];
this.index = 0;
this.size = size;
}
CircularQueue.prototype.add = function(item)
{
this.data[this.index] = item;
this.index = (this.index + 1) % this.size;
};
CircularQueue.prototype.toArray = function()
{
return [].slice.call(this.data, this.index).concat([].slice.call(this.data, 0, this.index));
};
CircularQueue.prototype.clear = function()
{
this.data = [];
this.index = 0;
};
/**
* @param {Array} new_data
*/
CircularQueue.prototype.set = function(new_data)
{
this.data = new_data;
this.index = 0;
};
function dump_file(ab, name)
{
if(!(ab instanceof Array))
{
ab = [ab];
}
var blob = new Blob(ab);
download(blob, name);
}
function download(file_or_blob, name)
{
var a = document.createElement("a");
a["download"] = name;
a.href = window.URL.createObjectURL(file_or_blob);
a.dataset["downloadurl"] = ["application/octet-stream", a["download"], a.href].join(":");
if(document.createEvent)
{
var ev = document.createEvent("MouseEvent");
ev.initMouseEvent("click", true, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
a.dispatchEvent(ev);
}
else
{
a.click();
}
window.URL.revokeObjectURL(a.href);
}