mirror of
https://github.com/trebonian/visual6502.git
synced 2025-07-19 08:24:21 +00:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
18fbd2eb36 | ||
|
bc901566e3 | ||
|
6276d019d7 | ||
|
69ab63e406 | ||
|
d032580201 | ||
|
0ecb753ec6 | ||
|
e2e88cfae1 | ||
|
1fd86334f7 | ||
|
bf2108b9d6 | ||
|
2d2d0ef9b6 | ||
|
3398a6f181 | ||
|
b6d4ffda6a | ||
|
6dd7e9c24e | ||
|
51b4d8d7a0 | ||
|
e01093def5 | ||
|
27f085b743 | ||
|
d3223a9478 | ||
|
f8931fce49 | ||
|
b9cbe765b2 |
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
* text=auto
|
||||||
|
*.js text
|
||||||
|
*.css text
|
||||||
|
*.html text
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# emacs-style backup files
|
||||||
|
*~
|
||||||
|
# patch detritus
|
||||||
|
*.orig
|
||||||
|
*.rej
|
8
README
8
README
@@ -0,0 +1,8 @@
|
|||||||
|
This is the javascript simulator from the visual5602.org project.
|
||||||
|
|
||||||
|
It includes a general purpose switch-level simulator, layout browser,
|
||||||
|
and data from a 6502D chip.
|
||||||
|
|
||||||
|
Please note the various licenses of the different files.
|
||||||
|
|
||||||
|
Enjoy!
|
||||||
|
418
chipsim.js
418
chipsim.js
@@ -1,208 +1,210 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in
|
||||||
all copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var ctrace = false;
|
var ctrace = false;
|
||||||
var ridx = 0;
|
var noGraphics = false;
|
||||||
|
var loglevel = 3;
|
||||||
function recalcNodeList(list){
|
var ridx = 0;
|
||||||
var n = list[0];
|
|
||||||
var recalclist = new Array();
|
function recalcNodeList(list){
|
||||||
for(var j=0;j<100;j++){ // loop limiter
|
var n = list[0];
|
||||||
if(list.length==0) return;
|
var recalclist = new Array();
|
||||||
if(ctrace) console.log(j, list);
|
for(var j=0;j<100;j++){ // loop limiter
|
||||||
for(var i in list) recalcNode(list[i], recalclist);
|
if(list.length==0) return;
|
||||||
list = recalclist;
|
if(ctrace) console.log(j, list);
|
||||||
recalclist = new Array();
|
for(var i in list) recalcNode(list[i], recalclist);
|
||||||
}
|
list = recalclist;
|
||||||
console.log(n,'looping...');
|
recalclist = new Array();
|
||||||
}
|
}
|
||||||
|
console.log(n,'looping...');
|
||||||
function recalcNode(node, recalclist){
|
}
|
||||||
if(node==ngnd) return;
|
|
||||||
if(node==npwr) return;
|
function recalcNode(node, recalclist){
|
||||||
var group = getNodeGroup(node);
|
if(node==ngnd) return;
|
||||||
var newv = getNodeValue(group);
|
if(node==npwr) return;
|
||||||
if(ctrace) console.log('recalc', node, group);
|
var group = getNodeGroup(node);
|
||||||
for(var i in group){
|
var newv = getNodeValue(group);
|
||||||
var n = nodes[group[i]];
|
if(ctrace) console.log('recalc', node, group);
|
||||||
if(n.state!=newv && ctrace) console.log(group[i], n.state, newv);
|
for(var i in group){
|
||||||
n.state = newv;
|
var n = nodes[group[i]];
|
||||||
for(var t in n.gates) recalcTransistor(n.gates[t], recalclist);
|
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);
|
function recalcTransistor(tn, recalclist){
|
||||||
else turnTransistorOff(t, 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);
|
function turnTransistorOn(t, recalclist){
|
||||||
t.on = true;
|
if(t.on) return;
|
||||||
addRecalcNode(t.c1, recalclist);
|
if(ctrace) console.log(t.name, 'on', t.gate, t.c1, t.c2);
|
||||||
addRecalcNode(t.c2, recalclist);
|
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);
|
function turnTransistorOff(t, recalclist){
|
||||||
t.on = false;
|
if(!t.on) return;
|
||||||
floatnode(t.c1);
|
if(ctrace) console.log(t.name, 'off', t.gate, t.c1, t.c2);
|
||||||
floatnode(t.c2);
|
t.on = false;
|
||||||
addRecalcNode(t.c1, recalclist);
|
floatnode(t.c1);
|
||||||
addRecalcNode(t.c2, recalclist);
|
floatnode(t.c2);
|
||||||
}
|
addRecalcNode(t.c1, recalclist);
|
||||||
|
addRecalcNode(t.c2, recalclist);
|
||||||
function floatnode(nn){
|
}
|
||||||
if(nn==ngnd) return;
|
|
||||||
if(nn==npwr) return;
|
function floatnode(nn){
|
||||||
var n = nodes[nn];
|
if(nn==ngnd) return;
|
||||||
if(n.state=='gnd') n.state = 'fl';
|
if(nn==npwr) return;
|
||||||
if(n.state=='pd') n.state = 'fl';
|
var n = nodes[nn];
|
||||||
if(n.state=='vcc') n.state = 'fh';
|
if(n.state=='gnd') n.state = 'fl';
|
||||||
if(n.state=='pu') n.state = 'fh';
|
if(n.state=='pd') n.state = 'fl';
|
||||||
if(ctrace) console.log('floating', nn, 'to', n.state);
|
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;
|
function addRecalcNode(nn, recalclist){
|
||||||
if(arrayContains(recalclist, nn)) return;
|
if(nn==ngnd) return;
|
||||||
recalclist.push(nn);
|
if(nn==npwr) return;
|
||||||
// setAdd(recalclist, nn);
|
if(arrayContains(recalclist, nn)) return;
|
||||||
}
|
recalclist.push(nn);
|
||||||
|
// setAdd(recalclist, nn);
|
||||||
function getNodeGroup(i){
|
}
|
||||||
var group = new Array();
|
|
||||||
addNodeToGroup(i, group);
|
function getNodeGroup(i){
|
||||||
return group;
|
var group = new Array();
|
||||||
}
|
addNodeToGroup(i, group);
|
||||||
|
return group;
|
||||||
function addNodeToGroup(i, group){
|
}
|
||||||
if(arrayContains(group, i)) return;
|
|
||||||
group.push(i);
|
function addNodeToGroup(i, group){
|
||||||
if(i==ngnd) return;
|
if(arrayContains(group, i)) return;
|
||||||
if(i==npwr) return;
|
group.push(i);
|
||||||
for(var t in nodes[i].c1c2s) addNodeTransistor(i, nodes[i].c1c2s[t], group);
|
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;
|
function addNodeTransistor(node, t, group){
|
||||||
var other;
|
var tr = transistors[t];
|
||||||
if(tr.c1==node) other=tr.c2;
|
if(!tr.on) return;
|
||||||
if(tr.c2==node) other=tr.c1;
|
var other;
|
||||||
addNodeToGroup(other, group);
|
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';
|
function getNodeValue(group){
|
||||||
var flstate;
|
if(arrayContains(group, ngnd)) return 'gnd';
|
||||||
for(var i in group){
|
if(arrayContains(group, npwr)) return 'vcc';
|
||||||
var nn = group[i];
|
var flstate;
|
||||||
var n = nodes[nn];
|
for(var i in group){
|
||||||
if(n.pullup) return 'pu';
|
var nn = group[i];
|
||||||
if(n.pulldown) return 'pd';
|
var n = nodes[nn];
|
||||||
if((n.state=='fl')&&(flstate==undefined)) flstate = 'fl';
|
if(n.pullup) return 'pu';
|
||||||
if(n.state=='fh') flstate = 'fh';
|
if(n.pulldown) return 'pd';
|
||||||
}
|
if((n.state=='fl')&&(flstate==undefined)) flstate = 'fl';
|
||||||
if(flstate==undefined) console.log(group);
|
if(n.state=='fh') flstate = 'fh';
|
||||||
return flstate;
|
}
|
||||||
}
|
if(flstate==undefined) console.log(group);
|
||||||
|
return flstate;
|
||||||
|
}
|
||||||
function isNodeHigh(nn){
|
|
||||||
return arrayContains(['vcc','pu','fh'], nodes[nn].state);
|
|
||||||
}
|
function isNodeHigh(nn){
|
||||||
|
return arrayContains(['vcc','pu','fh'], nodes[nn].state);
|
||||||
function saveString(name, str){
|
}
|
||||||
var request = new XMLHttpRequest();
|
|
||||||
request.onreadystatechange=function(){};
|
function saveString(name, str){
|
||||||
request.open('PUT', 'save.php?name='+name, true);
|
var request = new XMLHttpRequest();
|
||||||
request.setRequestHeader('Content-Type', 'text/plain');
|
request.onreadystatechange=function(){};
|
||||||
request.send(str);
|
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);
|
function allNodes(){
|
||||||
return res;
|
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 = '';
|
function stateString(){
|
||||||
for(var i=0;i<1725;i++){
|
var codes = {gnd: 'g', vcc: 'v', pu: 'p', pd: 'd', fh: 'f', fl: 'l'};
|
||||||
var n = nodes[i];
|
var res = '';
|
||||||
if(n==undefined) res+='x';
|
for(var i=0;i<1725;i++){
|
||||||
else if(i==ngnd) res+='g';
|
var n = nodes[i];
|
||||||
else if(i==npwr) res+='v';
|
if(n==undefined) res+='x';
|
||||||
else res+= codes[n.state];
|
else if(i==ngnd) res+='g';
|
||||||
}
|
else if(i==npwr) res+='v';
|
||||||
return res;
|
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++){
|
function showState(str){
|
||||||
if(str[i]=='x') continue;
|
var codes = {g: 'gnd', v: 'vcc', p: 'pu', d: 'pd', f: 'fh', l: 'fl'};
|
||||||
nodes[i].state = codes[str[i]];
|
for(var i=0;i<str.length;i++){
|
||||||
var gates = nodes[i].gates;
|
if(str[i]=='x') continue;
|
||||||
for(var t in gates) transistors[gates[t]].on = isNodeHigh(i);
|
nodes[i].state = codes[str[i]];
|
||||||
}
|
var gates = nodes[i].gates;
|
||||||
refresh();
|
for(var t in gates) transistors[gates[t]].on = isNodeHigh(i);
|
||||||
}
|
}
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
function setPd(name){
|
|
||||||
var nn = nodenames[name];
|
|
||||||
nodes[nn].pullup = false;
|
function setPd(name){
|
||||||
nodes[nn].pulldown = true;
|
var nn = nodenames[name];
|
||||||
}
|
nodes[nn].pullup = false;
|
||||||
|
nodes[nn].pulldown = true;
|
||||||
function setHigh(name){
|
}
|
||||||
var nn = nodenames[name];
|
|
||||||
nodes[nn].pullup = true;
|
function setHigh(name){
|
||||||
nodes[nn].pulldown = false;
|
var nn = nodenames[name];
|
||||||
recalcNodeList([nn]);
|
nodes[nn].pullup = true;
|
||||||
}
|
nodes[nn].pulldown = false;
|
||||||
|
recalcNodeList([nn]);
|
||||||
function setLow(name){
|
}
|
||||||
var nn = nodenames[name];
|
|
||||||
nodes[nn].pullup = false;
|
function setLow(name){
|
||||||
nodes[nn].pulldown = true;
|
var nn = nodenames[name];
|
||||||
recalcNodeList([nn]);
|
nodes[nn].pullup = false;
|
||||||
}
|
nodes[nn].pulldown = true;
|
||||||
|
recalcNodeList([nn]);
|
||||||
function setAdd(arr, el){
|
}
|
||||||
var idx = ridx%(arr.length+1);
|
|
||||||
ridx+=131;
|
function setAdd(arr, el){
|
||||||
ridx%=123;
|
var idx = ridx%(arr.length+1);
|
||||||
arr.splice(idx, 0, el);
|
ridx+=131;
|
||||||
return arr;
|
ridx%=123;
|
||||||
}
|
arr.splice(idx, 0, el);
|
||||||
|
return arr;
|
||||||
function arrayContains(arr, el){return arr.indexOf(el)!=-1;}
|
}
|
||||||
|
|
||||||
|
function arrayContains(arr, el){return arr.indexOf(el)!=-1;}
|
||||||
|
100
index.html
100
index.html
@@ -1,36 +1,64 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>6502</title>
|
<title>6502</title>
|
||||||
<style type="text/css">@import "wires.css";</style>
|
<style type="text/css">@import "wires.css";</style>
|
||||||
<script src="segdefs.js"></script>
|
<script src="segdefs.js"></script>
|
||||||
<script src="transdefs.js"></script>
|
<script src="transdefs.js"></script>
|
||||||
<script src="nodenames.js"></script>
|
<script src="nodenames.js"></script>
|
||||||
<script src="wires.js"></script>
|
<script src="wires.js"></script>
|
||||||
<script src="chipsim.js"></script>
|
<script src="chipsim.js"></script>
|
||||||
<script src="memtable.js"></script>
|
<script src="memtable.js"></script>
|
||||||
<script src="macros.js"></script>
|
<script src="macros.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onload="setup();">
|
<body onload="setTimeout(setup,200)">
|
||||||
<p class="title">The 6502</p>
|
<br />
|
||||||
<div class="frame" id="frame">
|
<span id="title"><a href="/">The Visual 6502</a></span><br /><br />
|
||||||
<div class="chip">
|
<span id="plain">
|
||||||
<canvas class="chip" id="chipbg"></canvas>
|
If the chip does not load, try another browser: Chrome, Safari, or Firefox
|
||||||
<canvas class="chip" id="overlay"></canvas>
|
<br />
|
||||||
<canvas class="chip" id="hilite"></canvas>
|
<br />
|
||||||
<canvas class="chip" id="hitbuffer"></canvas>
|
Hit '>' to zoom in, '<' to zoom out
|
||||||
</div>
|
<br />
|
||||||
<div class = "buttons">
|
Right-click to scroll around
|
||||||
<a href ="javascript:stopChip()"id="stop"><img class="navstop" src="images/stop.png"></a>
|
<br />
|
||||||
<a href ="javascript:runChip()" id="start"><img class="navplay" src="images/play.png"></a>
|
Enter your own program into the array of RAM
|
||||||
<a href ="javascript:resetChip()"><img class="navbutton" src="images/up.png"></a>
|
<br />
|
||||||
<a href ="javascript:stepBack()"><img class="navbutton" src="images/prev.png"></a>
|
<br />
|
||||||
<a href ="javascript:stepForward()"><img class="navbutton" src="images/next.png"></a>
|
</span>
|
||||||
</div>
|
<div class="frame" id="frame">
|
||||||
<p class="status" id="status">x: 0<br>y: 0</p>
|
<div class="chip">
|
||||||
<table class="memtable" id="memtable"></table>
|
<canvas class="chip" id="chipbg"></canvas>
|
||||||
</div>
|
<canvas class="chip" id="overlay"></canvas>
|
||||||
</body>
|
<canvas class="chip" id="hilite"></canvas>
|
||||||
|
<canvas class="chip" id="hitbuffer"></canvas>
|
||||||
</html>
|
</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)" />(diff)
|
||||||
|
<input type="checkbox" name="2" id="updateShow2" onchange="updateShow(this.name,this.checked)" />(diode)
|
||||||
|
<input type="checkbox" name="3" id="updateShow3" onchange="updateShow(this.name,this.checked)" />(diff0)
|
||||||
|
<input type="checkbox" name="4" id="updateShow4" onchange="updateShow(this.name,this.checked)" />(diff1)
|
||||||
|
<input type="checkbox" name="5" id="updateShow5" onchange="updateShow(this.name,this.checked)" />(poly)
|
||||||
|
</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
496
macros.js
@@ -1,201 +1,295 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in
|
||||||
all copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var memory = Array();
|
var memory = Array();
|
||||||
var code = [0xa9, 0x00, 0x20, 0x10, 0x00, 0x4c, 0x02, 0x00,
|
var code = [0xa9, 0x00, 0x20, 0x10, 0x00, 0x4c, 0x02, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0xe8, 0x88, 0xe6, 0x40, 0x38, 0x69, 0x02, 0x60];
|
0xe8, 0x88, 0xe6, 0x40, 0x38, 0x69, 0x02, 0x60];
|
||||||
var cycle = 0;
|
var cycle = 0;
|
||||||
var trace = Array();
|
var trace = Array();
|
||||||
var running = false;
|
var running = false;
|
||||||
|
|
||||||
function go(n){
|
function go(n){
|
||||||
for(var i=0;i<code.length;i++){
|
for(var i=0;i<code.length;i++){
|
||||||
mWrite(i, code[i]);
|
mWrite(i, code[i]);
|
||||||
setCellValue(i, code[i]);
|
setCellValue(i, code[i]);
|
||||||
}
|
}
|
||||||
mWrite(0xfffc, 0x00);
|
mWrite(0xfffc, 0x00);
|
||||||
mWrite(0xfffd, 0x00);
|
mWrite(0xfffd, 0x00);
|
||||||
steps();
|
steps();
|
||||||
}
|
}
|
||||||
|
|
||||||
function steps(){
|
function steps(){
|
||||||
if(running) step();
|
if(running) {
|
||||||
setTimeout(steps, 200);
|
step();
|
||||||
}
|
setTimeout(steps, 0); // schedule the next poll
|
||||||
|
}
|
||||||
function initChip(){
|
}
|
||||||
for(var nn in nodes) nodes[nn].state = 'fl';
|
|
||||||
nodes[ngnd].state = 'gnd';
|
function testNMI(n){
|
||||||
nodes[npwr].state = 'vcc';
|
initChip();
|
||||||
for(var tn in transistors) transistors[tn].on = false;
|
|
||||||
setLow('res');
|
mWrite(0x0000, 0x38); // set carry
|
||||||
setLow('clk0');
|
mWrite(0x0001, 0x4c); // jump to test code
|
||||||
setHigh('rdy'); setLow('so');
|
mWrite(0x0002, 0x06);
|
||||||
setHigh('irq'); setHigh('nmi');
|
mWrite(0x0003, 0x23);
|
||||||
recalcNodeList(allNodes());
|
|
||||||
for(var i=0;i<8;i++){setHigh('clk0'), setLow('clk0');}
|
mWrite(0x22ff, 0x38); // set carry
|
||||||
setHigh('res');
|
mWrite(0x2300, 0xea);
|
||||||
for(var i=0;i<14;i++){step();}
|
mWrite(0x2301, 0xea);
|
||||||
refresh();
|
mWrite(0x2302, 0xea);
|
||||||
cycle = 0;
|
mWrite(0x2303, 0xea);
|
||||||
trace = Array();
|
mWrite(0x2304, 0xb0); // branch carry set to self
|
||||||
chipStatus();
|
mWrite(0x2305, 0xfe);
|
||||||
}
|
|
||||||
|
mWrite(0x2306, 0xb0); // branch carry set to self
|
||||||
function step(){
|
mWrite(0x2307, 0x01);
|
||||||
trace[cycle]= {chip: stateString(), mem: getMem()};
|
mWrite(0x2308, 0x00); // brk should be skipped
|
||||||
halfStep();
|
mWrite(0x2309, 0xa9); // anything
|
||||||
cycle++;
|
mWrite(0x230a, 0xde); // anything
|
||||||
chipStatus();
|
mWrite(0x230b, 0xb0); // branch back with page crossing
|
||||||
}
|
mWrite(0x230c, 0xf2);
|
||||||
|
|
||||||
function halfStep(){
|
mWrite(0xc018, 0x40); // nmi handler
|
||||||
var clk = isNodeHigh(nodenames['clk0']);
|
|
||||||
if (clk) {setLow('clk0'); handleBusRead(); }
|
mWrite(0xfffa, 0x18); // nmi vector
|
||||||
else {setHigh('clk0'); handleBusWrite();}
|
mWrite(0xfffb, 0xc0);
|
||||||
refresh();
|
mWrite(0xfffc, 0x00); // reset vector
|
||||||
}
|
mWrite(0xfffd, 0x00);
|
||||||
|
|
||||||
function handleBusRead(){
|
for(var i=0;i<n;i++){step();}
|
||||||
if(isNodeHigh(nodenames['rw'])) writeDataBus(mRead(readAddressBus()));
|
setLow('nmi');
|
||||||
}
|
chipStatus();
|
||||||
|
for(var i=0;i<8;i++){step();}
|
||||||
function handleBusWrite(){
|
setHigh('nmi');
|
||||||
if(!isNodeHigh(nodenames['rw'])){
|
chipStatus();
|
||||||
var a = readAddressBus();
|
for(var i=0;i<16;i++){step();}
|
||||||
var d = readDataBus();
|
}
|
||||||
mWrite(a,d);
|
|
||||||
if(a<0x200) setCellValue(a,d);
|
|
||||||
}
|
function initChip(){
|
||||||
}
|
var start = now();
|
||||||
|
for(var nn in nodes) nodes[nn].state = 'fl';
|
||||||
function readAddressBus(){return readBits('ab', 16);}
|
nodes[ngnd].state = 'gnd';
|
||||||
function readDataBus(){return readBits('db', 8);}
|
nodes[npwr].state = 'vcc';
|
||||||
function readA(){return readBits('a', 8);}
|
for(var tn in transistors) transistors[tn].on = false;
|
||||||
function readY(){return readBits('y', 8);}
|
setLow('res');
|
||||||
function readX(){return readBits('x', 8);}
|
setLow('clk0');
|
||||||
function readP(){return readBits('p', 8);}
|
setHigh('rdy'); setLow('so');
|
||||||
function readSP(){return readBits('s', 8);}
|
setHigh('irq'); setHigh('nmi');
|
||||||
|
recalcNodeList(allNodes());
|
||||||
function readBits(name, n){
|
for(var i=0;i<8;i++){setHigh('clk0'), setLow('clk0');}
|
||||||
var res = 0;
|
setHigh('res');
|
||||||
for(var i=0;i<n;i++){
|
for(var i=0;i<18;i++){resetStep();}
|
||||||
var nn = nodenames[name+i];
|
refresh();
|
||||||
res+=((isNodeHigh(nn))?1:0)<<i;
|
cycle = 0;
|
||||||
}
|
trace = Array();
|
||||||
return res;
|
chipStatus();
|
||||||
}
|
console.log('initChip done after', now()-start);
|
||||||
|
}
|
||||||
function writeDataBus(x){
|
|
||||||
var recalcs = Array();
|
function step(){
|
||||||
for(var i=0;i<8;i++){
|
trace[cycle]= {chip: stateString(), mem: getMem()};
|
||||||
var nn = nodenames['db'+i];
|
halfStep();
|
||||||
var n = nodes[nn];
|
cycle++;
|
||||||
if((x%2)==0) {n.pulldown=true; n.pullup=false;}
|
chipStatus();
|
||||||
else {n.pulldown=false; n.pullup=true;}
|
}
|
||||||
recalcs.push(nn);
|
|
||||||
x>>=1;
|
function halfStep(){
|
||||||
}
|
var clk = isNodeHigh(nodenames['clk0']);
|
||||||
recalcNodeList(recalcs);
|
if (clk) {setLow('clk0'); handleBusRead(); }
|
||||||
}
|
else {setHigh('clk0'); handleBusWrite();}
|
||||||
|
refresh();
|
||||||
function mRead(a){
|
}
|
||||||
if(memory[a]==undefined) return 0;
|
|
||||||
else return memory[a];
|
function resetStep(){
|
||||||
}
|
var clk = isNodeHigh(nodenames['clk0']);
|
||||||
|
if (clk) {setLow('clk0'); handleBusRead(); }
|
||||||
function mWrite(a, d){memory[a]=d;}
|
else {setHigh('clk0'); handleBusWrite();}
|
||||||
|
}
|
||||||
|
|
||||||
function clkNodes(){
|
function handleBusRead(){
|
||||||
var res = Array();
|
if(isNodeHigh(nodenames['rw'])) writeDataBus(mRead(readAddressBus()));
|
||||||
res.push(943);
|
}
|
||||||
for(var i in nodes[943].gates){
|
|
||||||
var t = transistors[nodes[943].gates[i]];
|
function handleBusWrite(){
|
||||||
if(t.c1==npwr) res.push(t.c2);
|
if(!isNodeHigh(nodenames['rw'])){
|
||||||
if(t.c2==npwr) res.push(t.c1);
|
var a = readAddressBus();
|
||||||
}
|
var d = readDataBus();
|
||||||
hiliteNode(res);
|
mWrite(a,d);
|
||||||
}
|
if(a<0x200) setCellValue(a,d);
|
||||||
|
}
|
||||||
function runChip(){
|
}
|
||||||
var start = document.getElementById('start');
|
|
||||||
var stop = document.getElementById('stop');
|
function readAddressBus(){return readBits('ab', 16);}
|
||||||
start.style.visibility = 'hidden';
|
function readDataBus(){return readBits('db', 8);}
|
||||||
stop.style.visibility = 'visible';
|
function readA(){return readBits('a', 8);}
|
||||||
running = true;
|
function readY(){return readBits('y', 8);}
|
||||||
}
|
function readX(){return readBits('x', 8);}
|
||||||
|
function readP(){return readBits('p', 8);}
|
||||||
function stopChip(){
|
function readPstring(){
|
||||||
var start = document.getElementById('start');
|
var result;
|
||||||
var stop = document.getElementById('stop');
|
result = (isNodeHigh(nodenames['p7'])?'N':'n') +
|
||||||
start.style.visibility = 'visible';
|
(isNodeHigh(nodenames['p6'])?'V':'v') +
|
||||||
stop.style.visibility = 'hidden';
|
'-' +
|
||||||
running = false;
|
(isNodeHigh(nodenames['p3'])?'B':'b') +
|
||||||
}
|
(isNodeHigh(nodenames['p3'])?'D':'d') +
|
||||||
|
(isNodeHigh(nodenames['p2'])?'I':'i') +
|
||||||
function resetChip(){
|
(isNodeHigh(nodenames['p1'])?'Z':'z') +
|
||||||
stopChip();
|
(isNodeHigh(nodenames['p0'])?'C':'c');
|
||||||
initChip();
|
return result;
|
||||||
}
|
}
|
||||||
|
function readSP(){return readBits('s', 8);}
|
||||||
function stepForward(){
|
function readPC(){return (readBits('pch', 8)<<8) + readBits('pcl', 8);}
|
||||||
stopChip();
|
function readPCL(){return readBits('pcl', 8);}
|
||||||
step();
|
function readPCH(){return readBits('pch', 8);}
|
||||||
}
|
|
||||||
|
function readBit(name){
|
||||||
function stepBack(){
|
return isNodeHigh(nodenames[name])?1:0;
|
||||||
if(cycle==0) return;
|
}
|
||||||
showState(trace[--cycle].chip);
|
function readBits(name, n){
|
||||||
setMem(trace[cycle].mem);
|
var res = 0;
|
||||||
var clk = isNodeHigh(nodenames['clk0']);
|
for(var i=0;i<n;i++){
|
||||||
if(!clk) writeDataBus(mRead(readAddressBus()));
|
var nn = nodenames[name+i];
|
||||||
chipStatus();
|
res+=((isNodeHigh(nn))?1:0)<<i;
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
function chipStatus(){
|
}
|
||||||
var pc = readAddressBus();
|
|
||||||
setStatus('PC:', hexWord(pc),
|
function writeDataBus(x){
|
||||||
'D:', hexByte(readDataBus()),
|
var recalcs = Array();
|
||||||
'SP:',hexByte(readSP()),
|
for(var i=0;i<8;i++){
|
||||||
'cycle:', cycle, '<br>',
|
var nn = nodenames['db'+i];
|
||||||
'A:', hexByte(readA()),
|
var n = nodes[nn];
|
||||||
'X:', hexByte(readX()),
|
if((x%2)==0) {n.pulldown=true; n.pullup=false;}
|
||||||
'Y:', hexByte(readY()),
|
else {n.pulldown=false; n.pullup=true;}
|
||||||
'P:', hexByte(readP())
|
recalcs.push(nn);
|
||||||
);
|
x>>=1;
|
||||||
selectCell(pc);
|
}
|
||||||
}
|
recalcNodeList(recalcs);
|
||||||
|
}
|
||||||
function getMem(){
|
|
||||||
var res = Array();
|
function mRead(a){
|
||||||
for(var i=0;i<0x200;i++) res.push(mRead(i));
|
if(memory[a]==undefined) return 0;
|
||||||
return res;
|
else return memory[a];
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMem(arr){
|
function mWrite(a, d){memory[a]=d;}
|
||||||
for(var i=0;i<0x200;i++){mWrite(i, arr[i]); setCellValue(i, arr[i]);}
|
|
||||||
}
|
|
||||||
|
function clkNodes(){
|
||||||
function hexWord(n){return (0x10000+n).toString(16).substring(1)}
|
var res = Array();
|
||||||
function hexByte(n){return (0x100+n).toString(16).substring(1)}
|
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) {
|
||||||
|
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)}
|
||||||
|
178
memtable.js
178
memtable.js
@@ -1,89 +1,89 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in
|
||||||
all copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var table;
|
var table;
|
||||||
var selected;
|
var selected;
|
||||||
|
|
||||||
function setupTable(){
|
function setupTable(){
|
||||||
table = document.getElementById('memtable');
|
table = document.getElementById('memtable');
|
||||||
for(var r=0;r<32;r++){
|
for(var r=0;r<32;r++){
|
||||||
var row = document.createElement('tr');
|
var row = document.createElement('tr');
|
||||||
table.appendChild(row);
|
table.appendChild(row);
|
||||||
var col = document.createElement('td');
|
var col = document.createElement('td');
|
||||||
col.appendChild(document.createTextNode(hexWord(r*16)+':'));
|
col.appendChild(document.createTextNode(hexWord(r*16)+':'));
|
||||||
col.onmousedown = unselectCell;
|
col.onmousedown = unselectCell;
|
||||||
row.appendChild(col);
|
row.appendChild(col);
|
||||||
for(var c=0;c<16;c++){
|
for(var c=0;c<16;c++){
|
||||||
col = document.createElement('td');
|
col = document.createElement('td');
|
||||||
col.addr = r*16+c;
|
col.addr = r*16+c;
|
||||||
col.val = 0;
|
col.val = 0;
|
||||||
col.onmousedown = function(e){handleCellClick(e);};
|
col.onmousedown = function(e){handleCellClick(e);};
|
||||||
col.appendChild(document.createTextNode('00'));
|
col.appendChild(document.createTextNode('00'));
|
||||||
row.appendChild(col);
|
row.appendChild(col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCellClick(e){
|
function handleCellClick(e){
|
||||||
var c = e.target;
|
var c = e.target;
|
||||||
selectCell(c.addr);
|
selectCell(c.addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cellKeydown(e){
|
function cellKeydown(e){
|
||||||
var c = e.keyCode;
|
var c = e.keyCode;
|
||||||
if(c==13) unselectCell();
|
if(c==13) unselectCell();
|
||||||
else if(c==32) selectCell((selected+1)%0x200);
|
else if(c==32) selectCell((selected+1)%0x200);
|
||||||
else if(c==8) selectCell((selected+0x1ff)%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>=48)&&(c<58)) setCellValue(selected, getCellValue(selected)*16+c-48);
|
||||||
else if((c>=65)&&(c<71)) setCellValue(selected, getCellValue(selected)*16+c-55);
|
else if((c>=65)&&(c<71)) setCellValue(selected, getCellValue(selected)*16+c-55);
|
||||||
mWrite(selected, getCellValue(selected));
|
mWrite(selected, getCellValue(selected));
|
||||||
}
|
}
|
||||||
|
|
||||||
function setCellValue(n, val){
|
function setCellValue(n, val){
|
||||||
val%=256;
|
val%=256;
|
||||||
cellEl(n).val=val;
|
cellEl(n).val=val;
|
||||||
cellEl(n).innerHTML=hexByte(val);
|
cellEl(n).innerHTML=hexByte(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCellValue(n){return cellEl(n).val;}
|
function getCellValue(n){return cellEl(n).val;}
|
||||||
|
|
||||||
function selectCell(n){
|
function selectCell(n){
|
||||||
unselectCell();
|
unselectCell();
|
||||||
if(n>=0x200) return;
|
if(n>=0x200) return;
|
||||||
cellEl(n).style.background = '#ff8';
|
cellEl(n).style.background = '#ff8';
|
||||||
selected = n;
|
selected = n;
|
||||||
window.onkeydown = function(e){cellKeydown(e);};
|
window.onkeydown = function(e){cellKeydown(e);};
|
||||||
}
|
}
|
||||||
|
|
||||||
function unselectCell(){
|
function unselectCell(){
|
||||||
if(selected==undefined) return;
|
if(selected==undefined) return;
|
||||||
cellEl(selected).style.background = '#fff';
|
cellEl(selected).style.background = '#fff';
|
||||||
selected = undefined;
|
selected = undefined;
|
||||||
window.onkeydown = undefined;
|
window.onkeydown = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cellEl(n){
|
function cellEl(n){
|
||||||
var r = n>>4;
|
var r = n>>4;
|
||||||
var c = n%16;
|
var c = n%16;
|
||||||
var e = table.children[r].children[c+1];
|
var e = table.children[r].children[c+1];
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
326
nodenames.js
326
nodenames.js
@@ -1,117 +1,209 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in
|
||||||
all copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var nodenames ={
|
var nodenames ={
|
||||||
db1: 82,
|
db1: 82,
|
||||||
db0: 1005,
|
db0: 1005,
|
||||||
db3: 650,
|
db3: 650,
|
||||||
db2: 945,
|
db2: 945,
|
||||||
db5: 175,
|
db5: 175,
|
||||||
db4: 1393,
|
db4: 1393,
|
||||||
db7: 1349,
|
db7: 1349,
|
||||||
db6: 1591,
|
db6: 1591,
|
||||||
a1: 1234,
|
idl0: 116,
|
||||||
ab1: 451,
|
idl1: 576,
|
||||||
ab2: 1340,
|
idl2: 1485,
|
||||||
a2: 978,
|
idl3: 1284,
|
||||||
s2: 81,
|
idl4: 1516,
|
||||||
a5: 858,
|
idl5: 498,
|
||||||
a4: 727,
|
idl6: 1537,
|
||||||
a7: 1653,
|
idl7: 529,
|
||||||
a6: 1136,
|
a1: 1234,
|
||||||
so: 1672,
|
ab1: 451,
|
||||||
sync: 539,
|
ab2: 1340,
|
||||||
vcc: 657,
|
a2: 978,
|
||||||
clk1out: 1163,
|
s2: 81,
|
||||||
p2: 1421,
|
a5: 858,
|
||||||
p3: 439,
|
a4: 727,
|
||||||
p0: 687,
|
a7: 1653,
|
||||||
p1: 1444,
|
a6: 1136,
|
||||||
p6: 77,
|
so: 1672,
|
||||||
p7: 1370,
|
sync: 539,
|
||||||
p4: 1119,
|
vcc: 657,
|
||||||
p5: 0,
|
clk1out: 1163,
|
||||||
pcl3: 1359,
|
p2: 1421,
|
||||||
pcl2: 655,
|
p3: 439,
|
||||||
pcl1: 1022,
|
p0: 687,
|
||||||
pcl0: 1139,
|
p1: 1444,
|
||||||
pcl7: 1611,
|
p6: 77,
|
||||||
pcl6: 377,
|
p7: 1370,
|
||||||
pcl5: 622,
|
p4: 1119,
|
||||||
pcl4: 900,
|
p5: 0,
|
||||||
clk0: 1171,
|
pcl3: 1359,
|
||||||
s3: 1532,
|
pcl2: 655,
|
||||||
res: 159,
|
pcl1: 1022,
|
||||||
s1: 183,
|
pcl0: 1139,
|
||||||
s0: 1403,
|
pcl7: 1611,
|
||||||
s7: 1435,
|
pcl6: 377,
|
||||||
s6: 1212,
|
pcl5: 622,
|
||||||
s5: 1098,
|
pcl4: 900,
|
||||||
s4: 1702,
|
clk0: 1171,
|
||||||
rw: 1156,
|
s3: 1532,
|
||||||
x2: 1,
|
res: 159,
|
||||||
x3: 1648,
|
s1: 183,
|
||||||
x0: 1216,
|
s0: 1403,
|
||||||
x1: 98,
|
s7: 1435,
|
||||||
x6: 448,
|
s6: 1212,
|
||||||
x7: 777,
|
s5: 1098,
|
||||||
x4: 85,
|
s4: 1702,
|
||||||
x5: 589,
|
nots0: 418,
|
||||||
rdy: 89,
|
nots1: 1064,
|
||||||
clk2out: 421,
|
nots2: 752,
|
||||||
nmi: 1297,
|
nots3: 828,
|
||||||
ab12: 1237,
|
nots4: 1603,
|
||||||
ab13: 349,
|
nots5: 601,
|
||||||
ab10: 1443,
|
nots6: 1029,
|
||||||
ab11: 399,
|
nots7: 181,
|
||||||
ab14: 672,
|
rw: 1156,
|
||||||
ab15: 195,
|
x2: 1,
|
||||||
ab0: 268,
|
x3: 1648,
|
||||||
a0: 737,
|
x0: 1216,
|
||||||
a3: 162,
|
x1: 98,
|
||||||
ab3: 211,
|
x6: 448,
|
||||||
ab4: 435,
|
x7: 777,
|
||||||
ab5: 736,
|
x4: 85,
|
||||||
ab6: 887,
|
x5: 589,
|
||||||
ab7: 1493,
|
rdy: 89,
|
||||||
ab8: 230,
|
clk2out: 421,
|
||||||
ab9: 148,
|
nmi: 1297,
|
||||||
pch7: 205,
|
ab12: 1237,
|
||||||
pch6: 1551,
|
ab13: 349,
|
||||||
pch5: 49,
|
ab10: 1443,
|
||||||
pch4: 948,
|
ab11: 399,
|
||||||
pch3: 584,
|
ab14: 672,
|
||||||
pch2: 502,
|
ab15: 195,
|
||||||
pch1: 292,
|
ab0: 268,
|
||||||
pch0: 1670,
|
a0: 737,
|
||||||
irq: 103,
|
a3: 162,
|
||||||
vss: 558,
|
ab3: 211,
|
||||||
y1: 1148,
|
ab4: 435,
|
||||||
y0: 64,
|
ab5: 736,
|
||||||
y3: 305,
|
ab6: 887,
|
||||||
y2: 573,
|
ab7: 1493,
|
||||||
y5: 615,
|
ab8: 230,
|
||||||
y4: 989,
|
ab9: 148,
|
||||||
y7: 843,
|
pch7: 205,
|
||||||
y6: 115,
|
pch6: 1551,
|
||||||
cclk: 943
|
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
|
||||||
|
}
|
||||||
|
36
save.php
36
save.php
@@ -1,18 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$filename = $_REQUEST['name'];
|
$filename = $_REQUEST['name'];
|
||||||
file_put_contents($filename, file_get_contents("php://input"));
|
file_put_contents($filename, file_get_contents("php://input"));
|
||||||
|
|
||||||
function file_put_contents($filename, $data) {
|
function file_put_contents($filename, $data) {
|
||||||
$f = @fopen($filename, 'w');
|
$f = @fopen($filename, 'w');
|
||||||
if ($f) {
|
if ($f) {
|
||||||
$bytes = fwrite($f, $data);
|
$bytes = fwrite($f, $data);
|
||||||
fclose($f);
|
fclose($f);
|
||||||
return $bytes;
|
return $bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
16481
segdefs.js
16481
segdefs.js
File diff suppressed because it is too large
Load Diff
7035
transdefs.js
7035
transdefs.js
File diff suppressed because it is too large
Load Diff
156
wires.css
156
wires.css
@@ -1,68 +1,88 @@
|
|||||||
body {
|
/*
|
||||||
background: white;
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
color: black;
|
|
||||||
font-family: cursive;
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
font-size: 30px;
|
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
|
||||||
div.frame {
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
margin-left: 10px;
|
furnished to do so, subject to the following conditions:
|
||||||
position: relative;
|
|
||||||
width: 1150px;
|
The above copyright notice and this permission notice shall be included in
|
||||||
height: 600px;
|
all copies or substantial portions of the Software.
|
||||||
}
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
div.chip {
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
background: lightgray;
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
border: 2px solid gray;
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
position: absolute;
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
width: 800px;
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
height: 600px;
|
THE SOFTWARE.
|
||||||
overflow: hidden;
|
*/
|
||||||
}
|
|
||||||
|
body {
|
||||||
canvas.chip {
|
background: white;
|
||||||
position: absolute;
|
color: black;
|
||||||
width: 600px;
|
font-family: cursive;
|
||||||
height: 600px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.buttons{
|
div.frame {
|
||||||
position: absolute;
|
margin-left: 10px;
|
||||||
top: -5px;
|
position: relative;
|
||||||
left: 820px;
|
width: 1150px;
|
||||||
}
|
height: 600px;
|
||||||
|
}
|
||||||
p.status {
|
|
||||||
position: absolute;
|
div.chip {
|
||||||
left: 820px;
|
background: lightgray;
|
||||||
top: 20px;
|
border: 2px solid gray;
|
||||||
font-family: monospace;
|
position: absolute;
|
||||||
font-size: 12px;
|
width: 800px;
|
||||||
}
|
height: 600px;
|
||||||
|
overflow: hidden;
|
||||||
img.navbutton{
|
}
|
||||||
margin-left: -5px;
|
|
||||||
border: 0px;
|
canvas.chip {
|
||||||
}
|
position: absolute;
|
||||||
|
width: 600px;
|
||||||
img.navplay{
|
height: 600px;
|
||||||
margin-left: -5px;
|
}
|
||||||
border: 0px;
|
|
||||||
}
|
div.buttons{
|
||||||
|
position: absolute;
|
||||||
img.navstop{
|
top: -5px;
|
||||||
position: absolute;
|
left: 820px;
|
||||||
left: -5px;
|
}
|
||||||
top: 9px;
|
|
||||||
border: 0px;
|
p.status {
|
||||||
}
|
position: absolute;
|
||||||
|
left: 820px;
|
||||||
table.memtable {
|
top: 20px;
|
||||||
position: absolute;
|
font-family: monospace;
|
||||||
top: 63px;
|
font-size: 12px;
|
||||||
left: 820px;
|
}
|
||||||
font-family: monospace;
|
|
||||||
font-size: 12px;
|
img.navbutton{
|
||||||
border-spacing: 0px;
|
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;
|
||||||
|
}
|
||||||
|
700
wires.js
700
wires.js
@@ -1,338 +1,362 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
in the Software without restriction, including without limitation the rights
|
in the Software without restriction, including without limitation the rights
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
furnished to do so, subject to the following conditions:
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in
|
||||||
all copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var frame, chipbg, overlay, hilite, hitbuffer, ctx;
|
var frame, chipbg, overlay, hilite, hitbuffer, ctx;
|
||||||
var centerx=300, centery=300;
|
var centerx=300, centery=300;
|
||||||
var zoom=1;
|
var zoom=1;
|
||||||
var dragMouseX, dragMouseY, moved;
|
var dragMouseX, dragMouseY, moved;
|
||||||
var statbox;
|
var statbox;
|
||||||
|
|
||||||
var colors = ['rgba(128,128,128,0.4)','#FFFF00','#FF00FF','#4DFF4D',
|
var layernames = ['metal', 'diff', 'inputdiode', 'diff0', 'diff1', 'poly'];
|
||||||
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
|
var colors = ['rgba(128,128,192,0.4)','#FFFF00','#FF00FF','#4DFF4D',
|
||||||
|
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
|
||||||
var nodes = new Array();
|
var drawlayers = [true, true, true, true, true, true];
|
||||||
var transistors = {};
|
|
||||||
|
var nodes = new Array();
|
||||||
var ngnd = nodenames['vss'];
|
var transistors = {};
|
||||||
var npwr = nodenames['vcc'];
|
|
||||||
|
var ngnd = nodenames['vss'];
|
||||||
|
var npwr = nodenames['vcc'];
|
||||||
/////////////////////////
|
|
||||||
//
|
|
||||||
// Drawing Setup
|
/////////////////////////
|
||||||
//
|
//
|
||||||
/////////////////////////
|
// Drawing Setup
|
||||||
|
//
|
||||||
function setup(){
|
/////////////////////////
|
||||||
frame = document.getElementById('frame');
|
|
||||||
statbox = document.getElementById('status');
|
// try to present a meaningful page before starting expensive work
|
||||||
setupNodes();
|
function setup(){
|
||||||
setupTransistors();
|
statbox = document.getElementById('status');
|
||||||
setupBackground();
|
setStatus('loading 6502...');
|
||||||
setupOverlay();
|
setTimeout(setup_part2, 0);
|
||||||
setupHilite();
|
}
|
||||||
setupHitBuffer();
|
|
||||||
recenter();
|
function setup_part2(){
|
||||||
refresh();
|
frame = document.getElementById('frame');
|
||||||
setupTable();
|
statbox = document.getElementById('status');
|
||||||
window.onkeypress = function(e){handleKey(e);}
|
setupNodes();
|
||||||
hilite.onmousedown = function(e){mouseDown(e);}
|
setupTransistors();
|
||||||
initChip();
|
setupLayerVisibility();
|
||||||
document.getElementById('stop').style.visibility = 'hidden';
|
setupBackground();
|
||||||
go();
|
setupOverlay();
|
||||||
}
|
setupHilite();
|
||||||
|
setupHitBuffer();
|
||||||
function setupNodes(){
|
recenter();
|
||||||
for(var i in segdefs){
|
refresh();
|
||||||
var seg = segdefs[i];
|
setupTable();
|
||||||
var w = seg[0];
|
window.onkeypress = function(e){handleKey(e);}
|
||||||
if(nodes[w]==undefined)
|
hilite.onmousedown = function(e){mouseDown(e);}
|
||||||
nodes[w] = {segs: new Array(), num: w, pullup: seg[1]=='+',
|
setStatus('resetting 6502...');
|
||||||
state: 'fl', gates: new Array(), c1c2s: new Array()};
|
setTimeout(setup_part3, 0);
|
||||||
if(w==ngnd) continue;
|
}
|
||||||
if(w==npwr) continue;
|
|
||||||
nodes[w].segs.push(seg.slice(3));
|
function setup_part3(){
|
||||||
}
|
initChip();
|
||||||
}
|
document.getElementById('stop').style.visibility = 'hidden';
|
||||||
|
go();
|
||||||
function setupTransistors(){
|
}
|
||||||
for(i in transdefs){
|
|
||||||
var tdef = transdefs[i];
|
function setupNodes(){
|
||||||
var name = tdef[0];
|
for(var i in segdefs){
|
||||||
var gate = tdef[1];
|
var seg = segdefs[i];
|
||||||
var c1 = tdef[2];
|
var w = seg[0];
|
||||||
var c2 = tdef[3];
|
if(nodes[w]==undefined)
|
||||||
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2};
|
nodes[w] = {segs: new Array(), num: w, pullup: seg[1]=='+',
|
||||||
nodes[gate].gates.push(name);
|
state: 'fl', gates: new Array(), c1c2s: new Array()};
|
||||||
nodes[c1].c1c2s.push(name);
|
if(w==ngnd) continue;
|
||||||
nodes[c2].c1c2s.push(name);
|
if(w==npwr) continue;
|
||||||
transistors[name] = trans;
|
nodes[w].segs.push(seg.slice(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setupTransistors(){
|
||||||
function setupBackground(){
|
for(i in transdefs){
|
||||||
chipbg = document.getElementById('chipbg');
|
var tdef = transdefs[i];
|
||||||
chipbg.width = 4000;
|
var name = tdef[0];
|
||||||
chipbg.height = 4000;
|
var gate = tdef[1];
|
||||||
var ctx = chipbg.getContext('2d');
|
var c1 = tdef[2];
|
||||||
ctx.scale(chipbg.width/10000, chipbg.height/10000);
|
var c2 = tdef[3];
|
||||||
ctx.fillStyle = '#000000';
|
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2};
|
||||||
ctx.strokeStyle = 'rgba(255,255,255,0.5)';
|
nodes[gate].gates.push(name);
|
||||||
ctx.lineWidth = 4;
|
nodes[c1].c1c2s.push(name);
|
||||||
ctx.fillRect(0,0,10000,10000);
|
nodes[c2].c1c2s.push(name);
|
||||||
var start = now();
|
transistors[name] = trans;
|
||||||
for(var i in segdefs){
|
}
|
||||||
var seg = segdefs[i];
|
}
|
||||||
var c = seg[2];
|
|
||||||
ctx.fillStyle = colors[c];
|
function setupLayerVisibility(){
|
||||||
drawSeg(ctx, segdefs[i].slice(3));
|
var x=document.getElementById('updateShow');
|
||||||
ctx.fill();
|
for (var i=0;i<x.childNodes.length;i++) {
|
||||||
if((c==0)||(c==6)) ctx.stroke();
|
if(x.childNodes[i].type='checkbox'){
|
||||||
}
|
x.childNodes[i].checked=drawlayers[x.childNodes[i].name];
|
||||||
// console.log('time to draw: ', now() - start, ' ms');
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function setupOverlay(){
|
|
||||||
overlay = document.getElementById('overlay');
|
function setupBackground(){
|
||||||
overlay.width = 4000;
|
console.log('starting setupBackground');
|
||||||
overlay.height = 4000;
|
chipbg = document.getElementById('chipbg');
|
||||||
ctx = overlay.getContext('2d');
|
chipbg.width = 4000;
|
||||||
ctx.scale(overlay.width/10000, overlay.height/10000);
|
chipbg.height = 4000;
|
||||||
}
|
var ctx = chipbg.getContext('2d');
|
||||||
|
ctx.scale(chipbg.width/10000, chipbg.height/10000);
|
||||||
function setupHilite(){
|
ctx.fillStyle = '#000000';
|
||||||
hilite = document.getElementById('hilite');
|
ctx.strokeStyle = 'rgba(255,255,255,0.5)';
|
||||||
hilite.width = 4000;
|
ctx.lineWidth = 4;
|
||||||
hilite.height = 4000;
|
ctx.fillRect(0,0,10000,10000);
|
||||||
var ctx = hilite.getContext('2d');
|
for(var i in segdefs){
|
||||||
ctx.scale(hilite.width/10000, hilite.height/10000);
|
var seg = segdefs[i];
|
||||||
}
|
var c = seg[2];
|
||||||
|
if (drawlayers[c]) {
|
||||||
function setupHitBuffer(){
|
ctx.fillStyle = colors[c];
|
||||||
hitbuffer = document.getElementById('hitbuffer');
|
drawSeg(ctx, segdefs[i].slice(3));
|
||||||
hitbuffer.width = 4000;
|
ctx.fill();
|
||||||
hitbuffer.height = 4000;
|
if((c==0)||(c==6)) ctx.stroke();
|
||||||
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 setupOverlay(){
|
||||||
|
overlay = document.getElementById('overlay');
|
||||||
function hitBufferNode(ctx, i, w){
|
overlay.width = 4000;
|
||||||
var low = hexdigit(i&0xf);
|
overlay.height = 4000;
|
||||||
var mid = hexdigit((i>>4)&0xf);
|
ctx = overlay.getContext('2d');
|
||||||
var high = hexdigit((i>>8)&0xf);
|
ctx.scale(overlay.width/10000, overlay.height/10000);
|
||||||
ctx.fillStyle = '#'+high+'F'+mid+'F'+low+'F';
|
}
|
||||||
for(i in w) {
|
|
||||||
drawSeg(ctx, w[i]);
|
function setupHilite(){
|
||||||
ctx.fill();
|
hilite = document.getElementById('hilite');
|
||||||
}
|
hilite.width = 4000;
|
||||||
}
|
hilite.height = 4000;
|
||||||
|
var ctx = hilite.getContext('2d');
|
||||||
function hexdigit(n){return '0123456789ABCDEF'.charAt(n);}
|
ctx.scale(hilite.width/10000, hilite.height/10000);
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////
|
function setupHitBuffer(){
|
||||||
//
|
hitbuffer = document.getElementById('hitbuffer');
|
||||||
// Drawing Runtime
|
hitbuffer.width = 4000;
|
||||||
//
|
hitbuffer.height = 4000;
|
||||||
/////////////////////////
|
hitbuffer.style.visibility = 'hidden';
|
||||||
|
var ctx = hitbuffer.getContext('2d');
|
||||||
function refresh(){
|
ctx.scale(hitbuffer.width/10000, hitbuffer.height/10000);
|
||||||
ctx.clearRect(0,0,10000,10000);
|
for(i in nodes) hitBufferNode(ctx, i, nodes[i].segs);
|
||||||
for(i in nodes){
|
}
|
||||||
if(isNodeHigh(i)) overlayNode(nodes[i].segs);
|
|
||||||
}
|
function hitBufferNode(ctx, i, w){
|
||||||
}
|
var low = hexdigit(i&0xf);
|
||||||
|
var mid = hexdigit((i>>4)&0xf);
|
||||||
function overlayNode(w){
|
var high = hexdigit((i>>8)&0xf);
|
||||||
ctx.fillStyle = 'rgba(255,0,64,0.4)';
|
ctx.fillStyle = '#'+high+'F'+mid+'F'+low+'F';
|
||||||
for(i in w) {
|
for(i in w) {
|
||||||
drawSeg(ctx, w[i]);
|
drawSeg(ctx, w[i]);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hiliteNode(n){
|
function hexdigit(n){return '0123456789ABCDEF'.charAt(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]))
|
// Drawing Runtime
|
||||||
ctx.fillStyle = 'rgba(255,0,0,0.7)';
|
//
|
||||||
|
/////////////////////////
|
||||||
for(var i in n){
|
|
||||||
var segs = nodes[n[i]].segs;
|
function refresh(){
|
||||||
for(var s in segs){drawSeg(ctx, segs[s]); ctx.fill();}
|
ctx.clearRect(0,0,10000,10000);
|
||||||
}
|
for(i in nodes){
|
||||||
}
|
if(isNodeHigh(i)) overlayNode(nodes[i].segs);
|
||||||
|
}
|
||||||
|
}
|
||||||
function drawSeg(ctx, seg){
|
|
||||||
var dx = 400;
|
function overlayNode(w){
|
||||||
ctx.beginPath();
|
ctx.fillStyle = 'rgba(255,0,64,0.4)';
|
||||||
ctx.moveTo(seg[0]+dx, 10000-seg[1])
|
for(i in w) {
|
||||||
for(var i=2;i<seg.length;i+=2) ctx.lineTo(seg[i]+dx, 10000-seg[i+1]);
|
drawSeg(ctx, w[i]);
|
||||||
ctx.lineTo(seg[0]+dx, 10000-seg[1])
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/////////////////////////
|
|
||||||
//
|
function hiliteNode(n){
|
||||||
// User Interface
|
var ctx = hilite.getContext('2d');
|
||||||
//
|
ctx.clearRect(0,0,10000,10000);
|
||||||
/////////////////////////
|
ctx.fillStyle = 'rgba(255,255,255,0.7)';
|
||||||
|
if(n==-1) return;
|
||||||
function handleKey(e){
|
if(isNodeHigh(n[0]))
|
||||||
var c = e.charCode;
|
ctx.fillStyle = 'rgba(255,0,0,0.7)';
|
||||||
c = String.fromCharCode(c);
|
|
||||||
if('<>?np'.indexOf(c)==-1) return;
|
for(var i in n){
|
||||||
if(c=='<' && zoom>1) setZoom(zoom/1.2);
|
var segs = nodes[n[i]].segs;
|
||||||
else if(c=='>' && zoom<16) setZoom(zoom*1.2);
|
for(var s in segs){drawSeg(ctx, segs[s]); ctx.fill();}
|
||||||
else if(c=='?') setZoom(1);
|
}
|
||||||
else if(c=='n') stepForward();
|
}
|
||||||
else if(c=='p') stepBack();
|
|
||||||
}
|
|
||||||
|
function drawSeg(ctx, seg){
|
||||||
function mouseDown(e){
|
if(noGraphics) return;
|
||||||
e.preventDefault();
|
var dx = 400;
|
||||||
moved=false;
|
ctx.beginPath();
|
||||||
dragMouseX = e.clientX;
|
ctx.moveTo(seg[0]+dx, 10000-seg[1])
|
||||||
dragMouseY = e.clientY;
|
for(var i=2;i<seg.length;i+=2) ctx.lineTo(seg[i]+dx, 10000-seg[i+1]);
|
||||||
window.onmousemove = function(e){mouseMove(e)};
|
ctx.lineTo(seg[0]+dx, 10000-seg[1])
|
||||||
window.onmouseup = function(e){mouseUp(e)};
|
}
|
||||||
}
|
|
||||||
|
/////////////////////////
|
||||||
function mouseMove(e){
|
//
|
||||||
moved = true;
|
// User Interface
|
||||||
if(zoom==1) return;
|
//
|
||||||
var dx = e.clientX-dragMouseX;
|
/////////////////////////
|
||||||
var dy = e.clientY-dragMouseY;
|
|
||||||
dragMouseX = e.clientX;
|
function handleKey(e){
|
||||||
dragMouseY = e.clientY;
|
var c = e.charCode;
|
||||||
centerx-=dx/zoom;
|
c = String.fromCharCode(c);
|
||||||
centerx = Math.max(centerx, 400/zoom);
|
if('<>?np'.indexOf(c)==-1) return;
|
||||||
centerx = Math.min(centerx, 600-400/zoom);
|
if(c=='<' && zoom>1) setZoom(zoom/1.2);
|
||||||
centery-=dy/zoom;
|
else if(c=='>' && zoom<16) setZoom(zoom*1.2);
|
||||||
centery = Math.max(centery, 300/zoom);
|
else if(c=='?') setZoom(1);
|
||||||
centery = Math.min(centery, 600-300/zoom);
|
else if(c=='n') stepForward();
|
||||||
recenter();
|
else if(c=='p') stepBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
function mouseUp(e){
|
function mouseDown(e){
|
||||||
if(!moved) handleClick(e);
|
e.preventDefault();
|
||||||
window.onmousemove = undefined;
|
moved=false;
|
||||||
window.onmouseup = undefined;
|
dragMouseX = e.clientX;
|
||||||
}
|
dragMouseY = e.clientY;
|
||||||
|
window.onmousemove = function(e){mouseMove(e)};
|
||||||
function setZoom(n){
|
window.onmouseup = function(e){mouseUp(e)};
|
||||||
zoom = n;
|
}
|
||||||
setChipStyle({
|
|
||||||
width: 600*n+'px',
|
function mouseMove(e){
|
||||||
height: 600*n+'px'
|
moved = true;
|
||||||
});
|
if(zoom==1) return;
|
||||||
recenter();
|
var dx = e.clientX-dragMouseX;
|
||||||
}
|
var dy = e.clientY-dragMouseY;
|
||||||
|
dragMouseX = e.clientX;
|
||||||
function recenter(){
|
dragMouseY = e.clientY;
|
||||||
var top = -centery*zoom+300;
|
centerx-=dx/zoom;
|
||||||
top = Math.min(top, 0);
|
centerx = Math.max(centerx, 400/zoom);
|
||||||
top = Math.max(top, -600*(zoom-1));
|
centerx = Math.min(centerx, 600-400/zoom);
|
||||||
var left = -centerx*zoom+400;
|
centery-=dy/zoom;
|
||||||
left = Math.min(left, 0);
|
centery = Math.max(centery, 300/zoom);
|
||||||
left = Math.max(left, (zoom==1)?100:-600*zoom+800);
|
centery = Math.min(centery, 600-300/zoom);
|
||||||
setChipStyle({
|
recenter();
|
||||||
top: top+'px',
|
}
|
||||||
left: left+'px',
|
|
||||||
});
|
function mouseUp(e){
|
||||||
}
|
if(!moved) handleClick(e);
|
||||||
|
window.onmousemove = undefined;
|
||||||
function handleClick(e){
|
window.onmouseup = undefined;
|
||||||
var x = localx(hilite, e.clientX)/zoom;
|
}
|
||||||
var y = localy(hilite, e.clientY)/zoom;
|
|
||||||
var w = findNodeNumber(x,y);
|
function setZoom(n){
|
||||||
if(e.shiftKey) hiliteNode(getNodeGroup(w));
|
zoom = n;
|
||||||
else {var a=new Array(); a.push(w); hiliteNode(a);}
|
setChipStyle({
|
||||||
var cx = Math.round(x*10000/600);
|
width: 600*n+'px',
|
||||||
var cy = Math.round(y*10000/600);
|
height: 600*n+'px'
|
||||||
if(w==-1) setStatus('x:',cx,'<br>','y:',cy);
|
});
|
||||||
else {setStatus('x:',cx, 'y:', cy,'<br>','node:',w, nodeName(w));}
|
recenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
function findNodeNumber(x,y){
|
function recenter(){
|
||||||
var ctx = hitbuffer.getContext('2d');
|
var top = -centery*zoom+300;
|
||||||
var pixels = ctx.getImageData(x*4000/600, y*4000/600, 2, 2).data;
|
top = Math.min(top, 0);
|
||||||
if(pixels[0]==0) return -1;
|
top = Math.max(top, -600*(zoom-1));
|
||||||
var high = pixels[0]>>4;
|
var left = -centerx*zoom+400;
|
||||||
var mid = pixels[1]>>4;
|
left = Math.min(left, 0);
|
||||||
var low = pixels[2]>>4;
|
left = Math.max(left, (zoom==1)?100:-600*zoom+800);
|
||||||
return (high<<8)+(mid<<4)+low;
|
setChipStyle({
|
||||||
}
|
top: top+'px',
|
||||||
|
left: left+'px',
|
||||||
/////////////////////////
|
});
|
||||||
//
|
}
|
||||||
// Etc.
|
|
||||||
//
|
function handleClick(e){
|
||||||
/////////////////////////
|
var x = localx(hilite, e.clientX)/zoom;
|
||||||
|
var y = localy(hilite, e.clientY)/zoom;
|
||||||
function setChipStyle(props){
|
var w = findNodeNumber(x,y);
|
||||||
for(var i in props){
|
if(e.shiftKey) hiliteNode(getNodeGroup(w));
|
||||||
chipbg.style[i] = props[i];
|
else {var a=new Array(); a.push(w); hiliteNode(a);}
|
||||||
overlay.style[i] = props[i];
|
var cx = Math.round(x*10000/600);
|
||||||
hilite.style[i] = props[i];
|
var cy = Math.round(y*10000/600);
|
||||||
hitbuffer.style[i] = props[i];
|
if(w==-1) setStatus('x:',cx,'<br>','y:',cy);
|
||||||
}
|
else {setStatus('x:',cx, 'y:', cy,'<br>','node:',w, nodeName(w));}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findNodeNumber(x,y){
|
||||||
function localx(el, gx){
|
var ctx = hitbuffer.getContext('2d');
|
||||||
var lx = gx+window.pageXOffset;
|
var pixels = ctx.getImageData(x*4000/600, y*4000/600, 2, 2).data;
|
||||||
while(el.offsetLeft!=undefined){
|
if(pixels[0]==0) return -1;
|
||||||
lx-=el.offsetLeft+el.clientLeft;
|
var high = pixels[0]>>4;
|
||||||
el = el.parentNode;
|
var mid = pixels[1]>>4;
|
||||||
}
|
var low = pixels[2]>>4;
|
||||||
return lx;
|
return (high<<8)+(mid<<4)+low;
|
||||||
}
|
}
|
||||||
|
|
||||||
function localy(el, gy){
|
function updateShow(layer, on){
|
||||||
var ly = gy+window.pageYOffset;
|
drawlayers[layer]=on;
|
||||||
while(el.offsetTop!=undefined){
|
setupBackground();
|
||||||
ly-=el.offsetTop+el.clientTop;
|
}
|
||||||
el = el.parentNode;
|
|
||||||
}
|
/////////////////////////
|
||||||
return ly;
|
//
|
||||||
}
|
// Etc.
|
||||||
|
//
|
||||||
function setStatus(){
|
/////////////////////////
|
||||||
var res = '';
|
|
||||||
for(var i=0;i<arguments.length;i++) res=res+arguments[i]+' ';
|
function setChipStyle(props){
|
||||||
statbox.innerHTML = res;
|
for(var i in props){
|
||||||
}
|
chipbg.style[i] = props[i];
|
||||||
|
overlay.style[i] = props[i];
|
||||||
function nodeName(n) {
|
hilite.style[i] = props[i];
|
||||||
for(var i in nodenames){
|
hitbuffer.style[i] = props[i];
|
||||||
if(nodenames[i]==n) return i;
|
}
|
||||||
}
|
}
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
function localx(el, gx){
|
||||||
function now(){return new Date().getTime();}
|
var lx = gx+window.pageXOffset;
|
||||||
|
lx-=el.getBoundingClientRect().left
|
||||||
|
return lx;
|
||||||
|
}
|
||||||
|
|
||||||
|
function localy(el, gy){
|
||||||
|
var ly = gy+window.pageYOffset;
|
||||||
|
ly-=el.getBoundingClientRect().top
|
||||||
|
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();}
|
||||||
|
Reference in New Issue
Block a user