Compare commits
322 Commits
Author | SHA1 | Date |
---|---|---|
BigEd | d8ecc129b3 | |
BigEd | d14ade8be8 | |
BigEd | bc5da26ea2 | |
BigEd | 15911b02b4 | |
BigEd | badcf8e40b | |
Goran Devic | 8097137323 | |
BigEd | 5b86a57c2c | |
BigEd | 0d4cb75658 | |
David Banks | cb7815e1ad | |
BigEd | 7ee143a906 | |
John Scarfone | 52540e3c12 | |
BigEd | f33937cc92 | |
David Banks | deb6833f8a | |
David Banks | 296cd01f84 | |
David Banks | 8e799d6922 | |
David Banks | a4ed7a9178 | |
David Banks | 9795b463ac | |
David Banks | b384fb552f | |
David Banks | bf63c33552 | |
David Banks | 9760663cc1 | |
David Banks | 3ae93282ba | |
David Banks | ab53a12b2e | |
David Banks | a92f443ac1 | |
David Banks | 86e6e116d7 | |
David Banks | f360557572 | |
David Banks | 5005774b1b | |
David Banks | 924074e305 | |
Ed Spittles | b0c40b9e7b | |
BigEd | 74762264c1 | |
David Banks | 6fcb3077eb | |
David Banks | cbebb0e11d | |
BigEd | 2612132999 | |
Trent Reed | 8327a36826 | |
BigEd | 886efe1d5a | |
David Banks | d9c92ebdc3 | |
David Banks | 651a1753b7 | |
David Banks | f5cada53f7 | |
David Banks | 7d579fa4aa | |
David Banks | e33f40e60c | |
David Banks | 379d2d1ea1 | |
David Banks | 59792d75fc | |
David Banks | 225b49a6d8 | |
David Banks | 3de51801ea | |
David Banks | 2f882d7d34 | |
David Banks | b9e235fac2 | |
David Banks | 0e4c3e0ab0 | |
David Banks | 767e2492be | |
David Banks | 95f9d52306 | |
David Banks | 646f22b79e | |
David Banks | 2ff43fafb3 | |
David Banks | 8a9fe6f57e | |
David Banks | 3315f309a7 | |
David Banks | 85058171b2 | |
David Banks | 7a0cb72539 | |
Ed Spittles | 0a6866f10c | |
BigEd | 5b15e2d6c9 | |
BigEd | e6e446a256 | |
BigEd | bd0356f2a0 | |
BigEd | 096f6bbcf8 | |
mmfoerster | 698312b98e | |
BigEd | bd45334147 | |
mmfoerster | 7efe4fb8c7 | |
mmfoerster | ef0a714a29 | |
BigEd | e0547e6c35 | |
mmfoerster | 76edc1186a | |
mmfoerster | c1409b78cb | |
mmfoerster | d39bab7302 | |
mmfoerster | 587fa47d8a | |
mmfoerster | 27d0eb8fb2 | |
BigEd | 90f57631c0 | |
mmfoerster | cba0c7a6b5 | |
mmfoerster | c2348c5f63 | |
BigEd | 4bb43bfd0e | |
mmfoerster | 8d50388828 | |
Ed S | 1f78e25b3a | |
Ed S | 4364604b96 | |
BigEd | 2147762ee4 | |
BigEd | 651d8a44c5 | |
mmfoerster | 51d6bb216b | |
BigEd | 3b7fbe4385 | |
trebonian | f3cffeeed6 | |
BigEd | a2a4bc65c5 | |
trebonian | 815e972d14 | |
trebonian | 9f4f922e16 | |
trebonian | 27bec1bfe5 | |
BigEd | 976fe7e430 | |
shersom | 72ac2caf74 | |
trebonian | 741e035eb4 | |
BigEd | dd2241d3de | |
BigEd | c0809ba34e | |
Peter Mortensen | df33b88c56 | |
trebonian | 7d90b33187 | |
BigEd | 34244661cb | |
BigEd | ce74c3f5d3 | |
BigEd | cb03b9741a | |
BigEd | 7b95b5e345 | |
BigEd | de265ecdb8 | |
BigEd | e81c9fbe0f | |
BigEd | c300e6ad01 | |
BigEd | 79d0c4c445 | |
BigEd | a2d35d54ca | |
BigEd | e20eb08b91 | |
BigEd | 8487a7a9e1 | |
BigEd | 6c138a4f6b | |
BigEd | 658d40646c | |
BigEd | 67e15e68c1 | |
BigEd | a316831100 | |
ijor | acd7b0310e | |
BigEd | 9331be20fe | |
BigEd | e6d42eb1aa | |
BigEd | 8ae5c087f6 | |
BigEd | c6dd03ba17 | |
BigEd | fca2eb5cb6 | |
BigEd | b5c1759f32 | |
BigEd | 6ceae74e4a | |
BigEd | 94b306bace | |
BigEd | 9308b26c42 | |
BigEd | 335cb06832 | |
BigEd | d9440fa160 | |
BigEd | 10ba01cf12 | |
BigEd | e8b964a24f | |
BigEd | bbfcf77134 | |
BigEd | 73f21ffc47 | |
BigEd | 4e2c84dabc | |
BigEd | ca7124b176 | |
BigEd | b0710a4cda | |
BigEd | baac06bdc3 | |
BigEd | 9bb8caa025 | |
BigEd | b98010206e | |
BigEd | 7049cef9b7 | |
BigEd | 9d23382644 | |
BigEd | 8f5f50d197 | |
BigEd | 1d21f5ae8b | |
BigEd | 15b25491b9 | |
BigEd | 6033109dc6 | |
BigEd | 0e41f0a9a9 | |
BigEd | cb29fb4fad | |
BigEd | c02d181d5c | |
BigEd | 51d0e99389 | |
BigEd | d11cf44ae9 | |
BigEd | 2e69d3a7c3 | |
Barry Silverman | f098566335 | |
BigEd | e25ac6243c | |
BigEd | 94e22becb4 | |
BigEd | a56ee40bd8 | |
BigEd | 2ace0e8bad | |
BigEd | 84b005673b | |
BigEd | 09c578e361 | |
BigEd | 167f93f836 | |
BigEd | c88e0749cf | |
BigEd | 6db8836c5c | |
BigEd | 27fb1d539e | |
BigEd | 21c7a8ca90 | |
BigEd | cfb726d0e7 | |
BigEd | d352501c7c | |
Barry Silverman | 4eb1e4c848 | |
Barry Silverman | c3f0d10199 | |
Barry Silverman | 4398fdaddf | |
Barry Silverman | 4f7930eef3 | |
BigEd | c04f37a3df | |
BigEd | fc664c7243 | |
Barry Silverman | 8bdb9a0682 | |
BigEd | ae30a57822 | |
Sigbjorn Finne | 8a89310e96 | |
Sigbjorn Finne | 1c66a8af28 | |
BigEd | 78deb4aaa4 | |
Sigbjorn Finne | 85c8447064 | |
Sigbjorn Finne | 6cdbfc0c15 | |
BigEd | 8ef98d131f | |
BigEd | e660736204 | |
BigEd | fc46e50289 | |
BigEd | 4967b58e7f | |
BigEd | 6f7dab7990 | |
BigEd | 04196aa36a | |
BigEd | 94a2b38d27 | |
BigEd | e052255c55 | |
Barry Silverman | 15453f4435 | |
Barry Silverman | 7572b25453 | |
BigEd | 93252a0eb1 | |
BigEd | 172394845a | |
BigEd | ec7da19d77 | |
BigEd | 13e1f51b47 | |
BigEd | e6d3c62057 | |
BigEd | fbf0830d15 | |
BigEd | 019bca0a26 | |
BigEd | e866a3b58e | |
BigEd | 611490ad76 | |
BigEd | b3e58dcbab | |
BigEd | c7ac03edd8 | |
BigEd | b51b5c4398 | |
BigEd | 8f2e296ef6 | |
BigEd | ee2fa1befd | |
BigEd | 7c50999c9e | |
BigEd | 398060f56b | |
BigEd | cdd837dd0c | |
BigEd | 3df7065b83 | |
BigEd | f860067206 | |
BigEd | 33f00022ca | |
BigEd | abf6daef7d | |
BigEd | 8a6fe3634f | |
BigEd | 296599890a | |
BigEd | 580f4585a6 | |
BigEd | d045485ec4 | |
BigEd | 71a85b3135 | |
BigEd | b3a6a12ddc | |
BigEd | 5f472cbe10 | |
BigEd | 6ced887613 | |
BigEd | 3bf9ae1fac | |
BigEd | 6be4dd1673 | |
BigEd | c4af64f5e8 | |
BigEd | 7e6eb926ee | |
Barry Silverman | 6c899eda1a | |
BigEd | 82daddcfe4 | |
BigEd | 6c2217b8fa | |
BigEd | 50ecadaa00 | |
BigEd | f6a86088f0 | |
BigEd | 8a2342d83c | |
BigEd | 5c9b4e7581 | |
BigEd | 2a0e251088 | |
BigEd | 60b4ecab22 | |
BigEd | d2a31398fd | |
BigEd | 3804eace6e | |
BigEd | 369a188ad9 | |
BigEd | 9ff6ae027e | |
BigEd | 678acd6dc5 | |
BigEd | 758d53bf5b | |
BigEd | e885646e5e | |
BigEd | 353e0a8f78 | |
BigEd | 18e1946488 | |
BigEd | 0c6a90a558 | |
BigEd | 93e6d662df | |
BigEd | 0842501bb7 | |
BigEd | 294918789a | |
BigEd | cd05762f20 | |
BigEd | ef0bb5cdec | |
BigEd | 25e8397a0f | |
BigEd | 44b5c5e9d3 | |
BigEd | 633a2693ac | |
BigEd | da7ec1f3e3 | |
BigEd | bed571f10c | |
BigEd | 192d9a8ba8 | |
BigEd | b4747b0cad | |
BigEd | 62b0b314d5 | |
BigEd | 39959e711e | |
BigEd | 0156a72ae7 | |
BigEd | 759c188ef6 | |
BigEd | a406cee106 | |
BigEd | e3354a2aa4 | |
BigEd | 68e022a2bd | |
Barry Silverman | c4dcbcb435 | |
BigEd | bc8ef61fb9 | |
Barry Silverman | 86e544a065 | |
BigEd | ea9f54c398 | |
BigEd | dd95b40c6c | |
BigEd | 3fcc3ee787 | |
BigEd | 83af54a47d | |
BigEd | c9443e6718 | |
BigEd | e93c11ab20 | |
BigEd | 0d0973b0c6 | |
Barry Silverman | 4b19e21e66 | |
Barry Silverman | df6aaa392c | |
Barry Silverman | 5a4c574765 | |
Barry Silverman | 10787078c8 | |
Barry Silverman | 98ec727c50 | |
Barry Silverman | 33aa993c8d | |
Barry Silverman | b5e1064efb | |
Barry Silverman | 282c815791 | |
BigEd | 3258a24c91 | |
BigEd | 66d42665a9 | |
Barry Silverman | cede111a0f | |
Barry Silverman | dc0fb1ef06 | |
Barry Silverman | e60485fe6a | |
BigEd | 9705ca4093 | |
BigEd | a83cb1533e | |
BigEd | 971bbd03e3 | |
BigEd | 0773a9e7cf | |
BigEd | ee196947e3 | |
BigEd | f439d8fc8d | |
BigEd | 43f06031b0 | |
BigEd | c5e2bfd657 | |
BigEd | 2cfceefacd | |
BigEd | 67ad17122c | |
BigEd | c15e3ea5b5 | |
BigEd | 6aec2c96f0 | |
BigEd | d6e516cafa | |
BigEd | 2d20ef2dad | |
BigEd | 5f24e86c3e | |
BigEd | 5578726fd3 | |
BigEd | 1843c17ce9 | |
BigEd | 455949ceca | |
BigEd | f0536dc716 | |
BigEd | c8aabd6baa | |
BigEd | 0b1af8d70e | |
BigEd | f3375f4c4b | |
BigEd | 0892586d75 | |
BigEd | 0ae95d5338 | |
BigEd | a2d20cc403 | |
Barry Silverman | e72f11ee72 | |
BigEd | 4b0316170b | |
BigEd | 4849ad6ebc | |
BigEd | f26a508c4e | |
Barry Silverman | d94116d257 | |
Barry Silverman | b8d2872246 | |
BigEd | 730312e594 | |
BigEd | 46976519fe | |
BigEd | 4ce8e4291f | |
Barry Silverman | c03f3477bd | |
BigEd | f67125989c | |
BigEd | 25f4594fdf | |
BigEd | f6f467787a | |
Barry Silverman | 2e9991c8ec | |
Barry Silverman | b50da0d3ed | |
BigEd | 653379e5d7 | |
BigEd | b3606c3b7f | |
BigEd | 406c9731e8 | |
BigEd | 40fe1e0a7a | |
BigEd | 1f21f5283c | |
Barry Silverman | b161368455 | |
BigEd | eaf55f1f31 | |
BigEd | 11ab9bafce | |
BigEd | 8fbcefc2e2 | |
BigEd | ea48dae543 |
After Width: | Height: | Size: 834 B |
After Width: | Height: | Size: 855 B |
After Width: | Height: | Size: 830 B |
After Width: | Height: | Size: 840 B |
After Width: | Height: | Size: 843 B |
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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);
|
4
README
|
@ -1,9 +1,11 @@
|
|||
This is the javascript simulator from the visual5602.org project:
|
||||
This is the JavaScript simulator from the visual6502.org project:
|
||||
www.visual6502.org/JSSim
|
||||
|
||||
It includes a general purpose transistor-level simulator, layout browser,
|
||||
and the data from a 6502 revD chip.
|
||||
|
||||
It also includes a similar simulator for the 6800 chip.
|
||||
|
||||
Note the various licenses and Copyright associated with each file.
|
||||
|
||||
Enjoy!
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<head>
|
||||
<title>Visual 6502 in JavaScript</title>
|
||||
<style type="text/css">@import "wires.css";</style>
|
||||
<style type="text/css">@import "kiosk.css";</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
|
|
@ -0,0 +1,488 @@
|
|||
// chip-specific support functions
|
||||
//
|
||||
// may override function definitions made previously
|
||||
|
||||
chipname='6800';
|
||||
|
||||
grChipSize=6600;
|
||||
grChipOffsetX=25
|
||||
grChipOffsetY=-200;
|
||||
|
||||
ngnd = nodenames['gnd'];
|
||||
npwr = nodenames['vcc'];
|
||||
|
||||
nodenamereset = 'reset';
|
||||
|
||||
presetLogLists=[
|
||||
['cycle',],
|
||||
['ab','db','rw','vma','Fetch','pc','acca','accb','ix','sp','p'],
|
||||
['ir','sync','Execute','State'], // instruction fetch and execution control
|
||||
['dbi','dbo','tmp','sum','inc'], // internal register-sized state
|
||||
['idb','abh','abl','ablx'], // internal datapath busses
|
||||
['irq','nmi',nodenamereset,'tsc','dbe','halt','ba'], // other pins
|
||||
];
|
||||
|
||||
function setupTransistors(){
|
||||
for(i in transdefs){
|
||||
var tdef = transdefs[i];
|
||||
var name = tdef[0];
|
||||
var gate = tdef[1];
|
||||
var c1 = tdef[2];
|
||||
var c2 = tdef[3];
|
||||
var bb = tdef[4];
|
||||
if(tdef[6])
|
||||
// just ignore all the 'weak' transistors for now
|
||||
continue;
|
||||
if(c1==ngnd) {c1=c2;c2=ngnd;}
|
||||
if(c1==npwr) {c1=c2;c2=npwr;}
|
||||
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2, bb: bb};
|
||||
nodes[gate].gates.push(trans);
|
||||
nodes[c1].c1c2s.push(trans);
|
||||
nodes[c2].c1c2s.push(trans);
|
||||
transistors[name] = trans;
|
||||
}
|
||||
}
|
||||
|
||||
// simulate a single clock phase with no update to graphics or trace
|
||||
function halfStep(){
|
||||
var clk = isNodeHigh(nodenames['phi2']);
|
||||
eval(clockTriggers[cycle]);
|
||||
if (clk) {setLow('phi2'); setLow('dbe'); setHigh('phi1'); handleBusRead(); }
|
||||
else {setHigh('phi1'); setLow('phi1'); setHigh('phi2'); setHigh('dbe'); handleBusWrite();}
|
||||
}
|
||||
|
||||
function goUntilSyncOrWrite(){
|
||||
halfStep();
|
||||
cycle++;
|
||||
while(
|
||||
!isNodeHigh(nodenames['phi2']) ||
|
||||
( !isNodeHigh(nodenames['sync']) && isNodeHigh(nodenames['rw']) )
|
||||
) {
|
||||
halfStep();
|
||||
cycle++;
|
||||
}
|
||||
chipStatus();
|
||||
}
|
||||
|
||||
function initChip(){
|
||||
var start = now();
|
||||
for(var nn in nodes) {
|
||||
nodes[nn].state = false;
|
||||
nodes[nn].float = true;
|
||||
}
|
||||
|
||||
nodes[ngnd].state = false;
|
||||
nodes[ngnd].float = false;
|
||||
nodes[npwr].state = true;
|
||||
nodes[npwr].float = false;
|
||||
for(var tn in transistors) transistors[tn].on = false;
|
||||
setLow(nodenamereset);
|
||||
setHigh('phi1'); setLow('phi2'); setLow('dbe');
|
||||
setHigh('dbe'); setLow('tsc'); setHigh('halt');
|
||||
setHigh('irq'); setHigh('nmi');
|
||||
recalcNodeList(allNodes());
|
||||
for(var i=0;i<8;i++){
|
||||
setLow('phi1');
|
||||
setHigh('phi2'); setHigh('dbe');
|
||||
setLow('phi2'); setLow('dbe');
|
||||
setHigh('phi1');
|
||||
}
|
||||
setHigh(nodenamereset);
|
||||
for(var i=0;i<6;i++){halfStep();} // avoid updating graphics and trace buffer before user code
|
||||
refresh();
|
||||
cycle = 0;
|
||||
trace = Array();
|
||||
if(typeof expertMode != "undefined")
|
||||
updateLogList();
|
||||
chipStatus();
|
||||
if(ctrace)console.log('initChip done after', now()-start);
|
||||
}
|
||||
|
||||
function handleBusRead(){
|
||||
if(isNodeHigh(nodenames['rw'])){
|
||||
var a = readAddressBus();
|
||||
var d = eval(readTriggers[a]);
|
||||
if(d == undefined)
|
||||
d = mRead(readAddressBus());
|
||||
if(isNodeHigh(nodenames['sync']))
|
||||
eval(fetchTriggers[d]);
|
||||
writeDataBus(d);
|
||||
}
|
||||
}
|
||||
|
||||
function readAccA(){return readBits('acca', 8);}
|
||||
function readAccB(){return readBits('accb', 8);}
|
||||
function readIX(){return (readBits('ixh', 8)<<8) + readBits('ixl', 8);}
|
||||
function readSP(){return (readBits('sph', 8)<<8) + readBits('spl', 8);}
|
||||
function readPstring(){
|
||||
var result;
|
||||
result = '‑' + // non-breaking hyphen
|
||||
'‑' + // non-breaking hyphen
|
||||
(isNodeHigh(nodenames['flagh'])?'H':'h') +
|
||||
(isNodeHigh(nodenames['flagi'])?'I':'i') +
|
||||
(isNodeHigh(nodenames['flagn'])?'N':'n') +
|
||||
(isNodeHigh(nodenames['flagz'])?'Z':'z') +
|
||||
(isNodeHigh(nodenames['flagv'])?'V':'v') +
|
||||
(isNodeHigh(nodenames['flagc'])?'C':'c');
|
||||
return result;
|
||||
}
|
||||
|
||||
// The 6800 state control is something like a branching shift register
|
||||
// ... but not quite like that
|
||||
TCStates=[
|
||||
"Ts", "Tf",
|
||||
"Tx0", "Tx1", "Tx2",
|
||||
"Ta0", "Ta1", "Ta2",
|
||||
"Td0_0",
|
||||
"#Te0", "Te1_0",
|
||||
"Tg0", "Tg1", "Tg2", "Tg3", "Tg4", "Tg5", "Tg6", "Tg7", "Tg8",
|
||||
"Tr3", "Tr4", "Tr5", "Tr6", "Tr7", "Tr8",
|
||||
];
|
||||
|
||||
function listActiveTCStates() {
|
||||
var s=[];
|
||||
for(var i=0;i<TCStates.length;i++){
|
||||
var t=TCStates[i];
|
||||
// remove a leading hash, but invert the signal
|
||||
// in any case, remove any trailing suffix
|
||||
if(t[0]=="#"){
|
||||
if(!isNodeHigh(nodenames[t])) s.push(t.slice(1,4));
|
||||
} else {
|
||||
if(isNodeHigh(nodenames[t])) s.push(t.slice(0,3));
|
||||
}
|
||||
}
|
||||
return s.join("+");
|
||||
}
|
||||
|
||||
function busToString(busname){
|
||||
// takes a signal name or prefix
|
||||
// returns an appropriate string representation
|
||||
// some 'signal names' are CPU-specific aliases to user-friendly string output
|
||||
if(busname=='cycle')
|
||||
return cycle>>1;
|
||||
if(busname=='pc')
|
||||
return busToHex('pch') + busToHex('pcl');
|
||||
if(busname=='sp')
|
||||
return busToHex('sph') + busToHex('spl');
|
||||
if(busname=='ix')
|
||||
return busToHex('ixh') + busToHex('ixl');
|
||||
if(busname=='inc')
|
||||
return busToHex('inch') + busToHex('incl');
|
||||
if(busname=='p')
|
||||
return readPstring();
|
||||
if(busname=='State')
|
||||
return listActiveTCStates();
|
||||
if(busname=='Execute')
|
||||
return disassemblytoHTML(readBits('ir',8));
|
||||
if(busname=='Fetch')
|
||||
return isNodeHigh(nodenames['sync'])?disassemblytoHTML(readDataBus()):"";
|
||||
if(busname=='plaOutputs')
|
||||
// PLA outputs are mostly ^op- but some have a prefix too
|
||||
// - we'll allow the x and xx prefix but ignore the #
|
||||
return listActiveSignals('^([x]?x-)?op-');
|
||||
if(busname=='DPControl')
|
||||
return listActiveSignals('^dpc[0-9]+_');
|
||||
if(busname[0]=="-"){
|
||||
// invert the value of the bus for display
|
||||
var value=busToHex(busname.slice(1))
|
||||
if(typeof value != "undefined")
|
||||
return value.replace(/./g,function(x){return (15-parseInt(x,16)).toString(16)});
|
||||
else
|
||||
return undefined;;
|
||||
} else {
|
||||
return busToHex(busname);
|
||||
}
|
||||
}
|
||||
|
||||
function chipStatus(){
|
||||
var ab = readAddressBus();
|
||||
var machine1 =
|
||||
' halfcyc:' + cycle +
|
||||
' phi0:' + readBit('phi2') +
|
||||
' AB:' + hexWord(ab) +
|
||||
' D:' + hexByte(readDataBus()) +
|
||||
' RnW:' + readBit('rw') +
|
||||
' VMA:' + readBit('vma');
|
||||
var machine2 =
|
||||
' PC:' + hexWord(readPC()) +
|
||||
' A:' + hexByte(readAccA()) +
|
||||
' B:' + hexByte(readAccB()) +
|
||||
' IX:' + hexWord(readIX()) +
|
||||
' SP:' + hexWord(readSP()) +
|
||||
' ' + readPstring();
|
||||
var machine3 =
|
||||
'Hz: ' + estimatedHz().toFixed(1);
|
||||
if(typeof expertMode != "undefined") {
|
||||
machine3 += ' Exec: ' + busToString('Execute'); // no T-state info for 6800 yet
|
||||
if(isNodeHigh(nodenames['sync']))
|
||||
machine3 += ' (Fetch: ' + busToString('Fetch') + ')';
|
||||
if(goldenChecksum != undefined)
|
||||
machine3 += " Chk:" + traceChecksum + ((traceChecksum==goldenChecksum)?" OK":" no match");
|
||||
}
|
||||
|
||||
setStatus(machine1, machine2, machine3);
|
||||
if (logThese.length>1) {
|
||||
updateLogbox(logThese);
|
||||
}
|
||||
selectCell(ab);
|
||||
}
|
||||
|
||||
// javascript derived from http://segher.ircgeeks.net/6800/OPS
|
||||
var disassembly={
|
||||
0x00: "!",
|
||||
0x01: "nop",
|
||||
0x02: "!",
|
||||
0x03: "!",
|
||||
0x04: "!",
|
||||
0x05: "!",
|
||||
0x06: "tap",
|
||||
0x07: "tpa",
|
||||
0x10: "sba",
|
||||
0x11: "cba",
|
||||
0x12: "!",
|
||||
0x13: "!",
|
||||
0x14: "!nba",
|
||||
0x15: "!",
|
||||
0x16: "tab",
|
||||
0x17: "tba",
|
||||
0x20: "bra N",
|
||||
0x21: "!",
|
||||
0x22: "bhi N",
|
||||
0x23: "bls N",
|
||||
0x24: "bcc N",
|
||||
0x25: "bcs N",
|
||||
0x26: "bne N",
|
||||
0x27: "beq N",
|
||||
0x30: "tsx",
|
||||
0x31: "ins",
|
||||
0x32: "pul a",
|
||||
0x33: "pul b",
|
||||
0x34: "des",
|
||||
0x35: "txs",
|
||||
0x36: "psh a",
|
||||
0x37: "psh b",
|
||||
0x40: "neg a",
|
||||
0x41: "!",
|
||||
0x42: "!",
|
||||
0x43: "com a",
|
||||
0x44: "lsr a",
|
||||
0x45: "!",
|
||||
0x46: "ror a",
|
||||
0x47: "asr a",
|
||||
0x50: "neg b",
|
||||
0x51: "!",
|
||||
0x52: "!",
|
||||
0x53: "com b",
|
||||
0x54: "lsr b",
|
||||
0x55: "!",
|
||||
0x56: "ror b",
|
||||
0x57: "asr b",
|
||||
0x60: "neg Nx",
|
||||
0x61: "!",
|
||||
0x62: "!",
|
||||
0x63: "com Nx",
|
||||
0x64: "lsr Nx",
|
||||
0x65: "!",
|
||||
0x66: "ror Nx",
|
||||
0x67: "asr Nx",
|
||||
0x70: "neg NN",
|
||||
0x71: "!",
|
||||
0x72: "!",
|
||||
0x73: "com NN",
|
||||
0x74: "lsr NN",
|
||||
0x75: "!",
|
||||
0x76: "ror NN",
|
||||
0x77: "asr NN",
|
||||
0x80: "sub a #",
|
||||
0x81: "cmp a #",
|
||||
0x82: "sbc a #",
|
||||
0x83: "!",
|
||||
0x84: "and a #",
|
||||
0x85: "bit a #",
|
||||
0x86: "lda a #",
|
||||
0x87: "!",
|
||||
0x90: "sub a N",
|
||||
0x91: "cmp a N",
|
||||
0x92: "sbc a N",
|
||||
0x93: "!",
|
||||
0x94: "and a N",
|
||||
0x95: "bit a N",
|
||||
0x96: "lda a N",
|
||||
0x97: "sta a N",
|
||||
0xa0: "sub a Nx",
|
||||
0xa1: "cmp a Nx",
|
||||
0xa2: "sbc a Nx",
|
||||
0xa3: "!",
|
||||
0xa4: "and a Nx",
|
||||
0xa5: "bit a Nx",
|
||||
0xa6: "lda a Nx",
|
||||
0xa7: "sta a Nx",
|
||||
0xb0: "sub a NN",
|
||||
0xb1: "cmp a NN",
|
||||
0xb2: "sbc a NN",
|
||||
0xb3: "!",
|
||||
0xb4: "and a NN",
|
||||
0xb5: "bit a NN",
|
||||
0xb6: "lda a NN",
|
||||
0xb7: "sta a NN",
|
||||
0xc0: "sub b #",
|
||||
0xc1: "cmp b #",
|
||||
0xc2: "sbc b #",
|
||||
0xc3: "!",
|
||||
0xc4: "and b #",
|
||||
0xc5: "bit b #",
|
||||
0xc6: "lda b #",
|
||||
0xc7: "!",
|
||||
0xd0: "sub b N",
|
||||
0xd1: "cmp b N",
|
||||
0xd2: "sbc b N",
|
||||
0xd3: "!",
|
||||
0xd4: "and b N",
|
||||
0xd5: "bit b N",
|
||||
0xd6: "lda b N",
|
||||
0xd7: "sta b N",
|
||||
0xe0: "sub b Nx",
|
||||
0xe1: "cmp b Nx",
|
||||
0xe2: "sbc b Nx",
|
||||
0xe3: "!",
|
||||
0xe4: "and b Nx",
|
||||
0xe5: "bit b Nx",
|
||||
0xe6: "lda b Nx",
|
||||
0xe7: "sta b Nx",
|
||||
0xf0: "sub b NN",
|
||||
0xf1: "cmp b NN",
|
||||
0xf2: "sbc b NN",
|
||||
0xf3: "!",
|
||||
0xf4: "and b NN",
|
||||
0xf5: "bit b NN",
|
||||
0xf6: "lda b NN",
|
||||
0xf7: "sta b NN",
|
||||
0x08: "inx",
|
||||
0x09: "dex",
|
||||
0x0a: "clv",
|
||||
0x0b: "sev",
|
||||
0x0c: "clc",
|
||||
0x0d: "sec",
|
||||
0x0e: "cli",
|
||||
0x0f: "sei",
|
||||
0x18: "!",
|
||||
0x19: "daa",
|
||||
0x1a: "!",
|
||||
0x1b: "aba",
|
||||
0x1c: "!",
|
||||
0x1d: "!",
|
||||
0x1e: "!",
|
||||
0x1f: "!",
|
||||
0x28: "bvc N",
|
||||
0x29: "bvs N",
|
||||
0x2a: "bpl N",
|
||||
0x2b: "bmi N",
|
||||
0x2c: "bge N",
|
||||
0x2d: "blt N",
|
||||
0x2e: "bgt N",
|
||||
0x2f: "ble N",
|
||||
0x38: "!",
|
||||
0x39: "rts",
|
||||
0x3a: "!",
|
||||
0x3b: "rti",
|
||||
0x3c: "!",
|
||||
0x3d: "!",
|
||||
0x3e: "wai",
|
||||
0x3f: "swi",
|
||||
0x48: "asl a",
|
||||
0x49: "rol a",
|
||||
0x4a: "dec a",
|
||||
0x4b: "!",
|
||||
0x4c: "inc a",
|
||||
0x4d: "tst a",
|
||||
0x4e: "!",
|
||||
0x4f: "clr a",
|
||||
0x58: "asl b",
|
||||
0x59: "rol b",
|
||||
0x5a: "dec b",
|
||||
0x5b: "!",
|
||||
0x5c: "inc b",
|
||||
0x5d: "tst b",
|
||||
0x5e: "!",
|
||||
0x5f: "clr b",
|
||||
0x68: "asl Nx",
|
||||
0x69: "rol Nx",
|
||||
0x6a: "dec Nx",
|
||||
0x6b: "!",
|
||||
0x6c: "inc Nx",
|
||||
0x6d: "tst Nx",
|
||||
0x6e: "jmp Nx",
|
||||
0x6f: "clr Nx",
|
||||
0x78: "asl NN",
|
||||
0x79: "rol NN",
|
||||
0x7a: "dec NN",
|
||||
0x7b: "!",
|
||||
0x7c: "inc NN",
|
||||
0x7d: "tst NN",
|
||||
0x7e: "jmp NN",
|
||||
0x7f: "clr NN",
|
||||
0x88: "eor a #",
|
||||
0x89: "adc a #",
|
||||
0x8a: "ora a #",
|
||||
0x8b: "add a #",
|
||||
0x8c: "cpx ##",
|
||||
0x8d: "bsr N",
|
||||
0x8e: "lds ##",
|
||||
0x8f: "!",
|
||||
0x98: "eor a N",
|
||||
0x99: "adc a N",
|
||||
0x9a: "ora a N",
|
||||
0x9b: "add a N",
|
||||
0x9c: "cpx N",
|
||||
0x9d: "!hcf",
|
||||
0x9e: "lds N",
|
||||
0x9f: "sts N",
|
||||
0xa8: "eor a Nx",
|
||||
0xa9: "adc a Nx",
|
||||
0xaa: "ora a Nx",
|
||||
0xab: "add a Nx",
|
||||
0xac: "cpx Nx",
|
||||
0xad: "jsr Nx",
|
||||
0xae: "lds Nx",
|
||||
0xaf: "sts Nx",
|
||||
0xb8: "eor a NN",
|
||||
0xb9: "adc a NN",
|
||||
0xba: "ora a NN",
|
||||
0xbb: "add a NN",
|
||||
0xbc: "cpx NN",
|
||||
0xbd: "jsr NN",
|
||||
0xbe: "lds NN",
|
||||
0xbf: "sts NN",
|
||||
0xc8: "eor b #",
|
||||
0xc9: "adc b #",
|
||||
0xca: "ora b #",
|
||||
0xcb: "add b #",
|
||||
0xcc: "!",
|
||||
0xcd: "!",
|
||||
0xce: "ldx ##",
|
||||
0xcf: "!",
|
||||
0xd8: "eor b N",
|
||||
0xd9: "adc b N",
|
||||
0xda: "ora b N",
|
||||
0xdb: "add b N",
|
||||
0xdc: "!",
|
||||
0xdd: "!hcf",
|
||||
0xde: "ldx N",
|
||||
0xdf: "stx N",
|
||||
0xe8: "eor b Nx",
|
||||
0xe9: "adc b Nx",
|
||||
0xea: "ora b Nx",
|
||||
0xeb: "add b Nx",
|
||||
0xec: "!",
|
||||
0xed: "!",
|
||||
0xee: "ldx Nx",
|
||||
0xef: "stx Nx",
|
||||
0xf8: "eor b NN",
|
||||
0xf9: "adc b NN",
|
||||
0xfa: "ora b NN",
|
||||
0xfb: "add b NN",
|
||||
0xfc: "!",
|
||||
0xfd: "!",
|
||||
0xfe: "ldx NN",
|
||||
0xff: "stx NN",
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
// This file testprogram.js can be substituted by one of several tests
|
||||
testprogramAddress=0x0000;
|
||||
|
||||
// we want to auto-clear the console if any output is sent by the program
|
||||
var consoleboxStream="";
|
||||
|
||||
// demonstrate write hook
|
||||
writeTriggers[0x8000]="consoleboxStream += String.fromCharCode(d);"+
|
||||
"consolebox.innerHTML = consoleboxStream;";
|
||||
|
||||
// demonstrate read hook (not used by this test program)
|
||||
readTriggers[0x8004]="((consolegetc==undefined)?0:0xff)"; // return zero until we have a char
|
||||
readTriggers[0x8000]="var c=consolegetc; consolegetc=undefined; (c)";
|
||||
|
||||
// for opcodes, see http://www.textfiles.com/programming/CARDS/6800
|
||||
|
||||
testprogram = [
|
||||
0xce, 0x43, 0x21, // LDX #4321
|
||||
0x35, // TXS
|
||||
0xce, 0x80, 0x00, // LDX #8000
|
||||
0xc6, 0x40, // LDAB #$40
|
||||
0xbd, 0x00, 0x10, // JSR $0010
|
||||
0x7e, 0x00, 0x09, // JMP $0009
|
||||
0x01, // NOP
|
||||
0x4a, // DECA
|
||||
0xe7, 0x00, // STAB 0, X
|
||||
0x7c, 0x00, 0x0f, // INC $0F
|
||||
0x0d, // SEC
|
||||
0xc9, 0x02, // ADCB #$02
|
||||
0x39, // RTS
|
||||
]
|
|
@ -0,0 +1,530 @@
|
|||
// ***********************************************************
|
||||
// * This file is automatically generated by Z80Simulator. *
|
||||
// * Please do not manually edit! Instead, find a transistor *
|
||||
// * that uses the new signal and use FindTransistor(x,y) in *
|
||||
// * Z80Simulator to cause that signal to be added. *
|
||||
// * This seems a pain, but it has two advantages: *
|
||||
// * - all signals are then available in Z80Simulator *
|
||||
// * - it avoids renumbering issues if/when the PNGs change *
|
||||
// ***********************************************************
|
||||
var nodenames ={
|
||||
// Pads
|
||||
vss: 1,
|
||||
vcc: 2,
|
||||
clk: 3,
|
||||
ab0: 5,
|
||||
ab1: 6,
|
||||
ab2: 7,
|
||||
ab3: 8,
|
||||
ab4: 9,
|
||||
ab5: 10,
|
||||
ab6: 11,
|
||||
ab7: 12,
|
||||
ab8: 13,
|
||||
ab9: 14,
|
||||
ab10: 15,
|
||||
ab11: 16,
|
||||
ab12: 17,
|
||||
ab13: 18,
|
||||
ab14: 19,
|
||||
ab15: 20,
|
||||
_reset: 21,
|
||||
_wait: 22,
|
||||
wait: 22,
|
||||
_int: 23,
|
||||
int: 23,
|
||||
_irq: 23,
|
||||
irq: 23,
|
||||
_nmi: 24,
|
||||
nmi: 24,
|
||||
_busrq: 25,
|
||||
busrq: 25,
|
||||
_m1: 26,
|
||||
_rd: 27,
|
||||
_wr: 28,
|
||||
_mreq: 29,
|
||||
_iorq: 30,
|
||||
_rfsh: 31,
|
||||
db0: 32,
|
||||
db1: 33,
|
||||
db2: 34,
|
||||
db3: 35,
|
||||
db4: 36,
|
||||
db5: 37,
|
||||
db6: 38,
|
||||
db7: 39,
|
||||
_halt: 40,
|
||||
_busak: 41,
|
||||
// T-States
|
||||
t1: 115,
|
||||
t2: 137,
|
||||
t3: 144,
|
||||
t4: 166,
|
||||
t5: 134,
|
||||
t6: 168,
|
||||
// Machine cycles
|
||||
m1: 155,
|
||||
m2: 173,
|
||||
m3: 163,
|
||||
m4: 159,
|
||||
m5: 209,
|
||||
m6: 210,
|
||||
// EXX latches
|
||||
ex_af: 631,
|
||||
ex_bcdehl: 1770,
|
||||
ex_dehl0: 625,
|
||||
ex_dehl1: 629,
|
||||
ex_dehl_combined: 626,
|
||||
// Registers
|
||||
reg_a0: 2245,
|
||||
reg_a1: 2319,
|
||||
reg_a2: 2357,
|
||||
reg_a3: 2442,
|
||||
reg_a4: 2463,
|
||||
reg_a5: 2552,
|
||||
reg_a6: 2586,
|
||||
reg_a7: 2656,
|
||||
reg_f0: 1827,
|
||||
reg_f1: 1903,
|
||||
reg_f2: 1928,
|
||||
reg_f3: 2009,
|
||||
reg_f4: 2032,
|
||||
reg_f5: 2107,
|
||||
reg_f6: 2132,
|
||||
reg_f7: 2209,
|
||||
reg_b0: 2242,
|
||||
reg_b1: 2316,
|
||||
reg_b2: 2354,
|
||||
reg_b3: 2439,
|
||||
reg_b4: 2460,
|
||||
reg_b5: 2549,
|
||||
reg_b6: 2583,
|
||||
reg_b7: 2653,
|
||||
reg_c0: 1824,
|
||||
reg_c1: 1900,
|
||||
reg_c2: 1925,
|
||||
reg_c3: 2006,
|
||||
reg_c4: 2029,
|
||||
reg_c5: 2104,
|
||||
reg_c6: 2129,
|
||||
reg_c7: 2206,
|
||||
reg_d0: 2238,
|
||||
reg_d1: 2312,
|
||||
reg_d2: 2350,
|
||||
reg_d3: 2435,
|
||||
reg_d4: 2456,
|
||||
reg_d5: 2545,
|
||||
reg_d6: 2579,
|
||||
reg_d7: 2649,
|
||||
reg_e0: 1820,
|
||||
reg_e1: 1896,
|
||||
reg_e2: 1921,
|
||||
reg_e3: 2002,
|
||||
reg_e4: 2025,
|
||||
reg_e5: 2100,
|
||||
reg_e6: 2125,
|
||||
reg_e7: 2202,
|
||||
reg_h0: 2240,
|
||||
reg_h1: 2314,
|
||||
reg_h2: 2352,
|
||||
reg_h3: 2437,
|
||||
reg_h4: 2458,
|
||||
reg_h5: 2547,
|
||||
reg_h6: 2581,
|
||||
reg_h7: 2651,
|
||||
reg_l0: 1822,
|
||||
reg_l1: 1898,
|
||||
reg_l2: 1923,
|
||||
reg_l3: 2004,
|
||||
reg_l4: 2027,
|
||||
reg_l5: 2102,
|
||||
reg_l6: 2127,
|
||||
reg_l7: 2204,
|
||||
reg_w0: 2234,
|
||||
reg_w1: 2308,
|
||||
reg_w2: 2346,
|
||||
reg_w3: 2431,
|
||||
reg_w4: 2452,
|
||||
reg_w5: 2541,
|
||||
reg_w6: 2575,
|
||||
reg_w7: 2645,
|
||||
reg_z0: 1816,
|
||||
reg_z1: 1892,
|
||||
reg_z2: 1917,
|
||||
reg_z3: 1998,
|
||||
reg_z4: 2021,
|
||||
reg_z5: 2096,
|
||||
reg_z6: 2121,
|
||||
reg_z7: 2198,
|
||||
reg_pch0: 2232,
|
||||
reg_pch1: 2306,
|
||||
reg_pch2: 2344,
|
||||
reg_pch3: 2429,
|
||||
reg_pch4: 2450,
|
||||
reg_pch5: 2539,
|
||||
reg_pch6: 2573,
|
||||
reg_pch7: 2643,
|
||||
reg_pcl0: 1814,
|
||||
reg_pcl1: 1890,
|
||||
reg_pcl2: 1915,
|
||||
reg_pcl3: 1996,
|
||||
reg_pcl4: 2019,
|
||||
reg_pcl5: 2094,
|
||||
reg_pcl6: 2119,
|
||||
reg_pcl7: 2196,
|
||||
reg_sph0: 2235,
|
||||
reg_sph1: 2309,
|
||||
reg_sph2: 2347,
|
||||
reg_sph3: 2432,
|
||||
reg_sph4: 2453,
|
||||
reg_sph5: 2542,
|
||||
reg_sph6: 2576,
|
||||
reg_sph7: 2646,
|
||||
reg_spl0: 1817,
|
||||
reg_spl1: 1893,
|
||||
reg_spl2: 1918,
|
||||
reg_spl3: 1999,
|
||||
reg_spl4: 2022,
|
||||
reg_spl5: 2097,
|
||||
reg_spl6: 2122,
|
||||
reg_spl7: 2199,
|
||||
reg_ixh0: 2237,
|
||||
reg_ixh1: 2311,
|
||||
reg_ixh2: 2349,
|
||||
reg_ixh3: 2434,
|
||||
reg_ixh4: 2455,
|
||||
reg_ixh5: 2544,
|
||||
reg_ixh6: 2578,
|
||||
reg_ixh7: 2648,
|
||||
reg_ixl0: 1819,
|
||||
reg_ixl1: 1895,
|
||||
reg_ixl2: 1920,
|
||||
reg_ixl3: 2001,
|
||||
reg_ixl4: 2024,
|
||||
reg_ixl5: 2099,
|
||||
reg_ixl6: 2124,
|
||||
reg_ixl7: 2201,
|
||||
reg_iyh0: 2236,
|
||||
reg_iyh1: 2310,
|
||||
reg_iyh2: 2348,
|
||||
reg_iyh3: 2433,
|
||||
reg_iyh4: 2454,
|
||||
reg_iyh5: 2543,
|
||||
reg_iyh6: 2577,
|
||||
reg_iyh7: 2647,
|
||||
reg_iyl0: 1818,
|
||||
reg_iyl1: 1894,
|
||||
reg_iyl2: 1919,
|
||||
reg_iyl3: 2000,
|
||||
reg_iyl4: 2023,
|
||||
reg_iyl5: 2098,
|
||||
reg_iyl6: 2123,
|
||||
reg_iyl7: 2200,
|
||||
reg_i0: 2233,
|
||||
reg_i1: 2307,
|
||||
reg_i2: 2345,
|
||||
reg_i3: 2430,
|
||||
reg_i4: 2451,
|
||||
reg_i5: 2540,
|
||||
reg_i6: 2574,
|
||||
reg_i7: 2644,
|
||||
reg_r0: 1815,
|
||||
reg_r1: 1891,
|
||||
reg_r2: 1916,
|
||||
reg_r3: 1997,
|
||||
reg_r4: 2020,
|
||||
reg_r5: 2095,
|
||||
reg_r6: 2120,
|
||||
reg_r7: 2197,
|
||||
reg_aa0: 2244,
|
||||
reg_aa1: 2318,
|
||||
reg_aa2: 2356,
|
||||
reg_aa3: 2441,
|
||||
reg_aa4: 2462,
|
||||
reg_aa5: 2551,
|
||||
reg_aa6: 2585,
|
||||
reg_aa7: 2655,
|
||||
reg_ff0: 1826,
|
||||
reg_ff1: 1902,
|
||||
reg_ff2: 1927,
|
||||
reg_ff3: 2008,
|
||||
reg_ff4: 2031,
|
||||
reg_ff5: 2106,
|
||||
reg_ff6: 2131,
|
||||
reg_ff7: 2208,
|
||||
reg_bb0: 2243,
|
||||
reg_bb1: 2317,
|
||||
reg_bb2: 2355,
|
||||
reg_bb3: 2440,
|
||||
reg_bb4: 2461,
|
||||
reg_bb5: 2550,
|
||||
reg_bb6: 2584,
|
||||
reg_bb7: 2654,
|
||||
reg_cc0: 1825,
|
||||
reg_cc1: 1901,
|
||||
reg_cc2: 1926,
|
||||
reg_cc3: 2007,
|
||||
reg_cc4: 2030,
|
||||
reg_cc5: 2105,
|
||||
reg_cc6: 2130,
|
||||
reg_cc7: 2207,
|
||||
reg_dd0: 2239,
|
||||
reg_dd1: 2313,
|
||||
reg_dd2: 2351,
|
||||
reg_dd3: 2436,
|
||||
reg_dd4: 2457,
|
||||
reg_dd5: 2546,
|
||||
reg_dd6: 2580,
|
||||
reg_dd7: 2650,
|
||||
reg_ee0: 1821,
|
||||
reg_ee1: 1897,
|
||||
reg_ee2: 1922,
|
||||
reg_ee3: 2003,
|
||||
reg_ee4: 2026,
|
||||
reg_ee5: 2101,
|
||||
reg_ee6: 2126,
|
||||
reg_ee7: 2203,
|
||||
reg_hh0: 2241,
|
||||
reg_hh1: 2315,
|
||||
reg_hh2: 2353,
|
||||
reg_hh3: 2438,
|
||||
reg_hh4: 2459,
|
||||
reg_hh5: 2548,
|
||||
reg_hh6: 2582,
|
||||
reg_hh7: 2652,
|
||||
reg_ll0: 1823,
|
||||
reg_ll1: 1899,
|
||||
reg_ll2: 1924,
|
||||
reg_ll3: 2005,
|
||||
reg_ll4: 2028,
|
||||
reg_ll5: 2103,
|
||||
reg_ll6: 2128,
|
||||
reg_ll7: 2205,
|
||||
// Data buses and control
|
||||
dp_dl: 82,
|
||||
dl_dp: 165,
|
||||
load_ir: 1354,
|
||||
dlatch0: 123,
|
||||
dlatch1: 195,
|
||||
dlatch2: 414,
|
||||
dlatch3: 930,
|
||||
dlatch4: 1000,
|
||||
dlatch5: 872,
|
||||
dlatch6: 751,
|
||||
dlatch7: 358,
|
||||
dl_d: 87,
|
||||
d_dl: 133,
|
||||
dbus0: 138,
|
||||
dbus1: 196,
|
||||
dbus2: 412,
|
||||
dbus3: 480,
|
||||
dbus4: 485,
|
||||
dbus5: 486,
|
||||
dbus6: 380,
|
||||
dbus7: 370,
|
||||
_instr0: 1350,
|
||||
_instr1: 1360,
|
||||
_instr2: 1366,
|
||||
_instr3: 1380,
|
||||
_instr4: 1388,
|
||||
_instr5: 1395,
|
||||
_instr6: 1370,
|
||||
_instr7: 1375,
|
||||
instr0: 1348,
|
||||
instr1: 1359,
|
||||
instr2: 1365,
|
||||
instr3: 1379,
|
||||
instr4: 1387,
|
||||
instr5: 1394,
|
||||
instr6: 1369,
|
||||
instr7: 1374,
|
||||
d_u: 546,
|
||||
ubus0: 545,
|
||||
ubus1: 528,
|
||||
ubus2: 526,
|
||||
ubus3: 770,
|
||||
ubus4: 779,
|
||||
ubus5: 790,
|
||||
ubus6: 716,
|
||||
ubus7: 525,
|
||||
u_v: 750,
|
||||
vbus0: 755,
|
||||
vbus1: 772,
|
||||
vbus2: 783,
|
||||
vbus3: 796,
|
||||
vbus4: 803,
|
||||
vbus5: 808,
|
||||
vbus6: 836,
|
||||
vbus7: 839,
|
||||
rl_wr: 678,
|
||||
rh_wr: 652,
|
||||
r_u: 692,
|
||||
r_v: 693,
|
||||
regbit0: 702,
|
||||
regbit1: 732,
|
||||
regbit2: 738,
|
||||
regbit3: 775,
|
||||
regbit4: 776,
|
||||
regbit5: 807,
|
||||
regbit6: 809,
|
||||
regbit7: 864,
|
||||
regbit8: 870,
|
||||
regbit9: 902,
|
||||
regbit10: 906,
|
||||
regbit11: 934,
|
||||
regbit12: 935,
|
||||
regbit13: 970,
|
||||
regbit14: 973,
|
||||
regbit15: 999,
|
||||
r_p: 1785,
|
||||
r_x1: 608,
|
||||
pcbit0: 703,
|
||||
pcbit1: 731,
|
||||
pcbit2: 739,
|
||||
pcbit3: 774,
|
||||
pcbit4: 777,
|
||||
pcbit5: 806,
|
||||
pcbit6: 810,
|
||||
pcbit7: 863,
|
||||
pcbit8: 871,
|
||||
pcbit9: 901,
|
||||
pcbit10: 907,
|
||||
pcbit11: 933,
|
||||
pcbit12: 936,
|
||||
pcbit13: 969,
|
||||
pcbit14: 974,
|
||||
pcbit15: 998,
|
||||
// ALU
|
||||
alubus0: 837,
|
||||
alubus1: 889,
|
||||
alubus2: 937,
|
||||
alubus3: 983,
|
||||
alubus4: 852,
|
||||
alubus5: 903,
|
||||
alubus6: 951,
|
||||
alubus7: 995,
|
||||
alua0: 850,
|
||||
alua1: 899,
|
||||
alua2: 947,
|
||||
alua3: 993,
|
||||
alua4: 868,
|
||||
alua5: 920,
|
||||
alua6: 968,
|
||||
alua7: 1007,
|
||||
alub0: 845,
|
||||
alub1: 897,
|
||||
alub2: 944,
|
||||
alub3: 988,
|
||||
alub4: 867,
|
||||
alub5: 918,
|
||||
alub6: 966,
|
||||
alub7: 1005,
|
||||
aluout0: 2211,
|
||||
aluout1: 2338,
|
||||
aluout2: 2504,
|
||||
aluout3: 816,
|
||||
alulat0: 865,
|
||||
alulat1: 912,
|
||||
alulat2: 960,
|
||||
alulat3: 1002,
|
||||
// PLA
|
||||
pla0: 287,
|
||||
pla1: 332,
|
||||
pla2: 314,
|
||||
pla3: 333,
|
||||
pla4: 315,
|
||||
pla5: 334,
|
||||
pla6: 316,
|
||||
pla7: 335,
|
||||
pla8: 317,
|
||||
pla9: 336,
|
||||
pla10: 318,
|
||||
pla11: 361,
|
||||
pla12: 261,
|
||||
pla13: 337,
|
||||
pla14: 319,
|
||||
pla15: 464,
|
||||
pla16: 288,
|
||||
pla17: 338,
|
||||
pla18: 320,
|
||||
pla19: 364,
|
||||
pla20: 325,
|
||||
pla21: 324,
|
||||
pla22: 308,
|
||||
pla23: 289,
|
||||
pla24: 339,
|
||||
pla25: 313,
|
||||
pla26: 340,
|
||||
pla27: 290,
|
||||
pla28: 341,
|
||||
pla29: 291,
|
||||
pla30: 342,
|
||||
pla31: 292,
|
||||
pla32: 365,
|
||||
pla33: 293,
|
||||
pla34: 362,
|
||||
pla35: 294,
|
||||
pla36: 331,
|
||||
pla37: 293,
|
||||
pla38: 343,
|
||||
pla39: 296,
|
||||
pla40: 297,
|
||||
pla41: 298,
|
||||
pla42: 344,
|
||||
pla43: 299,
|
||||
pla44: 269,
|
||||
pla45: 300,
|
||||
pla46: 237,
|
||||
pla47: 301,
|
||||
pla48: 345,
|
||||
pla49: 302,
|
||||
pla50: 346,
|
||||
pla51: 264,
|
||||
pla52: 266,
|
||||
pla53: 347,
|
||||
pla54: 303,
|
||||
pla55: 356,
|
||||
pla56: 227,
|
||||
pla57: 366,
|
||||
pla58: 304,
|
||||
pla59: 305,
|
||||
pla60: 271,
|
||||
pla61: 348,
|
||||
pla62: 306,
|
||||
pla63: 309,
|
||||
pla64: 311,
|
||||
pla65: 312,
|
||||
pla66: 307,
|
||||
pla67: 367,
|
||||
pla68: 272,
|
||||
pla69: 349,
|
||||
pla70: 273,
|
||||
pla71: 350,
|
||||
pla72: 274,
|
||||
pla73: 351,
|
||||
pla74: 275,
|
||||
pla75: 276,
|
||||
pla76: 268,
|
||||
pla77: 352,
|
||||
pla78: 277,
|
||||
pla79: 278,
|
||||
pla80: 279,
|
||||
pla81: 280,
|
||||
pla82: 368,
|
||||
pla83: 281,
|
||||
pla84: 282,
|
||||
pla85: 283,
|
||||
pla86: 284,
|
||||
pla87: 285,
|
||||
pla88: 286,
|
||||
pla89: 321,
|
||||
pla90: 353,
|
||||
pla91: 322,
|
||||
pla92: 354,
|
||||
pla93: 323,
|
||||
pla94: 369,
|
||||
pla95: 258,
|
||||
pla96: 249,
|
||||
pla97: 245,
|
||||
pla98: 355,
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
// This file testprogram.js can be substituted by one of several tests
|
||||
testprogramAddress=0x0000;
|
||||
|
||||
// we want to auto-clear the console if any output is sent by the program
|
||||
var consoleboxStream="";
|
||||
|
||||
// demonstrate write hook
|
||||
writeTriggers[0x8000]="consoleboxStream += String.fromCharCode(d);"+
|
||||
"consolebox.innerHTML = consoleboxStream;";
|
||||
|
||||
// demonstrate read hook (not used by this test program)
|
||||
readTriggers[0x8004]="((consolegetc==undefined)?0:0xff)"; // return zero until we have a char
|
||||
readTriggers[0x8000]="var c=consolegetc; consolegetc=undefined; (c)";
|
||||
|
||||
// for opcodes, see http://www.textfiles.com/programming/CARDS/6800
|
||||
|
||||
testprogram = [
|
||||
0x00, // NOP
|
||||
0x31, 0x00, 0x01, // LD SP,0x0100
|
||||
0xCD, 0x0B, 0x00, // CALL $000B
|
||||
0x00, // NOP
|
||||
0x21, 0x78, 0x56, // LD HL,$5678
|
||||
0x21, 0x34, 0x12, // LD HL,$1234
|
||||
0xe5, // PUSH HL
|
||||
0x00, // NOP
|
||||
0x00, // NOP
|
||||
0x3C, // INC A
|
||||
0x04, // INC B
|
||||
0x15, // DEC D
|
||||
0x24, // INC H
|
||||
0xEB, // EXX DE,HL
|
||||
0x00, // NOP
|
||||
0x3C, // INC A
|
||||
0x04, // INC B
|
||||
0x15, // DEC D
|
||||
0x24, // INC H
|
||||
0xD9, // EXX
|
||||
0x00, // NOP
|
||||
0x3C, // INC A
|
||||
0x04, // INC B
|
||||
0x15, // DEC D
|
||||
0x24, // INC H
|
||||
0xEB, // EXX DE,HL
|
||||
0x00, // NOP
|
||||
0x3C, // INC A
|
||||
0x04, // INC B
|
||||
0x15, // DEC D
|
||||
0x24, // INC H
|
||||
0x08, // EXX AF,AF'
|
||||
0x00, // NOP
|
||||
0x3C, // INC A
|
||||
0x04, // INC B
|
||||
0x15, // DEC D
|
||||
0x24, // INC H
|
||||
0x00, // NOP
|
||||
0x00, // NOP
|
||||
0x00, // NOP
|
||||
0x21, 0x00, 0x01, // LD HL,$0100
|
||||
0x36, 0xCC, // LD (HL),$CC
|
||||
0x00, // NOP
|
||||
0x7E, // LD A, (HL)
|
||||
0x00, // NOP
|
||||
// Pavel's original test program
|
||||
0x21, 0x34, 0x12, // LD HL,$1234
|
||||
0x31, 0xfe, 0xdc, // LD SP,0xDCFE
|
||||
0xe5, // PUSH HL
|
||||
0x21, 0x78, 0x56, // LD HL,$5678
|
||||
0xe3, // EX (SP),HL
|
||||
0xdd, 0x21, 0xbc,0x9a, // LD IX, 0x9ABC
|
||||
0xdd, 0xe3, // EX (SP),IX
|
||||
0x76, // HALT
|
||||
0x00 // NOP
|
||||
]
|
174
chipsim.js
|
@ -21,123 +21,116 @@
|
|||
*/
|
||||
|
||||
var ctrace = false;
|
||||
var noGraphics = false;
|
||||
var loglevel = 3;
|
||||
var ridx = 0;
|
||||
var traceTheseNodes = [];
|
||||
var traceTheseTransistors = [];
|
||||
var loglevel = 0;
|
||||
var recalclist = new Array();
|
||||
var recalcHash = new Array();
|
||||
var group = new Array();
|
||||
|
||||
function recalcNodeList(list){
|
||||
var n = list[0];
|
||||
var recalclist = new Array();
|
||||
recalclist = new Array();
|
||||
recalcHash = new Array();
|
||||
for(var j=0;j<100;j++){ // loop limiter
|
||||
if(list.length==0) return;
|
||||
if(ctrace) console.log(j, list);
|
||||
for(var i in list) recalcNode(list[i], recalclist);
|
||||
if(ctrace) {
|
||||
var i;
|
||||
for(i=0;i<traceTheseNodes.length;i++) {
|
||||
if(list.indexOf(traceTheseNodes[i])!=-1) break;
|
||||
}
|
||||
if((traceTheseNodes.length==0)||(list.indexOf(traceTheseNodes[i])==-1)) {
|
||||
console.log('recalcNodeList iteration: ', j, list.length, 'nodes');
|
||||
} else {
|
||||
console.log('recalcNodeList iteration: ', j, list.length, 'nodes', list);
|
||||
}
|
||||
}
|
||||
list.forEach(recalcNode);
|
||||
list = recalclist;
|
||||
recalclist = new Array();
|
||||
recalcHash = new Array();
|
||||
}
|
||||
if(ctrace) console.log(n,'looping...');
|
||||
}
|
||||
|
||||
function recalcNode(node, recalclist){
|
||||
function recalcNode(node){
|
||||
if(node==ngnd) return;
|
||||
if(node==npwr) return;
|
||||
var group = getNodeGroup(node);
|
||||
var newv = getNodeValue(group);
|
||||
if(ctrace) console.log('recalc', node, group);
|
||||
for(var i in group){
|
||||
var n = nodes[group[i]];
|
||||
if(n.state!=newv && ctrace) console.log(group[i], n.state, newv);
|
||||
n.state = newv;
|
||||
for(var t in n.gates) recalcTransistor(n.gates[t], recalclist);
|
||||
}
|
||||
getNodeGroup(node);
|
||||
var newState = getNodeValue();
|
||||
if(ctrace && (traceTheseNodes.indexOf(node)!=-1))
|
||||
console.log('recalc', node, group);
|
||||
group.forEach(function(i){
|
||||
var n = nodes[i];
|
||||
if(n.state==newState) return;
|
||||
n.state = newState;
|
||||
n.gates.forEach(function(t){
|
||||
if(n.state) turnTransistorOn(t);
|
||||
else turnTransistorOff(t);});
|
||||
});
|
||||
}
|
||||
|
||||
function recalcTransistor(tn, recalclist){
|
||||
var t = transistors[tn];
|
||||
if(isNodeHigh(t.gate)) turnTransistorOn(t, recalclist);
|
||||
else turnTransistorOff(t, recalclist);
|
||||
}
|
||||
|
||||
function turnTransistorOn(t, recalclist){
|
||||
function turnTransistorOn(t){
|
||||
if(t.on) return;
|
||||
if(ctrace) console.log(t.name, 'on', t.gate, t.c1, t.c2);
|
||||
if(ctrace && (traceTheseTransistors.indexOf(t.name)!=-1))
|
||||
console.log(t.name, 'on', t.gate, t.c1, t.c2);
|
||||
t.on = true;
|
||||
addRecalcNode(t.c1, recalclist);
|
||||
addRecalcNode(t.c2, recalclist);
|
||||
addRecalcNode(t.c1);
|
||||
}
|
||||
|
||||
function turnTransistorOff(t, recalclist){
|
||||
function turnTransistorOff(t){
|
||||
if(!t.on) return;
|
||||
if(ctrace) console.log(t.name, 'off', t.gate, t.c1, t.c2);
|
||||
if(ctrace && (traceTheseTransistors.indexOf(t.name)!=-1))
|
||||
console.log(t.name, 'off', t.gate, t.c1, t.c2);
|
||||
t.on = false;
|
||||
floatnode(t.c1);
|
||||
floatnode(t.c2);
|
||||
addRecalcNode(t.c1, recalclist);
|
||||
addRecalcNode(t.c2, recalclist);
|
||||
addRecalcNode(t.c1);
|
||||
addRecalcNode(t.c2);
|
||||
}
|
||||
|
||||
function floatnode(nn){
|
||||
if(nn==ngnd) return;
|
||||
if(nn==npwr) return;
|
||||
var n = nodes[nn];
|
||||
if(n.state=='gnd') n.state = 'fl';
|
||||
if(n.state=='pd') n.state = 'fl';
|
||||
if(n.state=='vcc') n.state = 'fh';
|
||||
if(n.state=='pu') n.state = 'fh';
|
||||
if(ctrace) console.log('floating', nn, 'to', n.state);
|
||||
}
|
||||
|
||||
function addRecalcNode(nn, recalclist){
|
||||
if(nn==ngnd) return;
|
||||
if(nn==npwr) return;
|
||||
if(arrayContains(recalclist, nn)) return;
|
||||
recalclist.push(nn);
|
||||
// setAdd(recalclist, nn);
|
||||
function addRecalcNode(nn){
|
||||
if(nn==ngnd) return;
|
||||
if(nn==npwr) return;
|
||||
if(recalcHash[nn] == 1)return;
|
||||
recalclist.push(nn);
|
||||
recalcHash[nn] = 1;
|
||||
}
|
||||
|
||||
function getNodeGroup(i){
|
||||
var group = new Array();
|
||||
addNodeToGroup(i, group);
|
||||
return group;
|
||||
group = new Array();
|
||||
addNodeToGroup(i);
|
||||
}
|
||||
|
||||
function addNodeToGroup(i, group){
|
||||
if(arrayContains(group, i)) return;
|
||||
function addNodeToGroup(i){
|
||||
if(group.indexOf(i) != -1) return;
|
||||
group.push(i);
|
||||
if(i==ngnd) return;
|
||||
if(i==npwr) return;
|
||||
for(var t in nodes[i].c1c2s) addNodeTransistor(i, nodes[i].c1c2s[t], group);
|
||||
}
|
||||
|
||||
function addNodeTransistor(node, t, group){
|
||||
var tr = transistors[t];
|
||||
if(!tr.on) return;
|
||||
var other;
|
||||
if(tr.c1==node) other=tr.c2;
|
||||
if(tr.c2==node) other=tr.c1;
|
||||
addNodeToGroup(other, group);
|
||||
nodes[i].c1c2s.forEach(
|
||||
function(t){
|
||||
if(!t.on) return;
|
||||
var other;
|
||||
if(t.c1==i) other=t.c2;
|
||||
if(t.c2==i) other=t.c1;
|
||||
addNodeToGroup(other);});
|
||||
}
|
||||
|
||||
|
||||
function getNodeValue(group){
|
||||
if(arrayContains(group, ngnd)) return 'gnd';
|
||||
if(arrayContains(group, npwr)) return 'vcc';
|
||||
var flstate;
|
||||
function getNodeValue(){
|
||||
if(arrayContains(group, ngnd)) return false;
|
||||
if(arrayContains(group, npwr)) return true;
|
||||
for(var i in group){
|
||||
var nn = group[i];
|
||||
var n = nodes[nn];
|
||||
if(n.pullup) return 'pu';
|
||||
if(n.pulldown) return 'pd';
|
||||
if((n.state=='fl')&&(flstate==undefined)) flstate = 'fl';
|
||||
if(n.state=='fh') flstate = 'fh';
|
||||
if(n.pullup) return true;
|
||||
if(n.pulldown) return false;
|
||||
if(n.state) return true;
|
||||
}
|
||||
if(flstate==undefined && ctrace) console.log(group);
|
||||
return flstate;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function isNodeHigh(nn){
|
||||
return arrayContains(['vcc','pu','fh'], nodes[nn].state);
|
||||
return(nodes[nn].state);
|
||||
}
|
||||
|
||||
function saveString(name, str){
|
||||
|
@ -150,30 +143,39 @@ function saveString(name, str){
|
|||
|
||||
function allNodes(){
|
||||
var res = new Array();
|
||||
for(var i in nodes) if((i!=npwr)&&(i!=ngnd)) res.push(i);
|
||||
var ii = 0;
|
||||
for(var i in nodes) {
|
||||
// Don't feed numeric strings to recalcNodeList(). Numeric
|
||||
// strings can cause a (data dependent) duplicate node number
|
||||
// hiccup when accumulating a node group's list, ie:
|
||||
// group => [ "49", 483, 49 ]
|
||||
ii = Number( i );
|
||||
if((ii!=npwr)&&(ii!=ngnd)) res.push(ii);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function stateString(){
|
||||
var codes = {gnd: 'g', vcc: 'v', pu: 'p', pd: 'd', fh: 'f', fl: 'l'};
|
||||
var codes = ['l','h'];
|
||||
var res = '';
|
||||
for(var i=0;i<1725;i++){
|
||||
for(var i=0;i<nodes.length;i++){
|
||||
var n = nodes[i];
|
||||
if(n==undefined) res+='x';
|
||||
else if(i==ngnd) res+='g';
|
||||
else if(i==npwr) res+='v';
|
||||
else res+= codes[n.state];
|
||||
else res+= codes[0+n.state];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function showState(str){
|
||||
var codes = {g: 'gnd', v: 'vcc', p: 'pu', d: 'pd', f: 'fh', l: 'fl'};
|
||||
var codes = {g: false, h: true, v: true, l: false};
|
||||
for(var i=0;i<str.length;i++){
|
||||
if(str[i]=='x') continue;
|
||||
nodes[i].state = codes[str[i]];
|
||||
var state = codes[str[i]];
|
||||
nodes[i].state = state;
|
||||
var gates = nodes[i].gates;
|
||||
for(var t in gates) transistors[gates[t]].on = isNodeHigh(i);
|
||||
gates.forEach(function(t){t.on=state;});
|
||||
}
|
||||
refresh();
|
||||
}
|
||||
|
@ -199,12 +201,4 @@ function setLow(name){
|
|||
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;}
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<title>Visual 6800 in JavaScript</title>
|
||||
<style type="text/css">@import "expert.css";</style>
|
||||
<script src="chip-6800/segdefs.js"></script>
|
||||
<script src="chip-6800/transdefs.js"></script>
|
||||
<script src="chip-6800/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="chip-6800/support.js"></script>
|
||||
<script src="chip-6800/testprogram.js"></script>
|
||||
<script src="3rdparty/jquery-1.3.2.min.js"></script>
|
||||
<script src="3rdparty/jquery.cookie.js"></script>
|
||||
<script src="3rdparty/splitter.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function handleOnload() {
|
||||
/MSIE (\d+\.\d+);/.test(navigator.appVersion);
|
||||
IEVersion=Number(RegExp.$1);
|
||||
if((navigator.appName == 'Microsoft Internet Explorer') && (IEVersion<9)){
|
||||
document.getElementById('browsertrouble').innerHTML=
|
||||
'<p>Sorry, '+navigator.appName+' not supported - showing you a picture instead!</p>';
|
||||
document.getElementById('frame').innerHTML='<a href="browsertrouble.html"><img src="images/jssim2.png" style="border:10px"></a>';
|
||||
}else{
|
||||
setTimeout(setup,200);
|
||||
}
|
||||
};
|
||||
|
||||
// initialise splitter (built on jquery)
|
||||
$().ready(function(){
|
||||
$("#frame").splitter({
|
||||
type: "v",
|
||||
outline: true,
|
||||
minLeft: 20,
|
||||
sizeLeft: 810,
|
||||
resizeToWidth: true,
|
||||
anchorToWindow: true,
|
||||
});
|
||||
$("#rightcolumn").splitter({
|
||||
type: "h",
|
||||
outline: true,
|
||||
sizeBottom: 180,
|
||||
minTop: 100,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="handleOnload();">
|
||||
<span id="plain">
|
||||
<a href="http://www.visual6502.org/faq.html">FAQ</a>
|
||||
<a href="http://blog.visual6502.org">Blog</a>
|
||||
<a href="http://www.visual6502.org/links.html">Links</a>
|
||||
<a href="http://github.com/trebonian/visual6502">Source</a>
|
||||
<a href="http://www.textfiles.com/programming/CARDS/6800">6800 instruction card</a>
|
||||
<a href="http://www.sbprojects.com/sbasm/6800.htm#model">programming model</a>
|
||||
</span>
|
||||
<div class="frame" id="frame">
|
||||
<div class="leftcolumn" id="leftcolumn">
|
||||
<div id="chipsurround" tabindex="1">
|
||||
<div class="chip" id="chip">
|
||||
<span id="waiting">Please wait, graphics initialising...</span>
|
||||
<canvas class="chip" id="chipbg"></canvas>
|
||||
<canvas class="chip" id="overlay"></canvas>
|
||||
<canvas class="chip" id="hilite"></canvas>
|
||||
<canvas class="chip" id="hitbuffer"></canvas>
|
||||
</div>
|
||||
</div> <!-- chipsurround -->
|
||||
<div class="nochip" id="nochip">
|
||||
<form>
|
||||
<input type="button" value="Show chip layout" onclick="updateChipLayoutVisibility(true)" />
|
||||
</form>
|
||||
</div>
|
||||
<div id="layoutControlPanel">
|
||||
Use 'z' or '>' to zoom in, 'x' or '<' to zoom out, click to probe signals and drag to pan.
|
||||
<form id="updateShow"> Show:
|
||||
<input type="checkbox" name="1" id="updateShow1" onchange="updateShow(this.name,this.checked)" />(diffusion)
|
||||
<input type="checkbox" name="3" id="updateShow3" onchange="updateShow(this.name,this.checked)" />(grounded diffusion)
|
||||
<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="Find:" 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 style="float:right;">
|
||||
<a href="http://visual6502.org/wiki/index.php?title=JssimUserHelp" target="_blank">User Guide</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">
|
||||
<textarea id="consolebox">
|
||||
click here and type if your program handles input
|
||||
</textarea>
|
||||
<div id="expertControlPanel" tabindex="3">
|
||||
<form action="javascript:updateLogList()">
|
||||
<input type="button" value="Trace more" onclick="updateLoglevel(++loglevel)" />
|
||||
<input type="button" value="Trace less" onclick="updateLoglevel(--loglevel)" />
|
||||
<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>
|
|
@ -0,0 +1,151 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<title>Visual Z80 in JavaScript</title>
|
||||
<style type="text/css">@import "expert.css";</style>
|
||||
<script src="chip-z80/segdefs.js"></script>
|
||||
<script src="chip-z80/transdefs.js"></script>
|
||||
<script src="chip-z80/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="chip-z80/support.js"></script>
|
||||
<script src="chip-z80/testprogram.js"></script>
|
||||
<script src="3rdparty/jquery-1.3.2.min.js"></script>
|
||||
<script src="3rdparty/jquery.cookie.js"></script>
|
||||
<script src="3rdparty/splitter.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function handleOnload() {
|
||||
/MSIE (\d+\.\d+);/.test(navigator.appVersion);
|
||||
IEVersion=Number(RegExp.$1);
|
||||
if((navigator.appName == 'Microsoft Internet Explorer') && (IEVersion<9)){
|
||||
document.getElementById('browsertrouble').innerHTML=
|
||||
'<p>Sorry, '+navigator.appName+' not supported - showing you a picture instead!</p>';
|
||||
document.getElementById('frame').innerHTML='<a href="browsertrouble.html"><img src="images/jssim2.png" style="border:10px"></a>';
|
||||
}else{
|
||||
setTimeout(setup,200);
|
||||
}
|
||||
};
|
||||
|
||||
// initialise splitter (built on jquery)
|
||||
$().ready(function(){
|
||||
$("#frame").splitter({
|
||||
type: "v",
|
||||
outline: true,
|
||||
minLeft: 20,
|
||||
sizeLeft: 810,
|
||||
resizeToWidth: true,
|
||||
anchorToWindow: true,
|
||||
});
|
||||
$("#rightcolumn").splitter({
|
||||
type: "h",
|
||||
outline: true,
|
||||
sizeBottom: 180,
|
||||
minTop: 100,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="handleOnload();">
|
||||
<span id="plain">
|
||||
<a href="http://www.visual6502.org/faq.html">FAQ</a>
|
||||
<a href="http://blog.visual6502.org">Blog</a>
|
||||
<a href="http://www.visual6502.org/links.html">Links</a>
|
||||
<a href="http://github.com/trebonian/visual6502">Source</a>
|
||||
</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 'z' or '>' to zoom in, 'x' or '<' to zoom out, click to probe signals and drag to pan.
|
||||
<form id="updateShow"> Show:
|
||||
<input type="checkbox" name="1" id="updateShow1" onchange="updateShow(this.name,this.checked)" />(diffusion)
|
||||
<input type="checkbox" name="3" id="updateShow3" onchange="updateShow(this.name,this.checked)" />(grounded diffusion)
|
||||
<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="Find:" 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 style="float:right;">
|
||||
<a href="http://visual6502.org/wiki/index.php?title=JssimUserHelp" target="_blank">User Guide</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">
|
||||
<textarea id="consolebox">
|
||||
click here and type if your program handles input
|
||||
</textarea>
|
||||
<div id="expertControlPanel" tabindex="3">
|
||||
<form action="javascript:updateLogList()">
|
||||
<input type="button" value="Trace more" onclick="updateLoglevel(++loglevel)" />
|
||||
<input type="button" value="Trace less" onclick="updateLoglevel(--loglevel)" />
|
||||
<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>
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
textarea#consolebox{
|
||||
font-family:courier,monospace;
|
||||
border: 1px solid gray;
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
width: 80em;
|
||||
}
|
||||
|
||||
div#logstreamscroller{
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
table.logstream {
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
border-collapse: collapse;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
td {
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
td.header {
|
||||
background-color: rgb(187, 204, 255); /* medium-dark blue */
|
||||
}
|
||||
|
||||
td.oddcol {
|
||||
background-color: rgb(227, 233, 255); /* light blue */
|
||||
}
|
||||
|
||||
td.oddrow {
|
||||
background-color: rgb(207, 218, 255); /* medium blue */
|
||||
}
|
||||
|
||||
td.oddrowcol {
|
||||
background-color: rgb(227, 233, 255); /* light blue */
|
||||
}
|
||||
|
||||
/* Splitter */
|
||||
#frame {
|
||||
height: 750px;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
span#plain {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<title>Visual 6502 in JavaScript</title>
|
||||
<style type="text/css">@import "expert.css";</style>
|
||||
<script src="segdefs.js"></script>
|
||||
<script src="transdefs.js"></script>
|
||||
<script src="nodenames.js"></script>
|
||||
<script src="wires.js"></script>
|
||||
<script src="expertWires.js"></script>
|
||||
<script src="chipsim.js"></script>
|
||||
<script src="memtable.js"></script>
|
||||
<script src="macros.js"></script>
|
||||
<script src="testprogram.js"></script>
|
||||
<script src="3rdparty/jquery-1.3.2.min.js"></script>
|
||||
<script src="3rdparty/jquery.cookie.js"></script>
|
||||
<script src="3rdparty/splitter.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function handleOnload() {
|
||||
/MSIE (\d+\.\d+);/.test(navigator.appVersion);
|
||||
IEVersion=Number(RegExp.$1);
|
||||
if((navigator.appName == 'Microsoft Internet Explorer') && (IEVersion<9)){
|
||||
document.getElementById('browsertrouble').innerHTML=
|
||||
'<p>Sorry, '+navigator.appName+' not supported - showing you a picture instead!</p>';
|
||||
document.getElementById('frame').innerHTML='<a href="browsertrouble.html"><img src="images/jssim2.png" style="border:10px"></a>';
|
||||
}else{
|
||||
setTimeout(setup,200);
|
||||
}
|
||||
};
|
||||
|
||||
// initialise splitter (built on jquery)
|
||||
$().ready(function(){
|
||||
$("#frame").splitter({
|
||||
type: "v",
|
||||
outline: true,
|
||||
minLeft: 20,
|
||||
sizeLeft: 810,
|
||||
resizeToWidth: true,
|
||||
anchorToWindow: true,
|
||||
});
|
||||
$("#rightcolumn").splitter({
|
||||
type: "h",
|
||||
outline: true,
|
||||
sizeBottom: 180,
|
||||
minTop: 100,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
||||
<body onload="handleOnload();">
|
||||
<span id="plain">
|
||||
<a href="http://www.visual6502.org/faq.html">FAQ</a>
|
||||
<a href="http://blog.visual6502.org">Blog</a>
|
||||
<a href="http://www.visual6502.org/links.html">Links</a>
|
||||
<a href="http://github.com/trebonian/visual6502">Source</a>
|
||||
<a href="http://skilldrick.github.io/easy6502/#first-program">easy6502 assembler</a>
|
||||
<a href="http://www.masswerk.at/6502/disassembler.html">mass:werk disassembler</a>
|
||||
</span>
|
||||
<div class="frame" id="frame">
|
||||
<div class="leftcolumn" id="leftcolumn">
|
||||
<div id="chipsurround" tabindex="1">
|
||||
<div class="chip" id="chip">
|
||||
<span id="waiting">Please wait, graphics initialising...</span>
|
||||
<canvas class="chip" id="chipbg"></canvas>
|
||||
<canvas class="chip" id="overlay"></canvas>
|
||||
<canvas class="chip" id="hilite"></canvas>
|
||||
<canvas class="chip" id="hitbuffer"></canvas>
|
||||
</div>
|
||||
</div> <!-- chipsurround -->
|
||||
<div class="nochip" id="nochip">
|
||||
<form>
|
||||
<input type="button" value="Show chip layout" onclick="updateChipLayoutVisibility(true)" />
|
||||
</form>
|
||||
</div>
|
||||
<div id="layoutControlPanel">
|
||||
Use 'z' or '>' to zoom in, 'x' or '<' to zoom out, click to probe signals and drag to pan.
|
||||
<form id="updateShow"> Show:
|
||||
<input type="checkbox" name="1" id="updateShow1" onchange="updateShow(this.name,this.checked)" /><label for="updateShow1">(diffusion)</label>
|
||||
<input type="checkbox" name="3" id="updateShow3" onchange="updateShow(this.name,this.checked)" /><label for="updateShow3">(grounded diffusion)</label>
|
||||
<input type="checkbox" name="4" id="updateShow4" onchange="updateShow(this.name,this.checked)" /><label for="updateShow4">(powered diffusion)</label>
|
||||
<input type="checkbox" name="5" id="updateShow5" onchange="updateShow(this.name,this.checked)" /><label for="updateShow5">(polysilicon)</label>
|
||||
<input type="checkbox" name="0" id="updateShow0" onchange="updateShow(this.name,this.checked)" /><label for="updateShow0">(metal)</label>
|
||||
<input type="checkbox" name="2" id="updateShow2" onchange="updateShow(this.name,this.checked)" /><label for="updateShow2">(protection)</label>
|
||||
</form>
|
||||
<form action="javascript:hiliteNodeList();">
|
||||
<input type="button" value="Find:" onclick="hiliteNodeList();" />
|
||||
<input type="text" id="HighlightThese" name="HighlightThese" value="" />
|
||||
<input type="button" value="Clear Highlighting" onclick="clearHighlight();" />
|
||||
<span class="animatebox">
|
||||
<label for="animateModeCheckbox">Animate during simulation:</label>
|
||||
<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 style="float:right;">
|
||||
<a href="https://web.archive.org/web/20210608195625/http://visual6502.org/wiki/index.php?title=JssimUserHelp" target="_blank">User Guide</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">
|
||||
<textarea id="consolebox">
|
||||
click here and type if your program handles input
|
||||
</textarea>
|
||||
<div id="expertControlPanel" tabindex="3">
|
||||
<form action="javascript:updateLogList()">
|
||||
<input type="button" value="Trace more" onclick="updateLoglevel(++loglevel)" />
|
||||
<input type="button" value="Trace less" onclick="updateLoglevel(--loglevel)" />
|
||||
<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>
|
|
@ -0,0 +1,646 @@
|
|||
/*
|
||||
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;
|
||||
var findThese;
|
||||
var labelThese=[];
|
||||
|
||||
// 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 grChipOffsetX=400;
|
||||
var grChipOffsetY=0;
|
||||
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 ' + chipname + '...');
|
||||
setTimeout(setup_part4, 0);
|
||||
}
|
||||
|
||||
function setup_part4(){
|
||||
setupTable();
|
||||
setupNodeNameList();
|
||||
logThese=signalSet(loglevel);
|
||||
loadProgram();
|
||||
setupConsole();
|
||||
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
|
||||
// perform a search, highlight and zoom to object(s)
|
||||
if(name=="find" && value.length>0){
|
||||
findThese=value;
|
||||
} else
|
||||
// affix label with optional box to highlight an area of interest
|
||||
if(name=="label" && value.length>0){
|
||||
labelThese.push(value.split(","));
|
||||
} else
|
||||
// load a test program: Address, Data and Reset
|
||||
if(name=="a" && parseInt(value,16)!=NaN){
|
||||
userAddress=parseInt(value,16);
|
||||
} 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]=[clockTriggers[value],"setLow(nodenamereset);"].join("");
|
||||
} else if(name=="reset1" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setHigh(nodenamereset);"].join("");
|
||||
} else if(name=="irq0" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setLow('irq');"].join("");
|
||||
} else if(name=="irq1" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setHigh('irq');"].join("");
|
||||
} else if(name=="nmi0" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setLow('nmi');"].join("");
|
||||
} else if(name=="nmi1" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setHigh('nmi');"].join("");
|
||||
} else if(name=="rdy0" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setLow('rdy');"].join("");
|
||||
} else if(name=="rdy1" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setHigh('rdy');"].join("");
|
||||
} else if(name=="so0" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setLow('so');"].join("");
|
||||
} else if(name=="so1" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setHigh('so');"].join("");
|
||||
// Some Z80 inputs - we can refactor if this becomes unwieldy
|
||||
} else if(name=="int0" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setLow('int');"].join("");
|
||||
} else if(name=="int1" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setHigh('int');"].join("");
|
||||
} else if(name=="wait0" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setLow('wait');"].join("");
|
||||
} else if(name=="wait1" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setHigh('wait');"].join("");
|
||||
} else if(name=="busrq0" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setLow('busrq');"].join("");
|
||||
} else if(name=="busrq1" && parseInt(value)!=NaN){
|
||||
clockTriggers[value]=[clockTriggers[value],"setHigh('busrq');"].join("");
|
||||
//
|
||||
} else if(name=="time" && parseInt(value)!=NaN){
|
||||
eventTime=value;
|
||||
} else if(name=="databus" && parseInt(value)!=NaN){
|
||||
clockTriggers[eventTime]=[clockTriggers[eventTime],"writeDataBus(0x"+value+");"].join("");
|
||||
} 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 || e.keyCode;
|
||||
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 zoom in/out using the mouse wheel
|
||||
function handleWheelZoom(e){
|
||||
chipsurround.focus();
|
||||
e.preventDefault();
|
||||
var n = e.deltaY / 100;
|
||||
if(n>0 && zoom>1) setZoom(zoom/1.2);
|
||||
if(n<0 && zoom<grMaxZoom) setZoom(zoom*1.2);
|
||||
}
|
||||
|
||||
// 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',
|
||||
});
|
||||
updateLinkHere();
|
||||
}
|
||||
|
||||
function updateLinkHere(){
|
||||
var target = location.pathname + "?nosim=t&";
|
||||
var findlist = document.getElementById('HighlightThese').value.split(/[\s,]+/).join(",");
|
||||
if (findlist != "")
|
||||
target = target + "find=" + findlist + "&";
|
||||
target = target + whereAmIAsQuery();
|
||||
document.getElementById('linkHere').href=target;
|
||||
}
|
||||
|
||||
// place a text label on the highlight layer
|
||||
// with an optional box around an area of interest
|
||||
// coordinates used are those reported by a click
|
||||
// for example:
|
||||
// boxLabel(['PD', 50, 8424, 3536, 9256, 2464])
|
||||
// boxLabel(['IR', 50, 8432, 2332, 9124, 984])
|
||||
// boxLabel(['PLA', 100, 1169, 2328, 8393, 934])
|
||||
// boxLabel(['Y', 50, 2143, 8820, 2317, 5689])
|
||||
// boxLabel(['X', 50, 2317, 8820, 2490, 5689])
|
||||
// boxLabel(['S', 50, 2490, 8820, 2814, 5689])
|
||||
// boxLabel(['ALU', 50, 2814, 8820, 4525, 5689])
|
||||
// boxLabel(['DAdj', 40, 4525, 8820, 5040, 5689])
|
||||
// boxLabel(['A', 50, 5040, 8820, 5328, 5689])
|
||||
// boxLabel(['PC', 50, 5559, 8820, 6819, 5689])
|
||||
// boxLabel(['ID', 50, 7365, 8820, 7676, 5689])
|
||||
// boxLabel(['TimC', 40, 600, 1926, 1174, 604])
|
||||
|
||||
function flashBoxLabel(args) {
|
||||
clearHighlight();
|
||||
var callBack = function(){boxLabel(args);};
|
||||
setTimeout(callBack, 400);
|
||||
setTimeout(clearHighlight, 800);
|
||||
setTimeout(callBack, 1200);
|
||||
}
|
||||
|
||||
function boxLabel(args) {
|
||||
var text = args[0];
|
||||
var textsize = args[1];
|
||||
var thickness = 1+ textsize / 20;
|
||||
var boxXmin = args[2] * grCanvasSize / grChipSize;
|
||||
var boxYmin = args[3] * grCanvasSize / grChipSize;
|
||||
var boxXmax = args[4] * grCanvasSize / grChipSize;
|
||||
var boxYmax = args[5] * grCanvasSize / grChipSize;
|
||||
ctx.lineWidth = thickness;
|
||||
ctx.font = textsize + 'px sans-serif';
|
||||
ctx.fillStyle = '#ff0'; // yellow
|
||||
ctx.fillStyle = '#f8f'; // magenta
|
||||
ctx.fillStyle = '#fff'; // white
|
||||
ctx.strokeStyle = '#fff'; // white
|
||||
if(args.length>4){
|
||||
ctxDrawBox(ctx, boxXmin, boxYmin, boxXmax, boxYmax);
|
||||
// offset the text label to the interior of the box
|
||||
boxYmin -= thickness * 2;
|
||||
}
|
||||
ctx.strokeStyle = '#fff'; // white
|
||||
ctx.strokeStyle = '#000'; // black
|
||||
ctx.lineWidth = thickness*2;
|
||||
ctx.strokeText(text, boxXmin, boxYmin);
|
||||
ctx.fillText(text, boxXmin, boxYmin);
|
||||
}
|
||||
|
||||
var highlightThese;
|
||||
|
||||
// flash some set of nodes according to user input
|
||||
// also zoom to fit those nodes (not presently optional)
|
||||
function hiliteNodeList(){
|
||||
var tmplist = document.getElementById('HighlightThese').value.split(/[\s,]+/);
|
||||
if(tmplist.join("").length==0){
|
||||
// request to highlight nothing, so switch off any signal highlighting
|
||||
hiliteNode(-1);
|
||||
return;
|
||||
}
|
||||
highlightThese = [];
|
||||
var seglist=[];
|
||||
var report="";
|
||||
for(var i=0;i<tmplist.length;i++){
|
||||
// get a node number from a signal name or a node number
|
||||
var name = tmplist[i];
|
||||
var value = parseInt(tmplist[i]);
|
||||
if((value!=NaN) && (typeof nodes[value] != "undefined")) {
|
||||
highlightThese.push(value);
|
||||
report="node: " + value + ' ' + nodeName(value);
|
||||
for(var s in nodes[value].segs)
|
||||
seglist.push(nodes[value].segs[s]);
|
||||
} else if(typeof nodenames[name] != "undefined") {
|
||||
highlightThese.push(nodenames[name]);
|
||||
report="node: " + nodenames[name] + ' ' + name;
|
||||
for(var s in nodes[nodenames[name]].segs)
|
||||
seglist.push(nodes[nodenames[name]].segs[s]);
|
||||
} else if(typeof transistors[name] != "undefined") {
|
||||
// normally we push numbers: a non-number is a transistor name
|
||||
highlightThese.push(name);
|
||||
report="transistor: " + name;
|
||||
seglist.push([
|
||||
transistors[name].bb[0],transistors[name].bb[2],
|
||||
transistors[name].bb[1],transistors[name].bb[3]
|
||||
]);
|
||||
} else {
|
||||
// allow match of underscore-delimited components, so
|
||||
// SUMS and dpc17 both match the node dpc17_SUMS
|
||||
for(var i in nodenames){
|
||||
re=new RegExp("(^" + name + "_|_" + name + "$)");
|
||||
if (re.test(i)){
|
||||
value = nodenames[i];
|
||||
highlightThese.push(value);
|
||||
report="node: " + value + ' ' + nodeName(value);
|
||||
for(var s in nodes[value].segs)
|
||||
seglist.push(nodes[value].segs[s]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(highlightThese.length==0){
|
||||
setStatus('Find: nothing found!','(Enter a list of nodenumbers, names or transistor names)');
|
||||
return;
|
||||
} else if (highlightThese.length==1){
|
||||
setStatus('Find results:',report);
|
||||
} else {
|
||||
setStatus('Find: multiple objects found','(' + highlightThese.length + ' objects)');
|
||||
}
|
||||
var xmin=seglist[0][0], xmax=seglist[0][0];
|
||||
var ymin=seglist[0][1], ymax=seglist[0][1];
|
||||
for(var s in seglist){
|
||||
for(var i=0;i<seglist[s].length;i+=2){
|
||||
if(seglist[s][i]<xmin) xmin=seglist[s][i];
|
||||
if(seglist[s][i]>xmax) xmax=seglist[s][i];
|
||||
if(seglist[s][i+1]<ymin) ymin=seglist[s][i+1];
|
||||
if(seglist[s][i+1]>ymax) ymax=seglist[s][i+1];
|
||||
}
|
||||
}
|
||||
zoomToBox(xmin,xmax,ymin,ymax);
|
||||
updateLinkHere();
|
||||
clearHighlight(); // nullify the simulation overlay (orange/purple)
|
||||
hiliteNode(-1); // unhighlight all nodes
|
||||
setTimeout("hiliteNode(highlightThese);", 400);
|
||||
setTimeout("hiliteNode(-1);", 800);
|
||||
setTimeout("hiliteNode(highlightThese);", 1200);
|
||||
}
|
||||
|
||||
// some notes on coordinates:
|
||||
// the localx and localy functions return canvas coordinate offsets from the canvas window top left corner
|
||||
// we divide the results by 'zoom' to get drawn coordinates useful in findNodeNumber
|
||||
// to convert to reported user chip coordinates we multiply by grChipSize/600
|
||||
// to compare to segdefs and transdefs coordinates we subtract grChipOffsetX from x and subtract y from grChipSize plus grChipOffsetY
|
||||
|
||||
function handleClick(e){
|
||||
var x = localx(hilite, e.clientX)/zoom;
|
||||
var y = localy(hilite, e.clientY)/zoom;
|
||||
var w = findNodeNumber(x,y);
|
||||
// convert to chip coordinates
|
||||
var cx = Math.round(x*grChipSize/600);
|
||||
var cy = Math.round(y*grChipSize/600);
|
||||
// prepare two lines of status report
|
||||
var s1='x: ' + (cx - grChipOffsetX) + ' y: ' + (cy - grChipOffsetY);
|
||||
var s2='node: ' + w + ' ' + nodeName(w);
|
||||
if(w==-1) {
|
||||
setStatus(s1); // no node found, so report only coordinates
|
||||
return;
|
||||
}
|
||||
// we have a node, but maybe we clicked over a transistor
|
||||
var nodelist=[w];
|
||||
// match the coordinate against transistor gate bounding boxes
|
||||
x=cx-grChipOffsetX;
|
||||
y=grChipSize+grChipOffsetY-cy;
|
||||
for(var i=0;i<nodes[w].gates.length;i++){
|
||||
var xmin=nodes[w].gates[i].bb[0], xmax=nodes[w].gates[i].bb[1];
|
||||
var ymin=nodes[w].gates[i].bb[2], ymax=nodes[w].gates[i].bb[3];
|
||||
if((x >= xmin) && (x <= xmax) && (y >= ymin) && (y <= ymax)){
|
||||
// only one match at most, so we replace rather than push
|
||||
nodelist=[nodes[w].gates[i].name];
|
||||
s2='transistor: ' + nodes[w].gates[i].name + ' on ' + s2;
|
||||
}
|
||||
}
|
||||
// if this is a shift-click, just find and highlight the pass-connected group
|
||||
// and list the nodes (or nodenames, preferably)
|
||||
if(e.shiftKey) {
|
||||
getNodeGroup(w);
|
||||
nodelist = group;
|
||||
s2 = "nodegroup from " + s2 +
|
||||
" (nodes: " +
|
||||
group.map(function(x){return nodeName(x)?nodeName(x):x;}).join(",") +
|
||||
")";
|
||||
}
|
||||
hiliteNode(nodelist);
|
||||
setStatus(s1, s2);
|
||||
if(ctrace) console.log(s1, s2);
|
||||
}
|
||||
|
||||
function updateLoglevel(value){
|
||||
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 consolegetc; // global variable to hold last keypress in the console area
|
||||
var consolebox;
|
||||
|
||||
function setupConsole(){
|
||||
consolebox=document.getElementById('consolebox');
|
||||
consolebox.onkeypress=function(e){consolegetc=e.charCode || e.keyCode;};
|
||||
}
|
||||
|
||||
var chipsurround;
|
||||
|
||||
function updateChipLayoutVisibility(isOn){
|
||||
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
|
||||
// pre-fill the Find box if parameters supplied
|
||||
if(typeof findThese != "undefined") {
|
||||
document.getElementById('HighlightThese').value = findThese;
|
||||
hiliteNodeList(); // will pan and zoom to fit
|
||||
}
|
||||
// pre-pan and zoom if requested (will override any zoom-to-fit by hiliteNodeList)
|
||||
if(moveHereFirst!=null)
|
||||
moveHere(moveHereFirst);
|
||||
// draw any URL-requested labels and boxes
|
||||
if(labelThese.length>0) {
|
||||
for(var i=0;i<labelThese.length;i+=1)
|
||||
flashBoxLabel(labelThese[i]);
|
||||
}
|
||||
// grant focus to the chip display to enable zoom keys
|
||||
chipsurround.focus();
|
||||
chipsurround.onwheel = function(e){handleWheelZoom(e);};
|
||||
chipsurround.onmousedown = function(e){mouseDown(e);};
|
||||
chipsurround.onkeypress = function(e){handleKey(e);};
|
||||
chipsurround.onmouseout = function(e){mouseLeave(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];
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 321 B |
After Width: | Height: | Size: 319 B |
56
index.html
|
@ -2,17 +2,25 @@
|
|||
|
||||
<head>
|
||||
<title>Visual 6502 in JavaScript</title>
|
||||
<style type="text/css">@import "wires.css";</style>
|
||||
|
||||
<!-- by default, index.html will run in kiosk mode -->
|
||||
<style type="text/css">@import "kiosk.css";</style>
|
||||
<script src="segdefs.js"></script>
|
||||
<script src="transdefs.js"></script>
|
||||
<script src="nodenames.js"></script>
|
||||
<script src="kioskWires.js"></script>
|
||||
<script src="wires.js"></script>
|
||||
<script src="chipsim.js"></script>
|
||||
<script src="memtable.js"></script>
|
||||
<script src="macros.js"></script>
|
||||
<script src="testprogram.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
function handleOnload() {
|
||||
// two checks and fixes here:
|
||||
// - replace the dynamic content with an image if running older versions of IE
|
||||
// - redirect to the expert page if we find any query parameters
|
||||
//
|
||||
/MSIE (\d+\.\d+);/.test(navigator.appVersion);
|
||||
IEVersion=Number(RegExp.$1);
|
||||
if((navigator.appName == 'Microsoft Internet Explorer') && (IEVersion<9)){
|
||||
|
@ -20,7 +28,20 @@ function handleOnload() {
|
|||
'<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);
|
||||
var suffix=location.search;
|
||||
var path=location.pathname;
|
||||
// ensure we always have a trailing slash
|
||||
path=path.replace("index.html","").replace(/\/?$/,"/");
|
||||
|
||||
if (suffix != "") {
|
||||
// redirect to the expert page
|
||||
var prefix=location.protocol+"//"+location.host+path;
|
||||
window.location.replace(prefix+"expert.html"+suffix);
|
||||
return;
|
||||
} else {
|
||||
// normal case: start the simulator
|
||||
setTimeout(setup,200);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -41,11 +62,11 @@ lots of RAM. If you have trouble, please <a href="browsertrouble.html">check com
|
|||
<br />
|
||||
<span id="browsertrouble"></span>
|
||||
<br />
|
||||
Hit '>' to zoom in, '<' to zoom out
|
||||
Keyboard controls: 'z' to zoom in, 'x' to zoom out, 'n' to step the simulation.
|
||||
<br />
|
||||
Right-click to scroll around
|
||||
Mouse controls: Left-click and drag to scroll around (when you're zoomed in.)
|
||||
<br />
|
||||
Enter your own program into the array of RAM
|
||||
More information in the <a href="https://web.archive.org/web/20210608195625/http://visual6502.org/wiki/index.php?title=JssimUserHelp">User Guide</a>.
|
||||
<br />
|
||||
<br />
|
||||
</span>
|
||||
|
@ -58,31 +79,28 @@ Enter your own program into the array of RAM
|
|||
</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>
|
||||
<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="start"></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>
|
||||
<a href ="javascript:resetChip()"><img class="navbutton" src="images/up.png" title="reset"></a>
|
||||
<a href ="javascript:stepBack()"><img class="navbutton" src="images/prev.png" title="back"></a>
|
||||
<a href ="javascript:stepForward()"><img class="navbutton" src="images/next.png" title="step"></a>
|
||||
</div>
|
||||
<div style="float:right; margin-left:20px;">... or try <a href="expert.html">Advanced</a></div>
|
||||
</div>
|
||||
<p class="status" id="status">x: 0<br>y: 0</p>
|
||||
<table class="memtable" id="memtable"></table>
|
||||
</div>
|
||||
<div id="updateShow"> Show:
|
||||
<input type="checkbox" name="0" id="updateShow0" onchange="updateShow(this.name,this.checked)" />(metal)
|
||||
<input type="checkbox" name="1" id="updateShow1" onchange="updateShow(this.name,this.checked)" />(switched 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="2" id="updateShow2" onchange="updateShow(this.name,this.checked)" />(diode)
|
||||
<div id="updateShow">
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
Source code is available on GitHub: <a href="http://github.com/trebonian/visual6502">http://github.com/trebonian/visual6502</a>
|
||||
Source code is available on <a href="http://github.com/trebonian/visual6502">github visual6502</a>.
|
||||
Use the online <a href="https://skilldrick.github.io/easy6502/#first-program">emulator and assembler</a> from the easy6502 tutorial
|
||||
and <a href="http://www.masswerk.at/6502/disassembler.html">disassembler</a> from mass:werk
|
||||
<br />
|
||||
In addition to this JavaScript project, see our <a href="../python6502.html">Python-based simulator</a> which may be easier to customize, verify, and apply to the study of long programs.<br />
|
||||
For in-depth 6502 investigation and some more advanced features, try our <a href="expert.html">Advanced</a> page.
|
||||
<br />
|
||||
<br />
|
||||
|
||||
|
|
|
@ -89,6 +89,6 @@ table.memtable {
|
|||
}
|
||||
|
||||
#title {
|
||||
font-size:30px;
|
||||
font-size:30px;
|
||||
font-weight:bold;
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
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 grChipOffsetX=400;
|
||||
var grChipOffsetY=0;
|
||||
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();
|
||||
writeTriggers={}; // kiosk mode does not handle I/O
|
||||
initChip();
|
||||
document.getElementById('stop').style.visibility = 'hidden';
|
||||
go();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// User Interface
|
||||
//
|
||||
/////////////////////////
|
||||
|
||||
function handleKey(e){
|
||||
var c = e.charCode || e.keyCode;
|
||||
c = String.fromCharCode(c);
|
||||
if('zx<>?np'.indexOf(c)==-1) return;
|
||||
if((c=='x' || c=='<') && zoom>1) setZoom(zoom/1.2);
|
||||
else if((c=='z' || c=='>') && zoom<grMaxZoom) setZoom(zoom*1.2);
|
||||
else if(c=='?') setZoom(1);
|
||||
else if(c=='n') stepForward();
|
||||
else if(c=='p') stepBack();
|
||||
}
|
||||
|
||||
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) {
|
||||
getNodeGroup(w);
|
||||
hiliteNode(group);
|
||||
}
|
||||
else {var a=new Array(); a.push(w); hiliteNode(a);}
|
||||
var cx = Math.round(x*grChipSize/600);
|
||||
var cy = Math.round(y*grChipSize/600);
|
||||
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];
|
||||
}
|
||||
}
|
675
macros.js
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2010 Brian Silverman, Barry Silverman
|
||||
Copyright (c) 2010 Brian Silverman, Barry Silverman, Ed Spittles, Achim Breidenbach
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -21,30 +21,82 @@
|
|||
*/
|
||||
|
||||
var memory = Array();
|
||||
var code = [0xa9, 0x00, 0x20, 0x10, 0x00, 0x4c, 0x02, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xe8, 0x88, 0xe6, 0x40, 0x38, 0x69, 0x02, 0x60];
|
||||
var cycle = 0;
|
||||
var trace = Array();
|
||||
var logstream = Array();
|
||||
var running = false;
|
||||
var logThese=[];
|
||||
var chipname='6502';
|
||||
var nodenamereset='res';
|
||||
var presetLogLists=[
|
||||
['cycle'],
|
||||
['ab','db','rw','Fetch','pc','a','x','y','s','p'],
|
||||
['Execute','State'],
|
||||
['ir','tcstate','-pd'],
|
||||
['adl','adh','sb','alu'],
|
||||
['alucin','alua','alub','alucout','aluvout','dasb'],
|
||||
['plaOutputs','DPControl'],
|
||||
['idb','dor'],
|
||||
['irq','nmi',nodenamereset],
|
||||
];
|
||||
|
||||
function go(n){
|
||||
for(var i=0;i<code.length;i++){
|
||||
mWrite(i, code[i]);
|
||||
setCellValue(i, code[i]);
|
||||
}
|
||||
mWrite(0xfffc, 0x00);
|
||||
mWrite(0xfffd, 0x00);
|
||||
steps();
|
||||
function loadProgram(){
|
||||
// a moderate size of static testprogram might be loaded
|
||||
if(testprogram.length!=0 && testprogramAddress != undefined)
|
||||
for(var i=0;testprogram[i]!=undefined;i++){
|
||||
var a=testprogramAddress+i;
|
||||
mWrite(a, testprogram[i]);
|
||||
if(a<0x200)
|
||||
setCellValue(a, testprogram[i]);
|
||||
}
|
||||
// a small test program or patch might be passed in the URL
|
||||
if(userCode.length!=0)
|
||||
for(var i=0;i<userCode.length;i++){
|
||||
if(userCode[i] != undefined){
|
||||
mWrite(i, userCode[i]);
|
||||
if(i<0x200)
|
||||
setCellValue(i, userCode[i]);
|
||||
}
|
||||
}
|
||||
// default reset vector will be 0x0000 because undefined memory reads as zero
|
||||
if(userResetLow!=undefined)
|
||||
mWrite(0xfffc, userResetLow);
|
||||
if(userResetHigh!=undefined)
|
||||
mWrite(0xfffd, userResetHigh);
|
||||
}
|
||||
|
||||
function steps(){
|
||||
function go(){
|
||||
if(typeof userSteps != "undefined"){
|
||||
if(--userSteps==0){
|
||||
running=false;
|
||||
userSteps=undefined;
|
||||
}
|
||||
}
|
||||
if(running) {
|
||||
step();
|
||||
setTimeout(steps, 0); // schedule the next poll
|
||||
setTimeout(go, 0); // schedule the next poll
|
||||
}
|
||||
}
|
||||
|
||||
function goUntilSync(){
|
||||
halfStep();
|
||||
while(!isNodeHigh(nodenames['sync']) || isNodeHigh(nodenames['clk0']))
|
||||
halfStep();
|
||||
}
|
||||
|
||||
function goUntilSyncOrWrite(){
|
||||
halfStep();
|
||||
cycle++;
|
||||
while(
|
||||
!isNodeHigh(nodenames['clk0']) ||
|
||||
( !isNodeHigh(nodenames['sync']) && isNodeHigh(nodenames['rw']) )
|
||||
) {
|
||||
halfStep();
|
||||
cycle++;
|
||||
}
|
||||
chipStatus();
|
||||
}
|
||||
|
||||
function testNMI(n){
|
||||
initChip();
|
||||
|
||||
|
@ -85,56 +137,118 @@ function testNMI(n){
|
|||
for(var i=0;i<16;i++){step();}
|
||||
}
|
||||
|
||||
|
||||
function initChip(){
|
||||
var start = now();
|
||||
for(var nn in nodes) nodes[nn].state = 'fl';
|
||||
nodes[ngnd].state = 'gnd';
|
||||
nodes[npwr].state = 'vcc';
|
||||
for(var nn in nodes) {
|
||||
nodes[nn].state = false;
|
||||
nodes[nn].float = true;
|
||||
}
|
||||
|
||||
nodes[ngnd].state = false;
|
||||
nodes[ngnd].float = false;
|
||||
nodes[npwr].state = true;
|
||||
nodes[npwr].float = false;
|
||||
for(var tn in transistors) transistors[tn].on = false;
|
||||
setLow('res');
|
||||
setLow(nodenamereset);
|
||||
setLow('clk0');
|
||||
setHigh('rdy'); setLow('so');
|
||||
setHigh('irq'); setHigh('nmi');
|
||||
recalcNodeList(allNodes());
|
||||
for(var i=0;i<8;i++){setHigh('clk0'), setLow('clk0');}
|
||||
setHigh('res');
|
||||
for(var i=0;i<18;i++){resetStep();}
|
||||
setHigh(nodenamereset);
|
||||
for(var i=0;i<18;i++){halfStep();} // avoid updating graphics and trace buffer before user code
|
||||
refresh();
|
||||
cycle = 0;
|
||||
trace = Array();
|
||||
if(typeof expertMode != "undefined")
|
||||
updateLogList();
|
||||
chipStatus();
|
||||
if(ctrace)console.log('initChip done after', now()-start);
|
||||
}
|
||||
|
||||
function signalSet(n){
|
||||
var signals=[];
|
||||
for (var i=0; (i<=n)&&(i<presetLogLists.length) ; i++){
|
||||
for (var j=0; j<presetLogLists[i].length; j++){
|
||||
signals.push(presetLogLists[i][j]);
|
||||
}
|
||||
}
|
||||
return signals;
|
||||
}
|
||||
|
||||
function updateLogList(names){
|
||||
// user supplied a list of signals, which we append to the set defined by loglevel
|
||||
logThese = signalSet(loglevel);
|
||||
if(typeof names == "undefined")
|
||||
// this is a UI call - read the text input
|
||||
names = document.getElementById('LogThese').value;
|
||||
else
|
||||
// this is an URL call - update the text input box
|
||||
document.getElementById('LogThese').value = names;
|
||||
names = names.split(/[\s,]+/);
|
||||
for(var i=0;i<names.length;i++){
|
||||
// could be a signal name, a node number, or a special name
|
||||
if(typeof busToString(names[i]) != "undefined")
|
||||
logThese.push(names[i]);
|
||||
}
|
||||
initLogbox(logThese);
|
||||
}
|
||||
|
||||
var traceChecksum='';
|
||||
var goldenChecksum;
|
||||
|
||||
// simulate a single clock phase, updating trace and highlighting layout
|
||||
function step(){
|
||||
trace[cycle]= {chip: stateString(), mem: getMem()};
|
||||
var s=stateString();
|
||||
var m=getMem();
|
||||
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
|
||||
// almost always are undefined when tested, so minimal impact on performance
|
||||
clockTriggers={};
|
||||
writeTriggers={};
|
||||
readTriggers={};
|
||||
fetchTriggers={};
|
||||
|
||||
// example instruction tracing triggers
|
||||
// fetchTriggers[0x20]="console.log('0x'+readAddressBus().toString(16)+': JSR');";
|
||||
// fetchTriggers[0x60]="console.log('0x'+readAddressBus().toString(16)+': RTS');";
|
||||
// fetchTriggers[0x4c]="console.log('0x'+readAddressBus().toString(16)+': JMP');";
|
||||
|
||||
// simulate a single clock phase with no update to graphics or trace
|
||||
function halfStep(){
|
||||
var clk = isNodeHigh(nodenames['clk0']);
|
||||
if (clk) {setLow('clk0'); handleBusRead(); }
|
||||
else {setHigh('clk0'); handleBusWrite();}
|
||||
refresh();
|
||||
}
|
||||
eval(clockTriggers[cycle+1]); // pre-apply next tick's inputs now, so the updates are displayed
|
||||
|
||||
function resetStep(){
|
||||
var clk = isNodeHigh(nodenames['clk0']);
|
||||
if (clk) {setLow('clk0'); handleBusRead(); }
|
||||
else {setHigh('clk0'); handleBusWrite();}
|
||||
}
|
||||
|
||||
function handleBusRead(){
|
||||
if(isNodeHigh(nodenames['rw'])) writeDataBus(mRead(readAddressBus()));
|
||||
if(isNodeHigh(nodenames['rw'])){
|
||||
var a = readAddressBus();
|
||||
var d = eval(readTriggers[a]);
|
||||
if(d == undefined)
|
||||
d = mRead(readAddressBus());
|
||||
if(isNodeHigh(nodenames['sync']))
|
||||
eval(fetchTriggers[d]);
|
||||
writeDataBus(d);
|
||||
}
|
||||
}
|
||||
|
||||
function handleBusWrite(){
|
||||
if(!isNodeHigh(nodenames['rw'])){
|
||||
var a = readAddressBus();
|
||||
var d = readDataBus();
|
||||
eval(writeTriggers[a]);
|
||||
mWrite(a,d);
|
||||
if(a<0x200) setCellValue(a,d);
|
||||
}
|
||||
|
@ -150,8 +264,8 @@ function readPstring(){
|
|||
var result;
|
||||
result = (isNodeHigh(nodenames['p7'])?'N':'n') +
|
||||
(isNodeHigh(nodenames['p6'])?'V':'v') +
|
||||
'-' +
|
||||
(isNodeHigh(nodenames['p3'])?'B':'b') +
|
||||
'‑' + // non-breaking hyphen
|
||||
(isNodeHigh(nodenames['p4'])?'B':'b') +
|
||||
(isNodeHigh(nodenames['p3'])?'D':'d') +
|
||||
(isNodeHigh(nodenames['p2'])?'I':'i') +
|
||||
(isNodeHigh(nodenames['p1'])?'Z':'z') +
|
||||
|
@ -163,6 +277,98 @@ function readPC(){return (readBits('pch', 8)<<8) + readBits('pcl', 8);}
|
|||
function readPCL(){return readBits('pcl', 8);}
|
||||
function readPCH(){return readBits('pch', 8);}
|
||||
|
||||
// for one-hot or few-hot signal collections we want to list the active ones
|
||||
// and for brevity we remove the common prefix
|
||||
function listActiveSignals(pattern){
|
||||
var r=new RegExp(pattern);
|
||||
var list=[];
|
||||
for(var i in nodenamelist){
|
||||
if(r.test(nodenamelist[i])) {
|
||||
if(isNodeHigh(nodenames[nodenamelist[i]]))
|
||||
// also map hyphen to a non-breaking version
|
||||
list.push(nodenamelist[i].replace(r,'').replace(/-/g,'‑'));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// The 6502 TCState is almost but not quite an inverted one-hot shift register
|
||||
function listActiveTCStates() {
|
||||
var s=[];
|
||||
if(!isNodeHigh(nodenames['clock1'])) s.push("T0");
|
||||
if(!isNodeHigh(nodenames['clock2'])) s.push("T1");
|
||||
if(!isNodeHigh(nodenames['t2'])) s.push("T2");
|
||||
if(!isNodeHigh(nodenames['t3'])) s.push("T3");
|
||||
if(!isNodeHigh(nodenames['t4'])) s.push("T4");
|
||||
if(!isNodeHigh(nodenames['t5'])) s.push("T5");
|
||||
return s.join("+");
|
||||
}
|
||||
|
||||
// Show all time code node states (active and inactive) in fixed format,
|
||||
// with non-PLA-controlling internal state indication in square
|
||||
// brackets, followed by RCL-resident timing state indication.
|
||||
// ".." for a PLA-controlling node indicates inactive state, "T"* for a
|
||||
// PLA-controlling node indicates active state.
|
||||
// Bracketed codes are one of T1/V0/T6/..
|
||||
// V0 indicates the VEC0 node, T6 is a synonym for the VEC1 node.
|
||||
// The RCL codes are one of SD1/SD2/...
|
||||
// For discussion of this reconstruction, see:
|
||||
// http://visual6502.org/wiki/index.php?title=6502_Timing_States
|
||||
function allTCStates( useHTML )
|
||||
{
|
||||
var s = "";
|
||||
var _spc;
|
||||
useHTML = (typeof useHTML === 'undefined') ? false : useHTML;
|
||||
// Use Non-Breaking Space for presentation in an HTML (browser)
|
||||
// context, else use ASCII space for logging context
|
||||
_spc = useHTML ? ' ' : ' ';
|
||||
if ( !isNodeHigh( nodenames[ 'clock1' ] ) ) s += "T0"; else s += "..";
|
||||
s += _spc;
|
||||
// T+ in visual6502 is called T1x in
|
||||
// http://www.weihenstephan.org/~michaste/pagetable/6502/6502.jpg
|
||||
// Notated as T+ for compatibility with PLA node names
|
||||
if ( !isNodeHigh( nodenames[ 'clock2' ] ) ) s += "T+"; else s += "..";
|
||||
s += _spc;
|
||||
if ( !isNodeHigh( nodenames[ 't2' ] ) ) s += "T2"; else s += "..";
|
||||
s += _spc;
|
||||
if ( !isNodeHigh( nodenames[ 't3' ] ) ) s += "T3"; else s += "..";
|
||||
s += _spc;
|
||||
if ( !isNodeHigh( nodenames[ 't4' ] ) ) s += "T4"; else s += "..";
|
||||
s += _spc;
|
||||
if ( !isNodeHigh( nodenames[ 't5' ] ) ) s += "T5"; else s += "..";
|
||||
s += _spc + "[";
|
||||
// Check three confirmed exclusive states (three nodes)
|
||||
if ( isNodeHigh( 862 ) ) {
|
||||
s += "T1";
|
||||
// ...else if VEC0 is on...
|
||||
} else if ( isNodeHigh( nodenames[ 'VEC0' ] ) ) {
|
||||
// ...then tell the outside world
|
||||
s += "V0";
|
||||
// ...else if VEC1 is on...
|
||||
} else if ( isNodeHigh( nodenames[ 'VEC1' ] ) ) {
|
||||
// ...then this is the canonical T6. It is a synonym for VEC1
|
||||
s += "T6";
|
||||
} else {
|
||||
// ...else none of the "hidden" bits in the clock state is active
|
||||
s += "..";
|
||||
}
|
||||
s += "]" + _spc;
|
||||
// Check the RCL's two confirmed exclusive states (two nodes)
|
||||
// If this node is grounding ~WR...
|
||||
if ( isNodeHigh( 440 ) ) {
|
||||
// ...then we can regard this state as Store Data 1
|
||||
s += "SD1";
|
||||
// ...else if this node is grounding ~WR...
|
||||
} else if ( isNodeHigh( 1258 ) ) {
|
||||
// ...then we can regard this state as Store Data 2
|
||||
s += "SD2";
|
||||
} else {
|
||||
// ...else none of the RCL-resident timing bits is active
|
||||
s += "...";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function readBit(name){
|
||||
return isNodeHigh(nodenames[name])?1:0;
|
||||
}
|
||||
|
@ -175,6 +381,72 @@ function readBits(name, n){
|
|||
return res;
|
||||
}
|
||||
|
||||
function busToString(busname){
|
||||
// takes a signal name or prefix
|
||||
// returns an appropriate string representation
|
||||
// some 'signal names' are CPU-specific aliases to user-friendly string output
|
||||
if(busname=='cycle')
|
||||
return cycle>>1;
|
||||
if(busname=='pc')
|
||||
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=='State')
|
||||
return listActiveTCStates();
|
||||
if(busname=='TState')
|
||||
return allTCStates( true );
|
||||
if(busname=='Phi')
|
||||
// Pretty-printed phase indication based on the state of cp1,
|
||||
// the internal Phase 1 node
|
||||
return 'Φ' +
|
||||
(isNodeHigh( nodenames[ 'cp1' ] ) ? '1' : '2');
|
||||
if(busname=='Execute')
|
||||
return disassemblytoHTML(readBits('ir',8));
|
||||
if(busname=='Fetch')
|
||||
return isNodeHigh(nodenames['sync'])?disassemblytoHTML(readDataBus()):"";
|
||||
if(busname=='plaOutputs')
|
||||
// PLA outputs are mostly ^op- but some have a prefix too
|
||||
// - we'll allow the x and xx prefix but ignore the #
|
||||
return listActiveSignals('^([x]?x-)?op-');
|
||||
if(busname=='DPControl')
|
||||
return listActiveSignals('^dpc[-]?[0-9]+_');
|
||||
if(busname[0]=="-"){
|
||||
// invert the value of the bus for display
|
||||
var value=busToHex(busname.slice(1))
|
||||
if(typeof value != "undefined")
|
||||
return value.replace(/./g,function(x){return (15-parseInt(x,16)).toString(16)});
|
||||
else
|
||||
return undefined;;
|
||||
} else {
|
||||
return busToHex(busname);
|
||||
}
|
||||
}
|
||||
|
||||
function busToHex(busname){
|
||||
// may be passed a bus or a signal, so allow multiple signals
|
||||
var width=0;
|
||||
var r=new RegExp('^' + busname + '[0-9]+$');
|
||||
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++){
|
||||
|
@ -195,12 +467,11 @@ function mRead(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 = transistors[nodes[943].gates[i]];
|
||||
var t = nodes[943].gates[i];
|
||||
if(t.c1==npwr) res.push(t.c2);
|
||||
if(t.c2==npwr) res.push(t.c1);
|
||||
}
|
||||
|
@ -212,8 +483,10 @@ function runChip(){
|
|||
var stop = document.getElementById('stop');
|
||||
start.style.visibility = 'hidden';
|
||||
stop.style.visibility = 'visible';
|
||||
if(typeof running == "undefined")
|
||||
initChip();
|
||||
running = true;
|
||||
steps();
|
||||
go();
|
||||
}
|
||||
|
||||
function stopChip(){
|
||||
|
@ -226,11 +499,13 @@ function stopChip(){
|
|||
|
||||
function resetChip(){
|
||||
stopChip();
|
||||
setStatus('resetting 6502...');
|
||||
setStatus('resetting ' + chipname + '...');
|
||||
setTimeout(initChip,0);
|
||||
}
|
||||
|
||||
function stepForward(){
|
||||
if(typeof running == "undefined")
|
||||
initChip();
|
||||
stopChip();
|
||||
step();
|
||||
}
|
||||
|
@ -259,28 +534,148 @@ function chipStatus(){
|
|||
' Y:' + hexByte(readY()) +
|
||||
' SP:' + hexByte(readSP()) +
|
||||
' ' + readPstring();
|
||||
var machine3 =
|
||||
' Sync:' + readBit('sync')
|
||||
' IRQ:' + readBit('irq') +
|
||||
' NMI:' + readBit('nmi');
|
||||
var machine4 =
|
||||
' IR:' + hexByte(255 - readBits('notir', 8)) +
|
||||
' idl:' + hexByte(255 - readBits('idl', 8)) +
|
||||
' alu:' + hexByte(255 - readBits('alu', 8)) +
|
||||
' TCstate:' + readBit('clock1') + readBit('clock2') +
|
||||
readBit('t2') + readBit('t3') + readBit('t4') + readBit('t5');
|
||||
var machine5 =
|
||||
' notRdy0:' + readBit('notRdy0') +
|
||||
' fetch:' + readBit('fetch') +
|
||||
' clearIR:' + readBit('clearIR') +
|
||||
' D1x1:' + readBit('D1x1');
|
||||
setStatus(machine1 + "<br>" + machine2);
|
||||
if (loglevel>2 && ctrace) {
|
||||
console.log(machine1 + " " + machine2 + " " + machine3 + " " + machine4 + " " + machine5);
|
||||
var machine3 =
|
||||
'Hz: ' + estimatedHz().toFixed(1);
|
||||
if(typeof expertMode != "undefined") {
|
||||
machine3 += ' Exec: ' + busToString('Execute') + '(' + busToString('State') + ')';
|
||||
if(isNodeHigh(nodenames['sync']))
|
||||
machine3 += ' (Fetch: ' + busToString('Fetch') + ')';
|
||||
if(goldenChecksum != undefined)
|
||||
machine3 += " Chk:" + traceChecksum + ((traceChecksum==goldenChecksum)?" OK":" no match");
|
||||
}
|
||||
setStatus(machine1, machine2, machine3);
|
||||
if (logThese.length>1) {
|
||||
updateLogbox(logThese);
|
||||
}
|
||||
selectCell(ab);
|
||||
}
|
||||
|
||||
// run for an extended number of cycles, with low overhead, for interactive programs or for benchmarking
|
||||
// note: to run an interactive program, use an URL like
|
||||
// http://visual6502.org/JSSim/expert.html?graphics=f&loglevel=-1&headlesssteps=-500
|
||||
function goFor(){
|
||||
var n = headlessSteps; // a negative value is a request to free-run
|
||||
if(headlessSteps<0)
|
||||
n=-n;
|
||||
var start = document.getElementById('start');
|
||||
var stop = document.getElementById('stop');
|
||||
start.style.visibility = 'hidden';
|
||||
stop.style.visibility = 'visible';
|
||||
if(typeof running == "undefined") {
|
||||
initChip();
|
||||
}
|
||||
running = true;
|
||||
setTimeout("instantaneousHz(); goForN("+n+")",0);
|
||||
}
|
||||
|
||||
// helper function: allows us to poll 'running' without resetting it when we're re-scheduled
|
||||
function goForN(n){
|
||||
var n2=n; // save our parameter so we can re-submit ourselves
|
||||
while(n--){
|
||||
halfStep();
|
||||
cycle++;
|
||||
}
|
||||
instantaneousHz();
|
||||
chipStatus();
|
||||
if((headlessSteps<0) && running){
|
||||
setTimeout("goForN("+n2+")",0); // re-submit ourselves if we are meant to free-run
|
||||
return;
|
||||
}
|
||||
running = false;
|
||||
var start = document.getElementById('start');
|
||||
var stop = document.getElementById('stop');
|
||||
start.style.visibility = 'visible';
|
||||
stop.style.visibility = 'hidden';
|
||||
}
|
||||
|
||||
var prevHzTimeStamp=0;
|
||||
var prevHzCycleCount=0;
|
||||
var prevHzEstimate1=1;
|
||||
var prevHzEstimate2=1;
|
||||
var HzSamplingRate=10;
|
||||
|
||||
// return an averaged speed: called periodically during normal running
|
||||
function estimatedHz(){
|
||||
if(cycle%HzSamplingRate!=3)
|
||||
return prevHzEstimate1;
|
||||
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
|
||||
}
|
||||
|
||||
// return instantaneous speed: called twice, before and after a timed run using goFor()
|
||||
function instantaneousHz(){
|
||||
var HzTimeStamp = now();
|
||||
var HzEstimate = (cycle-prevHzCycleCount+.01)/(HzTimeStamp-prevHzTimeStamp+.01);
|
||||
HzEstimate=HzEstimate*1000/2; // convert from phases per millisecond to Hz
|
||||
prevHzEstimate1=HzEstimate;
|
||||
prevHzEstimate2=prevHzEstimate1;
|
||||
prevHzTimeStamp=HzTimeStamp;
|
||||
prevHzCycleCount=cycle;
|
||||
return prevHzEstimate1
|
||||
}
|
||||
|
||||
var logbox;
|
||||
function initLogbox(names){
|
||||
logbox=document.getElementById('logstream');
|
||||
if(logbox==null)return;
|
||||
|
||||
names=names.map(function(x){return x.replace(/^-/,'')});
|
||||
logStream = [];
|
||||
logStream.push("<td class=header>" + names.join("</td><td class=header>") + "</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(){
|
||||
var loglines=[];
|
||||
logboxAppend=!logboxAppend;
|
||||
// the first element is the header so we can't reverse()
|
||||
for (var i=1;i<logStream.length;i++) {
|
||||
loglines.unshift(logStream[i]);
|
||||
}
|
||||
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 signals=[];
|
||||
var odd=true;
|
||||
var bg;
|
||||
var row;
|
||||
|
||||
for(var i in names){
|
||||
if(cycle % 4 < 2){
|
||||
bg = odd ? " class=oddcol":"";
|
||||
} else {
|
||||
bg = odd ? " class=oddrow":" class=oddrowcol";
|
||||
}
|
||||
signals.push("<td" + bg + ">" + busToString(names[i]) + "</td>");
|
||||
odd =! odd;
|
||||
}
|
||||
row = "<tr>" + signals.join("") + "</tr>";
|
||||
if(logboxAppend)
|
||||
logStream.push(row);
|
||||
else
|
||||
logStream.splice(1,0,row);
|
||||
|
||||
logbox.innerHTML = logStream.join("");
|
||||
}
|
||||
|
||||
function getMem(){
|
||||
var res = Array();
|
||||
for(var i=0;i<0x200;i++) res.push(mRead(i));
|
||||
|
@ -293,3 +688,177 @@ function setMem(arr){
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
// sanitised opcode for HTML output
|
||||
function disassemblytoHTML(byte){
|
||||
var opcode=disassembly[byte];
|
||||
if(typeof opcode == "undefined")
|
||||
return "unknown"
|
||||
return opcode.replace(/ /,' ');
|
||||
}
|
||||
|
||||
// opcode lookup for 6502 - not quite a disassembly
|
||||
// javascript derived from Debugger.java by Achim Breidenbach
|
||||
var disassembly={
|
||||
0x00:"BRK",
|
||||
0x01:"ORA (zp,X)",
|
||||
0x05:"ORA zp",
|
||||
0x06:"ASL zp",
|
||||
0x08:"PHP",
|
||||
0x09:"ORA #",
|
||||
0x0A:"ASL ",
|
||||
0x0D:"ORA Abs",
|
||||
0x0E:"ASL Abs",
|
||||
0x10:"BPL ",
|
||||
0x11:"ORA (zp),Y",
|
||||
0x15:"ORA zp,X",
|
||||
0x16:"ASL zp,X",
|
||||
0x18:"CLC",
|
||||
0x19:"ORA Abs,Y",
|
||||
0x1D:"ORA Abs,X",
|
||||
0x1E:"ASL Abs,X",
|
||||
0x20:"JSR Abs",
|
||||
0x21:"AND (zp,X)",
|
||||
0x24:"BIT zp",
|
||||
0x25:"AND zp",
|
||||
0x26:"ROL zp",
|
||||
0x28:"PLP",
|
||||
0x29:"AND #",
|
||||
0x2A:"ROL ",
|
||||
0x2C:"BIT Abs",
|
||||
0x2D:"AND Abs",
|
||||
0x2E:"ROL Abs",
|
||||
0x30:"BMI ",
|
||||
0x31:"AND (zp),Y",
|
||||
0x35:"AND zp,X",
|
||||
0x36:"ROL zp,X",
|
||||
0x38:"SEC",
|
||||
0x39:"AND Abs,Y",
|
||||
0x3D:"AND Abs,X",
|
||||
0x3E:"ROL Abs,X",
|
||||
0x40:"RTI",
|
||||
0x41:"EOR (zp,X)",
|
||||
0x45:"EOR zp",
|
||||
0x46:"LSR zp",
|
||||
0x48:"PHA",
|
||||
0x49:"EOR #",
|
||||
0x4A:"LSR ",
|
||||
0x4C:"JMP Abs",
|
||||
0x4D:"EOR Abs",
|
||||
0x4E:"LSR Abs",
|
||||
0x50:"BVC ",
|
||||
0x51:"EOR (zp),Y",
|
||||
0x55:"EOR zp,X",
|
||||
0x56:"LSR zp,X",
|
||||
0x58:"CLI",
|
||||
0x59:"EOR Abs,Y",
|
||||
0x5D:"EOR Abs,X",
|
||||
0x5E:"LSR Abs,X",
|
||||
0x60:"RTS",
|
||||
0x61:"ADC (zp,X)",
|
||||
0x65:"ADC zp",
|
||||
0x66:"ROR zp",
|
||||
0x68:"PLA",
|
||||
0x69:"ADC #",
|
||||
0x6A:"ROR ",
|
||||
0x6C:"JMP (Abs)",
|
||||
0x6D:"ADC Abs",
|
||||
0x6E:"ROR Abs",
|
||||
0x70:"BVS ",
|
||||
0x71:"ADC (zp),Y",
|
||||
0x75:"ADC zp,X",
|
||||
0x76:"ROR zp,X",
|
||||
0x78:"SEI",
|
||||
0x79:"ADC Abs,Y",
|
||||
0x7D:"ADC Abs,X",
|
||||
0x7E:"ROR Abs,X",
|
||||
0x81:"STA (zp,X)",
|
||||
0x84:"STY zp",
|
||||
0x85:"STA zp",
|
||||
0x86:"STX zp",
|
||||
0x88:"DEY",
|
||||
0x8A:"TXA",
|
||||
0x8C:"STY Abs",
|
||||
0x8D:"STA Abs",
|
||||
0x8E:"STX Abs",
|
||||
0x90:"BCC ",
|
||||
0x91:"STA (zp),Y",
|
||||
0x94:"STY zp,X",
|
||||
0x95:"STA zp,X",
|
||||
0x96:"STX zp,Y",
|
||||
0x98:"TYA",
|
||||
0x99:"STA Abs,Y",
|
||||
0x9A:"TXS",
|
||||
0x9D:"STA Abs,X",
|
||||
0xA0:"LDY #",
|
||||
0xA1:"LDA (zp,X)",
|
||||
0xA2:"LDX #",
|
||||
0xA4:"LDY zp",
|
||||
0xA5:"LDA zp",
|
||||
0xA6:"LDX zp",
|
||||
0xA8:"TAY",
|
||||
0xA9:"LDA #",
|
||||
0xAA:"TAX",
|
||||
0xAC:"LDY Abs",
|
||||
0xAD:"LDA Abs",
|
||||
0xAE:"LDX Abs",
|
||||
0xB0:"BCS ",
|
||||
0xB1:"LDA (zp),Y",
|
||||
0xB4:"LDY zp,X",
|
||||
0xB5:"LDA zp,X",
|
||||
0xB6:"LDX zp,Y",
|
||||
0xB8:"CLV",
|
||||
0xB9:"LDA Abs,Y",
|
||||
0xBA:"TSX",
|
||||
0xBC:"LDY Abs,X",
|
||||
0xBD:"LDA Abs,X",
|
||||
0xBE:"LDX Abs,Y",
|
||||
0xC0:"CPY #",
|
||||
0xC1:"CMP (zp,X)",
|
||||
0xC4:"CPY zp",
|
||||
0xC5:"CMP zp",
|
||||
0xC6:"DEC zp",
|
||||
0xC8:"INY",
|
||||
0xC9:"CMP #",
|
||||
0xCA:"DEX",
|
||||
0xCC:"CPY Abs",
|
||||
0xCD:"CMP Abs",
|
||||
0xCE:"DEC Abs",
|
||||
0xD0:"BNE ",
|
||||
0xD1:"CMP (zp),Y",
|
||||
0xD5:"CMP zp,X",
|
||||
0xD6:"DEC zp,X",
|
||||
0xD8:"CLD",
|
||||
0xD9:"CMP Abs,Y",
|
||||
0xDD:"CMP Abs,X",
|
||||
0xDE:"DEC Abs,X",
|
||||
0xE0:"CPX #",
|
||||
0xE1:"SBC (zp,X)",
|
||||
0xE4:"CPX zp",
|
||||
0xE5:"SBC zp",
|
||||
0xE6:"INC zp",
|
||||
0xE8:"INX",
|
||||
0xE9:"SBC #",
|
||||
0xEA:"NOP",
|
||||
0xEC:"CPX Abs",
|
||||
0xED:"SBC Abs",
|
||||
0xEE:"INC Abs",
|
||||
0xF0:"BEQ ",
|
||||
0xF1:"SBC (zp),Y",
|
||||
0xF5:"SBC zp,X",
|
||||
0xF6:"INC zp,X",
|
||||
0xF8:"SED",
|
||||
0xF9:"SBC Abs,Y",
|
||||
0xFD:"SBC Abs,X",
|
||||
0xFE:"INC Abs,X",
|
||||
};
|
||||
|
|
|
@ -59,7 +59,9 @@ function cellKeydown(e){
|
|||
}
|
||||
|
||||
function setCellValue(n, val){
|
||||
val%=256;
|
||||
if(val==undefined)
|
||||
val=0x00;
|
||||
val%=256;
|
||||
cellEl(n).val=val;
|
||||
cellEl(n).innerHTML=hexByte(val);
|
||||
}
|
||||
|
@ -71,7 +73,7 @@ function selectCell(n){
|
|||
if(n>=0x200) return;
|
||||
cellEl(n).style.background = '#ff8';
|
||||
selected = n;
|
||||
window.onkeydown = function(e){cellKeydown(e);};
|
||||
table.onkeydown = function(e){cellKeydown(e);};
|
||||
}
|
||||
|
||||
function unselectCell(){
|
||||
|
@ -84,6 +86,6 @@ function unselectCell(){
|
|||
function cellEl(n){
|
||||
var r = n>>4;
|
||||
var c = n%16;
|
||||
var e = table.children[r].children[c+1];
|
||||
var e = table.childNodes[r].childNodes[c+1];
|
||||
return e;
|
||||
}
|
||||
|
|
1022
nodenames.js
18
save.php
|
@ -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;
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// 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;
|
||||
|
||||
// we want to auto-clear the console if any output is sent by the program
|
||||
var consoleboxStream="";
|
||||
|
||||
// demonstrate write hook
|
||||
writeTriggers[0x000F]="consoleboxStream += String.fromCharCode(d);"+
|
||||
"consolebox.innerHTML = consoleboxStream;";
|
||||
|
||||
// demonstrate read hook (not used by this test program)
|
||||
readTriggers[0xD011]="((consolegetc==undefined)?0:0xff)"; // return zero until we have a char
|
||||
readTriggers[0xD010]="var c=consolegetc; consolegetc=undefined; (c)";
|
||||
|
||||
testprogram = [
|
||||
0xa9, 0x00, // LDA #$00
|
||||
0x20, 0x10, 0x00, // JSR $0010
|
||||
0x4c, 0x02, 0x00, // JMP $0002
|
||||
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x40,
|
||||
|
||||
0xe8, // INX
|
||||
0x88, // DEY
|
||||
0xe6, 0x0F, // INC $0F
|
||||
0x38, // SEC
|
||||
0x69, 0x02, // ADC #$02
|
||||
0x60 // RTS
|
||||
];
|
7031
transdefs.js
288
wires.js
|
@ -21,61 +21,15 @@
|
|||
*/
|
||||
|
||||
var frame, chipbg, overlay, hilite, hitbuffer, ctx;
|
||||
var centerx=300, centery=300;
|
||||
var zoom=1;
|
||||
var dragMouseX, dragMouseY, moved;
|
||||
var statbox;
|
||||
|
||||
// Index of layerNames corresponds to index into drawLayers
|
||||
var layernames = ['metal', 'switched diffusion', 'inputdiode', 'grounded diffusion', 'powered diffusion', 'polysilicon'];
|
||||
var colors = ['rgba(128,128,192,0.4)','#FFFF00','#FF00FF','#4DFF4D',
|
||||
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
|
||||
var drawlayers = [true, true, true, true, true, true];
|
||||
|
||||
var nodes = new Array();
|
||||
var transistors = {};
|
||||
var nodenamelist=[];
|
||||
|
||||
var ngnd = nodenames['vss'];
|
||||
var npwr = nodenames['vcc'];
|
||||
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Drawing Setup
|
||||
//
|
||||
/////////////////////////
|
||||
|
||||
// try to present a meaningful page before starting expensive work
|
||||
function setup(){
|
||||
statbox = document.getElementById('status');
|
||||
setStatus('loading 6502...');
|
||||
setTimeout(setup_part2, 0);
|
||||
}
|
||||
|
||||
function setup_part2(){
|
||||
frame = document.getElementById('frame');
|
||||
statbox = document.getElementById('status');
|
||||
setupNodes();
|
||||
setupTransistors();
|
||||
setupLayerVisibility();
|
||||
setupBackground();
|
||||
setupOverlay();
|
||||
setupHilite();
|
||||
setupHitBuffer();
|
||||
recenter();
|
||||
refresh();
|
||||
setupTable();
|
||||
window.onkeypress = function(e){handleKey(e);}
|
||||
hilite.onmousedown = function(e){mouseDown(e);}
|
||||
setStatus('resetting 6502...');
|
||||
setTimeout(setup_part3, 0);
|
||||
}
|
||||
|
||||
function setup_part3(){
|
||||
initChip();
|
||||
document.getElementById('stop').style.visibility = 'hidden';
|
||||
go();
|
||||
}
|
||||
var chipLayoutIsVisible = true; // only modified in expert mode
|
||||
var hilited = [];
|
||||
|
||||
function setupNodes(){
|
||||
for(var i in segdefs){
|
||||
|
@ -83,7 +37,7 @@ function setupNodes(){
|
|||
var w = seg[0];
|
||||
if(nodes[w]==undefined)
|
||||
nodes[w] = {segs: new Array(), num: w, pullup: seg[1]=='+',
|
||||
state: 'fl', gates: new Array(), c1c2s: new Array()};
|
||||
state: false, gates: new Array(), c1c2s: new Array()};
|
||||
if(w==ngnd) continue;
|
||||
if(w==npwr) continue;
|
||||
nodes[w].segs.push(seg.slice(3));
|
||||
|
@ -97,10 +51,13 @@ function setupTransistors(){
|
|||
var gate = tdef[1];
|
||||
var c1 = tdef[2];
|
||||
var c2 = tdef[3];
|
||||
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2};
|
||||
nodes[gate].gates.push(name);
|
||||
nodes[c1].c1c2s.push(name);
|
||||
nodes[c2].c1c2s.push(name);
|
||||
var bb = tdef[4];
|
||||
if(c1==ngnd) {c1=c2;c2=ngnd;}
|
||||
if(c1==npwr) {c1=c2;c2=npwr;}
|
||||
var trans = {name: name, on: false, gate: gate, c1: c1, c2: c2, bb: bb};
|
||||
nodes[gate].gates.push(trans);
|
||||
nodes[c1].c1c2s.push(trans);
|
||||
nodes[c2].c1c2s.push(trans);
|
||||
transistors[name] = trans;
|
||||
}
|
||||
}
|
||||
|
@ -116,14 +73,13 @@ function setupLayerVisibility(){
|
|||
|
||||
function setupBackground(){
|
||||
chipbg = document.getElementById('chipbg');
|
||||
chipbg.width = 4000;
|
||||
chipbg.height = 4000;
|
||||
chipbg.width = grCanvasSize;
|
||||
chipbg.height = grCanvasSize;
|
||||
var ctx = chipbg.getContext('2d');
|
||||
ctx.scale(chipbg.width/10000, chipbg.height/10000);
|
||||
ctx.fillStyle = '#000000';
|
||||
ctx.strokeStyle = 'rgba(255,255,255,0.5)';
|
||||
ctx.lineWidth = 4;
|
||||
ctx.fillRect(0,0,10000,10000);
|
||||
ctx.lineWidth = grLineWidth;
|
||||
ctx.fillRect(0,0,grCanvasSize,grCanvasSize);
|
||||
for(var i in segdefs){
|
||||
var seg = segdefs[i];
|
||||
var c = seg[2];
|
||||
|
@ -138,27 +94,24 @@ function setupBackground(){
|
|||
|
||||
function setupOverlay(){
|
||||
overlay = document.getElementById('overlay');
|
||||
overlay.width = 4000;
|
||||
overlay.height = 4000;
|
||||
overlay.width = grCanvasSize;
|
||||
overlay.height = grCanvasSize;
|
||||
ctx = overlay.getContext('2d');
|
||||
ctx.scale(overlay.width/10000, overlay.height/10000);
|
||||
}
|
||||
|
||||
function setupHilite(){
|
||||
hilite = document.getElementById('hilite');
|
||||
hilite.width = 4000;
|
||||
hilite.height = 4000;
|
||||
hilite.width = grCanvasSize;
|
||||
hilite.height = grCanvasSize;
|
||||
var ctx = hilite.getContext('2d');
|
||||
ctx.scale(hilite.width/10000, hilite.height/10000);
|
||||
}
|
||||
|
||||
function setupHitBuffer(){
|
||||
hitbuffer = document.getElementById('hitbuffer');
|
||||
hitbuffer.width = 4000;
|
||||
hitbuffer.height = 4000;
|
||||
hitbuffer.width = grCanvasSize;
|
||||
hitbuffer.height = grCanvasSize;
|
||||
hitbuffer.style.visibility = 'hidden';
|
||||
var ctx = hitbuffer.getContext('2d');
|
||||
ctx.scale(hitbuffer.width/10000, hitbuffer.height/10000);
|
||||
for(i in nodes) hitBufferNode(ctx, i, nodes[i].segs);
|
||||
}
|
||||
|
||||
|
@ -183,10 +136,12 @@ function hexdigit(n){return '0123456789ABCDEF'.charAt(n);}
|
|||
/////////////////////////
|
||||
|
||||
function refresh(){
|
||||
ctx.clearRect(0,0,10000,10000);
|
||||
if(!chipLayoutIsVisible) return;
|
||||
ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
|
||||
for(i in nodes){
|
||||
if(isNodeHigh(i)) overlayNode(nodes[i].segs);
|
||||
}
|
||||
hiliteNode(hilited);
|
||||
}
|
||||
|
||||
function overlayNode(w){
|
||||
|
@ -197,115 +152,90 @@ function overlayNode(w){
|
|||
}
|
||||
}
|
||||
|
||||
// originally to highlight using a list of node numbers
|
||||
// but can now include transistor names
|
||||
function hiliteNode(n){
|
||||
var ctx = hilite.getContext('2d');
|
||||
ctx.clearRect(0,0,10000,10000);
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.7)';
|
||||
ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
|
||||
if(n==-1) return;
|
||||
if(isNodeHigh(n[0]))
|
||||
ctx.fillStyle = 'rgba(255,0,0,0.7)';
|
||||
hilited = n;
|
||||
|
||||
for(var i in n){
|
||||
if(typeof n[i] != "number") {
|
||||
hiliteTrans([n[i]]);
|
||||
continue;
|
||||
}
|
||||
if(isNodeHigh(n[i])) {
|
||||
ctx.fillStyle = 'rgba(255,0,0,0.7)';
|
||||
} else {
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.7)';
|
||||
}
|
||||
var segs = nodes[n[i]].segs;
|
||||
for(var s in segs){drawSeg(ctx, segs[s]); ctx.fill();}
|
||||
}
|
||||
}
|
||||
|
||||
// highlight a single transistor (additively - does not clear highlighting)
|
||||
function hiliteTrans(n){
|
||||
var ctx = hilite.getContext('2d');
|
||||
ctx.strokeStyle = 'rgba(255,255,255,0.7)';
|
||||
ctx.lineWidth = 4
|
||||
for(var t in n){
|
||||
var bb = transistors[n[t]].bb
|
||||
var segs = [[bb[0], bb[2], bb[1], bb[2], bb[1], bb[3], bb[0], bb[3]]]
|
||||
for(var s in segs){drawSeg(ctx, segs[s]); ctx.stroke();}
|
||||
}
|
||||
}
|
||||
|
||||
function ctxDrawBox(ctx, xMin, yMin, xMax, yMax){
|
||||
var cap=ctx.lineCap;
|
||||
ctx.lineCap="square";
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(xMin, yMin);
|
||||
ctx.lineTo(xMin, yMax);
|
||||
ctx.lineTo(xMax, yMax);
|
||||
ctx.lineTo(xMax, yMin);
|
||||
ctx.lineTo(xMin, yMin);
|
||||
ctx.stroke();
|
||||
ctx.lineCap=cap;
|
||||
}
|
||||
|
||||
// takes a bounding box in chip coords and centres the display over it
|
||||
function zoomToBox(xmin,xmax,ymin,ymax){
|
||||
var xmid=(xmin+xmax)/2;
|
||||
var ymid=(ymin+ymax)/2;
|
||||
var x=(xmid+grChipOffsetX)/grChipSize*600;
|
||||
var y=600-(ymid-grChipOffsetY)/grChipSize*600;
|
||||
// Zoom to fill 80% of the window with the selection
|
||||
var fillfactor=0.80;
|
||||
var dx=xmax-xmin;
|
||||
var dy=ymax-ymin;
|
||||
if (dx < 1) dx=1;
|
||||
if (dy < 1) dy=1;
|
||||
var zx=(800/600)*fillfactor*grChipSize/dx;
|
||||
var zy=fillfactor*grChipSize/dy;
|
||||
var zoom=Math.min(zx,zy);
|
||||
if (zoom < 1) {
|
||||
zoom = 1;
|
||||
}
|
||||
if (zoom > grMaxZoom) {
|
||||
zoom = grMaxZoom;
|
||||
}
|
||||
moveHere([x,y,zoom]);
|
||||
}
|
||||
|
||||
function drawSeg(ctx, seg){
|
||||
if(noGraphics) return;
|
||||
var dx = 400;
|
||||
var dx = grChipOffsetX;
|
||||
var dy = grChipOffsetY;
|
||||
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]);
|
||||
ctx.lineTo(seg[0]+dx, 10000-seg[1])
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// User Interface
|
||||
//
|
||||
/////////////////////////
|
||||
|
||||
function handleKey(e){
|
||||
var c = e.charCode;
|
||||
c = String.fromCharCode(c);
|
||||
if('<>?np'.indexOf(c)==-1) return;
|
||||
if(c=='<' && zoom>1) setZoom(zoom/1.2);
|
||||
else if(c=='>' && zoom<16) 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*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));}
|
||||
ctx.moveTo(grScale(seg[0]+dx), grScale(grChipSize-seg[1]+dy));
|
||||
for(var i=2;i<seg.length;i+=2) ctx.lineTo(grScale(seg[i]+dx), grScale(grChipSize-seg[i+1]+dy));
|
||||
ctx.lineTo(grScale(seg[0]+dx), grScale(grChipSize-seg[1]+dy));
|
||||
}
|
||||
|
||||
function findNodeNumber(x,y){
|
||||
var ctx = hitbuffer.getContext('2d');
|
||||
var pixels = ctx.getImageData(x*4000/600, y*4000/600, 2, 2).data;
|
||||
var pixels = ctx.getImageData(x*grCanvasSize/600, y*grCanvasSize/600, 2, 2).data;
|
||||
if(pixels[0]==0) return -1;
|
||||
var high = pixels[0]>>4;
|
||||
var mid = pixels[1]>>4;
|
||||
|
@ -313,27 +243,23 @@ function findNodeNumber(x,y){
|
|||
return (high<<8)+(mid<<4)+low;
|
||||
}
|
||||
|
||||
function clearHighlight(){
|
||||
// remove red/white overlay according to logic value
|
||||
// for easier layout navigation
|
||||
ctx.clearRect(0,0,grCanvasSize,grCanvasSize);
|
||||
}
|
||||
|
||||
function updateShow(layer, on){
|
||||
drawlayers[layer]=on;
|
||||
setupBackground();
|
||||
}
|
||||
|
||||
/////////////////////////
|
||||
//
|
||||
// Etc.
|
||||
//
|
||||
/////////////////////////
|
||||
|
||||
function setChipStyle(props){
|
||||
for(var i in props){
|
||||
chipbg.style[i] = props[i];
|
||||
overlay.style[i] = props[i];
|
||||
hilite.style[i] = props[i];
|
||||
hitbuffer.style[i] = props[i];
|
||||
}
|
||||
// we draw the chip data scaled down to the canvas
|
||||
// and so avoid scaling a large canvas
|
||||
function grScale(x){
|
||||
return Math.round(x*grCanvasSize/grChipSize);
|
||||
}
|
||||
|
||||
|
||||
function localx(el, gx){
|
||||
return gx-el.getBoundingClientRect().left;
|
||||
}
|
||||
|
@ -344,10 +270,20 @@ function localy(el, gy){
|
|||
|
||||
function setStatus(){
|
||||
var res = '';
|
||||
for(var i=0;i<arguments.length;i++) res=res+arguments[i]+' ';
|
||||
// pad the arguments to make this a three-line display
|
||||
// there must be a clean way to do this
|
||||
if(arguments[1]==undefined)arguments[1]="";
|
||||
if(arguments[2]==undefined)arguments[2]="";
|
||||
arguments.length=3;
|
||||
for(var i=0;i<arguments.length;i++) res=res+arguments[i]+'<br>';
|
||||
statbox.innerHTML = res;
|
||||
}
|
||||
|
||||
function setupNodeNameList(){
|
||||
for(var i in nodenames)
|
||||
nodenamelist.push(i);
|
||||
}
|
||||
|
||||
function nodeName(n) {
|
||||
for(var i in nodenames){
|
||||
if(nodenames[i]==n) return i;
|
||||
|
|