64 Commits
V0.4 ... V0.6

Author SHA1 Message Date
84b005673b give the names of the nodes in a shift-click group, if they have names 2010-12-22 21:16:50 +00:00
09c578e361 shift-click: list members of channel-connected nodegroup 2010-12-21 22:31:38 +00:00
167f93f836 feature: URL can define labels and optional boxes 2010-12-20 19:30:49 +00:00
c88e0749cf feature: add support for box and label in highlight layer 2010-12-20 19:00:44 +00:00
6db8836c5c feature: find matches names on underscore-delimited components 2010-12-19 18:31:10 +00:00
27fb1d539e bugfix: shift-click to highlight a pass-connected node-group should work on gates too 2010-12-19 17:54:37 +00:00
21c7a8ca90 bugfix: zoom-to-fit on found objects needed an x offset 2010-12-19 17:41:16 +00:00
cfb726d0e7 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-12-19 17:24:35 +00:00
d352501c7c update the "link here" to include searched objects 2010-12-19 17:24:14 +00:00
4eb1e4c848 Fix protection bits on some files 2010-12-19 12:04:35 -05:00
c3f0d10199 Merge branches 'ed' and 'master' into ed 2010-12-19 12:01:44 -05:00
4398fdaddf Added Bends and Gate Area to transdefs 2010-12-19 10:38:31 -05:00
4f7930eef3 Fix Shift Click which broke in performance improvement changes 2010-12-19 10:37:51 -05:00
c04f37a3df add feature: click can highlight transistors 2010-12-19 12:45:44 +00:00
fc664c7243 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-12-18 11:30:06 +00:00
8bdb9a0682 New transdefs with Gate Bounding Box and Geometry 2010-12-17 21:35:19 -05:00
ae30a57822 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-12-12 18:22:13 +00:00
8a89310e96 Fix expert mode's keyboard handling too. 2010-12-08 06:53:38 +08:00
1c66a8af28 handleKey(): if .charCode is undefined, use .keyCode (Opera compatible.) 2010-12-08 06:53:37 +08:00
78deb4aaa4 fixup nodenames type 2010-12-07 22:49:38 +00:00
85c8447064 Fix expert mode's keyboard handling too. 2010-12-05 12:34:39 +01:00
6cdbfc0c15 handleKey(): if .charCode is undefined, use .keyCode (Opera compatible.) 2010-12-05 09:50:00 +01:00
8ef98d131f added signal names - mostly ALU - from Segher 2010-12-04 17:05:24 +00:00
e660736204 fixup status message when no find command in URL 2010-12-03 16:28:55 +00:00
fc46e50289 add "find" mechanism to URL 2010-12-03 13:35:01 +00:00
4967b58e7f update status box when find is used 2010-12-03 12:46:10 +00:00
6f7dab7990 more nodenames from Segher: alu internals 2010-12-03 12:27:26 +00:00
04196aa36a more nodenames from Segher: decimal mode and carry chain 2010-12-03 12:14:18 +00:00
94a2b38d27 import more signal names from Segher 2010-11-30 21:15:49 +00:00
e052255c55 add first cut of zooming to fit found objects: transistors and nodes. Renamed "Highlight:" button to "Find:" 2010-11-29 20:07:29 +00:00
15453f4435 Merge branch 'ed' 2010-11-28 16:38:32 -05:00
7572b25453 Hilite transistors 2010-11-28 16:37:02 -05:00
93252a0eb1 [bug]fixup obsolete css file reference in browsertrouble.html 2010-11-27 15:58:46 +00:00
172394845a [bug]typo: fixed B bit of status register 2010-11-27 14:30:19 +00:00
ec7da19d77 add z and x to expert mode help text 2010-11-27 14:19:57 +00:00
13e1f51b47 kiosk mode: add link to user guide, tweak help text and add alphabetic zoom controls 2010-11-27 13:54:31 +00:00
e6d3c62057 [bug]deal with disassembly of unknown opcodes 2010-11-27 12:37:14 +00:00
fbf0830d15 Expert page: add link to user guide (wiki page) 2010-11-27 11:37:08 +00:00
019bca0a26 remove white gaps in new logstream table colour scheme 2010-11-26 22:14:09 +00:00
e866a3b58e put non-breaking spaces into disassembly fragments 2010-11-26 14:27:03 +00:00
611490ad76 various blue backgrounds to logstream table 2010-11-26 14:22:45 +00:00
b3e58dcbab immunize kiosk mode against I/O triggers in test program 2010-11-22 15:20:24 +00:00
c7ac03edd8 move the I/O port (incremented value) to the top right for better visibility 2010-11-22 15:19:38 +00:00
b51b5c4398 re-simplify kiosk mode status panel 2010-11-22 15:18:55 +00:00
398060f56b add opcode and machine state info to status panel, add Fetch Execute and State pseudo signals to log tabulation 2010-11-22 13:27:26 +00:00
cdd837dd0c display machine state in status panel 2010-11-22 12:23:20 +00:00
3df7065b83 fold 6502 opcode lookup into macro.js and delete Java original 2010-11-22 12:22:36 +00:00
f860067206 convert java debugger to javascript almost-disassembler 2010-11-22 11:40:14 +00:00
33f00022ca add Achim's original Debugger.java 2010-11-22 11:33:56 +00:00
8a6fe3634f add tracing of datapath control signals 2010-11-19 22:42:26 +00:00
296599890a correct the PC master/slave labelling and revert the predecode to the (inverted) latch nodes 2010-11-19 21:50:20 +00:00
580f4585a6 allow inverted display of negative sense busses 2010-11-19 21:49:16 +00:00
d045485ec4 [enh]allow free-running low-overhead mode, for interactive programs 2010-11-15 17:29:50 +00:00
71a85b3135 small improvement to trigger examples in testprogram 2010-11-15 17:28:45 +00:00
b3a6a12ddc adding URL control of IRQ and NMI pins 2010-11-14 20:15:49 +00:00
5f472cbe10 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-11-10 22:20:36 +00:00
6ced887613 add link to Advanced page and re-word other link 2010-11-10 10:53:59 -05:00
6be4dd1673 add link to Advanced page and re-word other link 2010-11-09 21:25:56 +00:00
7e6eb926ee Merge branch 'master' of git://github.com/trebonian/visual6502 2010-11-09 20:31:19 +00:00
6c899eda1a Add white space between links and chip window 2010-11-08 19:35:12 -05:00
6c2217b8fa [bug]kiosk mode must also load macros before testprogram 2010-11-08 22:29:08 +00:00
f6a86088f0 [enh]add a putc action to the test program 2010-11-08 22:18:07 +00:00
5c9b4e7581 [dev]adding console box and read/write hook mechanism for test program I/O 2010-11-08 22:03:47 +00:00
2a0e251088 [bug]fix improper closing tag (expert.html) 2010-11-08 16:36:45 +00:00
11 changed files with 4406 additions and 3660 deletions

View File

@ -2,7 +2,7 @@
<head>
<title>Visual 6502 in JavaScript</title>
<style type="text/css">@import "wires.css";</style>
<style type="text/css">@import "kiosk.css";</style>
</head>
<body>

View File

@ -138,6 +138,14 @@ a#linkHere{
padding:2px;
}
textarea#consolebox{
font-family:courier,monospace;
border: 1px solid gray;
margin: 2px;
padding: 2px;
width: 80em;
}
div#logstreamscroller{
overflow:auto;
}
@ -145,10 +153,31 @@ div#logstreamscroller{
table.logstream {
font-family: monospace;
font-size: 12px;
border-spacing: 2px;
border-collapse: collapse;
text-align:center;
}
td {
padding-left: 3px;
padding-right: 3px;
}
td.header {
background-color: rgb(187, 204, 255); /* medium-dark blue */
}
td.oddcol {
background-color: rgb(227, 233, 255); /* light blue */
}
td.oddrow {
background-color: rgb(207, 218, 255); /* medium blue */
}
td.oddrowcol {
background-color: rgb(227, 233, 255); /* light blue */
}
/* Splitter */
#frame {
height: 750px;
@ -192,3 +221,8 @@ div.rightcolumn {
.hsplitbar.active, .hsplitbar:hover {
background: #c66 url(3rdparty/img/hgrabber.gif) no-repeat center;
}
span#plain {
display: block;
margin-bottom: 4px;
}

View File

@ -76,7 +76,7 @@ $().ready(function(){
</form>
</div>
<div id="layoutControlPanel">
Use '>' to zoom in, '<' to zoom out, click to probe signals and drag to pan.
Use 'z' or '>' to zoom in, 'x' or '<' to zoom out, click to probe signals and drag to pan.
<form id="updateShow"> Show:
<input type="checkbox" name="1" id="updateShow1" onchange="updateShow(this.name,this.checked)" />(diffusion)
<input type="checkbox" name="3" id="updateShow3" onchange="updateShow(this.name,this.checked)" />(grounded diffusion)
@ -85,8 +85,8 @@ $().ready(function(){
<input type="checkbox" name="0" id="updateShow0" onchange="updateShow(this.name,this.checked)" />(metal)
<input type="checkbox" name="2" id="updateShow2" onchange="updateShow(this.name,this.checked)" />(protection)
</form>
<form action="javascript:hiliteNodeList();" />
<input type="button" value="Highlight:" onclick="hiliteNodeList();" />
<form action="javascript:hiliteNodeList();">
<input type="button" value="Find:" onclick="hiliteNodeList();" />
<input type="text" id="HighlightThese" name="HighlightThese" value="" />
<input type="button" value="Clear Highlighting" onclick="clearHighlight();" />
<span class="animatebox">
@ -114,6 +114,10 @@ $().ready(function(){
<a href ="javascript:goUntilSyncOrWrite()"><img class="navbutton" src="images/singlestep.png" title="step"></a>
<a href ="javascript:goFor()"><img class="navbutton" src="images/fastforward.png" title="fastforward"></a>
</div>
<div style="float:right;">
<a href="http://visual6502.org/wiki/index.php?title=JssimUserHelp" target="_blank">User Guide</a>
&nbsp;
</div>
</div> <!-- buttons -->
<div class="status" id="status"><p>x: 0<br>y: 0</p>
</div> <!-- status -->
@ -124,7 +128,10 @@ $().ready(function(){
</div> <!-- righttopdiv -->
<div id="tracingdiv">
<div id="expertControlPanel">
<textarea id="consolebox">
click here and type if your program handles input
</textarea>
<div id="expertControlPanel" tabindex="3">
<form action="javascript:updateLogList()">
<input type="button" value="Trace more" onclick="updateLoglevel(++loglevel)" />
<input type="button" value="Trace less" onclick="updateLoglevel(--loglevel)" />

View File

@ -24,6 +24,8 @@ var centerx=300, centery=300;
var zoom=1;
var dragMouseX, dragMouseY, moved;
var statbox;
var findThese;
var labelThese=[];
// Some constants for the graphics presentation
// the canvas is embedded in an 800x600 clipping div
@ -103,6 +105,7 @@ function setup_part4(){
setupNodeNameList();
logThese=signalSet(loglevel);
loadProgram();
setupConsole();
if(noSimulation){
stopChip();
running=undefined;
@ -172,6 +175,14 @@ function setupParams(){
} else if(name=="zoom" && parseInt(value)!=NaN){
zoom=parseInt(value);
} else
// perform a search, highlight and zoom to object(s)
if(name=="find" && value.length>0){
findThese=value;
} else
// affix label with optional box to highlight an area of interest
if(name=="label" && value.length>0){
labelThese.push(value.split(","));
} else
// load a test program: Address, Data and Reset
if(name=="a" && parseInt(value,16)!=NaN){
userAddress=parseInt(value,16);
@ -187,6 +198,14 @@ function setupParams(){
clockTriggers[value]="setLow('res');";
} else if(name=="reset1" && parseInt(value)!=NaN){
clockTriggers[value]="setHigh('res');";
} else if(name=="irq0" && parseInt(value)!=NaN){
clockTriggers[value]="setLow('irq');";
} else if(name=="irq1" && parseInt(value)!=NaN){
clockTriggers[value]="setHigh('irq');";
} else if(name=="nmi0" && parseInt(value)!=NaN){
clockTriggers[value]="setLow('nmi');";
} else if(name=="nmi1" && parseInt(value)!=NaN){
clockTriggers[value]="setHigh('nmi');";
} else
// run a test program, and optionally check against a golden checksum
if(name=="steps" && parseInt(value)!=NaN){
@ -219,7 +238,7 @@ function updateChipLayoutAnimation(isOn){
// these keyboard actions are primarily for the chip display
function handleKey(e){
var c = e.charCode;
var c = e.charCode || e.keyCode;
c = String.fromCharCode(c);
if('<>?npZzx'.indexOf(c)==-1) return;
if((c=='Z'||c=='x'||c=='<') && zoom>1) setZoom(zoom/1.2);
@ -284,35 +303,141 @@ function recenter(){
top: top+'px',
left: left+'px',
});
document.getElementById('linkHere').href=location.pathname+"?"+whereAmIAsQuery();
updateLinkHere();
}
function updateLinkHere(){
var target = location.pathname + "?nosim=t&";
var findlist = document.getElementById('HighlightThese').value.split(/[\s,]+/).join(",");
if (findlist != "")
target = target + "find=" + findlist + "&";
target = target + whereAmIAsQuery();
document.getElementById('linkHere').href=target;
}
// place a text label on the highlight layer
// with an optional box around an area of interest
// coordinates used are those reported by a click
// for example:
// boxLabel(['PD', 50, 8424, 3536, 9256, 2464])
// boxLabel(['IR', 50, 8432, 2332, 9124, 984])
// boxLabel(['PLA', 100, 1169, 2328, 8393, 934])
// boxLabel(['Y', 50, 2143, 8820, 2317, 5689])
// boxLabel(['X', 50, 2317, 8820, 2490, 5689])
// boxLabel(['S', 50, 2490, 8820, 2814, 5689])
// boxLabel(['ALU', 50, 2814, 8820, 4525, 5689])
// boxLabel(['DAdj', 40, 4525, 8820, 5040, 5689])
// boxLabel(['A', 50, 5040, 8820, 5328, 5689])
// boxLabel(['PC', 50, 5559, 8820, 6819, 5689])
// boxLabel(['ID', 50, 7365, 8820, 7676, 5689])
// boxLabel(['TimC', 40, 600, 1926, 1174, 604])
function flashBoxLabel(args) {
clearHighlight();
var callBack = function(){boxLabel(args);};
setTimeout(callBack, 400);
setTimeout(clearHighlight, 800);
setTimeout(callBack, 1200);
}
function boxLabel(args) {
var text = args[0];
var textsize = args[1];
var thickness = 1+ textsize / 20;
var boxXmin = args[2] * grCanvasSize / grChipSize;
var boxYmin = args[3] * grCanvasSize / grChipSize;
var boxXmax = args[4] * grCanvasSize / grChipSize;
var boxYmax = args[5] * grCanvasSize / grChipSize;
ctx.lineWidth = thickness;
ctx.font = textsize + 'px sans-serif';
ctx.fillStyle = '#ff0'; // yellow
ctx.fillStyle = '#f8f'; // magenta
ctx.fillStyle = '#fff'; // white
ctx.strokeStyle = '#fff'; // white
if(args.length>4){
ctxDrawBox(ctx, boxXmin, boxYmin, boxXmax, boxYmax);
// offset the text label to the interior of the box
boxYmin -= thickness * 2;
}
ctx.strokeStyle = '#fff'; // white
ctx.strokeStyle = '#000'; // black
ctx.lineWidth = thickness*2;
ctx.strokeText(text, boxXmin, boxYmin);
ctx.fillText(text, boxXmin, boxYmin);
}
var highlightThese;
// flash some set of nodes according to user input
// also zoom to fit those nodes (not presently optional)
function hiliteNodeList(){
var tmplist = document.getElementById('HighlightThese').value.split(/[\s,]+/);
if(tmplist.length==0){
if(tmplist.join("").length==0){
// request to highlight nothing, so switch off any signal highlighting
hiliteNode(-1);
return;
}
highlightThese = [];
var seglist=[];
var report="";
for(var i=0;i<tmplist.length;i++){
// get a node number from a signal name or a node number
var name = tmplist[i];
var value = parseInt(tmplist[i]);
if((value!=NaN) && (typeof nodes[name] != "undefined")) {
if((value!=NaN) && (typeof nodes[value] != "undefined")) {
highlightThese.push(value);
report="node: " + value + ' ' + nodeName(value);
for(var s in nodes[value].segs)
seglist.push(nodes[value].segs[s]);
} else if(typeof nodenames[name] != "undefined") {
highlightThese.push(nodenames[name]);
report="node: " + nodenames[name] + ' ' + name;
for(var s in nodes[nodenames[name]].segs)
seglist.push(nodes[nodenames[name]].segs[s]);
} else if(typeof transistors[name] != "undefined") {
// normally we push numbers: a non-number is a transistor name
highlightThese.push(name);
report="transistor: " + name;
seglist.push([
transistors[name].bb[0],transistors[name].bb[2],
transistors[name].bb[1],transistors[name].bb[3]
]);
} else {
// allow match of underscore-delimited components, so
// SUMS and dpc17 both match the node dpc17_SUMS
for(var i in nodenames){
re=new RegExp("(^" + name + "_|_" + name + "$)");
if (re.test(i)){
value = nodenames[i];
highlightThese.push(value);
report="node: " + value + ' ' + nodeName(value);
for(var s in nodes[value].segs)
seglist.push(nodes[value].segs[s]);
break;
}
}
}
// invalid input: how to tell the user?
}
if(highlightThese.length==0){
// all input rejected: how to tell the user?
setStatus('Find: nothing found!','(Enter a list of nodenumbers, names or transistor names)');
return;
} else if (highlightThese.length==1){
setStatus('Find results:',report);
} else {
setStatus('Find: multiple objects found','(' + highlightThese.length + ' objects)');
}
var xmin=seglist[0][0], xmax=seglist[0][0];
var ymin=seglist[0][1], ymax=seglist[0][1];
for(var s in seglist){
for(var i=0;i<seglist[s].length;i+=2){
if(seglist[s][i]<xmin) xmin=seglist[s][i];
if(seglist[s][i]>xmax) xmax=seglist[s][i];
if(seglist[s][i+1]<ymin) ymin=seglist[s][i+1];
if(seglist[s][i+1]>ymax) ymax=seglist[s][i+1];
}
}
zoomToBox(xmin,xmax,ymin,ymax);
updateLinkHere();
clearHighlight(); // nullify the simulation overlay (orange/purple)
hiliteNode(-1); // unhighlight all nodes
setTimeout("hiliteNode(highlightThese);", 400);
@ -320,22 +445,53 @@ function hiliteNodeList(){
setTimeout("hiliteNode(highlightThese);", 1200);
}
// some notes on coordinates:
// the localx and localy functions return canvas coordinate offsets from the canvas window top left corner
// we divide the results by 'zoom' to get drawn coordinates useful in findNodeNumber
// to convert to reported user chip coordinates we multiply by grChipSize/600
// to compare to segdefs and transdefs coordinates we subtract 400 from x and subtract y from grChipSize
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);}
// convert to chip coordinates
var cx = Math.round(x*grChipSize/600);
var cy = Math.round(y*grChipSize/600);
var cy = Math.round(y*grChipSize/600);
// prepare two lines of status report
var s1='x: ' + cx + ' y: ' + cy;
var s2='node:&nbsp;' + w + '&nbsp;' + nodeName(w);
if(w==-1) {
setStatus('x: '+cx, 'y: '+cy);
} else {
var s1='x: ' + cx + ' y: ' + cy;
var s2='node: ' + w + ' ' + nodeName(w);
setStatus(s1, s2);
if(ctrace) console.log(s1, s2);
setStatus(s1); // no node found, so report only coordinates
return;
}
// we have a node, but maybe we clicked over a transistor
var nodelist=[w];
// match the coordinate against transistor gate bounding boxes
x=cx-400;
y=grChipSize-cy;
for(var i=0;i<nodes[w].gates.length;i++){
var xmin=nodes[w].gates[i].bb[0], xmax=nodes[w].gates[i].bb[1];
var ymin=nodes[w].gates[i].bb[2], ymax=nodes[w].gates[i].bb[3];
if((x >= xmin) && (x <= xmax) && (y >= ymin) && (y <= ymax)){
// only one match at most, so we replace rather than push
nodelist=[nodes[w].gates[i].name];
s2='transistor: ' + nodes[w].gates[i].name + ' on ' + s2;
}
}
// if this is a shift-click, just find and highlight the pass-connected group
// and list the nodes (or nodenames, preferably)
if(e.shiftKey) {
getNodeGroup(w);
nodelist = group;
s2 = "nodegroup from&nbsp;" + s2 +
" (nodes:&nbsp;" +
group.map(function(x){return nodeName(x)?nodeName(x):x;}).join(",") +
")";
}
hiliteNode(nodelist);
setStatus(s1, s2);
if(ctrace) console.log(s1, s2);
}
function updateLoglevel(value){
@ -352,6 +508,14 @@ function setupExpertMode(isOn){
document.getElementById('layoutControlPanel').style.display = 'block';
}
var consolegetc; // global variable to hold last keypress in the console area
var consolebox;
function setupConsole(){
consolebox=document.getElementById('consolebox');
consolebox.onkeypress=function(e){consolegetc=e.charCode || e.keyCode;};
}
var chipsurround;
function updateChipLayoutVisibility(isOn){
@ -392,8 +556,19 @@ function setupChipLayoutGraphics(){
refresh();
document.getElementById('waiting').style.display = 'none';
setStatus('Ready!'); // would prefer chipStatus but it's not idempotent
// pre-fill the Find box if parameters supplied
if(typeof findThese != "undefined") {
document.getElementById('HighlightThese').value = findThese;
hiliteNodeList(); // will pan and zoom to fit
}
// pre-pan and zoom if requested (will override any zoom-to-fit by hiliteNodeList)
if(moveHereFirst!=null)
moveHere(moveHereFirst);
// draw any URL-requested labels and boxes
if(labelThese.length>0) {
for(var i=0;i<labelThese.length;i+=1)
flashBoxLabel(labelThese[i]);
}
// grant focus to the chip display to enable zoom keys
chipsurround.focus();
chipsurround.onmousedown = function(e){mouseDown(e);};

View File

@ -12,8 +12,8 @@
<script src="wires.js"></script>
<script src="chipsim.js"></script>
<script src="memtable.js"></script>
<script src="testprogram.js"></script>
<script src="macros.js"></script>
<script src="testprogram.js"></script>
<script type="text/javascript">
function handleOnload() {
@ -62,11 +62,11 @@ lots of RAM. If you have trouble, please <a href="browsertrouble.html">check com
<br />
<span id="browsertrouble"></span>
<br />
Hit '>' to zoom in, '<' to zoom out
Keyboard controls: 'z' to zoom in, 'x' to zoom out, 'n' to step the simulation.
<br />
Left-click and drag to scroll around
Mouse controls: Left-click and drag to scroll around (when you're zoomed in.)
<br />
Enter your own program into the array of RAM
More information in the <a href="http://visual6502.org/wiki/index.php?title=JssimUserHelp">User Guide<a>.
<br />
<br />
</span>
@ -87,6 +87,7 @@ Enter your own program into the array of RAM
<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 style="float:right; margin-left:20px;">... or try <a href="expert.html">Advanced</a></div>
</div>
<p class="status" id="status">x: 0<br>y: 0</p>
<table class="memtable" id="memtable"></table>
@ -99,7 +100,7 @@ Source code is available on <a href="http://github.com/trebonian/visual6502">git
Use the online <a href="http://www.6502asm.com/">emulator and assembler</a> from 6502asm.com
and <a href="http://www.e-tradition.net/bytes/6502/disassembler.html">disassembler</a> from e-tradition.net
<br />
For in-depth 6502 investigation and some more advanced features, try our <a href="/JSSim/expert.html">Experimenter's (Beta) version</a>.
For in-depth 6502 investigation and some more advanced features, try our <a href="expert.html">Advanced</a> page.
<br />
<br />

View File

@ -88,6 +88,7 @@ function setup_part2(){
function setup_part3(){
loadProgram();
writeTriggers={}; // kiosk mode does not handle I/O
initChip();
document.getElementById('stop').style.visibility = 'hidden';
go();
@ -101,11 +102,11 @@ function setup_part3(){
/////////////////////////
function handleKey(e){
var c = e.charCode;
var c = e.charCode || e.keyCode;
c = String.fromCharCode(c);
if('<>?np'.indexOf(c)==-1) return;
if(c=='<' && zoom>1) setZoom(zoom/1.2);
else if(c=='>' && zoom<grMaxZoom) setZoom(zoom*1.2);
if('zx<>?np'.indexOf(c)==-1) return;
if((c=='x' || c=='<') && zoom>1) setZoom(zoom/1.2);
else if((c=='z' || c=='>') && zoom<grMaxZoom) setZoom(zoom*1.2);
else if(c=='?') setZoom(1);
else if(c=='n') stepForward();
else if(c=='p') stepBack();
@ -168,7 +169,10 @@ 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));
if(e.shiftKey) {
getNodeGroup(w);
hiliteNode(group);
}
else {var a=new Array(); a.push(w); hiliteNode(a);}
var cx = Math.round(x*grChipSize/600);
var cy = Math.round(y*grChipSize/600);

342
macros.js
View File

@ -1,5 +1,5 @@
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles
Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles, Achim Breidenbach
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -28,11 +28,12 @@ var running = false;
var logThese=[];
var presetLogLists=[
['cycle'],
['ab','db','rw','sync','pc','a','x','y','s','p'],
['ir','tcstate','pd'],
['ab','db','rw','Fetch','pc','a','x','y','s','p'],
['Execute','State'],
['ir','tcstate','-pd'],
['adl','adh','sb','alu'],
['alucin','alua','alub','alucout','aluvout','dasb'],
['plaOutputs'],
['plaOutputs','DPControl'],
['idb','dor'],
['irq','nmi','res'],
];
@ -209,24 +210,42 @@ function step(){
}
// triggers for breakpoints, watchpoints, input pin events
// almost always are undefined when tested, so minimal impact on performance
clockTriggers={};
writeTriggers={};
readTriggers={};
fetchTriggers={};
// example instruction tracing triggers
// fetchTriggers[0x20]="console.log('0x'+readAddressBus().toString(16)+': JSR');";
// fetchTriggers[0x60]="console.log('0x'+readAddressBus().toString(16)+': RTS');";
// fetchTriggers[0x4c]="console.log('0x'+readAddressBus().toString(16)+': JMP');";
// simulate a single clock phase with no update to graphics or trace
function halfStep(){
var clk = isNodeHigh(nodenames['clk0']);
eval(clockTriggers[cycle]); // usually undefined, no measurable performance loss
eval(clockTriggers[cycle]);
if (clk) {setLow('clk0'); handleBusRead(); }
else {setHigh('clk0'); handleBusWrite();}
}
function handleBusRead(){
if(isNodeHigh(nodenames['rw'])) writeDataBus(mRead(readAddressBus()));
if(isNodeHigh(nodenames['rw'])){
var a = readAddressBus();
var d = eval(readTriggers[a]);
if(d == undefined)
d = mRead(readAddressBus());
if(isNodeHigh(nodenames['sync']))
eval(fetchTriggers[d]);
writeDataBus(d);
}
}
function handleBusWrite(){
if(!isNodeHigh(nodenames['rw'])){
var a = readAddressBus();
var d = readDataBus();
eval(writeTriggers[a]);
mWrite(a,d);
if(a<0x200) setCellValue(a,d);
}
@ -243,7 +262,7 @@ function readPstring(){
result = (isNodeHigh(nodenames['p7'])?'N':'n') +
(isNodeHigh(nodenames['p6'])?'V':'v') +
'&#8209' + // non-breaking hyphen
(isNodeHigh(nodenames['p3'])?'B':'b') +
(isNodeHigh(nodenames['p4'])?'B':'b') +
(isNodeHigh(nodenames['p3'])?'D':'d') +
(isNodeHigh(nodenames['p2'])?'I':'i') +
(isNodeHigh(nodenames['p1'])?'Z':'z') +
@ -255,18 +274,31 @@ function readPC(){return (readBits('pch', 8)<<8) + readBits('pcl', 8);}
function readPCL(){return readBits('pcl', 8);}
function readPCH(){return readBits('pch', 8);}
function listActivePlaOutputs(){
// PLA outputs are mostly ^op- but some have a prefix too
// - we'll allow the x and xx prefix but ignore the #
var r=new RegExp('^([x]?x-)?op-');
var pla=[];
// for one-hot or few-hot signal collections we want to list the active ones
// and for brevity we remove the common prefix
function listActiveSignals(pattern){
var r=new RegExp(pattern);
var list=[];
for(var i in nodenamelist){
if(r.test(nodenamelist[i])) {
if(isNodeHigh(nodenames[nodenamelist[i]]))
pla.push(nodenamelist[i]);
// also map hyphen to a non-breaking version
list.push(nodenamelist[i].replace(r,'').replace(/-/g,'&#8209'));
}
}
return pla;
return list;
}
// The 6502 TCState is almost but not quite an inverted one-hot shift register
function listActiveTCStates() {
var s=[];
if(!isNodeHigh(nodenames['clock1'])) s.push("T0");
if(!isNodeHigh(nodenames['clock2'])) s.push("T1");
if(!isNodeHigh(nodenames['t2'])) s.push("T2");
if(!isNodeHigh(nodenames['t3'])) s.push("T3");
if(!isNodeHigh(nodenames['t4'])) s.push("T4");
if(!isNodeHigh(nodenames['t5'])) s.push("T5");
return s.join("+");
}
function readBit(name){
@ -284,6 +316,7 @@ function readBits(name, n){
function busToString(busname){
// takes a signal name or prefix
// returns an appropriate string representation
// some 'signal names' are CPU-specific aliases to user-friendly string output
if(busname=='cycle')
return cycle>>1;
if(busname=='pc')
@ -292,15 +325,34 @@ function busToString(busname){
return readPstring();
if(busname=='tcstate')
return ['clock1','clock2','t2','t3','t4','t5'].map(busToHex).join("");
if(busname=='State')
return listActiveTCStates();
if(busname=='Execute')
return dis6502toHTML(readBits('ir',8));
if(busname=='Fetch')
return isNodeHigh(nodenames['sync'])?dis6502toHTML(readDataBus()):"";
if(busname=='plaOutputs')
return listActivePlaOutputs();
return busToHex(busname);
// PLA outputs are mostly ^op- but some have a prefix too
// - we'll allow the x and xx prefix but ignore the #
return listActiveSignals('^([x]?x-)?op-');
if(busname=='DPControl')
return listActiveSignals('^dpc[0-9]+_');
if(busname[0]=="-"){
// invert the value of the bus for display
var value=busToHex(busname.slice(1))
if(typeof value != "undefined")
return value.replace(/./g,function(x){return (15-parseInt(x,16)).toString(16)});
else
return undefined;;
} else {
return busToHex(busname);
}
}
function busToHex(busname){
// may be passed a bus or a signal, so allow multiple signals
var width=0;
var r=new RegExp('^' + busname + '[0-9]');
var r=new RegExp('^' + busname + '[0-9]+$');
for(var i in nodenamelist){
if(r.test(nodenamelist[i])) {
width++;
@ -407,25 +459,56 @@ function chipStatus(){
' Y:' + hexByte(readY()) +
' SP:' + hexByte(readSP()) +
' ' + readPstring();
var chk='';
if(goldenChecksum != undefined)
chk=" Chk:" + traceChecksum + ((traceChecksum==goldenChecksum)?" OK":" no match");
setStatus(machine1, machine2, "Hz: " + estimatedHz().toFixed(1) + chk);
var machine3 =
'Hz: ' + estimatedHz().toFixed(1);
if(typeof expertMode != "undefined") {
machine3 += ' Exec: ' + busToString('Execute') + '(' + busToString('State') + ')';
if(isNodeHigh(nodenames['sync']))
machine3 += ' (Fetch: ' + busToString('Fetch') + ')';
if(goldenChecksum != undefined)
machine3 += " Chk:" + traceChecksum + ((traceChecksum==goldenChecksum)?" OK":" no match");
}
setStatus(machine1, machine2, machine3);
if (loglevel>0) {
updateLogbox(logThese);
}
selectCell(ab);
}
// run for an extended number of cycles, with low overhead, for interactive programs or for benchmarking
// note: to run an interactive program, use an URL like
// http://visual6502.org/JSSim/expert.html?graphics=f&loglevel=-1&headlesssteps=-500
function goFor(){
var n = headlessSteps;
estimatedHz1();
var n = headlessSteps; // a negative value is a request to free-run
if(headlessSteps<0)
n=-n;
var start = document.getElementById('start');
var stop = document.getElementById('stop');
start.style.visibility = 'hidden';
stop.style.visibility = 'visible';
if(typeof running == "undefined") {
initChip();
}
running = true;
setTimeout("instantaneousHz(); goForN("+n+")",0);
}
// helper function: allows us to poll 'running' without resetting it when we're re-scheduled
function goForN(n){
var n2=n; // save our parameter so we can re-submit ourselves
while(n--){
halfStep();
cycle++;
}
estimatedHz1();
instantaneousHz();
chipStatus();
if((headlessSteps<0) && running){
setTimeout("goForN("+n2+")",0); // re-submit ourselves if we are meant to free-run
return;
}
running = false;
start.style.visibility = 'visible';
stop.style.visibility = 'hidden';
}
var prevHzTimeStamp=0;
@ -434,13 +517,10 @@ var prevHzEstimate1=1;
var prevHzEstimate2=1;
var HzSamplingRate=10;
// return an averaged speed: called periodically during normal running
function estimatedHz(){
if(cycle%HzSamplingRate!=3)
return prevHzEstimate1;
return estimatedHz1();
}
function estimatedHz1(){
var HzTimeStamp = now();
var HzEstimate = (cycle-prevHzCycleCount+.01)/(HzTimeStamp-prevHzTimeStamp+.01);
HzEstimate=HzEstimate*1000/2; // convert from phases per millisecond to Hz
@ -455,12 +535,26 @@ function estimatedHz1(){
return prevHzEstimate1
}
// return instantaneous speed: called twice, before and after a timed run using goFor()
function instantaneousHz(){
var HzTimeStamp = now();
var HzEstimate = (cycle-prevHzCycleCount+.01)/(HzTimeStamp-prevHzTimeStamp+.01);
HzEstimate=HzEstimate*1000/2; // convert from phases per millisecond to Hz
prevHzEstimate1=HzEstimate;
prevHzEstimate2=prevHzEstimate1;
prevHzTimeStamp=HzTimeStamp;
prevHzCycleCount=cycle;
return prevHzEstimate1
}
var logbox;
function initLogbox(names){
var logbox=document.getElementById('logstream');
logbox=document.getElementById('logstream');
if(logbox==null)return;
names=names.map(function(x){return x.replace(/^-/,'')});
logStream = [];
logStream.push("<td>" + names.join("</td><td>") + "</td>");
logStream.push("<td class=header>" + names.join("</td><td class=header>") + "</td>");
logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>";
}
@ -469,9 +563,8 @@ var logboxAppend=true;
// can append or prepend new states to the log table
// when we reverse direction we need to reorder the log stream
function updateLogDirection(){
logboxAppend=!logboxAppend;
var logbox=document.getElementById('logstream');
var loglines=[];
logboxAppend=!logboxAppend;
// the first element is the header so we can't reverse()
for (var i=1;i<logStream.length;i++) {
loglines.unshift(logStream[i]);
@ -483,18 +576,27 @@ function updateLogDirection(){
// update the table of signal values, by prepending or appending
function updateLogbox(names){
var logbox=document.getElementById('logstream');
var signals=[];
var odd=true;
var bg;
var row;
for(i in names){
signals.push(busToString(names[i]));
for(var i in names){
if(cycle % 4 < 2){
bg = odd ? " class=oddcol":"";
} else {
bg = odd ? " class=oddrow":" class=oddrowcol";
}
signals.push("<td" + bg + ">" + busToString(names[i]) + "</td>");
odd =! odd;
}
row = "<tr>" + signals.join("") + "</tr>";
if(logboxAppend)
logStream.push("<td>" + signals.join("</td><td>") + "</td>");
logStream.push(row);
else
logStream.splice(1,0,"<td>" + signals.join("</td><td>") + "</td>");
logStream.splice(1,0,row);
logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>";
logbox.innerHTML = logStream.join("");
}
function getMem(){
@ -519,3 +621,167 @@ function adler32(x){
}
return (0x100000000+(b<<16)+a).toString(16).slice(-8);
}
// sanitised opcode for HTML output
function dis6502toHTML(byte){
var opcode=dis6502[byte];
if(typeof opcode == "undefined")
return "unknown"
return opcode.replace(/ /,'&nbsp;');
}
// opcode lookup for 6502 - not quite a disassembly
// javascript derived from Debugger.java by Achim Breidenbach
var dis6502={
0x00:"BRK",
0x01:"ORA (zp,X)",
0x05:"ORA zp",
0x06:"ASL zp",
0x08:"PHP",
0x09:"ORA #",
0x0A:"ASL ",
0x0D:"ORA Abs",
0x0E:"ASL Abs",
0x10:"BPL ",
0x11:"ORA (zp),Y",
0x15:"ORA zp,X",
0x16:"ASL zp,X",
0x18:"CLC",
0x19:"ORA Abs,Y",
0x1D:"ORA Abs,X",
0x1E:"ASL Abs,X",
0x20:"JSR Abs",
0x21:"AND (zp,X)",
0x24:"BIT zp",
0x25:"AND zp",
0x26:"ROL zp",
0x28:"PLP",
0x29:"AND #",
0x2A:"ROL ",
0x2C:"BIT Abs",
0x2D:"AND Abs",
0x2E:"ROL Abs",
0x30:"BMI ",
0x31:"AND (zp),Y",
0x35:"AND zp,X",
0x36:"ROL zp,X",
0x38:"SEC",
0x39:"AND Abs,Y",
0x3D:"AND Abs,X",
0x3E:"ROL Abs,X",
0x40:"RTI",
0x41:"EOR (zp,X)",
0x45:"EOR zp",
0x46:"LSR zp",
0x48:"PHA",
0x49:"EOR #",
0x4A:"LSR ",
0x4C:"JMP Abs",
0x4D:"EOR Abs",
0x4E:"LSR Abs",
0x50:"BVC ",
0x51:"EOR (zp),Y",
0x55:"EOR zp,X",
0x56:"LSR zp,X",
0x58:"CLI",
0x59:"EOR Abs,Y",
0x5D:"EOR Abs,X",
0x5E:"LSR Abs,X",
0x60:"RTS",
0x61:"ADC (zp,X)",
0x65:"ADC zp",
0x66:"ROR zp",
0x68:"PLA",
0x69:"ADC #",
0x6A:"ROR ",
0x6C:"JMP zp",
0x6D:"ADC Abs",
0x6E:"ROR Abs",
0x70:"BVS ",
0x71:"ADC (zp),Y",
0x75:"ADC zp,X",
0x76:"ROR zp,X",
0x78:"SEI",
0x79:"ADC Abs,Y",
0x7D:"ADC Abs,X",
0x7E:"ROR Abs,X",
0x81:"STA (zp,X)",
0x84:"STY zp",
0x85:"STA zp",
0x86:"STX zp",
0x88:"DEY",
0x8A:"TXA",
0x8C:"STY Abs",
0x8D:"STA Abs",
0x8E:"STX Abs",
0x90:"BCC ",
0x91:"STA (zp),Y",
0x94:"STY zp,X",
0x95:"STA zp,X",
0x96:"STX zp,Y",
0x98:"TYA",
0x99:"STA Abs,Y",
0x9A:"TXS",
0x9D:"STA Abs,X",
0xA0:"LDY #",
0xA1:"LDA (zp,X)",
0xA2:"LDX #",
0xA4:"LDY zp",
0xA5:"LDA zp",
0xA6:"LDX zp",
0xA8:"TAY",
0xA9:"LDA #",
0xAA:"TAX",
0xAC:"LDY Abs",
0xAD:"LDA Abs",
0xAE:"LDX Abs",
0xB0:"BCS ",
0xB1:"LDA (zp),Y",
0xB4:"LDY zp,X",
0xB5:"LDA zp,X",
0xB6:"LDX zp,Y",
0xB8:"CLV",
0xB9:"LDA Abs,Y",
0xBA:"TSX",
0xBC:"LDY Abs,X",
0xBD:"LDA Abs,X",
0xBE:"LDX Abs,Y",
0xC0:"CPY #",
0xC1:"CMP (zp,X)",
0xC4:"CPY zp",
0xC5:"CMP zp",
0xC6:"DEC zp",
0xC8:"INY",
0xC9:"CMP #",
0xCA:"DEX",
0xCC:"CPY Abs",
0xCD:"CMP Abs",
0xCE:"DEC Abs",
0xD0:"BNE ",
0xD1:"CMP (zp),Y",
0xD5:"CMP zp,X",
0xD6:"DEC zp,X",
0xD8:"CLD",
0xD9:"CMP Abs,Y",
0xDD:"CMP Abs,X",
0xDE:"DEC Abs,X",
0xE0:"CPX #",
0xE1:"SBC (zp,X)",
0xE4:"CPX zp",
0xE5:"SBC zp",
0xE6:"INC zp",
0xE8:"INX",
0xE9:"SBC #",
0xEA:"NOP",
0xEC:"CPX Abs",
0xED:"SBC Abs",
0xEE:"INC Abs",
0xF0:"BEQ ",
0xF1:"SBC (zp),Y",
0xF5:"SBC zp,X",
0xF6:"INC zp,X",
0xF8:"SED",
0xF9:"SBC Abs,Y",
0xFD:"SBC Abs,X",
0xFE:"INC Abs,X",
};

View File

@ -90,13 +90,13 @@ pcl4: 900,
pcl5: 622,
pcl6: 377,
pcl7: 1611,
pclp0: 526, // machine state: program counter low (pre-incremented?, second storage node)
pclp0: 1227, // machine state: program counter low (pre-incremented?, second storage node)
pclp1: 1102,
pclp2: 1411,
pclp2: 1079,
pclp3: 868,
pclp4: 15,
pclp4: 39,
pclp5: 1326,
pclp6: 993,
pclp6: 731,
pclp7: 536,
pch0: 1670, // machine state: program counter high (first storage node)
pch1: 292,
@ -107,21 +107,33 @@ pch5: 49,
pch6: 1551,
pch7: 205,
pchp0: 780, // machine state: program counter high (pre-incremented?, second storage node)
pchp1: 126,
pchp1: 113,
pchp2: 114,
pchp3: 1061,
pchp3: 124,
pchp4: 820,
pchp5: 469,
pchp5: 33,
pchp6: 751,
pchp7: 663,
p0: 687, // machine state: status register
p1: 1444,
p2: 1421,
p3: 439,
p4: 1119, // there is no bit4 in the status register!
p5: -1, // there is no bit5 in the status register!
p6: 77,
p7: 1370,
pchp7: 535,
// machine state: status register (not the storage nodes)
p0: 32, // C bit of status register (storage node)
p1: 627, // Z bit of status register (storage node)
p2: 1553, // I bit of status register (storage node)
p3: 348, // D bit of status register (storage node)
p4: 1119, // there is no bit4 in the status register! (not a storage node)
p5: -1, // there is no bit5 in the status register! (not a storage node)
p6: 77, // V bit of status register (storage node)
p7: 1370, // N bit of status register (storage node)
// internal bus: status register outputs for push P
Pout0: 687,
Pout1: 1444,
Pout2: 1421,
Pout3: 439,
Pout4: 1119, // there is no bit4 in the status register!
Pout5: -1, // there is no bit5 in the status register!
Pout6: 77,
Pout7: 1370,
s0: 1403, // machine state: stack pointer
s1: 183,
s2: 81,
@ -147,12 +159,28 @@ notir5: 1394,
notir6: 895,
notir7: 1320,
irline3: 996, // internal signal: PLA input - ir0 AND ir1
clock1: 1536, // internal state: timing control
clock2: 156, // internal state: timing control
clock1: 1536, // internal state: timing control aka #T0
clock2: 156, // internal state: timing control aka #T+
t2: 971, // internal state: timing control
t3: 1567,
t4: 690,
t5: 909,
noty0: 1025, // datapath state: not Y register
noty1: 1138,
noty2: 1484,
noty3: 184,
noty4: 565,
noty5: 981,
noty6: 1439,
noty7: 1640,
notx0: 987, // datapath state: not X register
notx1: 1434,
notx2: 890,
notx3: 1521,
notx4: 485,
notx5: 1017,
notx6: 730,
notx7: 1561,
nots0: 418, // datapath state: not stack pointer
nots1: 1064,
nots2: 752,
@ -185,7 +213,7 @@ sb4: 1405,
sb5: 166,
sb6: 1336,
sb7: 1001,
notalu0: 394, // datapath state: alu output storage node (inverse)
notalu0: 394, // datapath state: alu output storage node (inverse) aka #ADD0
notalu1: 697,
notalu2: 276,
notalu3: 495,
@ -193,7 +221,7 @@ notalu4: 1490,
notalu5: 893,
notalu6: 68,
notalu7: 1123,
alu0: 401, // datapath signal: ALU output
alu0: 401, // datapath signal: ALU output aka ADD0out
alu1: 872,
alu2: 1637,
alu3: 1414,
@ -210,7 +238,7 @@ dasb4: 1405, // same node as sb4
dasb5: 263,
dasb6: 679,
dasb7: 1494,
adl0: 413, // internal state: address latch low
adl0: 413, // internal bus: address low
adl1: 1282,
adl2: 1242,
adl3: 684,
@ -218,7 +246,7 @@ adl4: 1437,
adl5: 1630,
adl6: 121,
adl7: 1299,
adh0: 407, // internal state: address latch high
adh0: 407, // internal bus: address high
adh1: 52,
adh2: 1651,
adh3: 315,
@ -226,7 +254,7 @@ adh4: 1160,
adh5: 483,
adh6: 13,
adh7: 1539,
idb0: 1108, // internal state: data buffer
idb0: 1108, // internal bus: data bus
idb1: 991,
idb2: 1473,
idb3: 1302,
@ -250,33 +278,79 @@ dor4: 1088,
dor5: 1453,
dor6: 1415,
dor7: 63,
pd0: 1622, // internal state: predecode register output (anded with not ClearIR)
pd1: 809,
pd2: 1671,
pd3: 1587,
pd4: 540,
pd5: 667,
pd6: 1460,
pd7: 1410,
notpd0: 758, // internal state: predecode register (storage node)
notpd1: 361,
notpd2: 955,
notpd3: 894,
notpd4: 369,
notpd5: 829,
notpd6: 1669,
notpd7: 1690,
"pd0.clearIR": 1622, // internal state: predecode register output (anded with not ClearIR)
"pd1.clearIR": 809,
"pd2.clearIR": 1671,
"pd3.clearIR": 1587,
"pd4.clearIR": 540,
"pd5.clearIR": 667,
"pd6.clearIR": 1460,
"pd7.clearIR": 1410,
pd0: 758, // internal state: predecode register (storage node)
pd1: 361,
pd2: 955,
pd3: 894,
pd4: 369,
pd5: 829,
pd6: 1669,
pd7: 1690,
// internal signals: predecode latch partial decodes
"PD-xxxx10x0": 1019,
"PD-1xx000x0": 1294,
"PD-0xx0xx0x": 365,
"PD-xxx010x1": 302,
"PD-n-0xx0xx0x": 125,
"#TWOCYCLE": 851,
"#TWOCYCLE.phi1": 792,
"ONEBYTE": 778,
abl0: 1096, // internal bus: address bus low latched data out (inverse of inverted storage node)
abl1: 376,
abl2: 1502,
abl3: 1250,
abl4: 1232,
abl5: 234,
abl6: 178,
abl7: 178,
"#ABL0": 153, // internal state: address bus low latched data out (storage node, inverted)
"#ABL1": 107,
"#ABL2": 707,
"#ABL3": 825,
"#ABL4": 364,
"#ABL5": 1513,
"#ABL6": 1307,
"#ABL7": 28,
abh0: 1429, // internal bus: address bus high latched data out (inverse of inverted storage node)
abh1: 713,
abh2: 287,
abh3: 422,
abh4: 1143,
abh5: 775,
abh6: 997,
abh7: 489,
"#ABH0": 1062, // internal state: address bus high latched data out (storage node, inverted)
"#ABH1": 907,
"#ABH2": 768,
"#ABH3": 92,
"#ABH4": 668,
"#ABH5": 1128,
"#ABH6": 289,
"#ABH7": 429,
notRdy0: 248, // internal signal: global pipeline control
Reset0: 67, // internal signal: retimed reset from pin
C1x5Reset: 926, // retimed and pipelined reset in progress
notRnWprepad: 187, // internal signal: to pad, yet to be inverted and retimed
RnWstretched: 353, // internal signal: control datapad output drivers
RnWstretched: 353, // internal signal: control datapad output drivers, aka TRISTATE
"#DBE": 1035, // internal signal: formerly from DBE pad (6501)
cp1: 710, // internal signal: clock phase 1
cclk: 943, // unbonded pad: internal non-overlappying phi2
fetch: 879, // internal signal
clearIR: 1077, // internal signal
D1x1: 827, // internal signal: interrupt handler related
H1x1: 1042, // internal signal: drive status byte onto databus
"brk-done": 1382, // internal signal: interrupt handler related
INTG: 1350, // internal signal: interrupt handler related
// internal signal: pla outputs block 1 (west/left edge of die)
// often 130 pla outputs are mentioned - we have 131 here
@ -434,11 +508,36 @@ H1x1: 1042, // internal signal: drive status byte onto databus
"op-clv":1164, // pla129
"op-implied":1006, // pla130 // has extra pulldowns: pla121 and ir0
// internal signals: derived from pla outputs
"#op-branch-done": 1048,
"op-ANDS": 1228,
"op-EORS": 1689,
"op-ORS": 522,
"op-SUMS": 1196,
"op-SRS": 934,
"#op-store": 925,
"#WR": 1352,
"op-rmw": 434,
"short-circuit-idx-add": 1185,
"#op-set-C": 252,
// internal signals: control signals
nnT2BR: 967, // doubly inverted
BRtaken: 1544,
BRtaken: 1544, // aka #TAKEN
// interrupt and vector related
NMIP: 1032,
VEC0: 1465,
VEC1: 1481,
"#VEC": 1134,
// internal state: misc pipeline state clocked by cclk (phi2)
"pipe#VEC": 1431, // latched #VEC
"pipeT-SYNC": 537,
pipeT2out: 40,
pipeT3out: 706,
pipeT4out: 1373,
pipeT5out: 940,
pipeBRtaken: 832,
pipeUNK01: 1530,
pipeUNK02: 974,
@ -477,20 +576,23 @@ pipeUNK34: 56,
pipeUNK35: 1713,
pipeUNK36: 729,
pipeUNK37: 197,
pipeUNK38: 1131,
"pipe#WR.phi2": 1131,
pipeUNK39: 151,
pipeUNK40: 456,
pipeUNK41: 1438,
pipeUNK42: 1104,
pipeUNK43: 554,
"pipe#T0": 554, // aka #T0.phi2
// internal state: vector address pulldown control
pipeVectorA0: 357,
pipeVectorA1: 170,
pipeVectorA2: 45,
// internal signals: vector address pulldown control
"0/ADL0": 217,
"0/ADL1": 686,
"0/ADL2": 1193,
// internal state: datapath control drivers
pipedpc28: 683,
@ -512,17 +614,105 @@ alub5: 1678,
alub6: 235,
alub7: 1535,
aluanorb0: 143,
aluanandb0: 1628,
aluaorb0: 693,
notaluoutmux0: 957, // alu result latch input
// alu carry chain and decimal mode
C01: 1285,
C12: 505,
C23: 1023,
C34: 78,
C45: 142,
C56: 500,
C67: 1314,
C78: 808,
"C78.phi2": 560,
DC34: 1372, // lower nibble decimal carry
DC78: 333, // carry for decimal mode
"DC78.phi2": 164,
"#C01": 1506,
"#C12": 1122,
"#C23": 1003,
"#C34": 1425,
"#C45": 1571,
"#C56": 427,
"#C67": 592,
"#C78": 1327,
"DA-C01": 623,
"DA-AB2": 216,
"DA-AxB2": 516,
"DA-C45": 1144,
"#DA-ADD1": 901,
"#DA-ADD2": 699,
aluanorb1: 155,
aluanandb1: 841,
aluaorb1: 1021,
notaluoutmux1: 250, // alu result latch input
// misc alu internals
"#(AxBxC)0": 371,
"#(AxBxC)1": 965,
"#(AxBxC)2": 22,
"#(AxBxC)3": 274,
"#(AxBxC)4": 651,
"#(AxBxC)5": 486,
"#(AxBxC)6": 1197,
"#(AxBxC)7": 532,
AxB1: 425,
AxB3: 640,
AxB5: 1220,
AxB7: 1241,
"#(AxB)0": 1525,
"#(AxB)2": 701,
"#(AxB)4": 308,
"#(AxB)6": 1459,
"(AxB)0.#C0in": 555,
"(AxB)2.#C12": 193,
"(AxB)4.#C34": 65,
"(AxB)6.#C56": 174,
"#(AxB1).C01": 295,
"#(AxB3).C23": 860,
"#(AxB5).C45": 817,
"#(AxB7).C67": 1217,
"#A.B0": 1628,
"#A.B1": 841,
"#A.B2": 681,
"#A.B3": 350,
"#A.B4": 1063,
"#A.B5": 477,
"#A.B6": 336,
"#A.B7": 1318,
"A+B0": 693,
"A+B1": 1021,
"A+B2": 110,
"A+B3": 1313,
"A+B4": 918,
"A+B5": 1236,
"A+B6": 803,
"A+B7": 117,
"#(A+B)0": 143,
"#(A+B)1": 155,
"#(A+B)2": 1691,
"#(A+B)3": 649,
"#(A+B)4": 404,
"#(A+B)5": 1632,
"#(A+B)6": 1084,
"#(A+B)7": 1398,
"#(AxB)0": 1525,
"#(AxB)2": 701,
"#(AxB)4": 308,
"#(AxB)6": 1459,
"#(AxB)1": 953,
"#(AxB)3": 884,
"#(AxB)5": 1469,
"#(AxB)7": 177,
"#aluresult0": 957, // alu result latch input
"#aluresult1": 250,
"#aluresult2": 740,
"#aluresult3": 1071,
"#aluresult4": 296,
"#aluresult5": 277,
"#aluresult6": 722,
"#aluresult7": 304,
// internal signals: datapath control signals
"ADL/ABL": 639, // load ABL latches from ADL bus
"ADH/ABH": 821, // load ABH latches from ADH bus
dpc0_YSB: 801, // drive sb from y
dpc1_SBY: 325, // load y from sb
dpc2_XSB: 1263, // drive sb from x
@ -544,21 +734,27 @@ dpc16_EORS: 1666, // alu op: a xor b (?)
dpc17_SUMS: 921, // alu op: a plus b (?)
alucin: 910, // alu carry in
notalucin: 1165,
dpc18_DAA: 1201, // decimal related
"dpc18_#DAA": 1201, // decimal related (inverted)
dpc19_ADDSB7: 214, // alu to sb bit 7 only
dpc20_ADDSB06: 129, // alu to sb bits 6-0 only
dpc21_ADDADL: 1015, // alu to adl
alurawcout: 808, // alu raw carry out (no decimal adjust)
notalucout: 412, // alu carry out (inverted)
alucout: 1146, // alu carry out (latched by phi2)
notaluvout: 1308, // alu overflow out
aluvout: 938, // alu overflow out (latched by phi2)
dpc22_DSA: 725, // decimal related/SBC only
"#DBZ": 1268, // internal signal: not (databus is zero)
DBZ: 744, // internal signal: databus is zero
DBNeg: 1200, // internal signal: databus is negative (top bit of db) aka P-#DB7in
"dpc22_#DSA": 725, // decimal related/SBC only (inverted)
dpc23_SBAC: 534, // (optionalls decimal-adjusted) sb to acc
dpc24_ACSB: 1698, // acc to sb
dpc25_SBDB: 1060, // sb pass-connects to idb
dpc25_SBDB: 1060, // sb pass-connects to idb (bi-directionally)
dpc26_ACDB: 1331, // acc to idb
dpc27_SBADH: 140, // sb pass-connects to adh
dpc27_SBADH: 140, // sb pass-connects to adh (bi-directionally)
dpc28_0ADH0: 229, // zero to adh0 bit0 only
dpc29_0ADH17: 203, // zero to adh bits 7-1 only
@ -567,14 +763,23 @@ dpc31_PCHPCH: 741, // load pch from pch incremented
dpc32_PCHADH: 1235, // drive adh from pch incremented
dpc33_PCHDB: 247, // drive idb from pch incremented
dpc34_PCLC: 1704, // pch carry in and pcl FF detect?
dpc35: 1334, // pcl 0x?F detect - half-carry
dpc35_PCHC: 1334, // pcl 0x?F detect - half-carry
dpc36_IPC: 379, // pcl carry in
dpc37_PCLDB: 283, // drive idb from pcl incremented
dpc38_PCLADL: 438, // drive adl from pcl incremented
dpc39_PCLPCL: 898, // load pcl from pcl incremented
dpc40_ADLPCL: 414, // load pcl from adl
dpc41: 1564, // pass-connect adl to mux node driven by idl
dpc42: 41, // pass-connect adh to mux node driven by idl
dpc43: 863, // pass-connect idb to mux node driven by idl
"dpc41_DL/ADL": 1564,// pass-connect adl to mux node driven by idl
"dpc42_DL/ADH": 41, // pass-connect adh to mux node driven by idl
"dpc43_DL/DB": 863, // pass-connect idb to mux node driven by idl
}
/* many bus names taken from Donald F. Hanson's block diagram, found
* http://www.weihenstephan.org/~michaste/pagetable/6502/6502.jpg
* from his paper "A VHDL conversion tool for logic equations with embedded D latches"
* http://portal.acm.org/citation.cfm?id=1275143.1275151
* also available at
* http://www.ncsu.edu/wcae/WCAE1/hanson.pdf
*/

View File

@ -8,8 +8,29 @@
//
testprogramAddress=0x0000;
// we want to auto-clear the console if any output is sent by the program
var consoleboxStream="";
// demonstrate write hook
writeTriggers[0x000F]="consoleboxStream += String.fromCharCode(d);"+
"consolebox.innerHTML = consoleboxStream;";
// demonstrate read hook (not used by this test program)
readTriggers[0xD011]="((consolegetc==undefined)?0:0xff)"; // return zero until we have a char
readTriggers[0xD010]="var c=consolegetc; consolegetc=undefined; (c)";
testprogram = [
0xa9, 0x00, 0x20, 0x10, 0x00, 0x4c, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe8, 0x88, 0xe6, 0x40, 0x38, 0x69, 0x02, 0x60
0xa9, 0x00, // LDA #$00
0x20, 0x10, 0x00, // JSR $0010
0x4c, 0x02, 0x00, // JMP $0002
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40,
0xe8, // INX
0x88, // DEY
0xe6, 0x0F, // INC $0F
0x38, // SEC
0x69, 0x02, // ADC #$02
0x60 // RTS
];

File diff suppressed because it is too large Load Diff

View File

@ -50,9 +50,10 @@ function setupTransistors(){
var gate = tdef[1];
var c1 = tdef[2];
var c2 = tdef[3];
var bb = tdef[4];
if(c1==ngnd) {c1=c2;c2=ngnd;}
if(c1==npwr) {c1=c2;c2=npwr;}
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2};
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2, bb: bb};
nodes[gate].gates.push(trans);
nodes[c1].c1c2s.push(trans);
nodes[c2].c1c2s.push(trans);
@ -149,20 +150,63 @@ function overlayNode(w){
}
}
// originally to highlight using a list of node numbers
// but can now include transistor names
function hiliteNode(n){
var ctx = hilite.getContext('2d');
ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
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){
if(typeof n[i] != "number") {
hiliteTrans([n[i]]);
continue;
}
if(isNodeHigh(n[i])) {
ctx.fillStyle = 'rgba(255,0,0,0.7)';
} else {
ctx.fillStyle = 'rgba(255,255,255,0.7)';
}
var segs = nodes[n[i]].segs;
for(var s in segs){drawSeg(ctx, segs[s]); ctx.fill();}
}
}
// highlight a single transistor (additively - does not clear highlighting)
function hiliteTrans(n){
var ctx = hilite.getContext('2d');
ctx.strokeStyle = 'rgba(255,255,255,0.7)';
ctx.lineWidth = 4
for(var t in n){
var bb = transistors[n[t]].bb
var segs = [[bb[0], bb[2], bb[1], bb[2], bb[1], bb[3], bb[0], bb[3]]]
for(var s in segs){drawSeg(ctx, segs[s]); ctx.stroke();}
}
}
function ctxDrawBox(ctx, xMin, yMin, xMax, yMax){
var cap=ctx.lineCap;
ctx.lineCap="square";
ctx.beginPath();
ctx.moveTo(xMin, yMin);
ctx.lineTo(xMin, yMax);
ctx.lineTo(xMax, yMax);
ctx.lineTo(xMax, yMin);
ctx.lineTo(xMin, yMin);
ctx.stroke();
ctx.lineCap=cap;
}
// takes a bounding box in chip coords and centres the display over it
function zoomToBox(xmin,xmax,ymin,ymax){
var xmid=(xmin+xmax)/2;
var ymid=(ymin+ymax)/2;
var x=(xmid+400)/grChipSize*600;
var y=600-ymid/grChipSize*600;
var zoom=5; // pending a more careful calculation
moveHere([x,y,zoom]);
}
function drawSeg(ctx, seg){
var dx = 400;
ctx.beginPath();