Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
416cd57947 | |||
e5bd2a5296 |
BIN
3rdparty/img/hgrabber.gif
vendored
Before Width: | Height: | Size: 834 B |
BIN
3rdparty/img/vdockbar.gif
vendored
Before Width: | Height: | Size: 855 B |
BIN
3rdparty/img/vgrabber.gif
vendored
Before Width: | Height: | Size: 830 B |
BIN
3rdparty/img/vgrabber2-active.gif
vendored
Before Width: | Height: | Size: 840 B |
BIN
3rdparty/img/vgrabber2-normal.gif
vendored
Before Width: | Height: | Size: 843 B |
19
3rdparty/jquery-1.3.2.min.js
vendored
92
3rdparty/jquery.cookie.js
vendored
@ -1,92 +0,0 @@
|
|||||||
/**
|
|
||||||
* Cookie plugin
|
|
||||||
*
|
|
||||||
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
|
|
||||||
* Dual licensed under the MIT and GPL licenses:
|
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a cookie with the given name and value and other optional parameters.
|
|
||||||
*
|
|
||||||
* @example $.cookie('the_cookie', 'the_value');
|
|
||||||
* @desc Set the value of a cookie.
|
|
||||||
* @example $.cookie('the_cookie', 'the_value', {expires: 7, path: '/', domain: 'jquery.com', secure: true});
|
|
||||||
* @desc Create a cookie with all available options.
|
|
||||||
* @example $.cookie('the_cookie', 'the_value');
|
|
||||||
* @desc Create a session cookie.
|
|
||||||
* @example $.cookie('the_cookie', null);
|
|
||||||
* @desc Delete a cookie by passing null as value.
|
|
||||||
*
|
|
||||||
* @param String name The name of the cookie.
|
|
||||||
* @param String value The value of the cookie.
|
|
||||||
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
|
|
||||||
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
|
|
||||||
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
|
|
||||||
* If set to null or omitted, the cookie will be a session cookie and will not be retained
|
|
||||||
* when the the browser exits.
|
|
||||||
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
|
|
||||||
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
|
|
||||||
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
|
|
||||||
* require a secure protocol (like HTTPS).
|
|
||||||
* @type undefined
|
|
||||||
*
|
|
||||||
* @name $.cookie
|
|
||||||
* @cat Plugins/Cookie
|
|
||||||
* @author Klaus Hartl/klaus.hartl@stilbuero.de
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the value of a cookie with the given name.
|
|
||||||
*
|
|
||||||
* @example $.cookie('the_cookie');
|
|
||||||
* @desc Get the value of a cookie.
|
|
||||||
*
|
|
||||||
* @param String name The name of the cookie.
|
|
||||||
* @return The value of the cookie.
|
|
||||||
* @type String
|
|
||||||
*
|
|
||||||
* @name $.cookie
|
|
||||||
* @cat Plugins/Cookie
|
|
||||||
* @author Klaus Hartl/klaus.hartl@stilbuero.de
|
|
||||||
*/
|
|
||||||
jQuery.cookie = function(name, value, options) {
|
|
||||||
if (typeof value != 'undefined') { // name and value given, set cookie
|
|
||||||
options = options || {};
|
|
||||||
if (value === null) {
|
|
||||||
value = '';
|
|
||||||
options.expires = -1;
|
|
||||||
}
|
|
||||||
var expires = '';
|
|
||||||
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
|
|
||||||
var date;
|
|
||||||
if (typeof options.expires == 'number') {
|
|
||||||
date = new Date();
|
|
||||||
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
|
|
||||||
} else {
|
|
||||||
date = options.expires;
|
|
||||||
}
|
|
||||||
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
|
|
||||||
}
|
|
||||||
var path = options.path ? '; path=' + options.path : '';
|
|
||||||
var domain = options.domain ? '; domain=' + options.domain : '';
|
|
||||||
var secure = options.secure ? '; secure' : '';
|
|
||||||
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
|
|
||||||
} else { // only name given, get cookie
|
|
||||||
var cookieValue = null;
|
|
||||||
if (document.cookie && document.cookie != '') {
|
|
||||||
var cookies = document.cookie.split(';');
|
|
||||||
for (var i = 0; i < cookies.length; i++) {
|
|
||||||
var cookie = jQuery.trim(cookies[i]);
|
|
||||||
// Does this cookie string begin with the name we want?
|
|
||||||
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
|
||||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cookieValue;
|
|
||||||
}
|
|
||||||
};
|
|
213
3rdparty/splitter.js
vendored
@ -1,213 +0,0 @@
|
|||||||
/*
|
|
||||||
* jQuery.splitter.js - two-pane splitter window plugin
|
|
||||||
*
|
|
||||||
* version 1.51 (2009/01/09)
|
|
||||||
*
|
|
||||||
* Dual licensed under the MIT and GPL licenses:
|
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The splitter() plugin implements a two-pane resizable splitter window.
|
|
||||||
* The selected elements in the jQuery object are converted to a splitter;
|
|
||||||
* each selected element should have two child elements, used for the panes
|
|
||||||
* of the splitter. The plugin adds a third child element for the splitbar.
|
|
||||||
*
|
|
||||||
* For more details see: http://methvin.com/splitter/
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @example $('#MySplitter').splitter();
|
|
||||||
* @desc Create a vertical splitter with default settings
|
|
||||||
*
|
|
||||||
* @example $('#MySplitter').splitter({type: 'h', accessKey: 'M'});
|
|
||||||
* @desc Create a horizontal splitter resizable via Alt+Shift+M
|
|
||||||
*
|
|
||||||
* @name splitter
|
|
||||||
* @type jQuery
|
|
||||||
* @param Object options Options for the splitter (not required)
|
|
||||||
* @cat Plugins/Splitter
|
|
||||||
* @return jQuery
|
|
||||||
* @author Dave Methvin (dave.methvin@gmail.com)
|
|
||||||
*/
|
|
||||||
;(function($){
|
|
||||||
|
|
||||||
$.fn.splitter = function(args){
|
|
||||||
args = args || {};
|
|
||||||
return this.each(function() {
|
|
||||||
var zombie; // left-behind splitbar for outline resizes
|
|
||||||
function startSplitMouse(evt) {
|
|
||||||
if ( opts.outline )
|
|
||||||
zombie = zombie || bar.clone(false).insertAfter(A);
|
|
||||||
panes.css("-webkit-user-select", "none"); // Safari selects A/B text on a move
|
|
||||||
bar.addClass(opts.activeClass);
|
|
||||||
A._posSplit = A[0][opts.pxSplit] - evt[opts.eventPos];
|
|
||||||
$(document)
|
|
||||||
.bind("mousemove", doSplitMouse)
|
|
||||||
.bind("mouseup", endSplitMouse);
|
|
||||||
}
|
|
||||||
function doSplitMouse(evt) {
|
|
||||||
var newPos = A._posSplit+evt[opts.eventPos];
|
|
||||||
if ( opts.outline ) {
|
|
||||||
newPos = Math.max(0, Math.min(newPos, splitter._DA - bar._DA));
|
|
||||||
bar.css(opts.origin, newPos);
|
|
||||||
} else
|
|
||||||
resplit(newPos);
|
|
||||||
}
|
|
||||||
function endSplitMouse(evt) {
|
|
||||||
bar.removeClass(opts.activeClass);
|
|
||||||
var newPos = A._posSplit+evt[opts.eventPos];
|
|
||||||
if ( opts.outline ) {
|
|
||||||
zombie.remove(); zombie = null;
|
|
||||||
resplit(newPos);
|
|
||||||
}
|
|
||||||
panes.css("-webkit-user-select", "text"); // let Safari select text again
|
|
||||||
$(document)
|
|
||||||
.unbind("mousemove", doSplitMouse)
|
|
||||||
.unbind("mouseup", endSplitMouse);
|
|
||||||
}
|
|
||||||
function resplit(newPos) {
|
|
||||||
// Constrain new splitbar position to fit pane size limits
|
|
||||||
newPos = Math.max(A._min, splitter._DA - B._max,
|
|
||||||
Math.min(newPos, A._max, splitter._DA - bar._DA - B._min));
|
|
||||||
// Resize/position the two panes
|
|
||||||
bar._DA = bar[0][opts.pxSplit]; // bar size may change during dock
|
|
||||||
bar.css(opts.origin, newPos).css(opts.fixed, splitter._DF);
|
|
||||||
A.css(opts.origin, 0).css(opts.split, newPos).css(opts.fixed, splitter._DF);
|
|
||||||
B.css(opts.origin, newPos+bar._DA)
|
|
||||||
.css(opts.split, splitter._DA-bar._DA-newPos).css(opts.fixed, splitter._DF);
|
|
||||||
// IE fires resize for us; all others pay cash
|
|
||||||
if ( !$.browser.msie )
|
|
||||||
panes.trigger("resize");
|
|
||||||
}
|
|
||||||
function dimSum(jq, dims) {
|
|
||||||
// Opera returns -1 for missing min/max width, turn into 0
|
|
||||||
var sum = 0;
|
|
||||||
for ( var i=1; i < arguments.length; i++ )
|
|
||||||
sum += Math.max(parseInt(jq.css(arguments[i])) || 0, 0);
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine settings based on incoming opts, element classes, and defaults
|
|
||||||
var vh = (args.splitHorizontal? 'h' : args.splitVertical? 'v' : args.type) || 'v';
|
|
||||||
var opts = $.extend({
|
|
||||||
activeClass: 'active', // class name for active splitter
|
|
||||||
pxPerKey: 8, // splitter px moved per keypress
|
|
||||||
tabIndex: 0, // tab order indicator
|
|
||||||
accessKey: '' // accessKey for splitbar
|
|
||||||
},{
|
|
||||||
v: { // Vertical splitters:
|
|
||||||
keyLeft: 39, keyRight: 37, cursor: "e-resize",
|
|
||||||
splitbarClass: "vsplitbar", outlineClass: "voutline",
|
|
||||||
type: 'v', eventPos: "pageX", origin: "left",
|
|
||||||
split: "width", pxSplit: "offsetWidth", side1: "Left", side2: "Right",
|
|
||||||
fixed: "height", pxFixed: "offsetHeight", side3: "Top", side4: "Bottom"
|
|
||||||
},
|
|
||||||
h: { // Horizontal splitters:
|
|
||||||
keyTop: 40, keyBottom: 38, cursor: "n-resize",
|
|
||||||
splitbarClass: "hsplitbar", outlineClass: "houtline",
|
|
||||||
type: 'h', eventPos: "pageY", origin: "top",
|
|
||||||
split: "height", pxSplit: "offsetHeight", side1: "Top", side2: "Bottom",
|
|
||||||
fixed: "width", pxFixed: "offsetWidth", side3: "Left", side4: "Right"
|
|
||||||
}
|
|
||||||
}[vh], args);
|
|
||||||
|
|
||||||
// Create jQuery object closures for splitter and both panes
|
|
||||||
var splitter = $(this).css({position: "relative"});
|
|
||||||
var panes = $(">*", splitter[0]).css({
|
|
||||||
position: "absolute", // positioned inside splitter container
|
|
||||||
"z-index": "1", // splitbar is positioned above
|
|
||||||
"-moz-outline-style": "none" // don't show dotted outline
|
|
||||||
});
|
|
||||||
var A = $(panes[0]); // left or top
|
|
||||||
var B = $(panes[1]); // right or bottom
|
|
||||||
|
|
||||||
// Focuser element, provides keyboard support; title is shown by Opera accessKeys
|
|
||||||
var focuser = $('<a href="javascript:void(0)"></a>')
|
|
||||||
.attr({accessKey: opts.accessKey, tabIndex: opts.tabIndex, title: opts.splitbarClass})
|
|
||||||
.bind($.browser.opera?"click":"focus", function(){ this.focus(); bar.addClass(opts.activeClass) })
|
|
||||||
.bind("keydown", function(e){
|
|
||||||
var key = e.which || e.keyCode;
|
|
||||||
var dir = key==opts["key"+opts.side1]? 1 : key==opts["key"+opts.side2]? -1 : 0;
|
|
||||||
if ( dir )
|
|
||||||
resplit(A[0][opts.pxSplit]+dir*opts.pxPerKey, false);
|
|
||||||
})
|
|
||||||
.bind("blur", function(){ bar.removeClass(opts.activeClass) });
|
|
||||||
|
|
||||||
// Splitbar element, can be already in the doc or we create one
|
|
||||||
var bar = $(panes[2] || '<div></div>')
|
|
||||||
.insertAfter(A).css("z-index", "100").append(focuser)
|
|
||||||
.attr({"class": opts.splitbarClass, unselectable: "on"})
|
|
||||||
.css({position: "absolute", "user-select": "none", "-webkit-user-select": "none",
|
|
||||||
"-khtml-user-select": "none", "-moz-user-select": "none"})
|
|
||||||
.bind("mousedown", startSplitMouse);
|
|
||||||
// Use our cursor unless the style specifies a non-default cursor
|
|
||||||
if ( /^(auto|default|)$/.test(bar.css("cursor")) )
|
|
||||||
bar.css("cursor", opts.cursor);
|
|
||||||
|
|
||||||
// Cache several dimensions for speed, rather than re-querying constantly
|
|
||||||
bar._DA = bar[0][opts.pxSplit];
|
|
||||||
splitter._PBF = $.boxModel? dimSum(splitter, "border"+opts.side3+"Width", "border"+opts.side4+"Width") : 0;
|
|
||||||
splitter._PBA = $.boxModel? dimSum(splitter, "border"+opts.side1+"Width", "border"+opts.side2+"Width") : 0;
|
|
||||||
A._pane = opts.side1;
|
|
||||||
B._pane = opts.side2;
|
|
||||||
$.each([A,B], function(){
|
|
||||||
this._min = opts["min"+this._pane] || dimSum(this, "min-"+opts.split);
|
|
||||||
this._max = opts["max"+this._pane] || dimSum(this, "max-"+opts.split) || 9999;
|
|
||||||
this._init = opts["size"+this._pane]===true ?
|
|
||||||
parseInt($.curCSS(this[0],opts.split)) : opts["size"+this._pane];
|
|
||||||
});
|
|
||||||
|
|
||||||
// Determine initial position, get from cookie if specified
|
|
||||||
var initPos = A._init;
|
|
||||||
if ( !isNaN(B._init) ) // recalc initial B size as an offset from the top or left side
|
|
||||||
initPos = splitter[0][opts.pxSplit] - splitter._PBA - B._init - bar._DA;
|
|
||||||
if ( opts.cookie ) {
|
|
||||||
if ( !$.cookie )
|
|
||||||
alert('jQuery.splitter(): jQuery cookie plugin required');
|
|
||||||
var ckpos = parseInt($.cookie(opts.cookie));
|
|
||||||
if ( !isNaN(ckpos) )
|
|
||||||
initPos = ckpos;
|
|
||||||
$(window).bind("unload", function(){
|
|
||||||
var state = String(bar.css(opts.origin)); // current location of splitbar
|
|
||||||
$.cookie(opts.cookie, state, {expires: opts.cookieExpires || 365,
|
|
||||||
path: opts.cookiePath || document.location.pathname});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ( isNaN(initPos) ) // King Solomon's algorithm
|
|
||||||
initPos = Math.round((splitter[0][opts.pxSplit] - splitter._PBA - bar._DA)/2);
|
|
||||||
|
|
||||||
// Resize event propagation and splitter sizing
|
|
||||||
if ( opts.anchorToWindow ) {
|
|
||||||
// Account for margin or border on the splitter container and enforce min height
|
|
||||||
splitter._hadjust = dimSum(splitter, "borderTopWidth", "borderBottomWidth", "marginBottom");
|
|
||||||
splitter._hmin = Math.max(dimSum(splitter, "minHeight"), 20);
|
|
||||||
$(window).bind("resize", function(){
|
|
||||||
var top = splitter.offset().top;
|
|
||||||
var wh = $(window).height();
|
|
||||||
splitter.css("height", Math.max(wh-top-splitter._hadjust, splitter._hmin)+"px");
|
|
||||||
if ( !$.browser.msie ) splitter.trigger("resize");
|
|
||||||
}).trigger("resize");
|
|
||||||
}
|
|
||||||
else if ( opts.resizeToWidth && !$.browser.msie )
|
|
||||||
$(window).bind("resize", function(){
|
|
||||||
splitter.trigger("resize");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Resize event handler; triggered immediately to set initial position
|
|
||||||
splitter.bind("resize", function(e, size){
|
|
||||||
// Custom events bubble in jQuery 1.3; don't Yo Dawg
|
|
||||||
if ( e.target != this ) return;
|
|
||||||
// Determine new width/height of splitter container
|
|
||||||
splitter._DF = splitter[0][opts.pxFixed] - splitter._PBF;
|
|
||||||
splitter._DA = splitter[0][opts.pxSplit] - splitter._PBA;
|
|
||||||
// Bail if splitter isn't visible or content isn't there yet
|
|
||||||
if ( splitter._DF <= 0 || splitter._DA <= 0 ) return;
|
|
||||||
// Re-divvy the adjustable dimension; maintain size of the preferred pane
|
|
||||||
resplit(!isNaN(size)? size : (!(opts.sizeRight||opts.sizeBottom)? A[0][opts.pxSplit] :
|
|
||||||
splitter._DA-B[0][opts.pxSplit]-bar._DA));
|
|
||||||
}).trigger("resize" , [initPos]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
})(jQuery);
|
|
162
chipsim.js
@ -21,116 +21,123 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var ctrace = false;
|
var ctrace = false;
|
||||||
var traceTheseNodes = [];
|
var noGraphics = false;
|
||||||
var traceTheseTransistors = [];
|
var loglevel = 3;
|
||||||
var loglevel = 0;
|
var ridx = 0;
|
||||||
var recalclist = new Array();
|
|
||||||
var recalcHash = new Array();
|
|
||||||
var group = new Array();
|
|
||||||
|
|
||||||
function recalcNodeList(list){
|
function recalcNodeList(list){
|
||||||
var n = list[0];
|
var n = list[0];
|
||||||
recalclist = new Array();
|
var recalclist = new Array();
|
||||||
recalcHash = new Array();
|
|
||||||
for(var j=0;j<100;j++){ // loop limiter
|
for(var j=0;j<100;j++){ // loop limiter
|
||||||
if(list.length==0) return;
|
if(list.length==0) return;
|
||||||
if(ctrace) {
|
if(ctrace) console.log(j, list);
|
||||||
var i;
|
for(var i in list) recalcNode(list[i], recalclist);
|
||||||
for(i=0;i<traceTheseNodes.length;i++) {
|
|
||||||
if(list.indexOf(traceTheseNodes[i])!=-1) break;
|
|
||||||
}
|
|
||||||
if((traceTheseNodes.length==0)||(list.indexOf(traceTheseNodes[i])==-1)) {
|
|
||||||
console.log('recalcNodeList iteration: ', j, list.length, 'nodes');
|
|
||||||
} else {
|
|
||||||
console.log('recalcNodeList iteration: ', j, list.length, 'nodes', list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.forEach(recalcNode);
|
|
||||||
list = recalclist;
|
list = recalclist;
|
||||||
recalclist = new Array();
|
recalclist = new Array();
|
||||||
recalcHash = new Array();
|
|
||||||
}
|
}
|
||||||
if(ctrace) console.log(n,'looping...');
|
if(ctrace) console.log(n,'looping...');
|
||||||
}
|
}
|
||||||
|
|
||||||
function recalcNode(node){
|
function recalcNode(node, recalclist){
|
||||||
if(node==ngnd) return;
|
if(node==ngnd) return;
|
||||||
if(node==npwr) return;
|
if(node==npwr) return;
|
||||||
getNodeGroup(node);
|
var group = getNodeGroup(node);
|
||||||
var newState = getNodeValue();
|
var newv = getNodeValue(group);
|
||||||
if(ctrace && (traceTheseNodes.indexOf(node)!=-1))
|
if(ctrace) console.log('recalc', node, group);
|
||||||
console.log('recalc', node, group);
|
for(var i in group){
|
||||||
group.forEach(function(i){
|
var n = nodes[group[i]];
|
||||||
var n = nodes[i];
|
if(n.state!=newv && ctrace) console.log(group[i], n.state, newv);
|
||||||
if(n.state==newState) return;
|
n.state = newv;
|
||||||
n.state = newState;
|
for(var t in n.gates) recalcTransistor(n.gates[t], recalclist);
|
||||||
n.gates.forEach(function(t){
|
}
|
||||||
if(n.state) turnTransistorOn(t);
|
|
||||||
else turnTransistorOff(t);});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function turnTransistorOn(t){
|
function recalcTransistor(tn, recalclist){
|
||||||
|
var t = transistors[tn];
|
||||||
|
if(isNodeHigh(t.gate)) turnTransistorOn(t, recalclist);
|
||||||
|
else turnTransistorOff(t, recalclist);
|
||||||
|
}
|
||||||
|
|
||||||
|
function turnTransistorOn(t, recalclist){
|
||||||
if(t.on) return;
|
if(t.on) return;
|
||||||
if(ctrace && (traceTheseTransistors.indexOf(t.name)!=-1))
|
if(ctrace) console.log(t.name, 'on', t.gate, t.c1, t.c2);
|
||||||
console.log(t.name, 'on', t.gate, t.c1, t.c2);
|
|
||||||
t.on = true;
|
t.on = true;
|
||||||
addRecalcNode(t.c1);
|
addRecalcNode(t.c1, recalclist);
|
||||||
|
addRecalcNode(t.c2, recalclist);
|
||||||
}
|
}
|
||||||
|
|
||||||
function turnTransistorOff(t){
|
function turnTransistorOff(t, recalclist){
|
||||||
if(!t.on) return;
|
if(!t.on) return;
|
||||||
if(ctrace && (traceTheseTransistors.indexOf(t.name)!=-1))
|
if(ctrace) console.log(t.name, 'off', t.gate, t.c1, t.c2);
|
||||||
console.log(t.name, 'off', t.gate, t.c1, t.c2);
|
|
||||||
t.on = false;
|
t.on = false;
|
||||||
addRecalcNode(t.c1);
|
floatnode(t.c1);
|
||||||
addRecalcNode(t.c2);
|
floatnode(t.c2);
|
||||||
|
addRecalcNode(t.c1, recalclist);
|
||||||
|
addRecalcNode(t.c2, recalclist);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRecalcNode(nn){
|
function floatnode(nn){
|
||||||
if(nn==ngnd) return;
|
if(nn==ngnd) return;
|
||||||
if(nn==npwr) return;
|
if(nn==npwr) return;
|
||||||
if(recalcHash[nn] == 1)return;
|
var n = nodes[nn];
|
||||||
recalclist.push(nn);
|
if(n.state=='gnd') n.state = 'fl';
|
||||||
recalcHash[nn] = 1;
|
if(n.state=='pd') n.state = 'fl';
|
||||||
|
if(n.state=='vcc') n.state = 'fh';
|
||||||
|
if(n.state=='pu') n.state = 'fh';
|
||||||
|
if(ctrace) console.log('floating', nn, 'to', n.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addRecalcNode(nn, recalclist){
|
||||||
|
if(nn==ngnd) return;
|
||||||
|
if(nn==npwr) return;
|
||||||
|
if(arrayContains(recalclist, nn)) return;
|
||||||
|
recalclist.push(nn);
|
||||||
|
// setAdd(recalclist, nn);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeGroup(i){
|
function getNodeGroup(i){
|
||||||
group = new Array();
|
var group = new Array();
|
||||||
addNodeToGroup(i);
|
addNodeToGroup(i, group);
|
||||||
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addNodeToGroup(i){
|
function addNodeToGroup(i, group){
|
||||||
if(group.indexOf(i) != -1) return;
|
if(arrayContains(group, i)) return;
|
||||||
group.push(i);
|
group.push(i);
|
||||||
if(i==ngnd) return;
|
if(i==ngnd) return;
|
||||||
if(i==npwr) return;
|
if(i==npwr) return;
|
||||||
nodes[i].c1c2s.forEach(
|
for(var t in nodes[i].c1c2s) addNodeTransistor(i, nodes[i].c1c2s[t], group);
|
||||||
function(t){
|
}
|
||||||
if(!t.on) return;
|
|
||||||
var other;
|
function addNodeTransistor(node, t, group){
|
||||||
if(t.c1==i) other=t.c2;
|
var tr = transistors[t];
|
||||||
if(t.c2==i) other=t.c1;
|
if(!tr.on) return;
|
||||||
addNodeToGroup(other);});
|
var other;
|
||||||
|
if(tr.c1==node) other=tr.c2;
|
||||||
|
if(tr.c2==node) other=tr.c1;
|
||||||
|
addNodeToGroup(other, group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function getNodeValue(){
|
function getNodeValue(group){
|
||||||
if(arrayContains(group, ngnd)) return false;
|
if(arrayContains(group, ngnd)) return 'gnd';
|
||||||
if(arrayContains(group, npwr)) return true;
|
if(arrayContains(group, npwr)) return 'vcc';
|
||||||
|
var flstate;
|
||||||
for(var i in group){
|
for(var i in group){
|
||||||
var nn = group[i];
|
var nn = group[i];
|
||||||
var n = nodes[nn];
|
var n = nodes[nn];
|
||||||
if(n.pullup) return true;
|
if(n.pullup) return 'pu';
|
||||||
if(n.pulldown) return false;
|
if(n.pulldown) return 'pd';
|
||||||
if(n.state) return true;
|
if((n.state=='fl')&&(flstate==undefined)) flstate = 'fl';
|
||||||
|
if(n.state=='fh') flstate = 'fh';
|
||||||
}
|
}
|
||||||
return false;
|
if(flstate==undefined && ctrace) console.log(group);
|
||||||
|
return flstate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function isNodeHigh(nn){
|
function isNodeHigh(nn){
|
||||||
return(nodes[nn].state);
|
return arrayContains(['vcc','pu','fh'], nodes[nn].state);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveString(name, str){
|
function saveString(name, str){
|
||||||
@ -148,26 +155,25 @@ function allNodes(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stateString(){
|
function stateString(){
|
||||||
var codes = ['l','h'];
|
var codes = {gnd: 'g', vcc: 'v', pu: 'p', pd: 'd', fh: 'f', fl: 'l'};
|
||||||
var res = '';
|
var res = '';
|
||||||
for(var i=0;i<1725;i++){
|
for(var i=0;i<1725;i++){
|
||||||
var n = nodes[i];
|
var n = nodes[i];
|
||||||
if(n==undefined) res+='x';
|
if(n==undefined) res+='x';
|
||||||
else if(i==ngnd) res+='g';
|
else if(i==ngnd) res+='g';
|
||||||
else if(i==npwr) res+='v';
|
else if(i==npwr) res+='v';
|
||||||
else res+= codes[0+n.state];
|
else res+= codes[n.state];
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showState(str){
|
function showState(str){
|
||||||
var codes = {g: false, h: true, v: true, l: false};
|
var codes = {g: 'gnd', v: 'vcc', p: 'pu', d: 'pd', f: 'fh', l: 'fl'};
|
||||||
for(var i=0;i<str.length;i++){
|
for(var i=0;i<str.length;i++){
|
||||||
if(str[i]=='x') continue;
|
if(str[i]=='x') continue;
|
||||||
var state = codes[str[i]];
|
nodes[i].state = codes[str[i]];
|
||||||
nodes[i].state = state;
|
|
||||||
var gates = nodes[i].gates;
|
var gates = nodes[i].gates;
|
||||||
gates.forEach(function(t){t.on=state;});
|
for(var t in gates) transistors[gates[t]].on = isNodeHigh(i);
|
||||||
}
|
}
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
@ -193,4 +199,12 @@ function setLow(name){
|
|||||||
recalcNodeList([nn]);
|
recalcNodeList([nn]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setAdd(arr, el){
|
||||||
|
var idx = ridx%(arr.length+1);
|
||||||
|
ridx+=131;
|
||||||
|
ridx%=123;
|
||||||
|
arr.splice(idx, 0, el);
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
function arrayContains(arr, el){return arr.indexOf(el)!=-1;}
|
function arrayContains(arr, el){return arr.indexOf(el)!=-1;}
|
||||||
|
194
expert.css
@ -1,194 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles
|
|
||||||
|
|
||||||
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 :Verdana, Arial, Helvetica, Sans-Serif;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#title {
|
|
||||||
font-size: 30px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.frame {
|
|
||||||
margin-left: 10px;
|
|
||||||
min-width: 1120px; /* ugh - prevent memtable flowing underneath chip */
|
|
||||||
}
|
|
||||||
|
|
||||||
div.leftcolumn {
|
|
||||||
width: 804px; /* ugh - matches the div.chip width + border */
|
|
||||||
}
|
|
||||||
|
|
||||||
div.rightcolumn {
|
|
||||||
padding-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.footer {
|
|
||||||
clear: both;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.nochip {
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#chipsurround {
|
|
||||||
height: 600px; /* matches the div.chip height */
|
|
||||||
}
|
|
||||||
|
|
||||||
div.chip {
|
|
||||||
background: lightgray;
|
|
||||||
border: 2px solid gray;
|
|
||||||
position: absolute; /* must be absolute to contain the canvas */
|
|
||||||
width: 800px;
|
|
||||||
height: 600px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.chip {
|
|
||||||
position: absolute;
|
|
||||||
width: 600px; /* square chip image same height as div.chip */
|
|
||||||
height: 600px; /* square */
|
|
||||||
}
|
|
||||||
|
|
||||||
div.twobuttons{
|
|
||||||
float:left;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.morebuttons{
|
|
||||||
float:left;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.buttons{
|
|
||||||
/* top: -5px; */
|
|
||||||
}
|
|
||||||
|
|
||||||
div.status {
|
|
||||||
clear: left;
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.navbutton {
|
|
||||||
border: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.navplay {
|
|
||||||
margin-right: 5px;
|
|
||||||
border: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img.navstop {
|
|
||||||
position: absolute;
|
|
||||||
border: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.expertcheckbox {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.memtable {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 12px;
|
|
||||||
border-spacing: 0px;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#layoutControlPanel{
|
|
||||||
display:none;
|
|
||||||
margin-top: 2px;
|
|
||||||
margin-bottom: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#expertControlPanel{
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.animatebox{
|
|
||||||
border:thin solid;
|
|
||||||
padding:2px;
|
|
||||||
border-color:gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
a#linkHere{
|
|
||||||
padding:2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#logstreamscroller{
|
|
||||||
overflow:auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.logstream {
|
|
||||||
font-family: monospace;
|
|
||||||
font-size: 12px;
|
|
||||||
border-spacing: 2px;
|
|
||||||
text-align:center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Splitter */
|
|
||||||
#frame {
|
|
||||||
height: 750px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.leftcolumn, div.rightcolumn, {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
div#righttopdiv, div#tracingdiv {
|
|
||||||
overflow: auto;
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.rightcolumn {
|
|
||||||
background-color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vsplitbar {
|
|
||||||
width: 5px;
|
|
||||||
background: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vsplitbar {
|
|
||||||
width: 6px;
|
|
||||||
background: #669 url(3rdparty/img/vgrabber.gif) no-repeat center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vsplitbar:hover, .vsplitbar.active {
|
|
||||||
background: #c66 url(3rdparty/img/vgrabber.gif) no-repeat center;
|
|
||||||
opacity: 0.7;
|
|
||||||
filter: alpha(opacity=70); /* IE */
|
|
||||||
background: #c99;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hsplitbar {
|
|
||||||
height: 6px;
|
|
||||||
background: #669 url(3rdparty/img/hgrabber.gif) no-repeat center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hsplitbar.active, .hsplitbar:hover {
|
|
||||||
background: #c66 url(3rdparty/img/hgrabber.gif) no-repeat center;
|
|
||||||
}
|
|
145
expert.html
@ -1,145 +0,0 @@
|
|||||||
<!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 src="3rdparty/jquery-1.3.2.min.js"></script>
|
|
||||||
<script src="3rdparty/jquery.cookie.js"></script>
|
|
||||||
<script src="3rdparty/splitter.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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// initialise splitter (built on jquery)
|
|
||||||
$().ready(function(){
|
|
||||||
$("#frame").splitter({
|
|
||||||
type: "v",
|
|
||||||
outline: true,
|
|
||||||
minLeft: 20,
|
|
||||||
sizeLeft: 810,
|
|
||||||
resizeToWidth: true,
|
|
||||||
anchorToWindow: true,
|
|
||||||
});
|
|
||||||
$("#rightcolumn").splitter({
|
|
||||||
type: "h",
|
|
||||||
outline: true,
|
|
||||||
sizeBottom: 180,
|
|
||||||
minTop: 100,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</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>
|
|
||||||
<a href="http://github.com/trebonian/visual6502">Source</a>
|
|
||||||
<a href="http://www.6502asm.com/">6502asm assembler</a>
|
|
||||||
<a href="http://www.e-tradition.net/bytes/6502/disassembler.html">e-tradition disassembler</a>
|
|
||||||
</span>
|
|
||||||
<div class="frame" id="frame">
|
|
||||||
<div class="leftcolumn" id="leftcolumn">
|
|
||||||
<div id="chipsurround" tabindex="1">
|
|
||||||
<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">
|
|
||||||
Use '>' to zoom in, '<' 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)
|
|
||||||
<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 action="javascript:hiliteNodeList();" />
|
|
||||||
<input type="button" value="Highlight:" onclick="hiliteNodeList();" />
|
|
||||||
<input type="text" id="HighlightThese" name="HighlightThese" value="" />
|
|
||||||
<input type="button" value="Clear Highlighting" onclick="clearHighlight();" />
|
|
||||||
<span class="animatebox">
|
|
||||||
Animate during simulation:
|
|
||||||
<input type="checkbox" id="animateModeCheckbox" onchange="updateChipLayoutAnimation(this.checked)"
|
|
||||||
/></span>
|
|
||||||
</form>
|
|
||||||
<form>
|
|
||||||
<input type="button" value="Hide Chip Layout" onclick="updateChipLayoutVisibility(false)" />
|
|
||||||
<a href="" id="linkHere" >Link to this location</a>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div> <!-- closing leftcolumn -->
|
|
||||||
<div class="rightcolumn" id="rightcolumn">
|
|
||||||
<div id="righttopdiv">
|
|
||||||
<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="morebuttons">
|
|
||||||
<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="forward"></a>
|
|
||||||
<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> <!-- buttons -->
|
|
||||||
<div class="status" id="status"><p>x: 0<br>y: 0</p>
|
|
||||||
</div> <!-- status -->
|
|
||||||
|
|
||||||
<div id="memtablediv">
|
|
||||||
<table class="memtable" id="memtable" tabindex="2"></table>
|
|
||||||
</div>
|
|
||||||
</div> <!-- righttopdiv -->
|
|
||||||
|
|
||||||
<div id="tracingdiv">
|
|
||||||
<div id="expertControlPanel">
|
|
||||||
<form action="javascript:updateLogList()">
|
|
||||||
<input type="button" value="Trace more" onclick="updateLoglevel(++loglevel)" />
|
|
||||||
<input type="button" value="Trace less" onclick="updateLoglevel(--loglevel)" />
|
|
||||||
<input type="button" value="Trace these too:" onclick="updateLogList()" />
|
|
||||||
<input type="text" id="LogThese" name="LogThese" value="" />
|
|
||||||
<input type="button" value="Log Up/Down" onclick="updateLogDirection();" />
|
|
||||||
<input type="button" value="Clear Log" onclick="updateLoglevel(loglevel)" />
|
|
||||||
</form>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
<div id="logstreamscroller">
|
|
||||||
<table class="logstream" id="logstream"></table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div> <!-- closing rightcolumn -->
|
|
||||||
</div> <!-- closing 'frame' div -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
432
expertWires.js
@ -1,432 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles
|
|
||||||
|
|
||||||
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=true;
|
|
||||||
var animateChipLayout = true;
|
|
||||||
var userCode=[];
|
|
||||||
var userResetLow;
|
|
||||||
var userResetHigh;
|
|
||||||
var headlessSteps=1000;
|
|
||||||
var noSimulation=false;
|
|
||||||
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');
|
|
||||||
// load the circuit before acting on URL parameters
|
|
||||||
setupNodes();
|
|
||||||
setupTransistors();
|
|
||||||
setupParams();
|
|
||||||
setupExpertMode();
|
|
||||||
detectOldBrowser();
|
|
||||||
setStatus('loading graphics...');
|
|
||||||
setTimeout(setup_part3, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setup_part3(){
|
|
||||||
if(chipLayoutIsVisible){
|
|
||||||
// if user requests no chip layout, we can skip all canvas operations
|
|
||||||
// which saves a lot of memory and allows us to run on small systems
|
|
||||||
updateChipLayoutVisibility(true);
|
|
||||||
}
|
|
||||||
setStatus('resetting 6502...');
|
|
||||||
setTimeout(setup_part4, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setup_part4(){
|
|
||||||
setupTable();
|
|
||||||
setupNodeNameList();
|
|
||||||
logThese=signalSet(loglevel);
|
|
||||||
loadProgram();
|
|
||||||
if(noSimulation){
|
|
||||||
stopChip();
|
|
||||||
running=undefined;
|
|
||||||
setStatus('Ready!');
|
|
||||||
} else {
|
|
||||||
initChip();
|
|
||||||
document.getElementById('stop').style.visibility = 'hidden';
|
|
||||||
go();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function detectOldBrowser(){
|
|
||||||
if(!("getBoundingClientRect" in document.documentElement)){
|
|
||||||
// simplify these functions (and adjust layout window position)
|
|
||||||
localx= function(el, gx){
|
|
||||||
return gx-el.offsetLeft;
|
|
||||||
}
|
|
||||||
localy= function(el, gy){
|
|
||||||
return gy-el.offsetTop;
|
|
||||||
}
|
|
||||||
document.getElementById('plain').style["float"]="right";
|
|
||||||
document.getElementById('chip').style.left=0;
|
|
||||||
document.getElementById('chip').style.top=0;
|
|
||||||
document.getElementById('chip').style.border=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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=="logmore" && value!=""){
|
|
||||||
updateLogList(value);
|
|
||||||
} else if(name=="headlesssteps" && parseInt(value)!=NaN){
|
|
||||||
headlessSteps=parseInt(value);
|
|
||||||
} else if(name=="graphics" && value.indexOf("f")==0){
|
|
||||||
updateChipLayoutVisibility(false);
|
|
||||||
} else if(name=="canvas" && parseInt(value)!=NaN){
|
|
||||||
grCanvasSize=value;
|
|
||||||
// suppress simulation (for layout viewing only on slow browsers)
|
|
||||||
} else if(name=="nosim" && value.indexOf("t")==0){
|
|
||||||
noSimulation=true;
|
|
||||||
} 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
|
|
||||||
// setup input pin events, breakpoints, watchpoints
|
|
||||||
if(name=="reset0" && parseInt(value)!=NaN){
|
|
||||||
clockTriggers[value]="setLow('res');";
|
|
||||||
} else if(name=="reset1" && parseInt(value)!=NaN){
|
|
||||||
clockTriggers[value]="setHigh('res');";
|
|
||||||
} 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
|
|
||||||
//
|
|
||||||
/////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
// these keyboard actions are primarily for the chip display
|
|
||||||
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);
|
|
||||||
// FIXME these keys are for the simulator (but not when focus is in a textbox)
|
|
||||||
else if(c=='n') stepForward();
|
|
||||||
else if(c=='p') stepBack();
|
|
||||||
}
|
|
||||||
|
|
||||||
// handler for mousedown events over chip display
|
|
||||||
// must handle click-to-select (and focus), and drag to pan
|
|
||||||
function mouseDown(e){
|
|
||||||
chipsurround.focus();
|
|
||||||
e.preventDefault();
|
|
||||||
moved=false;
|
|
||||||
dragMouseX = e.clientX;
|
|
||||||
dragMouseY = e.clientY;
|
|
||||||
chipsurround.onmousemove = function(e){mouseMove(e)};
|
|
||||||
chipsurround.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);
|
|
||||||
chipsurround.onmousemove = undefined;
|
|
||||||
chipsurround.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();
|
|
||||||
}
|
|
||||||
|
|
||||||
var highlightThese;
|
|
||||||
|
|
||||||
// flash some set of nodes according to user input
|
|
||||||
function hiliteNodeList(){
|
|
||||||
var tmplist = document.getElementById('HighlightThese').value.split(/[\s,]+/);
|
|
||||||
if(tmplist.length==0){
|
|
||||||
// request to highlight nothing, so switch off any signal highlighting
|
|
||||||
hiliteNode(-1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
highlightThese = [];
|
|
||||||
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")) {
|
|
||||||
highlightThese.push(value);
|
|
||||||
} else if(typeof nodenames[name] != "undefined") {
|
|
||||||
highlightThese.push(nodenames[name]);
|
|
||||||
}
|
|
||||||
// invalid input: how to tell the user?
|
|
||||||
}
|
|
||||||
if(highlightThese.length==0){
|
|
||||||
// all input rejected: how to tell the user?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
clearHighlight(); // nullify the simulation overlay (orange/purple)
|
|
||||||
hiliteNode(-1); // unhighlight all nodes
|
|
||||||
setTimeout("hiliteNode(highlightThese);", 400);
|
|
||||||
setTimeout("hiliteNode(-1);", 800);
|
|
||||||
setTimeout("hiliteNode(highlightThese);", 1200);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
logThese = signalSet(loglevel);
|
|
||||||
initLogbox(logThese);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupExpertMode(isOn){
|
|
||||||
document.getElementById('expertControlPanel').style.display = 'block';
|
|
||||||
if(loglevel==0)
|
|
||||||
updateLoglevel(1);
|
|
||||||
if(chipLayoutIsVisible)
|
|
||||||
document.getElementById('layoutControlPanel').style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
var chipsurround;
|
|
||||||
|
|
||||||
function updateChipLayoutVisibility(isOn){
|
|
||||||
chipLayoutIsVisible=isOn;
|
|
||||||
if(chipLayoutIsVisible) {
|
|
||||||
updateChipLayoutAnimation(true);
|
|
||||||
// resize the two panes appropriately
|
|
||||||
$("#frame").trigger("resize", [ 810 ]);
|
|
||||||
$("#rightcolumn").trigger("resize", [ 738 - 180 ]);
|
|
||||||
// replace the Show Chip button with the chip graphics
|
|
||||||
chipsurround=document.getElementById('chipsurround');
|
|
||||||
chipsurround.style.display = 'block';
|
|
||||||
document.getElementById('layoutControlPanel').style.display = 'block';
|
|
||||||
document.getElementById('nochip').style.display = 'none';
|
|
||||||
// allow the browser to respond while we load the graphics
|
|
||||||
setStatus('loading graphics...');
|
|
||||||
setTimeout(setupChipLayoutGraphics, 0);
|
|
||||||
} else {
|
|
||||||
// cannot animate the layout if there is no canvas
|
|
||||||
updateChipLayoutAnimation(false);
|
|
||||||
// resize the two panes appropriately
|
|
||||||
$("#frame").trigger("resize", [ 120 ]);
|
|
||||||
$("#rightcolumn").trigger("resize", [ 200 ]);
|
|
||||||
// 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';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
// grant focus to the chip display to enable zoom keys
|
|
||||||
chipsurround.focus();
|
|
||||||
chipsurround.onmousedown = function(e){mouseDown(e);};
|
|
||||||
chipsurround.onkeypress = function(e){handleKey(e);};
|
|
||||||
}
|
|
||||||
|
|
||||||
// utility function to save graphics pan and zoom
|
|
||||||
function whereAmIAsQuery(){
|
|
||||||
var w=whereAmI();
|
|
||||||
return "panx="+w[0].toFixed(1)+"&pany="+w[1].toFixed(1)+"&zoom="+w[2].toFixed(1);
|
|
||||||
}
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 321 B |
Before Width: | Height: | Size: 319 B |
27
index.html
@ -2,25 +2,17 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>Visual 6502 in JavaScript</title>
|
<title>Visual 6502 in JavaScript</title>
|
||||||
|
<style type="text/css">@import "wires.css";</style>
|
||||||
<!-- by default, index.html will run in kiosk mode -->
|
|
||||||
<style type="text/css">@import "kiosk.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="kioskWires.js"></script>
|
|
||||||
<script src="wires.js"></script>
|
<script src="wires.js"></script>
|
||||||
<script src="chipsim.js"></script>
|
<script src="chipsim.js"></script>
|
||||||
<script src="memtable.js"></script>
|
<script src="memtable.js"></script>
|
||||||
<script src="testprogram.js"></script>
|
|
||||||
<script src="macros.js"></script>
|
<script src="macros.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
function handleOnload() {
|
function handleOnload() {
|
||||||
// two checks and fixes here:
|
|
||||||
// - replace the dynamic content with an image if running older versions of IE
|
|
||||||
// - redirect to the expert page if we find any query parameters
|
|
||||||
//
|
|
||||||
/MSIE (\d+\.\d+);/.test(navigator.appVersion);
|
/MSIE (\d+\.\d+);/.test(navigator.appVersion);
|
||||||
IEVersion=Number(RegExp.$1);
|
IEVersion=Number(RegExp.$1);
|
||||||
if((navigator.appName == 'Microsoft Internet Explorer') && (IEVersion<9)){
|
if((navigator.appName == 'Microsoft Internet Explorer') && (IEVersion<9)){
|
||||||
@ -28,20 +20,7 @@ function handleOnload() {
|
|||||||
'<p>Sorry, '+navigator.appName+' not supported - showing you a picture instead!</p>';
|
'<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>';
|
document.getElementById('frame').innerHTML='<a href="browsertrouble.html"><img src="images/jssim2.png" style="border:10px"></a>';
|
||||||
}else{
|
}else{
|
||||||
var suffix=location.search;
|
setTimeout(setup,200);
|
||||||
var path=location.pathname;
|
|
||||||
// ensure we always have a trailing slash
|
|
||||||
path=path.replace("index.html","").replace(/\/?$/,"/");
|
|
||||||
|
|
||||||
if (suffix != "") {
|
|
||||||
// redirect to the expert page
|
|
||||||
var prefix=location.protocol+"//"+location.host+path;
|
|
||||||
window.location.replace(prefix+"expert.html"+suffix);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// normal case: start the simulator
|
|
||||||
setTimeout(setup,200);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -99,7 +78,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
|
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
|
and <a href="http://www.e-tradition.net/bytes/6502/disassembler.html">disassembler</a> from e-tradition.net
|
||||||
<br />
|
<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="/stage/JSSim/index.html">Experimenter's (Beta) version</a>.
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
196
kioskWires.js
@ -1,196 +0,0 @@
|
|||||||
/*
|
|
||||||
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 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];
|
|
||||||
}
|
|
||||||
}
|
|
329
macros.js
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles
|
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -21,79 +21,30 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var memory = Array();
|
var memory = Array();
|
||||||
|
var code = [0xa9, 0x00, 0x20, 0x10, 0x00, 0x4c, 0x02, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0xe8, 0x88, 0xe6, 0x40, 0x38, 0x69, 0x02, 0x60];
|
||||||
var cycle = 0;
|
var cycle = 0;
|
||||||
var trace = Array();
|
var trace = Array();
|
||||||
var logstream = Array();
|
|
||||||
var running = false;
|
var running = false;
|
||||||
var logThese=[];
|
|
||||||
var presetLogLists=[
|
|
||||||
['cycle'],
|
|
||||||
['ab','db','rw','sync','pc','a','x','y','s','p'],
|
|
||||||
['ir','tcstate','pd'],
|
|
||||||
['adl','adh','sb','alu'],
|
|
||||||
['alucin','alua','alub','alucout','aluvout','dasb'],
|
|
||||||
['plaOutputs'],
|
|
||||||
['idb','dor'],
|
|
||||||
['irq','nmi','res'],
|
|
||||||
];
|
|
||||||
|
|
||||||
function loadProgram(){
|
function go(n){
|
||||||
// a moderate size of static testprogram might be loaded
|
for(var i=0;i<code.length;i++){
|
||||||
if(testprogram.length!=0 && testprogramAddress != undefined)
|
mWrite(i, code[i]);
|
||||||
for(var i=0;testprogram[i]!=undefined;i++){
|
setCellValue(i, code[i]);
|
||||||
var a=testprogramAddress+i;
|
}
|
||||||
mWrite(a, testprogram[i]);
|
mWrite(0xfffc, 0x00);
|
||||||
if(a<0x200)
|
mWrite(0xfffd, 0x00);
|
||||||
setCellValue(a, testprogram[i]);
|
steps();
|
||||||
}
|
|
||||||
// a small test program or patch might be passed in the URL
|
|
||||||
if(userCode.length!=0)
|
|
||||||
for(var i=0;i<userCode.length;i++){
|
|
||||||
if(userCode[i] != undefined){
|
|
||||||
mWrite(i, userCode[i]);
|
|
||||||
if(i<0x200)
|
|
||||||
setCellValue(i, userCode[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// default reset vector will be 0x0000 because undefined memory reads as zero
|
|
||||||
if(userResetLow!=undefined)
|
|
||||||
mWrite(0xfffc, userResetLow);
|
|
||||||
if(userResetHigh!=undefined)
|
|
||||||
mWrite(0xfffd, userResetHigh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function go(){
|
function steps(){
|
||||||
if(typeof userSteps != "undefined"){
|
|
||||||
if(--userSteps==0){
|
|
||||||
running=false;
|
|
||||||
userSteps=undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(running) {
|
if(running) {
|
||||||
step();
|
step();
|
||||||
setTimeout(go, 0); // schedule the next poll
|
setTimeout(steps, 0); // schedule the next poll
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function goUntilSync(){
|
|
||||||
halfStep();
|
|
||||||
while(!isNodeHigh(nodenames['sync']) || isNodeHigh(nodenames['clk0']))
|
|
||||||
halfStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
function goUntilSyncOrWrite(){
|
|
||||||
halfStep();
|
|
||||||
cycle++;
|
|
||||||
while(
|
|
||||||
!isNodeHigh(nodenames['clk0']) ||
|
|
||||||
( !isNodeHigh(nodenames['sync']) && isNodeHigh(nodenames['rw']) )
|
|
||||||
) {
|
|
||||||
halfStep();
|
|
||||||
cycle++;
|
|
||||||
}
|
|
||||||
chipStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
function testNMI(n){
|
function testNMI(n){
|
||||||
initChip();
|
initChip();
|
||||||
|
|
||||||
@ -134,17 +85,12 @@ function testNMI(n){
|
|||||||
for(var i=0;i<16;i++){step();}
|
for(var i=0;i<16;i++){step();}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function initChip(){
|
function initChip(){
|
||||||
var start = now();
|
var start = now();
|
||||||
for(var nn in nodes) {
|
for(var nn in nodes) nodes[nn].state = 'fl';
|
||||||
nodes[nn].state = false;
|
nodes[ngnd].state = 'gnd';
|
||||||
nodes[nn].float = true;
|
nodes[npwr].state = 'vcc';
|
||||||
}
|
|
||||||
|
|
||||||
nodes[ngnd].state = false;
|
|
||||||
nodes[ngnd].float = false;
|
|
||||||
nodes[npwr].state = true;
|
|
||||||
nodes[npwr].float = false;
|
|
||||||
for(var tn in transistors) transistors[tn].on = false;
|
for(var tn in transistors) transistors[tn].on = false;
|
||||||
setLow('res');
|
setLow('res');
|
||||||
setLow('clk0');
|
setLow('clk0');
|
||||||
@ -153,70 +99,32 @@ function initChip(){
|
|||||||
recalcNodeList(allNodes());
|
recalcNodeList(allNodes());
|
||||||
for(var i=0;i<8;i++){setHigh('clk0'), setLow('clk0');}
|
for(var i=0;i<8;i++){setHigh('clk0'), setLow('clk0');}
|
||||||
setHigh('res');
|
setHigh('res');
|
||||||
for(var i=0;i<18;i++){halfStep();} // avoid updating graphics and trace buffer before user code
|
for(var i=0;i<18;i++){resetStep();}
|
||||||
refresh();
|
refresh();
|
||||||
cycle = 0;
|
cycle = 0;
|
||||||
trace = Array();
|
trace = Array();
|
||||||
if(typeof expertMode != "undefined")
|
|
||||||
updateLogList();
|
|
||||||
chipStatus();
|
chipStatus();
|
||||||
if(ctrace)console.log('initChip done after', now()-start);
|
if(ctrace)console.log('initChip done after', now()-start);
|
||||||
}
|
}
|
||||||
|
|
||||||
function signalSet(n){
|
|
||||||
var signals=[];
|
|
||||||
for (var i=0; (i<=n)&&(i<presetLogLists.length) ; i++){
|
|
||||||
for (var j=0; j<presetLogLists[i].length; j++){
|
|
||||||
signals.push(presetLogLists[i][j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return signals;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateLogList(names){
|
|
||||||
// user supplied a list of signals, which we append to the set defined by loglevel
|
|
||||||
logThese = signalSet(loglevel);
|
|
||||||
if(typeof names == "undefined")
|
|
||||||
// this is a UI call - read the text input
|
|
||||||
names = document.getElementById('LogThese').value;
|
|
||||||
else
|
|
||||||
// this is an URL call - update the text input box
|
|
||||||
document.getElementById('LogThese').value = names;
|
|
||||||
names = names.split(/[\s,]+/);
|
|
||||||
for(var i=0;i<names.length;i++){
|
|
||||||
// could be a signal name, a node number, or a special name
|
|
||||||
if(typeof busToString(names[i]) != "undefined")
|
|
||||||
logThese.push(names[i]);
|
|
||||||
}
|
|
||||||
initLogbox(logThese);
|
|
||||||
}
|
|
||||||
|
|
||||||
var traceChecksum='';
|
|
||||||
var goldenChecksum;
|
|
||||||
|
|
||||||
// simulate a single clock phase, updating trace and highlighting layout
|
|
||||||
function step(){
|
function step(){
|
||||||
var s=stateString();
|
trace[cycle]= {chip: stateString(), mem: getMem()};
|
||||||
var m=getMem();
|
|
||||||
trace[cycle]= {chip: s, mem: m};
|
|
||||||
if(goldenChecksum != undefined)
|
|
||||||
traceChecksum=adler32(traceChecksum+s+m.slice(0,511).toString(16));
|
|
||||||
halfStep();
|
halfStep();
|
||||||
if(animateChipLayout)
|
|
||||||
refresh();
|
|
||||||
cycle++;
|
cycle++;
|
||||||
chipStatus();
|
chipStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
// triggers for breakpoints, watchpoints, input pin events
|
|
||||||
clockTriggers={};
|
|
||||||
|
|
||||||
// simulate a single clock phase with no update to graphics or trace
|
|
||||||
function halfStep(){
|
function halfStep(){
|
||||||
var clk = isNodeHigh(nodenames['clk0']);
|
var clk = isNodeHigh(nodenames['clk0']);
|
||||||
eval(clockTriggers[cycle]); // usually undefined, no measurable performance loss
|
|
||||||
if (clk) {setLow('clk0'); handleBusRead(); }
|
if (clk) {setLow('clk0'); handleBusRead(); }
|
||||||
else {setHigh('clk0'); handleBusWrite();}
|
else {setHigh('clk0'); handleBusWrite();}
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetStep(){
|
||||||
|
var clk = isNodeHigh(nodenames['clk0']);
|
||||||
|
if (clk) {setLow('clk0'); handleBusRead(); }
|
||||||
|
else {setHigh('clk0'); handleBusWrite();}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBusRead(){
|
function handleBusRead(){
|
||||||
@ -242,7 +150,7 @@ function readPstring(){
|
|||||||
var result;
|
var result;
|
||||||
result = (isNodeHigh(nodenames['p7'])?'N':'n') +
|
result = (isNodeHigh(nodenames['p7'])?'N':'n') +
|
||||||
(isNodeHigh(nodenames['p6'])?'V':'v') +
|
(isNodeHigh(nodenames['p6'])?'V':'v') +
|
||||||
'‑' + // non-breaking hyphen
|
'-' +
|
||||||
(isNodeHigh(nodenames['p3'])?'B':'b') +
|
(isNodeHigh(nodenames['p3'])?'B':'b') +
|
||||||
(isNodeHigh(nodenames['p3'])?'D':'d') +
|
(isNodeHigh(nodenames['p3'])?'D':'d') +
|
||||||
(isNodeHigh(nodenames['p2'])?'I':'i') +
|
(isNodeHigh(nodenames['p2'])?'I':'i') +
|
||||||
@ -255,20 +163,6 @@ function readPC(){return (readBits('pch', 8)<<8) + readBits('pcl', 8);}
|
|||||||
function readPCL(){return readBits('pcl', 8);}
|
function readPCL(){return readBits('pcl', 8);}
|
||||||
function readPCH(){return readBits('pch', 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(var i in nodenamelist){
|
|
||||||
if(r.test(nodenamelist[i])) {
|
|
||||||
if(isNodeHigh(nodenames[nodenamelist[i]]))
|
|
||||||
pla.push(nodenamelist[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pla;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readBit(name){
|
function readBit(name){
|
||||||
return isNodeHigh(nodenames[name])?1:0;
|
return isNodeHigh(nodenames[name])?1:0;
|
||||||
}
|
}
|
||||||
@ -281,45 +175,6 @@ function readBits(name, n){
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function busToString(busname){
|
|
||||||
// takes a signal name or prefix
|
|
||||||
// returns an appropriate string representation
|
|
||||||
if(busname=='cycle')
|
|
||||||
return cycle>>1;
|
|
||||||
if(busname=='pc')
|
|
||||||
return busToHex('pch') + busToHex('pcl');
|
|
||||||
if(busname=='p')
|
|
||||||
return readPstring();
|
|
||||||
if(busname=='tcstate')
|
|
||||||
return ['clock1','clock2','t2','t3','t4','t5'].map(busToHex).join("");
|
|
||||||
if(busname=='plaOutputs')
|
|
||||||
return listActivePlaOutputs();
|
|
||||||
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]');
|
|
||||||
for(var i in nodenamelist){
|
|
||||||
if(r.test(nodenamelist[i])) {
|
|
||||||
width++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(width==0) {
|
|
||||||
// not a bus, so could be a signal, a nodenumber or a mistake
|
|
||||||
if(typeof nodenames[busname] != "undefined")
|
|
||||||
return isNodeHigh(nodenames[busname])?"1":"0";
|
|
||||||
if((parseInt(busname)!=NaN) && (typeof nodes[busname] != "undefined"))
|
|
||||||
return isNodeHigh(busname)?"1":"0";
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if(width>16)
|
|
||||||
return undefined;
|
|
||||||
// finally, convert from logic values to hex
|
|
||||||
return (0x10000+readBits(busname,width)).toString(16).slice(-(width-1)/4-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeDataBus(x){
|
function writeDataBus(x){
|
||||||
var recalcs = Array();
|
var recalcs = Array();
|
||||||
for(var i=0;i<8;i++){
|
for(var i=0;i<8;i++){
|
||||||
@ -340,11 +195,12 @@ function mRead(a){
|
|||||||
|
|
||||||
function mWrite(a, d){memory[a]=d;}
|
function mWrite(a, d){memory[a]=d;}
|
||||||
|
|
||||||
|
|
||||||
function clkNodes(){
|
function clkNodes(){
|
||||||
var res = Array();
|
var res = Array();
|
||||||
res.push(943);
|
res.push(943);
|
||||||
for(var i in nodes[943].gates){
|
for(var i in nodes[943].gates){
|
||||||
var t = nodes[943].gates[i];
|
var t = transistors[nodes[943].gates[i]];
|
||||||
if(t.c1==npwr) res.push(t.c2);
|
if(t.c1==npwr) res.push(t.c2);
|
||||||
if(t.c2==npwr) res.push(t.c1);
|
if(t.c2==npwr) res.push(t.c1);
|
||||||
}
|
}
|
||||||
@ -356,10 +212,8 @@ function runChip(){
|
|||||||
var stop = document.getElementById('stop');
|
var stop = document.getElementById('stop');
|
||||||
start.style.visibility = 'hidden';
|
start.style.visibility = 'hidden';
|
||||||
stop.style.visibility = 'visible';
|
stop.style.visibility = 'visible';
|
||||||
if(typeof running == "undefined")
|
|
||||||
initChip();
|
|
||||||
running = true;
|
running = true;
|
||||||
go();
|
steps();
|
||||||
}
|
}
|
||||||
|
|
||||||
function stopChip(){
|
function stopChip(){
|
||||||
@ -377,8 +231,6 @@ function resetChip(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function stepForward(){
|
function stepForward(){
|
||||||
if(typeof running == "undefined")
|
|
||||||
initChip();
|
|
||||||
stopChip();
|
stopChip();
|
||||||
step();
|
step();
|
||||||
}
|
}
|
||||||
@ -407,95 +259,50 @@ function chipStatus(){
|
|||||||
' Y:' + hexByte(readY()) +
|
' Y:' + hexByte(readY()) +
|
||||||
' SP:' + hexByte(readSP()) +
|
' SP:' + hexByte(readSP()) +
|
||||||
' ' + readPstring();
|
' ' + readPstring();
|
||||||
var chk='';
|
var machine3 =
|
||||||
if(goldenChecksum != undefined)
|
' Sync:' + readBit('sync')
|
||||||
chk=" Chk:" + traceChecksum + ((traceChecksum==goldenChecksum)?" OK":" no match");
|
' IRQ:' + readBit('irq') +
|
||||||
setStatus(machine1, machine2, "Hz: " + estimatedHz().toFixed(1) + chk);
|
' NMI:' + readBit('nmi');
|
||||||
if (loglevel>0) {
|
var machine4 =
|
||||||
updateLogbox(logThese);
|
' IR:' + hexByte(255 - readBits('notir', 8)) +
|
||||||
|
' idl:' + hexByte(255 - readBits('idl', 8)) +
|
||||||
|
' alu:' + hexByte(255 - readBits('alu', 8)) +
|
||||||
|
' TCstate:' + readBit('clock1') + readBit('clock2') +
|
||||||
|
readBit('t2') + readBit('t3') + readBit('t4') + readBit('t5');
|
||||||
|
var machine5 =
|
||||||
|
' notRdy0:' + readBit('notRdy0') +
|
||||||
|
' fetch:' + readBit('fetch') +
|
||||||
|
' clearIR:' + readBit('clearIR') +
|
||||||
|
' D1x1:' + readBit('D1x1');
|
||||||
|
setStatus(machine1 + "<br>" + machine2 + "<br>Hz: " + estimatedHz().toFixed(1));
|
||||||
|
if (loglevel>2 && ctrace) {
|
||||||
|
console.log(machine1 + " " + machine2 + " " + machine3 + " " + machine4 + " " + machine5);
|
||||||
}
|
}
|
||||||
selectCell(ab);
|
selectCell(ab);
|
||||||
}
|
}
|
||||||
|
|
||||||
function goFor(){
|
|
||||||
var n = headlessSteps;
|
|
||||||
estimatedHz1();
|
|
||||||
while(n--){
|
|
||||||
halfStep();
|
|
||||||
cycle++;
|
|
||||||
}
|
|
||||||
estimatedHz1();
|
|
||||||
chipStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
var prevHzTimeStamp=0;
|
var prevHzTimeStamp=0;
|
||||||
var prevHzCycleCount=0;
|
var prevHzCycleCount=0;
|
||||||
var prevHzEstimate1=1;
|
var prevHzEstimate1=1;
|
||||||
var prevHzEstimate2=1;
|
var prevHzEstimate2=1;
|
||||||
var HzSamplingRate=10;
|
var HzSamplingRate=10;
|
||||||
|
|
||||||
function estimatedHz(){
|
function estimatedHz(){
|
||||||
if(cycle%HzSamplingRate!=3)
|
if(cycle%HzSamplingRate!=3)
|
||||||
return prevHzEstimate1;
|
return prevHzEstimate1;
|
||||||
return estimatedHz1();
|
var HzTimeStamp = now();
|
||||||
|
var HzEstimate = (cycle-prevHzCycleCount+.01)/(HzTimeStamp-prevHzTimeStamp+.01);
|
||||||
|
HzEstimate=HzEstimate*1000/2; // convert from phases per millisecond to Hz
|
||||||
|
if(HzEstimate<5)
|
||||||
|
HzSamplingRate=5; // quicker
|
||||||
|
if(HzEstimate>10)
|
||||||
|
HzSamplingRate=10; // smoother
|
||||||
|
prevHzEstimate2=prevHzEstimate1;
|
||||||
|
prevHzEstimate1=(HzEstimate+prevHzEstimate1+prevHzEstimate2)/3; // wrong way to average speeds
|
||||||
|
prevHzTimeStamp=HzTimeStamp;
|
||||||
|
prevHzCycleCount=cycle;
|
||||||
|
return prevHzEstimate1
|
||||||
}
|
}
|
||||||
|
|
||||||
function estimatedHz1(){
|
|
||||||
var HzTimeStamp = now();
|
|
||||||
var HzEstimate = (cycle-prevHzCycleCount+.01)/(HzTimeStamp-prevHzTimeStamp+.01);
|
|
||||||
HzEstimate=HzEstimate*1000/2; // convert from phases per millisecond to Hz
|
|
||||||
if(HzEstimate<5)
|
|
||||||
HzSamplingRate=5; // quicker
|
|
||||||
if(HzEstimate>10)
|
|
||||||
HzSamplingRate=10; // smoother
|
|
||||||
prevHzEstimate2=prevHzEstimate1;
|
|
||||||
prevHzEstimate1=(HzEstimate+prevHzEstimate1+prevHzEstimate2)/3; // wrong way to average speeds
|
|
||||||
prevHzTimeStamp=HzTimeStamp;
|
|
||||||
prevHzCycleCount=cycle;
|
|
||||||
return prevHzEstimate1
|
|
||||||
}
|
|
||||||
|
|
||||||
function initLogbox(names){
|
|
||||||
var logbox=document.getElementById('logstream');
|
|
||||||
if(logbox==null)return;
|
|
||||||
|
|
||||||
logStream = [];
|
|
||||||
logStream.push("<td>" + names.join("</td><td>") + "</td>");
|
|
||||||
logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>";
|
|
||||||
}
|
|
||||||
|
|
||||||
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=[];
|
|
||||||
// the first element is the header so we can't reverse()
|
|
||||||
for (var i=1;i<logStream.length;i++) {
|
|
||||||
loglines.unshift(logStream[i]);
|
|
||||||
}
|
|
||||||
loglines.unshift(logStream[0]);
|
|
||||||
logStream=loglines;
|
|
||||||
logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>";
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the table of signal values, by prepending or appending
|
|
||||||
function updateLogbox(names){
|
|
||||||
var logbox=document.getElementById('logstream');
|
|
||||||
var signals=[];
|
|
||||||
|
|
||||||
for(i in names){
|
|
||||||
signals.push(busToString(names[i]));
|
|
||||||
}
|
|
||||||
if(logboxAppend)
|
|
||||||
logStream.push("<td>" + signals.join("</td><td>") + "</td>");
|
|
||||||
else
|
|
||||||
logStream.splice(1,0,"<td>" + signals.join("</td><td>") + "</td>");
|
|
||||||
|
|
||||||
logbox.innerHTML = "<tr>"+logStream.join("</tr><tr>")+"</tr>";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMem(){
|
function getMem(){
|
||||||
var res = Array();
|
var res = Array();
|
||||||
@ -509,13 +316,3 @@ function setMem(arr){
|
|||||||
|
|
||||||
function hexWord(n){return (0x10000+n).toString(16).substring(1)}
|
function hexWord(n){return (0x10000+n).toString(16).substring(1)}
|
||||||
function hexByte(n){return (0x100+n).toString(16).substring(1)}
|
function hexByte(n){return (0x100+n).toString(16).substring(1)}
|
||||||
|
|
||||||
function adler32(x){
|
|
||||||
var a=1;
|
|
||||||
var b=0;
|
|
||||||
for(var i=0;i<x.length;i++){
|
|
||||||
a=(a+x.charCodeAt(i))%65521;
|
|
||||||
b=(b+a)%65521;
|
|
||||||
}
|
|
||||||
return (0x100000000+(b<<16)+a).toString(16).slice(-8);
|
|
||||||
}
|
|
||||||
|
@ -59,9 +59,7 @@ function cellKeydown(e){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setCellValue(n, val){
|
function setCellValue(n, val){
|
||||||
if(val==undefined)
|
val%=256;
|
||||||
val=0x00;
|
|
||||||
val%=256;
|
|
||||||
cellEl(n).val=val;
|
cellEl(n).val=val;
|
||||||
cellEl(n).innerHTML=hexByte(val);
|
cellEl(n).innerHTML=hexByte(val);
|
||||||
}
|
}
|
||||||
@ -73,7 +71,7 @@ function selectCell(n){
|
|||||||
if(n>=0x200) return;
|
if(n>=0x200) return;
|
||||||
cellEl(n).style.background = '#ff8';
|
cellEl(n).style.background = '#ff8';
|
||||||
selected = n;
|
selected = n;
|
||||||
table.onkeydown = function(e){cellKeydown(e);};
|
window.onkeydown = function(e){cellKeydown(e);};
|
||||||
}
|
}
|
||||||
|
|
||||||
function unselectCell(){
|
function unselectCell(){
|
||||||
|
292
nodenames.js
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles, Segher Boessenkool
|
Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -147,8 +147,8 @@ notir5: 1394,
|
|||||||
notir6: 895,
|
notir6: 895,
|
||||||
notir7: 1320,
|
notir7: 1320,
|
||||||
irline3: 996, // internal signal: PLA input - ir0 AND ir1
|
irline3: 996, // internal signal: PLA input - ir0 AND ir1
|
||||||
clock1: 1536, // internal state: timing control
|
clock1: 156, // internal state: timing control
|
||||||
clock2: 156, // internal state: timing control
|
clock2: 1536, // internal state: timing control
|
||||||
t2: 971, // internal state: timing control
|
t2: 971, // internal state: timing control
|
||||||
t3: 1567,
|
t3: 1567,
|
||||||
t4: 690,
|
t4: 690,
|
||||||
@ -250,22 +250,14 @@ dor4: 1088,
|
|||||||
dor5: 1453,
|
dor5: 1453,
|
||||||
dor6: 1415,
|
dor6: 1415,
|
||||||
dor7: 63,
|
dor7: 63,
|
||||||
pd0: 1622, // internal state: predecode register output (anded with not ClearIR)
|
pd0: 758, // internal state: predecode register
|
||||||
pd1: 809,
|
pd1: 361,
|
||||||
pd2: 1671,
|
pd2: 955,
|
||||||
pd3: 1587,
|
pd3: 894,
|
||||||
pd4: 540,
|
pd4: 369,
|
||||||
pd5: 667,
|
pd5: 829,
|
||||||
pd6: 1460,
|
pd6: 1669,
|
||||||
pd7: 1410,
|
pd7: 1690,
|
||||||
notpd0: 758, // internal state: predecode register (storage node)
|
|
||||||
notpd1: 361,
|
|
||||||
notpd2: 955,
|
|
||||||
notpd3: 894,
|
|
||||||
notpd4: 369,
|
|
||||||
notpd5: 829,
|
|
||||||
notpd6: 1669,
|
|
||||||
notpd7: 1690,
|
|
||||||
notRdy0: 248, // internal signal: global pipeline control
|
notRdy0: 248, // internal signal: global pipeline control
|
||||||
Reset0: 67, // internal signal: retimed reset from pin
|
Reset0: 67, // internal signal: retimed reset from pin
|
||||||
C1x5Reset: 926, // retimed and pipelined reset in progress
|
C1x5Reset: 926, // retimed and pipelined reset in progress
|
||||||
@ -280,159 +272,159 @@ H1x1: 1042, // internal signal: drive status byte onto databus
|
|||||||
|
|
||||||
// internal signal: pla outputs block 1 (west/left edge of die)
|
// internal signal: pla outputs block 1 (west/left edge of die)
|
||||||
// often 130 pla outputs are mentioned - we have 131 here
|
// often 130 pla outputs are mentioned - we have 131 here
|
||||||
"op-sty/cpy-mem": 1601, // pla0
|
pla0: 1601,
|
||||||
"op-T3-ind-y": 60, // pla1
|
pla1: 60,
|
||||||
"op-T2-abs-y": 1512, // pla2
|
pla2: 1512,
|
||||||
"op-T0-iny/dey": 382, // pla3
|
pla3: 382,
|
||||||
"x-op-T0-tya": 1173, // pla4
|
pla4: 1173,
|
||||||
"op-T0-cpy/iny": 1233, // pla5
|
pla5: 1233,
|
||||||
|
|
||||||
// internal signal: pla outputs block 2
|
// internal signal: pla outputs block 2
|
||||||
"op-T2-idx-x-xy": 258, // pla6
|
pla6: 258,
|
||||||
"op-xy": 1562, // pla7
|
pla7: 1562,
|
||||||
"op-T2-ind-x": 84, // pla8
|
pla8: 84,
|
||||||
"x-op-T0-txa": 1543, // pla9
|
pla9: 1543,
|
||||||
"op-T0-dex": 76, // pla10
|
pla10: 76,
|
||||||
"op-T0-cpx/inx": 1658, // pla11
|
pla11: 1658,
|
||||||
"op-from-x": 1540, // pla12
|
pla12: 1540,
|
||||||
"op-T0-txs": 245, // pla13
|
pla13: 245,
|
||||||
"op-T0-ldx/tax/tsx": 985, // pla14
|
pla14: 985,
|
||||||
"op-T+-dex": 786, // pla15
|
pla15: 786,
|
||||||
"op-T+-inx": 1664, // pla16
|
pla16: 1664,
|
||||||
"op-T0-tsx": 682, // pla17
|
pla17: 682,
|
||||||
"op-T+-iny/dey": 1482, // pla18
|
pla18: 1482,
|
||||||
"op-T0-ldy-mem": 665, // pla19
|
pla19: 665,
|
||||||
"op-T0-tay/ldy-not-idx": 286, // pla20
|
pla20: 286,
|
||||||
|
|
||||||
// internal signal: pla outputs block 3
|
// internal signal: pla outputs block 3
|
||||||
// not pla, feed through
|
// not pla, feed through
|
||||||
"op-T0-jsr": 271, // pla21
|
pla21: 271,
|
||||||
"op-T5-brk": 370, // pla22
|
pla22: 370,
|
||||||
"op-T0-php/pha": 552, // pla23
|
pla23: 552,
|
||||||
"op-T4-rts": 1612, // pla24
|
pla24: 1612,
|
||||||
"op-T3-plp/pla": 1487, // pla25
|
pla25: 1487,
|
||||||
"op-T5-rti": 784, // pla26
|
pla26: 784,
|
||||||
"op-ror": 244, // pla27
|
pla27: 244,
|
||||||
"op-T2": 788, // pla28
|
pla28: 788,
|
||||||
"op-T0-eor": 1623, // pla29
|
pla29: 1623,
|
||||||
"op-jmp": 764, // pla30
|
pla30: 764,
|
||||||
"op-T2-abs": 1057, // pla31
|
pla31: 1057,
|
||||||
"op-T0-ora": 403, // pla32
|
pla32: 403,
|
||||||
"op-T2-ADL/ADD":204, // pla33
|
pla33: 204,
|
||||||
"op-T0":1273, // pla34
|
pla34: 1273,
|
||||||
"op-T2-stack":1582, // pla35
|
pla35: 1582,
|
||||||
"op-T3-stack/bit/jmp":1031, // pla36
|
pla36: 1031,
|
||||||
|
|
||||||
// internal signal: pla outputs block 4
|
// internal signal: pla outputs block 4
|
||||||
"op-T4-brk/jsr":804, // pla37
|
pla37: 804,
|
||||||
"op-T4-rti":1311, // pla38
|
pla38: 1311,
|
||||||
"op-T3-ind-x":1428, // pla39
|
pla39: 1428,
|
||||||
"op-T4-ind-y":492, // pla40
|
pla40: 492,
|
||||||
"op-T2-ind-y":1204, // pla41
|
pla41: 1204,
|
||||||
"op-T3-abs-idx":58, // pla42
|
pla42: 58,
|
||||||
"op-plp/pla":1520, // pla43
|
pla43: 1520,
|
||||||
"op-inc/nop":324, // pla44
|
pla44: 324,
|
||||||
"op-T4-ind-x":1259, // pla45
|
pla45: 1259,
|
||||||
"x-op-T3-ind-y":342, // pla46
|
pla46: 342,
|
||||||
"op-rti/rts":857, // pla47
|
pla47: 857,
|
||||||
"op-T2-jsr":712, // pla48
|
pla48: 712,
|
||||||
"op-T0-cpx/cpy/inx/iny":1337, // pla49
|
pla49: 1337,
|
||||||
"op-T0-cmp":1355, // pla50
|
pla50: 1355,
|
||||||
"op-T0-sbc":787, // pla51 // 52:111XXXXX 1 0 T0SBC
|
pla51_T0SBC: 787, // 52:111XXXXX 1 0 T0SBC
|
||||||
"op-T0-adc/sbc":575, // pla52 // 51:X11XXXXX 1 0 T0ADCSBC
|
pla52_T0ADCSBC: 575, // 51:X11XXXXX 1 0 T0ADCSBC
|
||||||
"op-rol/ror":1466, // pla53
|
pla53: 1466,
|
||||||
|
|
||||||
// internal signal: pla outputs block 5
|
// internal signal: pla outputs block 5
|
||||||
"op-T3-jmp":1381, // pla54
|
pla54: 1381,
|
||||||
"op-shift":546, // pla55
|
pla55: 546,
|
||||||
"op-T5-jsr":776, // pla56
|
pla56: 776,
|
||||||
"op-T2-stack-access":157, // pla57
|
pla57: 157,
|
||||||
"op-T0-tya":257, // pla58
|
pla58: 257,
|
||||||
"op-T+-ora/and/eor/adc":1243, // pla59
|
pla59: 1243,
|
||||||
"op-T+-adc/sbc":822, // pla60
|
pla60: 822,
|
||||||
"op-T+-shift-a":1324, // pla61
|
pla61: 1324,
|
||||||
"op-T0-txa":179, // pla62
|
pla62: 179,
|
||||||
"op-T0-pla":131, // pla63
|
pla63: 131,
|
||||||
"op-T0-lda":1420, // pla64
|
pla64: 1420,
|
||||||
"op-T0-acc":1342, // pla65
|
pla65: 1342,
|
||||||
"op-T0-tay":4, // pla66
|
pla66: 4,
|
||||||
"op-T0-shift-a":1396, // pla67
|
pla67: 1396,
|
||||||
"op-T0-tax":167, // pla68
|
pla68: 167,
|
||||||
"op-T0-bit":303, // pla69
|
pla69: 303,
|
||||||
"op-T0-and":1504, // pla70
|
pla70: 1504,
|
||||||
"op-T4-abs-idx":354, // pla71
|
pla71: 354,
|
||||||
"op-T5-ind-y":1168, // pla72
|
pla72: 1168,
|
||||||
|
|
||||||
// internal signal: pla outputs block 6
|
// internal signal: pla outputs block 6
|
||||||
"op-branch-done":1721, // pla73 // has extra non-pla input
|
pla73: 1721, // has extra non-pla input
|
||||||
"op-T2-pha":1086, // pla74
|
pla74: 1086,
|
||||||
"op-T0-shift-right-a":1074, // pla75
|
pla75: 1074,
|
||||||
"op-shift-right":1246, // pla76
|
pla76: 1246,
|
||||||
"op-T2-brk":487, // pla77
|
pla77: 487,
|
||||||
"op-T3-jsr":579, // pla78
|
pla78: 579,
|
||||||
"op-sta/cmp":145, // pla79
|
pla79: 145,
|
||||||
"op-T2-branch":1239, // pla80 // T2BR, 83 for Balazs
|
pla80_T2BR: 1239, // T2BR, 83 for Balazs
|
||||||
"op-T2-zp/zp-idx":285, // pla81
|
pla81: 285,
|
||||||
// not pla, feed through
|
// not pla, feed through
|
||||||
// not pla, feed through
|
// not pla, feed through
|
||||||
"op-T2-ind":1524, // pla82
|
pla82: 1524,
|
||||||
"op-T2-abs-access":273, // pla83 // has extra pulldown: pla97
|
pla83: 273, // has extra pulldown: pla97
|
||||||
"op-T5-rts":0, // pla84
|
pla84: 0,
|
||||||
"op-T4":341, // pla85
|
pla85: 341,
|
||||||
"op-T3":120, // pla86
|
pla86: 120,
|
||||||
"op-T0-brk/rti":1478, // pla87
|
pla87: 1478,
|
||||||
"op-T0-jmp":594, // pla88
|
pla88: 594,
|
||||||
"op-T5-ind-x":1210, // pla89
|
pla89: 1210,
|
||||||
"op-T3-abs/idx/ind":677, // pla90 // has extra pulldown: pla97
|
pla90: 677, // has extra pulldown: pla97
|
||||||
|
|
||||||
// internal signal: pla outputs block 7
|
// internal signal: pla outputs block 7
|
||||||
"x-op-T4-ind-y":461, // pla91
|
pla91: 461,
|
||||||
"x-op-T3-abs-idx":447, // pla92
|
pla92: 447,
|
||||||
"op-T3-branch":660, // pla93
|
pla93: 660,
|
||||||
"op-brk/rti":1557, // pla94
|
pla94: 1557,
|
||||||
"op-jsr":259, // pla95
|
pla95: 259,
|
||||||
"x-op-jmp":1052, // pla96
|
pla96: 1052,
|
||||||
// gap
|
// gap
|
||||||
"op-push/pull":791, // pla97 // feeds into pla83 and pla90 (no normal pla output)
|
pla97: 791, // feeds into pla83 and pla90 (no normal pla output)
|
||||||
"op-store":517, // pla98
|
pla98: 517,
|
||||||
"op-T4-brk":352, // pla99
|
pla99: 352,
|
||||||
"op-T2-php":750, // pla100
|
pla100: 750,
|
||||||
"op-T2-php/pha":932, // pla101
|
pla101: 932,
|
||||||
"op-T4-jmp":1589, // pla102
|
pla102: 1589,
|
||||||
// gap
|
// gap
|
||||||
"op-T5-rti/rts":446, // pla103
|
pla103: 446,
|
||||||
"xx-op-T5-jsr":528, // pla104
|
pla104: 528,
|
||||||
|
|
||||||
// internal signal: pla outputs block 8
|
// internal signal: pla outputs block 8
|
||||||
"op-T2-jmp-abs":309, // pla105
|
pla105: 309,
|
||||||
"x-op-T3-plp/pla":1430, // pla106
|
pla106: 1430,
|
||||||
"op-lsr/ror/dec/inc":53, // pla107
|
pla107: 53,
|
||||||
"op-asl/rol":691, // pla108
|
pla108: 691,
|
||||||
"op-T0-cli/sei":1292, // pla109
|
pla109: 1292,
|
||||||
// gap
|
// gap
|
||||||
"op-T+-bit":1646, // pla110
|
pla110: 1646,
|
||||||
"op-T0-clc/sec":1114, // pla111
|
pla111: 1114,
|
||||||
"op-T3-mem-zp-idx":904, // pla112
|
pla112: 904,
|
||||||
"x-op-T+-adc/sbc":1155, // pla113
|
pla113: 1155,
|
||||||
"x-op-T0-bit":1476, // pla114
|
pla114: 1476,
|
||||||
"op-T0-plp":1226, // pla115
|
pla115: 1226,
|
||||||
"x-op-T4-rti":1569, // pla116
|
pla116: 1569,
|
||||||
"op-T+-cmp":301, // pla117
|
pla117: 301,
|
||||||
"op-T+-cpx/cpy-abs":950, // pla118
|
pla118: 950,
|
||||||
"op-T+-asl/rol-a":1665, // pla119
|
pla119: 1665,
|
||||||
|
|
||||||
// internal signal: pla outputs block 9
|
// internal signal: pla outputs block 9
|
||||||
"op-T+-cpx/cpy-imm/zp":1710, // pla120
|
pla120: 1710,
|
||||||
"x-op-push/pull":1050, // pla121 // feeds into pla130 (no normal pla output)
|
pla121: 1050, // feeds into pla130 (no normal pla output)
|
||||||
"op-T0-cld/sed":1419, // pla122
|
pla122: 1419,
|
||||||
"#op-branch-bit6":840, // pla123 // IR bit6 used only to detect branch type
|
pla123: 840,
|
||||||
"op-T3-mem-abs":607, // pla124
|
pla124: 607,
|
||||||
"op-T2-mem-zp":219, // pla125
|
pla125: 219,
|
||||||
"op-T5-mem-ind-idx":1385, // pla126
|
pla126: 1385,
|
||||||
"op-T4-mem-abs-idx":281, // pla127
|
pla127: 281,
|
||||||
"#op-branch-bit7":1174, // pla128 // IR bit7 used only to detect branch type
|
pla128: 1174,
|
||||||
"op-clv":1164, // pla129
|
pla129: 1164,
|
||||||
"op-implied":1006, // pla130 // has extra pulldowns: pla121 and ir0
|
pla130: 1006, // has extra pulldowns: pla121 and ir0
|
||||||
|
|
||||||
// internal signals: control signals
|
// internal signals: control signals
|
||||||
nnT2BR: 967, // doubly inverted
|
nnT2BR: 967, // doubly inverted
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
// This file testprogram.js can be substituted by one of several tests
|
|
||||||
// which may not be redistributable
|
|
||||||
// for example
|
|
||||||
// cbmbasic loaded at 0xa000 with entry point 0xe394
|
|
||||||
// test6502 (by Bird Computer) loaded at 0x8000 with entry point 0x8000
|
|
||||||
//
|
|
||||||
// (can use xxd -i to convert binary into C include syntax, as a starting point)
|
|
||||||
//
|
|
||||||
testprogramAddress=0x0000;
|
|
||||||
|
|
||||||
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
|
|
||||||
];
|
|
200
wires.js
@ -21,14 +21,80 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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 ngnd = nodenames['vss'];
|
var ngnd = nodenames['vss'];
|
||||||
var npwr = nodenames['vcc'];
|
var npwr = nodenames['vcc'];
|
||||||
|
|
||||||
var chipLayoutIsVisible = true; // only modified in expert mode
|
|
||||||
|
/////////////////////////
|
||||||
|
//
|
||||||
|
// Drawing Setup
|
||||||
|
//
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
// try to present a meaningful page before starting expensive work
|
||||||
|
function setup(){
|
||||||
|
statbox = document.getElementById('status');
|
||||||
|
setStatus('loading 6502...');
|
||||||
|
setTimeout(setup_part2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_part2(){
|
||||||
|
frame = document.getElementById('frame');
|
||||||
|
statbox = document.getElementById('status');
|
||||||
|
setupNodes();
|
||||||
|
setupTransistors();
|
||||||
|
setupLayerVisibility();
|
||||||
|
setupBackground();
|
||||||
|
setupOverlay();
|
||||||
|
setupHilite();
|
||||||
|
setupHitBuffer();
|
||||||
|
recenter();
|
||||||
|
refresh();
|
||||||
|
setupTable();
|
||||||
|
window.onkeypress = function(e){handleKey(e);}
|
||||||
|
hilite.onmousedown = function(e){mouseDown(e);}
|
||||||
|
setStatus('resetting 6502...');
|
||||||
|
setTimeout(setup_part3, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_part3(){
|
||||||
|
initChip();
|
||||||
|
document.getElementById('stop').style.visibility = 'hidden';
|
||||||
|
go();
|
||||||
|
}
|
||||||
|
|
||||||
function setupNodes(){
|
function setupNodes(){
|
||||||
for(var i in segdefs){
|
for(var i in segdefs){
|
||||||
@ -36,7 +102,7 @@ function setupNodes(){
|
|||||||
var w = seg[0];
|
var w = seg[0];
|
||||||
if(nodes[w]==undefined)
|
if(nodes[w]==undefined)
|
||||||
nodes[w] = {segs: new Array(), num: w, pullup: seg[1]=='+',
|
nodes[w] = {segs: new Array(), num: w, pullup: seg[1]=='+',
|
||||||
state: false, gates: new Array(), c1c2s: new Array()};
|
state: 'fl', gates: new Array(), c1c2s: new Array()};
|
||||||
if(w==ngnd) continue;
|
if(w==ngnd) continue;
|
||||||
if(w==npwr) continue;
|
if(w==npwr) continue;
|
||||||
nodes[w].segs.push(seg.slice(3));
|
nodes[w].segs.push(seg.slice(3));
|
||||||
@ -50,12 +116,10 @@ function setupTransistors(){
|
|||||||
var gate = tdef[1];
|
var gate = tdef[1];
|
||||||
var c1 = tdef[2];
|
var c1 = tdef[2];
|
||||||
var c2 = tdef[3];
|
var c2 = tdef[3];
|
||||||
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};
|
||||||
nodes[gate].gates.push(trans);
|
nodes[gate].gates.push(name);
|
||||||
nodes[c1].c1c2s.push(trans);
|
nodes[c1].c1c2s.push(name);
|
||||||
nodes[c2].c1c2s.push(trans);
|
nodes[c2].c1c2s.push(name);
|
||||||
transistors[name] = trans;
|
transistors[name] = trans;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,8 +198,7 @@ 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);
|
||||||
}
|
}
|
||||||
@ -163,7 +226,9 @@ function hiliteNode(n){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function drawSeg(ctx, seg){
|
function drawSeg(ctx, seg){
|
||||||
|
if(noGraphics) return;
|
||||||
var dx = 400;
|
var dx = 400;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.moveTo(grScale(seg[0]+dx), grScale(grChipSize-seg[1]));
|
ctx.moveTo(grScale(seg[0]+dx), grScale(grChipSize-seg[1]));
|
||||||
@ -171,6 +236,88 @@ 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('<>?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 {setStatus('x:',cx, 'y:', cy,'<br>','node:',w, nodeName(w));}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@ -181,17 +328,26 @@ function findNodeNumber(x,y){
|
|||||||
return (high<<8)+(mid<<4)+low;
|
return (high<<8)+(mid<<4)+low;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearHighlight(){
|
|
||||||
// remove red/white overlay according to logic value
|
|
||||||
// for easier layout navigation
|
|
||||||
ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateShow(layer, on){
|
function updateShow(layer, on){
|
||||||
drawlayers[layer]=on;
|
drawlayers[layer]=on;
|
||||||
setupBackground();
|
setupBackground();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////
|
||||||
|
//
|
||||||
|
// Etc.
|
||||||
|
//
|
||||||
|
/////////////////////////
|
||||||
|
|
||||||
|
function setChipStyle(props){
|
||||||
|
for(var i in props){
|
||||||
|
chipbg.style[i] = props[i];
|
||||||
|
overlay.style[i] = props[i];
|
||||||
|
hilite.style[i] = props[i];
|
||||||
|
hitbuffer.style[i] = props[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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){
|
||||||
@ -208,20 +364,10 @@ function localy(el, gy){
|
|||||||
|
|
||||||
function setStatus(){
|
function setStatus(){
|
||||||
var res = '';
|
var res = '';
|
||||||
// pad the arguments to make this a three-line display
|
for(var i=0;i<arguments.length;i++) res=res+arguments[i]+' ';
|
||||||
// there must be a clean way to do this
|
|
||||||
if(arguments[1]==undefined)arguments[1]="";
|
|
||||||
if(arguments[2]==undefined)arguments[2]="";
|
|
||||||
arguments.length=3;
|
|
||||||
for(var i=0;i<arguments.length;i++) res=res+arguments[i]+'<br>';
|
|
||||||
statbox.innerHTML = res;
|
statbox.innerHTML = res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupNodeNameList(){
|
|
||||||
for(var i in nodenames)
|
|
||||||
nodenamelist.push(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
function nodeName(n) {
|
function nodeName(n) {
|
||||||
for(var i in nodenames){
|
for(var i in nodenames){
|
||||||
if(nodenames[i]==n) return i;
|
if(nodenames[i]==n) return i;
|
||||||
|