mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2025-01-18 09:30:11 +00:00
added C preprocessor (mcpp); new 6502 disasm; fixed recompile
This commit is contained in:
parent
a82accf060
commit
7eae2e9274
528
src/disasm.js
528
src/disasm.js
@ -1,250 +1,292 @@
|
|||||||
|
|
||||||
var Disassembler6502 = function() {
|
var OPS_6502 = [
|
||||||
|
{mn:"BRK",am:"",nb:1,il:0,c1:7,c2:0}, // 00
|
||||||
|
{mn:"ORA",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // 01
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // 02
|
||||||
|
{mn:"SLO",am:"(aa,x)",nb:2,il:1,c1:8,c2:1}, // 03
|
||||||
|
{mn:"NOP",am:"aa",nb:2,il:1,c1:3,c2:0}, // 04
|
||||||
|
{mn:"ORA",am:"aa",nb:2,il:0,c1:3,c2:0}, // 05
|
||||||
|
{mn:"ASL",am:"aa",nb:2,il:0,c1:5,c2:0}, // 06
|
||||||
|
{mn:"SLO",am:"aa",nb:2,il:1,c1:5,c2:0}, // 07
|
||||||
|
{mn:"PHP",am:"",nb:1,il:0,c1:3,c2:0}, // 08
|
||||||
|
{mn:"ORA",am:"#aa",nb:2,il:0,c1:2,c2:0}, // 09
|
||||||
|
{mn:"ASL",am:"",nb:1,il:0,c1:2,c2:0}, // 0A
|
||||||
|
{mn:"ANC",am:"#aa",nb:2,il:1,c1:2,c2:0}, // 0B
|
||||||
|
{mn:"NOP",am:"AAAA",nb:3,il:1,c1:4,c2:0}, // 0C
|
||||||
|
{mn:"ORA",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // 0D
|
||||||
|
{mn:"ASL",am:"AAAA",nb:3,il:0,c1:6,c2:0}, // 0E
|
||||||
|
{mn:"SLO",am:"AAAA",nb:3,il:1,c1:6,c2:0}, // 0F
|
||||||
|
{mn:"BPL",am:"branch",nb:2,il:0,c1:2,c2:2}, // 10
|
||||||
|
{mn:"ORA",am:"(aa),y",nb:2,il:0,c1:5,c2:1}, // 11
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // 12
|
||||||
|
{mn:"SLO",am:"(aa),y",nb:2,il:1,c1:8,c2:1}, // 13
|
||||||
|
{mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0}, // 14
|
||||||
|
{mn:"ORA",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // 15
|
||||||
|
{mn:"ASL",am:"aa,x",nb:2,il:0,c1:6,c2:0}, // 16
|
||||||
|
{mn:"SLO",am:"aa,x",nb:2,il:1,c1:6,c2:1}, // 17
|
||||||
|
{mn:"CLC",am:"",nb:1,il:0,c1:2,c2:0}, // 18
|
||||||
|
{mn:"ORA",am:"AAAA,y",nb:3,il:0,c1:4,c2:1}, // 19
|
||||||
|
{mn:"NOP",am:"",nb:0,il:1,c1:0,c2:0}, // 1A
|
||||||
|
{mn:"SLO",am:"AAAA,y",nb:3,il:1,c1:7,c2:1}, // 1B
|
||||||
|
{mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:1}, // 1C
|
||||||
|
{mn:"ORA",am:"AAAA,x",nb:3,il:0,c1:4,c2:1}, // 1D
|
||||||
|
{mn:"ASL",am:"AAAA,x",nb:3,il:0,c1:7,c2:0}, // 1E
|
||||||
|
{mn:"SLO",am:"AAAA,x",nb:3,il:1,c1:7,c2:1}, // 1F
|
||||||
|
{mn:"JSR",am:"AAAA",nb:3,il:0,c1:6,c2:0}, // 20
|
||||||
|
{mn:"AND",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // 21
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // 22
|
||||||
|
{mn:"RLA",am:"(aa,x)",nb:2,il:1,c1:8,c2:1}, // 23
|
||||||
|
{mn:"BIT",am:"aa",nb:2,il:0,c1:3,c2:0}, // 24
|
||||||
|
{mn:"AND",am:"aa",nb:2,il:0,c1:3,c2:0}, // 25
|
||||||
|
{mn:"ROL",am:"aa",nb:2,il:0,c1:5,c2:0}, // 26
|
||||||
|
{mn:"RLA",am:"aa",nb:2,il:1,c1:5,c2:0}, // 27
|
||||||
|
{mn:"PLP",am:"",nb:1,il:0,c1:4,c2:0}, // 28
|
||||||
|
{mn:"AND",am:"#aa",nb:2,il:0,c1:2,c2:0}, // 29
|
||||||
|
{mn:"ROL",am:"",nb:1,il:0,c1:2,c2:0}, // 2A
|
||||||
|
{mn:"ANC",am:"#aa",nb:2,il:1,c1:2,c2:0}, // 2B
|
||||||
|
{mn:"BIT",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // 2C
|
||||||
|
{mn:"AND",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // 2D
|
||||||
|
{mn:"ROL",am:"AAAA",nb:3,il:0,c1:6,c2:0}, // 2E
|
||||||
|
{mn:"RLA",am:"AAAA",nb:3,il:1,c1:6,c2:0}, // 2F
|
||||||
|
{mn:"BMI",am:"branch",nb:2,il:0,c1:2,c2:2}, // 30
|
||||||
|
{mn:"AND",am:"(aa),y",nb:2,il:0,c1:5,c2:1}, // 31
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // 32
|
||||||
|
{mn:"RLA",am:"(aa),y",nb:2,il:1,c1:8,c2:1}, // 33
|
||||||
|
{mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0}, // 34
|
||||||
|
{mn:"AND",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // 35
|
||||||
|
{mn:"ROL",am:"aa,x",nb:2,il:0,c1:6,c2:0}, // 36
|
||||||
|
{mn:"RLA",am:"aa,x",nb:2,il:1,c1:6,c2:1}, // 37
|
||||||
|
{mn:"SEC",am:"",nb:1,il:0,c1:2,c2:0}, // 38
|
||||||
|
{mn:"AND",am:"AAAA,y",nb:3,il:0,c1:4,c2:1}, // 39
|
||||||
|
{mn:"NOP",am:"",nb:0,il:1,c1:0,c2:0}, // 3A
|
||||||
|
{mn:"RLA",am:"AAAA,y",nb:3,il:1,c1:7,c2:1}, // 3B
|
||||||
|
{mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:1}, // 3C
|
||||||
|
{mn:"AND",am:"AAAA,x",nb:3,il:0,c1:4,c2:1}, // 3D
|
||||||
|
{mn:"ROL",am:"AAAA,x",nb:3,il:0,c1:7,c2:0}, // 3E
|
||||||
|
{mn:"RLA",am:"AAAA,x",nb:3,il:1,c1:7,c2:1}, // 3F
|
||||||
|
{mn:"RTI",am:"",nb:1,il:0,c1:6,c2:0}, // 40
|
||||||
|
{mn:"EOR",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // 41
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // 42
|
||||||
|
{mn:"SRE",am:"(aa,x)",nb:2,il:1,c1:8,c2:1}, // 43
|
||||||
|
{mn:"NOP",am:"aa",nb:2,il:1,c1:3,c2:0}, // 44
|
||||||
|
{mn:"EOR",am:"aa",nb:2,il:0,c1:3,c2:0}, // 45
|
||||||
|
{mn:"LSR",am:"aa",nb:2,il:0,c1:5,c2:0}, // 46
|
||||||
|
{mn:"SRE",am:"aa",nb:2,il:1,c1:5,c2:0}, // 47
|
||||||
|
{mn:"PHA",am:"",nb:1,il:0,c1:3,c2:0}, // 48
|
||||||
|
{mn:"EOR",am:"#aa",nb:2,il:0,c1:2,c2:0}, // 49
|
||||||
|
{mn:"LSR",am:"",nb:1,il:0,c1:2,c2:0}, // 4A
|
||||||
|
{mn:"ASR",am:"#aa",nb:2,il:1,c1:2,c2:0}, // 4B
|
||||||
|
{mn:"JMP",am:"AAAA",nb:3,il:0,c1:3,c2:0}, // 4C
|
||||||
|
{mn:"EOR",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // 4D
|
||||||
|
{mn:"LSR",am:"AAAA",nb:3,il:0,c1:6,c2:0}, // 4E
|
||||||
|
{mn:"SRE",am:"AAAA",nb:3,il:1,c1:6,c2:0}, // 4F
|
||||||
|
{mn:"BVC",am:"branch",nb:2,il:0,c1:2,c2:2}, // 50
|
||||||
|
{mn:"EOR",am:"(aa),y",nb:2,il:0,c1:5,c2:1}, // 51
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // 52
|
||||||
|
{mn:"SRE",am:"(aa),y",nb:2,il:1,c1:8,c2:1}, // 53
|
||||||
|
{mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0}, // 54
|
||||||
|
{mn:"EOR",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // 55
|
||||||
|
{mn:"LSR",am:"aa,x",nb:2,il:0,c1:6,c2:0}, // 56
|
||||||
|
{mn:"SRE",am:"aa,x",nb:2,il:1,c1:6,c2:1}, // 57
|
||||||
|
{mn:"CLI",am:"",nb:1,il:0,c1:2,c2:0}, // 58
|
||||||
|
{mn:"EOR",am:"AAAA,y",nb:3,il:0,c1:4,c2:1}, // 59
|
||||||
|
{mn:"NOP",am:"",nb:0,il:1,c1:0,c2:0}, // 5A
|
||||||
|
{mn:"SRE",am:"AAAA,y",nb:3,il:1,c1:7,c2:1}, // 5B
|
||||||
|
{mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:1}, // 5C
|
||||||
|
{mn:"EOR",am:"AAAA,x",nb:3,il:0,c1:4,c2:1}, // 5D
|
||||||
|
{mn:"LSR",am:"AAAA,x",nb:3,il:0,c1:7,c2:0}, // 5E
|
||||||
|
{mn:"SRE",am:"AAAA,x",nb:3,il:1,c1:7,c2:1}, // 5F
|
||||||
|
{mn:"RTS",am:"",nb:1,il:0,c1:6,c2:0}, // 60
|
||||||
|
{mn:"ADC",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // 61
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // 62
|
||||||
|
{mn:"RRA",am:"(aa,x)",nb:2,il:1,c1:8,c2:1}, // 63
|
||||||
|
{mn:"NOP",am:"aa",nb:2,il:1,c1:3,c2:0}, // 64
|
||||||
|
{mn:"ADC",am:"aa",nb:2,il:0,c1:3,c2:0}, // 65
|
||||||
|
{mn:"ROR",am:"aa",nb:2,il:0,c1:5,c2:0}, // 66
|
||||||
|
{mn:"RRA",am:"aa",nb:2,il:1,c1:5,c2:0}, // 67
|
||||||
|
{mn:"PLA",am:"",nb:1,il:0,c1:4,c2:0}, // 68
|
||||||
|
{mn:"ADC",am:"#aa",nb:2,il:0,c1:2,c2:0}, // 69
|
||||||
|
{mn:"ROR",am:"",nb:1,il:0,c1:2,c2:0}, // 6A
|
||||||
|
{mn:"ARR",am:"#aa",nb:2,il:1,c1:2,c2:0}, // 6B
|
||||||
|
{mn:"JMP",am:"(AAAA)",nb:3,il:0,c1:5,c2:0}, // 6C
|
||||||
|
{mn:"ADC",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // 6D
|
||||||
|
{mn:"ROR",am:"AAAA",nb:3,il:0,c1:6,c2:0}, // 6E
|
||||||
|
{mn:"RRA",am:"AAAA",nb:3,il:1,c1:6,c2:0}, // 6F
|
||||||
|
{mn:"BVS",am:"branch",nb:2,il:0,c1:2,c2:2}, // 70
|
||||||
|
{mn:"ADC",am:"(aa),y",nb:2,il:0,c1:5,c2:1}, // 71
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // 72
|
||||||
|
{mn:"RRA",am:"(aa),y",nb:2,il:1,c1:8,c2:1}, // 73
|
||||||
|
{mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0}, // 74
|
||||||
|
{mn:"ADC",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // 75
|
||||||
|
{mn:"ROR",am:"aa,x",nb:2,il:0,c1:6,c2:0}, // 76
|
||||||
|
{mn:"RRA",am:"aa,x",nb:2,il:1,c1:6,c2:1}, // 77
|
||||||
|
{mn:"SEI",am:"",nb:1,il:0,c1:2,c2:0}, // 78
|
||||||
|
{mn:"ADC",am:"AAAA,y",nb:3,il:0,c1:4,c2:1}, // 79
|
||||||
|
{mn:"NOP",am:"",nb:0,il:1,c1:0,c2:0}, // 7A
|
||||||
|
{mn:"RRA",am:"AAAA,y",nb:3,il:1,c1:7,c2:1}, // 7B
|
||||||
|
{mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:1}, // 7C
|
||||||
|
{mn:"ADC",am:"AAAA,x",nb:3,il:0,c1:4,c2:1}, // 7D
|
||||||
|
{mn:"ROR",am:"AAAA,x",nb:3,il:0,c1:7,c2:0}, // 7E
|
||||||
|
{mn:"RRA",am:"AAAA,x",nb:3,il:1,c1:7,c2:1}, // 7F
|
||||||
|
{mn:"NOP",am:"#aa",nb:0,il:1,c1:0,c2:0}, // 80
|
||||||
|
{mn:"STA",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // 81
|
||||||
|
{mn:"NOP",am:"#aa",nb:0,il:1,c1:0,c2:0}, // 82
|
||||||
|
{mn:"SAX",am:"(aa,x)",nb:2,il:1,c1:6,c2:1}, // 83
|
||||||
|
{mn:"STY",am:"aa",nb:2,il:0,c1:3,c2:0}, // 84
|
||||||
|
{mn:"STA",am:"aa",nb:2,il:0,c1:3,c2:0}, // 85
|
||||||
|
{mn:"STX",am:"aa",nb:2,il:0,c1:3,c2:0}, // 86
|
||||||
|
{mn:"SAX",am:"aa",nb:2,il:1,c1:3,c2:0}, // 87
|
||||||
|
{mn:"DEY",am:"",nb:1,il:0,c1:2,c2:0}, // 88
|
||||||
|
{mn:"NOP",am:"#aa",nb:0,il:1,c1:0,c2:0}, // 89
|
||||||
|
{mn:"TXA",am:"",nb:1,il:0,c1:2,c2:0}, // 8A
|
||||||
|
{mn:"ANE",am:"#aa",nb:0,il:1,c1:0,c2:0}, // 8B
|
||||||
|
{mn:"STY",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // 8C
|
||||||
|
{mn:"STA",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // 8D
|
||||||
|
{mn:"STX",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // 8E
|
||||||
|
{mn:"SAX",am:"AAAA",nb:3,il:1,c1:4,c2:0}, // 8F
|
||||||
|
{mn:"BCC",am:"branch",nb:2,il:0,c1:2,c2:2}, // 90
|
||||||
|
{mn:"STA",am:"(aa),y",nb:2,il:0,c1:6,c2:0}, // 91
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // 92
|
||||||
|
{mn:"SHA",am:"(aa),y",nb:0,il:1,c1:0,c2:0}, // 93
|
||||||
|
{mn:"STY",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // 94
|
||||||
|
{mn:"STA",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // 95
|
||||||
|
{mn:"STX",am:"aa,y",nb:2,il:0,c1:4,c2:0}, // 96
|
||||||
|
{mn:"SAX",am:"aa,y",nb:3,il:1,c1:4,c2:1}, // 97
|
||||||
|
{mn:"TYA",am:"",nb:1,il:0,c1:2,c2:0}, // 98
|
||||||
|
{mn:"STA",am:"AAAA,y",nb:3,il:0,c1:5,c2:0}, // 99
|
||||||
|
{mn:"TXS",am:"",nb:1,il:0,c1:2,c2:0}, // 9A
|
||||||
|
{mn:"SHS",am:"AAAA,y",nb:0,il:1,c1:0,c2:0}, // 9B
|
||||||
|
{mn:"SHY",am:"AAAA,x",nb:0,il:1,c1:0,c2:0}, // 9C
|
||||||
|
{mn:"STA",am:"AAAA,x",nb:3,il:0,c1:5,c2:0}, // 9D
|
||||||
|
{mn:"SHX",am:"AAAA,y",nb:0,il:1,c1:0,c2:0}, // 9E
|
||||||
|
{mn:"SHA",am:"AAAA,y",nb:0,il:1,c1:0,c2:0}, // 9F
|
||||||
|
{mn:"LDY",am:"#aa",nb:2,il:0,c1:2,c2:0}, // A0
|
||||||
|
{mn:"LDA",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // A1
|
||||||
|
{mn:"LDX",am:"#aa",nb:2,il:0,c1:2,c2:0}, // A2
|
||||||
|
{mn:"LAX",am:"(aa,x)",nb:2,il:1,c1:6,c2:1}, // A3
|
||||||
|
{mn:"LDY",am:"aa",nb:2,il:0,c1:3,c2:0}, // A4
|
||||||
|
{mn:"LDA",am:"aa",nb:2,il:0,c1:3,c2:0}, // A5
|
||||||
|
{mn:"LDX",am:"aa",nb:2,il:0,c1:3,c2:0}, // A6
|
||||||
|
{mn:"LAX",am:"aa",nb:2,il:1,c1:3,c2:0}, // A7
|
||||||
|
{mn:"TAY",am:"",nb:1,il:0,c1:2,c2:0}, // A8
|
||||||
|
{mn:"LDA",am:"#aa",nb:2,il:0,c1:2,c2:0}, // A9
|
||||||
|
{mn:"TAX",am:"",nb:1,il:0,c1:2,c2:0}, // AA
|
||||||
|
{mn:"LXA",am:"#aa",nb:0,il:1,c1:0,c2:0}, // AB
|
||||||
|
{mn:"LDY",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // AC
|
||||||
|
{mn:"LDA",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // AD
|
||||||
|
{mn:"LDX",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // AE
|
||||||
|
{mn:"LAX",am:"AAAA",nb:3,il:1,c1:4,c2:0}, // AF
|
||||||
|
{mn:"BCS",am:"branch",nb:2,il:0,c1:2,c2:2}, // B0
|
||||||
|
{mn:"LDA",am:"(aa),y",nb:2,il:0,c1:5,c2:1}, // B1
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // B2
|
||||||
|
{mn:"LAX",am:"(aa),y",nb:2,il:1,c1:5,c2:1}, // B3
|
||||||
|
{mn:"LDY",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // B4
|
||||||
|
{mn:"LDA",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // B5
|
||||||
|
{mn:"LDX",am:"aa,y",nb:2,il:0,c1:4,c2:0}, // B6
|
||||||
|
{mn:"LAX",am:"aa,y",nb:2,il:1,c1:4,c2:1}, // B7
|
||||||
|
{mn:"CLV",am:"",nb:1,il:0,c1:2,c2:0}, // B8
|
||||||
|
{mn:"LDA",am:"AAAA,y",nb:3,il:0,c1:4,c2:1}, // B9
|
||||||
|
{mn:"TSX",am:"",nb:1,il:0,c1:2,c2:0}, // BA
|
||||||
|
{mn:"LAS",am:"AAAA,y",nb:0,il:1,c1:0,c2:0}, // BB
|
||||||
|
{mn:"LDY",am:"AAAA,x",nb:3,il:0,c1:4,c2:1}, // BC
|
||||||
|
{mn:"LDA",am:"AAAA,x",nb:3,il:0,c1:4,c2:1}, // BD
|
||||||
|
{mn:"LDX",am:"AAAA,y",nb:3,il:0,c1:4,c2:1}, // BE
|
||||||
|
{mn:"LAX",am:"AAAA,y",nb:3,il:1,c1:4,c2:1}, // BF
|
||||||
|
{mn:"CPY",am:"#aa",nb:2,il:0,c1:2,c2:0}, // C0
|
||||||
|
{mn:"CMP",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // C1
|
||||||
|
{mn:"NOP",am:"#aa",nb:0,il:1,c1:0,c2:0}, // C2
|
||||||
|
{mn:"DCP",am:"(aa,x)",nb:2,il:1,c1:8,c2:1}, // C3
|
||||||
|
{mn:"CPY",am:"aa",nb:2,il:0,c1:3,c2:0}, // C4
|
||||||
|
{mn:"CMP",am:"aa",nb:2,il:0,c1:3,c2:0}, // C5
|
||||||
|
{mn:"DEC",am:"aa",nb:2,il:0,c1:5,c2:0}, // C6
|
||||||
|
{mn:"DCP",am:"aa",nb:2,il:1,c1:5,c2:0}, // C7
|
||||||
|
{mn:"INY",am:"",nb:1,il:0,c1:2,c2:0}, // C8
|
||||||
|
{mn:"CMP",am:"#aa",nb:2,il:0,c1:2,c2:0}, // C9
|
||||||
|
{mn:"DEX",am:"",nb:1,il:0,c1:2,c2:0}, // CA
|
||||||
|
{mn:"SBX",am:"#aa",nb:2,il:1,c1:2,c2:0}, // CB
|
||||||
|
{mn:"CPY",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // CC
|
||||||
|
{mn:"CMP",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // CD
|
||||||
|
{mn:"DEC",am:"AAAA",nb:3,il:0,c1:3,c2:0}, // CE
|
||||||
|
{mn:"DCP",am:"AAAA",nb:3,il:1,c1:6,c2:0}, // CF
|
||||||
|
{mn:"BNE",am:"branch",nb:2,il:0,c1:2,c2:2}, // D0
|
||||||
|
{mn:"CMP",am:"(aa),y",nb:2,il:0,c1:5,c2:1}, // D1
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // D2
|
||||||
|
{mn:"DCP",am:"(aa),y",nb:2,il:1,c1:8,c2:1}, // D3
|
||||||
|
{mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0}, // D4
|
||||||
|
{mn:"CMP",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // D5
|
||||||
|
{mn:"DEC",am:"aa,x",nb:2,il:0,c1:6,c2:0}, // D6
|
||||||
|
{mn:"DCP",am:"aa,x",nb:2,il:1,c1:6,c2:1}, // D7
|
||||||
|
{mn:"CLD",am:"",nb:1,il:0,c1:2,c2:0}, // D8
|
||||||
|
{mn:"CMP",am:"AAAA,y",nb:3,il:0,c1:4,c2:1}, // D9
|
||||||
|
{mn:"NOP",am:"",nb:0,il:1,c1:0,c2:0}, // DA
|
||||||
|
{mn:"DCP",am:"AAAA,y",nb:3,il:1,c1:7,c2:1}, // DB
|
||||||
|
{mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:1}, // DC
|
||||||
|
{mn:"CMP",am:"AAAA,x",nb:3,il:0,c1:4,c2:1}, // DD
|
||||||
|
{mn:"DEC",am:"AAAA,x",nb:3,il:0,c1:7,c2:0}, // DE
|
||||||
|
{mn:"DCP",am:"AAAA,x",nb:3,il:1,c1:7,c2:1}, // DF
|
||||||
|
{mn:"CPX",am:"#aa",nb:2,il:0,c1:2,c2:0}, // E0
|
||||||
|
{mn:"SBC",am:"(aa,x)",nb:2,il:0,c1:6,c2:0}, // E1
|
||||||
|
{mn:"NOP",am:"#aa",nb:0,il:1,c1:0,c2:0}, // E2
|
||||||
|
{mn:"ISB",am:"(aa,x)",nb:2,il:1,c1:8,c2:1}, // E3
|
||||||
|
{mn:"CPX",am:"aa",nb:2,il:0,c1:3,c2:0}, // E4
|
||||||
|
{mn:"SBC",am:"aa",nb:2,il:0,c1:3,c2:0}, // E5
|
||||||
|
{mn:"INC",am:"aa",nb:2,il:0,c1:5,c2:0}, // E6
|
||||||
|
{mn:"ISB",am:"aa",nb:2,il:1,c1:5,c2:0}, // E7
|
||||||
|
{mn:"INX",am:"",nb:1,il:0,c1:2,c2:0}, // E8
|
||||||
|
{mn:"SBC",am:"#aa",nb:2,il:0,c1:2,c2:0}, // E9
|
||||||
|
{mn:"NOP",am:"",nb:1,il:0,c1:2,c2:0}, // EA
|
||||||
|
{mn:"SBC",am:"#aa",nb:0,il:1,c1:0,c2:0}, // EB
|
||||||
|
{mn:"CPX",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // EC
|
||||||
|
{mn:"SBC",am:"AAAA",nb:3,il:0,c1:4,c2:0}, // ED
|
||||||
|
{mn:"INC",am:"AAAA",nb:3,il:0,c1:6,c2:0}, // EE
|
||||||
|
{mn:"ISB",am:"AAAA",nb:3,il:1,c1:6,c2:0}, // EF
|
||||||
|
{mn:"BEQ",am:"branch",nb:2,il:0,c1:2,c2:2}, // F0
|
||||||
|
{mn:"SBC",am:"(aa),y",nb:2,il:0,c1:5,c2:1}, // F1
|
||||||
|
{mn:"KIL",am:"",nb:0,il:1,c1:0,c2:0}, // F2
|
||||||
|
{mn:"ISB",am:"(aa),y",nb:2,il:1,c1:8,c2:1}, // F3
|
||||||
|
{mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0}, // F4
|
||||||
|
{mn:"SBC",am:"aa,x",nb:2,il:0,c1:4,c2:0}, // F5
|
||||||
|
{mn:"INC",am:"aa,x",nb:2,il:0,c1:6,c2:0}, // F6
|
||||||
|
{mn:"ISB",am:"aa,x",nb:2,il:1,c1:6,c2:1}, // F7
|
||||||
|
{mn:"SED",am:"",nb:1,il:0,c1:2,c2:0}, // F8
|
||||||
|
{mn:"SBC",am:"AAAA,y",nb:3,il:0,c1:4,c2:1}, // F9
|
||||||
|
{mn:"NOP",am:"",nb:0,il:1,c1:0,c2:0}, // FA
|
||||||
|
{mn:"ISB",am:"AAAA,y",nb:3,il:1,c1:7,c2:1}, // FB
|
||||||
|
{mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:1}, // FC
|
||||||
|
{mn:"SBC",am:"AAAA,x",nb:3,il:0,c1:4,c2:1}, // FD
|
||||||
|
{mn:"INC",am:"AAAA,x",nb:3,il:0,c1:7,c2:0}, // FE
|
||||||
|
{mn:"ISB",am:"AAAA,x",nb:3,il:1,c1:7,c2:1}, // FF
|
||||||
|
];
|
||||||
|
|
||||||
this.disassemble = function(mem, start, end, ips) {
|
function disassemble6502(pc, b0, b1, b2) {
|
||||||
var i;
|
|
||||||
var lines = [];
|
|
||||||
function print_func(s) {
|
|
||||||
lines[i] = s;
|
|
||||||
}
|
|
||||||
for (i = start; i < end;) {
|
|
||||||
var opcode = OPS[mem[i]];
|
|
||||||
if (!opcode) {
|
|
||||||
print_func("#" + formatHex(mem[i], 2));
|
|
||||||
i += 1;
|
|
||||||
} else {
|
|
||||||
var bytes = opcode.bytes;
|
|
||||||
var args = mem.slice(i+1, i+1+bytes);
|
|
||||||
//console.log(opcode, bytes, args);
|
|
||||||
print_func(opcode.toString.call(opcode, args));
|
|
||||||
i += bytes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
};
|
|
||||||
|
|
||||||
function formatHex(number, len) {
|
function formatHex(number, len) {
|
||||||
if (typeof number === "undefined" || number === null || isNaN(number)) {
|
if (typeof number === "undefined" || number === null || isNaN(number)) {
|
||||||
throw new Error("Invalid value \"" + number + "\" passed to formatHex()");
|
throw new Error("Invalid value \"" + number + "\" passed to formatHex()");
|
||||||
}
|
|
||||||
var str = number.toString(16).toUpperCase();
|
|
||||||
if (!len) {
|
|
||||||
if (str.length % 2 == 1) {
|
|
||||||
len = str.length+1;
|
|
||||||
}
|
}
|
||||||
|
var str = number.toString(16).toUpperCase();
|
||||||
|
if (!len) {
|
||||||
|
if (str.length % 2 == 1) {
|
||||||
|
len = str.length+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (str.length < len) {
|
||||||
|
str = "0" + str;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
while (str.length < len) {
|
|
||||||
str = "0" + str;
|
|
||||||
|
var op = OPS_6502[b0];
|
||||||
|
var s = op.mn;
|
||||||
|
var am = op.am;
|
||||||
|
if (am == 'branch') {
|
||||||
|
var offset = (b1 < 0x80) ? (pc+b1) : (pc-(256-b1));
|
||||||
|
offset &= 0xffff;
|
||||||
|
am = '$'+formatHex(offset, 4);
|
||||||
|
} else {
|
||||||
|
am = am.replace('aa','$'+formatHex(b1, 2));
|
||||||
|
am = am.replace('AAAA','$'+formatHex(b1+(b2<<8), 4));
|
||||||
}
|
}
|
||||||
return str;
|
return {line:op.mn + " " + am, nbytes:op.nb};
|
||||||
}
|
|
||||||
|
|
||||||
function formatImmediate (args) {
|
|
||||||
return this.name + " #$" + formatHex(args[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatZeroPage (args) {
|
|
||||||
return this.name + " $" + formatHex(args[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatZeroPageIndexedX (args) {
|
|
||||||
return formatZeroPage.call(this, args) + ",X";
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatZeroPageIndexedY (args) {
|
|
||||||
return formatZeroPage.call(this, args) + ",Y";
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatAbsolute (args) {
|
|
||||||
return this.name + " $" + formatHex(args[1], 2) + formatHex(args[0], 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatAbsoluteIndexedX (args) {
|
|
||||||
return formatAbsolute.call(this, args) + ",X";
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatAbsoluteIndexedY (args) {
|
|
||||||
return formatAbsolute.call(this, args) + ",Y";
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatIndirect (args) {
|
|
||||||
return this.name + " ($" + formatHex(args[1], 2) + formatHex(args[0], 2) + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatIndirectIndexedX (args) {
|
|
||||||
return this.name + " ($" + formatHex(args[0], 2) + ",X)";
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatIndirectIndexedY (args) {
|
|
||||||
return this.name + " ($" + formatHex(args[0], 2) + "),Y";
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatRelative (args) {
|
|
||||||
return this.name + " $" + formatHex(args[0], 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatAccumulator (args) {
|
|
||||||
return this.name + " A";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var OPS = {
|
|
||||||
0xA0 : { name: "LDY", bytes: 2, toString: formatImmediate },
|
|
||||||
0xA4 : { name: "LDY", bytes: 2, toString: formatZeroPage },
|
|
||||||
0xB4 : { name: "LDY", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0xAC : { name: "LDY", bytes: 3, toString: formatAbsolute },
|
|
||||||
0xBC : { name: "LDY", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0xA2 : { name: "LDX", bytes: 2, toString: formatImmediate },
|
|
||||||
0xA6 : { name: "LDX", bytes: 2, toString: formatZeroPage },
|
|
||||||
0xB6 : { name: "LDX", bytes: 2, toString: formatZeroPageIndexedY },
|
|
||||||
0xAE : { name: "LDX", bytes: 3, toString: formatAbsolute },
|
|
||||||
0xBE : { name: "LDX", bytes: 3, toString: formatAbsoluteIndexedY },
|
|
||||||
0xA9 : { name: "LDA", bytes: 2, toString: formatImmediate },
|
|
||||||
0xA5 : { name: "LDA", bytes: 2, toString: formatZeroPage },
|
|
||||||
0xB5 : { name: "LDA", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0xAD : { name: "LDA", bytes: 3, toString: formatAbsolute },
|
|
||||||
0xBD : { name: "LDA", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0xB9 : { name: "LDA", bytes: 3, toString: formatAbsoluteIndexedY },
|
|
||||||
0xA1 : { name: "LDA", bytes: 2, toString: formatIndirectIndexedX },
|
|
||||||
0xB1 : { name: "LDA", bytes: 2, toString: formatIndirectIndexedY },
|
|
||||||
0x86 : { name: "STX", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x96 : { name: "STX", bytes: 2, toString: formatZeroPageIndexedY },
|
|
||||||
0x8E : { name: "STX", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x84 : { name: "STY", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x94 : { name: "STY", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x8C : { name: "STY", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x85 : { name: "STA", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x95 : { name: "STA", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x8D : { name: "STA", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x9D : { name: "STA", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0x99 : { name: "STA", bytes: 3, toString: formatAbsoluteIndexedY },
|
|
||||||
0x81 : { name: "STA", bytes: 2, toString: formatIndirectIndexedX },
|
|
||||||
0x91 : { name: "STA", bytes: 2, toString: formatIndirectIndexedY },
|
|
||||||
0xE8 : { name: "INX", bytes: 1, toString: formatName },
|
|
||||||
0xC8 : { name: "INY", bytes: 1, toString: formatName },
|
|
||||||
0xCA : { name: "DEX", bytes: 1, toString: formatName },
|
|
||||||
0x88 : { name: "DEY", bytes: 1, toString: formatName },
|
|
||||||
0xE6 : { name: "INC", bytes: 2, toString: formatZeroPage },
|
|
||||||
0xF6 : { name: "INC", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0xEE : { name: "INC", bytes: 3, toString: formatAbsolute },
|
|
||||||
0xFE : { name: "INC", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0xC6 : { name: "DEC", bytes: 2, toString: formatZeroPage },
|
|
||||||
0xD6 : { name: "DEC", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0xCE : { name: "DEC", bytes: 3, toString: formatAbsolute },
|
|
||||||
0xDE : { name: "DEC", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0x38 : { name: "SEC", bytes: 1, toString: formatName },
|
|
||||||
0xF8 : { name: "SED", bytes: 1, toString: formatName },
|
|
||||||
0x78 : { name: "SEI", bytes: 1, toString: formatName },
|
|
||||||
0x18 : { name: "CLC", bytes: 1, toString: formatName },
|
|
||||||
0xD8 : { name: "CLD", bytes: 1, toString: formatName },
|
|
||||||
0x58 : { name: "CLI", bytes: 1, toString: formatName },
|
|
||||||
0xB8 : { name: "CLV", bytes: 1, toString: formatName },
|
|
||||||
0xAA : { name: "TAX", bytes: 1, toString: formatName },
|
|
||||||
0x8A : { name: "TXA", bytes: 1, toString: formatName },
|
|
||||||
0xA8 : { name: "TAY", bytes: 1, toString: formatName },
|
|
||||||
0x98 : { name: "TYA", bytes: 1, toString: formatName },
|
|
||||||
0xBA : { name: "TSX", bytes: 1, toString: formatName },
|
|
||||||
0x9A : { name: "TXS", bytes: 1, toString: formatName },
|
|
||||||
0x48 : { name: "PHA", bytes: 1, toString: formatName },
|
|
||||||
0x08 : { name: "PHP", bytes: 1, toString: formatName },
|
|
||||||
0x68 : { name: "PLA", bytes: 1, toString: formatName },
|
|
||||||
0x28 : { name: "PLP", bytes: 1, toString: formatName },
|
|
||||||
0x29 : { name: "AND", bytes: 2, toString: formatImmediate },
|
|
||||||
0x25 : { name: "AND", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x35 : { name: "AND", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x2D : { name: "AND", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x3D : { name: "AND", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0x39 : { name: "AND", bytes: 3, toString: formatAbsoluteIndexedY },
|
|
||||||
0x21 : { name: "AND", bytes: 2, toString: formatIndirectIndexedX },
|
|
||||||
0x31 : { name: "AND", bytes: 2, toString: formatIndirectIndexedY },
|
|
||||||
0x09 : { name: "ORA", bytes: 2, toString: formatImmediate },
|
|
||||||
0x05 : { name: "ORA", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x15 : { name: "ORA", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x0D : { name: "ORA", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x1D : { name: "ORA", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0x19 : { name: "ORA", bytes: 3, toString: formatAbsoluteIndexedY },
|
|
||||||
0x01 : { name: "ORA", bytes: 2, toString: formatIndirectIndexedX },
|
|
||||||
0x11 : { name: "ORA", bytes: 2, toString: formatIndirectIndexedY },
|
|
||||||
0x49 : { name: "EOR", bytes: 2, toString: formatImmediate },
|
|
||||||
0x45 : { name: "EOR", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x55 : { name: "EOR", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x4D : { name: "EOR", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x5D : { name: "EOR", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0x59 : { name: "EOR", bytes: 3, toString: formatAbsoluteIndexedY },
|
|
||||||
0x41 : { name: "EOR", bytes: 2, toString: formatIndirectIndexedX },
|
|
||||||
0x51 : { name: "EOR", bytes: 2, toString: formatIndirectIndexedY },
|
|
||||||
0x4C : { name: "JMP", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x6C : { name: "JMP", bytes: 3, toString: formatIndirect },
|
|
||||||
0x20 : { name: "JSR", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x60 : { name: "RTS", bytes: 1, toString: formatName },
|
|
||||||
0x40 : { name: "RTI", bytes: 1, toString: formatName },
|
|
||||||
0x90 : { name: "BCC", bytes: 2, toString: formatRelative },
|
|
||||||
0xB0 : { name: "BCS", bytes: 2, toString: formatRelative },
|
|
||||||
0xF0 : { name: "BEQ", bytes: 2, toString: formatRelative },
|
|
||||||
0xD0 : { name: "BNE", bytes: 2, toString: formatRelative },
|
|
||||||
0x10 : { name: "BPL", bytes: 2, toString: formatRelative },
|
|
||||||
0x30 : { name: "BMI", bytes: 2, toString: formatRelative },
|
|
||||||
0x50 : { name: "BVC", bytes: 2, toString: formatRelative },
|
|
||||||
0x70 : { name: "BVS", bytes: 2, toString: formatRelative },
|
|
||||||
0x2A : { name: "ROL", bytes: 1, toString: formatAccumulator },
|
|
||||||
0x26 : { name: "ROL", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x36 : { name: "ROL", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x2E : { name: "ROL", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x3E : { name: "ROL", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0x6A : { name: "ROR", bytes: 1, toString: formatAccumulator },
|
|
||||||
0x66 : { name: "ROR", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x76 : { name: "ROR", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x6E : { name: "ROR", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x7E : { name: "ROR", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0x4A : { name: "LSR", bytes: 1, toString: formatAccumulator },
|
|
||||||
0x46 : { name: "LSR", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x56 : { name: "LSR", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x4E : { name: "LSR", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x5E : { name: "LSR", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0x0A : { name: "ASL", bytes: 1, toString: formatAccumulator },
|
|
||||||
0x06 : { name: "ASL", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x16 : { name: "ASL", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x0E : { name: "ASL", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x1E : { name: "ASL", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0xC9 : { name: "CMP", bytes: 2, toString: formatImmediate },
|
|
||||||
0xC5 : { name: "CMP", bytes: 2, toString: formatZeroPage },
|
|
||||||
0xD5 : { name: "CMP", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0xCD : { name: "CMP", bytes: 3, toString: formatAbsolute },
|
|
||||||
0xDD : { name: "CMP", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0xD9 : { name: "CMP", bytes: 3, toString: formatAbsoluteIndexedY },
|
|
||||||
0xC1 : { name: "CMP", bytes: 2, toString: formatIndirectIndexedX },
|
|
||||||
0xD1 : { name: "CMP", bytes: 2, toString: formatIndirectIndexedY },
|
|
||||||
0xE0 : { name: "CPX", bytes: 2, toString: formatImmediate },
|
|
||||||
0xE4 : { name: "CPX", bytes: 2, toString: formatZeroPage },
|
|
||||||
0xEC : { name: "CPX", bytes: 3, toString: formatAbsolute },
|
|
||||||
0xC0 : { name: "CPY", bytes: 2, toString: formatImmediate },
|
|
||||||
0xC4 : { name: "CPY", bytes: 2, toString: formatZeroPage },
|
|
||||||
0xCC : { name: "CPY", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x24 : { name: "BIT", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x2C : { name: "BIT", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x69 : { name: "ADC", bytes: 2, toString: formatImmediate },
|
|
||||||
0x65 : { name: "ADC", bytes: 2, toString: formatZeroPage },
|
|
||||||
0x75 : { name: "ADC", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0x6D : { name: "ADC", bytes: 3, toString: formatAbsolute },
|
|
||||||
0x7D : { name: "ADC", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0x79 : { name: "ADC", bytes: 3, toString: formatAbsoluteIndexedY },
|
|
||||||
0x61 : { name: "ADC", bytes: 2, toString: formatIndirectIndexedX },
|
|
||||||
0x71 : { name: "ADC", bytes: 2, toString: formatIndirectIndexedY },
|
|
||||||
0xE9 : { name: "SBC", bytes: 2, toString: formatImmediate },
|
|
||||||
0xE5 : { name: "SBC", bytes: 2, toString: formatZeroPage },
|
|
||||||
0xF5 : { name: "SBC", bytes: 2, toString: formatZeroPageIndexedX },
|
|
||||||
0xED : { name: "SBC", bytes: 3, toString: formatAbsolute },
|
|
||||||
0xFD : { name: "SBC", bytes: 3, toString: formatAbsoluteIndexedX },
|
|
||||||
0xF9 : { name: "SBC", bytes: 3, toString: formatAbsoluteIndexedY },
|
|
||||||
0xE1 : { name: "SBC", bytes: 2, toString: formatIndirectIndexedX },
|
|
||||||
0xF1 : { name: "SBC", bytes: 2, toString: formatIndirectIndexedY },
|
|
||||||
0xEA : { name: "NOP", bytes: 1, toString: formatName },
|
|
||||||
0x00 : { name: "BRK", bytes: 1, toString: formatName },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -19,7 +19,7 @@ function __createCanvas(mainElement, width, height) {
|
|||||||
var canvas = document.createElement('canvas');
|
var canvas = document.createElement('canvas');
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
canvas.height = height;
|
canvas.height = height;
|
||||||
canvas.style.class = "emuvideo";
|
canvas.style['class'] = "emuvideo";
|
||||||
canvas.style.width = "100%";
|
canvas.style.width = "100%";
|
||||||
canvas.style.height = "100%";
|
canvas.style.height = "100%";
|
||||||
canvas.tabIndex = "-1"; // Make it focusable
|
canvas.tabIndex = "-1"; // Make it focusable
|
||||||
@ -463,8 +463,8 @@ var Base6502Platform = function() {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.disassemble = function(mem, start, end, pcvisits) {
|
this.disassemble = function(pc, read) {
|
||||||
return new Disassembler6502().disassemble(mem, start, end, pcvisits);
|
return disassemble6502(pc, read(pc), read(pc+1), read(pc+2));
|
||||||
}
|
}
|
||||||
this.cpuStateToLongString = function(c) {
|
this.cpuStateToLongString = function(c) {
|
||||||
return cpuStateToLongString_6502(c);
|
return cpuStateToLongString_6502(c);
|
||||||
@ -700,7 +700,6 @@ var Keys = {
|
|||||||
VK_SCROLL_LOCK: {c: 145, n: "ScrLck"},
|
VK_SCROLL_LOCK: {c: 145, n: "ScrLck"},
|
||||||
VK_PAUSE: {c: 19, n: "Pause"},
|
VK_PAUSE: {c: 19, n: "Pause"},
|
||||||
VK_QUOTE: {c: 192, n: "'"},
|
VK_QUOTE: {c: 192, n: "'"},
|
||||||
VK_TILDE: {c: 222, n: "~"},
|
|
||||||
VK_1: {c: 49, n: "1"},
|
VK_1: {c: 49, n: "1"},
|
||||||
VK_2: {c: 50, n: "2"},
|
VK_2: {c: 50, n: "2"},
|
||||||
VK_3: {c: 51, n: "3"},
|
VK_3: {c: 51, n: "3"},
|
||||||
|
@ -85,6 +85,14 @@ var VCSPlatform = function() {
|
|||||||
this.getOriginPC = function() {
|
this.getOriginPC = function() {
|
||||||
return (this.readAddress(0xfffc) | (this.readAddress(0xfffd) << 8)) & 0xffff;
|
return (this.readAddress(0xfffc) | (this.readAddress(0xfffd) << 8)) & 0xffff;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
this.saveState = function() {
|
||||||
|
return Javatari.room.console.saveState(); // TODO
|
||||||
|
}
|
||||||
|
this.loadState = function(state) {
|
||||||
|
return Javatari.room.console.loadState(state); // TODO
|
||||||
|
}
|
||||||
|
*/
|
||||||
this.readAddress = function(addr) {
|
this.readAddress = function(addr) {
|
||||||
return current_output[addr & 0xfff]; // TODO: use bus to read
|
return current_output[addr & 0xfff]; // TODO: use bus to read
|
||||||
}
|
}
|
||||||
|
34
src/ui.js
34
src/ui.js
@ -116,7 +116,7 @@ var sourcefile = null;
|
|||||||
var pcvisits;
|
var pcvisits;
|
||||||
var trace_pending_at_pc;
|
var trace_pending_at_pc;
|
||||||
var store;
|
var store;
|
||||||
var pendingWorkerMessages;
|
var pendingWorkerMessages = 0;
|
||||||
|
|
||||||
var editor = CodeMirror(document.getElementById('editor'), {
|
var editor = CodeMirror(document.getElementById('editor'), {
|
||||||
theme: 'mbo',
|
theme: 'mbo',
|
||||||
@ -168,7 +168,7 @@ function loadCode(text, fileid) {
|
|||||||
function loadFile(fileid, filename, index) {
|
function loadFile(fileid, filename, index) {
|
||||||
current_preset_id = fileid;
|
current_preset_id = fileid;
|
||||||
current_preset_index = index;
|
current_preset_index = index;
|
||||||
var text = store.loadFile(fileid)|| "";
|
var text = store.loadFile(fileid) || "";
|
||||||
if (text) {
|
if (text) {
|
||||||
loadCode(text, fileid);
|
loadCode(text, fileid);
|
||||||
} else if (!text && index >= 0) {
|
} else if (!text && index >= 0) {
|
||||||
@ -275,30 +275,27 @@ function populateExamples(sel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateLocalFiles(sel) {
|
function populateFiles(sel, name, prefix) {
|
||||||
sel.append($("<option />").text("------- Local Files -------").attr('disabled',true));
|
sel.append($("<option />").text("------- " + name + " -------").attr('disabled',true));
|
||||||
var filenames = store.getFiles("local/");
|
var filenames = store.getFiles(prefix);
|
||||||
|
var foundSelected = false;
|
||||||
for (var i = 0; i < filenames.length; i++) {
|
for (var i = 0; i < filenames.length; i++) {
|
||||||
var name = filenames[i];
|
var name = filenames[i];
|
||||||
var key = "local/" + name;
|
var key = prefix + name;
|
||||||
sel.append($("<option />").val(key).text(name).attr('selected',key==current_preset_id));
|
sel.append($("<option />").val(key).text(name).attr('selected',key==current_preset_id));
|
||||||
|
if (key == current_preset_id) foundSelected = true;
|
||||||
}
|
}
|
||||||
}
|
if (!foundSelected && current_preset_id && current_preset_id.startsWith(prefix)) {
|
||||||
|
var name = current_preset_id.slice(prefix.length);
|
||||||
function populateSharedFiles(sel) {
|
var key = prefix + name;
|
||||||
sel.append($("<option />").text("--------- Shared ---------").attr('disabled',true));
|
sel.append($("<option />").val(key).text(name).attr('selected',true));
|
||||||
var filenames = store.getFiles("shared/");
|
|
||||||
for (var i = 0; i < filenames.length; i++) {
|
|
||||||
var name = filenames[i];
|
|
||||||
var key = "shared/" + name;
|
|
||||||
sel.append($("<option />").val(key).text(name).attr('selected',key==current_preset_id));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSelector() {
|
function updateSelector() {
|
||||||
var sel = $("#preset_select").empty();
|
var sel = $("#preset_select").empty();
|
||||||
populateLocalFiles(sel);
|
populateFiles(sel, "Local Files", "local/");
|
||||||
populateSharedFiles(sel);
|
populateFiles(sel, "Shared", "shared/");
|
||||||
populateExamples(sel);
|
populateExamples(sel);
|
||||||
// set click handlers
|
// set click handlers
|
||||||
sel.off('change').change(function(e) {
|
sel.off('change').change(function(e) {
|
||||||
@ -332,6 +329,7 @@ function arrayCompare(a,b) {
|
|||||||
|
|
||||||
worker.onmessage = function(e) {
|
worker.onmessage = function(e) {
|
||||||
if (pendingWorkerMessages > 1) {
|
if (pendingWorkerMessages > 1) {
|
||||||
|
pendingWorkerMessages = 0;
|
||||||
setCode(editor.getValue());
|
setCode(editor.getValue());
|
||||||
}
|
}
|
||||||
pendingWorkerMessages = 0;
|
pendingWorkerMessages = 0;
|
||||||
@ -821,7 +819,7 @@ function setupDebugControls(){
|
|||||||
if (platform_id == 'vcs') {
|
if (platform_id == 'vcs') {
|
||||||
$("#dbg_timing").click(traceTiming).show();
|
$("#dbg_timing").click(traceTiming).show();
|
||||||
}
|
}
|
||||||
if (platform.disassemble) {
|
if (platform.saveState) { // TODO: only show if listing or disasm available
|
||||||
$("#dbg_disasm").click(toggleDisassembly).show();
|
$("#dbg_disasm").click(toggleDisassembly).show();
|
||||||
}
|
}
|
||||||
$("#disassembly").hide();
|
$("#disassembly").hide();
|
||||||
|
25
src/worker/mcpp.js
Normal file
25
src/worker/mcpp.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -72,6 +72,7 @@ var print_fn = function(s) {
|
|||||||
|
|
||||||
// test.c(6) : warning 85: in function main unreferenced local variable : 'x'
|
// test.c(6) : warning 85: in function main unreferenced local variable : 'x'
|
||||||
// main.a (4): error: Unknown Mnemonic 'xxx'.
|
// main.a (4): error: Unknown Mnemonic 'xxx'.
|
||||||
|
// at 2: warning 190: ISO C forbids an empty source file
|
||||||
var re_msvc = /([^(]+)\s*[(](\d+)[)]\s*:\s*(.+?):\s*(.*)/;
|
var re_msvc = /([^(]+)\s*[(](\d+)[)]\s*:\s*(.+?):\s*(.*)/;
|
||||||
var re_msvc2 = /\s*(at)\s+(\d+)\s*(:)\s*(.*)/;
|
var re_msvc2 = /\s*(at)\s+(\d+)\s*(:)\s*(.*)/;
|
||||||
var msvc_errors;
|
var msvc_errors;
|
||||||
@ -508,12 +509,13 @@ function assemblelinkSDASZ80(code, platform) {
|
|||||||
if (!params) throw Error("Platform not supported: " + platform);
|
if (!params) throw Error("Platform not supported: " + platform);
|
||||||
{
|
{
|
||||||
msvc_errors = [];
|
msvc_errors = [];
|
||||||
//var match_re = /in line (\d+) of (.+)/; // TODO
|
//?ASxxxx-Error-<o> in line 1 of main.asm null
|
||||||
var match_re = / <\w> (.+)/; // TODO
|
// <o> .org in REL area or directive / mnemonic error
|
||||||
function match_fn(s) {
|
var match_asm_re = / <\w> (.+)/; // TODO
|
||||||
var matches = match_re.exec(s);
|
function match_asm_fn(s) {
|
||||||
|
var matches = match_asm_re.exec(s);
|
||||||
if (matches) {
|
if (matches) {
|
||||||
var errline = parseInt(matches[1]);
|
var errline = parseInt(matches[2]);
|
||||||
msvc_errors.push({
|
msvc_errors.push({
|
||||||
line:1, // TODO: errline,
|
line:1, // TODO: errline,
|
||||||
msg:matches[1]
|
msg:matches[1]
|
||||||
@ -523,8 +525,8 @@ function assemblelinkSDASZ80(code, platform) {
|
|||||||
var ASZ80 = sdasz80({
|
var ASZ80 = sdasz80({
|
||||||
noInitialRun:true,
|
noInitialRun:true,
|
||||||
//logReadFiles:true,
|
//logReadFiles:true,
|
||||||
print:match_fn,
|
print:match_asm_fn,
|
||||||
printErr:match_fn,
|
printErr:match_asm_fn,
|
||||||
});
|
});
|
||||||
var FS = ASZ80['FS'];
|
var FS = ASZ80['FS'];
|
||||||
FS.writeFile("main.asm", code, {encoding:'utf8'});
|
FS.writeFile("main.asm", code, {encoding:'utf8'});
|
||||||
@ -536,11 +538,22 @@ function assemblelinkSDASZ80(code, platform) {
|
|||||||
lstout = FS.readFile("main.lst", {encoding:'utf8'});
|
lstout = FS.readFile("main.lst", {encoding:'utf8'});
|
||||||
//symout = FS.readFile("main.sym", {encoding:'utf8'});
|
//symout = FS.readFile("main.sym", {encoding:'utf8'});
|
||||||
}{
|
}{
|
||||||
|
//?ASlink-Warning-Undefined Global '__divsint' referenced by module 'main'
|
||||||
|
var match_aslink_re = /\?ASlink-(\w+)-(.+)/;
|
||||||
|
function match_aslink_fn(s) {
|
||||||
|
var matches = match_aslink_re.exec(s);
|
||||||
|
if (matches) {
|
||||||
|
msvc_errors.push({
|
||||||
|
line:1,
|
||||||
|
msg:matches[2]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
var LDZ80 = sdldz80({
|
var LDZ80 = sdldz80({
|
||||||
noInitialRun:true,
|
noInitialRun:true,
|
||||||
//logReadFiles:true,
|
//logReadFiles:true,
|
||||||
print:match_msvc,
|
print:match_aslink_fn,
|
||||||
printErr:function() { },
|
printErr:match_aslink_fn,
|
||||||
});
|
});
|
||||||
var FS = LDZ80['FS'];
|
var FS = LDZ80['FS'];
|
||||||
FS.writeFile("main.rel", objout, {encoding:'utf8'});
|
FS.writeFile("main.rel", objout, {encoding:'utf8'});
|
||||||
@ -557,7 +570,7 @@ function assemblelinkSDASZ80(code, platform) {
|
|||||||
// 0000 21 02 00 [10] 52 ld hl, #2
|
// 0000 21 02 00 [10] 52 ld hl, #2
|
||||||
// TODO: offset by start address?
|
// TODO: offset by start address?
|
||||||
var asmlines = parseListing(lstout, /^\s*([0-9A-F]+)\s+([0-9A-F][0-9A-F r]*[0-9A-F])\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 4, 1, 2, 5, 3);
|
var asmlines = parseListing(lstout, /^\s*([0-9A-F]+)\s+([0-9A-F][0-9A-F r]*[0-9A-F])\s+\[([0-9 ]+)\]\s+(\d+) (.*)/i, 4, 1, 2, 5, 3);
|
||||||
var srclines = parseSourceLines(lstout, /^\s+\d+ ;\(null\):(\d+):/i, /^\s*([0-9A-F]{4})/i);
|
var srclines = parseSourceLines(lstout, /^\s+\d+ ;<stdin>:(\d+):/i, /^\s*([0-9A-F]{4})/i);
|
||||||
// parse symbol map
|
// parse symbol map
|
||||||
var symbolmap = {};
|
var symbolmap = {};
|
||||||
for (var s of mapout.split("\n")) {
|
for (var s of mapout.split("\n")) {
|
||||||
@ -578,6 +591,10 @@ function assemblelinkSDASZ80(code, platform) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function compileSDCC(code, platform) {
|
function compileSDCC(code, platform) {
|
||||||
|
var preproc = preprocessMCPP(code, platform);
|
||||||
|
if (preproc.errors) return preproc;
|
||||||
|
else code = preproc.code;
|
||||||
|
|
||||||
load("sdcc");
|
load("sdcc");
|
||||||
var params = PLATFORM_PARAMS[platform];
|
var params = PLATFORM_PARAMS[platform];
|
||||||
if (!params) throw Error("Platform not supported: " + platform);
|
if (!params) throw Error("Platform not supported: " + platform);
|
||||||
@ -592,16 +609,16 @@ function compileSDCC(code, platform) {
|
|||||||
setupFS(FS);
|
setupFS(FS);
|
||||||
//FS.writeFile("main.c", code, {encoding:'utf8'});
|
//FS.writeFile("main.c", code, {encoding:'utf8'});
|
||||||
msvc_errors = [];
|
msvc_errors = [];
|
||||||
SDCC.callMain(['--vc', '--c1mode', '--std-sdcc99', '-mz80', '-Wall',
|
SDCC.callMain(['--vc', '--std-sdcc99', '-mz80', '-Wall',
|
||||||
'--debug',
|
'--c1mode', // '--debug',
|
||||||
|
//'-S', 'main.c',
|
||||||
//'--asm=z80asm',
|
//'--asm=z80asm',
|
||||||
'--fomit-frame-pointer', '--opt-code-speed',
|
'--fomit-frame-pointer', '--opt-code-speed',
|
||||||
'-o', 'test.asm']);
|
'-o', 'main.asm']);
|
||||||
try {
|
if (msvc_errors.length) {
|
||||||
var asmout = FS.readFile("test.asm", {encoding:'utf8'});
|
|
||||||
} catch(e) {
|
|
||||||
return {errors:msvc_errors};
|
return {errors:msvc_errors};
|
||||||
}
|
}
|
||||||
|
var asmout = FS.readFile("main.asm", {encoding:'utf8'});
|
||||||
var warnings = msvc_errors;
|
var warnings = msvc_errors;
|
||||||
var result = assemblelinkSDASZ80(asmout, platform, true);
|
var result = assemblelinkSDASZ80(asmout, platform, true);
|
||||||
result.asmlines = result.lines;
|
result.asmlines = result.lines;
|
||||||
@ -642,7 +659,6 @@ function assembleXASM6809(code, platform) {
|
|||||||
//setupFS(FS);
|
//setupFS(FS);
|
||||||
FS.writeFile("main.asm", code);
|
FS.writeFile("main.asm", code);
|
||||||
Module.callMain(["-c", "-l", "-s", "-y", "-o=main.bin", "main.asm"]);
|
Module.callMain(["-c", "-l", "-s", "-y", "-o=main.bin", "main.asm"]);
|
||||||
console.log(alst);
|
|
||||||
try {
|
try {
|
||||||
var aout = FS.readFile("main.bin", {encoding:'binary'});
|
var aout = FS.readFile("main.bin", {encoding:'binary'});
|
||||||
// 00001 0000 [ 2] 1048 asld
|
// 00001 0000 [ 2] 1048 asld
|
||||||
@ -658,6 +674,33 @@ function assembleXASM6809(code, platform) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function preprocessMCPP(code, platform) {
|
||||||
|
load("mcpp");
|
||||||
|
var MCPP = mcpp({
|
||||||
|
noInitialRun:true,
|
||||||
|
noFSInit:true,
|
||||||
|
print:print_fn,
|
||||||
|
printErr:print_fn,
|
||||||
|
});
|
||||||
|
var FS = MCPP['FS'];
|
||||||
|
FS.writeFile("main.c", code, {encoding:'utf8'});
|
||||||
|
msvc_errors = [];
|
||||||
|
try {
|
||||||
|
MCPP.callMain([
|
||||||
|
"-D", "__8BITWORKSHOP__",
|
||||||
|
"-D", platform.toUpperCase(),
|
||||||
|
"-W", "31",
|
||||||
|
"main.c", "main.i"]);
|
||||||
|
var iout = FS.readFile("main.i", {encoding:'utf8'});
|
||||||
|
} catch (e) {
|
||||||
|
msvc_errors.push({line:1, msg:e+""});
|
||||||
|
}
|
||||||
|
if (msvc_errors.length) {
|
||||||
|
return {errors:msvc_errors};
|
||||||
|
}
|
||||||
|
return {code:iout};
|
||||||
|
}
|
||||||
|
|
||||||
var TOOLS = {
|
var TOOLS = {
|
||||||
'dasm': assembleDASM,
|
'dasm': assembleDASM,
|
||||||
'acme': assembleACME,
|
'acme': assembleACME,
|
||||||
|
20
test/cli/6502/test6502disasm.js
Normal file
20
test/cli/6502/test6502disasm.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
var assert = require('assert');
|
||||||
|
var vm = require('vm');
|
||||||
|
var fs = require('fs');
|
||||||
|
var includeInThisContext = function(path) {
|
||||||
|
var code = fs.readFileSync(path);
|
||||||
|
vm.runInThisContext(code, path);
|
||||||
|
};
|
||||||
|
|
||||||
|
includeInThisContext("src/disasm.js");
|
||||||
|
|
||||||
|
describe('6502 disassembler', function() {
|
||||||
|
it('Should work', function() {
|
||||||
|
assert.deepEqual({line:"BRK ",nbytes:1}, disassemble6502(0, 0, 0, 0));
|
||||||
|
assert.deepEqual({line:"LDA #$A9",nbytes:2}, disassemble6502(0, 0xa9, 0xa9, 0xa9));
|
||||||
|
assert.deepEqual({line:"JMP $6010",nbytes:3}, disassemble6502(0, 0x4c, 0x10, 0x60));
|
||||||
|
assert.deepEqual({line:"BPL $FFF0",nbytes:2}, disassemble6502(0, 0x10, 0xf0, 0));
|
||||||
|
assert.deepEqual({line:"BMI $0010",nbytes:2}, disassemble6502(0, 0x30, 0x10, 0));
|
||||||
|
});
|
||||||
|
});
|
@ -113,12 +113,18 @@ describe('Worker', function() {
|
|||||||
it('should NOT assemble SDASZ80', function(done) {
|
it('should NOT assemble SDASZ80', function(done) {
|
||||||
compile('sdasz80', '\txxx hl,#0\n\tret\n', 'mw8080bw', done, 0, 0, 1);
|
compile('sdasz80', '\txxx hl,#0\n\tret\n', 'mw8080bw', done, 0, 0, 1);
|
||||||
});
|
});
|
||||||
|
it('should NOT assemble SDASZ80', function(done) {
|
||||||
|
compile('sdasz80', '\tcall divxxx\n', 'mw8080bw', done, 0, 0, 1);
|
||||||
|
});
|
||||||
it('should compile SDCC', function(done) {
|
it('should compile SDCC', function(done) {
|
||||||
compile('sdcc', 'int foo=0;\nint main(int argc) {\nint x=1;\nint y=2+argc;\nreturn x+y+argc;\n}', 'mw8080bw', done, 8192, 3, 0);
|
compile('sdcc', 'int foo=0; // comment\nint main(int argc) {\nint x=1;\nint y=2+argc;\nreturn x+y+argc;\n}', 'mw8080bw', done, 8192, 3, 0);
|
||||||
});
|
});
|
||||||
it('should NOT compile SDCC', function(done) {
|
it('should NOT compile SDCC', function(done) {
|
||||||
compile('sdcc', 'foobar', 'mw8080bw', done, 0, 0, 1);
|
compile('sdcc', 'foobar', 'mw8080bw', done, 0, 0, 1);
|
||||||
});
|
});
|
||||||
|
it('should NOT preprocess SDCC', function(done) {
|
||||||
|
compile('sdcc', 'int x=0\n#bah\n', 'mw8080bw', done, 0, 0, 1);
|
||||||
|
});
|
||||||
it('should compile XASM6809', function(done) {
|
it('should compile XASM6809', function(done) {
|
||||||
compile('xasm6809', '\tasld\n\tasld\n', 'mw8080bw', done, 4, 2, 0);
|
compile('xasm6809', '\tasld\n\tasld\n', 'mw8080bw', done, 4, 2, 0);
|
||||||
});
|
});
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
<script src="src/platform/mw8080bw.js"></script>
|
<script src="src/platform/mw8080bw.js"></script>
|
||||||
|
|
||||||
<script src="test/ui/testemus.js"></script>
|
<script src="test/ui/testemus.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
mocha.run()
|
mocha.run()
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user