├── .gitattributes ├── .gitignore ├── 3rdparty ├── img │ ├── hgrabber.gif │ ├── vdockbar.gif │ ├── vgrabber.gif │ ├── vgrabber2-active.gif │ └── vgrabber2-normal.gif ├── jquery-1.3.2.min.js ├── jquery.cookie.js └── splitter.js ├── README ├── browsertrouble.html ├── chip-6800 ├── nodenames.js ├── segdefs.js ├── support.js ├── testprogram.js └── transdefs.js ├── chip-z80 ├── nodenames.js ├── segdefs.js ├── support.js ├── testprogram.js └── transdefs.js ├── chipsim.js ├── expert-6800.html ├── expert-allinone.js ├── expert-z80.html ├── expert.css ├── expert.html ├── expertWires.js ├── images ├── fastforward.png ├── jssim2.png ├── next.png ├── play.png ├── prev.png ├── singlestep.png ├── stop.png └── up.png ├── index.html ├── kiosk.css ├── kioskWires.js ├── macros.js ├── memtable.js ├── nodenames.js ├── segdefs.js ├── testprogram.js ├── transdefs.js └── wires.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.js text 3 | *.css text 4 | *.html text 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # emacs-style backup files 2 | *~ 3 | # patch detritus 4 | *.orig 5 | *.rej 6 | -------------------------------------------------------------------------------- /3rdparty/img/hgrabber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trebonian/visual6502/d8ecc129b34e0eaf320e0400fcf33329475bdb1e/3rdparty/img/hgrabber.gif -------------------------------------------------------------------------------- /3rdparty/img/vdockbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trebonian/visual6502/d8ecc129b34e0eaf320e0400fcf33329475bdb1e/3rdparty/img/vdockbar.gif -------------------------------------------------------------------------------- /3rdparty/img/vgrabber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trebonian/visual6502/d8ecc129b34e0eaf320e0400fcf33329475bdb1e/3rdparty/img/vgrabber.gif -------------------------------------------------------------------------------- /3rdparty/img/vgrabber2-active.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trebonian/visual6502/d8ecc129b34e0eaf320e0400fcf33329475bdb1e/3rdparty/img/vgrabber2-active.gif -------------------------------------------------------------------------------- /3rdparty/img/vgrabber2-normal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trebonian/visual6502/d8ecc129b34e0eaf320e0400fcf33329475bdb1e/3rdparty/img/vgrabber2-normal.gif -------------------------------------------------------------------------------- /3rdparty/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Cookie plugin 3 | * 4 | * Copyright (c) 2006 Klaus Hartl (stilbuero.de) 5 | * Dual licensed under the MIT and GPL licenses: 6 | * http://www.opensource.org/licenses/mit-license.php 7 | * http://www.gnu.org/licenses/gpl.html 8 | * 9 | */ 10 | 11 | /** 12 | * Create a cookie with the given name and value and other optional parameters. 13 | * 14 | * @example $.cookie('the_cookie', 'the_value'); 15 | * @desc Set the value of a cookie. 16 | * @example $.cookie('the_cookie', 'the_value', {expires: 7, path: '/', domain: 'jquery.com', secure: true}); 17 | * @desc Create a cookie with all available options. 18 | * @example $.cookie('the_cookie', 'the_value'); 19 | * @desc Create a session cookie. 20 | * @example $.cookie('the_cookie', null); 21 | * @desc Delete a cookie by passing null as value. 22 | * 23 | * @param String name The name of the cookie. 24 | * @param String value The value of the cookie. 25 | * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. 26 | * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. 27 | * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. 28 | * If set to null or omitted, the cookie will be a session cookie and will not be retained 29 | * when the the browser exits. 30 | * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). 31 | * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). 32 | * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will 33 | * require a secure protocol (like HTTPS). 34 | * @type undefined 35 | * 36 | * @name $.cookie 37 | * @cat Plugins/Cookie 38 | * @author Klaus Hartl/klaus.hartl@stilbuero.de 39 | */ 40 | 41 | /** 42 | * Get the value of a cookie with the given name. 43 | * 44 | * @example $.cookie('the_cookie'); 45 | * @desc Get the value of a cookie. 46 | * 47 | * @param String name The name of the cookie. 48 | * @return The value of the cookie. 49 | * @type String 50 | * 51 | * @name $.cookie 52 | * @cat Plugins/Cookie 53 | * @author Klaus Hartl/klaus.hartl@stilbuero.de 54 | */ 55 | jQuery.cookie = function(name, value, options) { 56 | if (typeof value != 'undefined') { // name and value given, set cookie 57 | options = options || {}; 58 | if (value === null) { 59 | value = ''; 60 | options.expires = -1; 61 | } 62 | var expires = ''; 63 | if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { 64 | var date; 65 | if (typeof options.expires == 'number') { 66 | date = new Date(); 67 | date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); 68 | } else { 69 | date = options.expires; 70 | } 71 | expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE 72 | } 73 | var path = options.path ? '; path=' + options.path : ''; 74 | var domain = options.domain ? '; domain=' + options.domain : ''; 75 | var secure = options.secure ? '; secure' : ''; 76 | document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); 77 | } else { // only name given, get cookie 78 | var cookieValue = null; 79 | if (document.cookie && document.cookie != '') { 80 | var cookies = document.cookie.split(';'); 81 | for (var i = 0; i < cookies.length; i++) { 82 | var cookie = jQuery.trim(cookies[i]); 83 | // Does this cookie string begin with the name we want? 84 | if (cookie.substring(0, name.length + 1) == (name + '=')) { 85 | cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 86 | break; 87 | } 88 | } 89 | } 90 | return cookieValue; 91 | } 92 | }; -------------------------------------------------------------------------------- /3rdparty/splitter.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery.splitter.js - two-pane splitter window plugin 3 | * 4 | * version 1.51 (2009/01/09) 5 | * 6 | * Dual licensed under the MIT and GPL licenses: 7 | * http://www.opensource.org/licenses/mit-license.php 8 | * http://www.gnu.org/licenses/gpl.html 9 | */ 10 | 11 | /** 12 | * The splitter() plugin implements a two-pane resizable splitter window. 13 | * The selected elements in the jQuery object are converted to a splitter; 14 | * each selected element should have two child elements, used for the panes 15 | * of the splitter. The plugin adds a third child element for the splitbar. 16 | * 17 | * For more details see: http://methvin.com/splitter/ 18 | * 19 | * 20 | * @example $('#MySplitter').splitter(); 21 | * @desc Create a vertical splitter with default settings 22 | * 23 | * @example $('#MySplitter').splitter({type: 'h', accessKey: 'M'}); 24 | * @desc Create a horizontal splitter resizable via Alt+Shift+M 25 | * 26 | * @name splitter 27 | * @type jQuery 28 | * @param Object options Options for the splitter (not required) 29 | * @cat Plugins/Splitter 30 | * @return jQuery 31 | * @author Dave Methvin (dave.methvin@gmail.com) 32 | */ 33 | ;(function($){ 34 | 35 | $.fn.splitter = function(args){ 36 | args = args || {}; 37 | return this.each(function() { 38 | var zombie; // left-behind splitbar for outline resizes 39 | function startSplitMouse(evt) { 40 | if ( opts.outline ) 41 | zombie = zombie || bar.clone(false).insertAfter(A); 42 | panes.css("-webkit-user-select", "none"); // Safari selects A/B text on a move 43 | bar.addClass(opts.activeClass); 44 | A._posSplit = A[0][opts.pxSplit] - evt[opts.eventPos]; 45 | $(document) 46 | .bind("mousemove", doSplitMouse) 47 | .bind("mouseup", endSplitMouse); 48 | } 49 | function doSplitMouse(evt) { 50 | var newPos = A._posSplit+evt[opts.eventPos]; 51 | if ( opts.outline ) { 52 | newPos = Math.max(0, Math.min(newPos, splitter._DA - bar._DA)); 53 | bar.css(opts.origin, newPos); 54 | } else 55 | resplit(newPos); 56 | } 57 | function endSplitMouse(evt) { 58 | bar.removeClass(opts.activeClass); 59 | var newPos = A._posSplit+evt[opts.eventPos]; 60 | if ( opts.outline ) { 61 | zombie.remove(); zombie = null; 62 | resplit(newPos); 63 | } 64 | panes.css("-webkit-user-select", "text"); // let Safari select text again 65 | $(document) 66 | .unbind("mousemove", doSplitMouse) 67 | .unbind("mouseup", endSplitMouse); 68 | } 69 | function resplit(newPos) { 70 | // Constrain new splitbar position to fit pane size limits 71 | newPos = Math.max(A._min, splitter._DA - B._max, 72 | Math.min(newPos, A._max, splitter._DA - bar._DA - B._min)); 73 | // Resize/position the two panes 74 | bar._DA = bar[0][opts.pxSplit]; // bar size may change during dock 75 | bar.css(opts.origin, newPos).css(opts.fixed, splitter._DF); 76 | A.css(opts.origin, 0).css(opts.split, newPos).css(opts.fixed, splitter._DF); 77 | B.css(opts.origin, newPos+bar._DA) 78 | .css(opts.split, splitter._DA-bar._DA-newPos).css(opts.fixed, splitter._DF); 79 | // IE fires resize for us; all others pay cash 80 | if ( !$.browser.msie ) 81 | panes.trigger("resize"); 82 | } 83 | function dimSum(jq, dims) { 84 | // Opera returns -1 for missing min/max width, turn into 0 85 | var sum = 0; 86 | for ( var i=1; i < arguments.length; i++ ) 87 | sum += Math.max(parseInt(jq.css(arguments[i])) || 0, 0); 88 | return sum; 89 | } 90 | 91 | // Determine settings based on incoming opts, element classes, and defaults 92 | var vh = (args.splitHorizontal? 'h' : args.splitVertical? 'v' : args.type) || 'v'; 93 | var opts = $.extend({ 94 | activeClass: 'active', // class name for active splitter 95 | pxPerKey: 8, // splitter px moved per keypress 96 | tabIndex: 0, // tab order indicator 97 | accessKey: '' // accessKey for splitbar 98 | },{ 99 | v: { // Vertical splitters: 100 | keyLeft: 39, keyRight: 37, cursor: "e-resize", 101 | splitbarClass: "vsplitbar", outlineClass: "voutline", 102 | type: 'v', eventPos: "pageX", origin: "left", 103 | split: "width", pxSplit: "offsetWidth", side1: "Left", side2: "Right", 104 | fixed: "height", pxFixed: "offsetHeight", side3: "Top", side4: "Bottom" 105 | }, 106 | h: { // Horizontal splitters: 107 | keyTop: 40, keyBottom: 38, cursor: "n-resize", 108 | splitbarClass: "hsplitbar", outlineClass: "houtline", 109 | type: 'h', eventPos: "pageY", origin: "top", 110 | split: "height", pxSplit: "offsetHeight", side1: "Top", side2: "Bottom", 111 | fixed: "width", pxFixed: "offsetWidth", side3: "Left", side4: "Right" 112 | } 113 | }[vh], args); 114 | 115 | // Create jQuery object closures for splitter and both panes 116 | var splitter = $(this).css({position: "relative"}); 117 | var panes = $(">*", splitter[0]).css({ 118 | position: "absolute", // positioned inside splitter container 119 | "z-index": "1", // splitbar is positioned above 120 | "-moz-outline-style": "none" // don't show dotted outline 121 | }); 122 | var A = $(panes[0]); // left or top 123 | var B = $(panes[1]); // right or bottom 124 | 125 | // Focuser element, provides keyboard support; title is shown by Opera accessKeys 126 | var focuser = $('') 127 | .attr({accessKey: opts.accessKey, tabIndex: opts.tabIndex, title: opts.splitbarClass}) 128 | .bind($.browser.opera?"click":"focus", function(){ this.focus(); bar.addClass(opts.activeClass) }) 129 | .bind("keydown", function(e){ 130 | var key = e.which || e.keyCode; 131 | var dir = key==opts["key"+opts.side1]? 1 : key==opts["key"+opts.side2]? -1 : 0; 132 | if ( dir ) 133 | resplit(A[0][opts.pxSplit]+dir*opts.pxPerKey, false); 134 | }) 135 | .bind("blur", function(){ bar.removeClass(opts.activeClass) }); 136 | 137 | // Splitbar element, can be already in the doc or we create one 138 | var bar = $(panes[2] || '
') 139 | .insertAfter(A).css("z-index", "100").append(focuser) 140 | .attr({"class": opts.splitbarClass, unselectable: "on"}) 141 | .css({position: "absolute", "user-select": "none", "-webkit-user-select": "none", 142 | "-khtml-user-select": "none", "-moz-user-select": "none"}) 143 | .bind("mousedown", startSplitMouse); 144 | // Use our cursor unless the style specifies a non-default cursor 145 | if ( /^(auto|default|)$/.test(bar.css("cursor")) ) 146 | bar.css("cursor", opts.cursor); 147 | 148 | // Cache several dimensions for speed, rather than re-querying constantly 149 | bar._DA = bar[0][opts.pxSplit]; 150 | splitter._PBF = $.boxModel? dimSum(splitter, "border"+opts.side3+"Width", "border"+opts.side4+"Width") : 0; 151 | splitter._PBA = $.boxModel? dimSum(splitter, "border"+opts.side1+"Width", "border"+opts.side2+"Width") : 0; 152 | A._pane = opts.side1; 153 | B._pane = opts.side2; 154 | $.each([A,B], function(){ 155 | this._min = opts["min"+this._pane] || dimSum(this, "min-"+opts.split); 156 | this._max = opts["max"+this._pane] || dimSum(this, "max-"+opts.split) || 9999; 157 | this._init = opts["size"+this._pane]===true ? 158 | parseInt($.curCSS(this[0],opts.split)) : opts["size"+this._pane]; 159 | }); 160 | 161 | // Determine initial position, get from cookie if specified 162 | var initPos = A._init; 163 | if ( !isNaN(B._init) ) // recalc initial B size as an offset from the top or left side 164 | initPos = splitter[0][opts.pxSplit] - splitter._PBA - B._init - bar._DA; 165 | if ( opts.cookie ) { 166 | if ( !$.cookie ) 167 | alert('jQuery.splitter(): jQuery cookie plugin required'); 168 | var ckpos = parseInt($.cookie(opts.cookie)); 169 | if ( !isNaN(ckpos) ) 170 | initPos = ckpos; 171 | $(window).bind("unload", function(){ 172 | var state = String(bar.css(opts.origin)); // current location of splitbar 173 | $.cookie(opts.cookie, state, {expires: opts.cookieExpires || 365, 174 | path: opts.cookiePath || document.location.pathname}); 175 | }); 176 | } 177 | if ( isNaN(initPos) ) // King Solomon's algorithm 178 | initPos = Math.round((splitter[0][opts.pxSplit] - splitter._PBA - bar._DA)/2); 179 | 180 | // Resize event propagation and splitter sizing 181 | if ( opts.anchorToWindow ) { 182 | // Account for margin or border on the splitter container and enforce min height 183 | splitter._hadjust = dimSum(splitter, "borderTopWidth", "borderBottomWidth", "marginBottom"); 184 | splitter._hmin = Math.max(dimSum(splitter, "minHeight"), 20); 185 | $(window).bind("resize", function(){ 186 | var top = splitter.offset().top; 187 | var wh = $(window).height(); 188 | splitter.css("height", Math.max(wh-top-splitter._hadjust, splitter._hmin)+"px"); 189 | if ( !$.browser.msie ) splitter.trigger("resize"); 190 | }).trigger("resize"); 191 | } 192 | else if ( opts.resizeToWidth && !$.browser.msie ) 193 | $(window).bind("resize", function(){ 194 | splitter.trigger("resize"); 195 | }); 196 | 197 | // Resize event handler; triggered immediately to set initial position 198 | splitter.bind("resize", function(e, size){ 199 | // Custom events bubble in jQuery 1.3; don't Yo Dawg 200 | if ( e.target != this ) return; 201 | // Determine new width/height of splitter container 202 | splitter._DF = splitter[0][opts.pxFixed] - splitter._PBF; 203 | splitter._DA = splitter[0][opts.pxSplit] - splitter._PBA; 204 | // Bail if splitter isn't visible or content isn't there yet 205 | if ( splitter._DF <= 0 || splitter._DA <= 0 ) return; 206 | // Re-divvy the adjustable dimension; maintain size of the preferred pane 207 | resplit(!isNaN(size)? size : (!(opts.sizeRight||opts.sizeBottom)? A[0][opts.pxSplit] : 208 | splitter._DA-B[0][opts.pxSplit]-bar._DA)); 209 | }).trigger("resize" , [initPos]); 210 | }); 211 | }; 212 | 213 | })(jQuery); -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is the JavaScript simulator from the visual6502.org project: 2 | www.visual6502.org/JSSim 3 | 4 | It includes a general purpose transistor-level simulator, layout browser, 5 | and the data from a 6502 revD chip. 6 | 7 | It also includes a similar simulator for the 6800 chip. 8 | 9 | Note the various licenses and Copyright associated with each file. 10 | 11 | Enjoy! 12 | - The Visual 6502 Team 13 | -------------------------------------------------------------------------------- /browsertrouble.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |18 | Our chip simulator makes heavy use of the latest version of HTML5 drawing technology. 19 |
20 | It will only run on recent browsers and on a computer with sufficient memory (we recommend at least 2Gbytes.) 21 |
22 | We've tested it on Chrome, Firefox, Safari and Opera. Unfortunately Internet Explorer isn't yet capable of running the graphics. 23 |
24 | If you're using one of the above browsers and having trouble, please restart the browser. 25 |
26 | If you have a problem report or you're able to help us with compatilibity, please get in touch - our contact details are on the main page. 27 |
28 | In the meantime, here's a picture of what you're missing: 29 |
32 | 33 | 41 | 44 | 45 | 46 |