First Commit

This commit is contained in:
Barry Silverman 2010-09-17 22:42:04 -04:00
commit 4d8da5b680
16 changed files with 12712 additions and 0 deletions

0
README Normal file
View File

186
chipsim.js Normal file
View File

@ -0,0 +1,186 @@
var ctrace = false;
var ridx = 0;
function recalcNodeList(list){
var n = list[0];
var recalclist = new Array();
for(var j=0;j<100;j++){ // loop limiter
if(list.length==0) return;
if(ctrace) console.log(j, list);
for(var i in list) recalcNode(list[i], recalclist);
list = recalclist;
recalclist = new Array();
}
console.log(n,'looping...');
}
function recalcNode(node, recalclist){
if(node==ngnd) return;
if(node==npwr) return;
var group = getNodeGroup(node);
var newv = getNodeValue(group);
if(ctrace) console.log('recalc', node, group);
for(var i in group){
var n = nodes[group[i]];
if(n.state!=newv && ctrace) console.log(group[i], n.state, newv);
n.state = newv;
for(var t in n.gates) recalcTransistor(n.gates[t], recalclist);
}
}
function recalcTransistor(tn, recalclist){
var t = transistors[tn];
if(isNodeHigh(t.gate)) turnTransistorOn(t, recalclist);
else turnTransistorOff(t, recalclist);
}
function turnTransistorOn(t, recalclist){
if(t.on) return;
if(ctrace) console.log(t.name, 'on', t.gate, t.c1, t.c2);
t.on = true;
addRecalcNode(t.c1, recalclist);
addRecalcNode(t.c2, recalclist);
}
function turnTransistorOff(t, recalclist){
if(!t.on) return;
if(ctrace) console.log(t.name, 'off', t.gate, t.c1, t.c2);
t.on = false;
floatnode(t.c1);
floatnode(t.c2);
addRecalcNode(t.c1, recalclist);
addRecalcNode(t.c2, recalclist);
}
function floatnode(nn){
if(nn==ngnd) return;
if(nn==npwr) return;
var n = nodes[nn];
if(n.state=='gnd') n.state = 'fl';
if(n.state=='pd') n.state = 'fl';
if(n.state=='vcc') n.state = 'fh';
if(n.state=='pu') n.state = 'fh';
if(ctrace) console.log('floating', nn, 'to', n.state);
}
function addRecalcNode(nn, recalclist){
if(nn==ngnd) return;
if(nn==npwr) return;
if(arrayContains(recalclist, nn)) return;
recalclist.push(nn);
// setAdd(recalclist, nn);
}
function getNodeGroup(i){
var group = new Array();
addNodeToGroup(i, group);
return group;
}
function addNodeToGroup(i, group){
if(arrayContains(group, i)) return;
group.push(i);
if(i==ngnd) return;
if(i==npwr) return;
for(var t in nodes[i].c1c2s) addNodeTransistor(i, nodes[i].c1c2s[t], group);
}
function addNodeTransistor(node, t, group){
var tr = transistors[t];
if(!tr.on) return;
var other;
if(tr.c1==node) other=tr.c2;
if(tr.c2==node) other=tr.c1;
addNodeToGroup(other, group);
}
function getNodeValue(group){
if(arrayContains(group, ngnd)) return 'gnd';
if(arrayContains(group, npwr)) return 'vcc';
var flstate;
for(var i in group){
var nn = group[i];
var n = nodes[nn];
if(n.pullup) return 'pu';
if(n.pulldown) return 'pd';
if((n.state=='fl')&&(flstate==undefined)) flstate = 'fl';
if(n.state=='fh') flstate = 'fh';
}
if(flstate==undefined) console.log(group);
return flstate;
}
function isNodeHigh(nn){
return arrayContains(['vcc','pu','fh'], nodes[nn].state);
}
function saveString(name, str){
var request = new XMLHttpRequest();
request.onreadystatechange=function(){};
request.open('PUT', 'save.php?name='+name, true);
request.setRequestHeader('Content-Type', 'text/plain');
request.send(str);
}
function allNodes(){
var res = new Array();
for(var i in nodes) if((i!=npwr)&&(i!=ngnd)) res.push(i);
return res;
}
function stateString(){
var codes = {gnd: 'g', vcc: 'v', pu: 'p', pd: 'd', fh: 'f', fl: 'l'};
var res = '';
for(var i=0;i<1725;i++){
var n = nodes[i];
if(n==undefined) res+='x';
else if(i==ngnd) res+='g';
else if(i==npwr) res+='v';
else res+= codes[n.state];
}
return res;
}
function showState(str){
var codes = {g: 'gnd', v: 'vcc', p: 'pu', d: 'pd', f: 'fh', l: 'fl'};
for(var i=0;i<str.length;i++){
if(str[i]=='x') continue;
nodes[i].state = codes[str[i]];
var gates = nodes[i].gates;
for(var t in gates) transistors[gates[t]].on = isNodeHigh(i);
}
refresh();
}
function setPd(name){
var nn = nodenames[name];
nodes[nn].pullup = false;
nodes[nn].pulldown = true;
}
function setHigh(name){
var nn = nodenames[name];
nodes[nn].pullup = true;
nodes[nn].pulldown = false;
recalcNodeList([nn]);
}
function setLow(name){
var nn = nodenames[name];
nodes[nn].pullup = false;
nodes[nn].pulldown = true;
recalcNodeList([nn]);
}
function setAdd(arr, el){
var idx = ridx%(arr.length+1);
ridx+=131;
ridx%=123;
arr.splice(idx, 0, el);
return arr;
}
function arrayContains(arr, el){return arr.indexOf(el)!=-1;}

BIN
images/next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

BIN
images/play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

BIN
images/prev.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

BIN
images/stop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
images/up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

36
index.html Normal file
View File

@ -0,0 +1,36 @@
<!DOCTYPE html>
<head>
<title>6502</title>
<style type="text/css">@import "wires.css";</style>
<script src="segdefs.js"></script>
<script src="transdefs.js"></script>
<script src="nodenames.js"></script>
<script src="wires.js"></script>
<script src="chipsim.js"></script>
<script src="memtable.js"></script>
<script src="macros.js"></script>
</head>
<body onload="setup();">
<p class="title">The 6502</p>
<div class="frame" id="frame">
<div class="chip">
<canvas class="chip" id="chipbg"></canvas>
<canvas class="chip" id="overlay"></canvas>
<canvas class="chip" id="hilite"></canvas>
<canvas class="chip" id="hitbuffer"></canvas>
</div>
<div class = "buttons">
<a href ="javascript:stopChip()"id="stop"><img class="navstop" src="images/stop.png"></a>
<a href ="javascript:runChip()" id="start"><img class="navplay" src="images/play.png"></a>
<a href ="javascript:resetChip()"><img class="navbutton" src="images/up.png"></a>
<a href ="javascript:stepBack()"><img class="navbutton" src="images/prev.png"></a>
<a href ="javascript:stepForward()"><img class="navbutton" src="images/next.png"></a>
</div>
<p class="status" id="status">x: 0<br>y: 0</p>
<table class="memtable" id="memtable"></table>
</div>
</body>
</html>

179
macros.js Normal file
View File

@ -0,0 +1,179 @@
var memory = Array();
var code = [0xa9, 0x00, 0x20, 0x10, 0x00, 0x4c, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x88, 0xe6, 0x40, 0x38, 0x69, 0x02, 0x60];
var cycle = 0;
var trace = Array();
var running = false;
function go(n){
for(var i=0;i<code.length;i++){
mWrite(i, code[i]);
setCellValue(i, code[i]);
}
mWrite(0xfffc, 0x00);
mWrite(0xfffd, 0x00);
steps();
}
function steps(){
if(running) step();
setTimeout(steps, 200);
}
function initChip(){
for(var nn in nodes) nodes[nn].state = 'fl';
nodes[ngnd].state = 'gnd';
nodes[npwr].state = 'vcc';
for(var tn in transistors) transistors[tn].on = false;
setLow('res');
setLow('clk0');
setHigh('rdy'); setLow('so');
setHigh('irq'); setHigh('nmi');
recalcNodeList(allNodes());
for(var i=0;i<8;i++){setHigh('clk0'), setLow('clk0');}
setHigh('res');
for(var i=0;i<14;i++){step();}
refresh();
cycle = 0;
trace = Array();
chipStatus();
}
function step(){
trace[cycle]= {chip: stateString(), mem: getMem()};
halfStep();
cycle++;
chipStatus();
}
function halfStep(){
var clk = isNodeHigh(nodenames['clk0']);
if (clk) {setLow('clk0'); handleBusRead(); }
else {setHigh('clk0'); handleBusWrite();}
refresh();
}
function handleBusRead(){
if(isNodeHigh(nodenames['rw'])) writeDataBus(mRead(readAddressBus()));
}
function handleBusWrite(){
if(!isNodeHigh(nodenames['rw'])){
var a = readAddressBus();
var d = readDataBus();
mWrite(a,d);
if(a<0x200) setCellValue(a,d);
}
}
function readAddressBus(){return readBits('ab', 16);}
function readDataBus(){return readBits('db', 8);}
function readA(){return readBits('a', 8);}
function readY(){return readBits('y', 8);}
function readX(){return readBits('x', 8);}
function readP(){return readBits('p', 8);}
function readSP(){return readBits('s', 8);}
function readBits(name, n){
var res = 0;
for(var i=0;i<n;i++){
var nn = nodenames[name+i];
res+=((isNodeHigh(nn))?1:0)<<i;
}
return res;
}
function writeDataBus(x){
var recalcs = Array();
for(var i=0;i<8;i++){
var nn = nodenames['db'+i];
var n = nodes[nn];
if((x%2)==0) {n.pulldown=true; n.pullup=false;}
else {n.pulldown=false; n.pullup=true;}
recalcs.push(nn);
x>>=1;
}
recalcNodeList(recalcs);
}
function mRead(a){
if(memory[a]==undefined) return 0;
else return memory[a];
}
function mWrite(a, d){memory[a]=d;}
function clkNodes(){
var res = Array();
res.push(943);
for(var i in nodes[943].gates){
var t = transistors[nodes[943].gates[i]];
if(t.c1==npwr) res.push(t.c2);
if(t.c2==npwr) res.push(t.c1);
}
hiliteNode(res);
}
function runChip(){
var start = document.getElementById('start');
var stop = document.getElementById('stop');
start.style.visibility = 'hidden';
stop.style.visibility = 'visible';
running = true;
}
function stopChip(){
var start = document.getElementById('start');
var stop = document.getElementById('stop');
start.style.visibility = 'visible';
stop.style.visibility = 'hidden';
running = false;
}
function resetChip(){
stopChip();
initChip();
}
function stepForward(){
stopChip();
step();
}
function stepBack(){
if(cycle==0) return;
showState(trace[--cycle].chip);
setMem(trace[cycle].mem);
var clk = isNodeHigh(nodenames['clk0']);
if(!clk) writeDataBus(mRead(readAddressBus()));
chipStatus();
}
function chipStatus(){
var pc = readAddressBus();
setStatus('PC:', hexWord(pc),
'D:', hexByte(readDataBus()),
'SP:',hexByte(readSP()),
'cycle:', cycle, '<br>',
'A:', hexByte(readA()),
'X:', hexByte(readX()),
'Y:', hexByte(readY()),
'P:', hexByte(readP())
);
selectCell(pc);
}
function getMem(){
var res = Array();
for(var i=0;i<0x200;i++) res.push(mRead(i));
return res;
}
function setMem(arr){
for(var i=0;i<0x200;i++){mWrite(i, arr[i]); setCellValue(i, arr[i]);}
}
function hexWord(n){return (0x10000+n).toString(16).substring(1)}
function hexByte(n){return (0x100+n).toString(16).substring(1)}

67
memtable.js Normal file
View File

@ -0,0 +1,67 @@
var table;
var selected;
function setupTable(){
table = document.getElementById('memtable');
for(var r=0;r<32;r++){
var row = document.createElement('tr');
table.appendChild(row);
var col = document.createElement('td');
col.appendChild(document.createTextNode(hexWord(r*16)+':'));
col.onmousedown = unselectCell;
row.appendChild(col);
for(var c=0;c<16;c++){
col = document.createElement('td');
col.addr = r*16+c;
col.val = 0;
col.onmousedown = function(e){handleCellClick(e);};
col.appendChild(document.createTextNode('00'));
row.appendChild(col);
}
}
}
function handleCellClick(e){
var c = e.target;
selectCell(c.addr);
}
function cellKeydown(e){
var c = e.keyCode;
if(c==13) unselectCell();
else if(c==32) selectCell((selected+1)%0x200);
else if(c==8) selectCell((selected+0x1ff)%0x200);
else if((c>=48)&&(c<58)) setCellValue(selected, getCellValue(selected)*16+c-48);
else if((c>=65)&&(c<71)) setCellValue(selected, getCellValue(selected)*16+c-55);
mWrite(selected, getCellValue(selected));
}
function setCellValue(n, val){
val%=256;
cellEl(n).val=val;
cellEl(n).innerHTML=hexByte(val);
}
function getCellValue(n){return cellEl(n).val;}
function selectCell(n){
unselectCell();
if(n>=0x200) return;
cellEl(n).style.background = '#ff8';
selected = n;
window.onkeydown = function(e){cellKeydown(e);};
}
function unselectCell(){
if(selected==undefined) return;
cellEl(selected).style.background = '#fff';
selected = undefined;
window.onkeydown = undefined;
}
function cellEl(n){
var r = n>>4;
var c = n%16;
var e = table.children[r].children[c+1];
return e;
}

95
nodenames.js Normal file
View File

@ -0,0 +1,95 @@
var nodenames ={
db1: 82,
db0: 1005,
db3: 650,
db2: 945,
db5: 175,
db4: 1393,
db7: 1349,
db6: 1591,
a1: 1234,
ab1: 451,
ab2: 1340,
a2: 978,
s2: 81,
a5: 858,
a4: 727,
a7: 1653,
a6: 1136,
so: 1672,
sync: 539,
vcc: 657,
clk1out: 1163,
p2: 1421,
p3: 439,
p0: 687,
p1: 1444,
p6: 77,
p7: 1370,
p4: 1119,
p5: 0,
pcl3: 1359,
pcl2: 655,
pcl1: 1022,
pcl0: 1139,
pcl7: 1611,
pcl6: 377,
pcl5: 622,
pcl4: 900,
clk0: 1171,
s3: 1532,
res: 159,
s1: 183,
s0: 1403,
s7: 1435,
s6: 1212,
s5: 1098,
s4: 1702,
rw: 1156,
x2: 1,
x3: 1648,
x0: 1216,
x1: 98,
x6: 448,
x7: 777,
x4: 85,
x5: 589,
rdy: 89,
clk2out: 421,
nmi: 1297,
ab12: 1237,
ab13: 349,
ab10: 1443,
ab11: 399,
ab14: 672,
ab15: 195,
ab0: 268,
a0: 737,
a3: 162,
ab3: 211,
ab4: 435,
ab5: 736,
ab6: 887,
ab7: 1493,
ab8: 230,
ab9: 148,
pch7: 205,
pch6: 1551,
pch5: 49,
pch4: 948,
pch3: 584,
pch2: 502,
pch1: 292,
pch0: 1670,
irq: 103,
vss: 558,
y1: 1148,
y0: 64,
y3: 305,
y2: 573,
y5: 615,
y4: 989,
y7: 843,
y6: 115,
cclk: 943
}

18
save.php Normal file
View File

@ -0,0 +1,18 @@
<?php
$filename = $_REQUEST['name'];
file_put_contents($filename, file_get_contents("php://input"));
function file_put_contents($filename, $data) {
$f = @fopen($filename, 'w');
if ($f) {
$bytes = fwrite($f, $data);
fclose($f);
return $bytes;
}
return false;
}
?>

8235
segdefs.js Normal file

File diff suppressed because it is too large Load Diff

3512
transdefs.js Normal file

File diff suppressed because it is too large Load Diff

68
wires.css Normal file
View File

@ -0,0 +1,68 @@
body {
background: white;
color: black;
font-family: cursive;
font-size: 30px;
}
div.frame {
margin-left: 10px;
position: relative;
width: 1150px;
height: 600px;
}
div.chip {
background: lightgray;
border: 2px solid gray;
position: absolute;
width: 800px;
height: 600px;
overflow: hidden;
}
canvas.chip {
position: absolute;
width: 600px;
height: 600px;
}
div.buttons{
position: absolute;
top: -5px;
left: 820px;
}
p.status {
position: absolute;
left: 820px;
top: 20px;
font-family: monospace;
font-size: 12px;
}
img.navbutton{
margin-left: -5px;
border: 0px;
}
img.navplay{
margin-left: -5px;
border: 0px;
}
img.navstop{
position: absolute;
left: -5px;
top: 9px;
border: 0px;
}
table.memtable {
position: absolute;
top: 63px;
left: 820px;
font-family: monospace;
font-size: 12px;
border-spacing: 0px;
}

316
wires.js Normal file
View File

@ -0,0 +1,316 @@
var frame, chipbg, overlay, hilite, hitbuffer, ctx;
var centerx=300, centery=300;
var zoom=1;
var dragMouseX, dragMouseY, moved;
var statbox;
var colors = ['rgba(128,128,128,0.4)','#FFFF00','#FF00FF','#4DFF4D',
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
var nodes = new Array();
var transistors = {};
var ngnd = nodenames['vss'];
var npwr = nodenames['vcc'];
/////////////////////////
//
// Drawing Setup
//
/////////////////////////
function setup(){
frame = document.getElementById('frame');
statbox = document.getElementById('status');
setupNodes();
setupTransistors();
setupBackground();
setupOverlay();
setupHilite();
setupHitBuffer();
recenter();
refresh();
setupTable();
window.onkeypress = function(e){handleKey(e);}
hilite.onmousedown = function(e){mouseDown(e);}
initChip();
document.getElementById('stop').style.visibility = 'hidden';
go();
}
function setupNodes(){
for(var i in segdefs){
var seg = segdefs[i];
var w = seg[0];
if(nodes[w]==undefined)
nodes[w] = {segs: new Array(), num: w, pullup: seg[1]=='+',
state: 'fl', gates: new Array(), c1c2s: new Array()};
if(w==ngnd) continue;
if(w==npwr) continue;
nodes[w].segs.push(seg.slice(3));
}
}
function setupTransistors(){
for(i in transdefs){
var tdef = transdefs[i];
var name = tdef[0];
var gate = tdef[1];
var c1 = tdef[2];
var c2 = tdef[3];
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2};
nodes[gate].gates.push(name);
nodes[c1].c1c2s.push(name);
nodes[c2].c1c2s.push(name);
transistors[name] = trans;
}
}
function setupBackground(){
chipbg = document.getElementById('chipbg');
chipbg.width = 4000;
chipbg.height = 4000;
var ctx = chipbg.getContext('2d');
ctx.scale(chipbg.width/10000, chipbg.height/10000);
ctx.fillStyle = '#000000';
ctx.strokeStyle = 'rgba(255,255,255,0.5)';
ctx.lineWidth = 4;
ctx.fillRect(0,0,10000,10000);
var start = now();
for(var i in segdefs){
var seg = segdefs[i];
var c = seg[2];
ctx.fillStyle = colors[c];
drawSeg(ctx, segdefs[i].slice(3));
ctx.fill();
if((c==0)||(c==6)) ctx.stroke();
}
// console.log('time to draw: ', now() - start, ' ms');
}
function setupOverlay(){
overlay = document.getElementById('overlay');
overlay.width = 4000;
overlay.height = 4000;
ctx = overlay.getContext('2d');
ctx.scale(overlay.width/10000, overlay.height/10000);
}
function setupHilite(){
hilite = document.getElementById('hilite');
hilite.width = 4000;
hilite.height = 4000;
var ctx = hilite.getContext('2d');
ctx.scale(hilite.width/10000, hilite.height/10000);
}
function setupHitBuffer(){
hitbuffer = document.getElementById('hitbuffer');
hitbuffer.width = 4000;
hitbuffer.height = 4000;
hitbuffer.style.visibility = 'hidden';
var ctx = hitbuffer.getContext('2d');
ctx.scale(hitbuffer.width/10000, hitbuffer.height/10000);
for(i in nodes) hitBufferNode(ctx, i, nodes[i].segs);
}
function hitBufferNode(ctx, i, w){
var low = hexdigit(i&0xf);
var mid = hexdigit((i>>4)&0xf);
var high = hexdigit((i>>8)&0xf);
ctx.fillStyle = '#'+high+'F'+mid+'F'+low+'F';
for(i in w) {
drawSeg(ctx, w[i]);
ctx.fill();
}
}
function hexdigit(n){return '0123456789ABCDEF'.charAt(n);}
/////////////////////////
//
// Drawing Runtime
//
/////////////////////////
function refresh(){
ctx.clearRect(0,0,10000,10000);
for(i in nodes){
if(isNodeHigh(i)) overlayNode(nodes[i].segs);
}
}
function overlayNode(w){
ctx.fillStyle = 'rgba(255,0,64,0.4)';
for(i in w) {
drawSeg(ctx, w[i]);
ctx.fill();
}
}
function hiliteNode(n){
var ctx = hilite.getContext('2d');
ctx.clearRect(0,0,10000,10000);
ctx.fillStyle = 'rgba(255,255,255,0.7)';
if(n==-1) return;
if(isNodeHigh(n[0]))
ctx.fillStyle = 'rgba(255,0,0,0.7)';
for(var i in n){
var segs = nodes[n[i]].segs;
for(var s in segs){drawSeg(ctx, segs[s]); ctx.fill();}
}
}
function drawSeg(ctx, seg){
var dx = 400;
ctx.beginPath();
ctx.moveTo(seg[0]+dx, 10000-seg[1])
for(var i=2;i<seg.length;i+=2) ctx.lineTo(seg[i]+dx, 10000-seg[i+1]);
ctx.lineTo(seg[0]+dx, 10000-seg[1])
}
/////////////////////////
//
// User Interface
//
/////////////////////////
function handleKey(e){
var c = e.charCode;
c = String.fromCharCode(c);
if('<>?np'.indexOf(c)==-1) return;
if(c=='<' && zoom>1) setZoom(zoom/1.2);
else if(c=='>' && zoom<16) setZoom(zoom*1.2);
else if(c=='?') setZoom(1);
else if(c=='n') stepForward();
else if(c=='p') stepBack();
}
function mouseDown(e){
e.preventDefault();
moved=false;
dragMouseX = e.clientX;
dragMouseY = e.clientY;
window.onmousemove = function(e){mouseMove(e)};
window.onmouseup = function(e){mouseUp(e)};
}
function mouseMove(e){
moved = true;
if(zoom==1) return;
var dx = e.clientX-dragMouseX;
var dy = e.clientY-dragMouseY;
dragMouseX = e.clientX;
dragMouseY = e.clientY;
centerx-=dx/zoom;
centerx = Math.max(centerx, 400/zoom);
centerx = Math.min(centerx, 600-400/zoom);
centery-=dy/zoom;
centery = Math.max(centery, 300/zoom);
centery = Math.min(centery, 600-300/zoom);
recenter();
}
function mouseUp(e){
if(!moved) handleClick(e);
window.onmousemove = undefined;
window.onmouseup = undefined;
}
function setZoom(n){
zoom = n;
setChipStyle({
width: 600*n+'px',
height: 600*n+'px'
});
recenter();
}
function recenter(){
var top = -centery*zoom+300;
top = Math.min(top, 0);
top = Math.max(top, -600*(zoom-1));
var left = -centerx*zoom+400;
left = Math.min(left, 0);
left = Math.max(left, (zoom==1)?100:-600*zoom+800);
setChipStyle({
top: top+'px',
left: left+'px',
});
}
function handleClick(e){
var x = localx(hilite, e.clientX)/zoom;
var y = localy(hilite, e.clientY)/zoom;
var w = findNodeNumber(x,y);
if(e.shiftKey) hiliteNode(getNodeGroup(w));
else {var a=new Array(); a.push(w); hiliteNode(a);}
var cx = Math.round(x*10000/600);
var cy = Math.round(y*10000/600);
if(w==-1) setStatus('x:',cx,'<br>','y:',cy);
else {setStatus('x:',cx, 'y:', cy,'<br>','node:',w, nodeName(w));}
}
function findNodeNumber(x,y){
var ctx = hitbuffer.getContext('2d');
var pixels = ctx.getImageData(x*4000/600, y*4000/600, 2, 2).data;
if(pixels[0]==0) return -1;
var high = pixels[0]>>4;
var mid = pixels[1]>>4;
var low = pixels[2]>>4;
return (high<<8)+(mid<<4)+low;
}
/////////////////////////
//
// Etc.
//
/////////////////////////
function setChipStyle(props){
for(var i in props){
chipbg.style[i] = props[i];
overlay.style[i] = props[i];
hilite.style[i] = props[i];
hitbuffer.style[i] = props[i];
}
}
function localx(el, gx){
var lx = gx+window.pageXOffset;
while(el.offsetLeft!=undefined){
lx-=el.offsetLeft+el.clientLeft;
el = el.parentNode;
}
return lx;
}
function localy(el, gy){
var ly = gy+window.pageYOffset;
while(el.offsetTop!=undefined){
ly-=el.offsetTop+el.clientTop;
el = el.parentNode;
}
return ly;
}
function setStatus(){
var res = '';
for(var i=0;i<arguments.length;i++) res=res+arguments[i]+' ';
statbox.innerHTML = res;
}
function nodeName(n) {
for(var i in nodenames){
if(nodenames[i]==n) return i;
}
return '';
}
function now(){return new Date().getTime();}