mirror of
https://github.com/trebonian/visual6502.git
synced 2024-12-26 07:29:23 +00:00
First cut refactor into expert and kiosk
This commit is contained in:
parent
dc0fb1ef06
commit
cede111a0f
103
expert.html
Normal file
103
expert.html
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Visual 6502 in JavaScript</title>
|
||||||
|
<style type="text/css">@import "expert.css";</style>
|
||||||
|
<script src="segdefs.js"></script>
|
||||||
|
<script src="transdefs.js"></script>
|
||||||
|
<script src="nodenames.js"></script>
|
||||||
|
<script src="wires.js"></script>
|
||||||
|
<script src="expertWires.js"></script>
|
||||||
|
<script src="chipsim.js"></script>
|
||||||
|
<script src="memtable.js"></script>
|
||||||
|
<script src="macros.js"></script>
|
||||||
|
<script src="testprogram.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function handleOnload() {
|
||||||
|
/MSIE (\d+\.\d+);/.test(navigator.appVersion);
|
||||||
|
IEVersion=Number(RegExp.$1);
|
||||||
|
if((navigator.appName == 'Microsoft Internet Explorer') && (IEVersion<9)){
|
||||||
|
document.getElementById('browsertrouble').innerHTML=
|
||||||
|
'<p>Sorry, '+navigator.appName+' not supported - showing you a picture instead!</p>';
|
||||||
|
document.getElementById('frame').innerHTML='<a href="browsertrouble.html"><img src="images/jssim2.png" style="border:10px"></a>';
|
||||||
|
}else{
|
||||||
|
setTimeout(setup,200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="handleOnload();">
|
||||||
|
<span id="plain">
|
||||||
|
<a href="http://www.visual6502.org/faq.html">FAQ</a>
|
||||||
|
<a href="http://blog.visual6502.org">Blog</a>
|
||||||
|
<a href="http://www.visual6502.org/links.html">Links</a> 
|
||||||
|
</span>
|
||||||
|
<div class="frame" id="frame">
|
||||||
|
<div class="leftcolumn">
|
||||||
|
<div id="chipsurround">
|
||||||
|
<div class="chip" id="chip">
|
||||||
|
<span id="waiting">Please wait, graphics initialising...</span>
|
||||||
|
<canvas class="chip" id="chipbg"></canvas>
|
||||||
|
<canvas class="chip" id="overlay"></canvas>
|
||||||
|
<canvas class="chip" id="hilite"></canvas>
|
||||||
|
<canvas class="chip" id="hitbuffer"></canvas>
|
||||||
|
</div>
|
||||||
|
</div> <!-- chipsurround -->
|
||||||
|
<div class="nochip" id="nochip">
|
||||||
|
<form>
|
||||||
|
<input type="button" value="Show chip layout" onclick="updateChipLayoutVisibility(true)" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="layoutControlPanel">
|
||||||
|
<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)
|
||||||
|
<input type="checkbox" name="4" id="updateShow4" onchange="updateShow(this.name,this.checked)" />(powered diffusion)
|
||||||
|
<input type="checkbox" name="5" id="updateShow5" onchange="updateShow(this.name,this.checked)" />(polysilicon)
|
||||||
|
<input type="checkbox" name="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>
|
||||||
|
<input type="button" value="Hide Chip Layout" onclick="updateChipLayoutVisibility(false)" />
|
||||||
|
<input type="button" value="Clear Highlighting" onclick="clearHighlight()" />
|
||||||
|
<span class="animatebox">
|
||||||
|
Animate during simulation:
|
||||||
|
<input type="checkbox" id="animateModeCheckbox" onchange="updateChipLayoutAnimation(this.checked)"
|
||||||
|
/></span>
|
||||||
|
|
||||||
|
<a href="" id="linkHere" >Link to this location</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="expertControlPanel">
|
||||||
|
<form>
|
||||||
|
<input type="button" value="Trace more" onclick="updateLoglevel(++loglevel)" />
|
||||||
|
<input type="button" value="Trace less" onclick="updateLoglevel(--loglevel)" />
|
||||||
|
</form>
|
||||||
|
<br />
|
||||||
|
<div id="logstreamscroller">
|
||||||
|
<table class="logstream" id="logstream"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> <!-- closing leftcolumn -->
|
||||||
|
<div class="rightcolumn">
|
||||||
|
<div class = "buttons">
|
||||||
|
<div class="twobuttons">
|
||||||
|
<a href ="javascript:stopChip()" id="stop"><img class="navstop" src="images/stop.png" title="stop"></a>
|
||||||
|
<a href ="javascript:runChip()" id="start"><img class="navplay" src="images/play.png" title="run"></a>
|
||||||
|
</div>
|
||||||
|
<div class="threebuttons">
|
||||||
|
<a href ="javascript:resetChip()"><img class="navbutton" src="images/up.png" title="reset"></a>
|
||||||
|
<a href ="javascript:stepBack()"><img class="navbutton" src="images/prev.png" title="back"></a>
|
||||||
|
<a href ="javascript:stepForward()"><img class="navbutton" src="images/next.png" title="step"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status" id="status"><p>x: 0<br>y: 0</p>
|
||||||
|
</div>
|
||||||
|
<table class="memtable" id="memtable"></table>
|
||||||
|
</div> <!-- closing rightcolumn -->
|
||||||
|
</div> <!-- closing 'frame' div -->
|
||||||
|
</body>
|
||||||
|
</html>
|
341
expertWires.js
Normal file
341
expertWires.js
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var centerx=300, centery=300;
|
||||||
|
var zoom=1;
|
||||||
|
var dragMouseX, dragMouseY, moved;
|
||||||
|
var statbox;
|
||||||
|
|
||||||
|
// Some constants for the graphics presentation
|
||||||
|
// the canvas is embedded in an 800x600 clipping div
|
||||||
|
// which gives rise to some of the 300 and 400 values in the code
|
||||||
|
// there are also some 600 values
|
||||||
|
// the 6502D chip coords are in the box (216,179) to (8983,9807)
|
||||||
|
// we have 4 canvases all the same size, now 2000 pixels square
|
||||||
|
// chip background - the layout
|
||||||
|
// overlay - a red/white transparency to show logic high or low
|
||||||
|
// hilite - to show the selected polygon
|
||||||
|
// hitbuffer - abusing color values to return which polygon is under a point
|
||||||
|
// we no longer use a scaling transform - we now scale the chip data at
|
||||||
|
// the point of drawing line segments
|
||||||
|
// if the canvas is any smaller than chip coordinates there will be
|
||||||
|
// rounding artifacts, and at high zoom there will be anti-aliasing on edges.
|
||||||
|
var grMaxZoom=12;
|
||||||
|
var grChipSize=10000;
|
||||||
|
var grCanvasSize=2000;
|
||||||
|
var grLineWidth=1;
|
||||||
|
|
||||||
|
// Index of layerNames corresponds to index into drawLayers
|
||||||
|
var layernames = ['metal', 'switched diffusion', 'inputdiode', 'grounded diffusion', 'powered diffusion', 'polysilicon'];
|
||||||
|
var colors = ['rgba(128,128,192,0.4)','#FFFF00','#FF00FF','#4DFF4D',
|
||||||
|
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
|
||||||
|
var drawlayers = [true, true, true, true, true, true];
|
||||||
|
|
||||||
|
// some modes and parameters which can be passed in from the URL query
|
||||||
|
var moveHereFirst;
|
||||||
|
var expertMode=false
|
||||||
|
var animateChipLayout = true;
|
||||||
|
var chipLayoutIsVisible = true;
|
||||||
|
var userCode=[];
|
||||||
|
var userResetLow;
|
||||||
|
var userResetHigh;
|
||||||
|
var userSteps;
|
||||||
|
var testprogram=[];
|
||||||
|
var testprogramAddress;
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
//
|
||||||
|
// Drawing Setup
|
||||||
|
//
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
// try to present a meaningful page before starting expensive work
|
||||||
|
function setup(){
|
||||||
|
statbox = document.getElementById('status');
|
||||||
|
setStatus('loading 6502...');
|
||||||
|
setTimeout(setup_part2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_part2(){
|
||||||
|
frame = document.getElementById('frame');
|
||||||
|
statbox = document.getElementById('status');
|
||||||
|
setupParams();
|
||||||
|
updateExpertMode(expertMode);
|
||||||
|
setupNodes();
|
||||||
|
setupTransistors();
|
||||||
|
if(chipLayoutIsVisible){
|
||||||
|
// if user requests no chip layout, we can do no canvas operations at all
|
||||||
|
// which saves a lot of memory and allows us to run on small systems
|
||||||
|
updateChipLayoutVisibility(true);
|
||||||
|
}
|
||||||
|
window.onkeypress = function(e){handleKey(e);}
|
||||||
|
setStatus('resetting 6502...');
|
||||||
|
setTimeout(setup_part3, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_part3(){
|
||||||
|
setupTable();
|
||||||
|
setupNodeNameList();
|
||||||
|
loadProgram();
|
||||||
|
initChip();
|
||||||
|
document.getElementById('stop').style.visibility = 'hidden';
|
||||||
|
go();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupParams(){
|
||||||
|
if(location.search=="")
|
||||||
|
return
|
||||||
|
var queryParts=location.search.slice(1).split('&');
|
||||||
|
var panx;
|
||||||
|
var pany;
|
||||||
|
var zoom;
|
||||||
|
var userAddress;
|
||||||
|
for(var i=0;i<queryParts.length;i++){
|
||||||
|
var params=queryParts[i].split("=");
|
||||||
|
if(params.length!=2){
|
||||||
|
if(loglevel>0)
|
||||||
|
console.log('malformed parameters',params);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var name=params[0];
|
||||||
|
var value=params[1].replace(/\/$/,""); // chrome sometimes adds trailing slash
|
||||||
|
// be (relatively) forgiving in what we accept
|
||||||
|
//
|
||||||
|
// user interface mode control
|
||||||
|
if(name=="loglevel" && parseInt(value)!=NaN){
|
||||||
|
updateLoglevel(value);
|
||||||
|
} else if(name=="expert" && value.indexOf("t")==0){
|
||||||
|
updateExpertMode(true);
|
||||||
|
} else if(name=="graphics" && value.indexOf("f")==0){
|
||||||
|
updateChipLayoutVisibility(false);
|
||||||
|
} else
|
||||||
|
// place the graphics window at a point of interest
|
||||||
|
if(name=="panx" && parseInt(value)!=NaN){
|
||||||
|
panx=parseInt(value);
|
||||||
|
} else if(name=="pany" && parseInt(value)!=NaN){
|
||||||
|
pany=parseInt(value);
|
||||||
|
} else if(name=="zoom" && parseInt(value)!=NaN){
|
||||||
|
zoom=parseInt(value);
|
||||||
|
} else
|
||||||
|
// load a test program: Address, Data and Reset
|
||||||
|
if(name=="a" && parseInt(value,16)!=NaN){
|
||||||
|
userAddress=parseInt(value,16);
|
||||||
|
} else if(name=="d" && value.match(/[0-9a-fA-F]*/)[0].length==value.length){
|
||||||
|
for(var j=0;j<value.length;j+=2)
|
||||||
|
userCode[userAddress++]=parseInt(value.slice(j,j+2),16);
|
||||||
|
} else if(name=="r" && parseInt(value,16)!=NaN){
|
||||||
|
userResetLow=parseInt(value,16)%256;
|
||||||
|
userResetHigh=(parseInt(value,16)>>8)%256;
|
||||||
|
} else
|
||||||
|
// run a test program, and optionally check against a golden checksum
|
||||||
|
if(name=="steps" && parseInt(value)!=NaN){
|
||||||
|
userSteps=parseInt(value);
|
||||||
|
running=true;
|
||||||
|
} else if(name=="checksum" && parseInt(value,16)!=NaN){
|
||||||
|
goldenChecksum=(0x100000000+parseInt(value,16)).toString(16).slice(-8);
|
||||||
|
} else {
|
||||||
|
if(loglevel>0)
|
||||||
|
console.log('unrecognised parameters:',params);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(panx!=null && pany!=null && zoom!=null)
|
||||||
|
moveHereFirst=[panx,pany,zoom];
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateChipLayoutAnimation(isOn){
|
||||||
|
// simulation is much faster if we don't update the chip layout on every step
|
||||||
|
animateChipLayout=isOn;
|
||||||
|
document.getElementById('animateModeCheckbox').checked = animateChipLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
//
|
||||||
|
// User Interface
|
||||||
|
//
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
function handleKey(e){
|
||||||
|
var c = e.charCode;
|
||||||
|
c = String.fromCharCode(c);
|
||||||
|
if('<>?npZzx'.indexOf(c)==-1) return;
|
||||||
|
if((c=='Z'||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();
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseDown(e){
|
||||||
|
e.preventDefault();
|
||||||
|
moved=false;
|
||||||
|
dragMouseX = e.clientX;
|
||||||
|
dragMouseY = e.clientY;
|
||||||
|
window.onmousemove = function(e){mouseMove(e)};
|
||||||
|
window.onmouseup = function(e){mouseUp(e)};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseMove(e){
|
||||||
|
moved = true;
|
||||||
|
if(zoom==1) return;
|
||||||
|
var dx = e.clientX-dragMouseX;
|
||||||
|
var dy = e.clientY-dragMouseY;
|
||||||
|
dragMouseX = e.clientX;
|
||||||
|
dragMouseY = e.clientY;
|
||||||
|
centerx-=dx/zoom;
|
||||||
|
centerx = Math.max(centerx, 400/zoom);
|
||||||
|
centerx = Math.min(centerx, 600-400/zoom);
|
||||||
|
centery-=dy/zoom;
|
||||||
|
centery = Math.max(centery, 300/zoom);
|
||||||
|
centery = Math.min(centery, 600-300/zoom);
|
||||||
|
recenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseUp(e){
|
||||||
|
if(!moved) handleClick(e);
|
||||||
|
window.onmousemove = undefined;
|
||||||
|
window.onmouseup = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setZoom(n){
|
||||||
|
zoom = n;
|
||||||
|
setChipStyle({
|
||||||
|
width: 600*n+'px',
|
||||||
|
height: 600*n+'px'
|
||||||
|
});
|
||||||
|
recenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
function recenter(){
|
||||||
|
var top = -centery*zoom+300;
|
||||||
|
top = Math.min(top, 0);
|
||||||
|
top = Math.max(top, -600*(zoom-1));
|
||||||
|
var left = -centerx*zoom+400;
|
||||||
|
left = Math.min(left, 0);
|
||||||
|
left = Math.max(left, (zoom==1)?100:-600*zoom+800);
|
||||||
|
setChipStyle({
|
||||||
|
top: top+'px',
|
||||||
|
left: left+'px',
|
||||||
|
});
|
||||||
|
document.getElementById('linkHere').href=location.pathname+"?"+whereAmIAsQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick(e){
|
||||||
|
var x = localx(hilite, e.clientX)/zoom;
|
||||||
|
var y = localy(hilite, e.clientY)/zoom;
|
||||||
|
var w = findNodeNumber(x,y);
|
||||||
|
if(e.shiftKey) hiliteNode(getNodeGroup(w));
|
||||||
|
else {var a=new Array(); a.push(w); hiliteNode(a);}
|
||||||
|
var cx = Math.round(x*grChipSize/600);
|
||||||
|
var cy = Math.round(y*grChipSize/600);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLoglevel(value){
|
||||||
|
loglevel = value;
|
||||||
|
initLogbox(signalSet(loglevel));
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateExpertMode(isOn){
|
||||||
|
expertMode=true
|
||||||
|
document.getElementById('expertControlPanel').style.display = 'block';
|
||||||
|
if(loglevel==0)
|
||||||
|
updateLoglevel(1);
|
||||||
|
if(chipLayoutIsVisible)
|
||||||
|
document.getElementById('layoutControlPanel').style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateChipLayoutVisibility(isOn){
|
||||||
|
chipLayoutIsVisible=isOn;
|
||||||
|
if(chipLayoutIsVisible) {
|
||||||
|
document.getElementById('chipsurround').style.display = 'block';
|
||||||
|
if(expertMode)
|
||||||
|
document.getElementById('layoutControlPanel').style.display = 'block';
|
||||||
|
document.getElementById('nochip').style.display = 'none';
|
||||||
|
document.getElementById('logstreamscroller').style.height="260px";
|
||||||
|
// allow the display to update while we load the graphics
|
||||||
|
setStatus('loading graphics...');
|
||||||
|
setTimeout(setupChipLayoutGraphics, 0);
|
||||||
|
} else {
|
||||||
|
// cannot animate the layout if there is no canvas
|
||||||
|
updateChipLayoutAnimation(false);
|
||||||
|
// replace the layout display with a button to show it
|
||||||
|
document.getElementById('chipsurround').style.display = 'none';
|
||||||
|
document.getElementById('layoutControlPanel').style.display = 'none';
|
||||||
|
document.getElementById('nochip').style.display = 'block';
|
||||||
|
document.getElementById('logstreamscroller').style.height="880px";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupChipLayoutGraphics(){
|
||||||
|
setupLayerVisibility();
|
||||||
|
setupBackground();
|
||||||
|
setupOverlay();
|
||||||
|
setupHilite();
|
||||||
|
setupHitBuffer();
|
||||||
|
recenter();
|
||||||
|
refresh();
|
||||||
|
document.getElementById('waiting').style.display = 'none';
|
||||||
|
setStatus('Ready!'); // would prefer chipStatus but it's not idempotent
|
||||||
|
if(moveHereFirst!=null)
|
||||||
|
moveHere(moveHereFirst);
|
||||||
|
hilite.onmousedown = function(e){mouseDown(e);}
|
||||||
|
}
|
||||||
|
|
||||||
|
// utility function to save graphics pan and zoom
|
||||||
|
function whereAmIAsQuery(){
|
||||||
|
var w=whereAmI();
|
||||||
|
return "panx="+w[0]+"&pany="+w[1]+"&zoom="+w[2]
|
||||||
|
}
|
||||||
|
function whereAmI(){
|
||||||
|
return [centerx, centery, zoom];
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore graphics pan and zoom (perhaps as given in the URL)
|
||||||
|
function moveHere(place){
|
||||||
|
centerx = place[0];
|
||||||
|
centery = place[1];
|
||||||
|
setZoom(place[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
//
|
||||||
|
// Etc.
|
||||||
|
//
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
function setChipStyle(props){
|
||||||
|
for(var i in props){
|
||||||
|
chipbg.style[i] = props[i];
|
||||||
|
overlay.style[i] = props[i];
|
||||||
|
hilite.style[i] = props[i];
|
||||||
|
hitbuffer.style[i] = props[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
47
index.html
47
index.html
@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Visual 6502 in JavaScript</title>
|
<title>Visual 6502 in JavaScript</title>
|
||||||
<style type="text/css">@import "wires.css";</style>
|
<style type="text/css">@import "expert.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="expertWires.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>
|
||||||
@ -29,30 +30,10 @@ function handleOnload() {
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onload="handleOnload();">
|
<body onload="handleOnload();">
|
||||||
<div id="basicModeText1">
|
|
||||||
<br />
|
|
||||||
<span id="title"><a href="http://visual6502.org">The Visual 6502</a></span>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
<span id="plain">
|
<span id="plain">
|
||||||
<a href="http://www.visual6502.org/faq.html">FAQ</a>
|
<a href="http://www.visual6502.org/faq.html">FAQ</a>
|
||||||
<a href="http://blog.visual6502.org">Blog</a>
|
<a href="http://blog.visual6502.org">Blog</a>
|
||||||
<a href="http://www.visual6502.org/links.html">Links</a> 
|
<a href="http://www.visual6502.org/links.html">Links</a> 
|
||||||
<div id="basicModeText2">
|
|
||||||
<br /><br />
|
|
||||||
This simulator uses HTML5 features only found on the latest versions of browsers and needs
|
|
||||||
lots of RAM. If you have trouble, please <a href="browsertrouble.html">check compatibility.</a>
|
|
||||||
<br />
|
|
||||||
<span id="browsertrouble"></span>
|
|
||||||
<br />
|
|
||||||
Hit '>' to zoom in, '<' to zoom out
|
|
||||||
<br />
|
|
||||||
Left-click and drag to scroll around
|
|
||||||
<br />
|
|
||||||
Enter your own program into the array of RAM
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
</span>
|
</span>
|
||||||
<div class="frame" id="frame">
|
<div class="frame" id="frame">
|
||||||
<div class="leftcolumn">
|
<div class="leftcolumn">
|
||||||
@ -111,36 +92,12 @@ Enter your own program into the array of RAM
|
|||||||
<a href ="javascript:resetChip()"><img class="navbutton" src="images/up.png" title="reset"></a>
|
<a href ="javascript:resetChip()"><img class="navbutton" src="images/up.png" title="reset"></a>
|
||||||
<a href ="javascript:stepBack()"><img class="navbutton" src="images/prev.png" title="back"></a>
|
<a href ="javascript:stepBack()"><img class="navbutton" src="images/prev.png" title="back"></a>
|
||||||
<a href ="javascript:stepForward()"><img class="navbutton" src="images/next.png" title="step"></a>
|
<a href ="javascript:stepForward()"><img class="navbutton" src="images/next.png" title="step"></a>
|
||||||
<span class="expertcheckbox">Expert:
|
|
||||||
<input type="checkbox" id="expertModeCheckbox" name="0" onchange="updateExpertMode(this.checked)" />
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="status" id="status"><p>x: 0<br>y: 0</p>
|
<div class="status" id="status"><p>x: 0<br>y: 0</p>
|
||||||
</div>
|
</div>
|
||||||
<table class="memtable" id="memtable"></table>
|
<table class="memtable" id="memtable"></table>
|
||||||
</div> <!-- closing rightcolumn -->
|
</div> <!-- closing rightcolumn -->
|
||||||
<div class="footer">
|
|
||||||
Source code is available on <a href="http://github.com/trebonian/visual6502">github visual6502</a>.
|
|
||||||
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 />
|
|
||||||
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 />
|
|
||||||
</div> <!-- footer -->
|
|
||||||
</div> <!-- closing 'frame' div -->
|
</div> <!-- closing 'frame' div -->
|
||||||
|
|
||||||
<script type="text/javascript"><!--
|
|
||||||
google_ad_client = "pub-9008420149077488";
|
|
||||||
/* 728x90, created 9/22/10 */
|
|
||||||
google_ad_slot = "4303982675";
|
|
||||||
google_ad_width = 728;
|
|
||||||
google_ad_height = 90;
|
|
||||||
//-->
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript"
|
|
||||||
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
94
kiosk.css
Normal file
94
kiosk.css
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: white;
|
||||||
|
color: black;
|
||||||
|
/* font-family: cursive;*/
|
||||||
|
font-family :Verdana, Arial, Helvetica, Sans-Serif;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.frame {
|
||||||
|
margin-left: 10px;
|
||||||
|
position: relative;
|
||||||
|
width: 1150px;
|
||||||
|
height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.chip {
|
||||||
|
background: lightgray;
|
||||||
|
border: 2px solid gray;
|
||||||
|
position: absolute;
|
||||||
|
width: 800px;
|
||||||
|
height: 600px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.chip {
|
||||||
|
position: absolute;
|
||||||
|
width: 600px;
|
||||||
|
height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.buttons{
|
||||||
|
position: absolute;
|
||||||
|
top: -5px;
|
||||||
|
left: 820px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.status {
|
||||||
|
position: absolute;
|
||||||
|
left: 820px;
|
||||||
|
top: 20px;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.navbutton{
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.navplay{
|
||||||
|
position: relative;
|
||||||
|
margin-right: 5px;
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.navstop{
|
||||||
|
position: absolute;
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.memtable {
|
||||||
|
position: absolute;
|
||||||
|
top: 78px;
|
||||||
|
left: 820px;
|
||||||
|
font-family: monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
border-spacing: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
font-size:30px;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
100
kiosk.html
Normal file
100
kiosk.html
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Visual 6502 in JavaScript</title>
|
||||||
|
<style type="text/css">@import "kiosk.css";</style>
|
||||||
|
<script src="segdefs.js"></script>
|
||||||
|
<script src="transdefs.js"></script>
|
||||||
|
<script src="nodenames.js"></script>
|
||||||
|
<script src="kioskWires.js"></script>
|
||||||
|
<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 type="text/javascript">
|
||||||
|
function handleOnload() {
|
||||||
|
/MSIE (\d+\.\d+);/.test(navigator.appVersion);
|
||||||
|
IEVersion=Number(RegExp.$1);
|
||||||
|
if((navigator.appName == 'Microsoft Internet Explorer') && (IEVersion<9)){
|
||||||
|
document.getElementById('browsertrouble').innerHTML=
|
||||||
|
'<p>Sorry, '+navigator.appName+' not supported - showing you a picture instead!</p>';
|
||||||
|
document.getElementById('frame').innerHTML='<a href="browsertrouble.html"><img src="images/jssim2.png" style="border:10px"></a>';
|
||||||
|
}else{
|
||||||
|
setTimeout(setup,200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body onload="handleOnload();">
|
||||||
|
<br />
|
||||||
|
<span id="title"><a href="http://visual6502.org">The Visual 6502</a></span>
|
||||||
|
<span id="plain">
|
||||||
|
<br />
|
||||||
|
<a href="http://www.visual6502.org/faq.html">FAQ</a>
|
||||||
|
<a href="http://blog.visual6502.org">Blog</a>
|
||||||
|
<a href="http://www.visual6502.org/links.html">Links</a> 
|
||||||
|
<br /><br />
|
||||||
|
This simulator uses HTML5 features only found on the latest versions of browsers and needs
|
||||||
|
lots of RAM. If you have trouble, please <a href="browsertrouble.html">check compatibility.</a>
|
||||||
|
<br />
|
||||||
|
<span id="browsertrouble"></span>
|
||||||
|
<br />
|
||||||
|
Hit '>' to zoom in, '<' to zoom out
|
||||||
|
<br />
|
||||||
|
Left-click and drag to scroll around
|
||||||
|
<br />
|
||||||
|
Enter your own program into the array of RAM
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
</span>
|
||||||
|
<div class="frame" id="frame">
|
||||||
|
<div class="chip" id="chip">
|
||||||
|
<canvas class="chip" id="chipbg"></canvas>
|
||||||
|
<canvas class="chip" id="overlay"></canvas>
|
||||||
|
<canvas class="chip" id="hilite"></canvas>
|
||||||
|
<canvas class="chip" id="hitbuffer"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class = "buttons">
|
||||||
|
<div style="position:relative; float:left;">
|
||||||
|
<a href ="javascript:stopChip()"id="stop"><img class="navstop" src="images/stop.png"></a>
|
||||||
|
<a href ="javascript:runChip()" id="start"><img class="navplay" src="images/play.png"></a>
|
||||||
|
</div>
|
||||||
|
<div style="float:left;">
|
||||||
|
<a href ="javascript:resetChip()"><img class="navbutton" src="images/up.png"></a>
|
||||||
|
<a href ="javascript:stepBack()"><img class="navbutton" src="images/prev.png"></a>
|
||||||
|
<a href ="javascript:stepForward()"><img class="navbutton" src="images/next.png"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="status" id="status">x: 0<br>y: 0</p>
|
||||||
|
<table class="memtable" id="memtable"></table>
|
||||||
|
</div>
|
||||||
|
<div id="updateShow">
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
Source code is available on <a href="http://github.com/trebonian/visual6502">github visual6502</a>.
|
||||||
|
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="/expert/JSSim/index.html">Experimenter's (Beta) version</a>.
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<script type="text/javascript"><!--
|
||||||
|
google_ad_client = "pub-9008420149077488";
|
||||||
|
/* 728x90, created 9/22/10 */
|
||||||
|
google_ad_slot = "4303982675";
|
||||||
|
google_ad_width = 728;
|
||||||
|
google_ad_height = 90;
|
||||||
|
//-->
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript"
|
||||||
|
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
198
kioskWires.js
Normal file
198
kioskWires.js
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var centerx=300, centery=300;
|
||||||
|
var zoom=1;
|
||||||
|
var dragMouseX, dragMouseY, moved;
|
||||||
|
var statbox;
|
||||||
|
var userSteps;
|
||||||
|
var animateChipLayout = true;
|
||||||
|
var userCode=[];
|
||||||
|
var userResetLow;
|
||||||
|
var userResetHigh;
|
||||||
|
|
||||||
|
// Some constants for the graphics presentation
|
||||||
|
// the canvas is embedded in an 800x600 clipping div
|
||||||
|
// which gives rise to some of the 300 and 400 values in the code
|
||||||
|
// there are also some 600 values
|
||||||
|
// the 6502D chip coords are in the box (216,179) to (8983,9807)
|
||||||
|
// we have 4 canvases all the same size, now 2000 pixels square
|
||||||
|
// chip background - the layout
|
||||||
|
// overlay - a red/white transparency to show logic high or low
|
||||||
|
// hilite - to show the selected polygon
|
||||||
|
// hitbuffer - abusing color values to return which polygon is under a point
|
||||||
|
// we no longer use a scaling transform - we now scale the chip data at
|
||||||
|
// the point of drawing line segments
|
||||||
|
// if the canvas is any smaller than chip coordinates there will be
|
||||||
|
// rounding artifacts, and at high zoom there will be anti-aliasing on edges.
|
||||||
|
var grMaxZoom=12;
|
||||||
|
var grChipSize=10000;
|
||||||
|
var grCanvasSize=2000;
|
||||||
|
var grLineWidth=1;
|
||||||
|
|
||||||
|
// Index of layerNames corresponds to index into drawLayers
|
||||||
|
var layernames = ['metal', 'switched diffusion', 'inputdiode', 'grounded diffusion', 'powered diffusion', 'polysilicon'];
|
||||||
|
var colors = ['rgba(128,128,192,0.4)','#FFFF00','#FF00FF','#4DFF4D',
|
||||||
|
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
|
||||||
|
var drawlayers = [true, true, true, true, true, true];
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
//
|
||||||
|
// Drawing Setup
|
||||||
|
//
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
// try to present a meaningful page before starting expensive work
|
||||||
|
function setup(){
|
||||||
|
statbox = document.getElementById('status');
|
||||||
|
setStatus('loading 6502...');
|
||||||
|
setTimeout(setup_part2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_part2(){
|
||||||
|
frame = document.getElementById('frame');
|
||||||
|
statbox = document.getElementById('status');
|
||||||
|
setupNodes();
|
||||||
|
setupTransistors();
|
||||||
|
setupLayerVisibility();
|
||||||
|
setupBackground();
|
||||||
|
setupOverlay();
|
||||||
|
setupHilite();
|
||||||
|
setupHitBuffer();
|
||||||
|
recenter();
|
||||||
|
refresh();
|
||||||
|
setupTable();
|
||||||
|
window.onkeypress = function(e){handleKey(e);}
|
||||||
|
hilite.onmousedown = function(e){mouseDown(e);}
|
||||||
|
setStatus('resetting 6502...');
|
||||||
|
setTimeout(setup_part3, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_part3(){
|
||||||
|
loadProgram();
|
||||||
|
initChip();
|
||||||
|
document.getElementById('stop').style.visibility = 'hidden';
|
||||||
|
go();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
//
|
||||||
|
// User Interface
|
||||||
|
//
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
function handleKey(e){
|
||||||
|
var c = e.charCode;
|
||||||
|
c = String.fromCharCode(c);
|
||||||
|
if('<>?np'.indexOf(c)==-1) return;
|
||||||
|
if(c=='<' && zoom>1) setZoom(zoom/1.2);
|
||||||
|
else if(c=='>' && zoom<grMaxZoom) setZoom(zoom*1.2);
|
||||||
|
else if(c=='?') setZoom(1);
|
||||||
|
else if(c=='n') stepForward();
|
||||||
|
else if(c=='p') stepBack();
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseDown(e){
|
||||||
|
e.preventDefault();
|
||||||
|
moved=false;
|
||||||
|
dragMouseX = e.clientX;
|
||||||
|
dragMouseY = e.clientY;
|
||||||
|
window.onmousemove = function(e){mouseMove(e)};
|
||||||
|
window.onmouseup = function(e){mouseUp(e)};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseMove(e){
|
||||||
|
moved = true;
|
||||||
|
if(zoom==1) return;
|
||||||
|
var dx = e.clientX-dragMouseX;
|
||||||
|
var dy = e.clientY-dragMouseY;
|
||||||
|
dragMouseX = e.clientX;
|
||||||
|
dragMouseY = e.clientY;
|
||||||
|
centerx-=dx/zoom;
|
||||||
|
centerx = Math.max(centerx, 400/zoom);
|
||||||
|
centerx = Math.min(centerx, 600-400/zoom);
|
||||||
|
centery-=dy/zoom;
|
||||||
|
centery = Math.max(centery, 300/zoom);
|
||||||
|
centery = Math.min(centery, 600-300/zoom);
|
||||||
|
recenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseUp(e){
|
||||||
|
if(!moved) handleClick(e);
|
||||||
|
window.onmousemove = undefined;
|
||||||
|
window.onmouseup = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setZoom(n){
|
||||||
|
zoom = n;
|
||||||
|
setChipStyle({
|
||||||
|
width: 600*n+'px',
|
||||||
|
height: 600*n+'px'
|
||||||
|
});
|
||||||
|
recenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
function recenter(){
|
||||||
|
var top = -centery*zoom+300;
|
||||||
|
top = Math.min(top, 0);
|
||||||
|
top = Math.max(top, -600*(zoom-1));
|
||||||
|
var left = -centerx*zoom+400;
|
||||||
|
left = Math.min(left, 0);
|
||||||
|
left = Math.max(left, (zoom==1)?100:-600*zoom+800);
|
||||||
|
setChipStyle({
|
||||||
|
top: top+'px',
|
||||||
|
left: left+'px',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleClick(e){
|
||||||
|
var x = localx(hilite, e.clientX)/zoom;
|
||||||
|
var y = localy(hilite, e.clientY)/zoom;
|
||||||
|
var w = findNodeNumber(x,y);
|
||||||
|
if(e.shiftKey) hiliteNode(getNodeGroup(w));
|
||||||
|
else {var a=new Array(); a.push(w); hiliteNode(a);}
|
||||||
|
var cx = Math.round(x*grChipSize/600);
|
||||||
|
var cy = Math.round(y*grChipSize/600);
|
||||||
|
if(w==-1) setStatus('x:',cx,'<br>','y:',cy);
|
||||||
|
else {
|
||||||
|
var s1='x: ' + cx + ' y: ' + cy;
|
||||||
|
var s2='node: ' + w + ' ' + nodeName(w);
|
||||||
|
setStatus(s1, s2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
//
|
||||||
|
// Etc.
|
||||||
|
//
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
function setChipStyle(props){
|
||||||
|
for(var i in props){
|
||||||
|
chipbg.style[i] = props[i];
|
||||||
|
overlay.style[i] = props[i];
|
||||||
|
hilite.style[i] = props[i];
|
||||||
|
hitbuffer.style[i] = props[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -403,6 +403,8 @@ function estimatedHz(){
|
|||||||
|
|
||||||
function initLogbox(names){
|
function initLogbox(names){
|
||||||
var logbox=document.getElementById('logstream');
|
var logbox=document.getElementById('logstream');
|
||||||
|
if(logbox==null)return;
|
||||||
|
|
||||||
logStream = [];
|
logStream = [];
|
||||||
logStream.push("<td>" + names.join("</td><td>") + "</td>");
|
logStream.push("<td>" + names.join("</td><td>") + "</td>");
|
||||||
logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>";
|
logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>";
|
||||||
|
18
save.php
18
save.php
@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
$filename = $_REQUEST['name'];
|
|
||||||
file_put_contents1($filename, file_get_contents("php://input"));
|
|
||||||
|
|
||||||
function file_put_contents1($filename, $data) {
|
|
||||||
$f = @fopen($filename, 'w');
|
|
||||||
if ($f) {
|
|
||||||
$bytes = fwrite($f, $data);
|
|
||||||
fclose($f);
|
|
||||||
return $bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
332
wires.js
332
wires.js
@ -21,36 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var frame, chipbg, overlay, hilite, hitbuffer, ctx;
|
var frame, chipbg, overlay, hilite, hitbuffer, ctx;
|
||||||
var centerx=300, centery=300;
|
|
||||||
var zoom=1;
|
|
||||||
var dragMouseX, dragMouseY, moved;
|
|
||||||
var statbox;
|
|
||||||
|
|
||||||
// Some constants for the graphics presentation
|
|
||||||
// the canvas is embedded in an 800x600 clipping div
|
|
||||||
// which gives rise to some of the 300 and 400 values in the code
|
|
||||||
// there are also some 600 values
|
|
||||||
// the 6502D chip coords are in the box (216,179) to (8983,9807)
|
|
||||||
// we have 4 canvases all the same size, now 2000 pixels square
|
|
||||||
// chip background - the layout
|
|
||||||
// overlay - a red/white transparency to show logic high or low
|
|
||||||
// hilite - to show the selected polygon
|
|
||||||
// hitbuffer - abusing color values to return which polygon is under a point
|
|
||||||
// we no longer use a scaling transform - we now scale the chip data at
|
|
||||||
// the point of drawing line segments
|
|
||||||
// if the canvas is any smaller than chip coordinates there will be
|
|
||||||
// rounding artifacts, and at high zoom there will be anti-aliasing on edges.
|
|
||||||
var grMaxZoom=12;
|
|
||||||
var grChipSize=10000;
|
|
||||||
var grCanvasSize=2000;
|
|
||||||
var grLineWidth=1;
|
|
||||||
|
|
||||||
// Index of layerNames corresponds to index into drawLayers
|
|
||||||
var layernames = ['metal', 'switched diffusion', 'inputdiode', 'grounded diffusion', 'powered diffusion', 'polysilicon'];
|
|
||||||
var colors = ['rgba(128,128,192,0.4)','#FFFF00','#FF00FF','#4DFF4D',
|
|
||||||
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
|
|
||||||
var drawlayers = [true, true, true, true, true, true];
|
|
||||||
|
|
||||||
var nodes = new Array();
|
var nodes = new Array();
|
||||||
var transistors = {};
|
var transistors = {};
|
||||||
var nodenamelist=[];
|
var nodenamelist=[];
|
||||||
@ -58,124 +28,6 @@ var nodenamelist=[];
|
|||||||
var ngnd = nodenames['vss'];
|
var ngnd = nodenames['vss'];
|
||||||
var npwr = nodenames['vcc'];
|
var npwr = nodenames['vcc'];
|
||||||
|
|
||||||
// some modes and parameters which can be passed in from the URL query
|
|
||||||
var moveHereFirst;
|
|
||||||
var expertMode=false
|
|
||||||
var animateChipLayout = true;
|
|
||||||
var chipLayoutIsVisible = true;
|
|
||||||
var userCode=[];
|
|
||||||
var userResetLow;
|
|
||||||
var userResetHigh;
|
|
||||||
var userSteps;
|
|
||||||
var testprogram=[];
|
|
||||||
var testprogramAddress;
|
|
||||||
|
|
||||||
/////////////////////////
|
|
||||||
//
|
|
||||||
// Drawing Setup
|
|
||||||
//
|
|
||||||
/////////////////////////
|
|
||||||
|
|
||||||
// try to present a meaningful page before starting expensive work
|
|
||||||
function setup(){
|
|
||||||
statbox = document.getElementById('status');
|
|
||||||
setStatus('loading 6502...');
|
|
||||||
setTimeout(setup_part2, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setup_part2(){
|
|
||||||
frame = document.getElementById('frame');
|
|
||||||
statbox = document.getElementById('status');
|
|
||||||
setupParams();
|
|
||||||
updateExpertMode(expertMode);
|
|
||||||
setupNodes();
|
|
||||||
setupTransistors();
|
|
||||||
if(chipLayoutIsVisible){
|
|
||||||
// if user requests no chip layout, we can do no canvas operations at all
|
|
||||||
// which saves a lot of memory and allows us to run on small systems
|
|
||||||
updateChipLayoutVisibility(true);
|
|
||||||
}
|
|
||||||
window.onkeypress = function(e){handleKey(e);}
|
|
||||||
setStatus('resetting 6502...');
|
|
||||||
setTimeout(setup_part3, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setup_part3(){
|
|
||||||
setupTable();
|
|
||||||
setupNodeNameList();
|
|
||||||
loadProgram();
|
|
||||||
initChip();
|
|
||||||
document.getElementById('stop').style.visibility = 'hidden';
|
|
||||||
go();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupParams(){
|
|
||||||
if(location.search=="")
|
|
||||||
return
|
|
||||||
var queryParts=location.search.slice(1).split('&');
|
|
||||||
var panx;
|
|
||||||
var pany;
|
|
||||||
var zoom;
|
|
||||||
var userAddress;
|
|
||||||
for(var i=0;i<queryParts.length;i++){
|
|
||||||
var params=queryParts[i].split("=");
|
|
||||||
if(params.length!=2){
|
|
||||||
if(loglevel>0)
|
|
||||||
console.log('malformed parameters',params);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
var name=params[0];
|
|
||||||
var value=params[1].replace(/\/$/,""); // chrome sometimes adds trailing slash
|
|
||||||
// be (relatively) forgiving in what we accept
|
|
||||||
//
|
|
||||||
// user interface mode control
|
|
||||||
if(name=="loglevel" && parseInt(value)!=NaN){
|
|
||||||
updateLoglevel(value);
|
|
||||||
} else if(name=="expert" && value.indexOf("t")==0){
|
|
||||||
updateExpertMode(true);
|
|
||||||
} else if(name=="graphics" && value.indexOf("f")==0){
|
|
||||||
updateChipLayoutVisibility(false);
|
|
||||||
} else
|
|
||||||
// place the graphics window at a point of interest
|
|
||||||
if(name=="panx" && parseInt(value)!=NaN){
|
|
||||||
panx=parseInt(value);
|
|
||||||
} else if(name=="pany" && parseInt(value)!=NaN){
|
|
||||||
pany=parseInt(value);
|
|
||||||
} else if(name=="zoom" && parseInt(value)!=NaN){
|
|
||||||
zoom=parseInt(value);
|
|
||||||
} else
|
|
||||||
// load a test program: Address, Data and Reset
|
|
||||||
if(name=="a" && parseInt(value,16)!=NaN){
|
|
||||||
userAddress=parseInt(value,16);
|
|
||||||
} else if(name=="d" && value.match(/[0-9a-fA-F]*/)[0].length==value.length){
|
|
||||||
for(var j=0;j<value.length;j+=2)
|
|
||||||
userCode[userAddress++]=parseInt(value.slice(j,j+2),16);
|
|
||||||
} else if(name=="r" && parseInt(value,16)!=NaN){
|
|
||||||
userResetLow=parseInt(value,16)%256;
|
|
||||||
userResetHigh=(parseInt(value,16)>>8)%256;
|
|
||||||
} else
|
|
||||||
// run a test program, and optionally check against a golden checksum
|
|
||||||
if(name=="steps" && parseInt(value)!=NaN){
|
|
||||||
userSteps=parseInt(value);
|
|
||||||
running=true;
|
|
||||||
} else if(name=="checksum" && parseInt(value,16)!=NaN){
|
|
||||||
goldenChecksum=(0x100000000+parseInt(value,16)).toString(16).slice(-8);
|
|
||||||
} else {
|
|
||||||
if(loglevel>0)
|
|
||||||
console.log('unrecognised parameters:',params);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(panx!=null && pany!=null && zoom!=null)
|
|
||||||
moveHereFirst=[panx,pany,zoom];
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateChipLayoutAnimation(isOn){
|
|
||||||
// simulation is much faster if we don't update the chip layout on every step
|
|
||||||
animateChipLayout=isOn;
|
|
||||||
document.getElementById('animateModeCheckbox').checked = animateChipLayout;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupNodes(){
|
function setupNodes(){
|
||||||
for(var i in segdefs){
|
for(var i in segdefs){
|
||||||
var seg = segdefs[i];
|
var seg = segdefs[i];
|
||||||
@ -278,8 +130,6 @@ function hexdigit(n){return '0123456789ABCDEF'.charAt(n);}
|
|||||||
/////////////////////////
|
/////////////////////////
|
||||||
|
|
||||||
function refresh(){
|
function refresh(){
|
||||||
if(!chipLayoutIsVisible)
|
|
||||||
return;
|
|
||||||
ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
|
ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
|
||||||
for(i in nodes){
|
for(i in nodes){
|
||||||
if(isNodeHigh(i)) overlayNode(nodes[i].segs);
|
if(isNodeHigh(i)) overlayNode(nodes[i].segs);
|
||||||
@ -316,95 +166,6 @@ function drawSeg(ctx, seg){
|
|||||||
ctx.lineTo(grScale(seg[0]+dx), grScale(grChipSize-seg[1]));
|
ctx.lineTo(grScale(seg[0]+dx), grScale(grChipSize-seg[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////
|
|
||||||
//
|
|
||||||
// User Interface
|
|
||||||
//
|
|
||||||
/////////////////////////
|
|
||||||
|
|
||||||
function handleKey(e){
|
|
||||||
var c = e.charCode;
|
|
||||||
c = String.fromCharCode(c);
|
|
||||||
if('<>?npZzx'.indexOf(c)==-1) return;
|
|
||||||
if((c=='Z'||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();
|
|
||||||
}
|
|
||||||
|
|
||||||
function mouseDown(e){
|
|
||||||
e.preventDefault();
|
|
||||||
moved=false;
|
|
||||||
dragMouseX = e.clientX;
|
|
||||||
dragMouseY = e.clientY;
|
|
||||||
window.onmousemove = function(e){mouseMove(e)};
|
|
||||||
window.onmouseup = function(e){mouseUp(e)};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mouseMove(e){
|
|
||||||
moved = true;
|
|
||||||
if(zoom==1) return;
|
|
||||||
var dx = e.clientX-dragMouseX;
|
|
||||||
var dy = e.clientY-dragMouseY;
|
|
||||||
dragMouseX = e.clientX;
|
|
||||||
dragMouseY = e.clientY;
|
|
||||||
centerx-=dx/zoom;
|
|
||||||
centerx = Math.max(centerx, 400/zoom);
|
|
||||||
centerx = Math.min(centerx, 600-400/zoom);
|
|
||||||
centery-=dy/zoom;
|
|
||||||
centery = Math.max(centery, 300/zoom);
|
|
||||||
centery = Math.min(centery, 600-300/zoom);
|
|
||||||
recenter();
|
|
||||||
}
|
|
||||||
|
|
||||||
function mouseUp(e){
|
|
||||||
if(!moved) handleClick(e);
|
|
||||||
window.onmousemove = undefined;
|
|
||||||
window.onmouseup = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setZoom(n){
|
|
||||||
zoom = n;
|
|
||||||
setChipStyle({
|
|
||||||
width: 600*n+'px',
|
|
||||||
height: 600*n+'px'
|
|
||||||
});
|
|
||||||
recenter();
|
|
||||||
}
|
|
||||||
|
|
||||||
function recenter(){
|
|
||||||
var top = -centery*zoom+300;
|
|
||||||
top = Math.min(top, 0);
|
|
||||||
top = Math.max(top, -600*(zoom-1));
|
|
||||||
var left = -centerx*zoom+400;
|
|
||||||
left = Math.min(left, 0);
|
|
||||||
left = Math.max(left, (zoom==1)?100:-600*zoom+800);
|
|
||||||
setChipStyle({
|
|
||||||
top: top+'px',
|
|
||||||
left: left+'px',
|
|
||||||
});
|
|
||||||
document.getElementById('linkHere').href=location.pathname+"?"+whereAmIAsQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleClick(e){
|
|
||||||
var x = localx(hilite, e.clientX)/zoom;
|
|
||||||
var y = localy(hilite, e.clientY)/zoom;
|
|
||||||
var w = findNodeNumber(x,y);
|
|
||||||
if(e.shiftKey) hiliteNode(getNodeGroup(w));
|
|
||||||
else {var a=new Array(); a.push(w); hiliteNode(a);}
|
|
||||||
var cx = Math.round(x*grChipSize/600);
|
|
||||||
var cy = Math.round(y*grChipSize/600);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function findNodeNumber(x,y){
|
function findNodeNumber(x,y){
|
||||||
var ctx = hitbuffer.getContext('2d');
|
var ctx = hitbuffer.getContext('2d');
|
||||||
var pixels = ctx.getImageData(x*grCanvasSize/600, y*grCanvasSize/600, 2, 2).data;
|
var pixels = ctx.getImageData(x*grCanvasSize/600, y*grCanvasSize/600, 2, 2).data;
|
||||||
@ -415,31 +176,6 @@ function findNodeNumber(x,y){
|
|||||||
return (high<<8)+(mid<<4)+low;
|
return (high<<8)+(mid<<4)+low;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateLoglevel(value){
|
|
||||||
loglevel = value;
|
|
||||||
initLogbox(signalSet(loglevel));
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateExpertMode(isOn){
|
|
||||||
expertMode=isOn
|
|
||||||
document.getElementById('expertModeCheckbox').checked = expertMode;
|
|
||||||
if(expertMode){
|
|
||||||
document.getElementById('expertControlPanel').style.display = 'block';
|
|
||||||
document.getElementById('basicModeText1').style.display = 'none';
|
|
||||||
document.getElementById('basicModeText2').style.display = 'none';
|
|
||||||
if(loglevel==0)
|
|
||||||
updateLoglevel(1);
|
|
||||||
if(chipLayoutIsVisible)
|
|
||||||
document.getElementById('layoutControlPanel').style.display = 'block';
|
|
||||||
} else {
|
|
||||||
document.getElementById('expertControlPanel').style.display = 'none';
|
|
||||||
document.getElementById('basicModeText1').style.display = 'block';
|
|
||||||
document.getElementById('basicModeText2').style.display = 'block';
|
|
||||||
if(chipLayoutIsVisible)
|
|
||||||
document.getElementById('layoutControlPanel').style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearHighlight(){
|
function clearHighlight(){
|
||||||
// remove red/white overlay according to logic value
|
// remove red/white overlay according to logic value
|
||||||
// for easier layout navigation
|
// for easier layout navigation
|
||||||
@ -451,74 +187,6 @@ function updateShow(layer, on){
|
|||||||
setupBackground();
|
setupBackground();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateChipLayoutVisibility(isOn){
|
|
||||||
chipLayoutIsVisible=isOn;
|
|
||||||
if(chipLayoutIsVisible) {
|
|
||||||
document.getElementById('chipsurround').style.display = 'block';
|
|
||||||
if(expertMode)
|
|
||||||
document.getElementById('layoutControlPanel').style.display = 'block';
|
|
||||||
document.getElementById('nochip').style.display = 'none';
|
|
||||||
document.getElementById('logstreamscroller').style.height="260px";
|
|
||||||
// allow the display to update while we load the graphics
|
|
||||||
setStatus('loading graphics...');
|
|
||||||
setTimeout(setupChipLayoutGraphics, 0);
|
|
||||||
} else {
|
|
||||||
// cannot animate the layout if there is no canvas
|
|
||||||
updateChipLayoutAnimation(false);
|
|
||||||
// replace the layout display with a button to show it
|
|
||||||
document.getElementById('chipsurround').style.display = 'none';
|
|
||||||
document.getElementById('layoutControlPanel').style.display = 'none';
|
|
||||||
document.getElementById('nochip').style.display = 'block';
|
|
||||||
document.getElementById('logstreamscroller').style.height="880px";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupChipLayoutGraphics(){
|
|
||||||
setupLayerVisibility();
|
|
||||||
setupBackground();
|
|
||||||
setupOverlay();
|
|
||||||
setupHilite();
|
|
||||||
setupHitBuffer();
|
|
||||||
recenter();
|
|
||||||
refresh();
|
|
||||||
document.getElementById('waiting').style.display = 'none';
|
|
||||||
setStatus('Ready!'); // would prefer chipStatus but it's not idempotent
|
|
||||||
if(moveHereFirst!=null)
|
|
||||||
moveHere(moveHereFirst);
|
|
||||||
hilite.onmousedown = function(e){mouseDown(e);}
|
|
||||||
}
|
|
||||||
|
|
||||||
// utility function to save graphics pan and zoom
|
|
||||||
function whereAmIAsQuery(){
|
|
||||||
var w=whereAmI();
|
|
||||||
return "panx="+w[0]+"&pany="+w[1]+"&zoom="+w[2]
|
|
||||||
}
|
|
||||||
function whereAmI(){
|
|
||||||
return [centerx, centery, zoom];
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore graphics pan and zoom (perhaps as given in the URL)
|
|
||||||
function moveHere(place){
|
|
||||||
centerx = place[0];
|
|
||||||
centery = place[1];
|
|
||||||
setZoom(place[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////////////
|
|
||||||
//
|
|
||||||
// Etc.
|
|
||||||
//
|
|
||||||
/////////////////////////
|
|
||||||
|
|
||||||
function setChipStyle(props){
|
|
||||||
for(var i in props){
|
|
||||||
chipbg.style[i] = props[i];
|
|
||||||
overlay.style[i] = props[i];
|
|
||||||
hilite.style[i] = props[i];
|
|
||||||
hitbuffer.style[i] = props[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we draw the chip data scaled down to the canvas
|
// we draw the chip data scaled down to the canvas
|
||||||
// and so avoid scaling a large canvas
|
// and so avoid scaling a large canvas
|
||||||
function grScale(x){
|
function grScale(x){
|
||||||
|
Loading…
Reference in New Issue
Block a user