25 Commits
V0.0 ... V0.2

Author SHA1 Message Date
9477ea64b4 allow IE9 (not tested on IE9, OK on firefox and chrome, IE8) 2010-09-20 13:09:15 +00:00
7ef9dc4c43 detect IE, add page of browser trouble, static image 2010-09-20 12:37:15 +00:00
efddb36049 remove page Offsets to fix probing in scrolled browser window 2010-09-19 18:27:48 +00:00
ef88fdeb90 Fixed console references for Firefox 2010-09-19 03:02:26 -04:00
470080015d Change title font and various wording changes from Greg 2010-09-18 19:59:41 -04:00
dccef54f2e top link should be absolute 2010-09-18 19:37:50 +00:00
18fbd2eb36 Merge branch 'ed' 2010-09-18 14:14:05 -04:00
bc901566e3 all layers start off visible 2010-09-18 18:06:42 +00:00
6276d019d7 Fixed localx/localy calculation 2010-09-18 14:04:52 -04:00
69ab63e406 fixup space above memtable 2010-09-18 17:56:34 +00:00
d032580201 improve load sequencing, add layer choosing, link to python sim, add keyboard tips, add example nmi test, tweak navbuttons, enhance chipstatus output 2010-09-18 17:46:24 +00:00
0ecb753ec6 fixup nav button positioning 2010-09-18 17:29:45 +00:00
e2e88cfae1 more internal busses and latches named 2010-09-18 17:25:33 +00:00
1fd86334f7 fixup line ends on one remaining file (by touching every line...) 2010-09-18 17:12:28 +00:00
bf2108b9d6 ignore patch detritus 2010-09-18 17:07:48 +00:00
2d2d0ef9b6 Merge branch 'master' of git://github.com/trebonian/visual6502
Conflicts:

	segdefs.js
2010-09-18 17:06:09 +00:00
3398a6f181 add copyright 2010-09-18 17:01:20 +00:00
b6d4ffda6a More copyrights 2010-09-18 13:00:23 -04:00
6dd7e9c24e Fixed line endings and Copyright notices 2010-09-18 12:56:48 -04:00
51b4d8d7a0 Introduce end-of-line normalization 2010-09-18 16:38:22 +00:00
e01093def5 ignore emacs backup files 2010-09-18 16:20:56 +00:00
27f085b743 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-09-18 16:17:54 +00:00
d3223a9478 Fixed README from Ed 2010-09-18 12:13:48 -04:00
f8931fce49 initial README content 2010-09-18 15:59:17 +00:00
b9cbe765b2 Fix slow reset loop 2010-09-18 11:42:30 -04:00
15 changed files with 13177 additions and 12821 deletions

4
.gitattributes vendored Normal file
View File

@ -0,0 +1,4 @@
* text=auto
*.js text
*.css text
*.html text

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# emacs-style backup files
*~
# patch detritus
*.orig
*.rej

10
README
View File

@ -0,0 +1,10 @@
This is the javascript simulator from the visual5602.org project:
www.visual6502.org/JSSim
It includes a general purpose transistor-level simulator, layout browser,
and the data from a 6502 revD chip.
Note the various licenses and Copyright associated with each file.
Enjoy!
- The Visual 6502 Team

33
browsertrouble.html Normal file
View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<head>
<title>Visual 6502 in JavaScript</title>
<style type="text/css">@import "wires.css";</style>
</head>
<body>
<span id="title"><a href="http://visual6502.org">The Visual 6502</a></span>
<span id="plain">
<br />
<span id="title">Browser Trouble?</span>
<br />
<a href="http://www.visual6502.org/faq.html">FAQ</a>&nbsp;
<a href="http://blog.visual6502.org">Blog</a>&nbsp;
<a href="http://www.visual6502.org/links.html">Links</a>&nbsp
<p>
Our chip simulator makes heavy use of the latest version of HTML5 drawing technology.
<p>
It will only run on recent browsers and on a computer with sufficient memory (we recommend at least 2Gbytes.)
<p>
We've tested it on Chrome, Firefox, Safari and Opera. Unfortunately Internet Explorer isn't yet capable of running the graphics.
<p>
If you're using one of the above browsers and having trouble, please restart the browser.
<p>
If you have a problem report or you're able to help us with compatilibity, please get in touch - our contact details are on the main page.
<p>
In the meantime, here's a picture of what you're missing:
<p>
<a href="http://visual6502.org"><img src="images/jssim2.png" style="border:10px"></a>
</span>
</body>
</html>

View File

@ -1,208 +1,210 @@
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
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;}
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var ctrace = false;
var noGraphics = false;
var loglevel = 3;
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();
}
if(ctrace) 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 && ctrace) 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/jssim2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

View File

@ -1,36 +1,84 @@
<!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>
<!DOCTYPE html>
<head>
<title>Visual 6502 in JavaScript</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>
<script type="text/javascript">
function handleOnload() {
if((navigator.appName == 'Microsoft Internet Explorer') && (parseInt(navigator.appVersion,10)<9)){
document.getElementById('browsertrouble').innerHTML=
'<p>Sorry, '+navigator.appName+' not supported - showing you a picture instead!</p>';
document.getElementById('frame').innerHTML='<a href="browsertrouble.html"><img src="images/jssim2.png" style="border:10px"></a>';
}else{
setTimeout(setup,200);
}
}
</script>
</head>
<body onload="handleOnload();">
<br />
<span id="title"><a href="http://visual6502.org">The Visual 6502</a></span>
<span id="plain">
<br />
<a href="http://www.visual6502.org/faq.html">FAQ</a>&nbsp;
<a href="http://blog.visual6502.org">Blog</a>&nbsp;
<a href="http://www.visual6502.org/links.html">Links</a>&nbsp
<br /><br />
This simulator uses HTML5 features only found on the latest versions of browsers and needs
lots of RAM. If you have trouble, please <a href="browsertrouble.html">check compatibility.</a>
<br />
<span id="browsertrouble"></span>
<br />
Hit '>' to zoom in, '<' to zoom out
<br />
Right-click to scroll around
<br />
Enter your own program into the array of RAM
<br />
<br />
</span>
<div class="frame" id="frame">
<div class="chip" id="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">
<div style="position:relative; float:left;">
<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>
</div>
<div style="float:left;">
<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>
</div>
<p class="status" id="status">x: 0<br>y: 0</p>
<table class="memtable" id="memtable"></table>
</div>
<div id="updateShow"> Show:
<input type="checkbox" name="0" id="updateShow0" onchange="updateShow(this.name,this.checked)" />(metal)
<input type="checkbox" name="1" id="updateShow1" onchange="updateShow(this.name,this.checked)" />(switched diffusion)
<input type="checkbox" name="3" id="updateShow3" onchange="updateShow(this.name,this.checked)" />(grounded diffusion)
<input type="checkbox" name="4" id="updateShow4" onchange="updateShow(this.name,this.checked)" />(powered diffusion)
<input type="checkbox" name="5" id="updateShow5" onchange="updateShow(this.name,this.checked)" />(polysilicon)
<input type="checkbox" name="2" id="updateShow2" onchange="updateShow(this.name,this.checked)" />(diode)
</div>
<br />
<br />
In addition to this JavaScript project, see our <a href="../python6502.html">Python-based simulator</a> which may be easier to customize, verify, and apply to the study of long programs.<br />
<br />
</body>
</html>

496
macros.js
View File

@ -1,201 +1,295 @@
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
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)}
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
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, 0); // schedule the next poll
}
}
function testNMI(n){
initChip();
mWrite(0x0000, 0x38); // set carry
mWrite(0x0001, 0x4c); // jump to test code
mWrite(0x0002, 0x06);
mWrite(0x0003, 0x23);
mWrite(0x22ff, 0x38); // set carry
mWrite(0x2300, 0xea);
mWrite(0x2301, 0xea);
mWrite(0x2302, 0xea);
mWrite(0x2303, 0xea);
mWrite(0x2304, 0xb0); // branch carry set to self
mWrite(0x2305, 0xfe);
mWrite(0x2306, 0xb0); // branch carry set to self
mWrite(0x2307, 0x01);
mWrite(0x2308, 0x00); // brk should be skipped
mWrite(0x2309, 0xa9); // anything
mWrite(0x230a, 0xde); // anything
mWrite(0x230b, 0xb0); // branch back with page crossing
mWrite(0x230c, 0xf2);
mWrite(0xc018, 0x40); // nmi handler
mWrite(0xfffa, 0x18); // nmi vector
mWrite(0xfffb, 0xc0);
mWrite(0xfffc, 0x00); // reset vector
mWrite(0xfffd, 0x00);
for(var i=0;i<n;i++){step();}
setLow('nmi');
chipStatus();
for(var i=0;i<8;i++){step();}
setHigh('nmi');
chipStatus();
for(var i=0;i<16;i++){step();}
}
function initChip(){
var start = now();
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<18;i++){resetStep();}
refresh();
cycle = 0;
trace = Array();
chipStatus();
if(ctrace)console.log('initChip done after', now()-start);
}
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 resetStep(){
var clk = isNodeHigh(nodenames['clk0']);
if (clk) {setLow('clk0'); handleBusRead(); }
else {setHigh('clk0'); handleBusWrite();}
}
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 readPstring(){
var result;
result = (isNodeHigh(nodenames['p7'])?'N':'n') +
(isNodeHigh(nodenames['p6'])?'V':'v') +
'-' +
(isNodeHigh(nodenames['p3'])?'B':'b') +
(isNodeHigh(nodenames['p3'])?'D':'d') +
(isNodeHigh(nodenames['p2'])?'I':'i') +
(isNodeHigh(nodenames['p1'])?'Z':'z') +
(isNodeHigh(nodenames['p0'])?'C':'c');
return result;
}
function readSP(){return readBits('s', 8);}
function readPC(){return (readBits('pch', 8)<<8) + readBits('pcl', 8);}
function readPCL(){return readBits('pcl', 8);}
function readPCH(){return readBits('pch', 8);}
function readBit(name){
return isNodeHigh(nodenames[name])?1:0;
}
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;
steps();
}
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();
setStatus('resetting 6502...');
setTimeout(initChip,0);
}
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 ab = readAddressBus();
var machine1 =
' halfcyc:' + cycle +
' phi0:' + readBit('clk0') +
' AB:' + hexWord(ab) +
' D:' + hexByte(readDataBus()) +
' RnW:' + readBit('rw');
var machine2 =
' PC:' + hexWord(readPC()) +
' A:' + hexByte(readA()) +
' X:' + hexByte(readX()) +
' Y:' + hexByte(readY()) +
' SP:' + hexByte(readSP()) +
' ' + readPstring();
var machine3 =
' Sync:' + readBit('sync')
' IRQ:' + readBit('irq') +
' NMI:' + readBit('nmi');
var machine4 =
' IR:' + hexByte(255 - readBits('notir', 8)) +
' idl:' + hexByte(255 - readBits('idl', 8)) +
' alu:' + hexByte(255 - readBits('alu', 8)) +
' TCstate:' + readBit('clock1') + readBit('clock2') +
readBit('t2') + readBit('t3') + readBit('t4') + readBit('t5');
var machine5 =
' notRdy0:' + readBit('notRdy0') +
' fetch:' + readBit('fetch') +
' clearIR:' + readBit('clearIR') +
' D1x1:' + readBit('D1x1');
setStatus(machine1 + "<br>" + machine2);
if (loglevel>2 && ctrace) {
console.log(machine1 + " " + machine2 + " " + machine3 + " " + machine4 + " " + machine5);
}
selectCell(ab);
}
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)}

View File

@ -1,89 +1,89 @@
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
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;
}
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
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;
}

View File

@ -1,117 +1,209 @@
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
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
}
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var nodenames ={
db1: 82,
db0: 1005,
db3: 650,
db2: 945,
db5: 175,
db4: 1393,
db7: 1349,
db6: 1591,
idl0: 116,
idl1: 576,
idl2: 1485,
idl3: 1284,
idl4: 1516,
idl5: 498,
idl6: 1537,
idl7: 529,
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,
nots0: 418,
nots1: 1064,
nots2: 752,
nots3: 828,
nots4: 1603,
nots5: 601,
nots6: 1029,
nots7: 181,
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, // aka cp2
clock1: 156,
clock2: 1536,
notir7: 1320,
notir6: 895, // OK
notir5: 1394, // OK
notir4: 26,
notir3: 1125,
notir2: 1182,
notir1: 702,
notir0: 194,
t2: 971,
t3: 1567,
t4: 690,
t5: 909,
cp1: 710,
fetch: 879,
clearIR: 1077,
D1x1: 827,
notRdy0: 248,
alu0: 394,
alu1: 697,
alu2: 276,
alu3: 495,
alu4: 1490,
alu5: 893,
alu6: 68,
alu7: 1123,
adl0: 413,
adl1: 1282,
adl2: 1242,
adl3: 684,
adl4: 1437,
adl5: 1630,
adl6: 121,
adl7: 1299,
adh0: 407,
adh1: 52,
adh2: 1651,
adh3: 315,
adh4: 1160,
adh5: 483,
adh6: 13,
adh7: 1539,
sb0: 54,
sb1: 1150,
sb2: 1287,
sb3: 1188,
sb4: 1405,
sb5: 166,
sb6: 1336,
sb7: 1001,
idb0: 1108,
idb1: 991,
idb2: 1473,
idb3: 1302,
idb4: 892,
idb5: 1503,
idb6: 833,
idb7: 493,
dor0: 222,
dor1: 527,
dor2: 1288,
dor3: 823,
dor4: 873,
dor5: 1266,
dor6: 1418,
dor7: 158,
pd0: 758,
pd1: 361,
pd2: 955,
pd3: 894,
pd4: 369,
pd5: 829,
pd6: 1669,
pd7: 1690,
h1x1: 1042, // drive status byte onto databus
}

View File

@ -1,18 +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;
}
?>
<?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;
}
?>

16481
segdefs.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

160
wires.css
View File

@ -1,68 +1,94 @@
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;
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
body {
background: white;
color: black;
/* font-family: cursive;*/
font-family :Verdana, Arial, Helvetica, Sans-Serif;
font-size: 12px;
}
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{
border: 0px;
}
img.navplay{
position: relative;
margin-right: 5px;
border: 0px;
}
img.navstop{
position: absolute;
border: 0px;
}
table.memtable {
position: absolute;
top: 78px;
left: 820px;
font-family: monospace;
font-size: 12px;
border-spacing: 0px;
}
#title {
font-size:30px;
font-weight:bold;
}

696
wires.js
View File

@ -1,338 +1,358 @@
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
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();}
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var frame, chipbg, overlay, hilite, hitbuffer, ctx;
var centerx=300, centery=300;
var zoom=1;
var dragMouseX, dragMouseY, moved;
var statbox;
// Index of layerNames corresponds to index into drawLayers
var layernames = ['metal', 'switched diffusion', 'inputdiode', 'grounded diffusion', 'powered diffusion', 'polysilicon'];
var colors = ['rgba(128,128,192,0.4)','#FFFF00','#FF00FF','#4DFF4D',
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
var drawlayers = [true, true, true, true, true, true];
var nodes = new Array();
var transistors = {};
var ngnd = nodenames['vss'];
var npwr = nodenames['vcc'];
/////////////////////////
//
// Drawing Setup
//
/////////////////////////
// try to present a meaningful page before starting expensive work
function setup(){
statbox = document.getElementById('status');
setStatus('loading 6502...');
setTimeout(setup_part2, 0);
}
function setup_part2(){
frame = document.getElementById('frame');
statbox = document.getElementById('status');
setupNodes();
setupTransistors();
setupLayerVisibility();
setupBackground();
setupOverlay();
setupHilite();
setupHitBuffer();
recenter();
refresh();
setupTable();
window.onkeypress = function(e){handleKey(e);}
hilite.onmousedown = function(e){mouseDown(e);}
setStatus('resetting 6502...');
setTimeout(setup_part3, 0);
}
function setup_part3(){
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 setupLayerVisibility(){
var x=document.getElementById('updateShow');
for (var i=0;i<x.childNodes.length;i++) {
if(x.childNodes[i].type='checkbox'){
x.childNodes[i].checked=drawlayers[x.childNodes[i].name];
}
}
}
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);
for(var i in segdefs){
var seg = segdefs[i];
var c = seg[2];
if (drawlayers[c]) {
ctx.fillStyle = colors[c];
drawSeg(ctx, segdefs[i].slice(3));
ctx.fill();
if((c==0)||(c==6)) ctx.stroke();
}
}
}
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){
if(noGraphics) return;
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;
}
function updateShow(layer, on){
drawlayers[layer]=on;
setupBackground();
}
/////////////////////////
//
// 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){
return gx-el.getBoundingClientRect().left;
}
function localy(el, gy){
return gy-el.getBoundingClientRect().top;
}
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();}