Permalink
Browse files

Rewrote the interface, prepared the editor for syntax highlighting

  • Loading branch information...
1 parent cf7b518 commit 0016060156fdfa69f18b8fe7d21101724d29b6ae @deNULL committed May 22, 2012
Showing with 730 additions and 6,155 deletions.
  1. +0 −4,960 css/bootstrap-2.0.3.css
  2. +268 −138 css/dcpu.css
  3. +0 −234 css/play.css
  4. +0 −186 dcpu.htm
  5. +141 −0 index.htm
  6. +89 −32 js/assembler.js
  7. +71 −0 js/common.js
  8. +1 −1 js/keyboard.js
  9. +0 −424 js/play.js
  10. +160 −40 js/ui.js
  11. +0 −140 play.html
View
4,960 css/bootstrap-2.0.3.css
0 additions, 4,960 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
406 css/dcpu.css
@@ -1,210 +1,340 @@
-body, button {
- font-family: Verdana, Tahoma, sans-serif;
- font-size: 14px;
-}
-button.big {
- font-size: 20px;
- width: 160px;
- height: 40px;
- text-align: left;
- margin: 4px;
-}
-.filewrap {
- margin: 6px 6px 0px 0px;
- position: relative;
- display: inline-block;
-}
-.filewrap .file {
- position: absolute;
- opacity: 0;
- -moz-opacity: 0;
- filter:alpha(opacity=0);
+html, body, #layout, #asm_wrap, #dasm_wrap {
+ padding: 0;
margin: 0;
- width: 100%;
height: 100%;
- z-index: -100;
+ border: none;
+}
+body, button {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+ color: #333;
}
-
h3 {
- font-size: 22px;
- margin-bottom: 0px;
+ margin: 0;
+ padding: 4px 0;
+ font-size: 18px;
+ height: 22px;
+ font-family: inherit;
+ font-weight: bold;
+ color: inherit;
+ text-rendering: optimizelegibility;
+}
+#header h3 {
+ overflow: hidden;
+ white-space: nowrap;
+}
+h4 {
+ margin: 14px 0px 7px 0px;
+ padding: 0 12px;
+ font-size: 15px;
}
table td {
position: relative;
}
+button {
+ font-size: 15px;
+ padding: 5px 10px;
+ margin: 6px 0 4px 2px;
+ background: #EAECEA;
+ color: #222 !important;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ border: solid 1px #aaa;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 1px 1px rgba(0, 0, 0, 0.2);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 1px 1px rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 1px 1px rgba(0, 0, 0, 0.2);
+ -webkit-transition-duration: 0.2s;
+ -moz-transition-duration: 0.2s;
+ transition-duration: 0.2s;
+ -webkit-user-select:none;
+ -moz-user-select:none;
+ -ms-user-select:none;
+ user-select:none;
+ cursor: pointer;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ text-decoration: none;
+ text-align: left;
+}
+button.big {
+ width: 124px;
+ height: 35px;
+}
+button.green {
+ background: #afa;
+}
+button:hover {
+ background: #dddddd;
+ border: solid 1px #999;
+ text-decoration: none;
+}
+button.green:hover {
+ background: #beb;
+}
+button:active {
+ -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
+ -moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
+ box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
+ background: #a9a9a9;
+ border: solid 1px #777;
+}
+button.green:active {
+ background: #6c6;
+}
+button:disabled:active, button:disabled {
+ background: #fAfCfA;
+ color: #aaa !important;
+ border: solid 1px #eee;
+}
.editor, .editor td {
font-family: Monaco, Lucida Console, Andale Mono, Courier New, Courier, monospace;
- font-size: 14px;
+ font-size: 13px;
line-height: 19px;
margin: 0;
}
-#linenums {
- padding: 2px 0px 2px 0px;
+.tabs {
+ clear: left;
+}
+.tab_active {
+ background-color: #8AE;
+ color: white;
+ padding: 2px 7px;
+ text-decoration: none;
+ border-radius: 4px 4px 0px 0px;
+ margin: 0;
+}
+.tab_inactive {
+ background-color: #FFF;
+ color: #57C;
+ padding: 2px 7px;
+ text-decoration: none;
+ border-radius: 4px 4px 0px 0px;
+ margin: 0;
+}
+.notice {
+ color: gray;
+ font-size: 10pt;
+ font-weight: normal;
+ margin-left: 10px;
+}
+.column {
+ position: relative;
+ min-height: 100%;
+}
+.fl_l {
+ float: left;
+}
+.fl_r {
+ float: right;
+}
+.clear {
+ clear: both;
+}
+.line_highlight {
+ background-color: #aaffaa;
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 19px;
+ z-index: -1000;
+}
+#header {
+ height: 48px;
+ margin-left: 6px;
+}
+#tab0_content, #tab1_content {
+ border: 1px solid #CCC;
+ border-width: 1px 0;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ height: 100%;
+ max-height: 100%;
+}
+#tab1_content {
+ display: none;
+}
+#asm_lines_wrap, #dasm_lines_wrap {
+ z-index: 2000;
+ background-color: #eee;
+}
+#asm_lines, #dasm_lines {
+ width: 50px;
text-align: right;
color: gray;
}
-#linenums u {
- margin: 1px 1px 2px 1px;
- padding: 1px 11px;
+#asm_lines u {
+ -moz-user-select: -moz-none;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ margin: 0px 1px 2px 1px;
+ padding: 0 11px;
+ border: 1px solid transparent;
+ border-radius: 3px;
line-height: 15px;
text-decoration: none;
display: block;
cursor: pointer;
}
-#linenums u.breakpoint {
- padding: 0px 10px;
+#asm_lines u.breakpoint {
background-color: #adf;
border: 1px solid #3ab;
- border-radius: 3px;
}
-#offsets {
- padding: 4px 10px 2px 24px;
+#asm_offsets, #dasm_offsets {
+ width: 50px;
+ padding: 1px 10px 2px 24px;
color: gray;
}
-#da_lines {
- padding: 4px 10px 2px 24px;
- color: gray;
-}
-#code {
- width: 100%;
- min-width: 500px;
+#asm_code, #dasm_dump {
+ display: block;
+ border: none;
+ padding: 0;
+ margin: 0;
+ overflow-y: hidden;
+ overflow-x: auto;
+ height: 100%;
+ min-height: 100%;
background-color: transparent;
-}
-#da_input {
- width: 100%;
- min-width: 200px;
-}
-#dump {
+ resize: none;
+ cursor: text;
+ white-space: nowrap;
+ border: 1px solid #CCC;
+ border-width: 0px 1px 0px 1px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+#asm_dump_wrap, #dasm_code_wrap {
+ z-index: 2000;
+}
+#dasm_code_wrap {
+ max-width: 35%;
+}
+#asm_dump, #dasm_code {
overflow-x: auto;
overflow-y: visible;
white-space: nowrap;
- padding: 4px;
- width: 300px;
+ padding:1px;
+ width: 200px;
}
-#da_code {
- padding: 4px;
-}
-#log {
- padding-top: 6px;
+#dasm_code {
+ width: 600px;
}
-#log .line {
- color: gray;
+
+#controls {
+ width: 392px;
}
-#log .fatal {
- font-weight: bold;
- color: #900;
+#info_panel {
+ width: 392px;
}
-#memory_wrapper {
+
+#screen_wrapper {
position: relative;
}
-#memory_window {
- overflow-y: scroll;
- width: 400px;
- height: 304px;
-}
-#memory_stub {
- height: 8480px;
-}
-#memory_view {
- position: relative;
- float: left;
- top: 0px;
- left:0px;
+#screen {
+ background-color: black;
+ padding: 4px;
}
-#memory_lines {
- position: relative;
- float: left;
+#loading_overlay {
+ position: absolute;
top: 0px;
left: 0px;
- padding-right: 6px;
- color: gray;
+ margin: 4px;
+}
+
+#cycles_wrap {
+ width: 200px;
+ margin-top: 12px;
+}
+#cycles_wrap .reg_name {
+ padding-left: 12px;
+ width: 94px;
+}
+
+#registers {
+ width: 400px;
}
.reg_name {
+ width: 30px;
+ height: 25px;
padding-left: 20px;
font-weight: bold;
color: gray;
}
-.cur_sp {
+.reg_value {
+ width: 40px;
+ padding-left: 4px;
+}
+#regSP, #memSP {
background-color: #aaaaff;
text-decoration: none;
}
-.cur_pc {
+#regPC, #memPC {
background-color: #aaffaa;
text-decoration: none;
}
-.line_highlight {
- background-color: #aaffaa;
- position: absolute;
- left: 0;
- top: 0;
- width: 100%;
- height: 19px;
- z-index: -1000;
-}
-.hlight_wrap {
+
+#memory_wrapper {
+ padding-left: 7px;
position: relative;
+ overflow-y: scroll;
+ width: 385px;
+ height: 304px;
}
-#screen {
- background-color: black;
- padding: 4px;
+#memory_content {
+ height: 8480px;
}
-.notice {
- margin: 6px 0px 10px 0px;
- color: gray;
- font-size: 14px;
+#memory_view {
+ position: relative;
+ top: 0px;
+ left:0px;
}
-.notice a {
- color: black;
+#memory_lines {
+ position: relative;
+ top: 0px;
+ left: 0px;
+ padding-right: 6px;
+ color: gray;
}
-#tab1_wrapper {
- display: none;
+#disassemble_dump {
+ float: right;
+ margin: 12px 10px 0 0;
+ padding: 2px 10px;
}
-#da_code .op, #log .op {
+
+#dasm_code .op, #log .op {
font-weight: bold;
color: #700;
}
-#da_code .reg, #log .reg {
+#dasm_code .reg, #log .reg {
font-weight: bold;
color: #070;
}
-#da_code .lit, #log .lit {
+#dasm_code .lit, #log .lit {
color: #007;
}
-#da_code .kw, #log .kw {
+#dasm_code .kw, #log .kw {
color: #077;
}
-#da_code .lbl, #log .lbl {
+#dasm_code .lbl, #log .lbl {
color: #707;
}
-.tabs {
- margin-bottom: 2px;
-}
-.tab_active {
- background-color: #8AE;
- color: white;
- padding: 2px 7px;
- text-decoration: none;
- border-radius: 4px 4px 0px 0px;
- margin: 0px 5px;
-}
-.tab_inactive {
- background-color: #FFF;
- color: #57C;
- padding: 2px 7px;
- text-decoration: none;
- border-radius: 4px 4px 0px 0px;
- margin: 0px 5px;
-}
-#disassembleDump {
- float: right;
- margin-top: 19px;
+
+#log {
+ float: left;
+ padding-top: 6px;
+ height: 48px;
}
-#screen_wrapper {
- position: relative;
+#log .line {
+ color: gray;
}
-#loading_overlay {
- position: absolute;
- top: 0px;
- left: 0px;
- margin: 4px;
+#log .fatal {
+ font-weight: bold;
+ color: #900;
}
View
234 css/play.css
@@ -1,234 +0,0 @@
-html {
- height: 100%;
- overflow-y: hidden;
-}
-body {
- margin: 1em;
- height: 100%;
- overflow-y: hidden;
-}
-a {
- text-decoration: none !important;
-}
-.mono {
- font-family: monospace;
- font-size: 14px;
- line-height: 20px;
-}
-
-/* override bootstrap */
-.row-fluid [class*="span"] {
- min-height: 1px;
-}
-
-#header {
- padding-bottom: 1em;
-}
-
-.main {
- overflow-y: no-display;
-}
-
-.tabs {
- margin-left: 0px !important;
- padding: 0px 10px;
- top: 4em;
-}
-.tab {
- font-size: 12pt;
- padding: 2px 7px;
- border-radius: 4px 4px 0px 0px;
- margin: 0px 1px;
- min-height: 0px; /* override bootstrap */
-}
-.tab_active {
- background-color: #8AE;
- color: white !important;
- text-decoration: none;
-}
-.tab_inactive {
- background-color: #eee;
- color: #57C !important;
-}
-
-/* in order to make the left panel scroll, all enclosing divs must be 100% height */
-.noscroll {
- height: 100%;
- overflow-y: no-display;
-}
-.tab_content {
- height: 100%;
- overflow-y: scroll;
- position: relative; /* so highlight line will work */
-}
-#tab1_wrapper {
- display: none;
-}
-#tab2_wrapper {
- display: none;
- overflow-y: scroll;
- position: relative;
-}
-
-.linenums {
- padding-left: 0px;
- padding-top: 5px;
- display: block;
- text-align: right;
- color: gray;
-}
-.pointer {
- cursor: pointer;
-}
-.linenums .breakpoint {
- background-color: #adf;
- border: 1px solid #3ab;
- border-radius: 3px;
- padding-top: 0px;
- padding-bottom: 0px;
- padding-right: 4px;
-}
-.linenum {
- margin-left: 1.0em !important;
- display: block;
- line-height: 18px;
- padding-top: 1px;
- padding-bottom: 1px;
- padding-right: 5px;
-}
-.addr {
- margin-left: 0px !important;
-}
-.dump {
- margin-left: 1.0em !important;
- padding-top: 6px;
- white-space: nowrap;
- text-align: left;
- overflow-x: hidden;
-}
-
-#line_highlight {
- background-color: #afa;
- position: absolute;
- left: 0;
- top: 6px;
- width: 100%;
- height: 20px;
- z-index: -1000;
-}
-
-.editor_div {
- margin-left: 0.5em !important;
-}
-.editor {
- color: black;
- width: 100%;
- min-height: 20em;
- background-color: transparent;
-}
-
-#md_view {
- position: relative;
- top: 0px;
- left: 0px;
- height: 8807px;
-}
-#md_lines {
- position: relative;
- top: 0px;
-}
-#md_dump {
- position: relative;
- top: 0px;
- left: 0px;
- border: solid 2px #ccc;
- border-radius: 2px;
- padding-top: 3px;
- padding-left: 0.5em;
-}
-
-.screen_frame {
- position: relative;
-}
-#screen {
- background-color: black;
- padding: 10px;
-}
-#loading_overlay {
- position: absolute;
- top: 0px;
- left: 0px;
- margin: 10px;
-}
-.notice {
- marginx: 6px 0px 10px 0px;
- color: gray;
- font-size: 10pt;
-}
-
-.buttons {
- margin-top: 1em;
-}
-.buttons button {
- font-size: 14px;
- font-weight: bold;
- width: 100%;
- text-align: left;
- padding: 10px 10px;
-}
-
-.registers {
- margin-top: 1em;
-}
-.registers table {
- margin-top: 0.5em;
-}
-.registers td {
- margin: 0px;
- padding: 2px;
-}
-.registers td.reg_name {
- padding-right: 5px;
- padding-left: 25px;
- font-weight: bold;
- color: gray;
-}
-.cur_sp {
- background-color: #aaaaff;
- text-decoration: none;
-}
-.cur_pc {
- background-color: #aaffaa;
- text-decoration: none;
-}
-.registers td.cycles {
- color: gray;
- text-align: right;
-}
-
-#disassemble {
- padding: 5px 10px;
- margin-top: 1em;
-}
-
-#log_frame {
- position: relative;
-}
-#log {
- position: fixed;
- left: 0px;
- bottom: 0px;
- font-family: monospace;
- font-size: 14px;
- padding: 1em;
- min-height: 4em;
- border-top: solid 1px gray;
- background-color: white;
-}
-#log .line {
- color: gray;
-}
-#log .fatal {
- font-weight: bold;
- color: #900;
-}
View
186 dcpu.htm
@@ -1,186 +0,0 @@
-<html>
-<head>
- <title>DCPU-16 emulator</title>
- <link rel="stylesheet" href="css/dcpu.css">
- <script type="text/javascript" src="js/common.js?v=1"></script>
- <script type="text/javascript" src="js/assembler.js?v=5"></script>
- <script type="text/javascript" src="js/disassembler.js?v=3"></script>
- <script type="text/javascript" src="js/emulator.js?v=2"></script>
- <script type="text/javascript" src="js/clock.js?v=1"></script>
- <script type="text/javascript" src="js/screen.js?v=1"></script>
- <script type="text/javascript" src="js/keyboard.js?v=1"></script>
- <script type="text/javascript">
- var _gaq = _gaq || [];
- _gaq.push(['_setAccount', 'UA-31249994-1']);
- _gaq.push(['_setDomainName', 'dcpu.ru']);
- _gaq.push(['_setAllowLinker', true]);
- _gaq.push(['_trackPageview']);
-
- (function() {
- var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
- ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
- var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
- })();
- </script>
- <style>
- </style>
-</head>
-<body>
- <h3>DCPU-16 Assembler, Emulator &amp; Disassembler</h3>
- <div class="notice">by deNULL. Report any problems at <a href="mailto:me@denull.ru">me@denull.ru</a>.</div>
-
- <table width="100%" border=0 cellpadding=0 cellspacing=0 style="padding-top: 6px"><tr valign=top>
- <td width="80%">
- <div class="tabs"><a href="javascript:" onclick="toggleTab(0)" class="tab_active" id="tab0">Assembler</a><a href="javascript:" onclick="toggleTab(1)" class="tab_inactive" id="tab1">Disassembler</a></div>
- <div id="tab0_wrapper">
- <table width="100%" id="assembler" cellpadding=0 cellspacing=0><tr valign=top>
- <td width="20"><div class="hlight_wrap"><div class="line_highlight" id="hlight1"></div></div><div class="editor" id="linenums"></div></td>
- <td width="60%"><div class="hlight_wrap"><div class="line_highlight" id="hlight2"></div></div><textarea class="editor" id="code" onkeyup="assemble()" onchange="assemble()" wrap=off spellcheck="false" placeholder="Place your code here"><?php
-$default_code = <<<EOF
- ; Try some basic stuff
- SET A, 0x30 ; 7c01 0030
- SET [0x1000], 0x20 ; 7de1 1000 0020
- SUB A, [0x1000] ; 7803 1000
- IFN A, 0x10 ; c00d
- SET PC, crash ; 7dc1 001a [*]
-
- ; Do a loopy thing
- SET I, 10 ; a861
- SET A, 0x2000 ; 7c01 2000
- :loop SET [0x2000+I], [A] ; 2161 2000
- SUB I, 1 ; 8463
- IFN I, 0 ; 806d
- SET PC, loop ; 7dc1 000d [*]
-
- ; Call a subroutine
- SET X, 0x4 ; 9031
- JSR testsub ; 7c10 0018 [*]
- SET PC, crash ; 7dc1 001a [*]
-
- :testsub SHL X, 4 ; 9037
- SET PC, POP ; 61c1
-
- ; Hang forever. X should now be 0x40 if everything went right.
- :crash SET PC, crash ; 7dc1 001a [*]
-
- ; [*]: Note that these can be one word shorter and one cycle faster by using the short form (0x00-0x1f) of literals,
- ; but my assembler doesn't support short form labels yet.
-EOF;
-$code = $default_code;
-if (isset($_REQUEST['code'])) {
- $code = $_REQUEST['code'];
-}
-echo htmlspecialchars($code);?></textarea>
-</td>
- <!--
- ; Assembler test for DCPU
- ; by Markus Persson
-
- :start
- set i, 0
- set j, 0
- set b, 0xf100
- :nextchar
- set a, [data+i]
- ife a, 0
- set PC, end
- ifg a, 0xff
- set PC, setcolor
- bor a, b
- set [0x8000+j], a
- add i, 1
- add j, 1
- set PC, nextchar
-
- :setcolor
- set b, a
- and b, 0xff
- shl b, 8
- ifg a, 0x1ff
- add b, 0x80
- add i, 1
- set PC, nextchar
-
-
- :data
- dat 0x170, "Hello ", 0x2e1, "world", 0x170, ", how are you?"
-
- :end
- set PC, start
- -->
- <td width="30"><div class="hlight_wrap"><div class="line_highlight" id="hlight3"></div></div><div class="editor" id="offsets"></div></td>
- <td width="40%"><div class="hlight_wrap"><div class="line_highlight" id="hlight4"></div></div><div class="editor" id="dump"></div></td>
- </tr>
-<tr valign=top><td></td><td colspan=3>
-<!--<button id="loadsrc" onclick="ge('savesrc_f').click();">Load source...</button>
-<button onclick="ge('savesrc_f').click();" id="savesrc">Save source...</button>
-<button onclick="ge('savebin_f').click();" id="savebin">Save assembled code...</button>-->
-<span class="notice">Click on the line numbers to toggle breakpoints.</span>
-</td></tr>
- </table>
- </div>
- <div id="tab1_wrapper">
- <table width="100%" id="disassembler" cellpadding=0 cellspacing=0><tr valign=top>
- <td width="40%"><textarea class="editor" id="da_input" onkeyup="disassemble()" onchange="disassemble()" wrap=off placeholder="Place your hex codes here"></textarea></td>
- <td width="30"><div class="editor" id="da_lines"></div></td>
- <td width="60%"><div class="editor" id="da_code"></div></td>
- </tr>
-<tr valign=top><td colspan=3>
-<!--<button onclick="loadbin()" id="loadbin">Load binary...</button>
-<button onclick="savebin2()" id="savebin2">Save binary...</button>
-<button onclick="savedisasm()" id="savedisasm">Save disassembled code...</button>-->
-</td></tr>
- </table>
- </div>
- </td>
- <td rowspan=2 width="20%" id="debugger" style="padding-left: 20px">
- <span>Cycles: </span><span id="cycles">0</span><br/>
- <button onclick="run(this)" id="button_run" class="big"/>&#8595; Run (F5)</button><button onclick="step()" class="big"/>&#8618; Step (F6)</button><button onclick="reset()" class="big">&#8634; Reset</button><br/>
- <label for="show_pc"><input type="checkbox" id="show_pc" name="show_pc" checked="checked" onchange="toggleShowPC()"/> Show current line</label>
- <h4>Screen:</h4>
- <div id="screen_wrapper">
- <canvas id="screen" width="384" height="288"></canvas>
- <img id="loading_overlay" src="http://i.imgur.com/DcNzS.png" width="384" height="288"/>
- </div>
- <div class="notice">Keyboard input is available while the program is running.</div>
- <h4>Registers:</h4>
- <table border=0 class="editor">
- <tr>
- <td class="reg_name">PC:</td><td id="regPC" class="cur_pc">0</td>
- <td class="reg_name">SP:</td><td id="regSP" class="cur_sp">0</td>
- <td class="reg_name">IA:</td><td id="regIA" class="cur_ia">0</td>
- </tr> <tr>
- <td class="reg_name">A:</td><td id="regA">0</td>
- <td class="reg_name">B:</td><td id="regB">0</td>
- <td class="reg_name">C:</td><td id="regC">0</td>
- </tr> <tr>
- <td class="reg_name">X:</td><td id="regX">0</td>
- <td class="reg_name">Y:</td><td id="regY">0</td>
- <td class="reg_name">Z:</td><td id="regZ">0</td>
- </tr> <tr>
- <td class="reg_name">I:</td><td id="regI">0</td>
- <td class="reg_name">J:</td><td id="regJ">0</td>
- </tr> <tr>
- <td class="reg_name">EX:</td><td id="regEX">0</td>
- </tr>
- </table>
-
- <button onclick="disassembleDump()" id="disassembleDump">Disassemble</button>
- <h4>Memory dump:</h4>
- <div id="memory_wrapper">
- <div id="memory_window" onscroll="updateMemoryView()">
- <div id="memory_stub">
- <div id="memory_lines" class="editor"></div>
- <div id="memory_view" class="editor"></div></div>
- </div>
- </div>
- </td>
- </tr><tr valign=top>
- <td colspan=3>
- <div id="log" class="editor"></div></td>
- </tr></table>
- <canvas id="fontCanvas" style="display: none"></canvas>
- <script language="javascript" src="js/ui.js?v=1">
- </script>
-</body>
-</html>
View
141 index.htm
@@ -0,0 +1,141 @@
+<html>
+<head>
+ <title>DCPU-16 emulator</title>
+ <meta name="viewport" content="width = 1300">
+ <link rel="stylesheet" href="css/dcpu.css">
+ <script type="text/javascript" src="js/common.js?v=1"></script>
+ <script type="text/javascript" src="js/assembler.js?v=5"></script>
+ <script type="text/javascript" src="js/disassembler.js?v=3"></script>
+ <script type="text/javascript" src="js/emulator.js?v=2"></script>
+ <script type="text/javascript" src="js/clock.js?v=1"></script>
+ <script type="text/javascript" src="js/screen.js?v=1"></script>
+ <script type="text/javascript" src="js/keyboard.js?v=1"></script>
+ <script type="text/javascript">
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-31249994-1']);
+ _gaq.push(['_setDomainName', 'dcpu.ru']);
+ _gaq.push(['_setAllowLinker', true]);
+ _gaq.push(['_trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+ })();
+ </script>
+</head>
+<body spellcheck="false" onresize="updateSizes()" onload="updateSizes()">
+ <div id="controls" class="fl_r">
+ <button onclick="run(this)" id="button_run" class="big green"/>&#8595; Run (F5)</button>
+ <button onclick="step()" class="big"/>&#8618; Step (F6)</button>
+ <button onclick="reset()" class="big">&#8634; Reset (Esc)</button>
+ </div>
+ <div id="cycles_wrap" class="editor fl_r"><div class="reg_name fl_l">Cycles:</div><div id="cycles" class="reg_value fl_l">0</div></div>
+ <div id="header">
+ <h3>DCPU-16 Assembler, Emulator &amp; Disassembler<span class="notice">by deNULL. In case of problems, write at <a href="mailto:me@denull.ru">me@denull.ru</a> or use <a href="/old/">the old version</a>.</span></h3>
+ <div class="tabs">
+ <a href="javascript:" onclick="toggleTab(0)" class="tab_active" id="tab0">Assembler</a>
+ <a href="javascript:" onclick="toggleTab(1)" class="tab_inactive" id="tab1">Disassembler</a>
+ </div>
+ </div>
+ <div id="info_panel" class="fl_r">
+ <div id="screen_wrapper">
+ <canvas id="screen" width="384" height="288"></canvas>
+ <img id="loading_overlay" src="http://i.imgur.com/DcNzS.png" width="384" height="288"/>
+ </div>
+ <h4>Registers:</h4>
+ <div id="registers" class="editor">
+ <div class="reg_name fl_l">PC:</div><div id="regPC" class="reg_value fl_l">0</div>
+ <div class="reg_name fl_l">SP:</div><div id="regSP" class="reg_value fl_l">0</div>
+ <div class="reg_name fl_l">IA:</div><div id="regIA" class="reg_value fl_l">0</div>
+ <div class="reg_name fl_l">EX:</div><div id="regEX" class="reg_value fl_l">0</div>
+
+ <div class="reg_name fl_l clear">A:</div><div id="regA" class="reg_value fl_l">0</div>
+ <div class="reg_name fl_l">B:</div><div id="regB" class="reg_value fl_l">0</div>
+ <div class="reg_name fl_l">C:</div><div id="regC" class="reg_value fl_l">0</div>
+
+ <div class="reg_name fl_l clear">X:</div><div id="regX" class="reg_value fl_l">0</div>
+ <div class="reg_name fl_l">Y:</div><div id="regY" class="reg_value fl_l">0</div>
+ <div class="reg_name fl_l">Z:</div><div id="regZ" class="reg_value fl_l">0</div>
+
+ <div class="reg_name fl_l clear">I:</div><div id="regI" class="reg_value fl_l">0</div>
+ <div class="reg_name fl_l">J:</div><div id="regJ" class="reg_value fl_l">0</div>
+ </div>
+ <div style="clear: both"></div>
+ <button onclick="disassembleDump()" id="disassemble_dump">Disassemble</button>
+ <h4>Memory dump:</h4>
+ <div id="memory_wrapper" onscroll="updateMemoryView()">
+ <div id="memory_content">
+ <div id="memory_lines" class="editor fl_l"></div>
+ <div id="memory_view" class="editor fl_l"></div>
+ </div>
+ </div>
+ </div>
+ <div id="tab0_content">
+ <div id="asm_lines_wrap" class="column fl_l">
+ <div class="editor" id="asm_lines"></div>
+ </div>
+ <div id="asm_dump_wrap" class="column fl_r">
+ <div class="editor" id="asm_dump"></div>
+ </div>
+ <div class="column fl_r">
+ <div class="editor" id="asm_offsets"></div>
+ </div>
+ <div class="column">
+ <div class="line_highlight" id="asm_hlight"></div>
+ <div class="editor" id="asm_code" wrap="off" spellcheck="false" onkeyup="assemble()" onkeydown="assemble()" onselect="assemble()" onkeypress="assemble()" onmouseup="assemble()" onchange="assemble()" contentEditable="true" autocomplete="off"><?php
+$default_code = <<<EOF
+ ; Try some basic stuff
+ SET A, 0x30 ; 7c01 0030
+ SET [0x1000], 0x20 ; 7de1 1000 0020
+ SUB A, [0x1000] ; 7803 1000
+ IFN A, 0x10 ; c00d
+ SET PC, crash ; 7dc1 001a [*]
+
+ ; Do a loopy thing
+ SET I, 10 ; a861
+ SET A, 0x2000 ; 7c01 2000
+ :loop SET [0x2000+I], [A] ; 2161 2000
+ SUB I, 1 ; 8463
+ IFN I, 0 ; 806d
+ SET PC, loop ; 7dc1 000d [*]
+
+ ; Call a subroutine
+ SET X, 0x4 ; 9031
+ JSR testsub ; 7c10 0018 [*]
+ SET PC, crash ; 7dc1 001a [*]
+
+ :testsub SHL X, 4 ; 9037
+ SET PC, POP ; 61c1
+
+ ; Hang forever. X should now be 0x40 if everything went right.
+ :crash SET PC, crash ; 7dc1 001a [*]
+
+ ; [*]: Note that these can be one word shorter and one cycle faster by using the short form (0x00-0x1f) of literals,
+ ; but my assembler doesn't support short form labels yet.
+EOF;
+$code = $default_code;
+if (isset($_REQUEST['code'])) {
+ $code = $_REQUEST['code'];
+}
+echo htmlspecialchars($code);?></div>
+ </div>
+ </div>
+ <div id="tab1_content">
+ <div id="dasm_lines_wrap" class="column fl_l">
+ <div class="editor" id="dasm_lines"></div>
+ </div>
+ <div class="column fl_r">
+ <div class="editor" id="dasm_offsets"></div>
+ </div>
+ <div id="dasm_code_wrap" class="column fl_r">
+ <div class="editor" id="dasm_code"></div>
+ </div>
+ <div class="editor" id="dasm_dump" wrap="off" spellcheck="false" onkeyup="disassemble()" onkeydown="disassemble()" onselect="disassemble()" onkeypress="disassemble()" onmouseup="disassemble()" onchange="disassemble()" contentEditable="true" autocomplete="off"></div>
+ </div>
+ <div id="log" class="editor">
+
+ </div>
+ <script language="javascript" src="js/ui.js?v=1"></script>
+</body>
+</html>
View
121 js/assembler.js
@@ -71,7 +71,7 @@ var Assembler = {
"hwn", "hwq", "hwi",
"jmp", "brk", "ret", "bra", "dat", "org" ],
- SPACE: { ' ': true, '\n': true, '\r': true, '\t': true }, // to replace charAt(pos).match(/\s/), using regexps is very slow
+ SPACE: { 32: true, 160: true, 13: true, 10: true, 9: true }, // to replace charAt(pos).match(/\s/), using regexps is very slow
/*
* parser state is passed around in a "state" object:
@@ -92,7 +92,7 @@ var Assembler = {
var subst = state.subst;
var logger = state.logger;
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
if (pos == end) {
logger(pos, "Value expected (operand or expression)", true);
return false;
@@ -105,7 +105,7 @@ var Assembler = {
atom = this.parseExpression(state, 0);
if (!atom) return false;
pos = atom.state.pos;
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
if (pos == end || text.charAt(pos) != ')') {
logger(pos, "Missing ) on expression", true);
return false;
@@ -168,7 +168,7 @@ var Assembler = {
var end = state.end;
var logger = state.logger;
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
if (pos == end) {
logger(pos, "Expression expected", true);
return false;
@@ -178,7 +178,7 @@ var Assembler = {
pos = left.state.pos;
while (true) {
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
if (pos == end || text.charAt(pos) == ')') return left;
var newprec = this.BINARY[text.charAt(pos)];
@@ -293,7 +293,7 @@ var Assembler = {
// manually find position of expression, for displaying nice error messages.
var pos = text.indexOf('=') + 1;
- while (this.SPACE[text.charAt(pos)]) pos++;
+ while (this.SPACE[text.charCodeAt(pos)]) pos++;
var state = { text: text, pos: pos, end: text.length, subst: subst, logger: logger };
var expr = this.parseExpression(state, 0);
if (expr) {
@@ -313,13 +313,16 @@ var Assembler = {
* - arg_ends (array): positions of the end of operands within the text
*/
parseLine: function(text, macros, subst, logger) {
+ var ppos = 0;
var pos = 0;
+ var pend = text.length;
var end = text.length;
- var line = { text: text, pos: pos, end: end, args: [] };
+ var line = { text: text, pos: pos, end: end, args: [], syntax: "", syntax_end: "" };
// strip comments so we don't have to worry about them
var in_string = false;
- var in_char = false
+ var in_char = false;
+
for (var i = 0; i < text.length; i++) {
if (in_string && text.charAt(i) == '\\' && i < text.length - 1) {
i++;
@@ -328,12 +331,16 @@ var Assembler = {
} else if (text.charAt(i) == '\'' && !in_string) {
in_char = !in_char;
} else if (text.charAt(i) == ';' && !in_string && !in_char) {
+ line.syntax_end = wrapAs(text.substr(i), "comm");
end = i;
break;
}
}
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
+
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
+ line.syntax += text.substring(ppos, pos);
+ ppos = pos;
if (pos >= end) return line;
if (text.charAt(pos) == ":") {
@@ -346,9 +353,14 @@ var Assembler = {
}
line.label = line.label[0].toLowerCase();
pos += line.label.length;
+
+ line.syntax += wrapAs(text.substr(ppos, pos), "lbl");
+ ppos = pos;
}
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
+ line.syntax += text.substring(ppos, pos);
+ ppos = pos;
if (pos >= end) return line;
if (text.charAt(pos) == "#") {
@@ -362,7 +374,12 @@ var Assembler = {
line.directive = line.directive[0].toLowerCase();
pos += line.directive.length;
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
+ line.syntax += wrapAs(text.substr(ppos, pos), "dir");
+ ppos = pos;
+
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
+ line.syntax += text.substring(ppos, pos);
+ ppos = pos;
if (pos >= end) return line;
if (line.directive == "macro") {
@@ -375,13 +392,18 @@ var Assembler = {
line.macro = line.macro[0].toLowerCase();
pos += line.macro.length;
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
- while (pos < end && this.SPACE[text.charAt(end - 1)]) end--;
+ line.syntax += wrapAs(text.substr(ppos, pos), "macro");
+ ppos = pos;
+
+ line.syntax += text.substr(pos, end) + wrapAs(comment, "comm");
+
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
+ while (pos < end && this.SPACE[text.charCodeAt(end - 1)]) end--;
if (text.charAt(end - 1) == "{") {
line.start_block = true;
end--;
}
- while (pos < end && this.SPACE[text.charAt(end - 1)]) end--;
+ while (pos < end && this.SPACE[text.charCodeAt(end - 1)]) end--;
if (text.charAt(pos) == "(" && text.charAt(end - 1) == ")") {
pos++;
end--;
@@ -405,7 +427,12 @@ var Assembler = {
}
line.define = line.define[0].toLowerCase();
pos += line.define.length;
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
+ line.syntax += wrapAs(text.substr(ppos, pos), "def");
+ ppos = pos;
+
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
+ line.syntax += text.substring(ppos, pos);
+ ppos = pos;
if (pos >= end) return line;
}
} else {
@@ -417,7 +444,9 @@ var Assembler = {
line.end_block = true;
pos++;
}
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
+ line.syntax += text.substring(ppos, pos);
+ ppos = pos;
if (pos >= end) return line;
var word = text.substr(pos, end - pos).match(/^[^ (]+/);
@@ -428,8 +457,11 @@ var Assembler = {
line.op = word[0].toLowerCase();
pos += line.op.length;
- while (pos < end && this.SPACE[text.charAt(pos)]) pos++;
- while (pos < end && this.SPACE[text.charAt(end - 1)]) end--;
+ line.syntax += wrapAs(text.substring(ppos, pos), "op");
+ ppos = pos;
+
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
+ while (pos < end && this.SPACE[text.charCodeAt(end - 1)]) end--;
if (subst[line.op] !== undefined) {
line.op = subst[line.op];
}
@@ -440,38 +472,57 @@ var Assembler = {
end--;
}
}
+
+ line.syntax += text.substring(ppos, pos);
+ ppos = pos;
+ line.syntax_end = text.substring(end, pend) + line.syntax_end;
+ pend = end;
}
+ while (pos < end && this.SPACE[text.charCodeAt(pos)]) pos++;
+ while (pos < end && this.SPACE[text.charCodeAt(end - 1)]) end--;
+ line.syntax += text.substring(ppos, pos);
+ ppos = pos;
+ line.syntax_end = text.substring(end, pend) + line.syntax_end;
+ pend = end;
+
var args = [ "" ];
var arg_locs = [ -1 ];
var arg_ends = [ -1 ];
var n = 0;
in_string = false;
in_char = false;
for (var i = pos; i < end; i++) {
- if (text.charAt(i) == '\\' && i + 1 < end) {
+ var ch = text.charAt(i);
+ if (!in_string && !in_char && (this.SPACE[text.charCodeAt(i)] || ch == ',' || ch == '(' || ch == ')' || ch == '[' || ch == ']' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%')) {
+ line.syntax += text.substring(ppos, pos);
+ ppos = pos;
+ }
+
+ if (ch == '\\' && i + 1 < end) {
if (arg_locs[n] == -1) arg_locs[n] = i;
- args[n] += text.charAt(i);
- } else if (text.charAt(i) == '"') {
+ args[n] += ch;
+ } else if (ch == '"' && !in_char) {
in_string = !in_string;
- args[n] += text.charAt(i);
- } else if (text.charAt(i) == "\'" && !in_string) {
+ args[n] += ch;
+ } else if (ch == "\'" && !in_string) {
in_char = !in_char;
- args[n] += text.charAt(i);
+ args[n] += ch;
if (arg_locs[n] == -1) arg_locs[n] = i;
- } else if (text.charAt(i) == ',' && !in_string && !in_char) {
+ } else if (ch == ',' && !in_string && !in_char) {
arg_ends[n] = i;
args.push("");
arg_locs.push(-1);
arg_ends.push(-1);
n += 1;
- } else if (text.charAt(i) == ';' && !in_string && !in_char) {
+ } else if (ch == ';' && !in_string && !in_char) {
break;
- } else if (in_string || in_char || text.charAt(i) != ' ') {
+ } else if (in_string || in_char || !this.SPACE[text.charCodeAt(i)]) {
if (arg_locs[n] == -1) arg_locs[n] = i;
- args[n] += text.charAt(i);
+ args[n] += ch;
}
}
+ line.syntax += text.substring(ppos, end);
if (args[n] == "") {
args.pop();
arg_locs.pop();
@@ -486,6 +537,7 @@ var Assembler = {
line.args = args;
line.arg_locs = arg_locs;
line.arg_ends = arg_ends;
+ line.syntax += line.syntax_end;
return line;
},
@@ -597,7 +649,7 @@ var Assembler = {
if (end - pos >= 4 && state.text.substr(pos, 4).toLowerCase() == "pick") {
pick = true;
state.pos += 4;
- while (state.pos < state.end && this.SPACE[state.text.charAt(state.pos)]) state.pos++;
+ while (state.pos < state.end && this.SPACE[state.text.charCodeAt(state.pos)]) state.pos++;
}
var expr = this.parseExpression(state);
@@ -709,7 +761,7 @@ var Assembler = {
compileLine: function(text, org, labels, macros, subst, logger) {
var line = this.parseLine(text, macros, subst, logger);
if (!line) return false;
- var info = { op: line.op, size: 0, dump: [] };
+ var info = { op: line.op, size: 0, dump: [], syntax: line.syntax };
if (macros[" "]) {
if (line.end_block) {
@@ -918,6 +970,7 @@ var Assembler = {
var pc = 0;
var infos = [ ];
var macros = { };
+ var syntax = [ ];
for (var i = 0; i < lines.length && !aborted; i++) {
var l_logger = function(pos, text, fatal) {
@@ -927,7 +980,11 @@ var Assembler = {
labels["."] = pc;
if (!this.parseConstant(lines[i], labels, { }, l_logger)) {
var info = this.compileLine(lines[i], pc, labels, macros, { }, l_logger);
- if (!info) break;
+ if (!info) {
+ syntax.push(lines[i]);
+ break;
+ }
+ syntax.push(info.syntax);
if (pc + info.size > 0xffff) {
l_logger(0, "Code is too big (exceeds 128 KB) &mdash; not enough memory", true);
break;
@@ -960,6 +1017,6 @@ var Assembler = {
}
if (aborted) return false;
- return { infos: infos };
+ return { infos: infos, syntax: syntax };
},
}
View
71 js/common.js
@@ -32,3 +32,74 @@ function bodyMargin() {
function matchHeight(dest, source) {
dest.style.height = computedHeight(source) + "px";
}
+
+function getInputSelection(el) {
+ var start = 0, end = 0, normalizedValue, range,
+ textInputRange, len, endRange;
+
+ if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
+ start = el.selectionStart;
+ end = el.selectionEnd;
+ } else {
+ range = document.selection.createRange();
+
+ if (range && range.parentElement() == el) {
+ len = el.value.length;
+ normalizedValue = el.value.replace(/\r\n/g, "\n");
+
+ // Create a working TextRange that lives only in the input
+ textInputRange = el.createTextRange();
+ textInputRange.moveToBookmark(range.getBookmark());
+
+ // Check if the start and end of the selection are at the very end
+ // of the input, since moveStart/moveEnd doesn't return what we want
+ // in those cases
+ endRange = el.createTextRange();
+ endRange.collapse(false);
+
+ if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
+ start = end = len;
+ } else {
+ start = -textInputRange.moveStart("character", -len);
+ start += normalizedValue.slice(0, start).split("\n").length - 1;
+
+ if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
+ end = len;
+ } else {
+ end = -textInputRange.moveEnd("character", -len);
+ end += normalizedValue.slice(0, end).split("\n").length - 1;
+ }
+ }
+ }
+ }
+
+ return {
+ start: start,
+ end: end
+ };
+}
+
+function getScrollerWidth() {
+ var scr = null;
+ var inn = null;
+ var wNoScroll = 0;
+ var wScroll = 0;
+ scr = document.createElement('div');
+ scr.style.position = 'absolute';
+ scr.style.top = '-1000px';
+ scr.style.left = '-1000px';
+ scr.style.width = '100px';
+ scr.style.height = '50px';
+ scr.style.overflow = 'hidden';
+ inn = document.createElement('div');
+ inn.style.width = '100%';
+ inn.style.height = '200px';
+ scr.appendChild(inn);
+ document.body.appendChild(scr);
+ wNoScroll = inn.offsetWidth;
+ scr.style.overflow = 'auto';
+ wScroll = inn.offsetWidth;
+ document.body.removeChild(
+ document.body.lastChild);
+ return (wNoScroll - wScroll);
+}
View
2 js/keyboard.js
@@ -96,7 +96,7 @@ var Keyboard = {
return false;
}
}
- return true;
+ return false;
},
onkeypress: function(event, queueInterrupt) {
View
424 js/play.js
@@ -1,424 +0,0 @@
-var startup = (new Date()).getTime();
-var cycles = 0;
-var memory = [];
-var registers = {A: 0, B: 0, C: 0, X: 0, Y: 0, Z: 0, I: 0, J: 0, PC: 0, SP: 0, EX: 0, IA: 0};
-var memToLine = {};
-var lineToMem = {};
-var breaks = {};
-var state = { interruptQueue: [ ] };
-var scrollTop = [ ];
-var hardware = [ Clock, Screen, Keyboard ];
-
-function scrollToLine(n) {
- if (!ge("ln" + n)) return;
- var logRects = ge("log").getClientRects();
- var tabRects = ge("tab0_wrapper").getClientRects();
- if (tabRects.length == 0) return;
- var bottom = (logRects.length == 0) ? tabRects[0].bottom : logRects[0].top;
- var top = tabRects[0].top;
- var line = ge("ln" + n).getClientRects()[0];
- if (line.top < top + line.height) {
- ge("tab0_wrapper").scrollTop = (n == 0) ? 0 : (n - 1) * line.height;
- } else if (line.bottom > bottom - line.height) {
- var height_lines = Math.floor((bottom - top) / line.height);
- ge("tab0_wrapper").scrollTop = (n + 2 - height_lines) * line.height;
- }
-};
-
-window.frames[0].onload = function() {
- var imported_text = window.frames[0].document.documentElement.innerText;
- ge("code").value = imported_text;
- reset();
-};
-
-function queueInterrupt(interrupt) {
- DCPU.queueInterrupt(memory, registers, state, hardware, interrupt);
-};
-
-document.onkeydown = function(event) {
- var code = window.event ? event.keyCode : event.which;
- switch (code) {
- case 116: { // F5
- run(ge("button_run"));
- return false;
- }
- case 117: { // F6
- step();
- return false;
- }
- default: { // pass it to program
- if (!runningTimer) return true;
- return Keyboard.onkeydown(event, queueInterrupt);
- }
- }
-};
-
-document.onkeypress = function(event) {
- if (!runningTimer) return true;
- if (event.which == 8) { return false; }
-
- Keyboard.onkeypress(event, queueInterrupt);
-};
-
-document.onkeyup = function(event) {
- if (!runningTimer) return true;
- Keyboard.onkeyup(event, queueInterrupt);
-};
-
-function toggleTab(index) {
- for (var i = 0; i < 3; i++) {
- // save scroll position
- var tab = ge("tab" + i + "_wrapper");
- if (getComputedStyle(tab, "").getPropertyValue("display") != "none") {
- this.scrollTop[i] = tab.scrollTop;
- }
- if (index == i) {
- tab.style.display = "block";
- if (this.scrollTop[i]) tab.scrollTop = this.scrollTop[i];
- } else {
- tab.style.display = "none";
- }
- ge("tab" + i).className = "tab pointer " + ((index == i) ? "tab_active" : "tab_inactive");
- }
-}
-
-function updateRegisters() {
- for (var reg in registers) {
- ge("reg" + reg).innerHTML = pad(parseInt(registers[reg]).toString(16), 4);
- }
- ge("cycles").innerHTML = cycles;
-}
-updateRegisters();
-
-function updateMemoryView() {
- var lns = "";
- var s = "";
- var offs = ge("tab2_wrapper").scrollTop * 8;
- ge("md_lines").style.top = (offs / 8) + "px";
- ge("md_dump").style.top = (offs / 8) + "px";
- for (var addr = offs; (addr < offs + 256) && (addr < 0x10000); addr += 8) {
- lns += pad(addr.toString(16), 4) + ":<br/>";
- for (var j = 0; j < 8; j++) {
- var v = pad(((memory[addr + j] || 0) & 0xffff).toString(16), 4);
- if (((addr + j + 1) & 0xffff) == registers.SP) {
- s += " <u class='cur_sp'>" + v + "</u>";
- } else if (addr + j == registers.PC) {
- s += " <u class='cur_pc'>" + v + "</u>";
- } else {
- s += " " + v;
- }
- }
- s += "<br/>";
- }
- ge("md_lines").innerHTML = lns;
- ge("md_dump").innerHTML = s;
-}
-updateMemoryView();
-
-function positionHighlight(line) {
- var hlight = ge("line_highlight");
- if (line >= 0) {
- hlight.style.top = (line * computedHeight(hlight) + 5) + "px";
- hlight.style.display = "block";
- } else {
- hlight.style.display = "none";
- }
-}
-function updateHighlight(alsoScroll) {
- var line = memToLine[registers.PC] - 1;
- positionHighlight(line);
- if (alsoScroll) this.scrollToLine(line);
-}
-positionHighlight(-1);
-
-function reset() {
- for (var reg in registers) {
- registers[reg] = 0;
- }
- registers.SP = 0;
- cycles = 0;
- keypointer = 0;
- Screen.MAP_SCREEN = 0x8000; // for backward compatability... will be reset to 0 in future
- Screen.MAP_FONT = 0x8180;
- Screen.MAP_PALETTE = 0;
- Screen.BORDER_COLOR = 0;
- state = { interruptQueue: [] };
- assemble();
- updateHighlight();
-}
-var logger = function(offset, msg, fatal) {
- //log.push(pad(line + 1, 5) + ": " + (fatal ? "(Fatal) " : "") + msg);
- if (fatal) clearInterval(runningTimer);
-};
-
-function updateViews(alsoScroll) {
- updateHighlight(alsoScroll);
- updateMemoryView();
- updateRegisters();
- Screen.update(memory);
- document.getElementById("cycles").innerHTML = cycles;
- resizeTabs();
- }
-
-function step() {
- ge('loading_overlay').style.display = 'none';
- var rv = DCPU.step(memory, registers, state, hardware);
- if (rv > 0) {
- cycles += rv;
- }
- updateViews(true);
-}
-
-var runningTimer = false;
-function run(button) {
- ge('loading_overlay').style.display = 'none';
- if (runningTimer) {
- Clock.stop();
- clearInterval(runningTimer);
- runningTimer = false;
- button.innerHTML = "&#8595; Run (F5)";
- updateViews(true);
- } else {
- Clock.start();
- runningTimer = setInterval(function() {
- var was_cycles = cycles;
- for (var i = 0; i < 10000; i++) {
- var rv = DCPU.step(memory, registers, state, hardware);
- if (rv < 0) { // break
- if (runningTimer) run(button);
- return;
- }
- cycles += rv;
- if (!runningTimer) return;
- if (breaks[memToLine[registers.PC] - 1]) {
- run(button);
- return;
- }
- if (cycles > was_cycles + 5213) break;
- }
- updateViews(false);
- }, 50);
- button.innerHTML = "&#215; Stop (F5)";
- }
-}
-function bp(line) {
- breaks[line] = !breaks[line] && (lineToMem[line] !== undefined);
- ge("ln" + line).className = "linenum " + (breaks[line] ? "breakpoint" : "");
-}
-function pad(v, w) {
- var s = "" + v;
- var len = s.length;
- for (var i = 0; i < w - len; i++)
- s = "0" + s;
- return s;
-}
-
-function assemble() {
- var lines = ge("code").value.split("\n");
- var log = [];
-
- var linenums = [];
- for (var i = 0; i < lines.length; i++) {
- linenums.push("<span class=linenum id=ln" + i + " onclick='bp(" + i + ")'>" + (i + 1) + "</span>");
- }
- ge("linenums").innerHTML = linenums.join("");
-
- var logger = function(line, address, pos, message, fatal) {
- log.push("<span class='line'>" + pad(line + 1, 5) + ":</span> " +
- (fatal ? "(<span class='fatal'>Fatal</span>) " : "") +
- message);
- ge("ln" + line).style.backgroundColor = '#f88';
- ge("log").style.display = "block";
- };
- for (var i = 0; i < 0xffff; i++) {
- if (memory[i]) memory[i] = 0;
- }
- Screen.resetFont(memory);
- var rv = Assembler.compile(lines, memory, logger);
-
- // map line # to address, and build up offsets/dump
- memToLine = {};
- lineToMem = {};
- var offsets = [];
- var dump = [];
- if (rv) {
- for (var i = 0; i < lines.length; i++) {
- if (rv.infos[i] === undefined || rv.infos[i].size == 0) {
- offsets.push("");
- dump.push("");
- } else {
- var info = rv.infos[i];
- offsets.push(pad(info.pc.toString(16), 4) + ":");
- lineToMem[i] = info.pc;
- var s = "";
- for (var j = 0; j < info.dump.length; j++) {
- s += pad(info.dump[j].toString(16), 4) + " ";
- memToLine[info.pc + j] = i + 1;
- }
- dump.push(s);
- }
- }
- }
-
- // update UI
- ge("offsets").innerHTML = offsets.join("<br/>");
- ge("dump").innerHTML = dump.join("<br/>");
- ge("log").innerHTML = log.join("<br/>");
- ge("log").style.display = (log.length == 0) ? "none" : "block";
-
- matchHeight(ge("code"), ge("linenums"));
-
- for (var line in breaks) {
- if (breaks[line] && (lineToMem[line] === undefined)) {
- bp(line);
- } else
- ge("ln" + line).className = breaks[line] ? "breakpoint" : "";
- }
- updateViews(false);
-}
-
-function disassemble() {
- var input = ge("da_input").value;
- var linenum = input.split("\n").length;
- var data = [];
- var s = "";
- for (var i = 0; i < input.length; i++) {
- if ("0123456789abcdefABCDEF".indexOf(input.charAt(i)) > -1) {
- s += input.charAt(i);
- if (s.length == 4) {
- data.push(parseInt(s, 16));
- s = "";
- }
- }
- }
-
- var log = [];
- var logger = function(offset, msg, fatal) {
- log.push("<span class='line'>" + pad(offset, 4) + ":</span> " + (fatal ? "(<span class='fatal'>Fatal</span>) " : "") + msg);
- ge("log").style.display = "block";
- if (fatal) aborted = true;
- };
-
- var used = {};
- var code = {};
- var stack = [];
- var conditional = false;
- if (data.length > 0) {
- stack.push(0);
- }
- var labels = {last: 0};
- while (stack.length > 0) {
- var pc = stack.pop();
- if (used[pc]) {
- continue;
- }
- do {
- var info = Disassembler.disassemble(data, pc, labels, function(type, str) {
- return "<span class='" + type + "'>" + str + "</span>";
- }, logger);
-
- if (info.branch !== undefined) {
- stack.push(info.branch);
- }
- for (var i = pc; i < pc + info.size; i++) {
- used[i] = true;
- }
- if (info.code !== undefined) {
- code[pc] = (conditional ? "&nbsp;&nbsp;" : "") + info.code;
- }
- pc += info.size;
- if (conditional) {
- info.terminal = false;
- }
- conditional = info.conditional;
- } while (pc < data.length && !info.terminal);
- }
-
- var lines = [];
- var output = [];
- for (var i = 0; i < data.length; i++) {
- if (labels[i]) {
- lines.push("");
- output.push("");
- lines.push("");
- output.push(":" + wrapAs(labels[i], "lbl"));
- }
- if (code[i] !== undefined) {
- lines.push(pad(i.toString(16), 4) + ":");
- output.push("&nbsp;&nbsp;" + code[i]);
- } else if (!used[i]) {
- var words = [];
- var all_zeros = true;
- var old_i = i;
- while (i < data.length && !used[i]) {
- words.push(wrapAs("0x" + pad(data[i].toString(16), 4), "lit"));
- if (data[i]) all_zeros = false;
- i++;
- }
- if (all_zeros) {
- if (i < data.length) {
- lines.push("");
- lines.push("");
- output.push("");
- output.push(wrapAs("ORG", "op") + " " + wrapAs("0x" + pad(i.toString(16), 4), "lit"));
- }
- } else {
- lines.push(pad(old_i.toString(16), 4) + ":");
- output.push("&nbsp;&nbsp;" + wrapAs("DAT", "op") + " " + words.join(", "));
- }
- i--;
- }
- }
-
- // update UI
- ge("da_lines").innerHTML = lines.join("<br/>");
- ge("da_code").innerHTML = output.join("<br/>");
- ge("log").innerHTML = log.join("<br/>");
- matchHeight(ge("da_input"), ge("da_code"));
-}
-
-function disassembleDump() {
- var dump = "";
- var end = 0x7ffe;
- while (!memory[end] && end > 0) end--;
- for (var i = 0; i <= end + 1; i++) {
- dump += pad((memory[i] || 0).toString(16), 4);
- dump += (i % 8 == 7) ? "\n" : " ";
- }
- ge("da_input").value = dump;
- disassemble();
- toggleTab(1);
-}
-
-Clock.reset(queueInterrupt);
-Screen.init();
-Keyboard.init();
-disassemble();
-reset();
-var lastCode = ge("code").value;
-var lastInput = ge("da_input").value;
-
-function resizeTabs(event) {
- var headerHeight = ge("header").clientHeight + ge("tab_row").clientHeight + bodyMargin();
- for (var i = 0; i < 2; i++) {
- ge("tab" + i + "_wrapper").style.height = (window.innerHeight - headerHeight) + "px";
- }
- ge("tab2_wrapper").style.height = (32 * 20 + 7) + "px";
-};
-window.onresize = resizeTabs;
-
-setInterval(function() {
- Screen.blink = !Screen.blink;
- Screen.update(memory);
-
- var code = ge("code").value;
- if (code != lastCode) {
- lastCode = code;
- assemble();
- }
- var input = ge("da_input").value;
- if (input != lastInput) {
- lastInput = input;
- disassemble();
- }
-}, 600);
View
200 js/ui.js
@@ -23,6 +23,10 @@ document.onkeydown = function(event) {
step();
return false;
}
+ case 27: {
+ reset();
+ return false;
+ }
default: { // pass it to program
if (!runningTimer) return true;
return Keyboard.onkeydown(event, queueInterrupt);
@@ -44,7 +48,7 @@ document.onkeyup = function(event) {
function toggleTab(index) {
for (var i = 0; i < 2; i++) {
- ge("tab" + i + "_wrapper").style.display = (index == i) ? "block" : "none";
+ ge("tab" + i + "_content").style.display = (index == i) ? "block" : "none";
ge("tab" + i).className = (index == i) ? "tab_active" : "tab_inactive";
}
}
@@ -57,25 +61,28 @@ function updateRegisters() {
function toggleShowPC() {
updateHighlight();
}
-updateRegisters();
+//updateRegisters();
+var MEMORY_ROW_SIZE = 8;
function updateMemoryView() {
var lns = "";
var s = "";
- var offs = ge("memory_window").scrollTop * 8;
- ge("memory_lines").style.top = (offs / 8) + "px";
- ge("memory_view").style.top = (offs / 8) + "px";
- for (var i = 0; i < 16; i++) {
- lns += pad((offs + i * 8).toString(16), 4) + ":<br/>";
- for (var j = 0; j < 8; j++) {
- var v = memory[offs + i * 8 + j];
+
+ var offs = ge("memory_wrapper").scrollTop * MEMORY_ROW_SIZE;
+ var vis_lines = ge("memory_wrapper").offsetHeight / 19;
+ ge("memory_lines").style.top = (offs / MEMORY_ROW_SIZE) + "px";
+ ge("memory_view").style.top = (offs / MEMORY_ROW_SIZE) + "px";
+ for (var i = 0; i < vis_lines; i++) {
+ lns += pad((offs + i * MEMORY_ROW_SIZE).toString(16), 4) + ":<br/>";
+ for (var j = 0; j < MEMORY_ROW_SIZE; j++) {
+ var v = memory[offs + i * MEMORY_ROW_SIZE + j];
if (!v) v = 0;
v = pad(v.toString(16), 4);
- if (((offs + i * 8 + j + 1) & 0xffff) == registers.SP) {
- s += " <u class='cur_sp'>" + v + "</u>";
+ if (registers.SP > 0 && ((offs + i * MEMORY_ROW_SIZE + j) & 0xffff) == registers.SP) {
+ s += " <u id='memSP'>" + v + "</u>";
} else
- if (offs + i * 8 + j == registers.PC) {
- s += " <u class='cur_pc'>" + v + "</u>";
+ if (offs + i * MEMORY_ROW_SIZE + j == registers.PC) {
+ s += " <u id='memPC'>" + v + "</u>";
} else {
s += " " + v;
}
@@ -85,25 +92,23 @@ function updateMemoryView() {
ge("memory_lines").innerHTML = lns;
ge("memory_view").innerHTML = s;
}
-updateMemoryView();
+//updateMemoryView();
function positionHighlight(line) {
- if (!ge("show_pc").checked) {
+ /*if (!ge("show_pc").checked) {
line = -1;
- }
- for (var i = 1; i <= 4; i++) {
- var hlight = ge("hlight" + i);
- if (line >= 0) {
- hlight.style.top = line * 19 + 2;
- hlight.style.display = "block";
- } else {
- hlight.style.display = "none";
- }
+ }*/
+ var hlight = ge("asm_hlight");
+ if (line >= 0) {
+ hlight.style.top = line * 19;
+ hlight.style.display = "block";
+ } else {
+ hlight.style.display = "none";
}
}
function updateHighlight() {
positionHighlight(memToLine[registers.PC] - 1);
}
-positionHighlight(-1);
+//positionHighlight(-1);
function reset() {
for (var reg in registers) {
registers[reg] = 0;
@@ -186,15 +191,54 @@ function pad(v, w) {
return s;
}
+function htmlEscape(s) {
+ return s.split(" ").join("&nbsp;").split("<").join("&lt;");
+}
function assemble() {
- var lines = ge("code").value.split("\n");
+ var asm_code = ge("asm_code");
+ /*var selStart = -1;
+ var selEnd = -1;
+ if (window.getSelection().rangeCount > 0) {
+ var range = window.getSelection().getRangeAt(0);
+ selStart = range.startOffset;
+ var startContainer = range.startContainer;
+ var startAtLineStart = selStart == 0;
+ while (startContainer != asm_code && startContainer != null) {
+ while (startContainer.previousSibling != null) {
+ startContainer = startContainer.previousSibling;
+ selStart += startContainer.textContent.length;
+ }
+ startContainer = startContainer.parentNode;
+ }
+ selEnd = range.endOffset;
+ var endContainer = range.endContainer;
+ var endAtLineStart = selEnd == 0;
+ while (endContainer != asm_code && endContainer != null) {
+ while (endContainer.previousSibling != null) {
+ endContainer = endContainer.previousSibling;
+ selEnd += endContainer.textContent.length;
+ }
+ endContainer = endContainer.parentNode;
+ }
+ if (startContainer == null || endContainer == null) {
+ selStart = -1;
+ selEnd = -1;
+ }
+ }*/
+ var lines = ge("asm_code").innerText.split("\n");
+ var emptyLine = false;
+ if (lines.length > 0 && lines[lines.length - 1].length == 0) {
+ emptyLine = true;
+ lines.pop();
+ }
+
var log = [];
var linenums = [];
for (var i = 0; i < lines.length; i++) {
linenums.push("<u id=ln" + i + " onclick='bp(" + i + ")'>" + (i + 1) + "</u>");
}
- ge("linenums").innerHTML = linenums.join("");
+ ge("asm_lines").innerHTML = linenums.join("");
var logger = function(line, address, pos, message, fatal) {
log.push("<span class='line'>" + pad(line + 1, 5) + ":</span> " +
@@ -230,13 +274,63 @@ function assemble() {
dump.push(s);
}
}
+
+ /*asm_code.innerHTML = rv.syntax.join("<br/>") + (emptyLine ? "<br/><span></span>" : "");
+ if (selStart > -1 && selEnd > -1) {
+ var sel = window.getSelection();
+ sel.removeAllRanges();
+ range = document.createRange();
+ startContainer = asm_code;
+ while (true) {
+ if (startContainer.childNodes.length > 0) {
+ startContainer = startContainer.childNodes[0];
+ } else
+ if (selStart < startContainer.textContent.length || (selStart == startContainer.textContent.length && !startAtLineStart) || (selStart == 0 && (startContainer == asm_code || (startContainer.parentNode == asm_code && startContainer.nextSibling == null)))) {
+ range.setStart(startContainer, selStart);
+ break;
+ } else
+ if (startContainer.nextSibling != null) {
+ selStart -= startContainer.textContent.length;
+ startContainer = startContainer.nextSibling;
+ } else {
+ selStart -= startContainer.textContent.length;
+ while (startContainer.parentNode.nextSibling == null) {
+ startContainer = startContainer.parentNode;
+ }
+ startContainer = startContainer.parentNode.nextSibling;
+ }
+ }
+ endContainer = asm_code;
+ while (true) {
+ if (endContainer.childNodes.length > 0) {
+ endContainer = endContainer.childNodes[0];
+ } else
+ if (selEnd < endContainer.textContent.length || (selEnd == endContainer.textContent.length && !endAtLineStart) || (selEnd == 0 && (endContainer == asm_code || (endContainer.parentNode == asm_code && endContainer.nextSibling == null)))) {
+ range.setEnd(endContainer, selEnd);
+ break;
+ } else
+ if (endContainer.nextSibling != null) {
+ selEnd -= endContainer.textContent.length;
+ endContainer = endContainer.nextSibling;
+ } else {
+ selEnd -= endContainer.textContent.length;
+ while (endContainer.parentNode.nextSibling == null) {
+ endContainer = endContainer.parentNode;
+ }
+ endContainer = endContainer.parentNode.nextSibling;
+ }
+ }
+ sel.addRange(range);
+ }*/
}
// update UI
- ge("offsets").innerHTML = offsets.join("<br/>");
- ge("dump").innerHTML = dump.join("<br/>");
+ ge("asm_offsets").innerHTML = offsets.join("<br/>");
+ ge("asm_dump").innerHTML = dump.join("<br/>");
ge("log").innerHTML = log.join("<br/>");
- ge("code").style.height = Math.max(560, ((lines.length + 1) * 19 + 9)) + "px";