/* ----------------------------------------------- * 6502 assembler and emulator in Javascript * Based on Stian Soreng sources(c)2006-2010 * www.6502asm.com * Released under the GNU General Public License * see http://gnu.org/licenses/gpl.html * TTL6502 TEST PASS on 26.12.2014. * Func Test for Easy6502 PASS on 29.12.2014. * Adapted and corrected by Lavr Semionovich * ----------------------------------------------*/ message( "Start 6502 jscript! "); var memory = new Array( 0x10000 ); //--- 0000-FFFFH; index от 0 var codeCompiledOK = false; var regA = 0; var regX = 0; var regY = 0; var regP = 0x30; //-- 0x20 var regSP = 0xff; var regPC = 0x600; var defaultCodePC = 0x600; var tempStr = ""; var tempInt = 0; var oldText = document.getElementById( "code" ).value.length; var newText = 0; var labelIndex = new Array(); var labelPtr = 0; var codeRunning = false; var xmlhttp; var myInterval; var display = new Array( 0x400 ); var debug = false; var monitoring = false; var memDisassm = false; var autoDebugg = false; var serialHex = false; var titleHex = false; var serialOut = ""; //--- string to system area; var titleOut = ""; //--- string to title; var autoDeb = 0x0000; //--- Breakpoint addr; var dtimeMS = 1; //--- Delay in mS var palette = new Array( "#000000", "#ffffff", "#880000", "#aaffee", "#cc44cc", "#00cc55", "#0000aa", "#eeee77", "#dd8855", "#664400", "#ff7777", "#333333", "#777777", "#aaff66", "#0088ff", "#bbbbbb" ); message( "Colour Palette is loaded! "); var inst = new Array( i00, //00 BRK i01, //01 ORA (z,X) ierr, //--- 02 ierr, //--- 03 ierr, //--- 04 i05, //05 ORA z i06, //06 ASL z ierr, //--- 07 i08, //08 PHP i09, //09 ORA #n i0a, //0a ASL ierr, //--- 0b ierr, //--- 0c i0d, //0d ORA a i0e, //0e ASL a ierr, //--- 0f i10, //10 BPL a i11, //11 ORA (z),Y ierr, //--- 12 ierr, //--- 13 ierr, //--- 14 i15, //15 ORA z,X i16, //16 ASL z,X ierr, //--- 17 i18, //18 CLC i19, //19 ORA a,Y ierr, //--- 1a ierr, //--- 1b ierr, //--- 1c i1d, //1d ORA a,X i1e, //1e ASL a,X ierr, //--- 1f i20, //20 JSR a i21, //21 AND (z,X) ierr, //--- 22 ierr, //--- 23 i24, //24 BIT z i25, //25 AND z i26, //26 ROL z ierr, //--- 27 i28, //28 PLP i29, //29 AND #n i2a, //2a ROL ierr, //--- 2b i2c, //2c BIT a i2d, //2d AND a i2e, //2e ROL a ierr, //--- 2f i30, //30 BMI e i31, //31 AND (z),Y ierr, //--- 32 ierr, //--- 33 ierr, //--- 34 i35, //35 AND z,X i36, //36 ROL z,X ierr, //--- 37 i38, //38 SEC i39, //39 AND a,Y ierr, //--- 3a ierr, //--- 3b ierr, //--- 3c i3d, //3d AND a,X i3e, //3e ROL a,X ierr, //--- 3f i40, //40 RTI i41, //41 EOR (z,X) ierr, //--- 42 ierr, //--- 43 ierr, //--- 44 i45, //45 EOR z i46, //46 LSR z ierr, //--- 47 i48, //48 PHA i49, //49 EOR #n i4a, //4a LSR ierr, //--- 4b i4c, //4c JMP a i4d, //4d EOR a i4e, //4e LSR a ierr, //--- 4f i50, //50 BVC e i51, //51 EOR (z),Y ierr, //--- 52 ierr, //--- 53 ierr, //--- 54 i55, //55 EOR z,X i56, //56 LSR z,X ierr, //--- 57 i58, //58 CLI i59, //59 EOR a,Y ierr, //--- 5a ierr, //--- 5b ierr, //--- 5c i5d, //5d EOR a,X i5e, //5e LSR a,X ierr, //--- 5f i60, //60 RTS i61, //61 ADC (z,X) ierr, //--- 62 ierr, //--- 63 ierr, //--- 64 i65, //65 ADC z i66, //66 ROR z ierr, //--- 67 i68, //68 PLA i69, //69 ADC #n i6a, //6a ROR ierr, //--- 6b i6c, //6c JMP (a) i6d, //6d ADC a i6e, //6e ROR a ierr, //--- 6f i70, //70 BVS e i71, //71 ADC (z),Y ierr, //--- 72 ierr, //--- 73 ierr, //--- 74 i75, //75 ADC z,X i76, //76 ROR z,X ierr, //--- 77 i78, //78 SEI i79, //79 ADC a,Y ierr, //--- 7a ierr, //--- 7b ierr, //--- 7c i7d, //7d ADC a,X i7e, //7e ROR a,X ierr, //--- 7f ierr, //--- 80 i81, //81 STA (z,X) ierr, //--- 82 ierr, //--- 83 i84, //84 STY z i85, //85 STA z i86, //86 STX z ierr, //--- 87 i88, //88 DEY ierr, //--- 89 i8a, //8a TXA ierr, //--- 8b i8c, //8c STY a i8d, //8d STA a i8e, //8e STX a ierr, //--- 8f i90, //90 BCC e i91, //91 STA (z),Y ierr, //--- 92 ierr, //--- 93 i94, //94 STY z,X i95, //95 STA z,X i96, //96 STX z,Y ierr, //--- 97 i98, //98 TYA i99, //99 STA a,Y i9a, //9a TXS ierr, //--- 9b ierr, //--- 9c i9d, //9d STA a,X ierr, //--- 9e ierr, //--- 9f ia0, //a0 LDY #n ia1, //a1 LDA (z,X) ia2, //a2 LDX #n ierr, //--- a3 ia4, //a4 LDY z ia5, //a5 LDA z ia6, //a6 LDX z ierr, //--- a7 ia8, //a8 TAY ia9, //a9 LDA #n iaa, //aa TAX ierr, //--- ab iac, //ac LDY a iad, //ad LDA a iae, //ae LDX a ierr, //--- af ib0, //b0 BCS e ib1, //b1 LDA (z),Y ierr, //--- b2 ierr, //--- b3 ib4, //b4 LDY z,X ib5, //b5 LDA z,X ib6, //b6 LDX z,Y ierr, //--- b7 ib8, //b8 CLV ib9, //b9 LDA a,Y iba, //ba TSX ierr, //--- bb ibc, //bc LDY a,X ibd, //bd LDA a,X ibe, //be LDX a,Y ierr, //--- bf ic0, //c0 CPY #n ic1, //c1 CMP (z,X) ierr, //--- c2 ierr, //--- c3 ic4, //c4 CPY z ic5, //c5 CMP z ic6, //c6 DEC z ierr, //--- c7 ic8, //c8 INY ic9, //c9 CMP #n ica, //ca DEX ierr, //--- cb icc, //cc CPY a icd, //cd CMP a ice, //--- DEC a ierr, //--- cf id0, //d0 BNE e id1, //d1 CMP (z),Y ierr, //--- d2 ierr, //--- d3 ierr, //--- d4 id5, //d5 CMP z,X id6, //d6 DEC z,X ierr, //--- d7 id8, //d8 CLD id9, //d9 CMP a,Y ierr, //--- da ierr, //--- db ierr, //--- dc idd, //dd CMP a,X ide, //de DEC a,X ierr, //--- df ie0, //e0 CPX #n ie1, //e1 SBC (z,X) ierr, //--- e2 ierr, //--- e3 ie4, //e4 CPX z ie5, //e5 SBC z ie6, //e6 INC z ierr, //--- e7 ie8, //e8 INX ie9, //e9 SBC #n iea, //ea NOP ierr, //--- eb iec, //ec CPX a ied, //ed SBC a iee, //ee INC a ierr, //--- ef if0, //f0 BEQ e if1, //f1 SBC (z),Y ierr, //--- f2 ierr, //--- f3 ierr, //--- f4 if5, //f5 SBC z,X if6, //f6 INC z,X ierr, //--- f7 if8, //f8 SED if9, //f9 SBC a,Y ierr, //--- fa ierr, //--- fb ierr, //--- fc ifd, //fd SBC a,X ife, //fe INC a,X iff //--- analog HLT (dcb $ff) ); message( "Instructions Array is created! "); /*= Mnemonics used by Disassembler subroutines =*/ var Mnemonics = [ /* Name, Imm, ZP, ZPX, ZPY, ABS, ABSX, ABSY, IND, INDX, INDY, SNGL, BRA */ ["ADC", 0x69, 0x65, 0x75, null, 0x6d, 0x7d, 0x79, null, 0x61, 0x71, null, null], ["AND", 0x29, 0x25, 0x35, null, 0x2d, 0x3d, 0x39, null, 0x21, 0x31, null, null], ["ASL", null, 0x06, 0x16, null, 0x0e, 0x1e, null, null, null, null, 0x0a, null], ["BIT", null, 0x24, null, null, 0x2c, null, null, null, null, null, null, null], ["BPL", null, null, null, null, null, null, null, null, null, null, null, 0x10], ["BMI", null, null, null, null, null, null, null, null, null, null, null, 0x30], ["BVC", null, null, null, null, null, null, null, null, null, null, null, 0x50], ["BVS", null, null, null, null, null, null, null, null, null, null, null, 0x70], ["BCC", null, null, null, null, null, null, null, null, null, null, null, 0x90], ["BCS", null, null, null, null, null, null, null, null, null, null, null, 0xb0], ["BNE", null, null, null, null, null, null, null, null, null, null, null, 0xd0], ["BEQ", null, null, null, null, null, null, null, null, null, null, null, 0xf0], ["BRK", null, null, null, null, null, null, null, null, null, null, 0x00, null], ["CMP", 0xc9, 0xc5, 0xd5, null, 0xcd, 0xdd, 0xd9, null, 0xc1, 0xd1, null, null], ["CPX", 0xe0, 0xe4, null, null, 0xec, null, null, null, null, null, null, null], ["CPY", 0xc0, 0xc4, null, null, 0xcc, null, null, null, null, null, null, null], ["DEC", null, 0xc6, 0xd6, null, 0xce, 0xde, null, null, null, null, null, null], ["EOR", 0x49, 0x45, 0x55, null, 0x4d, 0x5d, 0x59, null, 0x41, 0x51, null, null], ["CLC", null, null, null, null, null, null, null, null, null, null, 0x18, null], ["SEC", null, null, null, null, null, null, null, null, null, null, 0x38, null], ["CLI", null, null, null, null, null, null, null, null, null, null, 0x58, null], ["SEI", null, null, null, null, null, null, null, null, null, null, 0x78, null], ["CLV", null, null, null, null, null, null, null, null, null, null, 0xb8, null], ["CLD", null, null, null, null, null, null, null, null, null, null, 0xd8, null], ["SED", null, null, null, null, null, null, null, null, null, null, 0xf8, null], ["INC", null, 0xe6, 0xf6, null, 0xee, 0xfe, null, null, null, null, null, null], ["JMP", null, null, null, null, 0x4c, null, null, 0x6c, null, null, null, null], ["JSR", null, null, null, null, 0x20, null, null, null, null, null, null, null], ["LDA", 0xa9, 0xa5, 0xb5, null, 0xad, 0xbd, 0xb9, null, 0xa1, 0xb1, null, null], ["LDX", 0xa2, 0xa6, null, 0xb6, 0xae, null, 0xbe, null, null, null, null, null], ["LDY", 0xa0, 0xa4, 0xb4, null, 0xac, 0xbc, null, null, null, null, null, null], ["LSR", null, 0x46, 0x56, null, 0x4e, 0x5e, null, null, null, null, 0x4a, null], ["NOP", null, null, null, null, null, null, null, null, null, null, 0xea, null], ["ORA", 0x09, 0x05, 0x15, null, 0x0d, 0x1d, 0x19, null, 0x01, 0x11, null, null], ["TAX", null, null, null, null, null, null, null, null, null, null, 0xaa, null], ["TXA", null, null, null, null, null, null, null, null, null, null, 0x8a, null], ["DEX", null, null, null, null, null, null, null, null, null, null, 0xca, null], ["INX", null, null, null, null, null, null, null, null, null, null, 0xe8, null], ["TAY", null, null, null, null, null, null, null, null, null, null, 0xa8, null], ["TYA", null, null, null, null, null, null, null, null, null, null, 0x98, null], ["DEY", null, null, null, null, null, null, null, null, null, null, 0x88, null], ["INY", null, null, null, null, null, null, null, null, null, null, 0xc8, null], ["ROR", null, 0x66, 0x76, null, 0x6e, 0x7e, null, null, null, null, 0x6a, null], ["ROL", null, 0x26, 0x36, null, 0x2e, 0x3e, null, null, null, null, 0x2a, null], ["RTI", null, null, null, null, null, null, null, null, null, null, 0x40, null], ["RTS", null, null, null, null, null, null, null, null, null, null, 0x60, null], ["SBC", 0xe9, 0xe5, 0xf5, null, 0xed, 0xfd, 0xf9, null, 0xe1, 0xf1, null, null], ["STA", null, 0x85, 0x95, null, 0x8d, 0x9d, 0x99, null, 0x81, 0x91, null, null], ["TXS", null, null, null, null, null, null, null, null, null, null, 0x9a, null], ["TSX", null, null, null, null, null, null, null, null, null, null, 0xba, null], ["PHA", null, null, null, null, null, null, null, null, null, null, 0x48, null], ["PLA", null, null, null, null, null, null, null, null, null, null, 0x68, null], ["PHP", null, null, null, null, null, null, null, null, null, null, 0x08, null], ["PLP", null, null, null, null, null, null, null, null, null, null, 0x28, null], ["STX", null, 0x86, null, 0x96, 0x8e, null, null, null, null, null, null, null], ["STY", null, 0x84, 0x94, null, 0x8c, null, null, null, null, null, null, null], ["---", null, null, null, null, null, null, null, null, null, null, null, null] ]; var Opcodes = new Array( /* Name, Imm, ZP, ZPX, ZPY, ABS, ABSX, ABSY, INDX, INDY, SNGL, BRA */ Array("ADC", 0x69, 0x65, 0x75, 0x00, 0x6d, 0x7d, 0x79, 0x61, 0x71, 0x00, 0x00 ), Array("AND", 0x29, 0x25, 0x35, 0x00, 0x2d, 0x3d, 0x39, 0x21, 0x31, 0x00, 0x00 ), Array("ASL", 0x00, 0x06, 0x16, 0x00, 0x0e, 0x1e, 0x00, 0x00, 0x00, 0x0a, 0x00 ), Array("BIT", 0x00, 0x24, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("BPL", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ), Array("BMI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30 ), Array("BVC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50 ), Array("BVS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70 ), Array("BCC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90 ), Array("BCS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0 ), Array("BNE", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0 ), Array("BEQ", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0 ), Array("BRK", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("CMP", 0xc9, 0xc5, 0xd5, 0x00, 0xcd, 0xdd, 0xd9, 0xc1, 0xd1, 0x00, 0x00 ), Array("CPX", 0xe0, 0xe4, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("CPY", 0xc0, 0xc4, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("DEC", 0x00, 0xc6, 0xd6, 0x00, 0xce, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("EOR", 0x49, 0x45, 0x55, 0x00, 0x4d, 0x5d, 0x59, 0x41, 0x51, 0x00, 0x00 ), Array("CLC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00 ), Array("HLT", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00 ), Array("SEC", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00 ), Array("CLI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00 ), Array("SEI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00 ), Array("CLV", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00 ), Array("CLD", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00 ), Array("SED", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00 ), Array("INC", 0x00, 0xe6, 0xf6, 0x00, 0xee, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("JMP", 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("JSR", 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("LDA", 0xa9, 0xa5, 0xb5, 0x00, 0xad, 0xbd, 0xb9, 0xa1, 0xb1, 0x00, 0x00 ), Array("LDX", 0xa2, 0xa6, 0x00, 0xb6, 0xae, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00 ), Array("LDY", 0xa0, 0xa4, 0xb4, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("LSR", 0x00, 0x46, 0x56, 0x00, 0x4e, 0x5e, 0x00, 0x00, 0x00, 0x4a, 0x00 ), Array("NOP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00 ), Array("ORA", 0x09, 0x05, 0x15, 0x00, 0x0d, 0x1d, 0x19, 0x01, 0x11, 0x00, 0x00 ), Array("TAX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00 ), Array("TXA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00 ), Array("DEX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x00 ), Array("INX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00 ), Array("TAY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00 ), Array("TYA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00 ), Array("DEY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00 ), Array("INY", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00 ), Array("ROR", 0x00, 0x66, 0x76, 0x00, 0x6e, 0x7e, 0x00, 0x00, 0x00, 0x6a, 0x00 ), Array("ROL", 0x00, 0x26, 0x36, 0x00, 0x2e, 0x3e, 0x00, 0x00, 0x00, 0x2a, 0x00 ), Array("RTI", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00 ), Array("RTS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00 ), Array("SBC", 0xe9, 0xe5, 0xf5, 0x00, 0xed, 0xfd, 0xf9, 0xe1, 0xf1, 0x00, 0x00 ), Array("STA", 0x00, 0x85, 0x95, 0x00, 0x8d, 0x9d, 0x99, 0x81, 0x91, 0x00, 0x00 ), Array("TXS", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00 ), Array("TSX", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00 ), Array("PHA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00 ), Array("PLA", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00 ), Array("PHP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 ), Array("PLP", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00 ), Array("STX", 0x00, 0x86, 0x00, 0x96, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("STY", 0x00, 0x84, 0x94, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), Array("---", 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) ); message( "Array of Opcodes is loaded! "); // Initialize everything. document.getElementById( "compileButton" ).disabled = false; // 'Compile' enabled; document.getElementById( "runButton" ).disabled = true; // 'Run' disabled not 'Stop'; document.getElementById( "hexdumpButton" ).disabled = true; // 'HexDump' disabled; document.getElementById( "fileSelect" ).disabled = false; // 'Examples' enabled; document.getElementById( "submitCode" ).disabled = true; // 'Clear' disabled; document.getElementById( "setIRQCode" ).disabled = true; // 'IRQ' disabled; document.getElementById( "setNMICode" ).disabled = true; // 'NMI' disabled; document.getElementById( "watch" ).disabled = true; // 'Debugger' disabled; document.getElementById( "watch" ).checked = false; // '[] Deb' NOT checked; document.getElementById( "autod" ).disabled = true; // 'A-Debug' disabled; document.getElementById( "autod" ).checked = false; // '[] A-Deb' NOT checked; document.getElementById( "stepButton" ).disabled = true; // 'Step' disabled; document.getElementById( "gotoButton" ).disabled = true; // 'Jump to :' disabled; document.getElementById( "disButton" ).disabled = true; // 'Disassm' disabled; document.getElementById( "memRef" ).disabled = true; // 'Refresh' disabled; document.addEventListener( "keypress", keyPress, true ); // Divide the "display" message( "Preparing the 'display' "); html = ''; for( y=0; y<32; y++ ) { html += ""; for( x=0; x<32; x++ ) { html += ''; } html += ""; } html += "
"; document.getElementById( "screen" ).innerHTML = html; // Reset everything reset(); /* * keyPress() - Store keycode in ZP $ff * Executed when keyboard key is pressed. */ function keyPress( e ) { if( typeof window.event != "undefined" ) e = window.event; if( e.type == "keypress" ) { var value = e.which; // memStoreByte( 0xff, value ); //- conflict with serial out; memory[0xff] = value & 0xff; } } /* * debugExec() - Execute one instruction and print values. * Executed when button "Step" is pressed. */ function debugExec() { if( codeRunning ) execute(); updateDebugInfo(); } function updateDebugInfo() { var html = "A=$" + num2hex(regA).toUpperCase() + " X=$" + num2hex(regX).toUpperCase() + " Y=$" + num2hex(regY).toUpperCase() + " S=$" + num2hex(regSP).toUpperCase() + "
"; html += "   PC=$" + addr2hex(regPC).toUpperCase() + ";  "; html += "NV-B.DIZC
"; html += "    P=$" + num2hex(regP).toUpperCase() + "  :  "; for(var i = 7; i >=0; i--) { html += regP >> i & 1; if(i == 4) html += "."; } document.getElementById("md").innerHTML = html; updateMonitor(); } /* * gotoAddr() - Set PC to address (or address of label) * Executed when button "Jump to:" is pressed * */ document.getElementById("md") function gotoAddr() { var inp = prompt( "Enter HEX address or Label", "" ); // inp - get from prompt( ... ) request; var addr = 0; if( findLabel( inp ) ) //-- compare with Labeles... { addr = getLabelPC( inp ); //-- если нашли, то адрес метки. } else { if( inp.match( new RegExp( /^0x[0-9a-f]{1,4}$/i ) ) ) { // match (сопоставление) — смысл действия в том чтобы выяснить, // соответствует ли определенный текст заданному регулярному выражению. // ^ - Обозначает начало входных данных. // $ - Обозначает конец входных данных. // [0-9a-f] - Находит любой из перечисленных символов. // {1,4} - Находят от 1 до 4 повторений элемента. // i — не различать строчные и заглавные буквы; // g - повторить по всей строке. inp = inp.replace( /^0x/, "" ); //-- 0xFFDE оставит FFDE; addr = parseInt( inp, 16 ); //-- и преобразует как HEX. } else if( inp.match( new RegExp( /^\$[0-9a-f]{1,4}$/i))) { inp = inp.replace( /^\$/, "" ); //-- $DE оставит DE; addr = parseInt( inp, 16 ); //-- и преобразует как HEX. } } // end else findLabel( if( addr == 0 ) { alert( "Unable to find/parse given address/label" ); } else { regPC = addr; message( "Executing from PC = $" + addr2hex(regPC).toUpperCase() ); } updateDebugInfo(); } /* * editMemBytes() - edits memory bytes in blocks by 8. * Executed when memory Monitor area is klicked. */ function editMemBytes() { // alert('Sorry... This function is not implemented yet.'); if( debug && !autoDebugg ) //-- change memory only in debug mode. { // var addr = "ADDR: 00=01=02=03=04=05=06=07=08=09=0A=0B=0C=0D=0E=0F \n"; tempStr = document.getElementById( 'start' ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); var start = parseInt( tempStr, 16 ) & 0xFFF0; var adr = "Addr: 00=01=02=03=04=05=06=07"; var mem = ""; while(true) { if( (start & 0x000F) == 0x0008 ) { adr = "Addr: 08=09=0A=0B=0C=0D=0E=0F"; mem = addr2hex(start).toUpperCase() + ": "; } else { adr = "Addr: 00=01=02=03=04=05=06=07"; mem = addr2hex(start).toUpperCase() + ": "; } for (var x = 0; x < 8; x++) { mem += num2hex(memory[(start + x) & 0xffff]).toUpperCase(); if(x < 7) mem += "="; } var inp = prompt("Edit memory bytes in this format and press 'Ok':\n\n" + adr, mem ); if( inp == undefined ) break; if( inp == "" ) break; inp = inp.toUpperCase() + "="; if( inp.match( new RegExp( / /g ) ) ) { inp = inp.replace( / /g, "" ); //-- A= 34 оставит A=34; } // message( "Return: " + inp + ";" ); if( inp.match( new RegExp( /:/g ) ) ) { if( inp.match( new RegExp( /=/g ) ) ) { inp = inp + "="; var len = inp.length; var beg = inp.indexOf(":", 0) + 1; var fin = inp.indexOf("=", 0); var num = 0; while(true) { mem = inp.substring(beg,fin); if(mem.length > 0){ if( mem.match( new RegExp( /^[0-9A-F]{1,2}$/i ) ) ) { memStoreByte( start + num, parseInt( mem, 16 ) ) ; } else { if( mem.length > 1){ mem = mem.substring(0,1); if( mem.match( new RegExp( /^[0-9A-F]{1,2}$/i ) ) ) memStoreByte( start + num, parseInt( mem, 16 ) ) ; } } } beg = fin + 1; if(beg >= len) break; fin = inp.indexOf("=", beg); if(fin < 0) break; num++; } } } start = start + 8; updateMonitor(); } //- while( } } /* * editAllRegs() - edits All 6502 CPU Registers * Executed when miniDebugger area is klicked. */ function editAllRegs() { if( debug && !autoDebugg ) //-- change 6502 CPU Registers only in debug mode. { var rgs = "A=$" + num2hex(regA).toUpperCase() + " X=$" + num2hex(regX).toUpperCase() + " Y=$" + num2hex(regY).toUpperCase() + " S=$" + num2hex(regSP).toUpperCase() + " P=$" + num2hex(regP).toUpperCase() + " PC=$" + addr2hex(regPC).toUpperCase(); var inp = prompt( "Edit 6502 CPU Registers in this format and press 'Ok':", rgs ); if( inp == undefined ) return; if( inp == "" ) return; inp = inp.toUpperCase(); if( inp.match( new RegExp( /0X/g ) ) ) { inp = inp.replace( /0X/g, "" ); //-- 0xFFDE оставит FFDE; } if( inp.match( new RegExp( /\$/g ) ) ) { inp = inp.replace( /\$/g, "" ); //-- $DE оставит DE; } if( inp.match( new RegExp( / /g ) ) ) { inp = inp.replace( / /g, "" ); //-- A= 34 оставит A=34; } var len = inp.length; var beg = 0; var fin = 0; if( inp.match( new RegExp( /A=/g ) ) ) { inp = inp.replace( /A=/g, "R=" ); beg = inp.indexOf("R=", 0) + 2; fin = beg + 2; if(fin > len) fin = len; rgs = inp.substring(beg,fin); if( rgs.match( new RegExp( /^[0-9A-F]{1,2}$/i ) ) ) { regA = parseInt( rgs, 16 ); } else { if( rgs.length > 1){ rgs = rgs.substring(0,1); if( rgs.match( new RegExp( /^[0-9A-F]{1}$/i ) ) ) regA = parseInt( rgs, 16 ); } } } if( inp.match( new RegExp( /X=/g ) ) ) { beg = inp.indexOf("X=", 0) + 2; fin = beg + 2; if(fin > len) fin = len; rgs = inp.substring(beg,fin); if( rgs.match( new RegExp( /^[0-9A-F]{1,2}$/i ) ) ) { regX = parseInt( rgs, 16 ); } else { if( rgs.length > 1){ rgs = rgs.substring(0,1); if( rgs.match( new RegExp( /^[0-9A-F]{1}$/i ) ) ) regX = parseInt( rgs, 16 ); } } } if( inp.match( new RegExp( /Y=/g ) ) ) { beg = inp.indexOf("Y=", 0) + 2; fin = beg + 2; if(fin > len) fin = len; rgs = inp.substring(beg,fin); if( rgs.match( new RegExp( /^[0-9A-F]{1,2}$/i ) ) ) { regY = parseInt( rgs, 16 ); } else { if( rgs.length > 1){ rgs = rgs.substring(0,1); if( rgs.match( new RegExp( /^[0-9A-F]{1}$/i ) ) ) regY = parseInt( rgs, 16 ); } } } if( inp.match( new RegExp( /S=/g ) ) ) { beg = inp.indexOf("S=", 0) + 2; fin = beg + 2; if(fin > len) fin = len; rgs = inp.substring(beg,fin); if( rgs.match( new RegExp( /^[0-9A-F]{1,2}$/i ) ) ) { regSP = parseInt( rgs, 16 ); } else { if( rgs.length > 1){ rgs = rgs.substring(0,1); if( rgs.match( new RegExp( /^[0-9A-F]{1}$/i ) ) ) regSP = parseInt( rgs, 16 ); } } } if( inp.match( new RegExp( /P=/g ) ) ) { beg = inp.indexOf("P=", 0) + 2; fin = beg + 2; if(fin > len) fin = len; rgs = inp.substring(beg,fin); if( rgs.match( new RegExp( /^[0-9A-F]{1,2}$/i ) ) ) { regP = parseInt( rgs, 16 ) | 0x30; } else { if( rgs.length > 1){ rgs = rgs.substring(0,1); if( rgs.match( new RegExp( /^[0-9A-F]{1}$/i ) ) ) regP = parseInt( rgs, 16 ) | 0x30; } } } if( inp.match( new RegExp( /PC=/g ) ) ) { beg = inp.indexOf("PC=", 0) + 3; fin = beg + 4; if(fin > len) fin = len; rgs = inp.substring(beg,fin); len = rgs.length; if( rgs.match( new RegExp( /^[0-9A-F]{1,4}$/i ) ) ) { regPC = parseInt( rgs, 16 ); //-- convert value from HEX-string. } else { if(len > 1) { while(true) { len = len - 1; if(len < 1) break; rgs = rgs.substring(0,len); if(rgs.match( new RegExp( /^[0-9A-F]{1,4}$/i ) ) ){ regPC = parseInt( rgs, 16 ); break; } } // while( } // if(len } // else } // message( "Return: " + inp + "; " + len + "; $" + addr2hex(regPC).toUpperCase() ); // 012345678901234567890123456789 // A=00X=00Y=00S=FFP=30PC=0600; length = 27 // 4 } updateDebugInfo(); } /* * stopDebugger() - stops debugger * Executed when [] Debugger is UPchecked. */ function stopDebugger() { // debug = false; if( codeRunning ) { document.getElementById( "stepButton" ).disabled = true; // 'Step' disabled; document.getElementById( "gotoButton" ).disabled = true; // 'Jmp to:' disabled; autoDebugg = false; } document.getElementById( "autod" ).checked = false; // '[] A-Deb' NOT checked; document.getElementById( "autod" ).disabled = true; // 'A-Debug' disabled; message( "Debugger is disabled!"); updateDebugInfo(); } /* * enableDebugger() - stops debugger * Executed when [] Debugger is Checked. */ function enableDebugger() { // debug = true; if( codeRunning ) { updateDebugInfo(); document.getElementById( "stepButton" ).disabled = false; document.getElementById( "gotoButton" ).disabled = false; } document.getElementById( "autod" ).disabled = false; // [] 'A-Debug' disabled; message( "Debugger is enabled!"); updateDebugInfo(); } /* * toggleDebug() - Toggles debugging on/off * Executed when [] Debugger is klicked. */ function toggleDebug() { debug = !debug; if( debug ) { // = true; enableDebugger(); } else { stopDebugger(); } } /* * toggleADebug() - Toggles debugging auto mode on/off, id="autod"; * Executed when [] AutoDB is checked. */ function toggleADebug() { autoDebugg = !autoDebugg; if( autoDebugg ) { var inp = prompt( "Set breakpoint at:", "$" + addr2hex(autoDeb).toUpperCase() ); // inp - get from prompt( ... ) request; if( inp == null) { autoDeb = 0x0000; message( "Breakpoint is disabled..." ); document.getElementById( "autod" ).checked = false; // '[] A-Deb' NOT checked; autoDebugg = false; } else // inp != null { if( inp.match( new RegExp( /^0x[0-9a-f]{1,4}$/i ) ) ) { inp = inp.replace( /^0x/, "" ); //-- 0xFFDE оставит FFDE; autoDeb = parseInt( inp, 16 ); //-- и преобразует как HEX. } else if( inp.match( new RegExp( /^\$[0-9a-f]{1,4}$/i))) { inp = inp.replace( /^\$/, "" ); //-- $DE оставит DE; autoDeb = parseInt( inp, 16 ); //-- и преобразует как HEX. } else { autoDeb = parseInt( inp, 16 ); //-- преобразует как HEX } document.getElementById( "stepButton" ).disabled = true; document.getElementById( "gotoButton" ).disabled = true; message( "Breakpoint is set at: $" + addr2hex(autoDeb).toUpperCase() ); } } // ! autoDebugg, else { autoDeb = 0x0000; message( "Breakpoint is disabled..." ); document.getElementById( "stepButton" ).disabled = false; document.getElementById( "gotoButton" ).disabled = false; } } /* * toggleMemDis() - Toggles Disassembler source: file/mem; * Executed when [] Memory: is klicked. */ function toggleMemDis() { memDisassm = !memDisassm; } /* * Refresh memory Monitor manually; * Executed when 'Refresh' is klicked. */ function refreshMonitor() { if(monitoring) updateMonitor(); } /* * toggleMonitor() - Toggles memory Monitor on/off; * Executed when [] Memory monitor ON: is klicked. */ function toggleMonitor() { monitoring = !monitoring; if(monitoring){ document.getElementById( 'monitor' ).style.display = 'block'; document.getElementById('messages').style.height = 61; document.getElementById( 'memRef' ).disabled = false; updateMonitor(); } else { document.getElementById( 'memRef' ).disabled = true; document.getElementById( 'monitor' ).innerHTML = ""; document.getElementById( 'monitor' ).style.display = 'none'; document.getElementById('messages').style.height = 106; } // alert('Monitor is toggled...'); } function updateMonitor() { if (monitoring) { tempStr = document.getElementById( 'start' ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); var start = parseInt( tempStr, 16 ) & 0xFFF0; tempStr = document.getElementById( 'length' ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); var length = parseInt( tempStr, 16 ); if((length & 0x000F) > 0) length = (length & 0xFFF0) + 16; document.getElementById( 'monitor' ).innerHTML = memformat(start, length); } } function memformat(start, length) { var addr = "ADDR: 00=01=02=03=04=05=06=07=08=09=0A=0B=0C=0D=0E=0F \n"; var html = ""; var n; html += "
"; // 
          html += addr;
      for (var x = 0; x < length; x++) {

        if ((x & 15) === 0) { //-- операнды строго равны, без преобразования типов.
         if (x > 0) { //-- не переводить строку перед 1-й строкой
          html += "\n";
          if ((x & 127) === 0) html += addr;
             }
             n = (start + x) & 0xffff;
          html += num2hex(((n >> 8) & 0xff)).toUpperCase();
          html += num2hex((n & 0xff)).toUpperCase();
          html += ": ";
        }
        html += num2hex(memory[(start + x) & 0xffff]).toUpperCase();
        html += " ";
      }
        html += "\n";
        html += addr;
        html += '
'; return html; } /* * disableButtons() - Disables the Run and Debug buttons when text * is altered in the code editor * Executed while events in 'textarea' */ function disableButtons() { document.getElementById( "runButton" ).disabled = true; // 'Run' disabled not 'Stop'; document.getElementById( "hexdumpButton" ).disabled = true; // 'HexDump' disabled; document.getElementById( "fileSelect" ).disabled = false; // 'Examples' enabled; document.getElementById( "compileButton" ).disabled = false; // 'Compile' enabled; document.getElementById( "runButton" ).value = "Run"; document.getElementById( "submitCode" ).disabled = true; // 'Clear' enabled; codeCompiledOK = false; if(codeRunning){ //--- if it running message( "Stopped run at PC = $" + addr2hex(regPC).toUpperCase() ); } codeRunning = false; document.getElementById( "code" ).focus(); document.getElementById( "stepButton" ).disabled = true; document.getElementById( "gotoButton" ).disabled = true; clearInterval( myInterval ); } /* function fileExec() { //--- it's path's test message( "We are at: " + document.location.href ); message( "We are at: " + window.location.href ); message( "We are at: " + document.location.pathname ); } */ function textClick() { if(!codeRunning){ //--- if not running emulation. if(document.getElementById( "compileButton" ).disabled){ //--- compile.disabled = true // message( "Click at text area... " ); //--- it's test newText = document.getElementById( "code" ).value.length; if(newText != oldText){ //--- if there is difference // Disables Run & Debug buttons when text is altered in the code editor disableButtons(); oldText = newText; } } } } function textKey() { if(document.getElementById( "compileButton" ).disabled){ //--- compile.disabled = true // message( "Key is Pressed at text area... " );//--- it's test disableButtons(); } } /* * Load() - Loads a file from server or HDD. * */ function Load( file ) { if( file.toUpperCase() == "EXAMPLES" ) return; reset(); disableButtons(); message("Prepare for loading file: Path.../examples/" + file); document.getElementById( "code" ).value = "Loading, please wait..."; document.getElementById( "compileButton" ).disabled = true; document.getElementById( "disButton" ).disabled = true; tempStr = window.location.href; message( "Full Path: " + tempStr ); if( (tempStr.toUpperCase().indexOf("FILE:") >= 0) || (tempStr.toUpperCase().indexOf("LOCALHOST") >= 0)) { var pos = 0; while(true) { var foundPos = tempStr.indexOf("/", pos); if(foundPos == -1) break; pos = foundPos + 1; } tempStr = tempStr.substring(0,pos) + "examples/" + file; message( "Loading: " + tempStr + "..." ); //--- 'FILE://LOCALHOST' document.getElementById( "code" ).value = ""; //--- clear TexBuff oldText = document.getElementById( "code" ).value.length; //--- remember TexBuff LoadHDD( tempStr, file ); /* var ua = navigator.userAgent; if(ua.search(/Opera/) > 0){ } */ var timer = setInterval(function() { if(w.closed) { clearInterval(timer); // alert('PopUp is closed'); if(document.getElementById( "code" ).value == ""){ document.getElementById( "code" ).value = "hlt ;--- File loading error..." document.getElementById('messages').innerHTML="File is not loaded. Try to load it manually!
"; disableButtons(); } } }, 500); document.getElementById( "fileSelect" ).options[0].selected = true; //--- "Examples" } else { oldText = document.getElementById( "code" ).value.length; //--- remember TexBuff //--- xmlhttp = getXmlHttp(); //--- new XMLHttpRequest(); xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = FileLoaded; xmlhttp.open( "GET", "./examples/" + file ); xmlhttp.send( null ); document.getElementById( "fileSelect" ).options[0].selected = true; //--- } stopDebugger(); } function FileLoaded() { message("xmlhttp.readyState = " + xmlhttp.readyState); if( xmlhttp.readyState == 4 ) { if( xmlhttp.status == 200 ) { message("Ready for Loading..."); message("xmlhttp.status = " + xmlhttp.status); document.getElementById( "code" ).value = xmlhttp.responseText; document.getElementById( "compileButton" ).disabled = false; document.getElementById( "disButton" ).disabled = false; message("Finish Loading..."); } else { message("xmlhttp.status = " + xmlhttp.status); } } } /* * Load local file from disk... * */ function LoadHDD( fpath, file ) { w = window.open('', file.toUpperCase(), 'width=400,height=510,resizable=no,scrollbars=no,toolbar=no,location=no,menubar=no,status=no' ); html = ""; html += ""; html += ""; html += ""; html += ""; html += file.toUpperCase(); html += ""; html += ""; html += ""; html += ""; html += ""; html += "
"; html += "

COPY selected text to 6502 Text window

"; html += "
"; html += ""; html += "
"; html += "
"; html += ">8) & 0xff); // High byte tempStr = document.getElementById( "IRQCode" ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); defaultCodePC = parseInt( tempStr, 16 ); message( "Setting 6502 _IRQ_ vector at $FFFE,FFFF = $" + addr2hex(defaultCodePC).toUpperCase() ); memory[0xfffe] = (defaultCodePC & 0xff); // Low byte memory[0xffff] = ((defaultCodePC>>8) & 0xff); // High byte tempStr = document.getElementById( "NMICode" ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); defaultCodePC = parseInt( tempStr, 16 ); message( "Setting 6502 _NMI_ vector at $FFFA,FFFB = $" + addr2hex(defaultCodePC).toUpperCase() ); memory[0xfffa] = (defaultCodePC & 0xff); // Low byte memory[0xfffb] = ((defaultCodePC>>8) & 0xff); // High byte defaultCodePC = regPC; regSP = 0xff; regP = 0x34; //--- 0011.0100b - flags B & unused are always = '1'; serialOut = ""; titleOut = ""; serialHex = false; titleHex = false; updateDebugInfo(); message( "Waiting for events..." ); } /* * message() - Prints text in the message window ; * */ function message( text ) { obj = document.getElementById( "messages" ); obj.innerHTML += text + "
"; obj.scrollTop = obj.scrollHeight; } /* * compileCode() * * "Compiles" the code into a string (global var compiledCode) * */ function compileCode() { reset(); document.getElementById( "messages" ).innerHTML = ""; var code = document.getElementById( "code" ).value; code += "\n\n"; lines = code.split( "\n" ); codeCompiledOK = true; labelIndex = new Array(); labelPtr = 0; message( "Indexing labels..." ); // defaultCodePC = regPC = 0x600; //--- tempStr = document.getElementById( "RUNCode" ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); regPC = parseInt( tempStr, 16 ); defaultCodePC = regPC; for( xc=0; xcLabel already defined at line "+(xc+1)+": "+lines[xc] ); return false; } } str = "Found " + labelIndex.length + " label"; if( labelIndex.length != 1 ) str += "s"; message( str + "..." ); tempStr = document.getElementById( "RUNCode" ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); defaultCodePC = parseInt( tempStr, 16 ); regPC = defaultCodePC; //--- 0x600 ORG message( "Compiling code... from ORG $" + addr2hex(defaultCodePC).toUpperCase() ); for( x=0; x", ">" ); message( "Syntax error line " + (x+1) + ": " + str + ""); document.getElementById( "runButton" ).disabled = true; document.getElementById( "compileButton" ).disabled = false; document.getElementById( "disButton" ).disabled = true; document.getElementById( "fileSelect" ).disabled = false; document.getElementById( "watch" ).disabled = true; return; } updateDisplayFull(); message( "Code compiled successfully, " + codeLen + " bytes." ); } /* * indexLabels() - Pushes all labels to array. * */ function indexLabels( input ) { // remove comments input = input.replace( new RegExp( /^(.*?);.*/ ), "$1" ); // trim line input = input.replace( new RegExp( /^\s+/ ), "" ); input = input.replace( new RegExp( /\s+$/ ), "" ); // Figure out how many bytes this instuction takes thisPC = defaultCodePC; codeLen = 0; // defaultCodePC = 0x600; compileLine( input ); regPC += codeLen; // Find command or label if( input.match( new RegExp( /^\w+:/ ) ) ) { label = input.replace( new RegExp( /(^\w+):.*$/ ), "$1" ); // message( "Find label: " + label + "; " ); return pushLabel( label + "|" + thisPC ); } return true; } /* * pushLabel() - Push label to array. Return false if label already exists. * */ function pushLabel( name ) { if( findLabel( name ) ) return false; labelIndex[labelPtr++] = name + "|"; return true; } /* * findLabel() - Returns true if label exists. * */ function findLabel( name ) { for( m=0; m 0xffff) ) { message( "Unable to relocate code outside 64k memory" ); return false; } defaultCodePC = addr; return true; } if( input.match( /^\w+\s+.*?$/ ) ) { param = input.replace( new RegExp( /^\w+\s+(.*?)/ ), "$1" ); } else { if( input.match( /^\w+$/ ) ) { param = ""; } else { return false; } } param = param.replace( /[ ]/g, "" ); if( command == "DCB" ){ // message( "Processing 'DCB' " + param ); return DCB( param ); } if( command == "BRK" ){ pushByte( 0x00 ); // Regardless of what ANY 6502 doc's says, BRK is a 2 byte opcode. pushByte( 0xea ); // The first is #$00, and the second is a padding byte (NOP). return true; } for( o=0; o 0 ) { ch = str.substring( 0, 1 ); if( ch == "$" ) { number = parseInt( str.replace( /^\$/, "" ), 16 ); pushByte( number ); } else if( ch >= "0" && ch <= "9" ) { number = parseInt( str, 10 ); pushByte( number ); } else { return false; } } } return true; } /* * checkBranch() - Commom branch function for all branches (BCC, BCS, BEQ, BNE..) * */ function checkBranch( param, opcode ) { if( opcode == 0x00 ) return false; addr = -1; if( param.match( /\w+/ ) ) addr = getLabelPC( param ); if( addr == -1 ) { pushWord( 0x00 ); return false; } pushByte( opcode ); if( addr < (defaultCodePC-0x600) ) { // Backwards? pushByte( (0xff - ((defaultCodePC-0x600)-addr)) & 0xff ); return true; } pushByte( (addr-(defaultCodePC-0x600)-1) & 0xff ); return true; } /* * checkImmediate() - Check if param is immediate and push value * */ function checkImmediate( param, opcode ) { if( opcode == 0x00 ) return false; if( param.match( new RegExp( /^#\$[0-9a-f]{1,2}$/i ) ) ) { pushByte( opcode ); value = parseInt( param.replace( /^#\$/, "" ), 16 ); if( value < 0 || value > 255 ) return false; pushByte( value ); return true; } if( param.match( new RegExp( /^#[0-9]{1,3}$/i ) ) ) { pushByte( opcode ); value = parseInt( param.replace( /^#/, "" ), 10 ); if( value < 0 || value > 255 ) return false; pushByte( value ); return true; } // Label lo/hi if( param.match( new RegExp( /^#[<>]\w+$/ ) ) ) { label = param.replace( new RegExp( /^#[<>](\w+)$/ ), "$1" ); hilo = param.replace( new RegExp( /^#([<>]).*$/ ), "$1" ); pushByte( opcode ); if( findLabel( label ) ) { addr = getLabelPC( label ); switch( hilo ) { case ">": pushByte( (addr >> 8) & 0xff ); return true; break; case "<": pushByte( addr & 0xff ); return true; break; default: return false; break; } } else { pushByte( 0x00 ); return true; } } return false; } /* * checkIndZP() - Check indirect ZP * */ /* * checkIndirectX() - Check if param is indirect X and push value * */ function checkIndirectX( param, opcode ) { if( opcode == 0x00 ) return false; if( param.match( /^\(\$[0-9a-f]{1,2},X\)$/i ) ) { pushByte( opcode ); value = param.replace( new RegExp( /^\(\$([0-9a-f]{1,2}).*$/i ), "$1" ); if( value < 0 || value > 255 ) return false; pushByte( parseInt( value, 16 ) ); return true; } return false; } /* * checkIndirectY() - Check if param is indirect Y and push value * */ function checkIndirectY( param, opcode ) { if( opcode == 0x00 ) return false; if( param.match( /^\(\$[0-9a-f]{1,2}\),Y$/i ) ) { pushByte( opcode ); value = param.replace( new RegExp( /^\([\$]([0-9a-f]{1,2}).*$/i ), "$1" ); if( value < 0 || value > 255 ) return false; pushByte( parseInt( value, 16 ) ); return true; } return false; } /* * checkSingle() - Single-byte opcodes * */ function checkSingle( param, opcode ) { if( opcode == 0x00 ) return false; if( param != "" ) return false; pushByte( opcode ); return true; } /* * checkZeroPage() - Check if param is ZP and push value * */ function checkZeroPage( param, opcode ) { if( opcode == 0x00 ) return false; if( param.match( /^\$[0-9a-f]{1,2}$/i ) ) { pushByte( opcode ); value = parseInt( param.replace( /^\$/, "" ), 16 ); if( value < 0 || value > 255 ) return false; pushByte( value ); return true; } if( param.match( /^[0-9]{1,3}$/i ) ) { pushByte( opcode ); value = parseInt( param, 10 ); if( value < 0 || value > 255 ) return false; pushByte( value ); return true; } return false; } /* * checkAbsoluteX() - Check if param is ABSX and push value * */ function checkAbsoluteX( param, opcode ) { if( opcode == 0x00 ) return false; if( param.match( /^\$[0-9a-f]{3,4},X$/i ) ) { pushByte( opcode ); number = param.replace( new RegExp( /^\$([0-9a-f]*),X/i ), "$1" ); value = parseInt( number, 16 ); if( value < 0 || value > 0xffff ) return false; pushWord( value ); return true; } if( param.match( /^\w+,X$/i ) ) { param = param.replace( new RegExp( /,X$/i ), "" ); pushByte( opcode ); if( findLabel( param ) ) { addr = getLabelPC( param ); if( addr < 0 || addr > 0xffff ) return false; pushWord( addr ); return true; } else { pushWord( 0x1234 ); return true; } } return false; } /* * checkAbsoluteY() - Check if param is ABSY and push value * */ function checkAbsoluteY( param, opcode ) { if( opcode == 0x00 ) return false; if( param.match( /^\$[0-9a-f]{3,4},Y$/i ) ) { pushByte( opcode ); number = param.replace( new RegExp( /^\$([0-9a-f]*),Y/i ), "$1" ); value = parseInt( number, 16 ); if( value < 0 || value > 0xffff ) return false; pushWord( value ); return true; } // it could be a label too.. if( param.match( /^\w+,Y$/i ) ) { param = param.replace( new RegExp( /,Y$/i ), "" ); pushByte( opcode ); if( findLabel( param ) ) { addr = getLabelPC( param ); if( addr < 0 || addr > 0xffff ) return false; pushWord( addr ); return true; } else { pushWord( 0x1234 ); return true; } } return false; } /* * checkZeroPageX() - Check if param is ZPX and push value * */ function checkZeroPageX( param, opcode ) { if( opcode == 0x00 ) return false; if( param.match( /^\$[0-9a-f]{1,2},X/i ) ) { pushByte( opcode ); number = param.replace( new RegExp( /^\$([0-9a-f]{1,2}),X/i ), "$1" ); value = parseInt( number, 16 ); if( value < 0 || value > 255 ) return false; pushByte( value ); return true; } if( param.match( /^[0-9]{1,3},X/i ) ) { pushByte( opcode ); number = param.replace( new RegExp( /^([0-9]{1,3}),X/i ), "$1" ); value = parseInt( number, 10 ); if( value < 0 || value > 255 ) return false; pushByte( value ); return true; } return false; } function checkZeroPageY( param, opcode ) { if( opcode == 0x00 ) return false; if( param.match( /^\$[0-9a-f]{1,2},Y/i ) ) { pushByte( opcode ); number = param.replace( new RegExp( /^\$([0-9a-f]{1,2}),Y/i ), "$1" ); value = parseInt( number, 16 ); if( value < 0 || value > 255 ) return false; pushByte( value ); return true; } if( param.match( /^[0-9]{1,3},Y/i ) ) { pushByte( opcode ); number = param.replace( new RegExp( /^([0-9]{1,3}),Y/i ), "$1" ); value = parseInt( number, 10 ); if( value < 0 || value > 255 ) return false; pushByte( value ); return true; } return false; } /* * checkAbsolute() - Check if param is ABS and push value * */ function checkAbsolute( param, opcode ) { if( opcode == 0x00 ) return false; pushByte( opcode ); if( param.match( /^\$[0-9a-f]{3,4}$/i ) ) { value = parseInt( param.replace( /^\$/, "" ), 16 ); if( value < 0 || value > 0xffff ) return false; pushWord( value ); return true; } if( param.match( /^[0-9]{1,5}$/i ) ) { // Thanks, Matt! value = parseInt( param, 10 ); if( value < 0 || value > 65535 ) return false; pushWord( value ); return( true ); } // it could be a label too.. if( param.match( /^\w+$/ ) ) { if( findLabel( param ) ) { addr = (getLabelPC( param )); if( addr < 0 || addr > 0xffff ) return false; pushWord( addr ); return true; } else { pushWord( 0x1234 ); return true; } } return false; } /***************************************************************************** ****************************************************************************/ /* * stackPush() - Push byte to stack * */ function stackPush( value ) { memory[(regSP&0xff)+0x100] = value & 0xff; regSP--; if( regSP < 0 ) { // message( "CPU Stack full: SP = $" + addr2hex(regSP).toUpperCase() ); regSP = 0xff; // message( "Stack overflow: SP = $" + num2hex(regSP).toUpperCase() ); } } /***************************************************************************** ****************************************************************************/ /* * stackPop() - Pop byte from stack * */ function stackPop() { var value; regSP++; if( regSP > 0xff ) { // message( "CPU Stack empty: SP = $" + addr2hex(regSP).toUpperCase() ); regSP = 0; // message( "Stack underflow: SP = $" + num2hex(regSP).toUpperCase() ); } value = memory[regSP+0x100]; return value; } /* * pushByte() - Push byte to compiledCode variable * */ function pushByte( value ) { memory[defaultCodePC] = value & 0xff; if( (defaultCodePC >= 0xfffa) && (defaultCodePC<=0xffff) ) { // If programm change NMI, RESET or IRQ vectors, they must be changed in input fields. if( (defaultCodePC >= 0xfffa) && (defaultCodePC<=0xfffb) ) { //--- set NMI-field value; tempInt = (memory[0xfffa] & 0xff) | ((memory[0xfffb] & 0xff)<<8); document.getElementById( "NMICode" ).value = "$" + addr2hex(tempInt).toUpperCase(); } if( (defaultCodePC >= 0xfffc) && (defaultCodePC<=0xfffd) ) { //--- set RESET-field value; tempInt = (memory[0xfffc] & 0xff) | ((memory[0xfffd] & 0xff)<<8); document.getElementById( "RUNCode" ).value = "$" + addr2hex(tempInt).toUpperCase(); } if( (defaultCodePC >= 0xfffe) && (defaultCodePC<=0xffff) ) { //--- set IRQ-field value; tempInt = (memory[0xfffe] & 0xff) | ((memory[0xffff] & 0xff)<<8); document.getElementById( "IRQCode" ).value = "$" + addr2hex(tempInt).toUpperCase(); } } defaultCodePC++; codeLen++; } /* * pushWord() - Push a word using pushByte twice * */ function pushWord( value ) { pushByte( value & 0xff ); pushByte( (value>>8) & 0xff ); } /* * popByte() - Pops a byte * */ function popByte() { return( memory[regPC++] & 0xff ); //--- control regPC++ ??? } /* * popWord() - Pops a word using popByte() twice * */ function popWord() { return popByte() + (popByte() << 8); } /* * memStoreByte() - Poke a byte, don't touch any registers * */ function memStoreByte( addr, value ) { /* OUTPUT to messagebox */ if( addr == 0x00ff) { //-- OUT - serial, IN - keyCode; if( (value & 0x00ff) == 0x0d ) { if(serialOut.length > 0) message(serialOut); serialOut = ""; } else if( (value & 0x00ff) == 0x1f ) { document.getElementById( "messages" ).innerHTML = ""; } else if( (value & 0x00ff) == 0x1b ) { serialHex = !serialHex; } else if( (value & 0x00ff) == 0x00 ) { serialOut = ""; } else { if(serialHex) { serialOut += num2hex(value & 0x00ff).toUpperCase() + " "; } else { if( ((value & 0x00ff) > 0x7f) && ((value & 0x00ff) < 0xc0) ){ serialOut += String.fromCharCode((value & 0x00ff) + 0x390); } else if ((value & 0x00ff) < 0x20) { serialOut += String.fromCharCode(0xa9); } else { serialOut += String.fromCharCode(value & 0x00ff); } } } return; } /* OUTPUT to title */ if( addr == 0x00fe) { //-- OUT - title, IN - random; if( (value & 0x00ff) == 0x0d ) { if(titleOut.length > 0) document.title = titleOut; titleOut = ""; } else if( (value & 0x00ff) == 0x1f ) { document.title = "-"; } else if( (value & 0x00ff) == 0x1b ) { titleHex = !titleHex; } else if( (value & 0x00ff) == 0x00 ) { titleOut = ""; } else { if(titleHex) { titleOut += num2hex(value & 0x00ff).toUpperCase() + " "; } else { if( ((value & 0x00ff) > 0x7f) && ((value & 0x00ff) < 0xc0) ){ titleOut += String.fromCharCode((value & 0x00ff) + 0x390); } else if ((value & 0x00ff) < 0x20) { titleOut += String.fromCharCode(0xa9); } else { //- String.charCodeAt(n); titleOut += String.fromCharCode(value & 0x00ff); } } } return; } //------ Stores Byte to memory ------------- memory[ addr ] = (value & 0xff); //---- trace NMI, ReseT & IRQ addresses... if( (addr >= 0xfffa) && (addr<=0xffff) ) { // If programm change NMI, RESET or IRQ vectors, they must be changed in input fields. if( (addr >= 0xfffa) && (addr<=0xfffb) ) { //--- set NMI-field value; tempInt = (memory[0xfffa] & 0xff) | ((memory[0xfffb] & 0xff)<<8); document.getElementById( "NMICode" ).value = "$" + addr2hex(tempInt).toUpperCase(); } if( (addr >= 0xfffc) && (addr<=0xfffd) ) { //--- set RESET-field value; tempInt = (memory[0xfffc] & 0xff) | ((memory[0xfffd] & 0xff)<<8); document.getElementById( "RUNCode" ).value = "$" + addr2hex(tempInt).toUpperCase(); } if( (addr >= 0xfffe) && (addr<=0xffff) ) { //--- set IRQ-field value; tempInt = (memory[0xfffe] & 0xff) | ((memory[0xffff] & 0xff)<<8); document.getElementById( "IRQCode" ).value = "$" + addr2hex(tempInt).toUpperCase(); } } //---- trace Video-buffer addresses if( (addr >= 0x200) && (addr<=0x5ff) ) display[addr-0x200].background = palette[memory[addr] & 0x0f]; } /* * setNMICode(); - Poke a word at $FFFA,B and make NMI push PCH on stack, decrement SP push PCL on stack, decrement SP push P on stack (with B flag *clear*), decrement SP fetch PCL ADDR = FFFA for NMI set I flag fetch PCH ADDR = FFFB for NMI * */ function setNMICode() { // NMI - Non-Maskable Interrupt /* здесь основная идея: прочитать вектор NMI и сравнить со значением в поле ввода. Если они отличаются, то значение в поле ввода записать по 0xFFFA, 0xFFFB и выполнить этот вызов NMI. */ tempStr = document.getElementById( "NMICode" ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); tempInt = parseInt( tempStr, 16 ); // get IRQ addr from InputBOX; addr = (memory[0xfffa] & 0xff) | ((memory[0xfffb] & 0xff)<<8); //...from MEM; if( tempInt != addr ){ memory[0xfffa] = (tempInt & 0xff); // save Low byte memory[0xfffb] = ((tempInt>>8) & 0xff); // save High byte addr = tempInt; } currAddr = regPC-1; stackPush( ((currAddr >> 8) & 0xff) ); stackPush( (currAddr & 0xff) ); regP &= 0xef; // B flag *clear* stackPush( regP ); regPC = addr; regP |= 0x04; // set I flag (запрещение прерываний) message( "Prosessing NMI, regPC = $" + addr2hex(regPC).toUpperCase() ); } /* * setIRQCode(); - Poke a word at $FFFE,F and make IRQ (= BRK) push PCH on stack, decrement SP push PCL on stack, decrement SP push P on stack (with B flag *clear*), decrement SP fetch PCL ADDR = FFFE for IRQ set I flag fetch PCH ADDR = FFFF for IRQ The B status flag doesn't physically exist inside the CPU, and only appears as different values being pushed for bit 4 * */ function setIRQCode() { /* здесь основная идея: прочитать вектор IRQ и сравнить со значением в поле ввода. Если они отличаются, то значение в поле ввода записать по 0xFFFE, 0xFFFF и выполнить этот вызов IRQ. */ if( regP & 0x04 ){ // testing flag I; Boolean(a) == !!a; message( "IRQ is disabled, flag I = " + Boolean(regP & 0x04).toString() ); } else { tempStr = document.getElementById( "IRQCode" ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); tempInt = parseInt( tempStr, 16 ); // get IRQ addr from InputBOX; addr = (memory[0xfffe] & 0xff) | ((memory[0xffff] & 0xff)<<8); //...from MEM; if( tempInt != addr ){ memory[0xfffe] = (tempInt & 0xff); // save Low byte memory[0xffff] = ((tempInt>>8) & 0xff); // save High byte addr = tempInt; } message( "Processing IRQ, flag I = " + Boolean(regP & 0x04).toString() ); currAddr = regPC-1; stackPush( ((currAddr >> 8) & 0xff) ); stackPush( (currAddr & 0xff) ); stackPush( regP & 0xef ) ; //- with B flag *clear* regPC = addr; regP |= 0x04; // set I flag (disable Int's) message( "Executing from PC = $" + addr2hex(regPC).toUpperCase() ); } } /* * submitCode() - Submits code (using XMLHttpRequest) to be published (moderated) * */ function submitCode() { area = document.getElementById("code"); area.value = ''; document.getElementById( "compileButton" ).disabled = false; document.getElementById( "messages" ).innerHTML = ""; /* resetValue(code); area = document.getElementById('someid'); area.onfocus = function() { if (area.value == 'DEFAULT VALUE HERE') area.value = ''; }; By the way, focus is better than click because it covers clicking as well as tabbing in using the keyboard, another form of focus. ------------- if( confirm( "Warning: This will submit your code to 6502asm.com for moderation.\n" + "Approved code will be published on the website." ) == false ) return; // Let's submit it xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if( xmlhttp.readyState==4 && xmlhttp.status==200 ) { message( "-- Thank you for sharing your code with other 6502asm.com users." ); message( "-- Your code has been submitted for moderation." ); message( "-- Once approved, it will be published on the website." ); if( xmlhttp.responseText != "" ) { alert( "An error occoured while submitting your code. The error message was:\n" + xmlhttp.responseText + "\n" + "Please try again later." ); } } } var code = document.getElementById( "code" ).value; var params = "code=" + code; xmlhttp.open( "POST", "submit.php", true ); xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xmlhttp.setRequestHeader("Content-length", params.length); xmlhttp.setRequestHeader("Connection", "close"); xmlhttp.send( params ); */ } function addr2hex( addr ) { return num2hex((addr>>8)&0xff)+num2hex(addr&0xff); } function num2hex( nr ) { str = "0123456789abcdef"; hi = ((nr&0xf0)>>4); lo = (nr&15); return str.substring( hi, hi+1 ) + str.substring( lo, lo+1 ); } function openPopup(content, title) { var w = window.open('', title, 'width=390,height=500,resizable=no,scrollbars=yes,toolbar=no,location=no,menubar=no,status=no'); var html = ""; html += ""; html += "" + title + ""; html += ""; html += ""; /* style='font-family:'Courier New';font-size:14.0pt' */ html += ""; html += "
"; html += "
"; html += "      "; html += "       "; html += ""; html += "
"; html += "
"; html += ""; html += ""; html += ""; w.document.write( html ); w.document.close(); } /* * hexDump() - Dump binary as hex to new window * */ function hexdump() { w = window.open('', 'HexDump', 'width=560,height=300,resizable=yes,scrollbars=yes,toolbar=no,location=no,menubar=no,status=no' ); html = ""; //--- style.css html += ""; html += "HexDump"; html += ""; html += ""; html += "ADDR: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
"; html += "-----+------------------------------------------------
"; tempStr = document.getElementById( "RUNCode" ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); tempInt = parseInt( tempStr, 16 ); // get RUN addr from InputBOX; for( x=0; x<=codeLen; x++ ) { if( (x&15) == 0 ) //--- codeLen ??? { if( x != 0 ){ html += "
"; } n = (tempInt+x); //--- offset 600 html += num2hex( ((n>>8)&0xff) ); html += num2hex( (n&0xff) ); html += ": "; } html += num2hex( memory[tempInt+x] ).toUpperCase(); // if( x&1 ) html += " "; } // if( (x&1) ) html += "-- [END]"; html += "
"; w.document.write( html ); w.document.close(); } /* * runBinary() - Executes the compiled code * Executed when button "Run"/"Stop" is pressed. */ function runBinary() { if( codeRunning ) { /* 'Stop' - Switch OFF everything */ document.getElementById( "runButton" ).value = "Run"; // 'Stop' Button = 'Run' document.getElementById( "hexdumpButton" ).disabled = false; // 'HexDump' enabled; document.getElementById( "fileSelect" ).disabled = false; // 'Examples' enabled; document.getElementById( "submitCode" ).disabled = false; // 'Clear' enabled; document.getElementById( "disButton" ).disabled = false; // 'Disassm' disabled; document.getElementById( "setNMICode" ).disabled = true; // 'NMI' disabled; document.getElementById( "setIRQCode" ).disabled = true; // 'IRQ' disabled; stopDebugger(); // debug = false; + updateDebugInfo(); codeRunning = false; clearInterval( myInterval ); message( "Stopped run at PC = $" + addr2hex(regPC).toUpperCase() ); } else { /* 'Run' - start executing */ document.getElementById( "runButton" ).value = "Stop"; // 'Stop' Button = 'Run' document.getElementById( "fileSelect" ).disabled = true; // 'Examples' disabled; document.getElementById( "hexdumpButton" ).disabled = true; // 'HexDump' disabled; document.getElementById( "submitCode" ).disabled = true; // 'Clear' disabled; document.getElementById( "setNMICode" ).disabled = false; // 'NMI' enabled; document.getElementById( "setIRQCode" ).disabled = false; // 'IRQ' enabled; document.getElementById( "disButton" ).disabled = true; // 'Disassm' enabled; document.getElementById( "watch" ).disabled = false; // 'Debugger' disabled; codeRunning = true; message( "Executing from PC = $" + addr2hex(regPC).toUpperCase() ); document.getElementById( "stepButton" ).disabled = !document.getElementById( "watch" ).checked; document.getElementById( "gotoButton" ).disabled = !document.getElementById( "watch" ).checked; document.getElementById( "autod" ).disabled = !document.getElementById( "watch" ).checked; // 'A-Debug' myInterval = setInterval( "multiexecute()", dtimeMS ); //-- Интервал в миллисекундах; updateDebugInfo(); } } /* * readZeroPage() - Get value from ZP ; * */ function jumpBranch( offset ) { if( offset > 0x7f ) regPC = (regPC - (0x100 - offset)); else regPC = (regPC + offset ); } function doCompare( reg, val ) { // if( (reg+val) > 0xff ) regP |= 0x01; else regP &= 0xfe; if( reg>=val ) regP |= 0x01; else regP &= 0xfe; // flag 'C' val = ( reg - val ) & 0xff; if( val ) regP &= 0xfd; else regP |= 0x02; // flag 'Z' if( val & 0x80 ) regP |= 0x80; else regP &= 0x7f; // flag 'N' } function testSBC( value ) { if( (regA ^ value ) & 0x80 ) regP |= 0x40; // V_flag = 1; else regP &= 0xbf; // V_flag = 0; if( regP & 8 ) { //- decimalMode tmp = 0xf + (regA & 0xf) - (value & 0xf) + (regP&1); if( tmp < 0x10 ) { w = 0; tmp -= 6; } else { w = 0x10; tmp -= 0x10; } w += 0xf0 + (regA & 0xf0) - (value & 0xf0); if( w < 0x100 ) { regP &= 0xfe; if( (regP&0xbf) && w<0x80) regP&=0xbf; w -= 0x60; } else { regP |= 1; if( (regP&0xbf) && w>=0x180) regP&=0xbf; } w += tmp; } else { w = 0xff + regA - value + (regP&1); if( w<0x100 ) { regP &= 0xfe; if( (regP&0xbf) && w<0x80 ) regP&=0xbf; } else { regP |= 1; if( (regP&0xbf) && w>= 0x180) regP&=0xbf; } } regA = w & 0xff; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function testADC( value ) { if( (regA ^ value) & 0x80 ) { regP &= 0xbf; } else { regP |= 0x40; } if( regP & 8 ) { tmp = (regA & 0xf) + (value & 0xf) + (regP&1); if( tmp >= 10 ) { tmp = 0x10 | ((tmp+6)&0xf); } tmp += (regA & 0xf0) + (value & 0xf0); if( tmp >= 160) { regP |= 1; if( (regP&0xbf) && tmp >= 0x180 ) regP &= 0xbf; tmp += 0x60; } else { regP &= 0xfe; if( (regP&0xbf) && tmp<0x80 ) regP &= 0xbf; } } else { tmp = regA + value + (regP&1); if( tmp >= 0x100 ) { regP |= 1; if( (regP&0xbf) && tmp>=0x180) regP &= 0xbf; } else { regP &= 0xfe; if( (regP&0xbf) && tmp<0x80) regP &= 0xbf; } } regA = tmp & 0xff; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } /* * multiexecute() - call from function runBinary(); * */ function multiexecute() { if( !debug || autoDebugg ) { //- если НЕдебаггер или если авто-дебаггер for( var w=0; w<64; w++ ) { execute(); execute(); //-- сработало выключение, но в цикле повторяется ***??? } if( (!codeRunning || !autoDebugg) && (document.getElementById( "runButton" ).value == "Stop" ) ) codeRunning = true; } } /* * execute() - Executes one instruction. * This is the main part of the CPU emulator. * */ function execute() { if( !codeRunning ) return; // set random number in 00FEH byte memory[0xfe] = Math.floor( Math.random()*256 ); if( autoDebugg ) { //-- если авто-дебаггер updateDebugInfo(); //-- Auto Debugger; if( regPC == autoDeb ) { //-- Break Point; alert ( "Break at PC = $" + addr2hex( regPC ).toUpperCase() ); message( "Breakpoint is disabled..." ); document.getElementById( "autod" ).checked = false; // '[] A-Deb' NOT checked; document.getElementById( "stepButton" ).disabled = false; document.getElementById( "gotoButton" ).disabled = false; codeRunning = false; //-- to avoid execution execute(); autoDebugg = false; //-- to avoid multiexecute(); return; } } // call function from Array inst[] with number popByte(); inst[popByte()](); //-- execute 1 command // flag 'codeRunning' can be changed during command execution. if( (regPC == 0) || (!codeRunning) ) { clearInterval( myInterval ); message( "Program end at PC = $" + addr2hex( regPC-1 ).toUpperCase() ); codeRunning = false; document.getElementById( "stepButton" ).disabled = true; document.getElementById( "gotoButton" ).disabled = true; document.getElementById( "runButton" ).value = "Run"; document.getElementById( "fileSelect" ).disabled = false; document.getElementById( "hexdumpButton" ).disabled = false; document.getElementById( "submitCode" ).disabled = false; } } /* ================= 6502 Opcode subroutines =================== */ function i00() { message( "BREAK Pass at $" + addr2hex(regPC).toUpperCase()); /* codeRunning = false; return; */ // B = break flag saved in stack (1 when interupt was caused by a BRK) tempStr = document.getElementById( "IRQCode" ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); tempInt = parseInt( tempStr, 16 ); // get IRQ addr from InputBOX; addr = (memory[0xfffe] & 0xff) | ((memory[0xffff] & 0xff)<<8); //...from MEM; if( tempInt != addr ){ memory[0xfffe] = (tempInt & 0xff); // save Low byte memory[0xffff] = ((tempInt>>8) & 0xff); // save High byte addr = tempInt; } /* message( "Processing BRK, flag I = $" + num2hex(regP & 0x10).toUpperCase() ); interrupt routines called by BRK always return 2 bytes after the actual BRK opcode the copy of the status register that is pushed on to the stack will have the B flag set if a BRK (software interrupt) was the cause of the interrupt, or cleared if an IRQ was the cause. */ currAddr = regPC; stackPush( ((currAddr >> 8) & 0xff) ); stackPush( (currAddr & 0xff) ); regP |= 0x10; // 0001.0000b set B flag in stack copy of regP stackPush( regP ); regPC = addr; message( "Executing from PC = $" + addr2hex(regPC).toUpperCase() ); } function i01() { //-- ORA (z,X) addr = (popByte() + regX) & 0xff; value = memory[addr] + (memory[addr+1] << 8); regA |= memory[value]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i05() { zp = popByte(); regA |= memory[zp]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i06() { // ASL z zp = popByte(); value = memory[zp]; regP = (regP & 0xfe) | ((value>>7)&1); value = value << 1; memStoreByte( zp, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i08() { // PHP, stackPush( regP | 0x30); } function i09() { regA |= popByte(); if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i0a() { // ASL, regP = (regP & 0xfe) | ((regA>>7)&1); regA = (regA << 1) & 0xff; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i0d() { regA |= memory[popWord()]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i0e() { // ASL a, addr = popWord(); value = memory[addr]; regP = (regP & 0xfe) | ((value>>7)&1); value = value << 1; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 2; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i10() { offset = popByte(); if( (regP & 0x80) == 0 ) jumpBranch( offset ); } function i11() { zp = popByte(); value = memory[zp] + (memory[zp+1]<<8) + regY; regA |= memory[value]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i15() { addr = (popByte() + regX) & 0xff; regA |= memory[addr]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i16() { addr = (popByte() + regX) & 0xff; value = memory[addr]; regP = (regP & 0xfe) | ((value>>7)&1); value = value << 1; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i18() { regP &= 0xfe; } function i19() { addr = popWord() + regY; regA |= memory[addr]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i1d() { addr = popWord() + regX; regA |= memory[addr]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i1e() { addr = popWord() + regX; value = memory[addr]; regP = (regP & 0xfe) | ((value>>7)&1); value = value << 1; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i20() { // JSR = CALL ADDR addr = popWord(); // JSR + Word ADDR currAddr = regPC-1; stackPush( ((currAddr >> 8) & 0xff) ); stackPush( (currAddr & 0xff) ); regPC = addr; } function i21() { //-- AND (z,X); addr = (popByte() + regX) & 0xff; value = memory[addr]+(memory[addr+1] << 8); regA &= memory[value]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i24() { zp = popByte(); value = memory[zp]; if( value & regA ) regP &= 0xfd; else regP |= 0x02; regP = (regP & 0x3f) | (value & 0xc0); } function i25() { //-- AND z ; zp = popByte(); regA &= memory[zp]; if( regA ) regP &= 0xfd; else regP |= 0x02; // Z if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; // N } /* message( "AND z = $" + num2hex(memory[value]).toUpperCase()+ "; regA = $" + num2hex(regA).toUpperCase() ); message( "AND A = $" + num2hex(regA).toUpperCase() ); message( "AND RegP = $" + num2hex(regP).toUpperCase() ); message( "AND z = $" + num2hex(memory[zp]).toUpperCase()+ "; regA = $" + num2hex(regA).toUpperCase() ); message( "AND A = $" + num2hex(regA).toUpperCase() ); message( "AND RegP = $" + num2hex(regP).toUpperCase() ); */ function i26() { sf = (regP & 1); addr = popByte(); value = memory[addr]; regP = (regP & 0xfe) | ((value>>7)&1); value = value << 1; value |= sf; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i28() { // PLP, regP = stackPop() | 0x30; // 0011.0000b // There is no real B bit! } function i29() { regA &= popByte(); if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i2a() { sf = (regP&1); regP = (regP&0xfe) | ((regA>>7)&1); regA = regA << 1; regA |= sf; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i2c() { value = memory[popWord()]; if( value & regA ) regP &= 0xfd; else regP |= 0x02; regP = (regP & 0x3f) | (value & 0xc0); } function i2d() { value = memory[popWord()]; regA &= value; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i2e() { sf = regP & 1; addr = popWord(); value = memory[addr]; regP = (regP & 0xfe) | ((value>>7)&1); value = value << 1; value |= sf; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i30() { offset = popByte(); if( regP & 0x80 ) jumpBranch( offset ); } function i31() { //-- AND (z),Y zp = popByte(); value = memory[zp]+(memory[zp+1]<<8) + regY; regA &= memory[value]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i35() { //-- AND z,X zp = popByte(); /* value = memory[zp]+(memory[zp+1]<<8) + regX; */ value = (zp + regX) & 0xff; regA &= memory[value]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i36() { // ROL z,X; sf = regP & 0x01; addr = (popByte() + regX) & 0xff; value = memory[addr]; regP = (regP & 0xfe) | ((value>>7)&1); value = value << 1; value |= sf; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i38() { //-- SEC regP |= 0x01; } function i39() { addr = popWord() + regY; value = memory[addr]; regA &= value; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i3d() { addr = popWord() + regX; value = memory[addr]; regA &= value; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i3e() { sf = regP & 1; addr = popWord() + regX; value = memory[addr]; regP = (regP & 0xfe) | ((value>>7)&1); value = value << 1; value |= sf; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i40() { // RTI - возврат из прерывания regP = stackPop() | 0x30; // 0011.0000b set B & unused flag; regPC = stackPop() | (stackPop()<<8); // regP &= 0xfb; // 1110.1011 - clear I flag } function i41() { //-- EOR (z,X) zp = (popByte() + regX) & 0xff; value = memory[zp]+ (memory[zp+1]<<8); regA ^= memory[value]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i45() { //-- EOR z; addr = popByte() & 0xff; value = memory[addr]; regA ^= value; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i46() { addr = popByte() & 0xff; value = memory[addr]; regP = (regP & 0xfe) | (value & 1); value = value >> 1; memStoreByte( addr, value ); if( value != 0 ) regP &= 0xfd; else regP |= 2; if( (value&0x80) == 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i48() { stackPush( regA ); } function i49() { //-- EOR #n regA ^= popByte(); if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i4a() { regP = (regP & 0xfe) | (regA & 1); regA = regA >> 1; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i4c() { regPC = popWord(); } function i4d() { //-- EOR a addr = popWord(); value = memory[addr]; regA ^= value; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i4e() { // LSR a addr = popWord(); value = memory[addr]; regP = (regP&0xfe)|(value&1); //--?? value = value >> 1; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i50() { offset = popByte(); if( (regP & 0x40) == 0 ) jumpBranch( offset ); } function i51() { //-- EOR (z),Y; zp = popByte(); value = memory[zp] + (memory[zp+1]<<8) + regY; regA ^= memory[value]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i55() { //-- EOR z,X; addr = (popByte() + regX) & 0xff; regA ^= memory[ addr ]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i56() { addr = (popByte() + regX) & 0xff; value = memory[ addr ]; regP = (regP&0xfe) | (value&1); value = value >> 1; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i58() { // CLI: I=0 (разрешение прерываний) regP &= 0xfb; // 1111.1011 - clear I flag } function i59() { addr = popWord() + regY; value = memory[ addr ]; regA ^= value; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i5d() { addr = popWord() + regX; value = memory[ addr ]; regA ^= value; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i5e() { addr = popWord() + regX; value = memory[ addr ]; regP = (regP&0xfe) | (value&1); value = value >> 1; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i60() { // RTS regPC = (stackPop()+1) | (stackPop()<<8); } function i61() { zp = (popByte() + regX) & 0xff; addr = memory[zp] + (memory[zp+1]<<8); value = memory[ addr ]; testADC( value ); } function i65() { addr = popByte(); value = memory[ addr ]; testADC( value ); } function i66() { sf = regP & 1; addr = popByte(); value = memory[ addr ]; regP = (regP&0xfe)|(value&1); value = value >> 1; if( sf ) value |= 0x80; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i68() { //-- PLA regA = stackPop(); if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i69() { value = popByte(); testADC( value ); } function i6a() { sf = regP & 1; regP = (regP&0xfe) | (regA&1); regA = regA >> 1; if( sf ) regA |= 0x80; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i6c() { //JMP, addr = popWord(); regPC = memory[addr] + (memory[addr+1]<<8); /* message( "regPC = " + addr2hex(regPC).toUpperCase()+ '; addr = ' + addr2hex(addr).toUpperCase()); value = memory[ addr ]; message( "Addr = " + addr2hex(regPC).toUpperCase() + '; addr = ' + addr2hex(addr).toUpperCase()); */ } function i6d() { addr = popWord(); value = memory[ addr ]; testADC( value ); } function i6e() { sf = regP & 1; addr = popWord(); value = memory[ addr ]; regP = (regP&0xfe)|(value&1); value = value >> 1; if( sf ) value |= 0x80; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i70() { offset = popByte(); if( regP & 0x40 ) jumpBranch( offset ); } function i71() { zp = popByte(); addr = memory[zp] + (memory[zp+1]<<8); value = memory[ addr + regY ]; testADC( value ); } function i75() { //- ADC z,X addr = (popByte() + regX) & 0xff; value = memory[ addr ]; // regP = (regP&0xfe) | (value&1); testADC( value ); } function i76() { sf = regP & 1; addr = (popByte() + regX) & 0xff; value = memory[ addr ]; regP = (regP&0xfe) | (value&1); value = value >> 1; if( sf ) value |= 0x80; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i78() { // SEI: I = 1 (запрещение прерываний) regP |= 0x04; // 0000.0100 - set I flag } function i79() { addr = popWord(); value = memory[ addr + regY ]; testADC( value ); } function i7d() { addr = popWord(); value = memory[ addr + regX ]; testADC( value ); } function i7e() { //--- ROR a,X; sf = regP & 1; addr = popWord() + regX; value = memory[ addr ]; regP = (regP & 0xfe) | (value & 1); value = value >> 1; if( sf ) value |= 0x80; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i81() { zp = (popByte()+regX)&0xff; addr = memory[zp] + (memory[zp+1]<<8); memStoreByte( addr, regA ); } function i84() { memStoreByte( popByte(), regY ); } function i85() { memStoreByte( popByte(), regA ); } function i86() { memStoreByte( popByte(), regX ); } function i88() { regY = (regY-1) & 0xff; if( regY ) regP &= 0xfd; else regP |= 0x02; if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i8a() { regA = regX & 0xff; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i8c() { memStoreByte( popWord(), regY ); } function i8d() { memStoreByte( popWord(), regA ); } function i8e() { memStoreByte( popWord(), regX ); } function i90() { offset = popByte(); if( ( regP & 1 ) == 0 ) jumpBranch( offset ); } function i91() { zp = popByte(); addr = memory[zp] + (memory[zp+1]<<8) + regY; memStoreByte( addr, regA ); } function i94() { memStoreByte( (popByte() + regX) & 0xff, regY ); } function i95() { memStoreByte( (popByte() + regX) & 0xff, regA ); } function i96() { memStoreByte( (popByte() + regY) & 0xff, regX ); } function i98() { regA = regY & 0xff; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function i99() { //--- STA a,Y; addr = popWord() + regY; memStoreByte( addr, regA ); } function i9a() { //--- TXS X -> S regSP = regX & 0xff; } function i9d() { addr = popWord(); memStoreByte( addr + regX, regA ); } function ia0() { //-- LDY #n regY = popByte(); if( regY ) regP &= 0xfd; else regP |= 0x02; if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ia1() { zp = (popByte()+regX)&0xff; addr = memory[zp] + (memory[zp+1]<<8); regA = memory[ addr ]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ia2() { regX = popByte(); if( regX ) regP &= 0xfd; else regP |= 0x02; if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ia4() { regY = memory[ popByte() ]; if( regY ) regP &= 0xfd; else regP |= 0x02; if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ia5() { regA = memory[ popByte() ]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ia6() { regX = memory[ popByte() ]; if( regX ) regP &= 0xfd; else regP |= 0x02; if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ia8() { regY = regA & 0xff; if( regY ) regP &= 0xfd; else regP |= 0x02; if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ia9() { //-- LDA; regA = popByte(); if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function iaa() { regX = regA & 0xff; if( regX ) regP &= 0xfd; else regP |= 0x02; if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function iac() { regY = memory[ popWord() ]; if( regY ) regP &= 0xfd; else regP |= 0x02; if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function iad() { regA = memory[ popWord() ]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function iae() { regX = memory[ popWord() ]; if( regX ) regP &= 0xfd; else regP |= 0x02; if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ib0() { offset = popByte(); if( regP & 1 ) jumpBranch( offset ); } function ib1() { zp = popByte(); addr = memory[zp] + (memory[zp+1]<<8) + regY; regA = memory[ addr ]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ib4() { regY = memory[ (popByte() + regX) & 0xff ]; if( regY ) regP &= 0xfd; else regP |= 0x02; if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ib5() { regA = memory[ (popByte() + regX) & 0xff ]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ib6() { //--LDX z,Y; addr = (popByte() + regY) & 0xff; regX = memory[ addr ]; if( regX ) regP &= 0xfd; else regP |= 0x02; if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ib8() { regP &= 0xbf; } function ib9() { //-- LDA a,Y; addr = popWord() + regY; regA = memory[ addr ]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function iba() { // TSX ; S -> X , flags N, Z regX = regSP & 0xff; if( regX ) regP &= 0xfd; else regP |= 0x02; if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ibc() { addr = popWord() + regX; regY = memory[ addr ]; if( regY ) regP &= 0xfd; else regP |= 0x02; if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ibd() { addr = popWord() + regX; regA = memory[ addr ]; if( regA ) regP &= 0xfd; else regP |= 0x02; if( regA & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ibe() { addr = popWord() + regY; regX = memory[ addr ]; if( regX ) regP &= 0xfd; else regP |= 0x02; if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ic0() { value = popByte(); doCompare( regY, value ); /* if( (regY+value) > 0xff ) regP |= 1; else regP &= 0xfe; ov = value; value = (regY-value); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; */ } function ic1() { zp = popByte(); addr = memory[zp] + (memory[zp+1]<<8) + regY; value = memory[ addr ]; doCompare( regA, value ); } function ic4() { value = memory[ popByte() ]; doCompare( regY, value ); } function ic5() { value = memory[ popByte() ]; doCompare( regA, value ); } function ic6() { zp = popByte(); value = memory[ zp ]; --value; memStoreByte( zp, value&0xff ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ic8() { regY = (regY + 1) & 0xff; if( regY ) regP &= 0xfd; else regP |= 0x02; if( regY & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ic9() { //-- CMP; value = popByte(); doCompare( regA, value ); } function ica() { regX = (regX-1) & 0xff; if( regX ) regP &= 0xfd; else regP |= 0x02; if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function icc() { value = memory[ popWord() ]; doCompare( regY, value ); } function icd() { value = memory[ popWord() ]; doCompare( regA, value ); } function ice() { addr = popWord(); value = memory[ addr ]; --value; value = value&0xff; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function id0() { offset = popByte(); if( (regP&2)==0 ) jumpBranch( offset ); } function id1() { zp = popByte(); addr = memory[zp] + (memory[zp+1]<<8) + regY; value = memory[ addr ]; doCompare( regA, value ); } function id5() { value = memory[ (popByte() + regX) & 0xff ]; doCompare( regA, value ); } function id6() { addr = (popByte() + regX) & 0xff; value = memory[ addr ]; --value; value = value&0xff; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function id8() { regP &= 0xf7; } function id9() { //-- CMP a,Y; addr = popWord() + regY; value = memory[ addr ]; doCompare( regA, value ); } function idd() { //-- CMP a,X; addr = popWord() + regX; value = memory[ addr ]; doCompare( regA, value ); } function ide() { // DEC a,X addr = popWord() + regX; value = memory[ addr ]; --value; value = value&0xff; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ie0() { value = popByte(); doCompare( regX, value ); } function ie1() { zp = (popByte() + regX) & 0xff; addr = memory[zp] + (memory[zp+1]<<8); value = memory[ addr ]; testSBC( value ); } function ie4() { value = memory[ popByte() ]; doCompare( regX, value ); } function ie5() { addr = popByte(); value = memory[ addr ]; testSBC( value ); } function ie6() { zp = popByte(); value = memory[ zp ]; ++value; value = (value)&0xff; memStoreByte( zp, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ie8() { regX = (regX + 1) & 0xff; if( regX ) regP &= 0xfd; else regP |= 0x02; if( regX & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function ie9() { // SBC value = popByte(); testSBC( value ); } function iea() { // NOP } function iec() { value = memory[ popWord() ]; doCompare( regX, value ); } function ied() { addr = popWord(); value = memory[ addr ]; testSBC( value ); } function iee() { addr = popWord(); value = memory[ addr ]; ++value; value = (value)&0xff; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function if0() { offset = popByte(); if( regP&2 ) jumpBranch( offset ); } function if1() { zp = popByte(); addr = memory[zp] + (memory[zp+1]<<8); value = memory[ addr + regY ]; testSBC( value ); } function if5() { addr = (popByte() + regX) & 0xff; value = memory[ addr ]; /* regP = (regP&0xfe)|(value&1); */ testSBC( value ); } function if6() { addr = (popByte() + regX) & 0xff; value = memory[ addr ]; ++value; value=value&0xff; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function if8() { regP |= 8; } function if9() { addr = popWord(); value = memory[ addr + regY ]; testSBC( value ); } function ifd() { addr = popWord(); value = memory[ addr + regX ]; testSBC( value ); } function ife() { addr = popWord() + regX; value = memory[ addr ]; ++value; value=value&0xff; memStoreByte( addr, value ); if( value ) regP &= 0xfd; else regP |= 0x02; if( value & 0x80 ) regP |= 0x80; else regP &= 0x7f; } function iff() { message( "HALT Executed! "); codeRunning = false; } function ierr() { /* message( "Address $" + addr2hex(regPC).toUpperCase() + " - unknown opcode: $" + num2hex(opcode).toUpperCase() ); message( "Executed as NOP" ); */ // codeRunning = false; return; } /* * updatePixelDisplay() - Updates the display at one pixel position * */ function updateDisplayPixel( addr ) { display[addr-0x200].background = palette[memory[addr] & 0x0f]; } /* * updateDisplayFull() - Simply redraws the entire display * according to memory * The colors are identical with the C64's palette. * */ function updateDisplayFull() { for( y=0; y<32; y++ ) { for( x=0; x<32; x++ ) { updateDisplayPixel( ((y<<5)+x) + 0x200 ); } } } /* ================ Disassembler subroutines =================== */ var addressingModes = [ null, 'Imm', 'ZP', 'ZPX', 'ZPY', 'ABS', 'ABSX', 'ABSY', 'IND', 'INDX', 'INDY', 'SNGL', 'BRA']; /* Это - просто ассоциативный массив, где ключ - это то, что до двоеточия, а значение - после двоеточия Он является "объектом" в JavaScript ниже происходит создание "объекта" и сразу же - указание его свойств. А можно var instr = new Object(); или instr = {}; после чего уже: instr.Imm = 2 или instr[Imm]=5; */ var instructionLength = { Imm: 2, ZP: 2, ZPX: 2, ZPY: 2, ABS: 3, ABSX: 3, ABSY: 3, IND: 3, INDX: 2, INDY: 2, SNGL: 1, BRA: 2 }; function getModeAndCode(byte) { var index; /* .filter(.. создаёт новый массив line, в который войдут только те элементы Mnemonics, для которых вызов function (line) возвратит true. */ var line = Mnemonics.filter( function (line) { var possibleIndex = line.indexOf(byte); if(possibleIndex > -1) { index = possibleIndex; return true; } } )[0]; if(!line) { //instruction not found return { opCode: 'DCB $' + num2hex(byte).toUpperCase() + "; - ???", mode: 'SNGL' }; } else { return { opCode: line[0], mode: addressingModes[index] }; } } function createInstruction(address) { var bytes = []; var opCode; var args = []; var mode; /* Если объявлена функция внутри другой функции, первая получает доступ к переменным и аргументам последней, объявленным как var */ function isAccumulatorInstruction() { var accumulatorBytes = [0x0a, 0x4a, 0x2a, 0x6a]; /* поиск подстроки - возвращает первый индекс, по которому данный элемент может быть найден в массиве или -1, если такого индекса */ if(accumulatorBytes.indexOf(bytes[0]) > -1) { return true; } } function isBranchInstruction() { /* .match(.. Выполняет поиск по строке с использованием регулярного выражения и возвращает массив, содержащий результаты поиска.*/ return opCode.match(/^B/) && !(opCode == 'BIT' || opCode == 'BRK'); } function formatArguments() { /* reverse() на месте обращает порядок следования элементов массива. Первый элемент массива становится последним */ var argsString = args.map(num2hex).reverse().join(''); if(isBranchInstruction()) { var destination = address + 2; if (args[0] > 0x7f) { destination -= 0x100 - args[0]; } else { destination += args[0]; } argsString = addr2hex(destination); } //-- end if(isBranch... if (argsString) { argsString = '$' + argsString; } if (mode == 'Imm') { argsString = '#' + argsString; } if (mode.match(/X$/)) { argsString += ',X'; } if (mode.match(/^IND/)) { argsString = '(' + argsString + ')'; } if (mode.match(/Y$/)) { argsString += ',Y'; } if (isAccumulatorInstruction()) { argsString = 'A'; } return argsString; } return { addByte: function (byte) { /* array.push( elem1, elem2, ... ) - будут добавлены в конец массива */ bytes.push(byte); }, setModeAndCode: function (modeAndCode) { opCode = modeAndCode.opCode; mode = modeAndCode.mode; }, addArg: function (arg) { /* array.push( elem1, elem2, ... ) - будут добавлены в конец массива */ args.push(arg); }, toString: function () { /* метод join объединяет элементы массива в строку с разделителем */ var bytesString = bytes.map(num2hex).join(' '); /* метод map проходит каждый элемент массива и вызывает функцию аргумента единожды для каждого элемента, передавая значение элемента как аргумент */ var padding = Array(11 - bytesString.length).join(' '); //-- пробелы return '$' + addr2hex(address).toUpperCase() + ' ' + bytesString.toUpperCase() + padding + opCode + ' ' + formatArguments(args).toUpperCase(); } }; } function disassemble( begAddr, lenCode ) { var startAddress = begAddr; var currentAddress = startAddress; var endAddress = startAddress + lenCode; var instructions = []; var length; var inst; var byte; var modeAndCode; while(currentAddress < endAddress) { // message( "Decompilling at $" + addr2hex(currentAddress).toUpperCase() ); inst = createInstruction(currentAddress); byte = memory[currentAddress]; inst.addByte(byte); modeAndCode = getModeAndCode(byte); length = instructionLength[modeAndCode.mode]; inst.setModeAndCode(modeAndCode); for(var i = 1; i < length; i++) { currentAddress++; byte = memory[currentAddress]; inst.addByte(byte); inst.addArg(byte); } //- end for instructions.push(inst); currentAddress++; } //- end while var html = 'Addr: HexDump Dissassembly
'; html += '------+----------+---------------
'; html += instructions.join('
'); openPopup( html, 'Disassembly' ); } /* * disassmCode() - programm or memory Disassembler. * Executed when button "Disassm" is pressed. */ function disassmCode() { document.getElementById( "disButton" ).value = "Wait..."; // 'Disassm' Button = 'Wait' document.getElementById( "disButton" ).disabled = true; // 'Disassm' disabled; if(memDisassm){ //-- Disassemble memory range //-- alert("Memory Disassember is not implemented yet..."); tempStr = document.getElementById( 'start' ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); var start = parseInt( tempStr, 16 ); tempStr = document.getElementById( 'length' ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); var length = parseInt( tempStr, 16 ); //-- Disassmble from start to start+length; message( "Disassembling from $" + addr2hex(start).toUpperCase() + "; length: " + length + " bytes;"); disassemble( start, length ); } else { //-- alert("Disassmber is not implemented yet..."); tempStr = document.getElementById( "RUNCode" ).value; tempStr = tempStr.replace( new RegExp( /^\$/ ), "" ); tempInt = parseInt( tempStr, 16 ); // get RUN addr from InputBOX; //-- Disassmble from tempInt to tempInt+codeLen; message( "Disassembling from $" + addr2hex(tempInt).toUpperCase() + "; length: " + codeLen + " bytes;"); disassemble( tempInt, codeLen ); } } /* =============================== THE END =====================================*/