130 Commits
V0.0 ... V0.4

Author SHA1 Message Date
d2a31398fd [bug]repair expert mode - had removed too much 2010-11-08 09:14:18 +00:00
3804eace6e simplify: expertMode is no longer a checkbox, just a static indicator 2010-11-08 09:04:47 +00:00
369a188ad9 use expertMode to suppress loglist actions in kiosk mode 2010-11-08 09:03:13 +00:00
678acd6dc5 URL handler: add requested signal names to logging set 2010-11-06 17:55:36 +00:00
758d53bf5b add clock trigger mechanism and URL interface for reset pin 2010-11-06 17:21:50 +00:00
e885646e5e [bug]fixup nosim=t initialisation (if a simulation is started manually) 2010-11-05 21:39:01 +00:00
353e0a8f78 highlight a list of nodes by name or number 2010-11-05 21:21:06 +00:00
18e1946488 allow forward or reverse log order 2010-11-05 19:53:22 +00:00
0c6a90a558 allow nodenumbers in additional trace requests 2010-11-05 19:02:41 +00:00
93e6d662df panes resize when chip graphics are shown/hidden 2010-11-05 18:25:51 +00:00
0842501bb7 [bug]direct keypresses to correct places: graphics, memtable, input box 2010-11-05 17:38:47 +00:00
294918789a add tracing of named nodes 2010-11-01 19:36:52 +00:00
cd05762f20 trivial fix to rename button container 2010-11-01 18:30:22 +00:00
ef0bb5cdec fix out by one error in fastforward/goFor 2010-11-01 18:19:46 +00:00
25e8397a0f scale down new button images 2010-11-01 18:15:36 +00:00
44b5c5e9d3 add new buttons and remove headless go 2010-11-01 18:03:30 +00:00
633a2693ac fixup single stepping function 2010-11-01 18:02:52 +00:00
da7ec1f3e3 add button icons for fast forward and single step 2010-11-01 18:02:06 +00:00
bed571f10c add button to clear log 2010-11-01 17:42:45 +00:00
192d9a8ba8 add plaOutputs to traceable log stream 2010-11-01 17:42:18 +00:00
b4747b0cad trivial annotation tweak to nodenames.js 2010-11-01 17:31:48 +00:00
62b0b314d5 remove kiosk.html and use index.html instead 2010-11-01 17:00:27 +00:00
39959e711e three panel splittable (dynamic) screen layout 2010-10-31 13:39:31 +00:00
0156a72ae7 add splitter and jquery library (GPL and MIT dual licensed) for draggable pane divisions 2010-10-31 12:47:20 +00:00
759c188ef6 Add useful links to existing minimal banner line 2010-10-31 10:22:30 +00:00
a406cee106 Add graphics command tips (no help page yet) 2010-10-31 10:17:53 +00:00
e3354a2aa4 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-10-30 20:33:16 +00:00
68e022a2bd [bug]tidy up pan+zoom URLs 2010-10-30 20:31:32 +00:00
c4dcbcb435 Merge branch 'ed' 2010-10-30 16:27:50 -04:00
bc8ef61fb9 [enh]add pla signalnames from Segher Boessenkool 2010-10-30 20:23:56 +00:00
86e544a065 Change link to expert mode from kiosk 2010-10-30 16:13:43 -04:00
ea9f54c398 [bug]index redirection fixup 2010-10-30 20:07:26 +00:00
dd95b40c6c added smart redirect in index.html to appropriate landing page 2010-10-30 18:59:00 +00:00
3fcc3ee787 bring in support for old/slow browser, including nosim node 2010-10-30 18:24:00 +00:00
83af54a47d re-simplify busname name matching 2010-10-30 18:05:29 +00:00
c9443e6718 [bug]passing steps on URL was not working 2010-10-30 16:16:54 +00:00
e93c11ab20 replace index.html with a redirector to the expert landing page 2010-10-30 16:07:48 +00:00
0d0973b0c6 [bugfix]tcstate and predecode register corrections 2010-10-30 14:05:14 +00:00
4b19e21e66 [BUG]Animate checkbox not initialized 2010-10-29 19:10:06 -04:00
df6aaa392c More simplifications from Brian 2010-10-15 08:11:43 -04:00
5a4c574765 Headless mode in expert 2010-10-14 22:48:25 -04:00
10787078c8 More forEach 2010-10-14 21:15:47 -04:00
98ec727c50 Performance: Remove float state 2010-10-14 21:00:07 -04:00
33aa993c8d Performance - use forEach, and more cleanup 2010-10-14 20:16:43 -04:00
b5e1064efb Performance improvement in checking for duplicate nodes in recalclist 2010-10-13 22:00:01 -04:00
282c815791 Chipsim change of states to booleans, and performance 2010-10-13 17:53:40 -04:00
3258a24c91 [bug]fixup chip layout visibility control 2010-10-09 13:43:47 +00:00
66d42665a9 [bug]graphics=false needs to work in expert mode 2010-10-08 15:27:33 +00:00
cede111a0f First cut refactor into expert and kiosk 2010-10-07 12:21:06 -04:00
dc0fb1ef06 Merging changes for testprogram, and various fixes from Ed 2010-10-07 08:15:07 -04:00
e60485fe6a Performance fix 2010-10-07 07:33:15 -04:00
9705ca4093 [bug]declarations for testprogram and fix for negative loglevel values 2010-10-06 21:00:56 +00:00
a83cb1533e [dev]add singlestepping functions (no UI) 2010-10-06 20:59:43 +00:00
971bbd03e3 [dev]externalise testprogram 2010-10-06 19:51:57 +00:00
0773a9e7cf [dev](commented out)performance tweak, 1.2x gain 2010-10-06 19:48:30 +00:00
ee196947e3 [dev]add trace checksum for self-checking tests 2010-10-05 19:14:08 +00:00
f439d8fc8d [bug]fixup output of tstate and P 2010-10-05 18:12:44 +00:00
43f06031b0 [dev]alternate zoom keys 2010-10-05 17:51:48 +00:00
c5e2bfd657 [bug]use the grMaxZoom constant as intended 2010-10-04 11:12:07 +00:00
2cfceefacd [dev]add comments and some symbolic constants for graphics code - no functional change 2010-10-04 11:04:35 +00:00
67ad17122c [dev]Brian's smaller canvas - simulates faster and working/virtual memory down from 330M/570M to 130M/350M 2010-10-04 10:50:54 +00:00
c15e3ea5b5 [bug]minimum log trace should be same as status set 2010-10-02 18:12:25 +00:00
6aec2c96f0 [bug]minor grammar fix 2010-10-02 16:47:28 +00:00
d6e516cafa [dev]major rejig of css and DOM hierarchy - removes some hard coded numbers and allows for large/small logstream when chip is hidden/visible 2010-10-02 16:37:33 +00:00
2d20ef2dad [dev]force status box to 3-line form, other layout tweaks 2010-10-02 16:36:02 +00:00
5f24e86c3e [dev]add speedometer 2010-10-02 11:51:33 +00:00
5578726fd3 [bug]reword the link to 6502 tools 2010-10-02 11:06:14 +00:00
1843c17ce9 [bug]older firefox likes childNodes 2010-10-01 20:58:13 +00:00
455949ceca [bug]logstream box should become scrollable when too large 2010-10-01 19:13:29 +00:00
f0536dc716 [dev]user program can be defined in url, can run for chosen number of steps 2010-10-01 18:39:33 +00:00
c8aabd6baa [dev]add links to 6502asm and e-tradition 2010-10-01 18:31:02 +00:00
0b1af8d70e [dev]add link to current pan+zoom 2010-10-01 16:56:14 +00:00
f3375f4c4b [dev]implement pan and zoom from URL 2010-10-01 16:10:33 +00:00
0892586d75 [dev]tidy rough edges in expert and graphics mode switching 2010-10-01 14:51:17 +00:00
0ae95d5338 [bug]rejig non-graphics mode 2010-10-01 13:02:03 +00:00
a2d20cc403 [dev]handle URL params like ?graphics=false&expert=true&loglevel=4 2010-10-01 11:29:22 +00:00
e72f11ee72 Merge branch 'ed' into staging 2010-09-30 17:31:59 -04:00
4b0316170b [bug]fixup alu c and v output node names 2010-09-30 21:07:36 +00:00
4849ad6ebc [dev]name some reset signals 2010-09-30 19:20:56 +00:00
f26a508c4e [dev]add selective node and transistor ctrace 2010-09-28 19:22:50 +00:00
d94116d257 Fixed save.php 2010-09-27 20:56:47 -04:00
b8d2872246 Merge branch 'ed' into staging 2010-09-27 13:48:54 -04:00
730312e594 [dev]enhancements to expert mode 2010-09-27 17:25:14 +00:00
46976519fe [dev]add hanson names to some datapath controls, add dasb 2010-09-27 17:24:42 +00:00
4ce8e4291f [dev]improve expert-mode tabulation 2010-09-27 13:16:59 +00:00
c03f3477bd Merge branch 'ed' into staging 2010-09-26 20:37:51 -04:00
f67125989c [dev]annotate some decimal signals 2010-09-26 21:39:58 +00:00
25f4594fdf [dev]label some pipeline state, add some pla and alu labelling 2010-09-26 19:55:54 +00:00
f6f467787a [dev]first (untidy) implementation of expert mode with tabular logging 2010-09-25 21:32:29 +00:00
2e9991c8ec Merge branch 'ed' into staging 2010-09-25 16:40:11 -04:00
b50da0d3ed Merge branch 'ed' into staging 2010-09-25 10:30:11 -04:00
653379e5d7 [bug]nodename additions and tweaks 2010-09-25 11:29:56 +00:00
b3606c3b7f [bug]fixup some inverted busses 2010-09-25 11:06:44 +00:00
406c9731e8 [dev]add datapath controls and other names 2010-09-25 10:30:25 +00:00
40fe1e0a7a [dev] tweak logging capability 2010-09-25 10:29:26 +00:00
1f21f5283c add Ed to copyright notice 2010-09-25 08:18:28 +00:00
b161368455 Fix scroll instructions 2010-09-24 10:20:14 -04:00
eaf55f1f31 [bug]correct pla output numbers, add ir signals 2010-09-24 14:02:57 +00:00
11ab9bafce [dev]assist probing by optionally logging node info to console 2010-09-23 19:39:12 +00:00
8fbcefc2e2 [dev]add 130 pla outputs and a couple of other tweaks 2010-09-23 19:38:16 +00:00
ea48dae543 [dev]reorder and add comments to nodenames 2010-09-23 18:53:43 +00:00
f293f2f10b [dev]fixup double-paste in previous commit 2010-09-22 21:34:00 +00:00
2ac9d92999 [dev]add adsense to other jssim html page 2010-09-22 21:32:01 +00:00
864b82d7b7 [bug]fixup IE version extraction 2010-09-22 20:38:52 +00:00
e4ccdcafcd github and google links 2010-09-22 07:34:14 -04:00
9477ea64b4 allow IE9 (not tested on IE9, OK on firefox and chrome, IE8) 2010-09-20 13:09:15 +00:00
7ef9dc4c43 detect IE, add page of browser trouble, static image 2010-09-20 12:37:15 +00:00
efddb36049 remove page Offsets to fix probing in scrolled browser window 2010-09-19 18:27:48 +00:00
ef88fdeb90 Fixed console references for Firefox 2010-09-19 03:02:26 -04:00
470080015d Change title font and various wording changes from Greg 2010-09-18 19:59:41 -04:00
dccef54f2e top link should be absolute 2010-09-18 19:37:50 +00:00
18fbd2eb36 Merge branch 'ed' 2010-09-18 14:14:05 -04:00
bc901566e3 all layers start off visible 2010-09-18 18:06:42 +00:00
6276d019d7 Fixed localx/localy calculation 2010-09-18 14:04:52 -04:00
69ab63e406 fixup space above memtable 2010-09-18 17:56:34 +00:00
d032580201 improve load sequencing, add layer choosing, link to python sim, add keyboard tips, add example nmi test, tweak navbuttons, enhance chipstatus output 2010-09-18 17:46:24 +00:00
0ecb753ec6 fixup nav button positioning 2010-09-18 17:29:45 +00:00
e2e88cfae1 more internal busses and latches named 2010-09-18 17:25:33 +00:00
1fd86334f7 fixup line ends on one remaining file (by touching every line...) 2010-09-18 17:12:28 +00:00
bf2108b9d6 ignore patch detritus 2010-09-18 17:07:48 +00:00
2d2d0ef9b6 Merge branch 'master' of git://github.com/trebonian/visual6502
Conflicts:

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

4
.gitattributes vendored Normal file
View File

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

5
.gitignore vendored Normal file
View File

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

BIN
3rdparty/img/hgrabber.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

BIN
3rdparty/img/vdockbar.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 855 B

BIN
3rdparty/img/vgrabber.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

BIN
3rdparty/img/vgrabber2-active.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

BIN
3rdparty/img/vgrabber2-normal.gif vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 843 B

19
3rdparty/jquery-1.3.2.min.js vendored Normal file

File diff suppressed because one or more lines are too long

92
3rdparty/jquery.cookie.js vendored Normal file
View File

@ -0,0 +1,92 @@
/**
* 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 Normal file
View File

@ -0,0 +1,213 @@
/*
* 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);

10
README
View File

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

46
browsertrouble.html Normal file
View File

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

View File

@ -1,208 +1,196 @@
/* /*
Copyright (c) 2010 Brian Silverman, Barry Silverman Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
var ctrace = false; var ctrace = false;
var ridx = 0; var traceTheseNodes = [];
var traceTheseTransistors = [];
function recalcNodeList(list){ var loglevel = 0;
var n = list[0]; var recalclist = new Array();
var recalclist = new Array(); var recalcHash = new Array();
for(var j=0;j<100;j++){ // loop limiter var group = new Array();
if(list.length==0) return;
if(ctrace) console.log(j, list); function recalcNodeList(list){
for(var i in list) recalcNode(list[i], recalclist); var n = list[0];
list = recalclist; recalclist = new Array();
recalclist = new Array(); recalcHash = new Array();
} for(var j=0;j<100;j++){ // loop limiter
console.log(n,'looping...'); if(list.length==0) return;
} if(ctrace) {
var i;
function recalcNode(node, recalclist){ for(i=0;i<traceTheseNodes.length;i++) {
if(node==ngnd) return; if(list.indexOf(traceTheseNodes[i])!=-1) break;
if(node==npwr) return; }
var group = getNodeGroup(node); if((traceTheseNodes.length==0)||(list.indexOf(traceTheseNodes[i])==-1)) {
var newv = getNodeValue(group); console.log('recalcNodeList iteration: ', j, list.length, 'nodes');
if(ctrace) console.log('recalc', node, group); } else {
for(var i in group){ console.log('recalcNodeList iteration: ', j, list.length, 'nodes', list);
var n = nodes[group[i]]; }
if(n.state!=newv && ctrace) console.log(group[i], n.state, newv); }
n.state = newv; list.forEach(recalcNode);
for(var t in n.gates) recalcTransistor(n.gates[t], recalclist); list = recalclist;
} recalclist = new Array();
} recalcHash = new Array();
}
function recalcTransistor(tn, recalclist){ if(ctrace) console.log(n,'looping...');
var t = transistors[tn]; }
if(isNodeHigh(t.gate)) turnTransistorOn(t, recalclist);
else turnTransistorOff(t, recalclist); function recalcNode(node){
} if(node==ngnd) return;
if(node==npwr) return;
function turnTransistorOn(t, recalclist){ getNodeGroup(node);
if(t.on) return; var newState = getNodeValue();
if(ctrace) console.log(t.name, 'on', t.gate, t.c1, t.c2); if(ctrace && (traceTheseNodes.indexOf(node)!=-1))
t.on = true; console.log('recalc', node, group);
addRecalcNode(t.c1, recalclist); group.forEach(function(i){
addRecalcNode(t.c2, recalclist); var n = nodes[i];
} if(n.state==newState) return;
n.state = newState;
function turnTransistorOff(t, recalclist){ n.gates.forEach(function(t){
if(!t.on) return; if(n.state) turnTransistorOn(t);
if(ctrace) console.log(t.name, 'off', t.gate, t.c1, t.c2); else turnTransistorOff(t);});
t.on = false; });
floatnode(t.c1); }
floatnode(t.c2);
addRecalcNode(t.c1, recalclist); function turnTransistorOn(t){
addRecalcNode(t.c2, recalclist); if(t.on) return;
} if(ctrace && (traceTheseTransistors.indexOf(t.name)!=-1))
console.log(t.name, 'on', t.gate, t.c1, t.c2);
function floatnode(nn){ t.on = true;
if(nn==ngnd) return; addRecalcNode(t.c1);
if(nn==npwr) return; }
var n = nodes[nn];
if(n.state=='gnd') n.state = 'fl'; function turnTransistorOff(t){
if(n.state=='pd') n.state = 'fl'; if(!t.on) return;
if(n.state=='vcc') n.state = 'fh'; if(ctrace && (traceTheseTransistors.indexOf(t.name)!=-1))
if(n.state=='pu') n.state = 'fh'; console.log(t.name, 'off', t.gate, t.c1, t.c2);
if(ctrace) console.log('floating', nn, 'to', n.state); t.on = false;
} addRecalcNode(t.c1);
addRecalcNode(t.c2);
function addRecalcNode(nn, recalclist){ }
if(nn==ngnd) return;
if(nn==npwr) return; function addRecalcNode(nn){
if(arrayContains(recalclist, nn)) return; if(nn==ngnd) return;
recalclist.push(nn); if(nn==npwr) return;
// setAdd(recalclist, nn); if(recalcHash[nn] == 1)return;
} recalclist.push(nn);
recalcHash[nn] = 1;
function getNodeGroup(i){ }
var group = new Array();
addNodeToGroup(i, group); function getNodeGroup(i){
return group; group = new Array();
} addNodeToGroup(i);
}
function addNodeToGroup(i, group){
if(arrayContains(group, i)) return; function addNodeToGroup(i){
group.push(i); if(group.indexOf(i) != -1) return;
if(i==ngnd) return; group.push(i);
if(i==npwr) return; if(i==ngnd) return;
for(var t in nodes[i].c1c2s) addNodeTransistor(i, nodes[i].c1c2s[t], group); if(i==npwr) return;
} nodes[i].c1c2s.forEach(
function(t){
function addNodeTransistor(node, t, group){ if(!t.on) return;
var tr = transistors[t]; var other;
if(!tr.on) return; if(t.c1==i) other=t.c2;
var other; if(t.c2==i) other=t.c1;
if(tr.c1==node) other=tr.c2; addNodeToGroup(other);});
if(tr.c2==node) other=tr.c1; }
addNodeToGroup(other, group);
}
function getNodeValue(){
if(arrayContains(group, ngnd)) return false;
function getNodeValue(group){ if(arrayContains(group, npwr)) return true;
if(arrayContains(group, ngnd)) return 'gnd'; for(var i in group){
if(arrayContains(group, npwr)) return 'vcc'; var nn = group[i];
var flstate; var n = nodes[nn];
for(var i in group){ if(n.pullup) return true;
var nn = group[i]; if(n.pulldown) return false;
var n = nodes[nn]; if(n.state) return true;
if(n.pullup) return 'pu'; }
if(n.pulldown) return 'pd'; return false;
if((n.state=='fl')&&(flstate==undefined)) flstate = 'fl'; }
if(n.state=='fh') flstate = 'fh';
}
if(flstate==undefined) console.log(group); function isNodeHigh(nn){
return flstate; return(nodes[nn].state);
} }
function saveString(name, str){
function isNodeHigh(nn){ var request = new XMLHttpRequest();
return arrayContains(['vcc','pu','fh'], nodes[nn].state); request.onreadystatechange=function(){};
} request.open('PUT', 'save.php?name='+name, true);
request.setRequestHeader('Content-Type', 'text/plain');
function saveString(name, str){ request.send(str);
var request = new XMLHttpRequest(); }
request.onreadystatechange=function(){};
request.open('PUT', 'save.php?name='+name, true); function allNodes(){
request.setRequestHeader('Content-Type', 'text/plain'); var res = new Array();
request.send(str); for(var i in nodes) if((i!=npwr)&&(i!=ngnd)) res.push(i);
} return res;
}
function allNodes(){
var res = new Array(); function stateString(){
for(var i in nodes) if((i!=npwr)&&(i!=ngnd)) res.push(i); var codes = ['l','h'];
return res; var res = '';
} for(var i=0;i<1725;i++){
var n = nodes[i];
function stateString(){ if(n==undefined) res+='x';
var codes = {gnd: 'g', vcc: 'v', pu: 'p', pd: 'd', fh: 'f', fl: 'l'}; else if(i==ngnd) res+='g';
var res = ''; else if(i==npwr) res+='v';
for(var i=0;i<1725;i++){ else res+= codes[0+n.state];
var n = nodes[i]; }
if(n==undefined) res+='x'; return res;
else if(i==ngnd) res+='g'; }
else if(i==npwr) res+='v';
else res+= codes[n.state]; function showState(str){
} var codes = {g: false, h: true, v: true, l: false};
return res; for(var i=0;i<str.length;i++){
} if(str[i]=='x') continue;
var state = codes[str[i]];
function showState(str){ nodes[i].state = state;
var codes = {g: 'gnd', v: 'vcc', p: 'pu', d: 'pd', f: 'fh', l: 'fl'}; var gates = nodes[i].gates;
for(var i=0;i<str.length;i++){ gates.forEach(function(t){t.on=state;});
if(str[i]=='x') continue; }
nodes[i].state = codes[str[i]]; refresh();
var gates = nodes[i].gates; }
for(var t in gates) transistors[gates[t]].on = isNodeHigh(i);
}
refresh(); function setPd(name){
} var nn = nodenames[name];
nodes[nn].pullup = false;
nodes[nn].pulldown = true;
function setPd(name){ }
var nn = nodenames[name];
nodes[nn].pullup = false; function setHigh(name){
nodes[nn].pulldown = true; var nn = nodenames[name];
} nodes[nn].pullup = true;
nodes[nn].pulldown = false;
function setHigh(name){ recalcNodeList([nn]);
var nn = nodenames[name]; }
nodes[nn].pullup = true;
nodes[nn].pulldown = false; function setLow(name){
recalcNodeList([nn]); var nn = nodenames[name];
} nodes[nn].pullup = false;
nodes[nn].pulldown = true;
function setLow(name){ recalcNodeList([nn]);
var nn = nodenames[name]; }
nodes[nn].pullup = false;
nodes[nn].pulldown = true; function arrayContains(arr, el){return arr.indexOf(el)!=-1;}
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;}

194
expert.css Normal file
View File

@ -0,0 +1,194 @@
/*
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 Normal file
View File

@ -0,0 +1,145 @@
<!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>&nbsp;
<a href="http://blog.visual6502.org">Blog</a>&nbsp;
<a href="http://www.visual6502.org/links.html">Links</a>&nbsp;
<a href="http://github.com/trebonian/visual6502">Source</a>&nbsp;
<a href="http://www.6502asm.com/">6502asm assembler</a>&nbsp;
<a href="http://www.e-tradition.net/bytes/6502/disassembler.html">e-tradition disassembler</a>&nbsp;
</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 Normal file
View File

@ -0,0 +1,432 @@
/*
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];
}
}

BIN
images/fastforward.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

BIN
images/jssim2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

BIN
images/singlestep.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

View File

@ -1,36 +1,119 @@
<!DOCTYPE html> <!DOCTYPE html>
<head> <head>
<title>6502</title> <title>Visual 6502 in JavaScript</title>
<style type="text/css">@import "wires.css";</style>
<script src="segdefs.js"></script> <!-- by default, index.html will run in kiosk mode -->
<script src="transdefs.js"></script> <style type="text/css">@import "kiosk.css";</style>
<script src="nodenames.js"></script> <script src="segdefs.js"></script>
<script src="wires.js"></script> <script src="transdefs.js"></script>
<script src="chipsim.js"></script> <script src="nodenames.js"></script>
<script src="memtable.js"></script> <script src="kioskWires.js"></script>
<script src="macros.js"></script> <script src="wires.js"></script>
</head> <script src="chipsim.js"></script>
<script src="memtable.js"></script>
<body onload="setup();"> <script src="testprogram.js"></script>
<p class="title">The 6502</p> <script src="macros.js"></script>
<div class="frame" id="frame">
<div class="chip"> <script type="text/javascript">
<canvas class="chip" id="chipbg"></canvas> function handleOnload() {
<canvas class="chip" id="overlay"></canvas> // two checks and fixes here:
<canvas class="chip" id="hilite"></canvas> // - replace the dynamic content with an image if running older versions of IE
<canvas class="chip" id="hitbuffer"></canvas> // - redirect to the expert page if we find any query parameters
</div> //
<div class = "buttons"> /MSIE (\d+\.\d+);/.test(navigator.appVersion);
<a href ="javascript:stopChip()"id="stop"><img class="navstop" src="images/stop.png"></a> IEVersion=Number(RegExp.$1);
<a href ="javascript:runChip()" id="start"><img class="navplay" src="images/play.png"></a> if((navigator.appName == 'Microsoft Internet Explorer') && (IEVersion<9)){
<a href ="javascript:resetChip()"><img class="navbutton" src="images/up.png"></a> document.getElementById('browsertrouble').innerHTML=
<a href ="javascript:stepBack()"><img class="navbutton" src="images/prev.png"></a> '<p>Sorry, '+navigator.appName+' not supported - showing you a picture instead!</p>';
<a href ="javascript:stepForward()"><img class="navbutton" src="images/next.png"></a> document.getElementById('frame').innerHTML='<a href="browsertrouble.html"><img src="images/jssim2.png" style="border:10px"></a>';
</div> }else{
<p class="status" id="status">x: 0<br>y: 0</p> var suffix=location.search;
<table class="memtable" id="memtable"></table> var path=location.pathname;
</div> // ensure we always have a trailing slash
</body> path=path.replace("index.html","").replace(/\/?$/,"/");
</html> 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>
</head>
<body onload="handleOnload();">
<br />
<span id="title"><a href="http://visual6502.org">The Visual 6502</a></span>
<span id="plain">
<br />
<a href="http://www.visual6502.org/faq.html">FAQ</a>&nbsp;
<a href="http://blog.visual6502.org">Blog</a>&nbsp;
<a href="http://www.visual6502.org/links.html">Links</a>&nbsp
<br /><br />
This simulator uses HTML5 features only found on the latest versions of browsers and needs
lots of RAM. If you have trouble, please <a href="browsertrouble.html">check compatibility.</a>
<br />
<span id="browsertrouble"></span>
<br />
Hit '>' to zoom in, '<' to zoom out
<br />
Left-click and drag to scroll around
<br />
Enter your own program into the array of RAM
<br />
<br />
</span>
<div class="frame" id="frame">
<div class="chip" id="chip">
<canvas class="chip" id="chipbg"></canvas>
<canvas class="chip" id="overlay"></canvas>
<canvas class="chip" id="hilite"></canvas>
<canvas class="chip" id="hitbuffer"></canvas>
</div>
<div class = "buttons">
<div style="position:relative; float:left;">
<a href ="javascript:stopChip()"id="stop"><img class="navstop" src="images/stop.png"></a>
<a href ="javascript:runChip()" id="start"><img class="navplay" src="images/play.png"></a>
</div>
<div style="float:left;">
<a href ="javascript:resetChip()"><img class="navbutton" src="images/up.png"></a>
<a href ="javascript:stepBack()"><img class="navbutton" src="images/prev.png"></a>
<a href ="javascript:stepForward()"><img class="navbutton" src="images/next.png"></a>
</div>
</div>
<p class="status" id="status">x: 0<br>y: 0</p>
<table class="memtable" id="memtable"></table>
</div>
<div id="updateShow">
</div>
<br />
<br />
Source code is available on <a href="http://github.com/trebonian/visual6502">github visual6502</a>.
Use the online <a href="http://www.6502asm.com/">emulator and assembler</a> from 6502asm.com
and <a href="http://www.e-tradition.net/bytes/6502/disassembler.html">disassembler</a> from e-tradition.net
<br />
For in-depth 6502 investigation and some more advanced features, try our <a href="/JSSim/expert.html">Experimenter's (Beta) version</a>.
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9008420149077488";
/* 728x90, created 9/22/10 */
google_ad_slot = "4303982675";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</body>
</html>

94
kiosk.css Normal file
View File

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

196
kioskWires.js Normal file
View File

@ -0,0 +1,196 @@
/*
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];
}
}

722
macros.js
View File

@ -1,201 +1,521 @@
/* /*
Copyright (c) 2010 Brian Silverman, Barry Silverman 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
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
var memory = Array(); var memory = Array();
var code = [0xa9, 0x00, 0x20, 0x10, 0x00, 0x4c, 0x02, 0x00, var cycle = 0;
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, var trace = Array();
0xe8, 0x88, 0xe6, 0x40, 0x38, 0x69, 0x02, 0x60]; var logstream = Array();
var cycle = 0; var running = false;
var trace = Array(); var logThese=[];
var running = false; var presetLogLists=[
['cycle'],
function go(n){ ['ab','db','rw','sync','pc','a','x','y','s','p'],
for(var i=0;i<code.length;i++){ ['ir','tcstate','pd'],
mWrite(i, code[i]); ['adl','adh','sb','alu'],
setCellValue(i, code[i]); ['alucin','alua','alub','alucout','aluvout','dasb'],
} ['plaOutputs'],
mWrite(0xfffc, 0x00); ['idb','dor'],
mWrite(0xfffd, 0x00); ['irq','nmi','res'],
steps(); ];
}
function loadProgram(){
function steps(){ // a moderate size of static testprogram might be loaded
if(running) step(); if(testprogram.length!=0 && testprogramAddress != undefined)
setTimeout(steps, 200); for(var i=0;testprogram[i]!=undefined;i++){
} var a=testprogramAddress+i;
mWrite(a, testprogram[i]);
function initChip(){ if(a<0x200)
for(var nn in nodes) nodes[nn].state = 'fl'; setCellValue(a, testprogram[i]);
nodes[ngnd].state = 'gnd'; }
nodes[npwr].state = 'vcc'; // a small test program or patch might be passed in the URL
for(var tn in transistors) transistors[tn].on = false; if(userCode.length!=0)
setLow('res'); for(var i=0;i<userCode.length;i++){
setLow('clk0'); if(userCode[i] != undefined){
setHigh('rdy'); setLow('so'); mWrite(i, userCode[i]);
setHigh('irq'); setHigh('nmi'); if(i<0x200)
recalcNodeList(allNodes()); setCellValue(i, userCode[i]);
for(var i=0;i<8;i++){setHigh('clk0'), setLow('clk0');} }
setHigh('res'); }
for(var i=0;i<14;i++){step();} // default reset vector will be 0x0000 because undefined memory reads as zero
refresh(); if(userResetLow!=undefined)
cycle = 0; mWrite(0xfffc, userResetLow);
trace = Array(); if(userResetHigh!=undefined)
chipStatus(); mWrite(0xfffd, userResetHigh);
} }
function step(){ function go(){
trace[cycle]= {chip: stateString(), mem: getMem()}; if(typeof userSteps != "undefined"){
halfStep(); if(--userSteps==0){
cycle++; running=false;
chipStatus(); userSteps=undefined;
} }
}
function halfStep(){ if(running) {
var clk = isNodeHigh(nodenames['clk0']); step();
if (clk) {setLow('clk0'); handleBusRead(); } setTimeout(go, 0); // schedule the next poll
else {setHigh('clk0'); handleBusWrite();} }
refresh(); }
}
function goUntilSync(){
function handleBusRead(){ halfStep();
if(isNodeHigh(nodenames['rw'])) writeDataBus(mRead(readAddressBus())); while(!isNodeHigh(nodenames['sync']) || isNodeHigh(nodenames['clk0']))
} halfStep();
}
function handleBusWrite(){
if(!isNodeHigh(nodenames['rw'])){ function goUntilSyncOrWrite(){
var a = readAddressBus(); halfStep();
var d = readDataBus(); cycle++;
mWrite(a,d); while(
if(a<0x200) setCellValue(a,d); !isNodeHigh(nodenames['clk0']) ||
} ( !isNodeHigh(nodenames['sync']) && isNodeHigh(nodenames['rw']) )
} ) {
halfStep();
function readAddressBus(){return readBits('ab', 16);} cycle++;
function readDataBus(){return readBits('db', 8);} }
function readA(){return readBits('a', 8);} chipStatus();
function readY(){return readBits('y', 8);} }
function readX(){return readBits('x', 8);}
function readP(){return readBits('p', 8);} function testNMI(n){
function readSP(){return readBits('s', 8);} initChip();
function readBits(name, n){ mWrite(0x0000, 0x38); // set carry
var res = 0; mWrite(0x0001, 0x4c); // jump to test code
for(var i=0;i<n;i++){ mWrite(0x0002, 0x06);
var nn = nodenames[name+i]; mWrite(0x0003, 0x23);
res+=((isNodeHigh(nn))?1:0)<<i;
} mWrite(0x22ff, 0x38); // set carry
return res; mWrite(0x2300, 0xea);
} mWrite(0x2301, 0xea);
mWrite(0x2302, 0xea);
function writeDataBus(x){ mWrite(0x2303, 0xea);
var recalcs = Array(); mWrite(0x2304, 0xb0); // branch carry set to self
for(var i=0;i<8;i++){ mWrite(0x2305, 0xfe);
var nn = nodenames['db'+i];
var n = nodes[nn]; mWrite(0x2306, 0xb0); // branch carry set to self
if((x%2)==0) {n.pulldown=true; n.pullup=false;} mWrite(0x2307, 0x01);
else {n.pulldown=false; n.pullup=true;} mWrite(0x2308, 0x00); // brk should be skipped
recalcs.push(nn); mWrite(0x2309, 0xa9); // anything
x>>=1; mWrite(0x230a, 0xde); // anything
} mWrite(0x230b, 0xb0); // branch back with page crossing
recalcNodeList(recalcs); mWrite(0x230c, 0xf2);
}
mWrite(0xc018, 0x40); // nmi handler
function mRead(a){
if(memory[a]==undefined) return 0; mWrite(0xfffa, 0x18); // nmi vector
else return memory[a]; mWrite(0xfffb, 0xc0);
} mWrite(0xfffc, 0x00); // reset vector
mWrite(0xfffd, 0x00);
function mWrite(a, d){memory[a]=d;}
for(var i=0;i<n;i++){step();}
setLow('nmi');
function clkNodes(){ chipStatus();
var res = Array(); for(var i=0;i<8;i++){step();}
res.push(943); setHigh('nmi');
for(var i in nodes[943].gates){ chipStatus();
var t = transistors[nodes[943].gates[i]]; for(var i=0;i<16;i++){step();}
if(t.c1==npwr) res.push(t.c2); }
if(t.c2==npwr) res.push(t.c1);
} function initChip(){
hiliteNode(res); var start = now();
} for(var nn in nodes) {
nodes[nn].state = false;
function runChip(){ nodes[nn].float = true;
var start = document.getElementById('start'); }
var stop = document.getElementById('stop');
start.style.visibility = 'hidden'; nodes[ngnd].state = false;
stop.style.visibility = 'visible'; nodes[ngnd].float = false;
running = true; nodes[npwr].state = true;
} nodes[npwr].float = false;
for(var tn in transistors) transistors[tn].on = false;
function stopChip(){ setLow('res');
var start = document.getElementById('start'); setLow('clk0');
var stop = document.getElementById('stop'); setHigh('rdy'); setLow('so');
start.style.visibility = 'visible'; setHigh('irq'); setHigh('nmi');
stop.style.visibility = 'hidden'; recalcNodeList(allNodes());
running = false; for(var i=0;i<8;i++){setHigh('clk0'), setLow('clk0');}
} setHigh('res');
for(var i=0;i<18;i++){halfStep();} // avoid updating graphics and trace buffer before user code
function resetChip(){ refresh();
stopChip(); cycle = 0;
initChip(); trace = Array();
} if(typeof expertMode != "undefined")
updateLogList();
function stepForward(){ chipStatus();
stopChip(); if(ctrace)console.log('initChip done after', now()-start);
step(); }
}
function signalSet(n){
function stepBack(){ var signals=[];
if(cycle==0) return; for (var i=0; (i<=n)&&(i<presetLogLists.length) ; i++){
showState(trace[--cycle].chip); for (var j=0; j<presetLogLists[i].length; j++){
setMem(trace[cycle].mem); signals.push(presetLogLists[i][j]);
var clk = isNodeHigh(nodenames['clk0']); }
if(!clk) writeDataBus(mRead(readAddressBus())); }
chipStatus(); return signals;
} }
function chipStatus(){ function updateLogList(names){
var pc = readAddressBus(); // user supplied a list of signals, which we append to the set defined by loglevel
setStatus('PC:', hexWord(pc), logThese = signalSet(loglevel);
'D:', hexByte(readDataBus()), if(typeof names == "undefined")
'SP:',hexByte(readSP()), // this is a UI call - read the text input
'cycle:', cycle, '<br>', names = document.getElementById('LogThese').value;
'A:', hexByte(readA()), else
'X:', hexByte(readX()), // this is an URL call - update the text input box
'Y:', hexByte(readY()), document.getElementById('LogThese').value = names;
'P:', hexByte(readP()) names = names.split(/[\s,]+/);
); for(var i=0;i<names.length;i++){
selectCell(pc); // could be a signal name, a node number, or a special name
} if(typeof busToString(names[i]) != "undefined")
logThese.push(names[i]);
function getMem(){ }
var res = Array(); initLogbox(logThese);
for(var i=0;i<0x200;i++) res.push(mRead(i)); }
return res;
} var traceChecksum='';
var goldenChecksum;
function setMem(arr){
for(var i=0;i<0x200;i++){mWrite(i, arr[i]); setCellValue(i, arr[i]);} // simulate a single clock phase, updating trace and highlighting layout
} function step(){
var s=stateString();
function hexWord(n){return (0x10000+n).toString(16).substring(1)} var m=getMem();
function hexByte(n){return (0x100+n).toString(16).substring(1)} trace[cycle]= {chip: s, mem: m};
if(goldenChecksum != undefined)
traceChecksum=adler32(traceChecksum+s+m.slice(0,511).toString(16));
halfStep();
if(animateChipLayout)
refresh();
cycle++;
chipStatus();
}
// triggers for breakpoints, watchpoints, input pin events
clockTriggers={};
// simulate a single clock phase with no update to graphics or trace
function halfStep(){
var clk = isNodeHigh(nodenames['clk0']);
eval(clockTriggers[cycle]); // usually undefined, no measurable performance loss
if (clk) {setLow('clk0'); handleBusRead(); }
else {setHigh('clk0'); handleBusWrite();}
}
function handleBusRead(){
if(isNodeHigh(nodenames['rw'])) writeDataBus(mRead(readAddressBus()));
}
function handleBusWrite(){
if(!isNodeHigh(nodenames['rw'])){
var a = readAddressBus();
var d = readDataBus();
mWrite(a,d);
if(a<0x200) setCellValue(a,d);
}
}
function readAddressBus(){return readBits('ab', 16);}
function readDataBus(){return readBits('db', 8);}
function readA(){return readBits('a', 8);}
function readY(){return readBits('y', 8);}
function readX(){return readBits('x', 8);}
function readP(){return readBits('p', 8);}
function readPstring(){
var result;
result = (isNodeHigh(nodenames['p7'])?'N':'n') +
(isNodeHigh(nodenames['p6'])?'V':'v') +
'&#8209' + // non-breaking hyphen
(isNodeHigh(nodenames['p3'])?'B':'b') +
(isNodeHigh(nodenames['p3'])?'D':'d') +
(isNodeHigh(nodenames['p2'])?'I':'i') +
(isNodeHigh(nodenames['p1'])?'Z':'z') +
(isNodeHigh(nodenames['p0'])?'C':'c');
return result;
}
function readSP(){return readBits('s', 8);}
function readPC(){return (readBits('pch', 8)<<8) + readBits('pcl', 8);}
function readPCL(){return readBits('pcl', 8);}
function readPCH(){return readBits('pch', 8);}
function 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){
return isNodeHigh(nodenames[name])?1:0;
}
function readBits(name, n){
var res = 0;
for(var i=0;i<n;i++){
var nn = nodenames[name+i];
res+=((isNodeHigh(nn))?1:0)<<i;
}
return res;
}
function 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){
var recalcs = Array();
for(var i=0;i<8;i++){
var nn = nodenames['db'+i];
var n = nodes[nn];
if((x%2)==0) {n.pulldown=true; n.pullup=false;}
else {n.pulldown=false; n.pullup=true;}
recalcs.push(nn);
x>>=1;
}
recalcNodeList(recalcs);
}
function mRead(a){
if(memory[a]==undefined) return 0;
else return memory[a];
}
function mWrite(a, d){memory[a]=d;}
function clkNodes(){
var res = Array();
res.push(943);
for(var i in nodes[943].gates){
var t = nodes[943].gates[i];
if(t.c1==npwr) res.push(t.c2);
if(t.c2==npwr) res.push(t.c1);
}
hiliteNode(res);
}
function runChip(){
var start = document.getElementById('start');
var stop = document.getElementById('stop');
start.style.visibility = 'hidden';
stop.style.visibility = 'visible';
if(typeof running == "undefined")
initChip();
running = true;
go();
}
function stopChip(){
var start = document.getElementById('start');
var stop = document.getElementById('stop');
start.style.visibility = 'visible';
stop.style.visibility = 'hidden';
running = false;
}
function resetChip(){
stopChip();
setStatus('resetting 6502...');
setTimeout(initChip,0);
}
function stepForward(){
if(typeof running == "undefined")
initChip();
stopChip();
step();
}
function stepBack(){
if(cycle==0) return;
showState(trace[--cycle].chip);
setMem(trace[cycle].mem);
var clk = isNodeHigh(nodenames['clk0']);
if(!clk) writeDataBus(mRead(readAddressBus()));
chipStatus();
}
function chipStatus(){
var ab = readAddressBus();
var machine1 =
' halfcyc:' + cycle +
' phi0:' + readBit('clk0') +
' AB:' + hexWord(ab) +
' D:' + hexByte(readDataBus()) +
' RnW:' + readBit('rw');
var machine2 =
' PC:' + hexWord(readPC()) +
' A:' + hexByte(readA()) +
' X:' + hexByte(readX()) +
' Y:' + hexByte(readY()) +
' SP:' + hexByte(readSP()) +
' ' + readPstring();
var chk='';
if(goldenChecksum != undefined)
chk=" Chk:" + traceChecksum + ((traceChecksum==goldenChecksum)?" OK":" no match");
setStatus(machine1, machine2, "Hz: " + estimatedHz().toFixed(1) + chk);
if (loglevel>0) {
updateLogbox(logThese);
}
selectCell(ab);
}
function goFor(){
var n = headlessSteps;
estimatedHz1();
while(n--){
halfStep();
cycle++;
}
estimatedHz1();
chipStatus();
}
var prevHzTimeStamp=0;
var prevHzCycleCount=0;
var prevHzEstimate1=1;
var prevHzEstimate2=1;
var HzSamplingRate=10;
function estimatedHz(){
if(cycle%HzSamplingRate!=3)
return prevHzEstimate1;
return estimatedHz1();
}
function estimatedHz1(){
var HzTimeStamp = now();
var HzEstimate = (cycle-prevHzCycleCount+.01)/(HzTimeStamp-prevHzTimeStamp+.01);
HzEstimate=HzEstimate*1000/2; // convert from phases per millisecond to Hz
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(){
var res = Array();
for(var i=0;i<0x200;i++) res.push(mRead(i));
return res;
}
function setMem(arr){
for(var i=0;i<0x200;i++){mWrite(i, arr[i]); setCellValue(i, arr[i]);}
}
function hexWord(n){return (0x10000+n).toString(16).substring(1)}
function hexByte(n){return (0x100+n).toString(16).substring(1)}
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);
}

View File

@ -1,89 +1,91 @@
/* /*
Copyright (c) 2010 Brian Silverman, Barry Silverman Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
var table; var table;
var selected; var selected;
function setupTable(){ function setupTable(){
table = document.getElementById('memtable'); table = document.getElementById('memtable');
for(var r=0;r<32;r++){ for(var r=0;r<32;r++){
var row = document.createElement('tr'); var row = document.createElement('tr');
table.appendChild(row); table.appendChild(row);
var col = document.createElement('td'); var col = document.createElement('td');
col.appendChild(document.createTextNode(hexWord(r*16)+':')); col.appendChild(document.createTextNode(hexWord(r*16)+':'));
col.onmousedown = unselectCell; col.onmousedown = unselectCell;
row.appendChild(col); row.appendChild(col);
for(var c=0;c<16;c++){ for(var c=0;c<16;c++){
col = document.createElement('td'); col = document.createElement('td');
col.addr = r*16+c; col.addr = r*16+c;
col.val = 0; col.val = 0;
col.onmousedown = function(e){handleCellClick(e);}; col.onmousedown = function(e){handleCellClick(e);};
col.appendChild(document.createTextNode('00')); col.appendChild(document.createTextNode('00'));
row.appendChild(col); row.appendChild(col);
} }
} }
} }
function handleCellClick(e){ function handleCellClick(e){
var c = e.target; var c = e.target;
selectCell(c.addr); selectCell(c.addr);
} }
function cellKeydown(e){ function cellKeydown(e){
var c = e.keyCode; var c = e.keyCode;
if(c==13) unselectCell(); if(c==13) unselectCell();
else if(c==32) selectCell((selected+1)%0x200); else if(c==32) selectCell((selected+1)%0x200);
else if(c==8) selectCell((selected+0x1ff)%0x200); else if(c==8) selectCell((selected+0x1ff)%0x200);
else if((c>=48)&&(c<58)) setCellValue(selected, getCellValue(selected)*16+c-48); else if((c>=48)&&(c<58)) setCellValue(selected, getCellValue(selected)*16+c-48);
else if((c>=65)&&(c<71)) setCellValue(selected, getCellValue(selected)*16+c-55); else if((c>=65)&&(c<71)) setCellValue(selected, getCellValue(selected)*16+c-55);
mWrite(selected, getCellValue(selected)); mWrite(selected, getCellValue(selected));
} }
function setCellValue(n, val){ function setCellValue(n, val){
val%=256; if(val==undefined)
cellEl(n).val=val; val=0x00;
cellEl(n).innerHTML=hexByte(val); val%=256;
} cellEl(n).val=val;
cellEl(n).innerHTML=hexByte(val);
function getCellValue(n){return cellEl(n).val;} }
function selectCell(n){ function getCellValue(n){return cellEl(n).val;}
unselectCell();
if(n>=0x200) return; function selectCell(n){
cellEl(n).style.background = '#ff8'; unselectCell();
selected = n; if(n>=0x200) return;
window.onkeydown = function(e){cellKeydown(e);}; cellEl(n).style.background = '#ff8';
} selected = n;
table.onkeydown = function(e){cellKeydown(e);};
function unselectCell(){ }
if(selected==undefined) return;
cellEl(selected).style.background = '#fff'; function unselectCell(){
selected = undefined; if(selected==undefined) return;
window.onkeydown = undefined; cellEl(selected).style.background = '#fff';
} selected = undefined;
window.onkeydown = undefined;
function cellEl(n){ }
var r = n>>4;
var c = n%16; function cellEl(n){
var e = table.children[r].children[c+1]; var r = n>>4;
return e; var c = n%16;
} var e = table.childNodes[r].childNodes[c+1];
return e;
}

View File

@ -1,117 +1,580 @@
/* /*
Copyright (c) 2010 Brian Silverman, Barry Silverman Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles, Segher Boessenkool
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
var nodenames ={ var nodenames ={
db1: 82, res: 159, // pads: reset
db0: 1005, rw: 1156, // pads: read not write
db3: 650, db0: 1005, // pads: databus
db2: 945, db1: 82,
db5: 175, db3: 650,
db4: 1393, db2: 945,
db7: 1349, db5: 175,
db6: 1591, db4: 1393,
a1: 1234, db7: 1349,
ab1: 451, db6: 1591,
ab2: 1340, ab0: 268, // pads: address bus
a2: 978, ab1: 451,
s2: 81, ab2: 1340,
a5: 858, ab3: 211,
a4: 727, ab4: 435,
a7: 1653, ab5: 736,
a6: 1136, ab6: 887,
so: 1672, ab7: 1493,
sync: 539, ab8: 230,
vcc: 657, ab9: 148,
clk1out: 1163, ab12: 1237,
p2: 1421, ab13: 349,
p3: 439, ab10: 1443,
p0: 687, ab11: 399,
p1: 1444, ab14: 672,
p6: 77, ab15: 195,
p7: 1370, sync: 539, // pads
p4: 1119, so: 1672, // pads: set overflow
p5: 0, clk0: 1171, // pads
pcl3: 1359, clk1out: 1163, // pads
pcl2: 655, clk2out: 421, // pads
pcl1: 1022, rdy: 89, // pads: ready
pcl0: 1139, nmi: 1297, // pads: non maskable interrupt
pcl7: 1611, irq: 103, // pads
pcl6: 377, vcc: 657, // pads
pcl5: 622, vss: 558, // pads
pcl4: 900,
clk0: 1171, a0: 737, // machine state: accumulator
s3: 1532, a1: 1234,
res: 159, a2: 978,
s1: 183, a3: 162,
s0: 1403, a4: 727,
s7: 1435, a5: 858,
s6: 1212, a6: 1136,
s5: 1098, a7: 1653,
s4: 1702, y0: 64, // machine state: y index register
rw: 1156, y1: 1148,
x2: 1, y2: 573,
x3: 1648, y3: 305,
x0: 1216, y4: 989,
x1: 98, y5: 615,
x6: 448, y6: 115,
x7: 777, y7: 843,
x4: 85, x0: 1216, // machine state: x index register
x5: 589, x1: 98,
rdy: 89, x2: 1,
clk2out: 421, x3: 1648,
nmi: 1297, x4: 85,
ab12: 1237, x5: 589,
ab13: 349, x6: 448,
ab10: 1443, x7: 777,
ab11: 399, pcl0: 1139, // machine state: program counter low (first storage node)
ab14: 672, pcl1: 1022,
ab15: 195, pcl2: 655,
ab0: 268, pcl3: 1359,
a0: 737, pcl4: 900,
a3: 162, pcl5: 622,
ab3: 211, pcl6: 377,
ab4: 435, pcl7: 1611,
ab5: 736, pclp0: 526, // machine state: program counter low (pre-incremented?, second storage node)
ab6: 887, pclp1: 1102,
ab7: 1493, pclp2: 1411,
ab8: 230, pclp3: 868,
ab9: 148, pclp4: 15,
pch7: 205, pclp5: 1326,
pch6: 1551, pclp6: 993,
pch5: 49, pclp7: 536,
pch4: 948, pch0: 1670, // machine state: program counter high (first storage node)
pch3: 584, pch1: 292,
pch2: 502, pch2: 502,
pch1: 292, pch3: 584,
pch0: 1670, pch4: 948,
irq: 103, pch5: 49,
vss: 558, pch6: 1551,
y1: 1148, pch7: 205,
y0: 64, pchp0: 780, // machine state: program counter high (pre-incremented?, second storage node)
y3: 305, pchp1: 126,
y2: 573, pchp2: 114,
y5: 615, pchp3: 1061,
y4: 989, pchp4: 820,
y7: 843, pchp5: 469,
y6: 115, pchp6: 751,
cclk: 943 pchp7: 663,
} p0: 687, // machine state: status register
p1: 1444,
p2: 1421,
p3: 439,
p4: 1119, // there is no bit4 in the status register!
p5: -1, // there is no bit5 in the status register!
p6: 77,
p7: 1370,
s0: 1403, // machine state: stack pointer
s1: 183,
s2: 81,
s3: 1532,
s4: 1702,
s5: 1098,
s6: 1212,
s7: 1435,
ir0: 328, // internal state: instruction register
ir1: 1626,
ir2: 1384,
ir3: 1576,
ir4: 1112,
ir5: 1329, // ir5 distinguishes branch set from branch clear
ir6: 337,
ir7: 1328,
notir0: 194, // internal signal: instruction register inverted outputs
notir1: 702,
notir2: 1182,
notir3: 1125,
notir4: 26,
notir5: 1394,
notir6: 895,
notir7: 1320,
irline3: 996, // internal signal: PLA input - ir0 AND ir1
clock1: 1536, // internal state: timing control
clock2: 156, // internal state: timing control
t2: 971, // internal state: timing control
t3: 1567,
t4: 690,
t5: 909,
nots0: 418, // datapath state: not stack pointer
nots1: 1064,
nots2: 752,
nots3: 828,
nots4: 1603,
nots5: 601,
nots6: 1029,
nots7: 181,
notidl0: 116, // datapath state: internal data latch (first storage node)
notidl1: 576,
notidl2: 1485,
notidl3: 1284,
notidl4: 1516,
notidl5: 498,
notidl6: 1537,
notidl7: 529,
idl0: 1597, // datapath signal: internal data latch (driven output)
idl1: 870,
idl2: 1066,
idl3: 464,
idl4: 1306,
idl5: 240,
idl6: 1116,
idl7: 391,
sb0: 54, // datapath bus: special bus
sb1: 1150,
sb2: 1287,
sb3: 1188,
sb4: 1405,
sb5: 166,
sb6: 1336,
sb7: 1001,
notalu0: 394, // datapath state: alu output storage node (inverse)
notalu1: 697,
notalu2: 276,
notalu3: 495,
notalu4: 1490,
notalu5: 893,
notalu6: 68,
notalu7: 1123,
alu0: 401, // datapath signal: ALU output
alu1: 872,
alu2: 1637,
alu3: 1414,
alu4: 606,
alu5: 314,
alu6: 331,
alu7: 765,
// datapath signal: decimally adjusted special bus
dasb0: 54, // same node as sb0
dasb1: 1009,
dasb2: 450,
dasb3: 1475,
dasb4: 1405, // same node as sb4
dasb5: 263,
dasb6: 679,
dasb7: 1494,
adl0: 413, // internal state: address latch low
adl1: 1282,
adl2: 1242,
adl3: 684,
adl4: 1437,
adl5: 1630,
adl6: 121,
adl7: 1299,
adh0: 407, // internal state: address latch high
adh1: 52,
adh2: 1651,
adh3: 315,
adh4: 1160,
adh5: 483,
adh6: 13,
adh7: 1539,
idb0: 1108, // internal state: data buffer
idb1: 991,
idb2: 1473,
idb3: 1302,
idb4: 892,
idb5: 1503,
idb6: 833,
idb7: 493,
notdor0: 222, // internal state: data output register (storage node)
notdor1: 527,
notdor2: 1288,
notdor3: 823,
notdor4: 873,
notdor5: 1266,
notdor6: 1418,
notdor7: 158,
dor0: 97, // internal signal: data output register
dor1: 746,
dor2: 1634,
dor3: 444,
dor4: 1088,
dor5: 1453,
dor6: 1415,
dor7: 63,
pd0: 1622, // internal state: predecode register output (anded with not ClearIR)
pd1: 809,
pd2: 1671,
pd3: 1587,
pd4: 540,
pd5: 667,
pd6: 1460,
pd7: 1410,
notpd0: 758, // internal state: predecode register (storage node)
notpd1: 361,
notpd2: 955,
notpd3: 894,
notpd4: 369,
notpd5: 829,
notpd6: 1669,
notpd7: 1690,
notRdy0: 248, // internal signal: global pipeline control
Reset0: 67, // internal signal: retimed reset from pin
C1x5Reset: 926, // retimed and pipelined reset in progress
notRnWprepad: 187, // internal signal: to pad, yet to be inverted and retimed
RnWstretched: 353, // internal signal: control datapad output drivers
cp1: 710, // internal signal: clock phase 1
cclk: 943, // unbonded pad: internal non-overlappying phi2
fetch: 879, // internal signal
clearIR: 1077, // internal signal
D1x1: 827, // internal signal: interrupt handler related
H1x1: 1042, // internal signal: drive status byte onto databus
// internal signal: pla outputs block 1 (west/left edge of die)
// often 130 pla outputs are mentioned - we have 131 here
"op-sty/cpy-mem": 1601, // pla0
"op-T3-ind-y": 60, // pla1
"op-T2-abs-y": 1512, // pla2
"op-T0-iny/dey": 382, // pla3
"x-op-T0-tya": 1173, // pla4
"op-T0-cpy/iny": 1233, // pla5
// internal signal: pla outputs block 2
"op-T2-idx-x-xy": 258, // pla6
"op-xy": 1562, // pla7
"op-T2-ind-x": 84, // pla8
"x-op-T0-txa": 1543, // pla9
"op-T0-dex": 76, // pla10
"op-T0-cpx/inx": 1658, // pla11
"op-from-x": 1540, // pla12
"op-T0-txs": 245, // pla13
"op-T0-ldx/tax/tsx": 985, // pla14
"op-T+-dex": 786, // pla15
"op-T+-inx": 1664, // pla16
"op-T0-tsx": 682, // pla17
"op-T+-iny/dey": 1482, // pla18
"op-T0-ldy-mem": 665, // pla19
"op-T0-tay/ldy-not-idx": 286, // pla20
// internal signal: pla outputs block 3
// not pla, feed through
"op-T0-jsr": 271, // pla21
"op-T5-brk": 370, // pla22
"op-T0-php/pha": 552, // pla23
"op-T4-rts": 1612, // pla24
"op-T3-plp/pla": 1487, // pla25
"op-T5-rti": 784, // pla26
"op-ror": 244, // pla27
"op-T2": 788, // pla28
"op-T0-eor": 1623, // pla29
"op-jmp": 764, // pla30
"op-T2-abs": 1057, // pla31
"op-T0-ora": 403, // pla32
"op-T2-ADL/ADD":204, // pla33
"op-T0":1273, // pla34
"op-T2-stack":1582, // pla35
"op-T3-stack/bit/jmp":1031, // pla36
// internal signal: pla outputs block 4
"op-T4-brk/jsr":804, // pla37
"op-T4-rti":1311, // pla38
"op-T3-ind-x":1428, // pla39
"op-T4-ind-y":492, // pla40
"op-T2-ind-y":1204, // pla41
"op-T3-abs-idx":58, // pla42
"op-plp/pla":1520, // pla43
"op-inc/nop":324, // pla44
"op-T4-ind-x":1259, // pla45
"x-op-T3-ind-y":342, // pla46
"op-rti/rts":857, // pla47
"op-T2-jsr":712, // pla48
"op-T0-cpx/cpy/inx/iny":1337, // pla49
"op-T0-cmp":1355, // pla50
"op-T0-sbc":787, // pla51 // 52:111XXXXX 1 0 T0SBC
"op-T0-adc/sbc":575, // pla52 // 51:X11XXXXX 1 0 T0ADCSBC
"op-rol/ror":1466, // pla53
// internal signal: pla outputs block 5
"op-T3-jmp":1381, // pla54
"op-shift":546, // pla55
"op-T5-jsr":776, // pla56
"op-T2-stack-access":157, // pla57
"op-T0-tya":257, // pla58
"op-T+-ora/and/eor/adc":1243, // pla59
"op-T+-adc/sbc":822, // pla60
"op-T+-shift-a":1324, // pla61
"op-T0-txa":179, // pla62
"op-T0-pla":131, // pla63
"op-T0-lda":1420, // pla64
"op-T0-acc":1342, // pla65
"op-T0-tay":4, // pla66
"op-T0-shift-a":1396, // pla67
"op-T0-tax":167, // pla68
"op-T0-bit":303, // pla69
"op-T0-and":1504, // pla70
"op-T4-abs-idx":354, // pla71
"op-T5-ind-y":1168, // pla72
// internal signal: pla outputs block 6
"op-branch-done":1721, // pla73 // has extra non-pla input
"op-T2-pha":1086, // pla74
"op-T0-shift-right-a":1074, // pla75
"op-shift-right":1246, // pla76
"op-T2-brk":487, // pla77
"op-T3-jsr":579, // pla78
"op-sta/cmp":145, // pla79
"op-T2-branch":1239, // pla80 // T2BR, 83 for Balazs
"op-T2-zp/zp-idx":285, // pla81
// not pla, feed through
// not pla, feed through
"op-T2-ind":1524, // pla82
"op-T2-abs-access":273, // pla83 // has extra pulldown: pla97
"op-T5-rts":0, // pla84
"op-T4":341, // pla85
"op-T3":120, // pla86
"op-T0-brk/rti":1478, // pla87
"op-T0-jmp":594, // pla88
"op-T5-ind-x":1210, // pla89
"op-T3-abs/idx/ind":677, // pla90 // has extra pulldown: pla97
// internal signal: pla outputs block 7
"x-op-T4-ind-y":461, // pla91
"x-op-T3-abs-idx":447, // pla92
"op-T3-branch":660, // pla93
"op-brk/rti":1557, // pla94
"op-jsr":259, // pla95
"x-op-jmp":1052, // pla96
// gap
"op-push/pull":791, // pla97 // feeds into pla83 and pla90 (no normal pla output)
"op-store":517, // pla98
"op-T4-brk":352, // pla99
"op-T2-php":750, // pla100
"op-T2-php/pha":932, // pla101
"op-T4-jmp":1589, // pla102
// gap
"op-T5-rti/rts":446, // pla103
"xx-op-T5-jsr":528, // pla104
// internal signal: pla outputs block 8
"op-T2-jmp-abs":309, // pla105
"x-op-T3-plp/pla":1430, // pla106
"op-lsr/ror/dec/inc":53, // pla107
"op-asl/rol":691, // pla108
"op-T0-cli/sei":1292, // pla109
// gap
"op-T+-bit":1646, // pla110
"op-T0-clc/sec":1114, // pla111
"op-T3-mem-zp-idx":904, // pla112
"x-op-T+-adc/sbc":1155, // pla113
"x-op-T0-bit":1476, // pla114
"op-T0-plp":1226, // pla115
"x-op-T4-rti":1569, // pla116
"op-T+-cmp":301, // pla117
"op-T+-cpx/cpy-abs":950, // pla118
"op-T+-asl/rol-a":1665, // pla119
// internal signal: pla outputs block 9
"op-T+-cpx/cpy-imm/zp":1710, // pla120
"x-op-push/pull":1050, // pla121 // feeds into pla130 (no normal pla output)
"op-T0-cld/sed":1419, // pla122
"#op-branch-bit6":840, // pla123 // IR bit6 used only to detect branch type
"op-T3-mem-abs":607, // pla124
"op-T2-mem-zp":219, // pla125
"op-T5-mem-ind-idx":1385, // pla126
"op-T4-mem-abs-idx":281, // pla127
"#op-branch-bit7":1174, // pla128 // IR bit7 used only to detect branch type
"op-clv":1164, // pla129
"op-implied":1006, // pla130 // has extra pulldowns: pla121 and ir0
// internal signals: control signals
nnT2BR: 967, // doubly inverted
BRtaken: 1544,
// internal state: misc pipeline state clocked by cclk (phi2)
pipeBRtaken: 832,
pipeUNK01: 1530,
pipeUNK02: 974,
pipeUNK03: 1436,
pipeUNK04: 99,
pipeUNK05: 44,
pipeUNK06: 443,
pipeUNK07: 215,
pipeUNK08: 338,
pipeUNK09: 199,
pipeUNK10: 215,
pipeUNK11: 1011,
pipeUNK12: 1283,
pipeUNK13: 1442,
pipeUNK14: 1607,
pipeUNK15: 1577, // inverse of H1x1, write P onto idb (PHP, interrupt)
pipeUNK16: 1051,
pipeUNK17: 1078,
pipeUNK18: 899,
pipeUNK19: 832,
pipeUNK20: 294,
pipeUNK21: 1176,
pipeUNK22: 561, // becomes dpc22
pipeUNK23: 596,
pipephi2Reset0: 449,
pipephi2Reset0x: 1036, // a second copy of the same latch
pipeUNK26: 1321,
pipeUNK27: 73,
pipeUNK28: 685,
pipeUNK29: 1008,
pipeUNK30: 1652,
pipeUNK31: 614,
pipeUNK32: 960,
pipeUNK33: 848,
pipeUNK34: 56,
pipeUNK35: 1713,
pipeUNK36: 729,
pipeUNK37: 197,
pipeUNK38: 1131,
pipeUNK39: 151,
pipeUNK40: 456,
pipeUNK41: 1438,
pipeUNK42: 1104,
pipeUNK43: 554,
// internal state: vector address pulldown control
pipeVectorA0: 357,
pipeVectorA1: 170,
pipeVectorA2: 45,
// internal state: datapath control drivers
pipedpc28: 683,
// internal signals: alu internal (private) busses
alua0: 1167,
alua1: 1248,
alua2: 1332,
alua3: 1680,
alua4: 1142,
alua5: 530,
alua6: 1627,
alua7: 1522,
alub0: 977,
alub1: 1432,
alub2: 704,
alub3: 96,
alub4: 1645,
alub5: 1678,
alub6: 235,
alub7: 1535,
aluanorb0: 143,
aluanandb0: 1628,
aluaorb0: 693,
notaluoutmux0: 957, // alu result latch input
aluanorb1: 155,
aluanandb1: 841,
aluaorb1: 1021,
notaluoutmux1: 250, // alu result latch input
// internal signals: datapath control signals
dpc0_YSB: 801, // drive sb from y
dpc1_SBY: 325, // load y from sb
dpc2_XSB: 1263, // drive sb from x
dpc3_SBX: 1186, // load x from sb
dpc4_SSB: 1700, // drive sb from stack pointer
dpc5_SADL: 1468, // drive adl from stack pointer
dpc6_SBS: 874, // load stack pointer from sb
dpc7_SS: 654, // recirculate stack pointer
dpc8_nDBADD: 1068, // alu b side: select not-idb input
dpc9_DBADD: 859, // alu b side: select idb input
dpc10_ADLADD: 437, // alu b side: select adl input
dpc11_SBADD: 549, // alu a side: select sb
dpc12_0ADD: 984, // alu a side: select zero
dpc13_ORS: 59, // alu op: a or b
dpc14_SRS: 362, // alu op: logical right shift
dpc15_ANDS: 574, // alu op: a and b
dpc16_EORS: 1666, // alu op: a xor b (?)
dpc17_SUMS: 921, // alu op: a plus b (?)
alucin: 910, // alu carry in
notalucin: 1165,
dpc18_DAA: 1201, // decimal related
dpc19_ADDSB7: 214, // alu to sb bit 7 only
dpc20_ADDSB06: 129, // alu to sb bits 6-0 only
dpc21_ADDADL: 1015, // alu to adl
alurawcout: 808, // alu raw carry out (no decimal adjust)
alucout: 1146, // alu carry out (latched by phi2)
notaluvout: 1308, // alu overflow out
aluvout: 938, // alu overflow out (latched by phi2)
dpc22_DSA: 725, // decimal related/SBC only
dpc23_SBAC: 534, // (optionalls decimal-adjusted) sb to acc
dpc24_ACSB: 1698, // acc to sb
dpc25_SBDB: 1060, // sb pass-connects to idb
dpc26_ACDB: 1331, // acc to idb
dpc27_SBADH: 140, // sb pass-connects to adh
dpc28_0ADH0: 229, // zero to adh0 bit0 only
dpc29_0ADH17: 203, // zero to adh bits 7-1 only
dpc30_ADHPCH: 48, // load pch from adh
dpc31_PCHPCH: 741, // load pch from pch incremented
dpc32_PCHADH: 1235, // drive adh from pch incremented
dpc33_PCHDB: 247, // drive idb from pch incremented
dpc34_PCLC: 1704, // pch carry in and pcl FF detect?
dpc35: 1334, // pcl 0x?F detect - half-carry
dpc36_IPC: 379, // pcl carry in
dpc37_PCLDB: 283, // drive idb from pcl incremented
dpc38_PCLADL: 438, // drive adl from pcl incremented
dpc39_PCLPCL: 898, // load pcl from pcl incremented
dpc40_ADLPCL: 414, // load pcl from adl
dpc41: 1564, // pass-connect adl to mux node driven by idl
dpc42: 41, // pass-connect adh to mux node driven by idl
dpc43: 863, // pass-connect idb to mux node driven by idl
}

View File

@ -1,18 +0,0 @@
<?php
$filename = $_REQUEST['name'];
file_put_contents($filename, file_get_contents("php://input"));
function file_put_contents($filename, $data) {
$f = @fopen($filename, 'w');
if ($f) {
$bytes = fwrite($f, $data);
fclose($f);
return $bytes;
}
return false;
}
?>

16481
segdefs.js

File diff suppressed because it is too large Load Diff

15
testprogram.js Normal file
View File

@ -0,0 +1,15 @@
// 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
];

File diff suppressed because it is too large Load Diff

View File

@ -1,68 +0,0 @@
body {
background: white;
color: black;
font-family: cursive;
font-size: 30px;
}
div.frame {
margin-left: 10px;
position: relative;
width: 1150px;
height: 600px;
}
div.chip {
background: lightgray;
border: 2px solid gray;
position: absolute;
width: 800px;
height: 600px;
overflow: hidden;
}
canvas.chip {
position: absolute;
width: 600px;
height: 600px;
}
div.buttons{
position: absolute;
top: -5px;
left: 820px;
}
p.status {
position: absolute;
left: 820px;
top: 20px;
font-family: monospace;
font-size: 12px;
}
img.navbutton{
margin-left: -5px;
border: 0px;
}
img.navplay{
margin-left: -5px;
border: 0px;
}
img.navstop{
position: absolute;
left: -5px;
top: 9px;
border: 0px;
}
table.memtable {
position: absolute;
top: 63px;
left: 820px;
font-family: monospace;
font-size: 12px;
border-spacing: 0px;
}

570
wires.js
View File

@ -1,338 +1,232 @@
/* /*
Copyright (c) 2010 Brian Silverman, Barry Silverman Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
var frame, chipbg, overlay, hilite, hitbuffer, ctx; var frame, chipbg, overlay, hilite, hitbuffer, ctx;
var centerx=300, centery=300; var nodes = new Array();
var zoom=1; var transistors = {};
var dragMouseX, dragMouseY, moved; var nodenamelist=[];
var statbox;
var ngnd = nodenames['vss'];
var colors = ['rgba(128,128,128,0.4)','#FFFF00','#FF00FF','#4DFF4D', var npwr = nodenames['vcc'];
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
var chipLayoutIsVisible = true; // only modified in expert mode
var nodes = new Array();
var transistors = {}; function setupNodes(){
for(var i in segdefs){
var ngnd = nodenames['vss']; var seg = segdefs[i];
var npwr = nodenames['vcc']; var w = seg[0];
if(nodes[w]==undefined)
nodes[w] = {segs: new Array(), num: w, pullup: seg[1]=='+',
///////////////////////// state: false, gates: new Array(), c1c2s: new Array()};
// if(w==ngnd) continue;
// Drawing Setup if(w==npwr) continue;
// nodes[w].segs.push(seg.slice(3));
///////////////////////// }
}
function setup(){
frame = document.getElementById('frame'); function setupTransistors(){
statbox = document.getElementById('status'); for(i in transdefs){
setupNodes(); var tdef = transdefs[i];
setupTransistors(); var name = tdef[0];
setupBackground(); var gate = tdef[1];
setupOverlay(); var c1 = tdef[2];
setupHilite(); var c2 = tdef[3];
setupHitBuffer(); if(c1==ngnd) {c1=c2;c2=ngnd;}
recenter(); if(c1==npwr) {c1=c2;c2=npwr;}
refresh(); var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2};
setupTable(); nodes[gate].gates.push(trans);
window.onkeypress = function(e){handleKey(e);} nodes[c1].c1c2s.push(trans);
hilite.onmousedown = function(e){mouseDown(e);} nodes[c2].c1c2s.push(trans);
initChip(); transistors[name] = trans;
document.getElementById('stop').style.visibility = 'hidden'; }
go(); }
}
function setupLayerVisibility(){
function setupNodes(){ var x=document.getElementById('updateShow');
for(var i in segdefs){ for (var i=0;i<x.childNodes.length;i++) {
var seg = segdefs[i]; if(x.childNodes[i].type='checkbox'){
var w = seg[0]; x.childNodes[i].checked=drawlayers[x.childNodes[i].name];
if(nodes[w]==undefined) }
nodes[w] = {segs: new Array(), num: w, pullup: seg[1]=='+', }
state: 'fl', gates: new Array(), c1c2s: new Array()}; }
if(w==ngnd) continue;
if(w==npwr) continue; function setupBackground(){
nodes[w].segs.push(seg.slice(3)); chipbg = document.getElementById('chipbg');
} chipbg.width = grCanvasSize;
} chipbg.height = grCanvasSize;
var ctx = chipbg.getContext('2d');
function setupTransistors(){ ctx.fillStyle = '#000000';
for(i in transdefs){ ctx.strokeStyle = 'rgba(255,255,255,0.5)';
var tdef = transdefs[i]; ctx.lineWidth = grLineWidth;
var name = tdef[0]; ctx.fillRect(0,0,grCanvasSize,grCanvasSize);
var gate = tdef[1]; for(var i in segdefs){
var c1 = tdef[2]; var seg = segdefs[i];
var c2 = tdef[3]; var c = seg[2];
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2}; if (drawlayers[c]) {
nodes[gate].gates.push(name); ctx.fillStyle = colors[c];
nodes[c1].c1c2s.push(name); drawSeg(ctx, segdefs[i].slice(3));
nodes[c2].c1c2s.push(name); ctx.fill();
transistors[name] = trans; if((c==0)||(c==6)) ctx.stroke();
} }
} }
}
function setupBackground(){ function setupOverlay(){
chipbg = document.getElementById('chipbg'); overlay = document.getElementById('overlay');
chipbg.width = 4000; overlay.width = grCanvasSize;
chipbg.height = 4000; overlay.height = grCanvasSize;
var ctx = chipbg.getContext('2d'); ctx = overlay.getContext('2d');
ctx.scale(chipbg.width/10000, chipbg.height/10000); }
ctx.fillStyle = '#000000';
ctx.strokeStyle = 'rgba(255,255,255,0.5)'; function setupHilite(){
ctx.lineWidth = 4; hilite = document.getElementById('hilite');
ctx.fillRect(0,0,10000,10000); hilite.width = grCanvasSize;
var start = now(); hilite.height = grCanvasSize;
for(var i in segdefs){ var ctx = hilite.getContext('2d');
var seg = segdefs[i]; }
var c = seg[2];
ctx.fillStyle = colors[c]; function setupHitBuffer(){
drawSeg(ctx, segdefs[i].slice(3)); hitbuffer = document.getElementById('hitbuffer');
ctx.fill(); hitbuffer.width = grCanvasSize;
if((c==0)||(c==6)) ctx.stroke(); hitbuffer.height = grCanvasSize;
} hitbuffer.style.visibility = 'hidden';
// console.log('time to draw: ', now() - start, ' ms'); var ctx = hitbuffer.getContext('2d');
} for(i in nodes) hitBufferNode(ctx, i, nodes[i].segs);
}
function setupOverlay(){
overlay = document.getElementById('overlay'); function hitBufferNode(ctx, i, w){
overlay.width = 4000; var low = hexdigit(i&0xf);
overlay.height = 4000; var mid = hexdigit((i>>4)&0xf);
ctx = overlay.getContext('2d'); var high = hexdigit((i>>8)&0xf);
ctx.scale(overlay.width/10000, overlay.height/10000); ctx.fillStyle = '#'+high+'F'+mid+'F'+low+'F';
} for(i in w) {
drawSeg(ctx, w[i]);
function setupHilite(){ ctx.fill();
hilite = document.getElementById('hilite'); }
hilite.width = 4000; }
hilite.height = 4000;
var ctx = hilite.getContext('2d'); function hexdigit(n){return '0123456789ABCDEF'.charAt(n);}
ctx.scale(hilite.width/10000, hilite.height/10000);
}
/////////////////////////
function setupHitBuffer(){ //
hitbuffer = document.getElementById('hitbuffer'); // Drawing Runtime
hitbuffer.width = 4000; //
hitbuffer.height = 4000; /////////////////////////
hitbuffer.style.visibility = 'hidden';
var ctx = hitbuffer.getContext('2d'); function refresh(){
ctx.scale(hitbuffer.width/10000, hitbuffer.height/10000); if(!chipLayoutIsVisible) return;
for(i in nodes) hitBufferNode(ctx, i, nodes[i].segs); ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
} for(i in nodes){
if(isNodeHigh(i)) overlayNode(nodes[i].segs);
function hitBufferNode(ctx, i, w){ }
var low = hexdigit(i&0xf); }
var mid = hexdigit((i>>4)&0xf);
var high = hexdigit((i>>8)&0xf); function overlayNode(w){
ctx.fillStyle = '#'+high+'F'+mid+'F'+low+'F'; ctx.fillStyle = 'rgba(255,0,64,0.4)';
for(i in w) { for(i in w) {
drawSeg(ctx, w[i]); drawSeg(ctx, w[i]);
ctx.fill(); ctx.fill();
} }
} }
function hexdigit(n){return '0123456789ABCDEF'.charAt(n);} function hiliteNode(n){
var ctx = hilite.getContext('2d');
ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
///////////////////////// ctx.fillStyle = 'rgba(255,255,255,0.7)';
// if(n==-1) return;
// Drawing Runtime if(isNodeHigh(n[0]))
// ctx.fillStyle = 'rgba(255,0,0,0.7)';
/////////////////////////
for(var i in n){
function refresh(){ var segs = nodes[n[i]].segs;
ctx.clearRect(0,0,10000,10000); for(var s in segs){drawSeg(ctx, segs[s]); ctx.fill();}
for(i in nodes){ }
if(isNodeHigh(i)) overlayNode(nodes[i].segs); }
}
} function drawSeg(ctx, seg){
var dx = 400;
function overlayNode(w){ ctx.beginPath();
ctx.fillStyle = 'rgba(255,0,64,0.4)'; ctx.moveTo(grScale(seg[0]+dx), grScale(grChipSize-seg[1]));
for(i in w) { for(var i=2;i<seg.length;i+=2) ctx.lineTo(grScale(seg[i]+dx), grScale(grChipSize-seg[i+1]));
drawSeg(ctx, w[i]); ctx.lineTo(grScale(seg[0]+dx), grScale(grChipSize-seg[1]));
ctx.fill(); }
}
} function findNodeNumber(x,y){
var ctx = hitbuffer.getContext('2d');
function hiliteNode(n){ var pixels = ctx.getImageData(x*grCanvasSize/600, y*grCanvasSize/600, 2, 2).data;
var ctx = hilite.getContext('2d'); if(pixels[0]==0) return -1;
ctx.clearRect(0,0,10000,10000); var high = pixels[0]>>4;
ctx.fillStyle = 'rgba(255,255,255,0.7)'; var mid = pixels[1]>>4;
if(n==-1) return; var low = pixels[2]>>4;
if(isNodeHigh(n[0])) return (high<<8)+(mid<<4)+low;
ctx.fillStyle = 'rgba(255,0,0,0.7)'; }
for(var i in n){ function clearHighlight(){
var segs = nodes[n[i]].segs; // remove red/white overlay according to logic value
for(var s in segs){drawSeg(ctx, segs[s]); ctx.fill();} // for easier layout navigation
} ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
} }
function updateShow(layer, on){
function drawSeg(ctx, seg){ drawlayers[layer]=on;
var dx = 400; setupBackground();
ctx.beginPath(); }
ctx.moveTo(seg[0]+dx, 10000-seg[1])
for(var i=2;i<seg.length;i+=2) ctx.lineTo(seg[i]+dx, 10000-seg[i+1]); // we draw the chip data scaled down to the canvas
ctx.lineTo(seg[0]+dx, 10000-seg[1]) // and so avoid scaling a large canvas
} function grScale(x){
return Math.round(x*grCanvasSize/grChipSize);
///////////////////////// }
//
// User Interface function localx(el, gx){
// return gx-el.getBoundingClientRect().left;
///////////////////////// }
function handleKey(e){ function localy(el, gy){
var c = e.charCode; return gy-el.getBoundingClientRect().top;
c = String.fromCharCode(c); }
if('<>?np'.indexOf(c)==-1) return;
if(c=='<' && zoom>1) setZoom(zoom/1.2); function setStatus(){
else if(c=='>' && zoom<16) setZoom(zoom*1.2); var res = '';
else if(c=='?') setZoom(1); // pad the arguments to make this a three-line display
else if(c=='n') stepForward(); // there must be a clean way to do this
else if(c=='p') stepBack(); if(arguments[1]==undefined)arguments[1]="";
} if(arguments[2]==undefined)arguments[2]="";
arguments.length=3;
function mouseDown(e){ for(var i=0;i<arguments.length;i++) res=res+arguments[i]+'<br>';
e.preventDefault(); statbox.innerHTML = res;
moved=false; }
dragMouseX = e.clientX;
dragMouseY = e.clientY; function setupNodeNameList(){
window.onmousemove = function(e){mouseMove(e)}; for(var i in nodenames)
window.onmouseup = function(e){mouseUp(e)}; nodenamelist.push(i);
} }
function mouseMove(e){ function nodeName(n) {
moved = true; for(var i in nodenames){
if(zoom==1) return; if(nodenames[i]==n) return i;
var dx = e.clientX-dragMouseX; }
var dy = e.clientY-dragMouseY; return '';
dragMouseX = e.clientX; }
dragMouseY = e.clientY;
centerx-=dx/zoom; function now(){return new Date().getTime();}
centerx = Math.max(centerx, 400/zoom);
centerx = Math.min(centerx, 600-400/zoom);
centery-=dy/zoom;
centery = Math.max(centery, 300/zoom);
centery = Math.min(centery, 600-300/zoom);
recenter();
}
function mouseUp(e){
if(!moved) handleClick(e);
window.onmousemove = undefined;
window.onmouseup = undefined;
}
function setZoom(n){
zoom = n;
setChipStyle({
width: 600*n+'px',
height: 600*n+'px'
});
recenter();
}
function recenter(){
var top = -centery*zoom+300;
top = Math.min(top, 0);
top = Math.max(top, -600*(zoom-1));
var left = -centerx*zoom+400;
left = Math.min(left, 0);
left = Math.max(left, (zoom==1)?100:-600*zoom+800);
setChipStyle({
top: top+'px',
left: left+'px',
});
}
function handleClick(e){
var x = localx(hilite, e.clientX)/zoom;
var y = localy(hilite, e.clientY)/zoom;
var w = findNodeNumber(x,y);
if(e.shiftKey) hiliteNode(getNodeGroup(w));
else {var a=new Array(); a.push(w); hiliteNode(a);}
var cx = Math.round(x*10000/600);
var cy = Math.round(y*10000/600);
if(w==-1) setStatus('x:',cx,'<br>','y:',cy);
else {setStatus('x:',cx, 'y:', cy,'<br>','node:',w, nodeName(w));}
}
function findNodeNumber(x,y){
var ctx = hitbuffer.getContext('2d');
var pixels = ctx.getImageData(x*4000/600, y*4000/600, 2, 2).data;
if(pixels[0]==0) return -1;
var high = pixels[0]>>4;
var mid = pixels[1]>>4;
var low = pixels[2]>>4;
return (high<<8)+(mid<<4)+low;
}
/////////////////////////
//
// Etc.
//
/////////////////////////
function setChipStyle(props){
for(var i in props){
chipbg.style[i] = props[i];
overlay.style[i] = props[i];
hilite.style[i] = props[i];
hitbuffer.style[i] = props[i];
}
}
function localx(el, gx){
var lx = gx+window.pageXOffset;
while(el.offsetLeft!=undefined){
lx-=el.offsetLeft+el.clientLeft;
el = el.parentNode;
}
return lx;
}
function localy(el, gy){
var ly = gy+window.pageYOffset;
while(el.offsetTop!=undefined){
ly-=el.offsetTop+el.clientTop;
el = el.parentNode;
}
return ly;
}
function setStatus(){
var res = '';
for(var i=0;i<arguments.length;i++) res=res+arguments[i]+' ';
statbox.innerHTML = res;
}
function nodeName(n) {
for(var i in nodenames){
if(nodenames[i]==n) return i;
}
return '';
}
function now(){return new Date().getTime();}