csim.xul |
csim.js |
options.xul |
options.js |
about.xul |
consts.js |
screen.js |
platform.js |
csim.dtd |
csim.css |
b2a.c
include(jslib_file);
include(jslib_fileutils);
include(jslib_dirutils);
include('chrome://csim/content/consts.js');
include('chrome://csim/content/platform.js');
include('chrome://csim/content/screen.js');
const
cmdBitMaskStr = Math.pow(2, 5).toString(2),
nsBitOprRange = 2147483647,
regSize = 32,
regNum = 32;
var
intDelay = 200,
intHistorySize = 100,
scrDelayMul = 2,
intHistoryLimit = true,
intHistoryLastTop = true,
binFile,
cheapMem = new Array,
cheapMemStr = new Array,
cheapReg = new Array(32),
cheapTmr = new Array,
cheapIrq = new Array(16),
cheapPrt = new Array(4096),
mpdiFile = { loc: 'mpdiFile', inUse: false },
mpdoFile = { loc: 'mpdoFile', inUse: false },
instrParam = { rg_alp_n: 0, rg_bet_n: 0, rg_alp_v: 0, rg_bet_v: 0, im_v: 0 },
intvInterpr = { id: 0, run: false},
intvScreen = { id: 0 },
cursor = { x: 0, y: 0 },
scrBuffer = new Array,
scrBufferSize = 128,
memOffsetMulti = 8, // 8 for 32 bit word, 32 for byte
irqEnabledCnt, servedInt, cnt, pause;
chrInitMem(64);
chrInitReg();
chrInitIrq();
chrInitScr();
var mainTab = document.getElementById('main-vbox').removeChild(document.getElementById('main-tab'));
mainTab.setAttribute('hidden', 'false');
var instrTreeItem = document.createElement('treeitem')
with (instrTreeItem) {
appendChild(document.createElement('treerow'));
firstChild.appendChild(document.createElement('treecell'));
firstChild.appendChild(document.createElement('treecell'));
firstChild.appendChild(document.createElement('treecell'));
}
function getNiceStr(numStr, base) {
var tmp = (numStr - 0).toString(base);
return '00000000'.substr(tmp.length) + tmp.toUpperCase();
}
function getBundledZeros() {
var tmpStr = '';
for (var i = 0; i != 8; i++)
tmpStr += '00000000 ';
return tmpStr.slice(0, -1);
}
function chrInitProgMem() {
var
memPos = 0,
treeChilds;
for (var treeItem = 0; memPos < cheapMem.length; treeItem++) {
var tmpStr = '';
for (memPos = treeItem * 8; memPos < treeItem * 8 + 8; memPos++)
tmpStr += getNiceStr(cheapMem[memPos] ? cheapMem[memPos] : '0', 16) + ' ';
if (treeItem == (treeChilds = document.getElementById('mem-treech')).childNodes.length)
chrInitMem(64);
treeChilds.childNodes[treeItem].lastChild.lastChild.setAttribute('label', tmpStr.slice(0, -1));
}
}
function chrInitMem(addLinesNum) {
var
treeItem, memChilds = document.getElementById('mem-treech'),
bundledZeros = getBundledZeros(),
addLinesOffset = memChilds.childNodes.length;
for (var i = addLinesOffset; i < addLinesOffset + addLinesNum; i++) {
with (treeItem = document.createElement('treeitem')) {
appendChild(document.createElement('treerow'));
lastChild.appendChild(document.createElement('treecell'));
lastChild.lastChild.setAttribute('label', getNiceStr(i * memOffsetMulti, 10));
lastChild.appendChild(document.createElement('treecell'));
lastChild.lastChild.setAttribute('label', bundledZeros);
}
memChilds.appendChild(treeItem);
}
}
function chrInitReg() {
var treeItem, regChilds = document.getElementById('reg-treech');
for (var i = 0; i != 32; i++) {
with (treeItem = document.createElement('treeitem')) {
appendChild(document.createElement('treerow'));
lastChild.appendChild(document.createElement('treecell'));
lastChild.lastChild.setAttribute('label', i);
lastChild.appendChild(document.createElement('treecell'));
lastChild.lastChild.setAttribute('label', '0');
}
regChilds.appendChild(treeItem);
}
}
function chrInitIrq() {
var newRow, irqRows = document.getElementById('irq-rows');
for (var i = 0; i != 8; i++) {
with (newRow = document.createElement('row')) {
appendChild(document.createElement('label'));
lastChild.setAttribute('value', i);
appendChild(document.createElement('spacer'));
appendChild(document.createElement('image'));
lastChild.setAttribute('id', 'irq_ri');
lastChild.setAttribute('style', 'max-height: 10px');
appendChild(document.createElement('spacer'));
appendChild(document.createElement('image'));
lastChild.setAttribute('id', 'irq_si');
lastChild.setAttribute('style', 'max-height: 10px');
appendChild(document.createElement('spacer'));
appendChild(document.createElement('label'));
lastChild.setAttribute('value', i + 8);
appendChild(document.createElement('spacer'));
appendChild(document.createElement('image'))
lastChild.setAttribute('id', 'irq_ri');
lastChild.setAttribute('style', 'max-height: 10px');
appendChild(document.createElement('spacer'));
appendChild(document.createElement('image'))
lastChild.setAttribute('id', 'irq_si');
lastChild.setAttribute('style', 'max-height: 10px');
appendChild(document.createElement('spacer'));
}
irqRows.appendChild(newRow);
}
}
function updControls(ctrlStr) {
var controls = document.getElementById('controls').childNodes, pos, name;
for (var i = 0; i != controls.length; i++) {
if ((name = controls[i].getAttribute('id').slice(4)).length == 0)
continue;
if ((pos = ctrlStr.search(name)) != -1 || (pos = ctrlStr.search('all')) != -1)
document.getElementById('btn-' + name).setAttribute('disabled', ctrlStr.charAt(pos - 1) == '-');
}
}
function initRegisters() {
for (var i = 0; i != cheapReg.length; cheapReg[i++] = 0);
}
function initMem() {
cheapMem.length = 0;
for (var i = 0; i != cheapMemStr.length; cheapMem[i] = cheapMemStr[i] - 0, i++);
}
function initInterrupts() {
for (var i = 0; i != cheapIrq.length; cheapIrq[i++] = { running: false, isrPos: 0 });
}
function initPorts() {
for (var i = 0; i != cheapPrt.length; cheapPrt[i++] = 0);
}
function initTimers() {
cheapTmr[regTA] = { active: false, actVal: 0 };
cheapTmr[regTB] = { active: false, actVal: 0 };
}
function pickFile() {
var nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(window, "Select a File", nsIFilePicker.modeOpen);
fp.appendFilter("Cheap Binary", "*.chb");
fp.appendFilters(nsIFilePicker.filterAll);
var res = fp.show();
if (res == nsIFilePicker.returnOK) return fp.file;
else return false;
}
function openFile() {
var pickedFile = pickFile();
if (pickedFile) {
/*
var b2aDirCpl = dSep + 'csim' + dSep + 'bin' + dSep;
var dirUtil = new DirUtils;
var fileUtil = new FileUtils;
fileUtil.spawn(dirUtil.getChromeDir() + b2aDirCpl + b2aBin,
[pickedFile.path, dirUtil.getChromeDir() + b2aDirCpl + 'b2a.output']);
var badFile = new File(pickedFile.path);
binFile = new File(dirUtil.getChromeDir() + b2aDirCpl + 'b2a.output');
*/
var
fileUtil = new FileUtils,
dirUtil = new DirUtils;
fileUtil.spawn(fileUtil.append(loca.natBin, b2aBin),
[pickedFile.path, fileUtil.append(dirUtil.getTmpDir(), 'b2a.output') ]);
var badFile = new File(pickedFile.path);
binFile = new File(fileUtil.append(dirUtil.getTmpDir(), 'b2a.output'));
initRegisters();
initInterrupts();
initPorts();
initTimers();
while (!(binFile.exists && binFile.size == badFile.size * 2.50));
binFile.open();
// cheapMemStr = binFile.read().slice(0, -1).split(String.fromCharCode(10));
cheapMemStr.length = 0;
cheapMemStr = binFile.read().match(/........../g);
binFile.close();
binFile.remove();
initMem();
document.getElementById('main-vbox').insertBefore(mainTab.cloneNode('true'), document.getElementById('status-bar'));
chrInitProgMem();
updControls('+start');
document.getElementById('status-text').setAttribute('label', badFile.path + ', ' + badFile.size + ' bytes');
document.getElementById('menu-help-doc_tab:command').setAttribute('disabled', false);
document.getElementById('menu-file-close:command').setAttribute('disabled', false);
document.getElementById('menu-file-open:command').setAttribute('disabled', true);
intvScreen.id =
window.setInterval('if (scrBuffer.length) chrUpdateScr(scrBuffer.shift())', intDelay * scrDelayMul);
}
}
function closeFile() {
if (mpdoFile.inUse) mpdoFile.close();
mpdoFile.inUse = mpdiFile.inUse = false;
scrBuffer.length = 0;
window.clearInterval(intvScreen.id);
with (intvInterpr) if (run) window.clearInterval((run = false, id));
document.getElementById('main-vbox').removeChild(document.getElementById('main-tab'));
updControls('-all');
document.getElementById('status-text').setAttribute('label', '');
document.getElementById('menu-help-doc_tab').setAttribute('checked', '');
document.getElementById('menu-help-doc_tab:command').setAttribute('disabled', true);
document.getElementById('menu-file-close:command').setAttribute('disabled', true);
document.getElementById('menu-file-open:command').setAttribute('disabled', false);
}
function startRun() {
irqEnabledCnt = cnt = 1;
servedInt = [cheapIrq.length];
with (cursor) { x = 0; y = 0; };
with (curr) { bc = colors.bc[40]; tc = colors.tc[37]; bold = 0 };
escape.status = 'off';
pause = false;
updControls('-start +pause +reset');
intvInterpr.id = window.setInterval('interprete()', intDelay);
intvInterpr.run = true;
}
function pauseRun() {
updControls('-pause +conti');
pause = true;
}
function contiRun() {
updControls('+pause -conti');
pause = false;
}
function resetRun() {
with (intvInterpr) if (run) window.clearInterval((run = false, id));
window.clearInterval(intvScreen.id);
document.getElementById('menu-help-doc_tab').setAttribute('checked', '');
document.getElementById('main-vbox').removeChild(document.getElementById('main-tab'));
document.getElementById('main-vbox').insertBefore(mainTab.cloneNode('true'), document.getElementById('status-bar'));
initRegisters();
initInterrupts();
initPorts();
initTimers();
initMem();
if (mpdoFile.inUse) mpdoFile.close();
mpdoFile.inUse = mpdiFile.inUse = false;
scrBuffer.length = 0;
chrInitProgMem();
updControls('+start -all');
intvScreen.id =
window.setInterval('if (scrBuffer.length) chrUpdateScr(scrBuffer.shift())', intDelay * scrDelayMul);
}
function interprete() {
if (!pause) {
var
cmdStr, oprStr, oprHexStr,
treeItem = instrTreeItem.cloneNode(true),
instrChilds = document.getElementById('instr-treech');
if (irqEnabledCnt == -1 || irqEnabledCnt == 0) irqEnabledCnt++;
if (cheapTmr[regTA].active && (new Date().getTime() >= cheapReg[regTA] + cheapTmr[regTA].actVal)) {
cheapTmr[regTA].active = false;
cheapIrq[1].running = true;
chrUpdIrqState(1, 'r', 'a');
}
if (cheapTmr[regTB].active && (new Date().getTime() >= cheapReg[regTB] + cheapTmr[regTB].actVal)) {
cheapTmr[regTB].active = false;
cheapIrq[2].running = true;
chrUpdIrqState(2, 'r', 'a');
}
if (document.getElementById('cheap-input').value.length) {
cheapIrq[3].running = true;
chrUpdIrqState(3, 'r', 'a');
}
if (scrBuffer.length >= scrBufferSize) {
cheapIrq[4].running = true;
chrUpdIrqState(4, 'r', 'a');
}
if (irqEnabledCnt == 1)
for (i = 0; i < servedInt[servedInt.length - 1]; i++)
if (cheapIrq[i].running) {
cheapReg[regRI] = cheapReg[regPC];
cheapReg[regPC] = cheapIrq[i].isrPos;
servedInt.push(i);
cheapIrq[i].running = false;
chrUpdIrqState(i, 'r', 'i');
chrUpdIrqState(i, 's', 'a');
}
with (document.getElementById('reg-treech').childNodes[regPC].lastChild.lastChild)
setAttribute('label', ++cheapReg[regPC]);
cmdStr = getCurr_cmdStr();
oprStr = instr[cmdStr]['name'] + '/' + instr[cmdStr]['type'] + ' ';
oprHexStr = getNiceStr(cheapMem[cheapReg[regPC] - 1], 16);
with (instrParam)
switch (instr[cmdStr]['type']) {
case 'i':
rg_alp_n = getCurr_rgn('alp');
rg_alp_v = cheapReg[rg_alp_n] - 0;
im_v = getCurr_im('sho');
oprStr += 'r' + rg_alp_n + '[' + rg_alp_v + '], ' + im_v;
break;
case 'r':
rg_alp_n = getCurr_rgn('alp');
rg_alp_v = cheapReg[rg_alp_n] - 0;
rg_bet_n = getCurr_rgn('bet');
rg_bet_v = cheapReg[rg_bet_n] - 0;
oprStr += 'r' + rg_alp_n + '[' + rg_alp_v + '], r' + rg_bet_n + '[' + rg_bet_v + ']';
break;
case 'j':
im_v = getCurr_im('lon');
oprStr += im_v;
break;
case 's':
rg_alp_n = getCurr_rgn('alp');
rg_alp_v = cheapReg[rg_alp_n] - 0;
oprStr += 'r' + rg_alp_n + '[' + rg_alp_v + ']';
break;
}
eval('with (instrParam) {' + instr[cmdStr]['code'] + '}');
with (treeItem.firstChild) {
firstChild.setAttribute('label', cnt);
firstChild.nextSibling.setAttribute('label', oprHexStr);
lastChild.setAttribute('label', oprStr);
}
while (intHistoryLimit && instrChilds.childNodes.length >= intHistorySize)
instrChilds.removeChild(instrChilds[intHistoryLastTop ? 'lastChild' : 'firstChild']);
if (intHistoryLastTop)
instrChilds.insertBefore(treeItem, instrChilds.firstChild);
else
instrChilds.appendChild(treeItem);
if (cheapReg[regPC] == 4095) {
document.getElementById('btn-pause').setAttribute('disabled', 'true');
with (intvInterpr) window.clearInterval((run = false, id));
}
cnt++;
}
}
function getCurr_cmdStr() {
var
opCode = opr_shr(cheapMem[cheapReg[regPC] - 1], 27),
tmpStr = (opCode ? opCode : cheapMem[cheapReg[regPC] - 1] & (Math.pow(2, 6) - 1)).toString(2);
return (opCode ? 'oc_' : 'sc_') + cmdBitMaskStr.substr(tmpStr.length) + tmpStr;
}
function getCurr_im(imType) {
return cheapMem[cheapReg[regPC] - 1] & (Math.pow(2, imType == 'sho' ? 22 : 27) - 1);
}
function getCurr_rgn(rgType) {
return rgType == 'alp' ? opr_shr(cheapMem[cheapReg[regPC] - 1] & 130023424 , 22)
: opr_shr(cheapMem[cheapReg[regPC] - 1] & 4063232, 17);
}
function setReg(value) {
var regSel = arguments.length == 2 ? arguments[1] : instrParam.rg_alp_n;
with (document.getElementById('reg-treech').childNodes[regSel].lastChild.lastChild)
setAttribute('label', cheapReg[regSel] = value);
if (regSel == regTA || regSel == regTB)
with (cheapTmr[regSel]) {
active = true;
actVal = new Date().getTime();
}
}
function updStrSection(str, pos, section) {
return str.slice(0, pos) + section + str.slice(pos + section.length);
}
function setMem(value, offset) {
while (document.getElementById('mem-treech').childNodes.length <= Math.floor(offset / 8))
chrInitMem(128);
var cellToChange = document.getElementById('mem-treech').childNodes[Math.floor(offset / 8)].lastChild.lastChild;
cellToChange.setAttribute('label', updStrSection(cellToChange.getAttribute('label'), offset % 8 * 9, getNiceStr(value, 16)));
cheapMem[offset] = value;
}
function subPdOut(value, port) {
switch (port) {
case 1:
scrBuffer.push(value);
break;
case 3:
if ( !mpdoFile.inUse ) {
var loc = mpdoFile.loc;
mpdoFile = new File((new FileUtils).append((new DirUtils).getHomeDir(), loc));
mpdoFile.loc = loc; // dirty !!
mpdoFile.inUse = true;
mpdoFile.open('w');
}
mpdoFile.write(String.fromCharCode(value));
break;
default:
alert('no device at port ' + port);
}
}
function subPdIn(port) {
switch (port) {
case 0:
var kbdBuffer = document.getElementById('cheap-input');
if (kbdBuffer.value.length) {
cheapPrt[port] = kbdBuffer.value.charCodeAt(0);
kbdBuffer.value = kbdBuffer.value.slice(1);
}
else
cheapPrt[port] = 0;
break;
case 2:
if ( !mpdiFile.inUse ) {
var loc = mpdiFile.loc;
mpdiFile = new File((new FileUtils).append((new DirUtils).getHomeDir(), loc));
mpdiFile.loc = loc; // dirty !!
mpdiFile.inUse = true;
mpdiFile.open();
mpdiFile.content = mpdiFile.read();
mpdiFile.close();
cheapPrt[port] = mpdiFile.size;
mpdiFile.pointer = 0;
break;
}
if (mpdiFile.pointer == mpdiFile.size) {
cheapPrt[port] = 0;
break;
}
cheapPrt[port] = mpdiFile.content.charCodeAt(mpdiFile.pointer++);
break;
case 4:
cheapPrt[port] = Math.floor(Math.random() * (Math.pow(2, 32) - 1));
break;
default:
alert('no device at port ' + port);
}
return cheapPrt[port];
}
function chrUpdIrqState(irqNum, irqState, aState) {
var
row = irqNum % 8,
col = irqNum < 8 ? 2 : 8,
res = 'irq_' + irqState + aState;
if (irqState == 's')
col += 2;
document.getElementById('irq-rows').childNodes[row].childNodes[col].setAttribute('id', res);
}
function resetIntDelay(val) {
switch (val) {
case 'inc':
intDelay *= 2; break;
case 'dec':
intDelay = Math.round(intDelay / 2); break;
default:
intDelay = val;
}
if (intvInterpr.run) {
clearInterval(intvInterpr.id);
intvInterpr.id = setInterval('interprete()', intDelay);
}
clearInterval(intvScreen.id);
intvScreen.id = setInterval('if (scrBuffer.length) chrUpdateScr(scrBuffer.shift())', intDelay * scrDelayMul);
}
function newFile() {
/*
var localFile = "/tmp/fubar.dat";
var f = new File(localFile);
if (!(f.exists())) f.create();
*/
/*
var tmpStr = '';
for (var prop in cheapReg) tmpStr += prop + ' => ' + cheapReg[prop] + '\n';
alert(tmpStr);
*/
alert('functionality not implemented yet.');
}
function openOptionsDlg() {
window.openDialog('chrome://csim/content/options.xul', 'win-options', 'chrome, dependent, alwaysRaised');
}
function openDoc() {
window.open(loca.urlDoc + '/csim.html', 'win-doc');
}
function openAbout() {
window.openDialog('chrome://csim/content/about.xul', 'win-about', 'chrome, dependent, alwaysRaised');
}
function addDocTab() {
if (document.getElementById('menu-help-doc_tab').getAttribute('checked') != 'true') {
document.getElementById('main-tab').firstChild.removeChild(document.getElementById('doc-panel-tab'));
with (document.getElementById('doc-panel'))
removeChild(firstChild);
}
else {
with (document.getElementById('main-tab').firstChild) {
appendChild(document.createElement('tab'));
lastChild.setAttribute('id', 'doc-panel-tab');
lastChild.setAttribute('label', 'Documentation');
}
with (document.getElementById('doc-panel')) {
appendChild(document.createElement('iframe'));
lastChild.contentWindow.window.name = '_blank';
lastChild.setAttribute('flex', '1');
lastChild.setAttribute('src', loca.urlDoc + '/csim.html');
}
}
}
function createBitArray(val) {
for (var bitArray = new Array, i = 0; i < regSize; i++)
bitArray[i] = val & Math.pow(2, i) ? 2 : 0;
return bitArray;
}
function opr_shl(val, pos) {
return val * Math.pow(2, pos) % Math.pow(2, 32);
}
function opr_shr(val, pos) {
return Math.floor(val / Math.pow(2, pos));
}
function opr_or(val_alp, val_bet) {
// one operand out of nsBitOprRange
if (Math.max(val_alp, val_bet) > nsBitOprRange) {
var
bitArrayAlp = createBitArray(val_alp),
bitArrayBet = createBitArray(val_bet),
result = 0;
for (var i = 1; i < regSize; i++)
result += Math.pow(bitArrayAlp[i] || bitArrayBet[i] ? 2 : 0, i);
return bitArrayAlp[0] || bitArrayBet[0] ? ++result : result;
}
else
return val_alp | val_bet;
}
function opr_xor(val_alp, val_bet) {
// one operand out of nsBitOprRange
if (Math.max(val_alp, val_bet) > nsBitOprRange) {
var
bitArrayAlp = createBitArray(val_alp),
bitArrayBet = createBitArray(val_bet),
result = 0;
for (var i = 1; i < regSize; i++)
result += Math.pow(bitArrayAlp[i] - bitArrayBet[i] ? 2 : 0, i);
return bitArrayAlp[0] - bitArrayBet[0] ? ++result : result;
}
else
return val_alp ^ val_bet;
}
function opr_and(val_alp, val_bet) {
// both operands out of nsBitOprRange
if (Math.min(val_alp, val_bet) > nsBitOprRange) {
var
bitArrayAlp = createBitArray(val_alp),
bitArrayBet = createBitArray(val_bet),
result = 0;
for (var i = 1; i < regSize; i++)
result += Marh.pow(bitArrayAlp[i] && bitArrayBet[i] ? 2 : 0, i);
return bitArrayAlp[0] && bitArrayBet[0] ? ++result : result;
}
else
return val_alp & val_bet;
}