├── keys.txt ├── input.txt ├── .gitignore ├── css ├── simulator.css ├── emu6502.css └── main.css ├── sidebar.html ├── README.md ├── main.html ├── legend.html ├── interface.html ├── interface6502.js └── emu6502.js /keys.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /input.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | listing.lst 2 | prog.hex -------------------------------------------------------------------------------- /css/simulator.css: -------------------------------------------------------------------------------- 1 | /*CSS for legend and emulator pages for all simulators*/ 2 | .legend_mono { 3 | font-family:"Lucida Console","Courier New",Courier,monospace; 4 | font-size:14px; 5 | padding:0px 16px 0px"; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /sidebar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 |

12 |

Sidebar

13 | 14 |

15 | 16 | -------------------------------------------------------------------------------- /css/emu6502.css: -------------------------------------------------------------------------------- 1 | body { 2 | /*font-family: Verdana, Geneva, sans-serif;*/ 3 | font-family: Arial, Helvetica, sans-serif; 4 | font-size: 15px; 5 | } 6 | h1 { 7 | margin-top:0px; 8 | margin-bottom:0px; 9 | } 10 | h2 { 11 | margin-bottom:0px; 12 | } 13 | 14 | /*container div for sidebar and emulator side by side*/ 15 | #emu_container { 16 | white-space: nowrap; 17 | } 18 | 19 | /*container div within emu_container for sidebar_iframe*/ 20 | #sidebar_container { 21 | display: inline-block; 22 | vertical-align: top; 23 | } 24 | 25 | #sidebar_iframe { 26 | padding: 10px; 27 | width: 125px; 28 | height: 400px; 29 | border: none; 30 | } 31 | 32 | /*div within emu_container emulator content*/ 33 | #emu_content { 34 | margin: 10px 10px 0px 10px; 35 | display: inline-block; 36 | white-space: normal; 37 | } 38 | 39 | 40 | .system_block { 41 | display: table-cell; 42 | border: 1px solid black; 43 | } 44 | 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 65C02 Emulator 2 | 3 | This is a 65C02 emulator created to test firmware for a calculator project. It passes Klaus Dormann's [6502 and 65C02 functional tests](https://github.com/Klaus2m5/6502_65C02_functional_tests), with the exception of interrupts. Chrome is recommended as it seems to run the emulator much faster than other browsers reaching up to 50 MHz. 4 | 5 | You can see the emulator running on my website: [Robot Game](http://calc6502.com/RobotGame/OptAsm.html). 6 | 7 | The emulator displays the registers, memory, and an assembly listing while single stepping. The listing there is a stripped down version of the file output by the assembler used to assemble the file loaded into the emulator. Programs are loaded from a hex file when the page loads. The emulator has 16 banks of 16 kB for a total of 256 kB memory. Memory is divided into four bank windows: 8 | 9 | 0x0000-0x01FF No banking\ 10 | 0x0200-0x3FFF Bank 1\ 11 | 0x4000-0x7FFF Bank 2\ 12 | 0x8000-0xBFFF Bank 3\ 13 | 0xC000-0xFFDF Bank 4 14 | 15 | Video memory (256x128) is mapped one byte per pixel and takes up the 32k from 0x10000 to 0x17FFFF. Each byte has two bits each of red, green, and blue. Valid color codes are 0-63. Peripherals are mapped starting at 0xFFE0: 16 | 17 | 0xFFE0 Bank 1 pointer\ 18 | 0xFFE1 Bank 2 pointer\ 19 | 0xFFE2 Bank 3 pointer\ 20 | 0xFFE3 Bank 4 pointer\ 21 | 0xFFE4 Non-blocking keyboard input\ 22 | 0xFFE5 Counter. Updates 250 times per second\ 23 | 0xFFE6 Counter. Updates once per second\ 24 | 0xFFE7 Output to debug window\ 25 | 0xFFE8 Hex output to debug window\ 26 | 0xFFE9 Decimal output to debug window\ 27 | 0xFFEA 16 bit decimal output to debug window\ 28 | 0xFFEB Debug counter for measuring cycles\ 29 | 0xFFEC Turn instruction logging on\ 30 | 0xFFED Turn instruction logging off\ 31 | 0xFFEE Send instruction log file 32 | -------------------------------------------------------------------------------- /main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 65C02 Emulator 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | /*font-family: Verdana, Geneva, sans-serif;*/ 3 | font-family: Arial, Helvetica, sans-serif; 4 | font-size: 15px; 5 | } 6 | h1 { 7 | margin-top:0px; 8 | margin-bottom:0px; 9 | } 10 | h2 { 11 | margin-bottom:0px; 12 | } 13 | 14 | #main_content { 15 | /*background-color: #C0C0C0;*/ 16 | /*color: blue;*/ 17 | margin: 10px; 18 | padding: 0px; 19 | position: relative; 20 | width:60%; 21 | display: inline-block; 22 | white-space: normal; 23 | } 24 | /*should be #main_image but then ignores width*/ 25 | .main_image { 26 | object-fit: contain; 27 | width: 100%; 28 | height: auto; 29 | } 30 | 31 | 32 | 33 | .ul_mono { 34 | font-family:"Courier New", Courier, monospace; 35 | } 36 | .li_spaced { 37 | margin-top: 0px; 38 | margin-bottom: 10px; 39 | } 40 | .li_toc { 41 | margin-top: 0px; 42 | margin-bottom: 4px; 43 | } 44 | .li_results { 45 | margin-top: 0px; 46 | margin-bottom: 4px; 47 | max-width: 95%; 48 | } 49 | .li_skill1 { 50 | color: #00C000; 51 | font-weight: bold; 52 | } 53 | .li_skill2 { 54 | color: #0000C0; 55 | font-weight: bold; 56 | } 57 | .li_skill3 { 58 | color: #C00000; 59 | font-weight: bold; 60 | } 61 | .todo { 62 | background-color:yellow; 63 | color:red; 64 | margin: 0px; 65 | padding: 0px; 66 | margin-top:0px; 67 | } 68 | .small_image { 69 | object-fit: contain; 70 | width: 50%; 71 | height: auto; 72 | } 73 | .very_small_image { 74 | object-fit: contain; 75 | width: 15%; 76 | height: auto; 77 | } 78 | .somewhat_small_image { 79 | object-fit: contain; 80 | width: 45%; 81 | height: auto; 82 | } 83 | .image_caption { 84 | font-style: italic; 85 | } 86 | .div_code { 87 | padding: 10px; 88 | background-color: #F0F0F0; 89 | border-style: solid; 90 | border-width: 1px; 91 | border-color: #C0C0C0; 92 | border-radius: 5px; 93 | font-family: "Courier New", Courier, monospace; 94 | font-size:smaller; 95 | line-height: 1.3 96 | } 97 | .src_keyword { 98 | color: #0000FF; 99 | font-weight: bold; 100 | } 101 | .src_number { 102 | color: #0080FF; 103 | } 104 | .src_register { 105 | color: #C000C0; 106 | /*font-weight: bold;*/ 107 | } 108 | .src_comment { 109 | color: #00C000; 110 | /*font-weight: bold;*/ 111 | } 112 | .src_macro { 113 | color: #FF0000; 114 | /*font-weight: bold;*/ 115 | } 116 | .src_string { 117 | color: #FFA000; 118 | } 119 | .src_operator { 120 | color: #00C000; 121 | } 122 | .src_linenumber { 123 | color: #808080; 124 | font-style: italic; 125 | } 126 | 127 | .table_side_by_side { 128 | width:100%; 129 | margin:0px; 130 | table-layout: fixed; 131 | } 132 | .td50 { 133 | width: 50%; 134 | } 135 | 136 | .div_bar { 137 | display: flex; 138 | flex-wrap: nowrap; 139 | /*box-sizing:border-box;*/ 140 | /*display: inline-block;*/ 141 | width: 100%; 142 | background-color: #C0C0C0; 143 | margin:5px; 144 | text-align: left; 145 | color: white; 146 | } 147 | .div_bar_inner { 148 | box-sizing:border-box; 149 | /*display: inline-block;*/ 150 | width: 100%; 151 | background-color: #C0C0C0; 152 | padding:8px; 153 | margin:0px; 154 | text-align: left; 155 | color: white; 156 | } 157 | .base_result { 158 | text-align:center; 159 | } 160 | .pos_result { 161 | background-color:#C0FFC0; 162 | text-align:center; 163 | } 164 | .neg_result { 165 | background-color:#FFC0C0; 166 | text-align:center; 167 | } 168 | .neutral_result { 169 | background-color:#FFFFFF; 170 | text-align:center; 171 | } 172 | 173 | -------------------------------------------------------------------------------- /legend.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Emulator

11 | 12 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /interface.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 37 | 38 | 39 | 40 | 41 | 42 |
43 | 44 | 47 | 48 | 49 |
50 | 51 | 52 |
53 | 54 | 55 |
56 |

Title here

57 |
58 |
59 | 60 | 61 |
62 | 63 | 64 |
65 | 66 | 67 |
68 |
69 | 6502 Calculator Emulator
70 | Press Run to start 71 |
72 |
73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 |
97 |
98 | 99 | 100 |
101 | Status: waiting...
102 | Speed: (stopped)
103 | 104 | 105 | 106 | 107 |
108 | 109 |
110 | 111 | 112 |
113 | 114 |
115 |
116 |
117 | 118 | 119 |
120 | 121 |
122 | 123 | 124 | 130 | 131 | 132 | 192 | 193 | 194 | 217 | 218 | 219 | 231 |
232 |
233 |
234 | 235 | 236 | -------------------------------------------------------------------------------- /interface6502.js: -------------------------------------------------------------------------------- 1 | 2 | //*********** 3 | //*CONSTANTS* 4 | //*********** 5 | 6 | //(would be better as separate file but import feature in JS is total trash 7 | //import {ColorTable} from '/ColorTable.js' 8 | 9 | //Room for 256 values! 10 | 11 | const ColorTable=[ 12 | /* 13 | [0 ,0 ,0 ], //0 = black 14 | [255,0 ,0 ], //1 = red 15 | [0 ,255,0 ], //2 = green 16 | [0 ,0 ,255], //3 = blue 17 | [255,255,0 ], //4 = yellow 18 | [255,0 ,255], //5 = purple 19 | [0 ,255,255], //6 = cyan 20 | [255,255,255], //7 = white 21 | */ 22 | [0 ,0 ,0 ], //0 = black 23 | [84 ,0 ,0 ], //1 = dark red 24 | [168,0 ,0 ], //2 = middle red 25 | [255,0 ,0 ], //3 = red 26 | [0 ,84 ,0 ], //4 = dark green 27 | [84 ,84 ,0 ], //5 = dark yellow 28 | [168,84 ,0 ], //6 = brown 29 | [255,84 ,0 ], //7 = orange 30 | [0 ,168,0 ], //8 = middle green 31 | [84 ,168,0 ], //9 32 | [168,168,0 ], //10 = middle yellow 33 | [255,168,0 ], //11 = bright orange 34 | [0 ,255,0 ], //12 = green 35 | [84 ,255,0 ], //13 = bright green 36 | [168,255,0 ], //14 = lime green 37 | [255,255,0 ], //15 = yellow 38 | [0 ,0 ,84 ], //16 = dark blue 39 | [84 ,0 ,84 ], //17 = dark purple 40 | [168,0 ,84 ], //18 41 | [255,0 ,84 ], //19 = bright pink 42 | [0 ,84 ,84 ], //20 = dark cyan 43 | [84 ,84 ,84 ], //21 = dark gray 44 | [168,84 ,84 ], //22 45 | [255,84 ,84 ], //23 = sunset orange 46 | [0 ,168,84 ], //24 47 | [84 ,168,84 ], //25 48 | [168,168,84 ], //26 = mustard 49 | [255,168,84 ], //27 = light orange 50 | [0 ,255,84 ], //28 51 | [84 ,255,84 ], //29 52 | [168,255,84 ], //30 53 | [255,255,84 ], //31 = bright yellow 54 | [0 ,0 ,168], //32 = middle blue 55 | [84 ,0 ,168], //33 56 | [168,0 ,168], //34 57 | [255,0 ,168], //35 58 | [0 ,84 ,168], //36 = nice blue 59 | [84 ,84 ,168], //37 60 | [168,84 ,168], //38 61 | [255,84 ,168], //39 = other pink 62 | [0 ,168,168], //40 = middle cyan 63 | [84 ,168,168], //41 64 | [168,168,168], //42 = middle gray 65 | [255,168,168], //43 = peach 66 | [0 ,255,168], //44 67 | [84 ,255,168], //45 68 | [168,255,168], //46 69 | [255,255,168], //47 = light yellow 70 | [0 ,0 ,255], //48 = blue 71 | [84 ,0 ,255], //49 72 | [168,0 ,255], //50 73 | [255,0 ,255], //51 = purple 74 | [0 ,84 ,255], //52 75 | [84 ,84 ,255], //53 76 | [168,84 ,255], //54 77 | [255,84 ,255], //55 = brighter purple 78 | [0 ,168,255], //56 79 | [84 ,168,255], //57 80 | [168,168,255], //58 = lilac? 81 | [255,168,255], //59 = light pink 82 | [0 ,255,255], //60 = cyan 83 | [84 ,255,255], //61 = lighter cyan 84 | [168,255,255], //62 = lightest cyan 85 | [255,255,255], //63 = white 86 | //Custom colors 87 | //[20 ,20 ,20 ] //64 = custom gray 88 | 89 | //Fill rest with black in case graphics memory contains invalid values 90 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 91 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 92 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 93 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 94 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 95 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 96 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 97 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 98 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 99 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 100 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 101 | [0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 102 | ]; 103 | 104 | //Virtual screen variables (independent of canvas) 105 | const screenWidth=256; 106 | const screenHeight=128; 107 | const screenPixelRatio=2; 108 | 109 | 110 | //****************** 111 | //*GLOBAL VARIABLES* 112 | //****************** 113 | 114 | //General state 115 | var ready=0; 116 | var running=0; 117 | var start_time=0; 118 | var cycle_offset=0; 119 | var cycle_temp=0; 120 | var cycle_last=0; 121 | var time_last=0; 122 | var cycle_int_id; 123 | var key_int_id; 124 | var gfx_int_id; 125 | var listing=[]; 126 | var draw_address=[-1,-1,-1]; 127 | var draw_color=['white','#E0E0E0','#C0C0C0','#00FF00']; 128 | 129 | //Worker variable 130 | var w; 131 | 132 | //Canvas drawing variables 133 | var canvas; 134 | var canvasWidth; 135 | var canvasHeight; 136 | var ctx; 137 | 138 | //Key buffer 139 | var keyBuffer=[]; 140 | 141 | //File input buffer 142 | var inputBuffer=[]; 143 | 144 | //Memory pane address 145 | memLeft=0xC000; 146 | memRight=0xFF00; 147 | 148 | //Debug buffer output on page 149 | var debugBufferState="normal"; 150 | var debugString=""; 151 | var debugBold=false; 152 | var debugItalics=false; 153 | var debugColor="black"; 154 | var debugRespan=false; 155 | 156 | //Audio for beep on bell character 7 157 | audio=new AudioContext(); 158 | 159 | //Memory viewer 160 | mem_contents=""; 161 | 162 | //Cycle log viewer 163 | cycle_log=""; 164 | 165 | //Constants for hardware 166 | RAM_BANK1=0xFFE0; 167 | RAM_BANK2=0xFFE1; 168 | RAM_BANK3=0xFFE2; 169 | ROM_BANK=0xFFE3; 170 | BANK_SIZE=0x4000; 171 | BANK_COUNT=16; 172 | 173 | //Moved to top level html! 174 | //setup(); 175 | 176 | //************** 177 | //*MESSAGE LOOP* 178 | //************** 179 | 180 | function RegCharFilter(character) 181 | { 182 | if ([0,12].includes(character)) 183 | return String.fromCharCode(1); //generic box character 184 | return String.fromCharCode(character); 185 | } 186 | 187 | function OnMessage(e) 188 | { 189 | switch (e.data.cmd) 190 | { 191 | case 'update': 192 | //document.getElementById("lbldebug").innerHTML="debug: " + e.data.debugflag+"
"; 193 | document.getElementById("lbldebug").innerHTML=e.data.debugflag+"
"; 194 | //if (e.data.loaded==0) alert('Not finished loading!'); 195 | var temp_address=e.data.PC.toString(16).toUpperCase(); 196 | var outstr= 197 | 'PC: ' + 198 | "0".repeat(4-e.data.PC.toString(16).length)+ 199 | e.data.PC.toString(16).toUpperCase()+''+ 200 | "
A: " + "0".repeat(2-e.data.A.toString(16).length)+ 201 | e.data.A.toString(16).toUpperCase()+" ("+RegCharFilter(e.data.A)+")"+ 202 | "
X: " + "0".repeat(2-e.data.X.toString(16).length)+ 203 | e.data.X.toString(16).toUpperCase()+" ("+RegCharFilter(e.data.X)+")"+ 204 | "
Y: " + "0".repeat(2-e.data.Y.toString(16).length)+ 205 | e.data.Y.toString(16).toUpperCase()+" ("+RegCharFilter(e.data.Y)+")"+ 206 | '
SP: ' + 207 | "0".repeat(2-e.data.SP.toString(16).length)+ 208 | e.data.SP.toString(16).toUpperCase()+''+ 209 | '
CA: ' 210 | if (e.data.CalcAddress==-1) outstr+='(none)'; 211 | else outstr+="0".repeat(4-e.data.CalcAddress.toString(16).length)+ 212 | e.data.CalcAddress.toString(16).toUpperCase()+''; 213 | document.getElementById("lblRegs").innerHTML=outstr; 214 | 215 | outstr=""; 216 | if (e.data.FlagN) outstr+='N ';else outstr+='n '; 217 | if (e.data.FlagV) outstr+='V ';else outstr+='v '; 218 | if (e.data.FlagB) outstr+='B ';else outstr+='b '; 219 | if (e.data.FlagD) outstr+='D ';else outstr+='d '; 220 | if (e.data.FlagI) outstr+='I ';else outstr+='i '; 221 | if (e.data.FlagZ) outstr+='Z ';else outstr+='z '; 222 | if (e.data.FlagC) outstr+='C';else outstr+='c'; 223 | document.getElementById("lblFlags").innerHTML=outstr; 224 | 225 | outstr=""; 226 | for (let i=1;i<5;i++) 227 | outstr+=GetBankFromReg(i,e); 228 | document.getElementById("lblBanks").innerHTML=outstr; 229 | 230 | document.getElementById("lblZP").innerHTML=DrawMem(0x0000,e); 231 | document.getElementById("lblStack").innerHTML=DrawMem(0x0100,e); 232 | if (document.getElementById("selLeftPC").checked==true) memLeft = e.data.PC&0xFF00; 233 | if ((document.getElementById("selRightPC").checked==true)&&(e.data.CalcAddress!=-1)) memRight = e.data.CalcAddress&0xFF00; 234 | document.getElementById("lblLeftMem").innerHTML=DrawMem(memLeft,e); 235 | document.getElementById("lblRightMem").innerHTML=DrawMem(memRight,e); 236 | document.getElementById("lblLeftMemTitle").innerHTML=""+GetBank(memLeft,e)+":"+memLeft.toString(16).toUpperCase().padStart(4,"0")+""; 237 | document.getElementById("lblRightMemTitle").innerHTML=""+GetBank(memRight,e)+":"+memRight.toString(16).toUpperCase().padStart(4,"0")+""; 238 | 239 | if (document.getElementById("tableMemory").style.display=="table") 240 | { 241 | w.postMessage({cmd:'memory viewer'}); 242 | } 243 | 244 | 245 | let listing_str=""; 246 | if (ready==1) 247 | { 248 | //Old style Kowalski listing 249 | if (listing_type=="Kowalski") 250 | { 251 | var old_address=-1; 252 | for (let i=0;i'; 258 | old_address=listing[i].address; 259 | } 260 | 261 | temp_address=listing[i].address.toString(16).toUpperCase(); 262 | temp_address="0".repeat(4-temp_address.length)+temp_address; 263 | 264 | if (listing[i].label!='') 265 | { 266 | listing[i].label=listing[i].label.replace("<","<"); 267 | listing[i].label=listing[i].label.replace(">",">"); 268 | listing_str+=temp_address+ " " +listing[i].label+":"; 269 | } 270 | else 271 | { 272 | listing[i].op=listing[i].op.replace("<","<"); 273 | listing[i].op=listing[i].op.replace(">",">"); 274 | listing_str+=temp_address+ " " + listing[i].op; 275 | } 276 | listing_str+="
"; 277 | } 278 | listing_str+=''; 279 | } 280 | else 281 | { 282 | //New style CA65 and AS listing 283 | let old_address=-1; 284 | let temp_address=''; 285 | for (let i=0;i'; 291 | old_address=listing[i].address; 292 | temp_address=listing[i].address.toString(16).toUpperCase(); 293 | temp_address="0".repeat(4-temp_address.length)+temp_address; 294 | } 295 | if (listing[i].line!='') 296 | { 297 | listing[i].line=listing[i].line.replace("<","<"); 298 | listing[i].line=listing[i].line.replace(">",">"); 299 | listing_str+=temp_address+" "+listing[i].line; 300 | } 301 | listing_str+="
"; 302 | } 303 | listing_str+=''; 304 | } 305 | 306 | var sysShow=document.getElementById("tableSystem").style.display; 307 | document.getElementById("tableSystem").style.display="block"; 308 | var temp_height=document.getElementById('bottom_row').offsetHeight; 309 | document.getElementById("divlisting").style.height=temp_height+'px'; 310 | document.getElementById("txtlisting").innerHTML=listing_str; 311 | document.getElementById("tableSystem").style.display=sysShow; 312 | 313 | ready=2; 314 | } 315 | 316 | //Leave coloring as is if PC is inside macro 317 | if (ready==2) 318 | { 319 | if (document.getElementById("s"+e.data.PC)!=null) 320 | { 321 | for (let j=0;j<3;j++) 322 | { 323 | if (draw_address[j]!=-1) 324 | { 325 | if (document.getElementById("s"+draw_address[j])!=null) 326 | document.getElementById("s"+draw_address[j]).style.backgroundColor=draw_color[j]; 327 | } 328 | if (j<2) draw_address[j]=draw_address[j+1]; 329 | } 330 | draw_address[2]=e.data.PC; 331 | if (document.getElementById("s"+e.data.PC)!=null) 332 | document.getElementById("s"+e.data.PC).style.backgroundColor=draw_color[3]; 333 | 334 | document.getElementById('divlisting').scrollTop=document.getElementById("s"+e.data.PC).offsetTop-763; 335 | } 336 | } 337 | break; 338 | case "msgbox": 339 | alert(e.data.msg); 340 | break; 341 | case "error": 342 | alert("Error: " + e.data.msg); 343 | break; 344 | case "status": 345 | document.getElementById("lblstatus").innerHTML="Status: " + e.data.msg; 346 | break; 347 | case "ready": 348 | ready=1; 349 | w.postMessage({cmd:'update'}); 350 | break; 351 | case "cycles": 352 | //Average speed since began running 353 | /* 354 | var t0=performance.now(); 355 | cycle_temp=e.data.cycle_count; 356 | document.getElementById("lblspeed").innerHTML="Speed: " + Math.round((e.data.cycle_count-cycle_offset)/(t0-start_time)/10)/100 + "MHz"; 357 | */ 358 | 359 | //Average speed since last reading 360 | var t0=performance.now(); 361 | cycle_temp=e.data.cycle_count; 362 | if (time_last!=0) 363 | { 364 | document.getElementById("lblspeed").innerHTML="Speed: " + Math.round((cycle_temp-cycle_last)/(t0-time_last)/10)/100 + "MHz"; 365 | } 366 | cycle_last=cycle_temp; 367 | time_last=t0; 368 | 369 | break; 370 | case "debug": 371 | if (e.data.debugBuffer.length>0) 372 | { 373 | let dlen=e.data.debugBuffer.length; 374 | for (i=0;i=9) 381 | { 382 | if (debugRespan) 383 | { 384 | debugString+=""; 388 | debugRespan=false; 389 | } 390 | if (newchar==" ") debugString+=" "; 391 | else if (newchar.charCodeAt(0)==9) debugString+=" "; 392 | else if (newchar.charCodeAt(0)==10) debugString+="
"; 393 | else debugString+=newchar; 394 | } 395 | } 396 | else if (debugBufferState=="slashed") 397 | { 398 | //Can also check by number here, which is why passed array instead of string 399 | 400 | //New line 401 | if (newchar=="n") debugString+="
"; 402 | //Colors 403 | else if ("roygbpwl".includes(newchar)) 404 | { 405 | if (newchar=="r") debugColor="red"; 406 | else if (newchar=="o") debugColor="#FF8000"; 407 | else if (newchar=="y") debugColor="#E0E000"; 408 | else if (newchar=="g") debugColor="#00E000"; 409 | else if (newchar=="b") debugColor="#0000FF"; 410 | else if (newchar=="p") debugColor="#FF00FF"; 411 | else if (newchar=="w") debugColor="white"; 412 | else if (newchar=="l") debugColor="black"; 413 | debugRespan=true; 414 | } 415 | //Bold, Italics, Reset 416 | else if (newchar=="B") {debugBold=true;debugRespan=true;} 417 | else if (newchar=="I") {debugItalics=true;debugRespan=true;} 418 | else if (newchar=="R") 419 | { 420 | debugBold=false; 421 | debugItalics=false; 422 | debugRespan=true; 423 | } 424 | //Not found so treat as not slashed 425 | else debugString+="\\"+newchar; 426 | debugBufferState="normal"; 427 | } 428 | } 429 | document.getElementById('divDebug').innerHTML=""+debugString+""; 430 | 431 | //document.getElementById('divDebug').scrollTop=document.getElementById('divDebug').scrollHeight-document.getElementById('divDebug').offsetHeight; 432 | document.getElementById('divDebug').scrollTop=document.getElementById('divDebug').scrollHeight; 433 | } 434 | break; 435 | case "stopped": 436 | w.postMessage({cmd:'update'}); 437 | w.postMessage({cmd:'debug'}); 438 | w.postMessage({cmd:'check screen'}); 439 | clearInterval(cycle_int_id); 440 | clearInterval(key_int_id); 441 | clearInterval(gfx_int_id); 442 | cycle_last=0; 443 | time_last=0; 444 | document.getElementById("lblspeed").innerHTML="Speed: (stopped)"; 445 | running=0; 446 | break; 447 | case "listing": 448 | listing=e.data.listing; 449 | break; 450 | case "screen update": 451 | //let draw_start_time=Date.now(); 452 | //Total: 150-270ms 453 | //getImageDate: 0-1ms 454 | //data=imdageData: 0-1ms 455 | //for loop: 150-260ms <===THIS IS THE PROBLEM 456 | //putImageData: 01-ms 457 | 458 | //Tried but didn't work 459 | //made data const 460 | //changed data in loop to imageData.data 461 | //commented out alpha value (alreadys set?) 462 | 463 | //Tried and worked 464 | //cache ColorTable entry 13-70ms 465 | 466 | //Hmm, cant use imageData here since used above if use let :/ 467 | var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight); 468 | var index=0; 469 | //const??? 470 | const data = imageData.data; 471 | for (let j=0;j"); 546 | cycle_log_temp=cycle_log_temp.replace(/ /g," "); 547 | document.getElementById('divCycles').innerHTML=cycle_log_temp; 548 | break; 549 | case "bell": 550 | beep(2,880,200); 551 | break; 552 | } 553 | } 554 | 555 | //Get string representing bank from address 556 | function GetBank(address,e) 557 | { 558 | if (address<0x200) bank=0; 559 | else if (address<0x4000) bank=parseInt(e.data.RamBank1/BANK_SIZE); 560 | else if (address<0x8000) bank=parseInt(e.data.RamBank2/BANK_SIZE); 561 | else if (address<0xC000) bank=parseInt(e.data.RamBank3/BANK_SIZE); 562 | else bank=parseInt(e.data.RomBank/BANK_SIZE); 563 | return bank.toString(16).toUpperCase().padStart(2,"0") 564 | } 565 | 566 | //Get string representing bank from bank regs 567 | function GetBankFromReg(bank,e) 568 | { 569 | let bankPC=-1; 570 | let bankCA=-1; 571 | if (e.data.PC<0x200) bankPC=-1; 572 | else if (e.data.PC<0x4000) bankPC=1; 573 | else if (e.data.PC<0x8000) bankPC=2; 574 | else if (e.data.PC<0xC000) bankPC=3; 575 | else bankPC=4; 576 | 577 | if (e.data.CalcAddress<0x200) bankCA=-1; 578 | else if (e.data.CalcAddress<0x4000) bankCA=1; 579 | else if (e.data.CalcAddress<0x8000) bankCA=2; 580 | else if (e.data.CalcAddress<0xC000) bankCA=3; 581 | else bankCA=4; 582 | 583 | let disp_bank=-1; 584 | if (bank==1) disp_bank=parseInt(e.data.RamBank1/BANK_SIZE); 585 | else if (bank==2) disp_bank=parseInt(e.data.RamBank2/BANK_SIZE); 586 | else if (bank==3) disp_bank=parseInt(e.data.RamBank3/BANK_SIZE); 587 | else if (bank==4) disp_bank=parseInt(e.data.RomBank/BANK_SIZE); 588 | 589 | if (bank==bankPC) outstr=''; 590 | else if (bank==bankCA) outstr=''; 591 | else outstr=''; 592 | outstr+="Bank "+bank.toString(16)+": "+"0".repeat(2-disp_bank.toString(16).length); 593 | outstr+=disp_bank.toString(16)+"
"; 594 | return outstr; 595 | } 596 | 597 | function selLeftHandler() 598 | { 599 | memLeft = document.getElementById("selLeftMem").selectedIndex*0x100; 600 | w.postMessage({cmd:'update'}); 601 | } 602 | 603 | function selRightHandler() 604 | { 605 | memRight = document.getElementById("selRightMem").selectedIndex*0x100; 606 | w.postMessage({cmd:'update'}); 607 | } 608 | 609 | function keyHandler(event) 610 | { 611 | let keyName = event.key; 612 | let key=0; 613 | //keyName=undefined; 614 | if (keyName!=undefined) 615 | { 616 | //Default behavior - Chrome 51 and up 617 | switch (keyName) 618 | { 619 | case "Shift": 620 | key=0; 621 | break; 622 | case "Alt": 623 | key=0; 624 | break; 625 | case "Enter": 626 | key=13; 627 | break; 628 | case "Backspace": 629 | key=8; 630 | break; 631 | case "Escape": 632 | key=27; 633 | break; 634 | default: 635 | //If length>1 then might be a named key like "Backspace" 636 | if (keyName.length==1) key=keyName.charCodeAt(0)&0xFF; 637 | break; 638 | } 639 | //console.log("\nHTML side key (default): "+key); 640 | } 641 | else 642 | { 643 | //Compatibility version - Chrome 50 and under 644 | keyName=event.code; 645 | //console.log("\nHTML side key (deprecated): "+keyName); 646 | const unshifted={KeyA:97,KeyB:98,KeyC:99,KeyD:100,KeyE:101,KeyF:102,KeyG:103,KeyH:104,KeyI:105,KeyJ:106,KeyK:107,KeyL:108, 647 | KeyM:109,KeyN:110,KeyO:111,KeyP:112,KeyQ:113,KeyR:114,KeyS:115,KeyT:116,KeyU:117,KeyV:118,KeyW:119,KeyX:120,KeyY:121,KeyZ:122, 648 | Digit0:48,Digit1:49,Digit2:50,Digit3:51,Digit4:52,Digit5:53,Digit6:54,Digit7:55,Digit8:56,Digit9:57, 649 | Comma:44,Period:46,Slash:47,Semicolon:59,Quote:39,BracketLeft:91,BracketRight:93,Backslash:92,Minus:45,Equal:61,Backspace:8, 650 | Enter:13,Tab:0,Backquote:96,Delete:0,Space:32}; 651 | 652 | const shifted={KeyA:65,KeyB:66,KeyC:67,KeyD:68,KeyE:69,KeyF:70,KeyG:71,KeyH:72,KeyI:73,KeyJ:74,KeyK:75,KeyL:76,KeyM:77, 653 | KeyN:78,KeyO:79,KeyP:80,KeyQ:81,KeyR:82,KeyS:83,KeyT:84,KeyU:85,KeyV:86,KeyW:87,KeyX:88,KeyY:89,KeyZ:90, 654 | Digit0:41,Digit1:33,Digit2:64,Digit3:35,Digit4:36,Digit5:37,Digit6:94,Digit7:38,Digit8:42,Digit9:40, 655 | Comma:60,Period:62,Slash:63,Semicolon:58,Quote:34,BracketLeft:123,BracketRight:125,Backslash:124,Minus:95,Equal:43,Backspace:8, 656 | Enter:13,Tab:0,Backquote:126,Delete:0,Space:32}; 657 | 658 | if (event.shiftKey) key=shifted[keyName]; 659 | else key=unshifted[keyName]; 660 | if (key==undefined) key=0; 661 | 662 | //console.log("HTML side key code (deprecated): "+key); 663 | } 664 | 665 | //Add to buffer and send all at once every 10ms (disabled) 666 | //keyBuffer.push(keyName); 667 | 668 | //Send immediately 669 | //w.postMessage({cmd:'keys',keys:key}); 670 | 671 | //Prevent default behavior, including typing and scrolling on space 672 | //Exceptions for ctrl+R, ctrl+C, ctrl+F 673 | //if (!((keyName=='r')&&(event.ctrlKey))) event.preventDefault(); 674 | 675 | if (!event.ctrlKey) 676 | { 677 | w.postMessage({cmd:'keys',keys:key}); 678 | event.preventDefault(); 679 | } 680 | else 681 | { 682 | if (keyName=='c'); 683 | else if (keyName=='f'); 684 | else if (keyName=='r'); 685 | else if (keyName=='a'); 686 | else 687 | { 688 | w.postMessage({cmd:'keys',keys:key}); 689 | event.preventDefault(); 690 | } 691 | } 692 | } 693 | 694 | // https://hackernoon.com/copying-text-to-clipboard-with-javascript-df4d4988697f 695 | function copyToClipboard(text) 696 | { 697 | const el = document.createElement('textarea'); 698 | el.value = text; 699 | el.setAttribute('readonly', ''); 700 | el.style.position = 'absolute'; 701 | el.style.left = '-9999px'; 702 | document.body.appendChild(el); 703 | el.select(); 704 | document.execCommand('copy'); 705 | document.body.removeChild(el); 706 | } 707 | 708 | function radioHandler(whichRadio) 709 | { 710 | document.getElementById("tableLegend").style.display="none"; 711 | document.getElementById("tableLegend2").style.display="none"; 712 | document.getElementById("tableDebug").style.display="none"; 713 | document.getElementById("tableSystem").style.display="none"; 714 | document.getElementById("tableMemory").style.display="none"; 715 | document.getElementById("tableCycles").style.display="none"; 716 | if (whichRadio.value=="legend") 717 | { 718 | document.getElementById("tableLegend").style.width= 719 | document.getElementById("tableMain").offsetWidth-34+"px"; 720 | document.getElementById("tableLegend").style.display="block"; 721 | } 722 | else if (whichRadio.value=="legend2") 723 | { 724 | document.getElementById("tableLegend2").style.width= 725 | document.getElementById("tableMain").offsetWidth-34+"px"; 726 | document.getElementById("tableLegend2").style.display="block"; 727 | } 728 | else if (whichRadio.value=="system") 729 | { 730 | document.getElementById("tableDebug").style.display="block"; 731 | document.getElementById("tableDebug").style.width= 732 | document.getElementById("tableMain").offsetWidth+"px"; 733 | document.getElementById("divDebug").style.width= 734 | document.getElementById("tableMain").offsetWidth+"px"; 735 | document.getElementById("tableSystem").style.display="block"; 736 | //Reset listing window 737 | w.postMessage({cmd:'update'}); 738 | //Scroll debug window to bottom 739 | document.getElementById('divDebug').scrollTop=document.getElementById('divDebug').scrollHeight-document.getElementById('divDebug').offsetHeight; 740 | } 741 | else if (whichRadio.value=="stack") document.getElementById("tableStack").style.display="block"; 742 | else if (whichRadio.value=="memory") 743 | { 744 | document.getElementById("tableMemory").style.width= 745 | document.getElementById("tableMain").offsetWidth+"px"; 746 | document.getElementById("tableMemory").style.display="block"; 747 | w.postMessage({cmd:'memory viewer'}); 748 | } 749 | else if (whichRadio.value=="cycles") 750 | { 751 | document.getElementById("tableCycles").style.width= 752 | document.getElementById("tableMain").offsetWidth+"px"; 753 | document.getElementById("tableCycles").style.display="block"; 754 | w.postMessage({cmd:'cycle table'}); 755 | } 756 | 757 | } 758 | 759 | //Old DrawMem that ignores banking 760 | /* 761 | function DrawMem(StartAddress,e) 762 | { 763 | var outstr='   '+ 764 | 'x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
0x
'; 765 | for (let i=StartAddress;i' 780 | if ((i%16==15)&&((i%0x100)!=0xFF)) outstr+='
'+ 781 | parseInt((i%0x100)/16+1).toString(16).toUpperCase()+'x '; 782 | else outstr+=' '; 783 | } 784 | return outstr; 785 | } 786 | */ 787 | 788 | function DrawMem(StartAddress,e) 789 | { 790 | var outstr='   '+ 791 | 'x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
0x
'; 792 | if (StartAddress<0x200) 793 | { 794 | BankAddress=StartAddress; 795 | } 796 | else if (StartAddress<0x4000) 797 | { 798 | BankAddress=StartAddress+e.data.RamBank1; 799 | } 800 | else if (StartAddress<0x8000) 801 | { 802 | BankAddress=StartAddress-0x4000+e.data.RamBank2; 803 | } 804 | else if (StartAddress<0xC000) 805 | { 806 | BankAddress=StartAddress-0x8000+e.data.RamBank3; 807 | } 808 | else 809 | { 810 | BankAddress=StartAddress-0xC000+e.data.RomBank; 811 | } 812 | 813 | for (let i=StartAddress;i' 828 | if ((i%16==15)&&((i%0x100)!=0xFF)) outstr+='
'+ 829 | parseInt((i%0x100)/16+1).toString(16).toUpperCase()+'x '; 830 | else outstr+=' '; 831 | } 832 | return outstr; 833 | } 834 | 835 | function DrawMemViewer(mem) 836 | { 837 | temp_str=''; 838 | for (let i=0;i' ; 841 | temp_str+="
Bank "+i.toString(16).toUpperCase().padStart(2,"0"); 842 | temp_str+="

"; 843 | temp_vals=""; 844 | temp_chars=""; 845 | for (let j=0;j=32)&&(mem[i*BANK_SIZE+j]<=126)) 854 | { 855 | temp_chars+=String.fromCharCode(mem[i*BANK_SIZE+j]); 856 | } 857 | else temp_chars+="."; 858 | 859 | if (j%16!=15) temp_chars+="."; 860 | else 861 | { 862 | temp_str+=temp_vals+"| "+temp_chars+"
"; 863 | temp_chars=""; 864 | temp_vals=""; 865 | } 866 | } 867 | temp_str+="
"; 868 | } 869 | temp_str+='
'; 870 | document.getElementById('divMemory').innerHTML=temp_str; 871 | 872 | temp_str=temp_str.replace(//g,""); 873 | temp_str=temp_str.replace(/<\/a>/g,""); 874 | temp_str=temp_str.replace(//g,""); 875 | temp_str=temp_str.replace(/<\/b>/g,""); 876 | temp_str=temp_str.replace(/
/g,""); 877 | temp_str=temp_str.replace(/<\/center>/g,""); 878 | temp_str=temp_str.replace(/
/g,"\n"); 879 | temp_str=temp_str.replace(//g,""); 880 | temp_str=temp_str.replace(/<\/span>/g,""); 881 | temp_str=temp_str.replace(/
/g,""); 882 | 883 | return temp_str; 884 | } 885 | 886 | 887 | //https://odino.org/emit-a-beeping-sound-with-javascript/ 888 | function beep(vol, freq, duration){ 889 | v=audio.createOscillator(); 890 | u=audio.createGain(); 891 | v.connect(u); 892 | v.frequency.value=freq; 893 | v.type="square"; 894 | u.connect(audio.destination); 895 | u.gain.value=vol*0.01; 896 | v.start(audio.currentTime); 897 | v.stop(audio.currentTime+duration*0.001); 898 | } 899 | 900 | 901 | function step() 902 | { 903 | if (ready==2) 904 | { 905 | w.postMessage({cmd:'single'}); 906 | w.postMessage({cmd:'debug'}); 907 | w.postMessage({cmd:'check screen'}); 908 | } 909 | } 910 | 911 | function run() 912 | { 913 | if ((ready==2)&&(running==0)) 914 | { 915 | keyBuffer=[]; 916 | inputBuffer=[]; 917 | w.postMessage({cmd:'run'}); 918 | cycle_offset=cycle_temp; 919 | //cycle_int_id=setInterval(function(){w.postMessage({cmd:'cycles'});},1000); 920 | cycle_int_id=setInterval(function() 921 | { 922 | w.postMessage({cmd:'cycles'}); 923 | w.postMessage({cmd:'debug'}); 924 | } 925 | ,1000); 926 | 927 | //Try sending keys immediately 928 | /* 929 | key_int_id=setInterval(function() 930 | { 931 | if (keyBuffer.length!=0) 932 | { 933 | w.postMessage({cmd:'keys',keys:keyBuffer}); 934 | keyBuffer=[]; 935 | } 936 | },10); 937 | */ 938 | 939 | //Update time is max 13-70ms down from 150-270ms. Update rate of 15ms then? 940 | //gfx_int_id=setInterval(function(){w.postMessage({cmd:'check screen'});},200); 941 | gfx_int_id=setInterval(function(){w.postMessage({cmd:'check screen'});},15); 942 | 943 | start_time=performance.now(); 944 | running=1; 945 | } 946 | } 947 | 948 | function stop() 949 | { 950 | if (running==1) 951 | { 952 | w.postMessage({cmd:'stop'}); 953 | document.getElementById("lblspeed").innerHTML="Speed: stopping..."; 954 | } 955 | } 956 | 957 | function reset() 958 | { 959 | w.postMessage({cmd:'reset'}); 960 | w.postMessage({cmd:'update'}); 961 | } 962 | 963 | function LoadPages() 964 | { 965 | //https://stackoverflow.com/questions/17636528/how-do-i-load-an-html-page-in-a-div-using-javascript 966 | var xmlHttp = new XMLHttpRequest(); 967 | 968 | function xmlStep(file,func) 969 | { 970 | xmlHttp.onreadystatechange = function() 971 | { 972 | if (xmlHttp.readyState == 4 && xmlHttp.status == 200) 973 | { 974 | func(); 975 | } 976 | } 977 | xmlHttp.open("GET", file, true); // true for asynchronous 978 | xmlHttp.send(null); 979 | } 980 | 981 | xmlStep(base_path + "interface.html", 982 | function() 983 | { 984 | //executes after main page loads 985 | content_div.innerHTML = xmlHttp.responseText; 986 | setup(path,listing_type); 987 | xmlStep(legend_page, 988 | function() 989 | { 990 | tableLegend.innerHTML = xmlHttp.responseText; 991 | if (visible_items.includes("legend2")) 992 | { 993 | xmlStep(legend2_page, 994 | function() 995 | { 996 | tableLegend2.innerHTML = xmlHttp.responseText; 997 | } 998 | ); 999 | } 1000 | } 1001 | ); 1002 | } 1003 | ); 1004 | } 1005 | 1006 | function setup(hexPath,listing_type) 1007 | { 1008 | //Worker 1009 | w = new Worker(base_path+"emu6502.js"); 1010 | w.addEventListener('message', OnMessage, false); 1011 | w.postMessage({cmd:'setup',path:hexPath,listing_type:listing_type,NMOS_mode:NMOS_mode,halt_on_BRK:halt_on_BRK}); 1012 | 1013 | //Interface 1014 | lbl_legend.innerHTML=legend_caption; 1015 | lbl_legend2.innerHTML=legend2_caption; 1016 | main_title.innerHTML=doc_title; 1017 | for (const item of visible_items) 1018 | { 1019 | if (item!="") 1020 | { 1021 | document.getElementById("br_"+item).style.display="inline-block"; 1022 | document.getElementById("lbl_"+item).style.display="inline-block"; 1023 | document.getElementById("radio_"+item).style.display="inline-block"; 1024 | } 1025 | } 1026 | 1027 | //Screen 1028 | canvas = document.getElementById('picScreen'); 1029 | canvasWidth = canvas.width; 1030 | canvasHeight = canvas.height; 1031 | ctx = canvas.getContext('2d'); 1032 | ctx.font = "16px Courier New"; 1033 | ctx.fillText("<=" ".charCodeAt(0))&&(A<="~".charCodeAt(0))) cycleLog+="("+String.fromCharCode(A)+") "; 180 | else cycleLog+="( ) "; 181 | cycleLog+="X:"+X.toString(16).toUpperCase().padStart(2,"0")+" "; 182 | cycleLog+="Y:"+Y.toString(16).toUpperCase().padStart(2,"0")+" "; 183 | cycleLog+="SP:"+SP.toString(16).toUpperCase().padStart(2,"0")+" "; 184 | if (CalcAddress==-1) cycleLog+=" "; 185 | else 186 | { 187 | cycleLog+="CA:"+CalcAddress.toString(16).toUpperCase().padStart(4,"0")+" "; 188 | cycleLog+="("+(CalcBanked>>16).toString(16).toUpperCase().padStart(2,"0")+":"; 189 | cycleLog+=(CalcBanked&0xFFFF).toString(16).toUpperCase().padStart(4,"0")+")"; 190 | } 191 | cycleLog+=" "+cycle_count; 192 | cycleLog+="\n"; 193 | if (op==0) cycleLog+="\n"; 194 | } 195 | 196 | 197 | //************** 198 | //*MESSAGE LOOP* 199 | //************** 200 | 201 | function OnMessage(e) 202 | { 203 | debugflag=''; 204 | //CalcAddress=-1; //Moved below 205 | switch (e.data.cmd) 206 | { 207 | case 'setup': 208 | setup(e.data.path,e.data.listing_type,e.data.NMOS_mode,e.data.halt_on_BRK); 209 | break; 210 | case 'debug': 211 | if (debugBuffer.length!=0) 212 | { 213 | self.postMessage({cmd:"debug",debugBuffer}); 214 | debugBuffer=[]; 215 | } 216 | break; 217 | case 'cycles': 218 | self.postMessage({cmd:"cycles",cycle_count}); 219 | break; 220 | case 'single': 221 | //debugflag='
Start PC: ' + PC.toString(16).toUpperCase() + '(' + mem[PC].toString(16).toUpperCase() + ')' 222 | CalcAddress=-1; 223 | if (cycleLogActivated) recordCycle(); 224 | else opList[mem[bank(PC++)]](); 225 | //debugflag+='
End PC: ' + PC.toString(16).toUpperCase() + '(' + mem[PC].toString(16).toUpperCase() + ')' 226 | //break; 227 | case 'update': 228 | debugflag+='Cycles: ' + cycle_count; 229 | self.postMessage({cmd:'update',PC,A,X,Y,SP,FlagC, 230 | FlagZ,FlagI,FlagD,FlagB,FlagV,FlagN,debugflag, 231 | mem,CalcAddress,RamBank1,RamBank2,RamBank3,RomBank}); 232 | break; 233 | case 'run': 234 | if (running==0) 235 | { 236 | //self.postMessage({cmd:"msgbox",msg:"begin running"}); 237 | running=1; 238 | cycleFunc(); 239 | } 240 | //else self.postMessage({cmd:"msgbox",msg:"did not begin running"}); 241 | break; 242 | case 'stop': 243 | if (running==1) 244 | { 245 | //self.postMessage({cmd:"msgbox",msg:"begin stopping"}); 246 | running=0; 247 | self.postMessage({cmd:"stopped"}); 248 | } 249 | //else self.postMessage({cmd:"msgbox",msg:"did not begin stopping"}); 250 | break; 251 | case 'reset': 252 | PC=mem[0xFFFC]+(mem[0xFFFD]<<8); 253 | FlagD=0; 254 | //What other flags get set at startup? I? B? 255 | break; 256 | case 'keys': 257 | keyBuffer=keyBuffer.concat(e.data.keys); 258 | break; 259 | case 'check screen': 260 | if (GraphicsDirty) 261 | { 262 | self.postMessage({cmd:"screen update",screenMem:mem.slice(GFX_MEM_BEGIN,GFX_MEM_END)}); 263 | GraphicsDirty=false; 264 | } 265 | break; 266 | case 'reset cycles': 267 | cycle_count=0; 268 | break; 269 | case 'memory dump': 270 | temp_str="" 271 | for (let i=0;i=32)&&(mem[i*BANK_SIZE+j]<=126)) 288 | { 289 | temp_chars+=String.fromCharCode(mem[i*BANK_SIZE+j]); 290 | } 291 | else temp_chars+="."; 292 | 293 | if (j%16!=15) temp_chars+="."; 294 | else 295 | { 296 | temp_str+=temp_vals+"| "+temp_chars+"\n"; 297 | temp_chars=""; 298 | temp_vals=""; 299 | } 300 | } 301 | temp_str+=temp_vals+"| "+temp_chars+"\n"; 302 | temp_chars=""; 303 | temp_vals=""; 304 | } 305 | self.postMessage({cmd:"memory dump",memDump:temp_str}); 306 | break; 307 | case 'memory viewer': 308 | self.postMessage({cmd:'memory viewer',mem}); 309 | break; 310 | case 'cycle table': 311 | self.postMessage({cmd:'cycle table',cycleLog}); 312 | break; 313 | case 'cycle log on': 314 | cycleLogActivated=true; 315 | break; 316 | } 317 | } 318 | 319 | 320 | //************** 321 | //*DEBUG OUTPUT* 322 | //************** 323 | function debugMsg(msg) 324 | { 325 | self.postMessage({cmd:"msgbox",msg:msg}); 326 | } 327 | 328 | 329 | //**************** 330 | //*SETUP FUNCTION* 331 | //**************** 332 | 333 | function setup(path,list_style,NMOS,BRK) 334 | { 335 | //Moved above since needed before receive message for setup 336 | //self.addEventListener('message', OnMessage , false); 337 | 338 | //self.postMessage({cmd:"status",msg:"zeroing memory"}); 339 | //for (i=0;i<0x40000;i++) mem[i]=0; 340 | 341 | var record_bytes=0; 342 | var record_address=0; 343 | var record_hi_address=0; 344 | var bytes_written=0; 345 | var listing=[]; 346 | var labellist=[]; 347 | 348 | GraphicsDirty=false; 349 | NMOS_mode=NMOS; 350 | halt_on_BRK=BRK; 351 | 352 | //Loading listing and hex files 353 | self.postMessage({cmd:"status",msg:"loading listing"}); 354 | var myRequest = new Request(path+'listing.lst'); 355 | fetch(myRequest).then(function(response) 356 | { 357 | return response.text().then(function(text) 358 | { 359 | //self.postMessage({cmd:"status",msg:"raw lst loaded (" + ((text.length)/1024).toFixed(1) + "k)"}); 360 | self.postMessage({cmd:"status",msg:"raw listing loaded"}); 361 | 362 | //Old version from Kowalski listing 363 | if (list_style=="Kowalski") 364 | { 365 | var listlines=text.split("\n"); 366 | var error_msg=''; 367 | for (i=0;i0) 552 | { 553 | skip_lines--; 554 | continue; 555 | } 556 | 557 | let addline=false; 558 | let address=listlines[i].substring(13,17).trim(); 559 | 560 | //First character of line after main listing is 12 (Form feed control character) 561 | if (listlines[i].charCodeAt(0)==12) 562 | { 563 | skip_lines=2; 564 | } 565 | //No address means continued line or output from console, so ignore 566 | else if (address.length!=0) 567 | { 568 | address=("0000"+address).slice(-4); 569 | //Valid lines have colon. Check should not be necessary but just in case 570 | if (listlines[i][18]==":") 571 | { 572 | //Check if any bytes were laid down 573 | if (((listlines[i][20]>="0")&&(listlines[i][20]<="9"))||((listlines[i][20]>="A")&&(listlines[i][20]<="F"))) 574 | if (((listlines[i][21]>="0")&&(listlines[i][21]<="9"))||((listlines[i][21]>="A")&&(listlines[i][21]<="F"))) 575 | if (listlines[i][22]==" ") addline=true; 576 | //If no bytes laid down, check for label 577 | //(AS supports label without colon if in first column but assume colon here) 578 | if (!addline) 579 | { 580 | let tempstr=listlines[i].substring(40).trim(); 581 | if (tempstr.indexOf(":")!=-1) 582 | { 583 | //Cut off at colon 584 | tempstr=tempstr.substring(0,tempstr.indexOf(":")); 585 | //Remove leading period if exists 586 | if (tempstr[0]==".") tempstr=tempstr.substring(1); 587 | //Label can't start with a number 588 | if ((tempstr[0]<"0")||(tempstr[0]>"9")) 589 | { 590 | //Must contain only valid characters 591 | if (tempstr.match(/^[_a-z0-9]+$/i)) addline=true; 592 | } 593 | } 594 | } 595 | } 596 | } 597 | 598 | //tempmsg=i + listlines[i]; 599 | //tempmsg+="$"+listlines[i].substring(40); 600 | //self.postMessage({cmd:"msgbox",msg:tempmsg}); 601 | if (error_msg!='') 602 | { 603 | self.postMessage({cmd:"status",msg:"unable to load listing file!"}); 604 | self.postMessage({cmd:"error",msg:error_msg}); 605 | return; 606 | } 607 | if (addline) 608 | { 609 | let line=listlines[i].substring(40).trim(); 610 | listing.push({address:parseInt("0x"+address),line:line}); 611 | } 612 | } 613 | } 614 | else if (list_style=="AS-142.251") 615 | { 616 | //Even newer version for Macroassembler AS 617 | //Like CA65, does not treat labels separately 618 | //NOTE: AS above had spaces between columns 619 | // - upgrade to 1.42 Bld 251 removed spaces 620 | // - USE THIS GOING FORWARD! 621 | 622 | let listlines=text.split("\n"); 623 | let error_msg=''; 624 | let skip_lines=0; 625 | //Skip first 3 rows 626 | for (i=3;i0) 630 | { 631 | skip_lines--; 632 | continue; 633 | } 634 | 635 | let addline=false; 636 | let first_slash=listlines[i].indexOf("/"); 637 | let first_colon=listlines[i].indexOf(":"); 638 | let address=""; 639 | if ((first_slash==0)||(first_colon==0)) address=""; 640 | else address=listlines[i].substring(first_slash+1,first_colon).trim(); 641 | 642 | //First character of line after main listing is 12 (Form feed control character) 643 | if (listlines[i].charCodeAt(0)==12) 644 | { 645 | skip_lines=2; 646 | } 647 | //No address means continued line or output from console, so ignore 648 | else if (address.length!=0) 649 | { 650 | address=("0000"+address).slice(-4); 651 | //Valid lines have colon. Check should not be necessary but just in case 652 | if (listlines[i][11]==":") 653 | { 654 | //Check if any bytes were laid down 655 | if (((listlines[i][13]>="0")&&(listlines[i][13]<="9"))||((listlines[i][13]>="A")&&(listlines[i][13]<="F"))) 656 | if (((listlines[i][14]>="0")&&(listlines[i][14]<="9"))||((listlines[i][14]>="A")&&(listlines[i][14]<="F"))) 657 | if (listlines[i][15]==" ") addline=true; 658 | //If no bytes laid down, check for label 659 | //(AS supports label without colon if in first column but assume colon here) 660 | if (!addline) 661 | { 662 | let tempstr=listlines[i].substring(44).trim(); 663 | if (tempstr.indexOf(":")!=-1) 664 | { 665 | //Cut off at colon 666 | tempstr=tempstr.substring(0,tempstr.indexOf(":")); 667 | //Remove leading period if exists 668 | if (tempstr[0]==".") tempstr=tempstr.substring(1); 669 | //Label can't start with a number 670 | if ((tempstr[0]<"0")||(tempstr[0]>"9")) 671 | { 672 | //Must contain only valid characters 673 | if (tempstr.match(/^[_a-z0-9]+$/i)) addline=true; 674 | } 675 | } 676 | } 677 | } 678 | } 679 | 680 | //tempmsg=i + listlines[i]; 681 | //tempmsg+="$"+listlines[i].substring(40); 682 | //self.postMessage({cmd:"msgbox",msg:tempmsg}); 683 | if (error_msg!='') 684 | { 685 | self.postMessage({cmd:"status",msg:"unable to load listing file!"}); 686 | self.postMessage({cmd:"error",msg:error_msg}); 687 | return; 688 | } 689 | if (addline) 690 | { 691 | let line=listlines[i].substring(40).trim(); 692 | //Don't show line with bytes but no text since probably bytes overflowing from line above 693 | if (line!="") 694 | listing.push({address:parseInt("0x"+address),line:line}); 695 | } 696 | } 697 | } 698 | else if (list_style=="Generic") 699 | { 700 | let listlines=text.split("\n"); 701 | let error_msg=''; 702 | 703 | for (i=0;i x.charCodeAt(0))); 728 | 729 | self.postMessage({cmd:"status",msg:"loading input"}); 730 | var myRequest = new Request(path+'input.txt'); 731 | fetch(myRequest).then(function(response) 732 | { 733 | 734 | return response.text().then(function(text) 735 | { 736 | inputBuffer=inputBuffer.concat(text.split('').map(x => x.charCodeAt(0))); 737 | 738 | self.postMessage({cmd:"status",msg:"loading hex"}); 739 | var myRequest = new Request(path+'prog.hex'); 740 | fetch(myRequest).then(function(response) 741 | { 742 | return response.text().then(function(text) 743 | { 744 | //self.postMessage({cmd:"status",msg:"raw hex loaded (" + ((text.length)/1024).toFixed(1) + "k)"}); 745 | self.postMessage({cmd:"status",msg:"raw hex loaded"}); 746 | var lines = text.split("\n"); 747 | for (i=0;i="0".charCodeAt(0))&&(hexchar.charCodeAt(0)<="9".charCodeAt(0))) 819 | { 820 | return hexchar.charCodeAt(0)-"0".charCodeAt(0); 821 | } 822 | else return hexchar.charCodeAt(0)-"A".charCodeAt(0)+10; 823 | } 824 | function IsHexChar(hexchar) 825 | { 826 | if ((hexchar.charCodeAt(0)>="0".charCodeAt(0))&&(hexchar.charCodeAt(0)<="9".charCodeAt(0))) 827 | return true; 828 | else if ((hexchar.charCodeAt(0)>="A".charCodeAt(0))&&(hexchar.charCodeAt(0)<="F".charCodeAt(0))) 829 | return true; 830 | else return false; 831 | } 832 | 833 | function IsNumChar(hexchar) 834 | { 835 | if ((hexchar.charCodeAt(0)>="0".charCodeAt(0))&&(hexchar.charCodeAt(0)<="9".charCodeAt(0))) 836 | return true; 837 | else return false; 838 | } 839 | 840 | function IsAlphaChar(hexchar) 841 | { 842 | if ((hexchar.charCodeAt(0)>="A".charCodeAt(0))&&(hexchar.charCodeAt(0)<="Z".charCodeAt(0))) 843 | return true; 844 | else if ((hexchar.charCodeAt(0)>="a".charCodeAt(0))&&(hexchar.charCodeAt(0)<="z".charCodeAt(0))) 845 | return true; 846 | else if (hexchar[0]=='_') return true; 847 | else return false; 848 | } 849 | 850 | 851 | //*************************************** 852 | //*MEMORY BANKING FUNCTIONS FOR EMULATOR* 853 | //*************************************** 854 | 855 | function bank(address) 856 | { 857 | //return address; //for debugging 858 | tempCalcBanked=0; 859 | if (address<0x200) 860 | { 861 | tempCalcBanked=address; 862 | return tempCalcBanked; 863 | } 864 | else if (address<0x4000) tempCalcBanked=address+RamBank1; //RAM Bank 0: 0x200- 0x3FFF 865 | else if (address<0x8000) tempCalcBanked=address+RamBank2-0x4000; //RAM Bank 1: 0x4000-0x7FFF 866 | else if (address<0xC000) tempCalcBanked=address+RamBank3-0x8000; //RAM Bank 2: 0x8000-0xBFFF 867 | //else return address+RomBank; //ROM Bank: 0xC000-0xFFFF 868 | else 869 | { 870 | tempCalcBanked=address+RomBank-0xC000; //ROM Bank: 0xC000-0xFFFF 871 | return tempCalcBanked; 872 | } 873 | //Mark graphics dirty if access to graphics mem between 64k and 92k 874 | if ((tempCalcBanked>=GFX_MEM_BEGIN)&&(tempCalcBanked=PERIPHERALS_BEGIN) 887 | { 888 | switch (CalcAddress&0xFFFF) 889 | { 890 | case RAM_BANK1: 891 | RamBank1=BANK_SIZE*data; 892 | break; 893 | case RAM_BANK2: 894 | RamBank2=BANK_SIZE*data; 895 | break; 896 | case RAM_BANK3: 897 | RamBank3=BANK_SIZE*data; 898 | break; 899 | case ROM_BANK: 900 | RomBank=BANK_SIZE*data; 901 | break; 902 | case DEBUG: 903 | debugBuffer.push(data); 904 | break; 905 | case DEBUG_HEX: 906 | let hexout=data.toString(16).toUpperCase(); 907 | if (hexout.length==1) 908 | { 909 | debugBuffer.push("0".charCodeAt(0)); 910 | debugBuffer.push(hexout.charCodeAt(0)); 911 | } 912 | else 913 | { 914 | debugBuffer.push(hexout.charCodeAt(0)); 915 | debugBuffer.push(hexout.charCodeAt(1)); 916 | } 917 | break; 918 | case DEBUG_DEC: 919 | let decout=data.toString(); 920 | for (i=0;i=PERIPHERALS_BEGIN) 982 | { 983 | switch (CalcAddress&0xFFFF) 984 | { 985 | case KB_INPUT: 986 | if (keyBuffer.length==0) return 0; 987 | else 988 | { 989 | //Barry was having trouble with key being undefined 990 | //console.log("Worker key read: "); 991 | //console.log(" buffer length: ",keyBuffer.length); 992 | const key=keyBuffer.shift(); 993 | //console.log(" key: ",key); 994 | return key; 995 | } 996 | break; 997 | case TIMER_MS4: 998 | //return parseInt((Date.now()%1000)/4); 999 | return parseInt((performance.now()%1000)/4); 1000 | break; 1001 | case TIMER_S: 1002 | //return parseInt((Date.now()/1000)%256); 1003 | return parseInt((performance.now()/1000)%256); 1004 | break; 1005 | case FILE_INPUT: 1006 | if (inputBuffer.length==0) return 0; 1007 | else 1008 | { 1009 | const new_byte=inputBuffer.shift(); 1010 | return new_byte; 1011 | } 1012 | default: 1013 | return data; 1014 | break; 1015 | } 1016 | } 1017 | else return data; 1018 | } 1019 | 1020 | 1021 | //************************************** 1022 | //*MEMORY ACCESS FUNCTIONS FOR EMULATOR* 1023 | //************************************** 1024 | 1025 | function memADDRESS() 1026 | { 1027 | CalcAddress=mem[bank(PC++)]; 1028 | CalcAddress+=(0x100*(mem[bank(PC++)])); 1029 | const temp=bank(CalcAddress); 1030 | CalcBanked=tempCalcBanked; 1031 | return mem[temp]; 1032 | } 1033 | function memADDRESSX() 1034 | { 1035 | CalcAddress=mem[bank(PC++)]; 1036 | CalcAddress+=(0x100*(mem[bank(PC++)])); 1037 | const high_byte=CalcAddress&0xFF00; 1038 | CalcAddress+=X; 1039 | if (high_byte!=(CalcAddress&0xFF00)) 1040 | { 1041 | cycle_count++; 1042 | cycle_penalty=1; 1043 | } 1044 | else cycle_penalty=0; 1045 | CalcAddress&=0xFFFF; 1046 | const temp=bank(CalcAddress); 1047 | CalcBanked=tempCalcBanked; 1048 | return mem[temp]; 1049 | } 1050 | function memADDRESSY() 1051 | { 1052 | CalcAddress=mem[bank(PC++)]; 1053 | CalcAddress+=(0x100*(mem[bank(PC++)])); 1054 | const high_byte=CalcAddress&0xFF00; 1055 | CalcAddress+=Y; 1056 | if (high_byte!=(CalcAddress&0xFF00)) 1057 | { 1058 | cycle_count++; 1059 | cycle_penalty=1; 1060 | } 1061 | else cycle_penalty=0; 1062 | CalcAddress&=0xFFFF; 1063 | const temp=bank(CalcAddress); 1064 | CalcBanked=tempCalcBanked; 1065 | return mem[temp]; 1066 | } 1067 | function memIMMED() 1068 | { 1069 | return mem[bank(PC++)]; 1070 | } 1071 | function memIX() 1072 | { 1073 | //No banking for pointer since always in ZP 1074 | const t0=(mem[bank(PC++)]+X)&0xFF; 1075 | CalcAddress=(mem[t0]+(mem[t0+1]<<8))&0xFFFF; 1076 | const temp=bank(CalcAddress); 1077 | CalcBanked=tempCalcBanked; 1078 | return mem[temp]; 1079 | } 1080 | function memIY() 1081 | { 1082 | //No banking for pointer since always in ZP 1083 | const t0=mem[bank(PC++)]; 1084 | CalcAddress=mem[t0]+(mem[(t0+1)&0xFF]<<8); 1085 | const high_byte=CalcAddress&0xFF00; 1086 | CalcAddress+=Y; 1087 | if (high_byte!=(CalcAddress&0xFF00)) 1088 | { 1089 | cycle_count++; 1090 | cycle_penalty=1; 1091 | } 1092 | else cycle_penalty=0; 1093 | CalcAddress&=0xFFFF; 1094 | const temp=bank(CalcAddress); 1095 | CalcBanked=tempCalcBanked; 1096 | return mem[temp]; 1097 | } 1098 | function memIZP() 1099 | { 1100 | //No banking for pointer since always in ZP 1101 | const t0=mem[bank(PC++)]; 1102 | //CalcAddress=mem[t0]+(mem[t0+1]<<8); 1103 | CalcAddress=(mem[t0]+(mem[(t0+1)&0xFF]<<8)); 1104 | const temp=bank(CalcAddress); 1105 | CalcBanked=tempCalcBanked; 1106 | return mem[temp]; 1107 | } 1108 | function memZP() 1109 | { 1110 | //No banking since always in ZP 1111 | CalcAddress=mem[bank(PC++)]; 1112 | CalcBanked=CalcAddress; 1113 | return mem[CalcAddress]; 1114 | } 1115 | function memZPX() 1116 | { 1117 | //No banking since always in ZP 1118 | CalcAddress=(mem[bank(PC++)]+X)&0xFF; 1119 | CalcBanked=CalcAddress; 1120 | return mem[CalcAddress]; 1121 | } 1122 | function memZPY() 1123 | { 1124 | //No banking since always in ZP 1125 | CalcAddress=(mem[bank(PC++)]+Y)&0xFF; 1126 | CalcBanked=CalcAddress; 1127 | return mem[CalcAddress]; 1128 | } 1129 | 1130 | 1131 | 1132 | //*********************** 1133 | //*EMULATED INSTRUCTIONS* 1134 | //*********************** 1135 | 1136 | function subADC(oper) 1137 | { 1138 | if (FlagD==1) 1139 | { 1140 | var t1=(A&0xF)+(oper&0xF)+FlagC; 1141 | if (t1>9) t1+=6; 1142 | t1+=(A&0xF0)+(oper&0xF0); 1143 | if (t1>=0xA0) t1+=0x60; 1144 | cycle_count++; 1145 | } 1146 | else var t1=A+oper+FlagC; 1147 | if (t1>=0x100){t1&=0xFF;FlagC=1;}else FlagC=0; 1148 | if ((A<0x80)&&(oper<0x80)&&(t1>=0x80)) FlagV=1; 1149 | else if ((A>=0x80)&&(oper>=0x80)&&(t1<0x80)) FlagV=1; 1150 | else FlagV=0; 1151 | A=t1; 1152 | if (A==0) FlagZ=1;else FlagZ=0; 1153 | if (A>=0x80) FlagN=1;else FlagN=0; 1154 | } 1155 | function subAND(oper) 1156 | { 1157 | A&=oper; 1158 | if (A==0) FlagZ=1;else FlagZ=0; 1159 | if (A>=0x80) FlagN=1;else FlagN=0; 1160 | } 1161 | function subASL(oper) 1162 | { 1163 | oper<<=1; 1164 | if (oper>=0x100){FlagC=1;oper&=0xFF;}else FlagC=0; 1165 | if (oper==0) FlagZ=1;else FlagZ=0; 1166 | if (oper>=0x80) FlagN=1;else FlagN=0; 1167 | mem[bank(CalcAddress)]=oper; 1168 | } 1169 | function subBBR(oper) 1170 | { 1171 | if ((memZP()&oper)==0) 1172 | { 1173 | var t0=memIMMED(); 1174 | if (t0>=0x80) PC-=(0x100-t0); 1175 | else PC+=t0; 1176 | } 1177 | else PC++; 1178 | } 1179 | function subBBS(oper) 1180 | { 1181 | if ((memZP()&oper)!=0) 1182 | { 1183 | var t0=memIMMED(); 1184 | if (t0>=0x80) PC-=(0x100-t0); 1185 | else PC+=t0; 1186 | } 1187 | else PC++; 1188 | } 1189 | function subBIT(oper) 1190 | { 1191 | if ((A&oper)==0) FlagZ=1;else FlagZ=0; 1192 | if (oper&0x80) FlagN=1;else FlagN=0; 1193 | if (oper&0x40) FlagV=1;else FlagV=0; 1194 | } 1195 | function subCMP(oper) 1196 | { 1197 | var temp=A-oper; 1198 | if (temp==0) FlagZ=1;else FlagZ=0; 1199 | if (temp>=0) FlagC=1;else FlagC=0; 1200 | if (temp<0) temp+=0x100; 1201 | if (temp>=0x80) FlagN=1;else FlagN=0; 1202 | } 1203 | function subCPX(oper) 1204 | { 1205 | var temp=X-oper; 1206 | if (temp==0) FlagZ=1;else FlagZ=0; 1207 | if (temp>=0) FlagC=1;else FlagC=0; 1208 | if (temp<0) temp+=0x100; 1209 | if (temp>=0x80) FlagN=1;else FlagN=0; 1210 | } 1211 | function subCPY(oper) 1212 | { 1213 | var temp=Y-oper; 1214 | if (temp==0) FlagZ=1;else FlagZ=0; 1215 | if (temp>=0) FlagC=1;else FlagC=0; 1216 | if (temp<0) temp+=0x100; 1217 | if (temp>=0x80) FlagN=1;else FlagN=0; 1218 | } 1219 | function subDEC(oper) 1220 | { 1221 | if (oper==0) oper=0xFF; 1222 | else oper--; 1223 | if (oper==0) FlagZ=1;else FlagZ=0; 1224 | if (oper>=0x80) FlagN=1;else FlagN=0; 1225 | mem[bank(CalcAddress)]=oper; 1226 | } 1227 | function subEOR(oper) 1228 | { 1229 | A^=oper; 1230 | if (A==0) FlagZ=1;else FlagZ=0; 1231 | if (A>=0x80) FlagN=1;else FlagN=0; 1232 | } 1233 | function subINC(oper) 1234 | { 1235 | if (oper==0xFF){oper=0;FlagZ=1;} else{oper++;FlagZ=0;} 1236 | if (oper>=0x80) FlagN=1;else FlagN=0; 1237 | mem[bank(CalcAddress)]=oper; 1238 | } 1239 | function subLDA(oper) 1240 | { 1241 | A=peripheral_read(oper); 1242 | if (A==0) FlagZ=1;else FlagZ=0; 1243 | if (A>=0x80) FlagN=1;else FlagN=0; 1244 | } 1245 | function subLDX(oper) 1246 | { 1247 | X=peripheral_read(oper); 1248 | if (X==0) FlagZ=1;else FlagZ=0; 1249 | if (X>=0x80) FlagN=1;else FlagN=0; 1250 | } 1251 | function subLDY(oper) 1252 | { 1253 | Y=peripheral_read(oper); 1254 | if (Y==0) FlagZ=1;else FlagZ=0; 1255 | if (Y>=0x80) FlagN=1;else FlagN=0; 1256 | } 1257 | function subLSR(oper) 1258 | { 1259 | if (oper&1) {FlagC=1;}else FlagC=0; 1260 | oper>>=1; 1261 | if (oper==0) FlagZ=1;else FlagZ=0; 1262 | //if (oper>=0x80) FlagN=1;else FlagN=0; 1263 | FlagN=0; 1264 | mem[bank(CalcAddress)]=oper; 1265 | } 1266 | function subORA(oper) 1267 | { 1268 | A|=oper; 1269 | if (A==0) FlagZ=1;else FlagZ=0; 1270 | if (A>=0x80) FlagN=1;else FlagN=0; 1271 | //debugflag+="\nFlagN: "+FlagN; 1272 | } 1273 | function subRMB(oper) 1274 | { 1275 | //No banking since zero page 1276 | CalcAddress=mem[bank(PC++)]; 1277 | mem[CalcAddress]=mem[CalcAddress]&oper; 1278 | } 1279 | function subROL(oper) 1280 | { 1281 | oper=(oper<<1)+FlagC; 1282 | if (oper>=0x100){FlagC=1;oper&=0xFF;}else FlagC=0; 1283 | if (oper==0) FlagZ=1;else FlagZ=0; 1284 | if (oper>=0x80) FlagN=1;else FlagN=0; 1285 | mem[bank(CalcAddress)]=oper; 1286 | } 1287 | function subROR(oper) 1288 | { 1289 | var t0; 1290 | if (oper&1) t0=1;else t0=0; 1291 | oper>>=1; 1292 | if (FlagC) oper|=0x80; 1293 | FlagC=t0; 1294 | if (oper==0) FlagZ=1;else FlagZ=0; 1295 | if (oper>=0x80) FlagN=1;else FlagN=0; 1296 | mem[bank(CalcAddress)]=oper; 1297 | } 1298 | function subSBC(oper) 1299 | { 1300 | if (FlagD==1) 1301 | { 1302 | if ((oper==0)&&(FlagC==0)) 1303 | { 1304 | oper=1; 1305 | FlagC=1; 1306 | } 1307 | var t1=(A&0xF)+(9-(oper&0xF)+FlagC); 1308 | if (t1>9) t1+=6; 1309 | t1+=(A&0xF0)+(0x90-(oper&0xF0)); 1310 | if (t1>0x99) t1+=0x60; 1311 | if (t1>=0x100) 1312 | { 1313 | t1-=0x100; 1314 | FlagC=1; 1315 | } 1316 | else FlagC=0; 1317 | //May happen if oper is not valid BCD 1318 | if (t1<0) t1=0; 1319 | cycle_count++; 1320 | } 1321 | else 1322 | { 1323 | var t1=A-oper-1+FlagC; 1324 | if (t1<0){t1+=0x100;FlagC=0;}else FlagC=1; 1325 | } 1326 | if ((A<0x80)&&(oper>=0x80)&&(t1>=0x80)) FlagV=1; 1327 | else if ((A>=0x80)&&(oper<0x80)&&(t1<0x80)) FlagV=1; 1328 | else FlagV=0; 1329 | A=t1; 1330 | if (A==0) FlagZ=1;else FlagZ=0; 1331 | if (A>=0x80) FlagN=1;else FlagN=0; 1332 | } 1333 | function subSMB(oper) 1334 | { 1335 | //No banking since zero page 1336 | CalcAddress=mem[bank(PC++)]; 1337 | mem[bank(CalcAddress)]=mem[bank(CalcAddress)]|oper; 1338 | } 1339 | function subSTA() 1340 | {peripheral(A);mem[bank(CalcAddress)]=A;} 1341 | function subSTX() 1342 | {peripheral(X);mem[bank(CalcAddress)]=X;} 1343 | function subSTY() 1344 | {peripheral(Y);mem[bank(CalcAddress)]=Y;} 1345 | function subSTZ() 1346 | {peripheral(0);mem[bank(CalcAddress)]=0;} 1347 | function subTRB(oper) 1348 | { 1349 | if ((A&oper)==0) FlagZ=1;else FlagZ=0; 1350 | mem[bank(CalcAddress)]=(A^0xFF)&oper; 1351 | } 1352 | function subTSB(oper) 1353 | { 1354 | if ((A&oper)==0) FlagZ=1;else FlagZ=0; 1355 | mem[bank(CalcAddress)]=A|oper; 1356 | } 1357 | 1358 | function opBRK() //0x00 1359 | { 1360 | if (halt_on_BRK) 1361 | { 1362 | PC++; 1363 | if (running==1) 1364 | { 1365 | running=0; 1366 | self.postMessage({cmd:"stopped"}); 1367 | } 1368 | } 1369 | else 1370 | { 1371 | mem[0x100+SP]=(PC+1)>>8; 1372 | if (SP==0) SP=0xFF;else SP--; 1373 | mem[0x100+SP]=(PC+1)&0xFF; 1374 | if (SP==0) SP=0xFF;else SP--; 1375 | opPHP(); 1376 | cycle_count-=3; //Counter-act cycle adjustment for PHP 1377 | FlagI=1; 1378 | if (!NMOS_mode) FlagD=0; 1379 | PC=mem[bank(0xFFFE)]+(mem[bank(0xFFFF)]<<8); 1380 | } 1381 | cycle_count+=7; 1382 | } 1383 | function opORA_IX(){subORA(memIX());cycle_count+=6;} //0x01 1384 | function opNOP_IMMED(){PC++;cycle_count+=2;} //0x02 1385 | function opNOP(){cycle_count+=2;} //0x03 1386 | function opTSB_ZP(){subTSB(memZP());cycle_count+=5;} //0x04 1387 | function opORA_ZP(){subORA(memZP());cycle_count+=3;} //0x05 1388 | function opASL_ZP(){subASL(memZP());cycle_count+=5;} //0x06 1389 | function opRMB0(){subRMB(0xFE);cycle_count+=5;} //0x07 1390 | function opPHP() //0x08 1391 | { 1392 | mem[0x100+SP]=FlagC+FlagZ*2+FlagI*4+FlagD*8+ 1393 | FlagB*16+32+FlagV*64+FlagN*128; 1394 | if (SP==0) SP=0xFF; 1395 | else SP--; 1396 | cycle_count+=3; 1397 | } 1398 | function opORA_IMMED(){subORA(memIMMED());cycle_count+=2;} //0x09 1399 | function opASL() //0x0A 1400 | { 1401 | A<<=1; 1402 | if (A>=0x100){FlagC=1;A&=0xFF}else FlagC=0; 1403 | if (A==0) FlagZ=1;else FlagZ=0; 1404 | if (A>=0x80) FlagN=1;else FlagN=0; 1405 | cycle_count+=2; 1406 | } 1407 | //function opNOP() //0x0B 1408 | function opTSB_ADDRESS(){subTSB(memADDRESS());cycle_count+=6;} //0x0C 1409 | function opORA_ADDRESS(){subORA(memADDRESS());cycle_count+=4;} //0x0D 1410 | function opASL_ADDRESS(){subASL(memADDRESS());cycle_count+=6;} //0x0E 1411 | function opBBR0(){subBBR(0x01);cycle_count+=5;} //0x0F 1412 | function opBPL() //0x10 1413 | { 1414 | if (FlagN==0) 1415 | { 1416 | //const high_byte=PC&0xFF00; 1417 | const t0=memIMMED(); 1418 | const high_byte=PC&0xFF00; 1419 | if (t0>=0x80) PC-=(0x100-t0); 1420 | else PC+=t0; 1421 | if (high_byte!=(PC&0xFF00)) cycle_count++; 1422 | cycle_count++; 1423 | } 1424 | else PC++; 1425 | cycle_count+=2; 1426 | } 1427 | function opORA_IY(){subORA(memIY());cycle_count+=5;} //0x11 1428 | function opORA_IZP(){subORA(memIZP());cycle_count+=5;} //0x12 1429 | //function opNOP() //0x13 1430 | function opTRB_ZP(){subTRB(memZP());cycle_count+=5;} //0x14 1431 | function opORA_ZPX(){subORA(memZPX());cycle_count+=4;} //0x15 1432 | function opASL_ZPX(){subASL(memZPX());cycle_count+=6;} //0x16 1433 | function opRMB1(){subRMB(0xFD);cycle_count+=5;} //0x17 1434 | function opCLC(){FlagC=0;cycle_count+=2;} //0x18 1435 | function opORA_ADDRESSY(){subORA(memADDRESSY());cycle_count+=4;} //0x19 1436 | function opINC() //0x1A 1437 | { 1438 | if (A==0xFF){A=0;FlagZ=1;} else{A++;FlagZ=0;} 1439 | if (A>=0x80) FlagN=1;else FlagN=0; 1440 | cycle_count+=2; 1441 | } 1442 | //function opNOP() //0x1B 1443 | function opTRB_ADDRESS(){subTRB(memADDRESS());cycle_count+=6;} //0x1C 1444 | function opORA_ADDRESSX(){subORA(memADDRESSX());cycle_count+=4;} //0x1D 1445 | function opASL_ADDRESSX(){subASL(memADDRESSX());cycle_count+=6;} //0x1E 1446 | function opBBR1(){subBBR(0x02);cycle_count+=5;} //0x1F 1447 | function opJSR() //0x20 1448 | { 1449 | mem[0x100+SP]=(PC+1)>>8; 1450 | if (SP==0) SP=0xFF;else SP--; 1451 | mem[0x100+SP]=(PC+1)&0xFF; 1452 | if (SP==0) SP=0xFF;else SP--; 1453 | PC=mem[bank(PC)]+0x100*mem[bank(PC+1)]; 1454 | cycle_count+=6; 1455 | } 1456 | function opAND_IX(){subAND(memIX());cycle_count+=6;} //0x21 1457 | //function opNOP_IMMED() //0x22 1458 | //function opNOP() //0x23 1459 | function opBIT_ZP(){subBIT(memZP());cycle_count+=3;} //0x24 1460 | function opAND_ZP(){subAND(memZP());cycle_count+=3;} //0x25 1461 | function opROL_ZP(){subROL(memZP());cycle_count+=5;} //0x26 1462 | function opRMB2(){subRMB(0xFB);cycle_count+=5;} //0x27 1463 | function opPLP() //0x28 1464 | { 1465 | if (SP==0xFF) SP=0; 1466 | else SP++; 1467 | t0=mem[0x100+SP]; 1468 | if (t0&1) FlagC=1;else FlagC=0; 1469 | if (t0&2) FlagZ=1;else FlagZ=0; 1470 | if (t0&4) FlagI=1;else FlagI=0; 1471 | if (t0&8) FlagD=1;else FlagD=0; 1472 | //if (t0&16) FlagB=1;else FlagB=0; 1473 | FlagB=1; 1474 | if (t0&64) FlagV=1;else FlagV=0; 1475 | if (t0&128) FlagN=1;else FlagN=0; 1476 | cycle_count+=4; 1477 | } 1478 | function opAND_IMMED(){subAND(memIMMED());cycle_count+=2;} //0x29 1479 | function opROL() //0x2A 1480 | { 1481 | A=(A<<1)+FlagC; 1482 | if (A>=0x100){FlagC=1;A&=0xFF;}else FlagC=0; 1483 | if (A==0) FlagZ=1;else FlagZ=0; 1484 | if (A>=0x80) FlagN=1;else FlagN=0; 1485 | cycle_count+=2; 1486 | } 1487 | //function opNOP() //0x2B 1488 | function opBIT_ADDRESS(){subBIT(memADDRESS());cycle_count+=4;} //0x2C 1489 | function opAND_ADDRESS(){subAND(memADDRESS());cycle_count+=4;} //0x2D 1490 | function opROL_ADDRESS(){subROL(memADDRESS());cycle_count+=6;} //0x2E 1491 | function opBBR2(){subBBR(0x04);cycle_count+=5;} //0x2F 1492 | function opBMI() //0x30 1493 | { 1494 | if (FlagN==1) 1495 | { 1496 | //const high_byte=PC&0xFF00; 1497 | const t0=memIMMED(); 1498 | const high_byte=PC&0xFF00; 1499 | if (t0>=0x80) PC-=(0x100-t0); 1500 | else PC+=t0; 1501 | if (high_byte!=(PC&0xFF00)) cycle_count++; 1502 | cycle_count++; 1503 | } 1504 | else PC++; 1505 | cycle_count+=2; 1506 | } 1507 | function opAND_IY(){subAND(memIY());cycle_count+=5;} //0x31 1508 | function opAND_IZP(){subAND(memIZP());cycle_count+=5;} //0x32 1509 | //function opNOP() //0x33 1510 | function opBIT_ZPX(){subBIT(memZPX());cycle_count+=4;} //0x34 1511 | function opAND_ZPX(){subAND(memZPX());cycle_count+=4;} //0x35 1512 | function opROL_ZPX(){subROL(memZPX());cycle_count+=6;} //0x36 1513 | function opRMB3(){subRMB(0xF7);cycle_count+=5;} //0x37 1514 | function opSEC(){FlagC=1;cycle_count+=2;} //0x38 1515 | function opAND_ADDRESSY(){subAND(memADDRESSY());cycle_count+=4;} //0x39 1516 | function opDEC() //0x3A 1517 | { 1518 | if (A==0) A=0xFF; 1519 | else A--; 1520 | if (A==0) FlagZ=1;else FlagZ=0; 1521 | if (A>=0x80) FlagN=1;else FlagN=0; 1522 | cycle_count+=2; 1523 | } 1524 | //function opNOP() //0x3B 1525 | function opBIT_ADDRESSX(){subBIT(memADDRESSX());cycle_count+=4;} //0x3C 1526 | function opAND_ADDRESSX(){subAND(memADDRESSX());cycle_count+=4;} //0x3D 1527 | function opROL_ADDRESSX(){subROL(memADDRESSX());cycle_count+=6;} //0x3E 1528 | function opBBR3(){subBBR(0x08);cycle_count+=5;} //0x3F 1529 | function opRTI() //0x40 1530 | { 1531 | opPLP();//4 cycles 1532 | opRTS();//6 cycles 1533 | PC=(PC-1);//interrupt pushes PC, not PC-1 1534 | cycle_count-=5;//should be +5 overall 1535 | } 1536 | function opEOR_IX(){subEOR(memIX());cycle_count+=6;} //0x41 1537 | //function opNOP_IMMED() //0x42 1538 | //function opNOP() //0x43 1539 | function opNOP_ZP(){PC++;cycle_count+=3;} //0x44 1540 | function opEOR_ZP(){subEOR(memZP());cycle_count+=3;} //0x45 1541 | function opLSR_ZP(){subLSR(memZP());cycle_count+=5;} //0x46 1542 | function opRMB4(){subRMB(0xEF);cycle_count+=5;} //0x47 1543 | function opPHA() //0x48 1544 | { 1545 | mem[0x100+SP]=A; 1546 | if (SP==0) SP=0xFF; 1547 | else SP--; 1548 | cycle_count+=3; 1549 | } 1550 | function opEOR_IMMED(){subEOR(memIMMED());cycle_count+=2;} //0x49 1551 | function opLSR() //0x4A 1552 | { 1553 | if (A&1)FlagC=1;else FlagC=0; 1554 | A>>=1; 1555 | if (A==0) FlagZ=1;else FlagZ=0; 1556 | //if (A>=0x80) FlagN=1;else FlagN=0; 1557 | FlagN=0; 1558 | cycle_count+=2; 1559 | } 1560 | //function opNOP() //0x4B 1561 | function opJMP_ADDRESS() //0x4C 1562 | { 1563 | PC=mem[bank(PC)]+0x100*mem[bank(PC+1)]; 1564 | cycle_count+=3; 1565 | } 1566 | function opEOR_ADDRESS(){subEOR(memADDRESS());cycle_count+=4;} //0x4D 1567 | function opLSR_ADDRESS(){subLSR(memADDRESS());cycle_count+=6;} //0x4E 1568 | 1569 | function opBBR4(){subBBR(0x10);cycle_count+=5;} //0x4F 1570 | function opBVC() //0x50 1571 | { 1572 | if (FlagV==0) 1573 | { 1574 | //const high_byte=PC&0xFF00; 1575 | const t0=memIMMED(); 1576 | const high_byte=PC&0xFF00; 1577 | if (t0>=0x80) PC-=(0x100-t0); 1578 | else PC+=t0; 1579 | if (high_byte!=(PC&0xFF00)) cycle_count++; 1580 | cycle_count++; 1581 | } 1582 | else PC++; 1583 | cycle_count+=2; 1584 | } 1585 | function opEOR_IY(){subEOR(memIY());cycle_count+=5;} //0x51 1586 | function opEOR_IZP(){subEOR(memIZP());cycle_count+=5;} //0x52 1587 | //function opNOP() //0x53 1588 | function opNOP_ZPX(){PC++;cycle_count+=4;} //0x54 1589 | function opEOR_ZPX(){subEOR(memZPX());cycle_count+=4;} //0x55 1590 | function opLSR_ZPX(){subLSR(memZPX());cycle_count+=6;} //0x56 1591 | function opRMB5(){subRMB(0xDF);cycle_count+=5;} //0x57 1592 | function opCLI(){FlagI=0;cycle_count+=2;} //0x58 1593 | function opEOR_ADDRESSY(){subEOR(memADDRESSY());cycle_count+=4;} //0x59 1594 | function opPHY() //0x5A 1595 | { 1596 | mem[0x100+SP]=Y; 1597 | if (SP==0) SP=0xFF; 1598 | else SP--; 1599 | cycle_count+=3; 1600 | } 1601 | //function opNOP() //0x5B 1602 | function opNOP_ADDRESS(){PC+=2;cycle_count+=8;} //0x5C 1603 | function opEOR_ADDRESSX(){subEOR(memADDRESSX());cycle_count+=4;} //0x5D 1604 | function opLSR_ADDRESSX(){subLSR(memADDRESSX());cycle_count+=6;} //0x5E 1605 | function opBBR5(){subBBR(0x20);cycle_count+=5;} //0x5F 1606 | function opRTS() //0x60 1607 | { 1608 | if (SP==0xFF) SP=0; 1609 | else SP++; 1610 | PC=mem[0x100+SP]; 1611 | if (SP==0xFF) SP=0; 1612 | else SP++; 1613 | PC+=mem[0x100+SP]*0x100+1; 1614 | cycle_count+=6; 1615 | } 1616 | function opADC_IX(){subADC(memIX());cycle_count+=6;} //0x61 1617 | //function opNOP_IMMED() //0x62 1618 | //function opNOP() //0x63 1619 | function opSTZ_ZP(){memZP();subSTZ();cycle_count+=3;} //0x64 1620 | function opADC_ZP(){subADC(memZP());cycle_count+=3;} //0x65 1621 | function opROR_ZP(){subROR(memZP());cycle_count+=5;} //0x66 1622 | function opRMB6(){subRMB(0xBF);cycle_count+=5;} //0x67 1623 | function opPLA() //0x68 1624 | { 1625 | if (SP==0xFF) SP=0; 1626 | else SP++; 1627 | A=mem[0x100+SP]; 1628 | if (A==0) FlagZ=1;else FlagZ=0; 1629 | if (A>=0x80) FlagN=1;else FlagN=0; 1630 | cycle_count+=4; 1631 | } 1632 | function opADC_IMMED(){subADC(memIMMED());cycle_count+=2;} //0x69 1633 | function opROR() //0x6A 1634 | { 1635 | var t0; 1636 | if (A&1) t0=1;else t0=0; 1637 | A>>=1; 1638 | if (FlagC) A|=0x80; 1639 | FlagC=t0; 1640 | if (A==0) FlagZ=1;else FlagZ=0; 1641 | if (A>=0x80) FlagN=1;else FlagN=0; 1642 | cycle_count+=2; 1643 | } 1644 | //function opNOP() //0x6B 1645 | function opJMP_I() //0x6C 1646 | { 1647 | if ((NMOS_mode)&&(mem[bank(PC)]==0xFF)) 1648 | { 1649 | //Keep PC on this instruction for debugging 1650 | PC--; 1651 | 1652 | if (running==1) 1653 | { 1654 | running=0; 1655 | self.postMessage({cmd:"stopped"}); 1656 | } 1657 | 1658 | self.postMessage({cmd:"msgbox",msg:"Trapped: JMP (xxFF) in NMOS mode!"}); 1659 | } 1660 | else 1661 | { 1662 | var t0=mem[bank(PC)]+0x100*mem[bank(PC+1)]; 1663 | PC=mem[bank(t0)]+0x100*mem[bank(t0+1)]; 1664 | } 1665 | cycle_count+=6; 1666 | } 1667 | function opADC_ADDRESS(){subADC(memADDRESS());cycle_count+=4;} //0x6D 1668 | function opROR_ADDRESS(){subROR(memADDRESS());cycle_count+=6;} //0x6E 1669 | function opBBR6(){subBBR(0x40);cycle_count+=5;} //0x6F 1670 | function opBVS() //0x70 1671 | { 1672 | if (FlagV==1) 1673 | { 1674 | //const high_byte=PC&0xFF00; 1675 | const t0=memIMMED(); 1676 | const high_byte=PC&0xFF00; 1677 | if (t0>=0x80) PC-=(0x100-t0); 1678 | else PC+=t0; 1679 | if (high_byte!=(PC&0xFF00)) cycle_count++; 1680 | cycle_count++; 1681 | } 1682 | else PC++; 1683 | cycle_count+=2; 1684 | } 1685 | function opADC_IY(){subADC(memIY());cycle_count+=5;} //0x71 1686 | function opADC_IZP(){subADC(memIZP());cycle_count+=5} //0x72 1687 | //function opNOP() //0x73 1688 | function opSTZ_ZPX(){memZPX();subSTZ();cycle_count+=4;} //0x74 1689 | function opADC_ZPX(){subADC(memZPX());cycle_count+=4;} //0x75 1690 | function opROR_ZPX(){subROR(memZPX());cycle_count+=6;} //0x76 1691 | function opRMB7(){subRMB(0x7F);cycle_count+=5;} //0x77 1692 | function opSEI(){FlagI=1;cycle_count+=2;} //0x78 1693 | function opADC_ADDRESSY(){subADC(memADDRESSY());cycle_count+=4;} //0x79 1694 | function opPLY() //0x7A 1695 | { 1696 | if (SP==0xFF) SP=0; 1697 | else SP++; 1698 | Y=mem[0x100+SP]; 1699 | if (Y==0) FlagZ=1;else FlagZ=0; 1700 | if (Y>=0x80) FlagN=1;else FlagN=0; 1701 | cycle_count+=4; 1702 | } 1703 | //function opNOP() //0x7B 1704 | function opJMP_IADDRESSX() //0x7C 1705 | { 1706 | var t0=mem[bank(PC)]+0x100*mem[bank(PC+1)]+X; 1707 | PC=mem[bank(t0)]+0x100*mem[bank(t0+1)]; 1708 | cycle_count+=6; 1709 | } 1710 | function opADC_ADDRESSX(){subADC(memADDRESSX());cycle_count+=4;} //0x7D 1711 | function opROR_ADDRESSX(){subROR(memADDRESSX());cycle_count+=6;} //0x7E 1712 | function opBBR7(){subBBR(0x80);cycle_count+=5;} //0x7F 1713 | function opBRA() //0x80 1714 | { 1715 | const t0=memIMMED(); 1716 | const high_byte=PC&0xFF00; 1717 | if (t0>=0x80) PC-=(0x100-t0); 1718 | else PC+=t0; 1719 | if (high_byte!=(PC&0xFF00)) cycle_count++; 1720 | cycle_count+=3; 1721 | } 1722 | function opSTA_IX(){memIX();subSTA();cycle_count+=6;} //0x81 1723 | //function opNOP_IMMED() //0x82 1724 | //function opNOP() //0x83 1725 | function opSTY_ZP(){memZP();subSTY();cycle_count+=3;} //0x84 1726 | function opSTA_ZP(){memZP();subSTA();cycle_count+=3;} //0x85 1727 | function opSTX_ZP(){memZP();subSTX();cycle_count+=3;} //0x86 1728 | function opSMB0(){subSMB(0x01);cycle_count+=5;} //0x87 1729 | function opDEY() //0x88 1730 | { 1731 | if (Y==0) Y=0xFF; 1732 | else Y--; 1733 | if (Y==0) FlagZ=1;else FlagZ=0; 1734 | if (Y>=0x80) FlagN=1;else FlagN=0; 1735 | cycle_count+=2; 1736 | } 1737 | function opBIT_IMMED() //0x89 1738 | { 1739 | if ((A&memIMMED())==0) FlagZ=1;else FlagZ=0; 1740 | cycle_count+=2; 1741 | } 1742 | function opTXA() //0x8A 1743 | { 1744 | A=X; 1745 | if (A==0) FlagZ=1;else FlagZ=0; 1746 | if (A>=0x80) FlagN=1;else FlagN=0; 1747 | cycle_count+=2; 1748 | } 1749 | //function opNOP() //0x8B 1750 | function opSTY_ADDRESS(){memADDRESS();subSTY();cycle_count+=4;} //0x8C 1751 | function opSTA_ADDRESS(){memADDRESS();subSTA();cycle_count+=4;} //0x8D 1752 | function opSTX_ADDRESS(){memADDRESS();subSTX();cycle_count+=4;} //0x8E 1753 | function opBBS0(){subBBS(0x01);cycle_count+=5;} //0x8F 1754 | function opBCC() //0x90 1755 | { 1756 | if (FlagC==0) 1757 | { 1758 | //const high_byte=PC&0xFF00; 1759 | const t0=memIMMED(); 1760 | const high_byte=PC&0xFF00; 1761 | if (t0>=0x80) PC-=(0x100-t0); 1762 | else PC+=t0; 1763 | if (high_byte!=(PC&0xFF00)) cycle_count++; 1764 | cycle_count++; 1765 | } 1766 | else PC++; 1767 | cycle_count+=2; 1768 | } 1769 | function opSTA_IY() //0x91 1770 | { 1771 | memIY(); 1772 | subSTA(); 1773 | cycle_count+=6-cycle_penalty; //no cycle penalty 1774 | } 1775 | function opSTA_IZP(){memIZP();subSTA();cycle_count+=5;} //0x92 1776 | //function opNOP() //0x93 1777 | function opSTY_ZPX(){memZPX();subSTY();cycle_count+=4;} //0x94 1778 | function opSTA_ZPX(){memZPX();subSTA();cycle_count+=4;} //0x95 1779 | function opSTX_ZPY(){memZPY();subSTX();cycle_count+=4;} //0x96 1780 | function opSMB1(){subSMB(0x02);cycle_count+=5;} //0x97 1781 | function opTYA() //0x98 1782 | { 1783 | A=Y; 1784 | if (A==0) FlagZ=1;else FlagZ=0; 1785 | if (A>=0x80) FlagN=1;else FlagN=0; 1786 | cycle_count+=2; 1787 | } 1788 | function opSTA_ADDRESSY() //0x99 1789 | { 1790 | memADDRESSY(); 1791 | subSTA(); 1792 | //debugMsg("STA_ADDRESSY: " + bank(CalcAddress)); 1793 | cycle_count+=5-cycle_penalty; //no cycle penalty 1794 | 1795 | } 1796 | function opTXS() //0x9A 1797 | { 1798 | SP=X; 1799 | //Don't set flags! 1800 | //if (SP==0) FlagZ=1;else FlagZ=0; 1801 | //if (SP>=0x80) FlagN=1;else FlagN=0; 1802 | cycle_count+=2; 1803 | } 1804 | //function opNOP() //0x9B 1805 | function opSTZ_ADDRESS(){memADDRESS();subSTZ();cycle_count+=4;} //0x9C 1806 | function opSTA_ADDRESSX() //0x9D 1807 | { 1808 | memADDRESSX(); 1809 | subSTA(); 1810 | cycle_count+=5-cycle_penalty;} //no cycle penalty 1811 | function opSTZ_ADDRESSX(){memADDRESSX();subSTZ();cycle_count+=5;} //0x9E 1812 | function opBBS1(){subBBS(0x02);cycle_count+=5;} //0x9F 1813 | function opLDY_IMMED(){subLDY(memIMMED());cycle_count+=2;} //0xA0 1814 | function opLDA_IX(){subLDA(memIX());cycle_count+=6;} //0xA1 1815 | function opLDX_IMMED(){subLDX(memIMMED());cycle_count+=2;} //0xA2 1816 | //function opNOP() //0xA3 1817 | function opLDY_ZP(){subLDY(memZP());cycle_count+=3;} //0xA4 1818 | function opLDA_ZP(){subLDA(memZP());cycle_count+=3;} //0xA5 1819 | function opLDX_ZP(){subLDX(memZP());cycle_count+=3;} //0xA6 1820 | function opSMB2_ZP(){subSMB(0x04);cycle_count+=5;} //0xA7 1821 | function opTAY() //0xA8 1822 | { 1823 | Y=A; 1824 | if (Y==0) FlagZ=1;else FlagZ=0; 1825 | if (Y>=0x80) FlagN=1;else FlagN=0; 1826 | cycle_count+=2; 1827 | } 1828 | function opLDA_IMMED(){subLDA(memIMMED());cycle_count+=2;} //0xA9 1829 | function opTAX() //0xAA 1830 | { 1831 | X=A; 1832 | if (X==0) FlagZ=1;else FlagZ=0; 1833 | if (X>=0x80) FlagN=1;else FlagN=0; 1834 | cycle_count+=2; 1835 | } 1836 | //function opNOP() //0xAB 1837 | function opLDY_ADDRESS(){subLDY(memADDRESS());cycle_count+=4;} //0xAC 1838 | function opLDA_ADDRESS(){subLDA(memADDRESS());cycle_count+=4;} //0xAD 1839 | function opLDX_ADDRESS(){subLDX(memADDRESS());cycle_count+=4;} //0xAE 1840 | function opBBS2(){subBBS(0x04);cycle_count+=5;} //0xAF 1841 | function opBCS() //0xB0 1842 | { 1843 | if (FlagC==1) 1844 | { 1845 | //const high_byte=PC&0xFF00; 1846 | const t0=memIMMED(); 1847 | const high_byte=PC&0xFF00; 1848 | if (t0>=0x80) PC-=(0x100-t0); 1849 | else PC+=t0; 1850 | if (high_byte!=(PC&0xFF00)) cycle_count++; 1851 | cycle_count++; 1852 | } 1853 | else PC++; 1854 | cycle_count+=2; 1855 | } 1856 | function opLDA_IY(){subLDA(memIY());cycle_count+=5;} //0xB1 1857 | function opLDA_IZP(){subLDA(memIZP());cycle_count+=5;} //0xB2 1858 | //function opNOP() //0xB3 1859 | function opLDY_ZPX(){subLDY(memZPX());cycle_count+=4;} //0xB4 1860 | function opLDA_ZPX(){subLDA(memZPX());cycle_count+=4;} //0xB5 1861 | function opLDX_ZPY(){subLDX(memZPY());cycle_count+=4;} //0xB6 1862 | function opSMB3(){subSMB(0x08);cycle_count+=5;} //0xB7 1863 | function opCLV(){FlagV=0;cycle_count+=2;} //0xB8 1864 | function opLDA_ADDRESSY(){subLDA(memADDRESSY());cycle_count+=4;} //0xB9 1865 | function opTSX() //0xBA 1866 | { 1867 | X=SP; 1868 | if (X==0) FlagZ=1;else FlagZ=0; 1869 | if (X>=0x80) FlagN=1;else FlagN=0; 1870 | cycle_count+=2; 1871 | } 1872 | //function opNOP() //0xBB 1873 | function opLDY_ADDRESSX(){subLDY(memADDRESSX());cycle_count+=4;} //0xBC 1874 | function opLDA_ADDRESSX(){subLDA(memADDRESSX());cycle_count+=4;} //0xBD 1875 | function opLDX_ADDRESSY(){subLDX(memADDRESSY());cycle_count+=4;} //0xBE 1876 | function opBBS3(){subBBS(0x08);cycle_count+=5;} //0xBF 1877 | function opCPY_IMMED(){subCPY(memIMMED());cycle_count+=2;} //0xC0 1878 | function opCMP_IX(){subCMP(memIX());cycle_count+=6;} //0xC1 1879 | //function opNOP_IMMED() //0xC2 1880 | //function opNOP() //0xC3 1881 | function opCPY_ZP(){subCPY(memZP());cycle_count+=3;} //0xC4 1882 | function opCMP_ZP(){subCMP(memZP());cycle_count+=3;} //0xC5 1883 | function opDEC_ZP(){subDEC(memZP());cycle_count+=5;} //0xC6 1884 | function opSMB4(){subSMB(0x10);cycle_count+=5;} //0xC7 1885 | function opINY() //0xC8 1886 | { 1887 | if (Y==0xFF){Y=0;FlagZ=1;} else{Y++;FlagZ=0;} 1888 | if (Y>=0x80) FlagN=1;else FlagN=0; 1889 | cycle_count+=2; 1890 | } 1891 | function opCMP_IMMED(){subCMP(memIMMED());cycle_count+=2;} //0xC9 1892 | function opDEX() //0xCA 1893 | { 1894 | if (X==0) X=0xFF; 1895 | else X--; 1896 | if (X==0) FlagZ=1;else FlagZ=0; 1897 | if (X>=0x80) FlagN=1;else FlagN=0; 1898 | cycle_count+=2; 1899 | } 1900 | function opWAI(){running=0;cycle_count+=3;} //0xCB 1901 | function opCPY_ADDRESS(){subCPY(memADDRESS());cycle_count+=4;} //0xCC 1902 | function opCMP_ADDRESS(){subCMP(memADDRESS());cycle_count+=4;} //0xCD 1903 | function opDEC_ADDRESS(){subDEC(memADDRESS());cycle_count+=6;} //0xCE 1904 | function opBBS4(){subBBS(0x10);cycle_count+=5;} //0xCF 1905 | function opBNE() //0xD0 1906 | { 1907 | if (FlagZ==0) 1908 | { 1909 | //const high_byte=PC&0xFF00; 1910 | const t0=memIMMED(); 1911 | const high_byte=PC&0xFF00; 1912 | if (t0>=0x80) PC-=(0x100-t0); 1913 | else PC+=t0; 1914 | if (high_byte!=(PC&0xFF00)) cycle_count++; 1915 | cycle_count++; 1916 | } 1917 | else PC++; 1918 | cycle_count+=2; 1919 | } 1920 | function opCMP_IY(){subCMP(memIY());cycle_count+=5;} //0xD1 1921 | function opCMP_IZP(){subCMP(memIZP());cycle_count+=5;} //0xD2 1922 | //function opNOP() //0xD3 1923 | //function opNOP_ZPX() //0xD4 1924 | function opCMP_ZPX(){subCMP(memZPX());cycle_count+=4;} //0xD5 1925 | function opDEC_ZPX(){subDEC(memZPX());cycle_count+=6;} //0xD6 1926 | function opSMB5(){subSMB(0x20);cycle_count+=5;} //0xD7 //0xD7 1927 | function opCLD(){FlagD=0;cycle_count+=2;} //0xD8 1928 | function opCMP_ADDRESSY(){subCMP(memADDRESSY());cycle_count+=4;} //0xD9 1929 | function opPHX() //0xDA 1930 | { 1931 | mem[0x100+SP]=X; 1932 | if (SP==0) SP=0xFF; 1933 | else SP--; 1934 | cycle_count+=3; 1935 | } 1936 | function opSTP(){running=0;cycle_count+=3;} //0xDB 1937 | //function opNOP_ADDRESS() //0xDC 1938 | function opCMP_ADDRESSX(){subCMP(memADDRESSX());cycle_count+=4;} //0xDD 1939 | function opDEC_ADDRESSX() //0xDE 1940 | { 1941 | subDEC(memADDRESSX()); 1942 | cycle_count+=7-cycle_penalty; //no cycle penalty 1943 | } 1944 | function opBBS5(){subBBS(0x20);cycle_count+=5;} //0xDF 1945 | function opCPX_IMMED(){subCPX(memIMMED());cycle_count+=2;} //0xE0 1946 | function opSBC_IX(){subSBC(memIX());cycle_count+=6;} //0xE1 1947 | //function opNOP_IMMED() //0xE2 1948 | //function opNOP() //0xE3 1949 | function opCPX_ZP(){subCPX(memZP());cycle_count+=3;} //0xE4 1950 | function opSBC_ZP(){subSBC(memZP());cycle_count+=3;} //0xE5 1951 | function opINC_ZP(){subINC(memZP());cycle_count+=5;} //0xE6 1952 | function opSMB6(){subSMB(0x40);cycle_count+=5;} //0xE7 1953 | function opINX() //0xE8 1954 | { 1955 | if (X==0xFF){X=0;FlagZ=1;} else{X++;FlagZ=0;} 1956 | if (X>=0x80) FlagN=1;else FlagN=0; 1957 | cycle_count+=2; 1958 | } 1959 | function opSBC_IMMED(){subSBC(memIMMED());cycle_count+=2;} //0xE9 1960 | //function opNOP() //0xEA 1961 | //function opNOP() //0xEB 1962 | function opCPX_ADDRESS(){subCPX(memADDRESS());cycle_count+=4;} //0xEC 1963 | function opSBC_ADDRESS(){subSBC(memADDRESS());cycle_count+=4;} //0xED 1964 | function opINC_ADDRESS(){subINC(memADDRESS());cycle_count+=5;} //0xEE 1965 | function opBBS6(){subBBS(0x40);cycle_count+=5;} //0xEF 1966 | function opBEQ() //0xF0 1967 | { 1968 | if (FlagZ==1) 1969 | { 1970 | //const high_byte=PC&0xFF00; 1971 | const t0=memIMMED(); 1972 | const high_byte=PC&0xFF00; 1973 | if (t0>=0x80) PC-=(0x100-t0); 1974 | else PC+=t0; 1975 | if (high_byte!=(PC&0xFF00)) cycle_count++; 1976 | cycle_count++; 1977 | } 1978 | else PC++; 1979 | cycle_count+=2; 1980 | } 1981 | function opSBC_IY(){subSBC(memIY());cycle_count+=5;} //0xF1 1982 | function opSBC_IZP(){subSBC(memIZP());cycle_count+=5;} //0xF2 1983 | //function opNOP() //0xF3 1984 | //function opNOP_ZPX() //0xF4 1985 | function opSBC_ZPX(){subSBC(memZPX());cycle_count+=4;} //0xF5 1986 | function opINC_ZPX(){subINC(memZPX());cycle_count+=6;} //0xF6 1987 | function opSMB7(){subSMB(0x80);cycle_count+=5;} //0xF7 1988 | function opSED(){FlagD=1;cycle_count+=2;} //0xF8 1989 | function opSBC_ADDRESSY(){subSBC(memADDRESSY());cycle_count+=4;} //0xF9 1990 | function opPLX() //0xFA 1991 | { 1992 | if (SP==0xFF) SP=0; 1993 | else SP++; 1994 | X=mem[0x100+SP]; 1995 | if (X==0) FlagZ=1;else FlagZ=0; 1996 | if (X>=0x80) FlagN=1;else FlagN=0; 1997 | cycle_count+=4; 1998 | } 1999 | //function opNOP() //0xFB 2000 | //function opNOP_ADDRESS() //0xFC 2001 | function opSBC_ADDRESSX(){subSBC(memADDRESSX());cycle_count+=4;} //0xFD 2002 | function opINC_ADDRESSX() //0xFE 2003 | { 2004 | subINC(memADDRESSX()); 2005 | cycle_count+=7-cycle_penalty; //no cycle penalty 2006 | } 2007 | function opBBS7(){subBBS(0x80);cycle_count+=5;} //0xFF 2008 | 2009 | var opLens=[2,2,2,1,2,2,2,2,1,2,1,1,3,3,3,3,2,2,2,1,2,2,2,2,1,3,1,1,3,3,3,3, 2010 | 3,2,2,1,2,2,2,2,1,2,1,1,3,3,3,3,2,2,2,1,2,2,2,2,1,3,1,1,3,3,3,3, 2011 | 1,2,2,1,2,2,2,2,1,2,1,1,3,3,3,3,2,2,2,1,2,2,2,2,1,3,1,1,3,3,3,3, 2012 | 1,2,2,1,2,2,2,2,1,2,1,1,3,3,3,3,2,2,2,1,2,2,2,2,1,3,1,1,3,3,3,3, 2013 | 2,2,2,1,2,2,2,2,1,2,1,1,3,3,3,3,2,2,2,1,2,2,2,2,1,2,1,1,3,3,3,3, 2014 | 2,2,2,1,2,2,2,2,1,2,1,1,3,3,3,3,2,2,2,1,2,2,2,2,1,3,1,1,3,3,3,3, 2015 | 2,2,2,1,2,2,2,2,1,2,1,1,3,3,3,3,2,2,2,1,2,2,2,2,1,3,1,1,3,3,3,3, 2016 | 2,2,2,1,2,2,2,2,1,2,1,1,3,3,3,3,2,2,2,1,3,2,2,2,1,3,1,1,3,3,3,3]; 2017 | 2018 | var opList=[ 2019 | opBRK, //0x00 2020 | opORA_IX, //0x01 2021 | opNOP_IMMED, //0x02 2022 | opNOP, //0x03 2023 | opTSB_ZP, //0x04 2024 | opORA_ZP, //0x05 2025 | opASL_ZP, //0x06 2026 | opRMB0, //0x07 2027 | opPHP, //0x08 2028 | opORA_IMMED, //0x09 2029 | opASL, //0x0A 2030 | opNOP, //0x0B 2031 | opTSB_ADDRESS, //0x0C 2032 | opORA_ADDRESS, //0x0D 2033 | opASL_ADDRESS, //0x0E 2034 | opBBR0, //0x0F 2035 | opBPL, //0x10 2036 | opORA_IY, //0x11 2037 | opORA_IZP, //0x12 2038 | opNOP, //0x13 2039 | opTRB_ZP, //0x14 2040 | opORA_ZPX, //0x15 2041 | opASL_ZPX, //0x16 2042 | opRMB1, //0x17 2043 | opCLC, //0x18 2044 | opORA_ADDRESSY, //0x19 2045 | opINC, //0x1A 2046 | opNOP, //0x1B 2047 | opTRB_ADDRESS, //0x1C 2048 | opORA_ADDRESSX, //0x1D 2049 | opASL_ADDRESSX, //0x1E 2050 | opBBR1, //0x1F 2051 | opJSR, //0x20 2052 | opAND_IX, //0x21 2053 | opNOP_IMMED, //0x22 2054 | opNOP, //0x23 2055 | opBIT_ZP, //0x24 2056 | opAND_ZP, //0x25 2057 | opROL_ZP, //0x26 2058 | opRMB2, //0x27 2059 | opPLP, //0x28 2060 | opAND_IMMED, //0x29 2061 | opROL, //0x2A 2062 | opNOP, //0x2B 2063 | opBIT_ADDRESS, //0x2C 2064 | opAND_ADDRESS, //0x2D 2065 | opROL_ADDRESS, //0x2E 2066 | opBBR2, //0x2F 2067 | opBMI, //0x30 2068 | opAND_IY, //0x31 2069 | opAND_IZP, //0x32 2070 | opNOP, //0x33 2071 | opBIT_ZPX, //0x34 2072 | opAND_ZPX, //0x35 2073 | opROL_ZPX, //0x36 2074 | opRMB3, //0x37 2075 | opSEC, //0x38 2076 | opAND_ADDRESSY, //0x39 2077 | opDEC, //0x3A 2078 | opNOP, //0x3B 2079 | opBIT_ADDRESSX, //0x3C 2080 | opAND_ADDRESSX, //0x3D 2081 | opROL_ADDRESSX, //0x3E 2082 | opBBR3, //0x3F 2083 | opRTI, //0x40 2084 | opEOR_IX, //0x41 2085 | opNOP_IMMED, //0x42 2086 | opNOP, //0x43 2087 | opNOP_ZP, //0x44 2088 | opEOR_ZP, //0x45 2089 | opLSR_ZP, //0x46 2090 | opRMB4, //0x47 2091 | opPHA, //0x48 2092 | opEOR_IMMED, //0x49 2093 | opLSR, //0x4A 2094 | opNOP, //0x4B 2095 | opJMP_ADDRESS, //0x4C 2096 | opEOR_ADDRESS, //0x4D 2097 | opLSR_ADDRESS, //0x4E 2098 | opBBR4, //0x4F 2099 | opBVC, //0x50 2100 | opEOR_IY, //0x51 2101 | opEOR_IZP, //0x52 2102 | opNOP, //0x53 2103 | opNOP_ZPX, //0x54 2104 | opEOR_ZPX, //0x55 2105 | opLSR_ZPX, //0x56 2106 | opRMB5, //0x57 2107 | opCLI, //0x58 2108 | opEOR_ADDRESSY, //0x59 2109 | opPHY, //0x5A 2110 | opNOP, //0x5B 2111 | opNOP_ADDRESS, //0x5C 2112 | opEOR_ADDRESSX, //0x5D 2113 | opLSR_ADDRESSX, //0x5E 2114 | opBBR5, //0x5F 2115 | opRTS, //0x60 2116 | opADC_IX, //0x61 2117 | opNOP_IMMED, //0x62 2118 | opNOP, //0x63 2119 | opSTZ_ZP, //0x64 2120 | opADC_ZP, //0x65 2121 | opROR_ZP, //0x66 2122 | opRMB6, //0x67 2123 | opPLA, //0x68 2124 | opADC_IMMED, //0x69 2125 | opROR, //0x6A 2126 | opNOP, //0x6B 2127 | opJMP_I, //0x6C 2128 | opADC_ADDRESS, //0x6D 2129 | opROR_ADDRESS, //0x6E 2130 | opBBR6, //0x6F 2131 | opBVS, //0x70 2132 | opADC_IY, //0x71 2133 | opADC_IZP, //0x72 2134 | opNOP, //0x73 2135 | opSTZ_ZPX, //0x74 2136 | opADC_ZPX, //0x75 2137 | opROR_ZPX, //0x76 2138 | opRMB7, //0x77 2139 | opSEI, //0x78 2140 | opADC_ADDRESSY, //0x79 2141 | opPLY, //0x7A 2142 | opNOP, //0x7B 2143 | opJMP_IADDRESSX, //0x7C 2144 | opADC_ADDRESSX, //0x7D 2145 | opROR_ADDRESSX, //0x7E 2146 | opBBR7, //0x7F 2147 | opBRA, //0x80 2148 | opSTA_IX, //0x81 2149 | opNOP_IMMED, //0x82 2150 | opNOP, //0x83 2151 | opSTY_ZP, //0x84 2152 | opSTA_ZP, //0x85 2153 | opSTX_ZP, //0x86 2154 | opSMB0, //0x87 2155 | opDEY, //0x88 2156 | opBIT_IMMED, //0x89 2157 | opTXA, //0x8A 2158 | opNOP, //0x8B 2159 | opSTY_ADDRESS, //0x8C 2160 | opSTA_ADDRESS, //0x8D 2161 | opSTX_ADDRESS, //0x8E 2162 | opBBS0, //0x8F 2163 | opBCC, //0x90 2164 | opSTA_IY, //0x91 2165 | opSTA_IZP, //0x92 2166 | opNOP, //0x93 2167 | opSTY_ZPX, //0x94 2168 | opSTA_ZPX, //0x95 2169 | opSTX_ZPY, //0x96 2170 | opSMB1, //0x97 2171 | opTYA, //0x98 2172 | opSTA_ADDRESSY, //0x99 2173 | opTXS, //0x9A 2174 | opNOP, //0x9B 2175 | opSTZ_ADDRESS, //0x9C 2176 | opSTA_ADDRESSX, //0x9D 2177 | opSTZ_ADDRESSX, //0x9E 2178 | opBBS1, //0x9F 2179 | opLDY_IMMED, //0xA0 2180 | opLDA_IX, //0xA1 2181 | opLDX_IMMED, //0xA2 2182 | opNOP, //0xA3 2183 | opLDY_ZP, //0xA4 2184 | opLDA_ZP, //0xA5 2185 | opLDX_ZP, //0xA6 2186 | opSMB2_ZP, //0xA7 2187 | opTAY, //0xA8 2188 | opLDA_IMMED, //0xA9 2189 | opTAX, //0xAA 2190 | opNOP, //0xAB 2191 | opLDY_ADDRESS, //0xAC 2192 | opLDA_ADDRESS, //0xAD 2193 | opLDX_ADDRESS, //0xAE 2194 | opBBS2, //0xAF 2195 | opBCS, //0xB0 2196 | opLDA_IY, //0xB1 2197 | opLDA_IZP, //0xB2 2198 | opNOP, //0xB3 2199 | opLDY_ZPX, //0xB4 2200 | opLDA_ZPX, //0xB5 2201 | opLDX_ZPY, //0xB6 2202 | opSMB3, //0xB7 2203 | opCLV, //0xB8 2204 | opLDA_ADDRESSY, //0xB9 2205 | opTSX, //0xBA 2206 | opNOP, //0xBB 2207 | opLDY_ADDRESSX, //0xBC 2208 | opLDA_ADDRESSX, //0xBD 2209 | opLDX_ADDRESSY, //0xBE 2210 | opBBS3, //0xBF 2211 | opCPY_IMMED, //0xC0 2212 | opCMP_IX, //0xC1 2213 | opNOP_IMMED, //0xC2 2214 | opNOP, //0xC3 2215 | opCPY_ZP, //0xC4 2216 | opCMP_ZP, //0xC5 2217 | opDEC_ZP, //0xC6 2218 | opSMB4, //0xC7 2219 | opINY, //0xC8 2220 | opCMP_IMMED, //0xC9 2221 | opDEX, //0xCA 2222 | opWAI, //0xCB 2223 | opCPY_ADDRESS, //0xCC 2224 | opCMP_ADDRESS, //0xCD 2225 | opDEC_ADDRESS, //0xCE 2226 | opBBS4, //0xCF 2227 | opBNE, //0xD0 2228 | opCMP_IY, //0xD1 2229 | opCMP_IZP, //0xD2 2230 | opNOP, //0xD3 2231 | opNOP_ZPX, //0xD4 2232 | opCMP_ZPX, //0xD5 2233 | opDEC_ZPX, //0xD6 2234 | opSMB5, //0xD7 2235 | opCLD, //0xD8 2236 | opCMP_ADDRESSY, //0xD9 2237 | opPHX, //0xDA 2238 | opSTP, //0xDB 2239 | opNOP_ADDRESS, //0xDC 2240 | opCMP_ADDRESSX, //0xDD 2241 | opDEC_ADDRESSX, //0xDE 2242 | opBBS5, //0xDF 2243 | opCPX_IMMED, //0xE0 2244 | opSBC_IX, //0xE1 2245 | opNOP_IMMED, //0xE2 2246 | opNOP, //0xE3 2247 | opCPX_ZP, //0xE4 2248 | opSBC_ZP, //0xE5 2249 | opINC_ZP, //0xE6 2250 | opSMB6, //0xE7 2251 | opINX, //0xE8 2252 | opSBC_IMMED, //0xE9 2253 | opNOP, //0xEA 2254 | opNOP, //0xEB 2255 | opCPX_ADDRESS, //0xEC 2256 | opSBC_ADDRESS, //0xED 2257 | opINC_ADDRESS, //0xEE 2258 | opBBS6, //0xEF 2259 | opBEQ, //0xF0 2260 | opSBC_IY, //0xF1 2261 | opSBC_IZP, //0xF2 2262 | opNOP, //0xF3 2263 | opNOP_ZPX, //0xF4 2264 | opSBC_ZPX, //0xF5 2265 | opINC_ZPX, //0xF6 2266 | opSMB7, //0xF7 2267 | opSED, //0xF8 2268 | opSBC_ADDRESSY, //0xF9 2269 | opPLX, //0xFA 2270 | opNOP, //0xFB 2271 | opNOP_ADDRESS, //0xFC 2272 | opSBC_ADDRESSX, //0xFD 2273 | opINC_ADDRESSX, //0xFE 2274 | opBBS7 //0xFF 2275 | ]; 2276 | 2277 | function disByte(byteData) 2278 | { 2279 | return "$"+byteData.toString(16).padStart(2,"0"); 2280 | } 2281 | 2282 | function disWord(byteDataLow, byteDataHigh) 2283 | { 2284 | return "$"+(byteDataLow+(byteDataHigh<<8)).toString(16).padStart(4,"0"); 2285 | } 2286 | 2287 | 2288 | function disassemble(byteList) 2289 | { 2290 | //$ = byte 2291 | //% = word 2292 | instructions=[ 2293 | "BRK", //opBRK, //0x00 2294 | "ORA ($,X)", //opORA_IX, //0x01 2295 | "NOP", //opNOP_IMMED, //0x02 2296 | "NOP", //opNOP, //0x03 2297 | "TSB $", //opTSB_ZP, //0x04 2298 | "ORA $", //opORA_ZP, //0x05 2299 | "ASL $", //opASL_ZP, //0x06 2300 | "RMB0 $", //opRMB0, //0x07 2301 | "PHP", //opPHP, //0x08 2302 | "ORA #$", //opORA_IMMED, //0x09 2303 | "ASL", //opASL, //0x0A 2304 | "NOP", //opNOP, //0x0B 2305 | "TSB %", //opTSB_ADDRESS, //0x0C 2306 | "ORA %", //opORA_ADDRESS, //0x0D 2307 | "ASL %", //opASL_ADDRESS, //0x0E 2308 | "BBR0 $,$", //opBBR0, //0x0F 2309 | "BPL $", //opBPL, //0x10 2310 | "ORA ($),Y", //opORA_IY, //0x11 2311 | "ORA ($)", //opORA_IZP, //0x12 2312 | "NOP", //opNOP, //0x13 2313 | "TRB $", //opTRB_ZP, //0x14 2314 | "ORA $,X", //opORA_ZPX, //0x15 2315 | "ASL $,X", //opASL_ZPX, //0x16 2316 | "RMB1 $", //opRMB1, //0x17 2317 | "CLC", //opCLC, //0x18 2318 | "ORA %,Y", //opORA_ADDRESSY, //0x19 2319 | "INC", //opINC, //0x1A 2320 | "NOP", //opNOP, //0x1B 2321 | "TRB %", //opTRB_ADDRESS, //0x1C 2322 | "ORA %,X", //opORA_ADDRESSX, //0x1D 2323 | "ASL %,X", //opASL_ADDRESSX, //0x1E 2324 | "BBR1 $,$", //opBBR1, //0x1F 2325 | "JSR %", //opJSR, //0x20 2326 | "AND ($,X)", //opAND_IX, //0x21 2327 | "NOP", //opNOP_IMMED, //0x22 2328 | "NOP", //opNOP, //0x23 2329 | "BIT $", //opBIT_ZP, //0x24 2330 | "AND $", //opAND_ZP, //0x25 2331 | "ROL $", //opROL_ZP, //0x26 2332 | "RMB $", //opRMB2, //0x27 2333 | "PLP", //opPLP, //0x28 2334 | "AND #$", //opAND_IMMED, //0x29 2335 | "ROL", //opROL, //0x2A 2336 | "NOP", //opNOP, //0x2B 2337 | "BIT %", //opBIT_ADDRESS, //0x2C 2338 | "AND %", //opAND_ADDRESS, //0x2D 2339 | "ROL %", //opROL_ADDRESS, //0x2E 2340 | "BBR2 $,$", //opBBR2, //0x2F 2341 | "BMI $", //opBMI, //0x30 2342 | "AND ($),Y", //opAND_IY, //0x31 2343 | "AND ($)", //opAND_IZP, //0x32 2344 | "NOP", //opNOP, //0x33 2345 | "BIT $,X", //opBIT_ZPX, //0x34 2346 | "AND $,X", //opAND_ZPX, //0x35 2347 | "ROL $,X", //opROL_ZPX, //0x36 2348 | "RMB3 $", //opRMB3, //0x37 2349 | "SEC", //opSEC, //0x38 2350 | "AND %,Y", //opAND_ADDRESSY, //0x39 2351 | "DEC", //opDEC, //0x3A 2352 | "NOP", //opNOP, //0x3B 2353 | "BIT %,X", //opBIT_ADDRESSX, //0x3C 2354 | "AND %,X", //opAND_ADDRESSX, //0x3D 2355 | "ROL %,X", //opROL_ADDRESSX, //0x3E 2356 | "BBR3 $,$", //opBBR3, //0x3F 2357 | "RTI", //opRTI, //0x40 2358 | "EOR ($,X)", //opEOR_IX, //0x41 2359 | "NOP", //opNOP_IMMED, //0x42 2360 | "NOP", //opNOP, //0x43 2361 | "NOP", //opNOP_ZP, //0x44 2362 | "EOR $", //opEOR_ZP, //0x45 2363 | "LSR $", //opLSR_ZP, //0x46 2364 | "RMB4 $", //opRMB4, //0x47 2365 | "PHA", //opPHA, //0x48 2366 | "EOR #$", //opEOR_IMMED, //0x49 2367 | "LSR", //opLSR, //0x4A 2368 | "NOP", //opNOP, //0x4B 2369 | "JMP %", //opJMP_ADDRESS, //0x4C 2370 | "EOR %", //opEOR_ADDRESS, //0x4D 2371 | "LSR %", //opLSR_ADDRESS, //0x4E 2372 | "BBR4 $,$", //opBBR4, //0x4F 2373 | "BVC $", //opBVC, //0x50 2374 | "EOR ($),Y", //opEOR_IY, //0x51 2375 | "EOR ($)", //opEOR_IZP, //0x52 2376 | "NOP", //opNOP, //0x53 2377 | "NOP", //opNOP_ZPX, //0x54 2378 | "EOR $,X", //opEOR_ZPX, //0x55 2379 | "LSR $,X", //opLSR_ZPX, //0x56 2380 | "RMB5 $", //opRMB5, //0x57 2381 | "CLI", //opCLI, //0x58 2382 | "EOR %,Y", //opEOR_ADDRESSY, //0x59 2383 | "PHY", //opPHY, //0x5A 2384 | "NOP", //opNOP, //0x5B 2385 | "NOP", //opNOP_ADDRESS, //0x5C 2386 | "EOR %,X", //opEOR_ADDRESSX, //0x5D 2387 | "LSR %,X", //opLSR_ADDRESSX, //0x5E 2388 | "BBR5 $,$", //opBBR5, //0x5F 2389 | "RTS", //opRTS, //0x60 2390 | "ADC ($,X)", //opADC_IX, //0x61 2391 | "NOP", //opNOP_IMMED, //0x62 2392 | "NOP", //opNOP, //0x63 2393 | "STZ $", //opSTZ_ZP, //0x64 2394 | "ADC $", //opADC_ZP, //0x65 2395 | "ROR $", //opROR_ZP, //0x66 2396 | "RMB6 $", //opRMB6, //0x67 2397 | "PLA", //opPLA, //0x68 2398 | "ADC #$", //opADC_IMMED, //0x69 2399 | "ROR", //opROR, //0x6A 2400 | "NOP", //opNOP, //0x6B 2401 | "JMP (%)", //opJMP_I, //0x6C 2402 | "ADC %", //opADC_ADDRESS, //0x6D 2403 | "ROR %", //opROR_ADDRESS, //0x6E 2404 | "BBR6 $,$", //opBBR6, //0x6F 2405 | "BVS $", //opBVS, //0x70 2406 | "ADC ($),Y", //opADC_IY, //0x71 2407 | "ADC ($)", //opADC_IZP, //0x72 2408 | "NOP", //opNOP, //0x73 2409 | "STZ $,X", //opSTZ_ZPX, //0x74 2410 | "ADC $,X", //opADC_ZPX, //0x75 2411 | "ROR $,X", //opROR_ZPX, //0x76 2412 | "RMB7 $", //opRMB7, //0x77 2413 | "SEI", //opSEI, //0x78 2414 | "ADC %,Y", //opADC_ADDRESSY, //0x79 2415 | "PLY", //opPLY, //0x7A 2416 | "NOP", //opNOP, //0x7B 2417 | "JMP (%,X)", //opJMP_IADDRESSX, //0x7C 2418 | "ADC %,X", //opADC_ADDRESSX, //0x7D 2419 | "ROR %,X", //opROR_ADDRESSX, //0x7E 2420 | "BBR7 $,$", //opBBR7, //0x7F 2421 | "BRA $", //opBRA, //0x80 2422 | "STA ($,X)", //opSTA_IX, //0x81 2423 | "NOP", //opNOP_IMMED, //0x82 2424 | "NOP", //opNOP, //0x83 2425 | "STY $", //opSTY_ZP, //0x84 2426 | "STA $", //opSTA_ZP, //0x85 2427 | "STX $", //opSTX_ZP, //0x86 2428 | "SMB0 $", //opSMB0, //0x87 2429 | "DEY", //opDEY, //0x88 2430 | "BIT #$", //opBIT_IMMED, //0x89 2431 | "TXA", //opTXA, //0x8A 2432 | "NOP", //opNOP, //0x8B 2433 | "STY %", //opSTY_ADDRESS, //0x8C 2434 | "STA %", //opSTA_ADDRESS, //0x8D 2435 | "STX %", //opSTX_ADDRESS, //0x8E 2436 | "BBS0 $,$", //opBBS0, //0x8F 2437 | "BCC $", //opBCC, //0x90 2438 | "STA ($),Y", //opSTA_IY, //0x91 2439 | "STA ($)", //opSTA_IZP, //0x92 2440 | "NOP", //opNOP, //0x93 2441 | "STY $,X", //opSTY_ZPX, //0x94 2442 | "STA $,X", //opSTA_ZPX, //0x95 2443 | "STX $,X", //opSTX_ZPY, //0x96 2444 | "SMB1 $", //opSMB1, //0x97 2445 | "TYA", //opTYA, //0x98 2446 | "STA %,Y", //opSTA_ADDRESSY, //0x99 2447 | "TXS", //opTXS, //0x9A 2448 | "NOP", //opNOP, //0x9B 2449 | "STZ %", //opSTZ_ADDRESS, //0x9C 2450 | "STA %,X", //opSTA_ADDRESSX, //0x9D 2451 | "STZ %,X", //opSTZ_ADDRESSX, //0x9E 2452 | "BBS1 $,$", //opBBS1, //0x9F 2453 | "LDY #$", //opLDY_IMMED, //0xA0 2454 | "LDA ($,X)", //opLDA_IX, //0xA1 2455 | "LDX #$", //opLDX_IMMED, //0xA2 2456 | "NOP", //opNOP, //0xA3 2457 | "LDY $", //opLDY_ZP, //0xA4 2458 | "LDA $", //opLDA_ZP, //0xA5 2459 | "LDX $", //opLDX_ZP, //0xA6 2460 | "SMB2 $", //opSMB2_ZP, //0xA7 2461 | "TAY", //opTAY, //0xA8 2462 | "LDA #$", //opLDA_IMMED, //0xA9 2463 | "TAX", //opTAX, //0xAA 2464 | "NOP", //opNOP, //0xAB 2465 | "LDY %", //opLDY_ADDRESS, //0xAC 2466 | "LDA %", //opLDA_ADDRESS, //0xAD 2467 | "LDX %", //opLDX_ADDRESS, //0xAE 2468 | "BBS2 $,$", //opBBS2, //0xAF 2469 | "BCS $", //opBCS, //0xB0 2470 | "LDA ($),Y", //opLDA_IY, //0xB1 2471 | "LDA ($)", //opLDA_IZP, //0xB2 2472 | "NOP", //opNOP, //0xB3 2473 | "LDY $,X", //opLDY_ZPX, //0xB4 2474 | "LDA $,X", //opLDA_ZPX, //0xB5 2475 | "LDX $,Y", //opLDX_ZPY, //0xB6 2476 | "SMB3 $", //opSMB3, //0xB7 2477 | "CLV", //opCLV, //0xB8 2478 | "LDA %,Y", //opLDA_ADDRESSY, //0xB9 2479 | "TSX", //opTSX, //0xBA 2480 | "NOP", //opNOP, //0xBB 2481 | "LDY %,X", //opLDY_ADDRESSX, //0xBC 2482 | "LDA %,X", //opLDA_ADDRESSX, //0xBD 2483 | "LDX %,Y", //opLDX_ADDRESSY, //0xBE 2484 | "BBS3 $,$", //opBBS3, //0xBF 2485 | "CPY #$", //opCPY_IMMED, //0xC0 2486 | "CMP ($,X)", //opCMP_IX, //0xC1 2487 | "NOP", //opNOP_IMMED, //0xC2 2488 | "NOP", //opNOP, //0xC3 2489 | "CPY $", //opCPY_ZP, //0xC4 2490 | "CMP $", //opCMP_ZP, //0xC5 2491 | "DEC $", //opDEC_ZP, //0xC6 2492 | "SMB4 $", //opSMB4, //0xC7 2493 | "INY", //opINY, //0xC8 2494 | "CMP #$", //opCMP_IMMED, //0xC9 2495 | "DEX", //opDEX, //0xCA 2496 | "WAI", //opWAI, //0xCB 2497 | "CPY %", //opCPY_ADDRESS, //0xCC 2498 | "CMP %", //opCMP_ADDRESS, //0xCD 2499 | "DEC %", //opDEC_ADDRESS, //0xCE 2500 | "BBS4 $,$", //opBBS4, //0xCF 2501 | "BNE $", //opBNE, //0xD0 2502 | "CMP ($),Y", //opCMP_IY, //0xD1 2503 | "CMP ($)", //opCMP_IZP, //0xD2 2504 | "NOP", //opNOP, //0xD3 2505 | "NOP", //opNOP_ZPX, //0xD4 2506 | "CMP $,X", //opCMP_ZPX, //0xD5 2507 | "DEC $,X", //opDEC_ZPX, //0xD6 2508 | "SMB5 $", //opSMB5, //0xD7 2509 | "CLD", //opCLD, //0xD8 2510 | "CMP %,Y", //opCMP_ADDRESSY, //0xD9 2511 | "PHX", //opPHX, //0xDA 2512 | "STP", //opSTP, //0xDB 2513 | "NOP", //opNOP_ADDRESS, //0xDC 2514 | "CMP %,X", //opCMP_ADDRESSX, //0xDD 2515 | "DEC %,X", //opDEC_ADDRESSX, //0xDE 2516 | "BBS5 $,$", //opBBS5, //0xDF 2517 | "CPX #$", //opCPX_IMMED, //0xE0 2518 | "SBC ($,X)", //opSBC_IX, //0xE1 2519 | "NOP", //opNOP_IMMED, //0xE2 2520 | "NOP", //opNOP, //0xE3 2521 | "CPX $", //opCPX_ZP, //0xE4 2522 | "SBC $", //opSBC_ZP, //0xE5 2523 | "INC $", //opINC_ZP, //0xE6 2524 | "SMB6 $", //opSMB6, //0xE7 2525 | "INX", //opINX, //0xE8 2526 | "SBC #$", //opSBC_IMMED, //0xE9 2527 | "NOP", //opNOP, //0xEA 2528 | "NOP", //opNOP, //0xEB 2529 | "CPX %", //opCPX_ADDRESS, //0xEC 2530 | "SBC %", //opSBC_ADDRESS, //0xED 2531 | "INC %", //opINC_ADDRESS, //0xEE 2532 | "BBS6 $,$", //opBBS6, //0xEF 2533 | "BEQ $", //opBEQ, //0xF0 2534 | "SBC ($),Y", //opSBC_IY, //0xF1 2535 | "SBC ($)", //opSBC_IZP, //0xF2 2536 | "NOP", //opNOP, //0xF3 2537 | "NOP", //opNOP_ZPX, //0xF4 2538 | "SBC $,X", //opSBC_ZPX, //0xF5 2539 | "INC $,X", //opINC_ZPX, //0xF6 2540 | "SMB7 $", //opSMB7, //0xF7 2541 | "SED", //opSED, //0xF8 2542 | "SBC %,Y", //opSBC_ADDRESSY, //0xF9 2543 | "PLX", //opPLX, //0xFA 2544 | "NOP", //opNOP, //0xFB 2545 | "NOP", //opNOP_ADDRESS, //0xFC 2546 | "SBC %,X", //opSBC_ADDRESSX, //0xFD 2547 | "INC %,X", //opINC_ADDRESSX, //0xFE 2548 | "BBS7 $,$", //opBBS7 //0xFF 2549 | ]; 2550 | let temp_str=instructions[byteList[0]]; 2551 | let byteIndex=1; 2552 | let ret_str=""; 2553 | for (let i=0;i