257 Commits

Author SHA1 Message Date
7056873887 Merge pull request #44 from trebonian/gh-pages
Update production from gh-pages
2017-03-16 10:44:38 +00:00
f736b092de Merge pull request #43 from trebonian/staging
Update gh-pages preview site
2017-03-13 16:20:15 +00:00
1cb58a1cab Merge pull request #42 from trebonian/master
Merge two small changes to staging
2017-03-13 16:17:52 +00:00
1f78e25b3a Tweak README - add 6800 sim 2017-03-13 16:16:06 +00:00
4364604b96 Whitespace fixups 2017-03-13 16:13:03 +00:00
7ddbbe7de6 Merge pull request #41 from trebonian/staging
Update gh-pages from staging for testing
2017-03-12 10:24:03 +00:00
d5f0604427 Merge pull request #40 from trebonian/master
Two small changes from master into staging
2017-03-11 22:47:55 +00:00
2147762ee4 Merge pull request #38 from BigEd/patch-1
Fix typo in comment
2017-03-11 22:45:51 +00:00
651d8a44c5 Merge pull request #39 from mmfoerster/master
Patch allNodes() to generate list of numbers for the node indexes instead of numeric strings, fix JMP indirect mnemonic
2017-03-11 22:43:36 +00:00
51d6bb216b Patch allNodes() to generate list of numbers for node indexes instead of numeric strings, fix JMP indirect mnemonic
Patches for the general chipsim code and the 6502 emulation.

    For the general chipsim code, allNodes() was constructing a list of
numeric strings for the node indexes instead of a list of numbers for them.
During the first iteration inside recalcNodeList(), the numeric string node
indexes would end up being the first elements of their respective node group
lists. This in turn would allow instances of a duplicate node index to be added
to the node group list. The duplicate in each case would be the numeric
equivalent of the initial numeric string index: indexOf() would not recognize
the string element as being the equivalent of the numeric node index, so the
numeric version would be added also.

For an example (from real log data), a node group list of: [ "49", 483 ] has a
node index of 49 tested against it. indexOf() says "49" is not an occurrence
of 49, so it allows 49 to be
2017-03-10 23:09:20 -05:00
3b7fbe4385 Fix typo in comment 2016-11-08 16:37:20 +00:00
f3cffeeed6 Merge pull request #36 from BigEd/patch-2
Add I/O to 6800
2015-04-26 13:48:07 -04:00
a2a4bc65c5 Add I/O to 6800 2015-04-26 18:30:53 +01:00
815e972d14 Merge pull request #30 from PeterMortensen/master
Spelling/case.
2015-04-26 11:29:56 -04:00
9f4f922e16 Merge pull request #34 from shersom/master
Add labels to layout controls
2015-04-26 11:29:21 -04:00
27bec1bfe5 Merge pull request #35 from BigEd/patch-1
Fixup link to 6800 programming card
2015-04-25 20:59:53 -04:00
976fe7e430 Fixup link to 6800 programming card 2015-04-25 14:17:15 +01:00
72ac2caf74 Add labels to layout controls 2014-05-05 23:54:54 -07:00
741e035eb4 Merge branch 'patch-1' of http://github.com/BigEd/visual6502 into ed 2013-06-26 17:23:14 -04:00
dd2241d3de bugfix - macros.js - pre-apply clock triggers for corrected display 2013-06-25 22:31:53 +02:00
c0809ba34e typo fixup in README 2013-06-24 18:53:07 +02:00
df33b88c56 Update README 2013-06-18 16:06:06 +03:00
7d90b33187 Merge pull request #28 from BigEd/patch-1
Correcting a comment in nodenames.js
2013-02-04 06:02:05 -08:00
34244661cb Correcting a comment in nodenames.js
Thanks to 'cerebrum' on forum.6502.org
2013-02-03 10:19:22 +00:00
ce74c3f5d3 Swap easy6502 tutorial in for 6502asm emulator/assembler 2012-08-16 07:52:17 +01:00
cb03b9741a html fixups by Quietust 2011-08-27 03:34:25 +02:00
7b95b5e345 html tidyup by Quietust 2011-08-27 03:29:23 +02:00
de265ecdb8 6502: add nodename aliases to allow more use of the URL interface 2011-05-12 08:54:52 +00:00
e81c9fbe0f update 6800 tracing to include alu and incrementer 2011-04-16 13:03:43 +00:00
c300e6ad01 update 6800 nodenames: ordering, comments, minor corrections 2011-04-16 13:02:46 +00:00
79d0c4c445 import remainder of Segher's 6800 nodename updates and begin process of ordering and commenting 2011-04-16 11:29:53 +00:00
a2d35d54ca 6800 nodename changes from Segher 2011-04-16 10:58:16 +00:00
e20eb08b91 updated 6800 transistor bounding boxes and geometries from Ijor 2011-04-12 18:08:51 +00:00
8487a7a9e1 6800: tweak nodenames and add the Tf state name/node 2011-04-11 18:22:26 +00:00
6c138a4f6b add 6800 timing state to tabulation 2011-04-11 14:07:51 +00:00
658d40646c add 6800 timing state signals 2011-04-11 13:51:37 +00:00
67e15e68c1 fixup comment in transdefs about geometry 2011-04-09 10:33:18 +00:00
a316831100 update comments at head of transdefs 2011-04-09 10:12:53 +00:00
acd7b0310e Edited chip-6800/transdefs.js via GitHub 2011-04-09 17:57:45 +08:00
9331be20fe allow tabulations with loglevel 0 (with only additional signals) 2011-04-06 18:13:04 +00:00
e6d42eb1aa 6800 declutter - remove clock phases from tabulated signals 2011-04-05 19:45:33 +00:00
8ae5c087f6 fixup missing assignments causing errors 2011-04-05 18:29:49 +00:00
c6dd03ba17 fixup 6800 test program 2011-04-05 18:09:53 +00:00
fca2eb5cb6 fixup 6800 pre-reset delay 2011-04-05 18:09:38 +00:00
b5c1759f32 improve 6800 machine state display 2011-04-02 08:01:09 +00:00
6ceae74e4a 6800 fixup single stepping 2011-04-02 07:57:15 +00:00
94b306bace update 6800 machine state readout 2011-04-01 20:57:42 +00:00
9308b26c42 update 6800 loglevel definitions 2011-04-01 20:12:22 +00:00
335cb06832 update 6800 segdefs to add missing pullups 2011-04-01 20:11:51 +00:00
d9440fa160 6800: fixup bus reads, add annotation for unassigned opcodes 2011-04-01 18:44:12 +00:00
10ba01cf12 fixup 6800 disassembly 2011-04-01 17:55:49 +00:00
e8b964a24f fixup 6800 IR nodenames 2011-04-01 17:55:30 +00:00
bbfcf77134 update 6800 nodenames and trace signals 2011-04-01 17:32:01 +00:00
73f21ffc47 update 6800 test program 2011-04-01 17:31:30 +00:00
4e2c84dabc update 6800 test program and add opcode map 2011-04-01 16:05:41 +00:00
ca7124b176 6800: treat dbe as phi2 clock in 2011-04-01 14:40:56 +00:00
b0710a4cda trying to clean up gh-pages 2011-04-01 11:59:22 +00:00
baac06bdc3 Merge branch 'gh-pages' of git@github.com:BigEd/visual6502 into gh-pages 2011-04-01 11:57:47 +00:00
9bb8caa025 update README 2011-04-01 11:50:04 +00:00
b98010206e trying to clean up gh-pages 2011-04-01 11:40:21 +00:00
7049cef9b7 update README 2011-04-01 11:38:37 +00:00
9d23382644 trying to clean up gh-pages 2011-04-01 11:34:02 +00:00
8f5f50d197 first cut of ijor's 6800 2011-04-01 11:19:42 +00:00
1d21f5ae8b few small changes to prepare for multi-chip capability 2011-04-01 11:17:34 +00:00
15b25491b9 nodename adjustments and additions 2011-02-20 20:06:29 +00:00
6033109dc6 adjust pclp and pchp to pickup non inverted state 2011-02-15 20:04:08 +00:00
0e41f0a9a9 [bug]fixup misnumbered node abl7 2011-02-15 19:54:06 +00:00
cb29fb4fad readjust timing of URL-scheduled events to match published version 2011-01-10 10:45:52 +00:00
c02d181d5c add more nodenames from Segher 2011-01-09 20:32:51 +00:00
51d0e99389 add ability to override the databus by URL 2011-01-09 16:18:01 +00:00
d11cf44ae9 add ability to sequence RDY pin from the URL 2011-01-09 13:10:13 +00:00
2e69d3a7c3 fix: allow coincident pin events 2011-01-09 13:09:25 +00:00
f098566335 Hilited nodes toggle state when stepped or run 2011-01-03 15:17:27 -05:00
e25ac6243c fixup merge conflict markers 2010-12-23 19:15:30 +00:00
94e22becb4 fixup expert.html consolidation 2010-12-23 19:00:05 +00:00
a56ee40bd8 attempt to get gh-pages into shape 2010-12-23 18:59:02 +00:00
2ace0e8bad try consolidating into just 2 files for efficient loading 2010-12-23 18:14:58 +00:00
84b005673b give the names of the nodes in a shift-click group, if they have names 2010-12-22 21:16:50 +00:00
09c578e361 shift-click: list members of channel-connected nodegroup 2010-12-21 22:31:38 +00:00
167f93f836 feature: URL can define labels and optional boxes 2010-12-20 19:30:49 +00:00
c88e0749cf feature: add support for box and label in highlight layer 2010-12-20 19:00:44 +00:00
6db8836c5c feature: find matches names on underscore-delimited components 2010-12-19 18:31:10 +00:00
27fb1d539e bugfix: shift-click to highlight a pass-connected node-group should work on gates too 2010-12-19 17:54:37 +00:00
21c7a8ca90 bugfix: zoom-to-fit on found objects needed an x offset 2010-12-19 17:41:16 +00:00
cfb726d0e7 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-12-19 17:24:35 +00:00
d352501c7c update the "link here" to include searched objects 2010-12-19 17:24:14 +00:00
4eb1e4c848 Fix protection bits on some files 2010-12-19 12:04:35 -05:00
c3f0d10199 Merge branches 'ed' and 'master' into ed 2010-12-19 12:01:44 -05:00
4398fdaddf Added Bends and Gate Area to transdefs 2010-12-19 10:38:31 -05:00
4f7930eef3 Fix Shift Click which broke in performance improvement changes 2010-12-19 10:37:51 -05:00
c04f37a3df add feature: click can highlight transistors 2010-12-19 12:45:44 +00:00
fc664c7243 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-12-18 11:30:06 +00:00
8bdb9a0682 New transdefs with Gate Bounding Box and Geometry 2010-12-17 21:35:19 -05:00
ae30a57822 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-12-12 18:22:13 +00:00
8a89310e96 Fix expert mode's keyboard handling too. 2010-12-08 06:53:38 +08:00
1c66a8af28 handleKey(): if .charCode is undefined, use .keyCode (Opera compatible.) 2010-12-08 06:53:37 +08:00
78deb4aaa4 fixup nodenames type 2010-12-07 22:49:38 +00:00
85c8447064 Fix expert mode's keyboard handling too. 2010-12-05 12:34:39 +01:00
6cdbfc0c15 handleKey(): if .charCode is undefined, use .keyCode (Opera compatible.) 2010-12-05 09:50:00 +01:00
8ef98d131f added signal names - mostly ALU - from Segher 2010-12-04 17:05:24 +00:00
e660736204 fixup status message when no find command in URL 2010-12-03 16:28:55 +00:00
fc46e50289 add "find" mechanism to URL 2010-12-03 13:35:01 +00:00
4967b58e7f update status box when find is used 2010-12-03 12:46:10 +00:00
6f7dab7990 more nodenames from Segher: alu internals 2010-12-03 12:27:26 +00:00
04196aa36a more nodenames from Segher: decimal mode and carry chain 2010-12-03 12:14:18 +00:00
94a2b38d27 import more signal names from Segher 2010-11-30 21:15:49 +00:00
e052255c55 add first cut of zooming to fit found objects: transistors and nodes. Renamed "Highlight:" button to "Find:" 2010-11-29 20:07:29 +00:00
15453f4435 Merge branch 'ed' 2010-11-28 16:38:32 -05:00
7572b25453 Hilite transistors 2010-11-28 16:37:02 -05:00
93252a0eb1 [bug]fixup obsolete css file reference in browsertrouble.html 2010-11-27 15:58:46 +00:00
172394845a [bug]typo: fixed B bit of status register 2010-11-27 14:30:19 +00:00
ec7da19d77 add z and x to expert mode help text 2010-11-27 14:19:57 +00:00
13e1f51b47 kiosk mode: add link to user guide, tweak help text and add alphabetic zoom controls 2010-11-27 13:54:31 +00:00
e6d3c62057 [bug]deal with disassembly of unknown opcodes 2010-11-27 12:37:14 +00:00
fbf0830d15 Expert page: add link to user guide (wiki page) 2010-11-27 11:37:08 +00:00
019bca0a26 remove white gaps in new logstream table colour scheme 2010-11-26 22:14:09 +00:00
e866a3b58e put non-breaking spaces into disassembly fragments 2010-11-26 14:27:03 +00:00
611490ad76 various blue backgrounds to logstream table 2010-11-26 14:22:45 +00:00
b3e58dcbab immunize kiosk mode against I/O triggers in test program 2010-11-22 15:20:24 +00:00
c7ac03edd8 move the I/O port (incremented value) to the top right for better visibility 2010-11-22 15:19:38 +00:00
b51b5c4398 re-simplify kiosk mode status panel 2010-11-22 15:18:55 +00:00
8f2e296ef6 update git project pages with placeholder/redirect empty content 2010-11-22 13:42:46 +00:00
ee2fa1befd removing gh-pages project preview 2010-11-22 13:41:40 +00:00
7c50999c9e Merge branch 'gh-pages' of git@github.com:BigEd/visual6502 into gh-pages 2010-11-22 13:40:15 +00:00
398060f56b add opcode and machine state info to status panel, add Fetch Execute and State pseudo signals to log tabulation 2010-11-22 13:27:26 +00:00
cdd837dd0c display machine state in status panel 2010-11-22 12:23:20 +00:00
3df7065b83 fold 6502 opcode lookup into macro.js and delete Java original 2010-11-22 12:22:36 +00:00
f860067206 convert java debugger to javascript almost-disassembler 2010-11-22 11:40:14 +00:00
33f00022ca add Achim's original Debugger.java 2010-11-22 11:33:56 +00:00
abf6daef7d Merge branch 'master' into gh-pages 2010-11-19 22:42:58 +00:00
8a6fe3634f add tracing of datapath control signals 2010-11-19 22:42:26 +00:00
296599890a correct the PC master/slave labelling and revert the predecode to the (inverted) latch nodes 2010-11-19 21:50:20 +00:00
580f4585a6 allow inverted display of negative sense busses 2010-11-19 21:49:16 +00:00
d045485ec4 [enh]allow free-running low-overhead mode, for interactive programs 2010-11-15 17:29:50 +00:00
71a85b3135 small improvement to trigger examples in testprogram 2010-11-15 17:28:45 +00:00
b3a6a12ddc adding URL control of IRQ and NMI pins 2010-11-14 20:15:49 +00:00
5f472cbe10 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-11-10 22:20:36 +00:00
6ced887613 add link to Advanced page and re-word other link 2010-11-10 10:53:59 -05:00
3bf9ae1fac Merge branch 'master' into gh-pages 2010-11-09 21:26:10 +00:00
6be4dd1673 add link to Advanced page and re-word other link 2010-11-09 21:25:56 +00:00
c4af64f5e8 Merge branch 'master' into gh-pages 2010-11-09 20:32:27 +00:00
7e6eb926ee Merge branch 'master' of git://github.com/trebonian/visual6502 2010-11-09 20:31:19 +00:00
6c899eda1a Add white space between links and chip window 2010-11-08 19:35:12 -05:00
82daddcfe4 Merge branch 'master' into gh-pages 2010-11-08 22:29:26 +00:00
6c2217b8fa [bug]kiosk mode must also load macros before testprogram 2010-11-08 22:29:08 +00:00
50ecadaa00 Merge branch 'master' into gh-pages 2010-11-08 22:18:24 +00:00
f6a86088f0 [enh]add a putc action to the test program 2010-11-08 22:18:07 +00:00
8a2342d83c Merge branch 'master' into gh-pages 2010-11-08 22:04:12 +00:00
5c9b4e7581 [dev]adding console box and read/write hook mechanism for test program I/O 2010-11-08 22:03:47 +00:00
2a0e251088 [bug]fix improper closing tag (expert.html) 2010-11-08 16:36:45 +00:00
60b4ecab22 Merge branch 'master' into gh-pages 2010-11-08 09:17:38 +00:00
d2a31398fd [bug]repair expert mode - had removed too much 2010-11-08 09:14:18 +00:00
3804eace6e simplify: expertMode is no longer a checkbox, just a static indicator 2010-11-08 09:04:47 +00:00
369a188ad9 use expertMode to suppress loglist actions in kiosk mode 2010-11-08 09:03:13 +00:00
9ff6ae027e note nature of this temporary export branch in the HTML 2010-11-06 17:59:40 +00:00
678acd6dc5 URL handler: add requested signal names to logging set 2010-11-06 17:55:36 +00:00
758d53bf5b add clock trigger mechanism and URL interface for reset pin 2010-11-06 17:21:50 +00:00
e885646e5e [bug]fixup nosim=t initialisation (if a simulation is started manually) 2010-11-05 21:39:01 +00:00
353e0a8f78 highlight a list of nodes by name or number 2010-11-05 21:21:06 +00:00
18e1946488 allow forward or reverse log order 2010-11-05 19:53:22 +00:00
0c6a90a558 allow nodenumbers in additional trace requests 2010-11-05 19:02:41 +00:00
93e6d662df panes resize when chip graphics are shown/hidden 2010-11-05 18:25:51 +00:00
0842501bb7 [bug]direct keypresses to correct places: graphics, memtable, input box 2010-11-05 17:38:47 +00:00
294918789a add tracing of named nodes 2010-11-01 19:36:52 +00:00
cd05762f20 trivial fix to rename button container 2010-11-01 18:30:22 +00:00
ef0bb5cdec fix out by one error in fastforward/goFor 2010-11-01 18:19:46 +00:00
25e8397a0f scale down new button images 2010-11-01 18:15:36 +00:00
44b5c5e9d3 add new buttons and remove headless go 2010-11-01 18:03:30 +00:00
633a2693ac fixup single stepping function 2010-11-01 18:02:52 +00:00
da7ec1f3e3 add button icons for fast forward and single step 2010-11-01 18:02:06 +00:00
bed571f10c add button to clear log 2010-11-01 17:42:45 +00:00
192d9a8ba8 add plaOutputs to traceable log stream 2010-11-01 17:42:18 +00:00
b4747b0cad trivial annotation tweak to nodenames.js 2010-11-01 17:31:48 +00:00
62b0b314d5 remove kiosk.html and use index.html instead 2010-11-01 17:00:27 +00:00
39959e711e three panel splittable (dynamic) screen layout 2010-10-31 13:39:31 +00:00
0156a72ae7 add splitter and jquery library (GPL and MIT dual licensed) for draggable pane divisions 2010-10-31 12:47:20 +00:00
759c188ef6 Add useful links to existing minimal banner line 2010-10-31 10:22:30 +00:00
a406cee106 Add graphics command tips (no help page yet) 2010-10-31 10:17:53 +00:00
e3354a2aa4 Merge branch 'master' of git://github.com/trebonian/visual6502 2010-10-30 20:33:16 +00:00
68e022a2bd [bug]tidy up pan+zoom URLs 2010-10-30 20:31:32 +00:00
c4dcbcb435 Merge branch 'ed' 2010-10-30 16:27:50 -04:00
bc8ef61fb9 [enh]add pla signalnames from Segher Boessenkool 2010-10-30 20:23:56 +00:00
86e544a065 Change link to expert mode from kiosk 2010-10-30 16:13:43 -04:00
ea9f54c398 [bug]index redirection fixup 2010-10-30 20:07:26 +00:00
dd95b40c6c added smart redirect in index.html to appropriate landing page 2010-10-30 18:59:00 +00:00
3fcc3ee787 bring in support for old/slow browser, including nosim node 2010-10-30 18:24:00 +00:00
83af54a47d re-simplify busname name matching 2010-10-30 18:05:29 +00:00
c9443e6718 [bug]passing steps on URL was not working 2010-10-30 16:16:54 +00:00
e93c11ab20 replace index.html with a redirector to the expert landing page 2010-10-30 16:07:48 +00:00
0d0973b0c6 [bugfix]tcstate and predecode register corrections 2010-10-30 14:05:14 +00:00
4b19e21e66 [BUG]Animate checkbox not initialized 2010-10-29 19:10:06 -04:00
df6aaa392c More simplifications from Brian 2010-10-15 08:11:43 -04:00
5a4c574765 Headless mode in expert 2010-10-14 22:48:25 -04:00
10787078c8 More forEach 2010-10-14 21:15:47 -04:00
98ec727c50 Performance: Remove float state 2010-10-14 21:00:07 -04:00
33aa993c8d Performance - use forEach, and more cleanup 2010-10-14 20:16:43 -04:00
b5e1064efb Performance improvement in checking for duplicate nodes in recalclist 2010-10-13 22:00:01 -04:00
282c815791 Chipsim change of states to booleans, and performance 2010-10-13 17:53:40 -04:00
3258a24c91 [bug]fixup chip layout visibility control 2010-10-09 13:43:47 +00:00
66d42665a9 [bug]graphics=false needs to work in expert mode 2010-10-08 15:27:33 +00:00
cede111a0f First cut refactor into expert and kiosk 2010-10-07 12:21:06 -04:00
dc0fb1ef06 Merging changes for testprogram, and various fixes from Ed 2010-10-07 08:15:07 -04:00
e60485fe6a Performance fix 2010-10-07 07:33:15 -04:00
9705ca4093 [bug]declarations for testprogram and fix for negative loglevel values 2010-10-06 21:00:56 +00:00
a83cb1533e [dev]add singlestepping functions (no UI) 2010-10-06 20:59:43 +00:00
971bbd03e3 [dev]externalise testprogram 2010-10-06 19:51:57 +00:00
0773a9e7cf [dev](commented out)performance tweak, 1.2x gain 2010-10-06 19:48:30 +00:00
ee196947e3 [dev]add trace checksum for self-checking tests 2010-10-05 19:14:08 +00:00
f439d8fc8d [bug]fixup output of tstate and P 2010-10-05 18:12:44 +00:00
43f06031b0 [dev]alternate zoom keys 2010-10-05 17:51:48 +00:00
c5e2bfd657 [bug]use the grMaxZoom constant as intended 2010-10-04 11:12:07 +00:00
2cfceefacd [dev]add comments and some symbolic constants for graphics code - no functional change 2010-10-04 11:04:35 +00:00
67ad17122c [dev]Brian's smaller canvas - simulates faster and working/virtual memory down from 330M/570M to 130M/350M 2010-10-04 10:50:54 +00:00
c15e3ea5b5 [bug]minimum log trace should be same as status set 2010-10-02 18:12:25 +00:00
6aec2c96f0 [bug]minor grammar fix 2010-10-02 16:47:28 +00:00
d6e516cafa [dev]major rejig of css and DOM hierarchy - removes some hard coded numbers and allows for large/small logstream when chip is hidden/visible 2010-10-02 16:37:33 +00:00
2d20ef2dad [dev]force status box to 3-line form, other layout tweaks 2010-10-02 16:36:02 +00:00
5f24e86c3e [dev]add speedometer 2010-10-02 11:51:33 +00:00
5578726fd3 [bug]reword the link to 6502 tools 2010-10-02 11:06:14 +00:00
1843c17ce9 [bug]older firefox likes childNodes 2010-10-01 20:58:13 +00:00
455949ceca [bug]logstream box should become scrollable when too large 2010-10-01 19:13:29 +00:00
f0536dc716 [dev]user program can be defined in url, can run for chosen number of steps 2010-10-01 18:39:33 +00:00
c8aabd6baa [dev]add links to 6502asm and e-tradition 2010-10-01 18:31:02 +00:00
0b1af8d70e [dev]add link to current pan+zoom 2010-10-01 16:56:14 +00:00
f3375f4c4b [dev]implement pan and zoom from URL 2010-10-01 16:10:33 +00:00
0892586d75 [dev]tidy rough edges in expert and graphics mode switching 2010-10-01 14:51:17 +00:00
0ae95d5338 [bug]rejig non-graphics mode 2010-10-01 13:02:03 +00:00
a2d20cc403 [dev]handle URL params like ?graphics=false&expert=true&loglevel=4 2010-10-01 11:29:22 +00:00
e72f11ee72 Merge branch 'ed' into staging 2010-09-30 17:31:59 -04:00
4b0316170b [bug]fixup alu c and v output node names 2010-09-30 21:07:36 +00:00
4849ad6ebc [dev]name some reset signals 2010-09-30 19:20:56 +00:00
f26a508c4e [dev]add selective node and transistor ctrace 2010-09-28 19:22:50 +00:00
d94116d257 Fixed save.php 2010-09-27 20:56:47 -04:00
b8d2872246 Merge branch 'ed' into staging 2010-09-27 13:48:54 -04:00
730312e594 [dev]enhancements to expert mode 2010-09-27 17:25:14 +00:00
46976519fe [dev]add hanson names to some datapath controls, add dasb 2010-09-27 17:24:42 +00:00
4ce8e4291f [dev]improve expert-mode tabulation 2010-09-27 13:16:59 +00:00
c03f3477bd Merge branch 'ed' into staging 2010-09-26 20:37:51 -04:00
f67125989c [dev]annotate some decimal signals 2010-09-26 21:39:58 +00:00
25f4594fdf [dev]label some pipeline state, add some pla and alu labelling 2010-09-26 19:55:54 +00:00
f6f467787a [dev]first (untidy) implementation of expert mode with tabular logging 2010-09-25 21:32:29 +00:00
2e9991c8ec Merge branch 'ed' into staging 2010-09-25 16:40:11 -04:00
b50da0d3ed Merge branch 'ed' into staging 2010-09-25 10:30:11 -04:00
653379e5d7 [bug]nodename additions and tweaks 2010-09-25 11:29:56 +00:00
b3606c3b7f [bug]fixup some inverted busses 2010-09-25 11:06:44 +00:00
406c9731e8 [dev]add datapath controls and other names 2010-09-25 10:30:25 +00:00
40fe1e0a7a [dev] tweak logging capability 2010-09-25 10:29:26 +00:00
1f21f5283c add Ed to copyright notice 2010-09-25 08:18:28 +00:00
b161368455 Fix scroll instructions 2010-09-24 10:20:14 -04:00
eaf55f1f31 [bug]correct pla output numbers, add ir signals 2010-09-24 14:02:57 +00:00
11ab9bafce [dev]assist probing by optionally logging node info to console 2010-09-23 19:39:12 +00:00
8fbcefc2e2 [dev]add 130 pla outputs and a couple of other tweaks 2010-09-23 19:38:16 +00:00
ea48dae543 [dev]reorder and add comments to nodenames 2010-09-23 18:53:43 +00:00
f293f2f10b [dev]fixup double-paste in previous commit 2010-09-22 21:34:00 +00:00
2ac9d92999 [dev]add adsense to other jssim html page 2010-09-22 21:32:01 +00:00
864b82d7b7 [bug]fixup IE version extraction 2010-09-22 20:38:52 +00:00
e4ccdcafcd github and google links 2010-09-22 07:34:14 -04:00
33 changed files with 37348 additions and 4027 deletions

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 855 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 843 B

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

File diff suppressed because one or more lines are too long

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

@ -0,0 +1,92 @@
/**
* Cookie plugin
*
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
/**
* Create a cookie with the given name and value and other optional parameters.
*
* @example $.cookie('the_cookie', 'the_value');
* @desc Set the value of a cookie.
* @example $.cookie('the_cookie', 'the_value', {expires: 7, path: '/', domain: 'jquery.com', secure: true});
* @desc Create a cookie with all available options.
* @example $.cookie('the_cookie', 'the_value');
* @desc Create a session cookie.
* @example $.cookie('the_cookie', null);
* @desc Delete a cookie by passing null as value.
*
* @param String name The name of the cookie.
* @param String value The value of the cookie.
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
* If set to null or omitted, the cookie will be a session cookie and will not be retained
* when the the browser exits.
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
* require a secure protocol (like HTTPS).
* @type undefined
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
/**
* Get the value of a cookie with the given name.
*
* @example $.cookie('the_cookie');
* @desc Get the value of a cookie.
*
* @param String name The name of the cookie.
* @return The value of the cookie.
* @type String
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
jQuery.cookie = function(name, value, options) {
if (typeof value != 'undefined') { // name and value given, set cookie
options = options || {};
if (value === null) {
value = '';
options.expires = -1;
}
var expires = '';
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
} else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
var path = options.path ? '; path=' + options.path : '';
var domain = options.domain ? '; domain=' + options.domain : '';
var secure = options.secure ? '; secure' : '';
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
} else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
};

213
3rdparty/splitter.js vendored Normal file
View File

@ -0,0 +1,213 @@
/*
* jQuery.splitter.js - two-pane splitter window plugin
*
* version 1.51 (2009/01/09)
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
/**
* The splitter() plugin implements a two-pane resizable splitter window.
* The selected elements in the jQuery object are converted to a splitter;
* each selected element should have two child elements, used for the panes
* of the splitter. The plugin adds a third child element for the splitbar.
*
* For more details see: http://methvin.com/splitter/
*
*
* @example $('#MySplitter').splitter();
* @desc Create a vertical splitter with default settings
*
* @example $('#MySplitter').splitter({type: 'h', accessKey: 'M'});
* @desc Create a horizontal splitter resizable via Alt+Shift+M
*
* @name splitter
* @type jQuery
* @param Object options Options for the splitter (not required)
* @cat Plugins/Splitter
* @return jQuery
* @author Dave Methvin (dave.methvin@gmail.com)
*/
;(function($){
$.fn.splitter = function(args){
args = args || {};
return this.each(function() {
var zombie; // left-behind splitbar for outline resizes
function startSplitMouse(evt) {
if ( opts.outline )
zombie = zombie || bar.clone(false).insertAfter(A);
panes.css("-webkit-user-select", "none"); // Safari selects A/B text on a move
bar.addClass(opts.activeClass);
A._posSplit = A[0][opts.pxSplit] - evt[opts.eventPos];
$(document)
.bind("mousemove", doSplitMouse)
.bind("mouseup", endSplitMouse);
}
function doSplitMouse(evt) {
var newPos = A._posSplit+evt[opts.eventPos];
if ( opts.outline ) {
newPos = Math.max(0, Math.min(newPos, splitter._DA - bar._DA));
bar.css(opts.origin, newPos);
} else
resplit(newPos);
}
function endSplitMouse(evt) {
bar.removeClass(opts.activeClass);
var newPos = A._posSplit+evt[opts.eventPos];
if ( opts.outline ) {
zombie.remove(); zombie = null;
resplit(newPos);
}
panes.css("-webkit-user-select", "text"); // let Safari select text again
$(document)
.unbind("mousemove", doSplitMouse)
.unbind("mouseup", endSplitMouse);
}
function resplit(newPos) {
// Constrain new splitbar position to fit pane size limits
newPos = Math.max(A._min, splitter._DA - B._max,
Math.min(newPos, A._max, splitter._DA - bar._DA - B._min));
// Resize/position the two panes
bar._DA = bar[0][opts.pxSplit]; // bar size may change during dock
bar.css(opts.origin, newPos).css(opts.fixed, splitter._DF);
A.css(opts.origin, 0).css(opts.split, newPos).css(opts.fixed, splitter._DF);
B.css(opts.origin, newPos+bar._DA)
.css(opts.split, splitter._DA-bar._DA-newPos).css(opts.fixed, splitter._DF);
// IE fires resize for us; all others pay cash
if ( !$.browser.msie )
panes.trigger("resize");
}
function dimSum(jq, dims) {
// Opera returns -1 for missing min/max width, turn into 0
var sum = 0;
for ( var i=1; i < arguments.length; i++ )
sum += Math.max(parseInt(jq.css(arguments[i])) || 0, 0);
return sum;
}
// Determine settings based on incoming opts, element classes, and defaults
var vh = (args.splitHorizontal? 'h' : args.splitVertical? 'v' : args.type) || 'v';
var opts = $.extend({
activeClass: 'active', // class name for active splitter
pxPerKey: 8, // splitter px moved per keypress
tabIndex: 0, // tab order indicator
accessKey: '' // accessKey for splitbar
},{
v: { // Vertical splitters:
keyLeft: 39, keyRight: 37, cursor: "e-resize",
splitbarClass: "vsplitbar", outlineClass: "voutline",
type: 'v', eventPos: "pageX", origin: "left",
split: "width", pxSplit: "offsetWidth", side1: "Left", side2: "Right",
fixed: "height", pxFixed: "offsetHeight", side3: "Top", side4: "Bottom"
},
h: { // Horizontal splitters:
keyTop: 40, keyBottom: 38, cursor: "n-resize",
splitbarClass: "hsplitbar", outlineClass: "houtline",
type: 'h', eventPos: "pageY", origin: "top",
split: "height", pxSplit: "offsetHeight", side1: "Top", side2: "Bottom",
fixed: "width", pxFixed: "offsetWidth", side3: "Left", side4: "Right"
}
}[vh], args);
// Create jQuery object closures for splitter and both panes
var splitter = $(this).css({position: "relative"});
var panes = $(">*", splitter[0]).css({
position: "absolute", // positioned inside splitter container
"z-index": "1", // splitbar is positioned above
"-moz-outline-style": "none" // don't show dotted outline
});
var A = $(panes[0]); // left or top
var B = $(panes[1]); // right or bottom
// Focuser element, provides keyboard support; title is shown by Opera accessKeys
var focuser = $('<a href="javascript:void(0)"></a>')
.attr({accessKey: opts.accessKey, tabIndex: opts.tabIndex, title: opts.splitbarClass})
.bind($.browser.opera?"click":"focus", function(){ this.focus(); bar.addClass(opts.activeClass) })
.bind("keydown", function(e){
var key = e.which || e.keyCode;
var dir = key==opts["key"+opts.side1]? 1 : key==opts["key"+opts.side2]? -1 : 0;
if ( dir )
resplit(A[0][opts.pxSplit]+dir*opts.pxPerKey, false);
})
.bind("blur", function(){ bar.removeClass(opts.activeClass) });
// Splitbar element, can be already in the doc or we create one
var bar = $(panes[2] || '<div></div>')
.insertAfter(A).css("z-index", "100").append(focuser)
.attr({"class": opts.splitbarClass, unselectable: "on"})
.css({position: "absolute", "user-select": "none", "-webkit-user-select": "none",
"-khtml-user-select": "none", "-moz-user-select": "none"})
.bind("mousedown", startSplitMouse);
// Use our cursor unless the style specifies a non-default cursor
if ( /^(auto|default|)$/.test(bar.css("cursor")) )
bar.css("cursor", opts.cursor);
// Cache several dimensions for speed, rather than re-querying constantly
bar._DA = bar[0][opts.pxSplit];
splitter._PBF = $.boxModel? dimSum(splitter, "border"+opts.side3+"Width", "border"+opts.side4+"Width") : 0;
splitter._PBA = $.boxModel? dimSum(splitter, "border"+opts.side1+"Width", "border"+opts.side2+"Width") : 0;
A._pane = opts.side1;
B._pane = opts.side2;
$.each([A,B], function(){
this._min = opts["min"+this._pane] || dimSum(this, "min-"+opts.split);
this._max = opts["max"+this._pane] || dimSum(this, "max-"+opts.split) || 9999;
this._init = opts["size"+this._pane]===true ?
parseInt($.curCSS(this[0],opts.split)) : opts["size"+this._pane];
});
// Determine initial position, get from cookie if specified
var initPos = A._init;
if ( !isNaN(B._init) ) // recalc initial B size as an offset from the top or left side
initPos = splitter[0][opts.pxSplit] - splitter._PBA - B._init - bar._DA;
if ( opts.cookie ) {
if ( !$.cookie )
alert('jQuery.splitter(): jQuery cookie plugin required');
var ckpos = parseInt($.cookie(opts.cookie));
if ( !isNaN(ckpos) )
initPos = ckpos;
$(window).bind("unload", function(){
var state = String(bar.css(opts.origin)); // current location of splitbar
$.cookie(opts.cookie, state, {expires: opts.cookieExpires || 365,
path: opts.cookiePath || document.location.pathname});
});
}
if ( isNaN(initPos) ) // King Solomon's algorithm
initPos = Math.round((splitter[0][opts.pxSplit] - splitter._PBA - bar._DA)/2);
// Resize event propagation and splitter sizing
if ( opts.anchorToWindow ) {
// Account for margin or border on the splitter container and enforce min height
splitter._hadjust = dimSum(splitter, "borderTopWidth", "borderBottomWidth", "marginBottom");
splitter._hmin = Math.max(dimSum(splitter, "minHeight"), 20);
$(window).bind("resize", function(){
var top = splitter.offset().top;
var wh = $(window).height();
splitter.css("height", Math.max(wh-top-splitter._hadjust, splitter._hmin)+"px");
if ( !$.browser.msie ) splitter.trigger("resize");
}).trigger("resize");
}
else if ( opts.resizeToWidth && !$.browser.msie )
$(window).bind("resize", function(){
splitter.trigger("resize");
});
// Resize event handler; triggered immediately to set initial position
splitter.bind("resize", function(e, size){
// Custom events bubble in jQuery 1.3; don't Yo Dawg
if ( e.target != this ) return;
// Determine new width/height of splitter container
splitter._DF = splitter[0][opts.pxFixed] - splitter._PBF;
splitter._DA = splitter[0][opts.pxSplit] - splitter._PBA;
// Bail if splitter isn't visible or content isn't there yet
if ( splitter._DF <= 0 || splitter._DA <= 0 ) return;
// Re-divvy the adjustable dimension; maintain size of the preferred pane
resplit(!isNaN(size)? size : (!(opts.sizeRight||opts.sizeBottom)? A[0][opts.pxSplit] :
splitter._DA-B[0][opts.pxSplit]-bar._DA));
}).trigger("resize" , [initPos]);
});
};
})(jQuery);

4
README
View File

@ -1,9 +1,11 @@
This is the javascript simulator from the visual5602.org project:
This is the JavaScript simulator from the visual5602.org project:
www.visual6502.org/JSSim
It includes a general purpose transistor-level simulator, layout browser,
and the data from a 6502 revD chip.
It also includes a similar simulator for the 6800 chip.
Note the various licenses and Copyright associated with each file.
Enjoy!

View File

@ -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>
@ -29,5 +29,18 @@ In the meantime, here's a picture of what you're missing:
<p>
<a href="http://visual6502.org"><img src="images/jssim2.png" style="border:10px"></a>
</span>
<script type="text/javascript"><!--
google_ad_client = "pub-9008420149077488";
/* 728x90, created 9/22/10 */
google_ad_slot = "4303982675";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</body>
</html>

1222
chip-6800/nodenames.js Normal file

File diff suppressed because it is too large Load Diff

9818
chip-6800/segdefs.js Normal file

File diff suppressed because one or more lines are too long

486
chip-6800/support.js Normal file
View File

@ -0,0 +1,486 @@
// chip-specific support functions
//
// may override function definitions made previously
chipname='6800';
grChipSize=7000;
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 = '&#8209' + // non-breaking hyphen
'&#8209' + // 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",
};

31
chip-6800/testprogram.js Normal file
View File

@ -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
]

4017
chip-6800/transdefs.js Executable file

File diff suppressed because it is too large Load Diff

View File

@ -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++){
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;}

153
expert-6800.html Normal file
View File

@ -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>&nbsp;
<a href="http://blog.visual6502.org">Blog</a>&nbsp;
<a href="http://www.visual6502.org/links.html">Links</a>&nbsp;
<a href="http://github.com/trebonian/visual6502">Source</a>&nbsp;
<a href="http://www.textfiles.com/programming/CARDS/6800">6800 instruction card</a>&nbsp;
<a href="http://www.sbprojects.com/sbasm/6800.htm#model">programming model</a>&nbsp;
</span>
<div class="frame" id="frame">
<div class="leftcolumn" id="leftcolumn">
<div id="chipsurround" tabindex="1">
<div class="chip" id="chip">
<span id="waiting">Please wait, graphics initialising...</span>
<canvas class="chip" id="chipbg"></canvas>
<canvas class="chip" id="overlay"></canvas>
<canvas class="chip" id="hilite"></canvas>
<canvas class="chip" id="hitbuffer"></canvas>
</div>
</div> <!-- chipsurround -->
<div class="nochip" id="nochip">
<form>
<input type="button" value="Show chip layout" onclick="updateChipLayoutVisibility(true)" />
</form>
</div>
<div id="layoutControlPanel">
Use '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>
&nbsp;
</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>

14866
expert-allinone.js Normal file

File diff suppressed because one or more lines are too long

228
expert.css Normal file
View File

@ -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;
}

152
expert.html Normal file
View File

@ -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>&nbsp;
<a href="http://blog.visual6502.org">Blog</a>&nbsp;
<a href="http://www.visual6502.org/links.html">Links</a>&nbsp;
<a href="http://github.com/trebonian/visual6502">Source</a>&nbsp;
<a href="http://skilldrick.github.com/easy6502/#first-program">easy6502 assembler</a>&nbsp;
<a href="http://www.e-tradition.net/bytes/6502/disassembler.html">e-tradition disassembler</a>&nbsp;
</span>
<div class="frame" id="frame">
<div class="leftcolumn" id="leftcolumn">
<div id="chipsurround" tabindex="1">
<div class="chip" id="chip">
<span id="waiting">Please wait, graphics initialising...</span>
<canvas class="chip" id="chipbg"></canvas>
<canvas class="chip" id="overlay"></canvas>
<canvas class="chip" id="hilite"></canvas>
<canvas class="chip" id="hitbuffer"></canvas>
</div>
</div> <!-- chipsurround -->
<div class="nochip" id="nochip">
<form>
<input type="button" value="Show chip layout" onclick="updateChipLayoutVisibility(true)" />
</form>
</div>
<div id="layoutControlPanel">
Use 'z' or '&gt;' to zoom in, 'x' or '&lt;' 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="http://visual6502.org/wiki/index.php?title=JssimUserHelp" target="_blank">User Guide</a>
&nbsp;
</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>

615
expertWires.js Normal file
View File

@ -0,0 +1,615 @@
/*
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 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=="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 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 400 from x and subtract y from grChipSize
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 + ' y: ' + cy;
var s2='node:&nbsp;' + w + '&nbsp;' + 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-400;
y=grChipSize-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&nbsp;" + s2 +
" (nodes:&nbsp;" +
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.onmousedown = function(e){mouseDown(e);};
chipsurround.onkeypress = function(e){handleKey(e);};
}
// utility function to save graphics pan and zoom
function whereAmIAsQuery(){
var w=whereAmI();
return "panx="+w[0].toFixed(1)+"&pany="+w[1].toFixed(1)+"&zoom="+w[2].toFixed(1);
}
function whereAmI(){
return [centerx, centery, zoom];
}
// restore graphics pan and zoom (perhaps as given in the URL)
function moveHere(place){
centerx = place[0];
centery = place[1];
setZoom(place[2]);
}
/////////////////////////
//
// Etc.
//
/////////////////////////
function setChipStyle(props){
for(var i in props){
chipbg.style[i] = props[i];
overlay.style[i] = props[i];
hilite.style[i] = props[i];
hitbuffer.style[i] = props[i];
}
}

BIN
images/fastforward.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

BIN
images/singlestep.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

View File

@ -2,24 +2,47 @@
<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() {
if((navigator.appName == 'Microsoft Internet Explorer') && (parseInt(navigator.appVersion,10)<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);
}
// 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)){
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{
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>
@ -39,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="http://visual6502.org/wiki/index.php?title=JssimUserHelp">User Guide</a>.
<br />
<br />
</span>
@ -56,29 +79,42 @@ 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 />
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 />
Source code is available on <a href="http://github.com/trebonian/visual6502">github visual6502</a>.
Use the online <a href="http://skilldrick.github.com/easy6502/#first-program">emulator and assembler</a> from the easy6502 tutorial
and <a href="http://www.e-tradition.net/bytes/6502/disassembler.html">disassembler</a> from e-tradition.net
<br />
For in-depth 6502 investigation and some more advanced features, try our <a href="expert.html">Advanced</a> page.
<br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-9008420149077488";
/* 728x90, created 9/22/10 */
google_ad_slot = "4303982675";
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</body>
</html>

View File

@ -89,6 +89,6 @@ table.memtable {
}
#title {
font-size:30px;
font-size:30px;
font-weight:bold;
}

200
kioskWires.js Normal file
View File

@ -0,0 +1,200 @@
/*
Copyright (c) 2010 Brian Silverman, Barry Silverman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
var centerx=300, centery=300;
var zoom=1;
var dragMouseX, dragMouseY, moved;
var statbox;
var animateChipLayout = true;
var userCode=[];
var userResetLow;
var userResetHigh;
// Some constants for the graphics presentation
// the canvas is embedded in an 800x600 clipping div
// which gives rise to some of the 300 and 400 values in the code
// there are also some 600 values
// the 6502D chip coords are in the box (216,179) to (8983,9807)
// we have 4 canvases all the same size, now 2000 pixels square
// chip background - the layout
// overlay - a red/white transparency to show logic high or low
// hilite - to show the selected polygon
// hitbuffer - abusing color values to return which polygon is under a point
// we no longer use a scaling transform - we now scale the chip data at
// the point of drawing line segments
// if the canvas is any smaller than chip coordinates there will be
// rounding artifacts, and at high zoom there will be anti-aliasing on edges.
var grMaxZoom=12;
var grChipSize=10000;
var grCanvasSize=2000;
var grLineWidth=1;
// Index of layerNames corresponds to index into drawLayers
var layernames = ['metal', 'switched diffusion', 'inputdiode', 'grounded diffusion', 'powered diffusion', 'polysilicon'];
var colors = ['rgba(128,128,192,0.4)','#FFFF00','#FF00FF','#4DFF4D',
'#FF4D4D','#801AC0','rgba(128,0,255,0.75)'];
var drawlayers = [true, true, true, true, true, true];
/////////////////////////
//
// Drawing Setup
//
/////////////////////////
// try to present a meaningful page before starting expensive work
function setup(){
statbox = document.getElementById('status');
setStatus('loading 6502...');
setTimeout(setup_part2, 0);
}
function setup_part2(){
frame = document.getElementById('frame');
statbox = document.getElementById('status');
setupNodes();
setupTransistors();
setupLayerVisibility();
setupBackground();
setupOverlay();
setupHilite();
setupHitBuffer();
recenter();
refresh();
setupTable();
window.onkeypress = function(e){handleKey(e);}
hilite.onmousedown = function(e){mouseDown(e);}
setStatus('resetting 6502...');
setTimeout(setup_part3, 0);
}
function setup_part3(){
loadProgram();
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];
}
}

603
macros.js
View File

@ -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') +
'&#8209' + // 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,33 @@ 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,'&#8209'));
}
}
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("+");
}
function readBit(name){
return isNodeHigh(nodenames[name])?1:0;
}
@ -175,6 +316,65 @@ 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=='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 +395,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 +411,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 +427,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 +462,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 +616,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(/ /,'&nbsp;');
}
// 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",
};

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

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

36
testprogram.js Normal file
View File

@ -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
];

File diff suppressed because it is too large Load Diff

271
wires.js
View File

@ -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,75 @@ 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+400)/grChipSize*600;
var y=600-ymid/grChipSize*600;
var zoom=5; // pending a more careful calculation
moveHere([x,y,zoom]);
}
function drawSeg(ctx, seg){
if(noGraphics) return;
var dx = 400;
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]));
for(var i=2;i<seg.length;i+=2) ctx.lineTo(grScale(seg[i]+dx), grScale(grChipSize-seg[i+1]));
ctx.lineTo(grScale(seg[0]+dx), grScale(grChipSize-seg[1]));
}
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 +228,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 +255,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;