From 69600744df520a93964d3184bc1bcc1135910162 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Tue, 31 Oct 2023 19:55:42 -0500 Subject: [PATCH] pce: optimizations, 32KB carts --- src/common/cpu/disasmHuC6280.ts | 283 ++ src/platform/pce.ts | 6876 ++++++++++++++++--------------- src/worker/tools/cc65.ts | 8 + src/worker/workermain.ts | 2 +- 4 files changed, 3741 insertions(+), 3428 deletions(-) create mode 100644 src/common/cpu/disasmHuC6280.ts diff --git a/src/common/cpu/disasmHuC6280.ts b/src/common/cpu/disasmHuC6280.ts new file mode 100644 index 00000000..d841d111 --- /dev/null +++ b/src/common/cpu/disasmHuC6280.ts @@ -0,0 +1,283 @@ + +import { hex } from "../util"; + +export var OPS_HuC6280 = [ + {mn:"BRK",am:"",nb:1,il:0,c1:7,c2:0,nw:3,br:1,mod:"SI"}, // 0 + {mn:"ORA",am:"(aa,x)",nb:2,il:0,c1:6,c2:0,nw:0,br:0,mod:"AZN"}, // 1 + {mn:"SXY",am:"",nb:1,il:0,c1:3,c2:0,nw:0,br:0,mod:"XY"}, // 2 + {mn:"ST0",am:"#aa",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:""}, // 3 + {mn:"TSB",am:"aa",nb:2,il:0,c1:6,c2:0,nw:0,br:0,mod:"NZV"}, // 4 + {mn:"ORA",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"AZN"}, // 5 + {mn:"ASL",am:"aa",nb:2,il:0,c1:5,c2:0,nw:2,br:0,mod:"CZN"}, // 6 + {mn:"RMB0",am:"aa",nb:2,il:0,c1:7,c2:0,nw:1,br:0,mod:""}, // 7 + {mn:"PHP",am:"",nb:1,il:0,c1:3,c2:0,nw:1,br:0,mod:"S"}, // 8 + {mn:"ORA",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"AZN"}, // 9 + {mn:"ASL",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"ACZN"}, // a + {mn:"ANC",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:"ACZN"}, // b + {mn:"TSB",am:"AAAA",nb:3,il:0,c1:7,c2:0,nw:0,br:0,mod:"NZV"}, // c + {mn:"ORA",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"AZN"}, // d + {mn:"ASL",am:"AAAA",nb:3,il:0,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // e + {mn:"BBR0",am:"AAAA",nb:3,il:0,c1:6,c2:0,nw:0,br:0,mod:""}, // f + // TODO: finish these + {mn:"BPL",am:"branch",nb:2,il:0,c1:2,c2:2,nw:0,br:1,mod:""}, // 10 + {mn:"ORA",am:"(aa),y",nb:2,il:0,c1:5,c2:1,nw:0,br:0,mod:"AZN"}, // 11 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // 12 + {mn:"SLO",am:"(aa),y",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"ACZN"}, // 13 + {mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // 14 + {mn:"ORA",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:"AZN"}, // 15 + {mn:"ASL",am:"aa,x",nb:2,il:0,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // 16 + {mn:"SLO",am:"aa,x",nb:2,il:1,c1:6,c2:0,nw:2,br:0,mod:"ACZN"}, // 17 + {mn:"CLC",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"C"}, // 18 + {mn:"ORA",am:"AAAA,y",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"AZN"}, // 19 + {mn:"NOP",am:"",nb:1,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // 1a + {mn:"SLO",am:"AAAA,y",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZN"}, // 1b + {mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // 1c + {mn:"ORA",am:"AAAA,x",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"AZN"}, // 1d + {mn:"ASL",am:"AAAA,x",nb:3,il:0,c1:7,c2:0,nw:2,br:0,mod:"CZN"}, // 1e + {mn:"SLO",am:"AAAA,x",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZN"}, // 1f + {mn:"JSR",am:"AAAA",nb:3,il:0,c1:6,c2:0,nw:2,br:1,mod:"S"}, // 20 + {mn:"AND",am:"(aa,x)",nb:2,il:0,c1:6,c2:0,nw:0,br:0,mod:"AZN"}, // 21 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // 22 + {mn:"RLA",am:"(aa,x)",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"ACZN"}, // 23 + {mn:"BIT",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"ZVN"}, // 24 + {mn:"AND",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"AZN"}, // 25 + {mn:"ROL",am:"aa",nb:2,il:0,c1:5,c2:0,nw:2,br:0,mod:"CZN"}, // 26 + {mn:"RLA",am:"aa",nb:2,il:1,c1:5,c2:0,nw:2,br:0,mod:"ACZN"}, // 27 + {mn:"PLP",am:"",nb:1,il:0,c1:4,c2:0,nw:0,br:0,mod:"SCZIDVN"}, // 28 + {mn:"AND",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"AZN"}, // 29 + {mn:"ROL",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"ACZN"}, // 2a + {mn:"ANC",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:"ACZN"}, // 2b + {mn:"BIT",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"ZVN"}, // 2c + {mn:"AND",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"AZN"}, // 2d + {mn:"ROL",am:"AAAA",nb:3,il:0,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // 2e + {mn:"RLA",am:"AAAA",nb:3,il:1,c1:6,c2:0,nw:2,br:0,mod:"ACZN"}, // 2f + {mn:"BMI",am:"branch",nb:2,il:0,c1:2,c2:2,nw:0,br:1,mod:""}, // 30 + {mn:"AND",am:"(aa),y",nb:2,il:0,c1:5,c2:1,nw:0,br:0,mod:"AZN"}, // 31 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // 32 + {mn:"RLA",am:"(aa),y",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"ACZN"}, // 33 + {mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // 34 + {mn:"AND",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:"AZN"}, // 35 + {mn:"ROL",am:"aa,x",nb:2,il:0,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // 36 + {mn:"RLA",am:"aa,x",nb:2,il:1,c1:6,c2:0,nw:2,br:0,mod:"ACZN"}, // 37 + {mn:"SEC",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"C"}, // 38 + {mn:"AND",am:"AAAA,y",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"AZN"}, // 39 + {mn:"NOP",am:"",nb:1,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // 3a + {mn:"RLA",am:"AAAA,y",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZN"}, // 3b + {mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // 3c + {mn:"AND",am:"AAAA,x",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"AZN"}, // 3d + {mn:"ROL",am:"AAAA,x",nb:3,il:0,c1:7,c2:0,nw:2,br:0,mod:"CZN"}, // 3e + {mn:"RLA",am:"AAAA,x",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZN"}, // 3f + {mn:"RTI",am:"",nb:1,il:0,c1:6,c2:0,nw:0,br:1,mod:"SCZIDVN"}, // 40 + {mn:"EOR",am:"(aa,x)",nb:2,il:0,c1:6,c2:0,nw:0,br:0,mod:"AZN"}, // 41 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // 42 + {mn:"SRE",am:"(aa,x)",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"ACZN"}, // 43 + {mn:"NOP",am:"aa",nb:2,il:1,c1:3,c2:0,nw:0,br:0,mod:""}, // 44 + {mn:"EOR",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"AZN"}, // 45 + {mn:"LSR",am:"aa",nb:2,il:0,c1:5,c2:0,nw:2,br:0,mod:"CZN"}, // 46 + {mn:"SRE",am:"aa",nb:2,il:1,c1:5,c2:0,nw:2,br:0,mod:"ACZN"}, // 47 + {mn:"PHA",am:"",nb:1,il:0,c1:3,c2:0,nw:1,br:0,mod:"S"}, // 48 + {mn:"EOR",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"AZN"}, // 49 + {mn:"LSR",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"ACZN"}, // 4a + {mn:"ASR",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:"ACZN"}, // 4b + {mn:"JMP",am:"AAAA",nb:3,il:0,c1:3,c2:0,nw:0,br:1,mod:""}, // 4c + {mn:"EOR",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"AZN"}, // 4d + {mn:"LSR",am:"AAAA",nb:3,il:0,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // 4e + {mn:"SRE",am:"AAAA",nb:3,il:1,c1:6,c2:0,nw:2,br:0,mod:"ACZN"}, // 4f + {mn:"BVC",am:"branch",nb:2,il:0,c1:2,c2:2,nw:0,br:1,mod:""}, // 50 + {mn:"EOR",am:"(aa),y",nb:2,il:0,c1:5,c2:1,nw:0,br:0,mod:"AZN"}, // 51 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // 52 + {mn:"SRE",am:"(aa),y",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"ACZN"}, // 53 + {mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // 54 + {mn:"EOR",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:"AZN"}, // 55 + {mn:"LSR",am:"aa,x",nb:2,il:0,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // 56 + {mn:"SRE",am:"aa,x",nb:2,il:1,c1:6,c2:0,nw:2,br:0,mod:"ACZN"}, // 57 + {mn:"CLI",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"I"}, // 58 + {mn:"EOR",am:"AAAA,y",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"AZN"}, // 59 + {mn:"NOP",am:"",nb:1,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // 5a + {mn:"SRE",am:"AAAA,y",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZN"}, // 5b + {mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // 5c + {mn:"EOR",am:"AAAA,x",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"AZN"}, // 5d + {mn:"LSR",am:"AAAA,x",nb:3,il:0,c1:7,c2:0,nw:2,br:0,mod:"CZN"}, // 5e + {mn:"SRE",am:"AAAA,x",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZN"}, // 5f + {mn:"RTS",am:"",nb:1,il:0,c1:6,c2:0,nw:0,br:1,mod:"S"}, // 60 + {mn:"ADC",am:"(aa,x)",nb:2,il:0,c1:6,c2:0,nw:0,br:0,mod:"ACZVN"}, // 61 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // 62 + {mn:"RRA",am:"(aa,x)",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"ACZVN"}, // 63 + {mn:"NOP",am:"aa",nb:2,il:1,c1:3,c2:0,nw:0,br:0,mod:""}, // 64 + {mn:"ADC",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"ACZVN"}, // 65 + {mn:"ROR",am:"aa",nb:2,il:0,c1:5,c2:0,nw:2,br:0,mod:"CZN"}, // 66 + {mn:"RRA",am:"aa",nb:2,il:1,c1:5,c2:0,nw:2,br:0,mod:"ACZVN"}, // 67 + {mn:"PLA",am:"",nb:1,il:0,c1:4,c2:0,nw:0,br:0,mod:"SAZN"}, // 68 + {mn:"ADC",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"ACZVN"}, // 69 + {mn:"ROR",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"ACZN"}, // 6a + {mn:"ARR",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:"ACZVN"}, // 6b + {mn:"JMP",am:"(AAAA)",nb:3,il:0,c1:5,c2:0,nw:0,br:1,mod:""}, // 6c + {mn:"ADC",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"ACZVN"}, // 6d + {mn:"ROR",am:"AAAA",nb:3,il:0,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // 6e + {mn:"RRA",am:"AAAA",nb:3,il:1,c1:6,c2:0,nw:2,br:0,mod:"ACZVN"}, // 6f + {mn:"BVS",am:"branch",nb:2,il:0,c1:2,c2:2,nw:0,br:1,mod:""}, // 70 + {mn:"ADC",am:"(aa),y",nb:2,il:0,c1:5,c2:1,nw:0,br:0,mod:"ACZVN"}, // 71 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // 72 + {mn:"RRA",am:"(aa),y",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"ACZVN"}, // 73 + {mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // 74 + {mn:"ADC",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:"ACZVN"}, // 75 + {mn:"ROR",am:"aa,x",nb:2,il:0,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // 76 + {mn:"RRA",am:"aa,x",nb:2,il:1,c1:6,c2:0,nw:2,br:0,mod:"ACZVN"}, // 77 + {mn:"SEI",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"I"}, // 78 + {mn:"ADC",am:"AAAA,y",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"ACZVN"}, // 79 + {mn:"NOP",am:"",nb:1,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // 7a + {mn:"RRA",am:"AAAA,y",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZVN"}, // 7b + {mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // 7c + {mn:"ADC",am:"AAAA,x",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"ACZVN"}, // 7d + {mn:"ROR",am:"AAAA,x",nb:3,il:0,c1:7,c2:0,nw:2,br:0,mod:"CZN"}, // 7e + {mn:"RRA",am:"AAAA,x",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZVN"}, // 7f + {mn:"BRA",am:"branch",nb:2,il:0,c1:2,c2:2,nw:0,br:1,mod:""}, // 80 + {mn:"STA",am:"(aa,x)",nb:2,il:0,c1:6,c2:0,nw:1,br:0,mod:""}, // 81 + {mn:"NOP",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // 82 + {mn:"SAX",am:"(aa,x)",nb:2,il:1,c1:6,c2:0,nw:1,br:0,mod:""}, // 83 + {mn:"STY",am:"aa",nb:2,il:0,c1:3,c2:0,nw:1,br:0,mod:""}, // 84 + {mn:"STA",am:"aa",nb:2,il:0,c1:3,c2:0,nw:1,br:0,mod:""}, // 85 + {mn:"STX",am:"aa",nb:2,il:0,c1:3,c2:0,nw:1,br:0,mod:""}, // 86 + {mn:"SAX",am:"aa",nb:2,il:1,c1:3,c2:0,nw:1,br:0,mod:""}, // 87 + {mn:"DEY",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"YZN"}, // 88 + {mn:"NOP",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // 89 + {mn:"TXA",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"AZN"}, // 8a + {mn:"ANE",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:"AZN"}, // 8b + {mn:"STY",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:1,br:0,mod:""}, // 8c + {mn:"STA",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:1,br:0,mod:""}, // 8d + {mn:"STX",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:1,br:0,mod:""}, // 8e + {mn:"SAX",am:"AAAA",nb:3,il:1,c1:4,c2:0,nw:1,br:0,mod:""}, // 8f + {mn:"BCC",am:"branch",nb:2,il:0,c1:2,c2:2,nw:0,br:1,mod:""}, // 90 + {mn:"STA",am:"(aa),y",nb:2,il:0,c1:6,c2:0,nw:1,br:0,mod:""}, // 91 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // 92 + {mn:"SHA",am:"(aa),y",nb:2,il:1,c1:6,c2:0,nw:1,br:0,mod:""}, // 93 + {mn:"STY",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:1,br:0,mod:""}, // 94 + {mn:"STA",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:1,br:0,mod:""}, // 95 + {mn:"STX",am:"aa,y",nb:2,il:0,c1:4,c2:0,nw:1,br:0,mod:""}, // 96 + {mn:"SAX",am:"aa,y",nb:3,il:1,c1:4,c2:0,nw:1,br:1,mod:""}, // 97 + {mn:"TYA",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"AZN"}, // 98 + {mn:"STA",am:"AAAA,y",nb:3,il:0,c1:5,c2:0,nw:1,br:0,mod:""}, // 99 + {mn:"TXS",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"S"}, // 9a + {mn:"SHS",am:"AAAA,y",nb:3,il:1,c1:5,c2:0,nw:1,br:0,mod:"S"}, // 9b + {mn:"SHY",am:"AAAA,x",nb:3,il:1,c1:5,c2:0,nw:1,br:0,mod:""}, // 9c + {mn:"STA",am:"AAAA,x",nb:3,il:0,c1:5,c2:0,nw:1,br:0,mod:""}, // 9d + {mn:"SHX",am:"AAAA,y",nb:3,il:1,c1:5,c2:0,nw:1,br:0,mod:""}, // 9e + {mn:"SHA",am:"AAAA,y",nb:3,il:1,c1:5,c2:0,nw:1,br:0,mod:""}, // 9f + {mn:"LDY",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"YZN"}, // a0 + {mn:"LDA",am:"(aa,x)",nb:2,il:0,c1:6,c2:0,nw:0,br:0,mod:"AZN"}, // a1 + {mn:"LDX",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"XZN"}, // a2 + {mn:"LAX",am:"(aa,x)",nb:2,il:1,c1:6,c2:0,nw:0,br:0,mod:"AXZN"}, // a3 + {mn:"LDY",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"YZN"}, // a4 + {mn:"LDA",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"AZN"}, // a5 + {mn:"LDX",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"XZN"}, // a6 + {mn:"LAX",am:"aa",nb:2,il:1,c1:3,c2:0,nw:0,br:0,mod:"AXZN"}, // a7 + {mn:"TAY",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"YZN"}, // a8 + {mn:"LDA",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"AZN"}, // a9 + {mn:"TAX",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"XZN"}, // aa + {mn:"LXA",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:"AXZN"}, // ab + {mn:"LDY",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"YZN"}, // ac + {mn:"LDA",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"AZN"}, // ad + {mn:"LDX",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"XZN"}, // ae + {mn:"LAX",am:"AAAA",nb:3,il:1,c1:4,c2:0,nw:0,br:0,mod:"AXZN"}, // af + {mn:"BCS",am:"branch",nb:2,il:0,c1:2,c2:2,nw:0,br:1,mod:""}, // b0 + {mn:"LDA",am:"(aa),y",nb:2,il:0,c1:5,c2:1,nw:0,br:0,mod:"AZN"}, // b1 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // b2 + {mn:"LAX",am:"(aa),y",nb:2,il:1,c1:5,c2:1,nw:0,br:0,mod:"AXZN"}, // b3 + {mn:"LDY",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:"YZN"}, // b4 + {mn:"LDA",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:"AZN"}, // b5 + {mn:"LDX",am:"aa,y",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:"XZN"}, // b6 + {mn:"LAX",am:"aa,y",nb:2,il:1,c1:4,c2:0,nw:0,br:0,mod:"AXZN"}, // b7 + {mn:"CLV",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"V"}, // b8 + {mn:"LDA",am:"AAAA,y",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"AZN"}, // b9 + {mn:"TSX",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"XZN"}, // ba + {mn:"LAS",am:"AAAA,y",nb:3,il:1,c1:4,c2:1,nw:0,br:0,mod:"SAXZN"}, // bb + {mn:"LDY",am:"AAAA,x",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"YZN"}, // bc + {mn:"LDA",am:"AAAA,x",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"AZN"}, // bd + {mn:"LDX",am:"AAAA,y",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"XZN"}, // be + {mn:"LAX",am:"AAAA,y",nb:3,il:1,c1:4,c2:1,nw:0,br:0,mod:"AXZN"}, // bf + {mn:"CPY",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"CZN"}, // c0 + {mn:"CMP",am:"(aa,x)",nb:2,il:0,c1:6,c2:0,nw:0,br:0,mod:"CZN"}, // c1 + {mn:"NOP",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // c2 + {mn:"DCP",am:"(aa,x)",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"CZN"}, // c3 + {mn:"CPY",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"CZN"}, // c4 + {mn:"CMP",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"CZN"}, // c5 + {mn:"DEC",am:"aa",nb:2,il:0,c1:5,c2:0,nw:2,br:0,mod:"ZN"}, // c6 + {mn:"DCP",am:"aa",nb:2,il:1,c1:5,c2:0,nw:2,br:0,mod:"CZN"}, // c7 + {mn:"INY",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"YZN"}, // c8 + {mn:"CMP",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"CZN"}, // c9 + {mn:"DEX",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"XZN"}, // ca + {mn:"SBX",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:"XCZN"}, // cb + {mn:"CPY",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"CZN"}, // cc + {mn:"CMP",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"CZN"}, // cd + {mn:"DEC",am:"AAAA",nb:3,il:0,c1:6,c2:0,nw:2,br:0,mod:"ZN"}, // ce + {mn:"DCP",am:"AAAA",nb:3,il:1,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // cf + {mn:"BNE",am:"branch",nb:2,il:0,c1:2,c2:2,nw:0,br:1,mod:""}, // d0 + {mn:"CMP",am:"(aa),y",nb:2,il:0,c1:5,c2:1,nw:0,br:0,mod:"CZN"}, // d1 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // d2 + {mn:"DCP",am:"(aa),y",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"CZN"}, // d3 + {mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // d4 + {mn:"CMP",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:"CZN"}, // d5 + {mn:"DEC",am:"aa,x",nb:2,il:0,c1:6,c2:0,nw:2,br:0,mod:"ZN"}, // d6 + {mn:"DCP",am:"aa,x",nb:2,il:1,c1:6,c2:0,nw:2,br:0,mod:"CZN"}, // d7 + {mn:"CLD",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"D"}, // d8 + {mn:"CMP",am:"AAAA,y",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"CZN"}, // d9 + {mn:"NOP",am:"",nb:1,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // da + {mn:"DCP",am:"AAAA,y",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"CZN"}, // db + {mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // dc + {mn:"CMP",am:"AAAA,x",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"CZN"}, // dd + {mn:"DEC",am:"AAAA,x",nb:3,il:0,c1:7,c2:0,nw:2,br:0,mod:"ZN"}, // de + {mn:"DCP",am:"AAAA,x",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"CZN"}, // df + {mn:"CPX",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"CZN"}, // e0 + {mn:"SBC",am:"(aa,x)",nb:2,il:0,c1:6,c2:0,nw:0,br:0,mod:"ACZVN"}, // e1 + {mn:"NOP",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // e2 + {mn:"ISB",am:"(aa,x)",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"ACZVN"}, // e3 + {mn:"CPX",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"CZN"}, // e4 + {mn:"SBC",am:"aa",nb:2,il:0,c1:3,c2:0,nw:0,br:0,mod:"ACZVN"}, // e5 + {mn:"INC",am:"aa",nb:2,il:0,c1:5,c2:0,nw:2,br:0,mod:"ZN"}, // e6 + {mn:"ISB",am:"aa",nb:2,il:1,c1:5,c2:0,nw:2,br:0,mod:"ACZVN"}, // e7 + {mn:"INX",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"XZN"}, // e8 + {mn:"SBC",am:"#aa",nb:2,il:0,c1:2,c2:0,nw:0,br:0,mod:"ACZVN"}, // e9 + {mn:"NOP",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:""}, // ea + {mn:"SBC",am:"#aa",nb:2,il:1,c1:2,c2:0,nw:0,br:0,mod:"ACZVN"}, // eb + {mn:"CPX",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"CZN"}, // ec + {mn:"SBC",am:"AAAA",nb:3,il:0,c1:4,c2:0,nw:0,br:0,mod:"ACZVN"}, // ed + {mn:"INC",am:"AAAA",nb:3,il:0,c1:6,c2:0,nw:2,br:0,mod:"ZN"}, // ee + {mn:"ISB",am:"AAAA",nb:3,il:1,c1:6,c2:0,nw:2,br:0,mod:"ACZVN"}, // ef + {mn:"BEQ",am:"branch",nb:2,il:0,c1:2,c2:2,nw:0,br:1,mod:""}, // f0 + {mn:"SBC",am:"(aa),y",nb:2,il:0,c1:5,c2:1,nw:0,br:0,mod:"ACZVN"}, // f1 + {mn:"KIL",am:"",nb:1,il:2,c1:3,c2:0,nw:0,br:1,mod:""}, // f2 + {mn:"ISB",am:"(aa),y",nb:2,il:1,c1:8,c2:0,nw:2,br:0,mod:"ACZVN"}, // f3 + {mn:"NOP",am:"aa,x",nb:2,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // f4 + {mn:"SBC",am:"aa,x",nb:2,il:0,c1:4,c2:0,nw:0,br:0,mod:"ACZVN"}, // f5 + {mn:"INC",am:"aa,x",nb:2,il:0,c1:6,c2:0,nw:2,br:0,mod:"ZN"}, // f6 + {mn:"ISB",am:"aa,x",nb:2,il:1,c1:6,c2:0,nw:2,br:0,mod:"ACZVN"}, // f7 + {mn:"SED",am:"",nb:1,il:0,c1:2,c2:0,nw:0,br:0,mod:"D"}, // f8 + {mn:"SBC",am:"AAAA,y",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"ACZVN"}, // f9 + {mn:"NOP",am:"",nb:1,il:1,c1:2,c2:0,nw:0,br:0,mod:""}, // fa + {mn:"ISB",am:"AAAA,y",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZVN"}, // fb + {mn:"NOP",am:"AAAA,x",nb:3,il:1,c1:4,c2:0,nw:0,br:0,mod:""}, // fc + {mn:"SBC",am:"AAAA,x",nb:3,il:0,c1:4,c2:1,nw:0,br:0,mod:"ACZVN"}, // fd + {mn:"INC",am:"AAAA,x",nb:3,il:0,c1:7,c2:0,nw:2,br:0,mod:"ZN"}, // fe + {mn:"ISB",am:"AAAA,x",nb:3,il:1,c1:7,c2:0,nw:2,br:0,mod:"ACZVN"}, // ff +]; + +export function disassembleHuC6280(pc:number, b0:number, b1:number, b2:number) : {line:string, nbytes:number, isaddr:boolean} { + + var op = OPS_HuC6280[b0]; + if (op == null) return {line:"???", nbytes:1, isaddr:false}; + var s = op.mn; + var am = op.am; + var isaddr = false; + if (am == 'branch') { + var offset = (b1 < 0x80) ? (pc+2+b1) : (pc+2-(256-b1)); + offset &= 0xffff; + am = '$'+hex(offset, 4); + isaddr = true; + } else { + am = am.replace('aa','$'+hex(b1, 2)); + am = am.replace('AAAA','$'+hex(b1+(b2<<8), 4)); + if (am.indexOf('#') < 0 && am.indexOf('$') >= 0) + isaddr = true; + } + return {line:op.mn + " " + am, nbytes:op.nb, isaddr:isaddr}; +}; diff --git a/src/platform/pce.ts b/src/platform/pce.ts index f8cdb59e..0547da75 100644 --- a/src/platform/pce.ts +++ b/src/platform/pce.ts @@ -1,22 +1,22 @@ -import { Platform, Preset, getToolForFilename_6502 } from "../common/baseplatform"; +import { DisasmLine, Platform, Preset, getToolForFilename_6502 } from "../common/baseplatform"; import { Keys, PLATFORMS, RasterVideo } from "../common/emu"; const PCE_PRESETS = [ - {id:'test_conio.c', name:'Hello World (conio)'}, - {id:'siegegame.c', name:'Siege Game (conio)'}, + { id: 'test_conio.c', name: 'Hello World (conio)' }, + { id: 'siegegame.c', name: 'Siege Game (conio)' }, ] class PCEnginePlatform implements Platform { - mainElement : HTMLElement; - pce : PCE; - video : RasterVideo; + mainElement: HTMLElement; + pce: PCE; + video: RasterVideo; constructor(mainElement) { this.mainElement = mainElement; - } + } start(): void | Promise { this.pce = new PCE(); - this.video = new RasterVideo(this.mainElement,684,262,{overscan:true}); + this.video = new RasterVideo(this.mainElement, 684, 262, { overscan: true }); this.video.create(); this.pce.SetCanvas(this.video.canvas); } @@ -36,7 +36,7 @@ class PCEnginePlatform implements Platform { getPresets(): Preset[] { return PCE_PRESETS; } - loadROM(title: string, rom: any) { + loadROM(title: string, rom: Uint8Array) { this.pce.Pause(); this.pce.Init(); this.pce.SetROM(rom); @@ -50,6 +50,21 @@ class PCEnginePlatform implements Platform { getDefaultExtension(): string { return ".pce"; } + readAddress(addr: number): number { + return this.pce.Get(addr); + } + writeAddress(addr: number, value: number): void { + this.pce.Set(addr, value); + } + readVRAMAddress(addr: number): number { + return this.pce.VDC[0].VRAM[addr]; + } + // TODO + /* + disassemble(pc: number, read: (addr: number) => number): DisasmLine { + return disassembleHuC6280(pc, read(pc), read(pc + 1), read(pc + 2)); + } + */ } PLATFORMS['pce'] = PCEnginePlatform; @@ -89,7 +104,7 @@ class PCE { CountryType: any; GamePadButton6: boolean; MultiTap: boolean; - TimerID: number | null;c + TimerID: number | null; c MainCanvas: HTMLCanvasElement | null = null; Ctx: CanvasRenderingContext2D | null = null; ImageData: ImageData | null = null; @@ -103,7 +118,7 @@ class PCE { PC: number; S: number; P: number; - NZCacheTable: any[]; + NZCacheTable: Uint8Array; NFlag: number; VFlag: number; TFlag: number; @@ -129,9 +144,9 @@ class PCE { LastInt: number; MPRSelect: any; MPR: any; - RAM: any[]; + RAM: Uint8Array; RAMMask: number; - BRAM: any[]; + BRAM: Uint8Array; BRAMUse: boolean; INTIRQ2: number; IntDisableRegister: number; @@ -156,7 +171,7 @@ class PCE { Mapper0: typeof this.MapperBase; Mapper1: typeof this.MapperBase; Mapper2: typeof this.MapperBase; - VDC: any; + VDC: any[]; INTTIQ: number; Palette: any[]; PaletteData: any[]; @@ -165,19 +180,19 @@ class PCE { VCEControl: number; VCEAddress: number; VCEData: number; - VPCRegister: any[]; + VPCRegister: Uint8Array; VPCWindow1: number; VPCWindow2: number; - VPCPriority: any[]; + VPCPriority: Uint8Array; VDCPutLineProgressClock: number; VDCPutLine: number; VDCLineClock: number; ScreenSize: any[]; PutScreenSize: any[]; VScreenWidthArray: any[]; - ReverseBit: any[]; - ReverseBit16: any[]; - ReverseBit256: any[]; + ReverseBit: Uint8Array; + ReverseBit16: Uint16Array; + ReverseBit256: Uint32Array; SPAddressMask: any[]; WaveDataArray: any[]; WaveClockCounter: number; @@ -216,2889 +231,2894 @@ class PCE { ScreenWidthMAX = 0; ScreenHeightMAX = 0; - constructor() { - /* ***************** */ - /* **** Setting **** */ - /* ***************** */ - this.SuperGrafx = false; - this.CountryTypePCE = 0x40; - this.CountryTypeTG16 = 0x00; - this.CountryType = this.CountryTypePCE; - this.GamePadButton6 = false; - this.MultiTap = false; - - /* ******************* */ - /* **** Construct **** */ - /* ******************* */ - this.EtcConstruct(); - this.CPUConstruct(); - this.StorageConstruct(); - this.VCEConstruct(); - this.VPCConstruct(); - this.VDCConstruct(); - this.SoundConstruct(); - this.PSGConstruct(); - this.TimerConstruct(); - this.JoystickConstruct(); - } - - - /* ************* */ - /* **** ETC **** */ - /* ************* */ - EtcConstruct() { - this.TimerID = null; - this.MainCanvas = null; - this.Ctx = null; - this.ImageData = null; - } - - - UpdateAnimationFrame() { - this.TimerID = window.requestAnimationFrame(this.UpdateAnimationFrame.bind(this)); - this.Run(); - } - - - CancelAnimationFrame() { - window.cancelAnimationFrame(this.TimerID); - this.TimerID = null; - } - - - Pause() { - if(this.TimerID != null) { - this.JoystickEventRelease(); - this.CancelAnimationFrame(); - } - } - - - Start() { - if(this.TimerID == null) { - this.JoystickEventInit(); - this.UpdateAnimationFrame(); - } - } - - - Run() { - this.CheckGamePad(); - this.DrawFlag = false; - while(!this.DrawFlag) { - this.CPURun(); - this.VDCRun(); - this.TimerRun(); - this.PSGRun(); - } - } - - - Reset() { - this.StorageReset(); - this.Mapper.Init(); - this.CPUInit(); - this.VCEInit(); - this.VPCInit(); - this.VDCInit(); - this.TimerInit(); - this.JoystickInit(); - this.PSGInit(); - this.CPUReset(); - } - - - Init() { - this.StorageInit(); - this.CPUInit(); - this.VCEInit(); - this.VPCInit(); - this.VDCInit(); - this.TimerInit(); - this.JoystickInit(); - this.PSGInit(); - } - - - SetCanvas(canvas: HTMLCanvasElement) { - this.MainCanvas = canvas; - if (!this.MainCanvas.getContext) - return false; - - this.Ctx = this.MainCanvas.getContext("2d"); - this.ImageData = this.Ctx.createImageData(this.MainCanvas.width, this.MainCanvas.height); // this.ScreenWidthMAX, this.ScreenHeightMAX); - for(let i=0; i { return i & 0x80; }); - this.NZCacheTable[0x00] = 0x02; - - this.NFlag = 0x80; - this.VFlag = 0x40; - this.TFlag = 0x20; - this.BFlag = 0x10; - this.DFlag = 0x08; - this.IFlag = 0x04; - this.ZFlag = 0x02; - this.CFlag = 0x01; - - this.TIQFlag = 0x04; - this.IRQ1Flag = 0x02; - this.IRQ2Flag = 0x01; - - this.ProgressClock = 0; - this.CPUBaseClock = 0; - - this.BaseClock1 = 12; - this.BaseClock3 = 6; - this.BaseClock5 = 4; - this.BaseClock7 = 3; - this.BaseClock10 = 2; - - this.TransferSrc = 0; - this.TransferDist = 0; - this.TransferLen = 0; - this.TransferAlt = 0; - } - - - CPUReset() { - this.TransferSrc = 0; - this.TransferDist = 0; - this.TransferLen = 0; - this.TransferAlt = 0; - - this.CPUBaseClock = this.BaseClock1; - - this.SetIFlag(); - this.PC = this.Get16(0xFFFE); - } - - - CPUInit() { - this.A = 0; - this.X = 0; - this.Y = 0; - this.PC = 0; - this.S = 0; - this.P = 0x00; - - this.ProgressClock = 0; - this.CPUBaseClock = this.BaseClock1; - - this.TransferSrc = 0; - this.TransferDist = 0; - this.TransferLen = 0; - this.TransferAlt = 0; - - this.LastInt = 0x00; - } - - - CPURun() { - this.ProgressClock = 0; - - let tmp = this.LastInt; - this.LastInt = (this.P & this.IFlag) == 0x00 ? this.GetIntStatus() : 0x00; - - if(tmp != 0x00 && this.TransferLen == 0) { - this.LastInt = 0x00; - - if((tmp & this.TIQFlag) == this.TIQFlag) {//TIQ - this.Push(this.PCH()); - this.Push(this.PCL()); - this.Push(this.P); - this.P = 0x04; - this.PC = this.Get16(0xFFFA); - } else if((tmp & this.IRQ1Flag) == this.IRQ1Flag) {//IRQ1 - this.Push(this.PCH()); - this.Push(this.PCL()); - this.Push(this.P); - this.P = 0x04; - this.PC = this.Get16(0xFFF8); - } else if((tmp & this.IRQ2Flag) == this.IRQ2Flag) {//IRQ2 - this.Push(this.PCH()); - this.Push(this.PCL()); - this.Push(this.P); - this.SetIFlag(); - this.PC = this.Get16(0xFFF6); - } - this.ProgressClock = 8 * this.CPUBaseClock; - } else - this.OpExec(); - } - - - OpExec() { - let address; - let tmp; - let data; - let bit; - let i; - - let op = this.Get(this.PC); - - switch(op) { - case 0x69: // ADC IMM - this.ADC(this.PC + 1); - break; - case 0x65: // ADC ZP - this.ADC(this.ZP()); - break; - case 0x75: // ADC ZP, X - this.ADC(this.ZP_X()); - break; - case 0x72: // ADC (IND) - this.ADC(this.IND()); - break; - case 0x61: // ADC (IND, X) - this.ADC(this.IND_X()); - break; - case 0x71: // ADC (IND), Y - this.ADC(this.IND_Y()); - break; - case 0x6D: // ADC ABS - this.ADC(this.ABS()); - break; - case 0x7D: // ADC ABS, X - this.ADC(this.ABS_X()); - break; - case 0x79: // ADC ABS, Y - this.ADC(this.ABS_Y()); - break; - - case 0xE9: // SBC IMM - this.SBC(this.PC + 1); - break; - case 0xE5: // SBC ZP - this.SBC(this.ZP()); - break; - case 0xF5: // SBC ZP, X - this.SBC(this.ZP_X()); - break; - case 0xF2: // SBC (IND) - this.SBC(this.IND()); - break; - case 0xE1: // SBC (IND, X) - this.SBC(this.IND_X()); - break; - case 0xF1: // SBC (IND), Y - this.SBC(this.IND_Y()); - break; - case 0xED: // SBC ABS - this.SBC(this.ABS()); - break; - case 0xFD: // SBC ABS, X - this.SBC(this.ABS_X()); - break; - case 0xF9: // SBC ABS, Y - this.SBC(this.ABS_Y()); - break; - - case 0x29: // AND IMM - this.AND(this.PC + 1); - break; - case 0x25: // AND ZP - this.AND(this.ZP()); - break; - case 0x35: // AND ZP, X - this.AND(this.ZP_X()); - break; - case 0x32: // AND (IND) - this.AND(this.IND()); - break; - case 0x21: // AND (IND, X) - this.AND(this.IND_X()); - break; - case 0x31: // AND (IND), Y - this.AND(this.IND_Y()); - break; - case 0x2D: // AND ABS - this.AND(this.ABS()); - break; - case 0x3D: // AND ABS, X - this.AND(this.ABS_X()); - break; - case 0x39: // AND ABS, Y - this.AND(this.ABS_Y()); - break; - - case 0x49: // EOR IMM - this.EOR(this.PC + 1); - break; - case 0x45: // EOR ZP - this.EOR(this.ZP()); - break; - case 0x55: // EOR ZP, X - this.EOR(this.ZP_X()); - break; - case 0x52: // EOR (IND) - this.EOR(this.IND()); - break; - case 0x41: // EOR (IND, X) - this.EOR(this.IND_X()); - break; - case 0x51: // EOR (IND), Y - this.EOR(this.IND_Y()); - break; - case 0x4D: // EOR ABS - this.EOR(this.ABS()); - break; - case 0x5D: // EOR ABS, X - this.EOR(this.ABS_X()); - break; - case 0x59: // EOR ABS, Y - this.EOR(this.ABS_Y()); - break; - - case 0x09: // ORA IMM - this.ORA(this.PC + 1); - break; - case 0x05: // ORA ZP - this.ORA(this.ZP()); - break; - case 0x15: // ORA ZP, X - this.ORA(this.ZP_X()); - break; - case 0x12: // ORA (IND) - this.ORA(this.IND()); - break; - case 0x01: // ORA (IND, X) - this.ORA(this.IND_X()); - break; - case 0x11: // ORA (IND), Y - this.ORA(this.IND_Y()); - break; - case 0x0D: // ORA ABS - this.ORA(this.ABS()); - break; - case 0x1D: // ORA ABS, X - this.ORA(this.ABS_X()); - break; - case 0x19: // ORA ABS, Y - this.ORA(this.ABS_Y()); - break; - - case 0x06: // ASL ZP - address = this.ZP(); - this.Set(address, this.ASL(this.Get(address))); - break; - case 0x16: // ASL ZP, X - address = this.ZP_X(); - this.Set(address, this.ASL(this.Get(address))); - break; - case 0x0E: // ASL ABS - address = this.ABS(); - this.Set(address, this.ASL(this.Get(address))); - break; - case 0x1E: // ASL ABS, X - address = this.ABS_X(); - this.Set(address, this.ASL(this.Get(address))); - break; - case 0x0A: // ASL A - this.A = this.ASL(this.A); - break; - - case 0x46: // LSR ZP - address = this.ZP(); - this.Set(address, this.LSR(this.Get(address))); - break; - case 0x56: // LSR ZP, X - address = this.ZP_X(); - this.Set(address, this.LSR(this.Get(address))); - break; - case 0x4E: // LSR ABS - address = this.ABS(); - this.Set(address, this.LSR(this.Get(address))); - break; - case 0x5E: // LSR ABS, X - address = this.ABS_X(); - this.Set(address, this.LSR(this.Get(address))); - break; - case 0x4A: // LSR A - this.A = this.LSR(this.A); - break; - - case 0x26: // ROL ZP - address = this.ZP(); - this.Set(address, this.ROL(this.Get(address))); - break; - case 0x36: // ROL ZP, X - address = this.ZP_X(); - this.Set(address, this.ROL(this.Get(address))); - break; - case 0x2E: // ROL ABS - address = this.ABS(); - this.Set(address, this.ROL(this.Get(address))); - break; - case 0x3E: // ROL ABS, X - address = this.ABS_X(); - this.Set(address, this.ROL(this.Get(address))); - break; - case 0x2A: // ROL A - this.A = this.ROL(this.A); - break; - - case 0x66: // ROR ZP - address = this.ZP(); - this.Set(address, this.ROR(this.Get(address))); - break; - case 0x76: // ROR ZP, X - address = this.ZP_X(); - this.Set(address, this.ROR(this.Get(address))); - break; - case 0x6E: // ROR ABS - address = this.ABS(); - this.Set(address, this.ROR(this.Get(address))); - break; - case 0x7E: // ROR ABS, X - address = this.ABS_X(); - this.Set(address, this.ROR(this.Get(address))); - break; - case 0x6A: // ROR A - this.A = this.ROR(this.A); - break; - - case 0x0F: // BBR0 - this.BBRi(0); - break; - case 0x1F: // BBR1 - this.BBRi(1); - break; - case 0x2F: // BBR2 - this.BBRi(2); - break; - case 0x3F: // BBR3 - this.BBRi(3); - break; - case 0x4F: // BBR4 - this.BBRi(4); - break; - case 0x5F: // BBR5 - this.BBRi(5); - break; - case 0x6F: // BBR6 - this.BBRi(6); - break; - case 0x7F: // BBR7 - this.BBRi(7); - break; - - case 0x8F: // BBS0 - this.BBSi(0); - break; - case 0x9F: // BBS1 - this.BBSi(1); - break; - case 0xAF: // BBS2 - this.BBSi(2); - break; - case 0xBF: // BBS3 - this.BBSi(3); - break; - case 0xCF: // BBS4 - this.BBSi(4); - break; - case 0xDF: // BBS5 - this.BBSi(5); - break; - case 0xEF: // BBS6 - this.BBSi(6); - break; - case 0xFF: // BBS7 - this.BBSi(7); - break; - - case 0x90: // BCC - this.Branch((this.P & this.CFlag) == 0x00, 1); - break; - case 0xB0: // BCS - this.Branch((this.P & this.CFlag) == this.CFlag, 1); - break; - case 0xD0: // BNE - this.Branch((this.P & this.ZFlag) == 0x00, 1); - break; - case 0xF0: // BEQ - this.Branch((this.P & this.ZFlag) == this.ZFlag, 1); - break; - case 0x10: // BPL - this.Branch((this.P & this.NFlag) == 0x00, 1); - break; - case 0x30: // BMI - this.Branch((this.P & this.NFlag) == this.NFlag, 1); - break; - case 0x50: // BVC - this.Branch((this.P & this.VFlag) == 0x00, 1); - break; - case 0x70: // BVS - this.Branch((this.P & this.VFlag) == this.VFlag, 1); - break; - case 0x80: // BRA - this.Branch(true, 1); - break; - - case 0x44: // BSR - this.PC++; - this.Push(this.PCH()); - this.Push(this.PCL()); - this.Branch(true, 0); - break; - case 0x20: // JSR ABS - tmp = this.ABS(); - this.PC += 2; - this.Push(this.PCH()); - this.Push(this.PCL()); - this.PC = tmp; - this.ClearTFlag(); - break; - - case 0x40: // RTI - this.P = this.Pull(); - this.toPCL(this.Pull()); - this.toPCH(this.Pull()); - break; - case 0x60: // RTS - this.ClearTFlag(); - this.toPCL(this.Pull()); - this.toPCH(this.Pull()); - this.PC++; - break; - - case 0x4C: // JMP ABS - this.PC = this.ABS(); - this.ClearTFlag(); - break; - case 0x6C: // JMP (ABS) - this.PC = this.ABS_IND(); - this.ClearTFlag(); - break; - case 0x7C: // JMP (ABS, X) - this.PC = this.ABS_X_IND(); - this.ClearTFlag(); - break; - - case 0x00: // BRK - this.PC += 2; - this.Push(this.PCH()); - this.Push(this.PCL()); - this.SetBFlag(); - this.Push(this.P); - this.ClearDFlag(); - this.ClearTFlag(); - this.SetIFlag(); - this.PC = this.Get16(0xFFF6); - break; - - case 0x62: // CLA - this.A = 0x00; - this.ClearTFlag(); - break; - case 0x82: // CLX - this.X = 0x00; - this.ClearTFlag(); - break; - case 0xC2: // CLY - this.Y = 0x00; - this.ClearTFlag(); - break; - - case 0x18: // CLC - this.ClearCFlag(); - this.ClearTFlag(); - break; - case 0xD8: // CLD - this.ClearDFlag(); - this.ClearTFlag(); - break; - case 0x58: // CLI - this.ClearIFlag(); - this.ClearTFlag(); - break; - case 0xB8: // CLV - this.ClearVFlag(); - this.ClearTFlag(); - break; - - case 0x38: // SEC - this.SetCFlag(); - this.ClearTFlag(); - break; - case 0xF8: // SED - this.SetDFlag(); - this.ClearTFlag(); - break; - case 0x78: // SEI - this.SetIFlag(); - this.ClearTFlag(); - break; - case 0xF4: // SET - this.SetTFlag(); - break; - - case 0xC9: // CMP IMM - this.Compare(this.A, this.PC + 1); - break; - case 0xC5: // CMP ZP - this.Compare(this.A, this.ZP()); - break; - case 0xD5: // CMP ZP, X - this.Compare(this.A, this.ZP_X()); - break; - case 0xD2: // CMP (IND) - this.Compare(this.A, this.IND()); - break; - case 0xC1: // CMP (IND, X) - this.Compare(this.A, this.IND_X()); - break; - case 0xD1: // CMP (IND), Y - this.Compare(this.A, this.IND_Y()); - break; - case 0xCD: // CMP ABS - this.Compare(this.A, this.ABS()); - break; - case 0xDD: // CMP ABS, X - this.Compare(this.A, this.ABS_X()); - break; - case 0xD9: // CMP ABS, Y - this.Compare(this.A, this.ABS_Y()); - break; - case 0xE0: // CPX IMM - this.Compare(this.X, this.PC + 1); - break; - case 0xE4: // CPX ZP - this.Compare(this.X, this.ZP()); - break; - case 0xEC: // CPX ABS - this.Compare(this.X, this.ABS()); - break; - case 0xC0: // CPY IMM - this.Compare(this.Y, this.PC + 1); - break; - case 0xC4: // CPY ZP - this.Compare(this.Y, this.ZP()); - break; - case 0xCC: // CPY ABS - this.Compare(this.Y, this.ABS()); - break; - - case 0xC6: // DEC ZP - address = this.ZP(); - this.Set(address, this.Decrement(this.Get(address))); - break; - case 0xD6: // DEC ZP, X - address = this.ZP_X(); - this.Set(address, this.Decrement(this.Get(address))); - break; - case 0xCE: // DEC ABS - address = this.ABS(); - this.Set(address, this.Decrement(this.Get(address))); - break; - case 0xDE: // DEC ABS, X - address = this.ABS_X(); - this.Set(address, this.Decrement(this.Get(address))); - break; - case 0x3A: // DEC A - this.A = this.Decrement(this.A); - break; - case 0xCA: // DEX - this.X = this.Decrement(this.X); - break; - case 0x88: // DEY - this.Y = this.Decrement(this.Y); - break; - - case 0xE6: // INC ZP - address = this.ZP(); - this.Set(address, this.Increment(this.Get(address))); - break; - case 0xF6: // INC ZP, X - address = this.ZP_X(); - this.Set(address, this.Increment(this.Get(address))); - break; - case 0xEE: // INC ABS - address = this.ABS(); - this.Set(address, this.Increment(this.Get(address))); - break; - case 0xFE: // INC ABS, X - address = this.ABS_X(); - this.Set(address, this.Increment(this.Get(address))); - break; - case 0x1A: // INC A - this.A = this.Increment(this.A); - break; - case 0xE8: // INX - this.X = this.Increment(this.X); - break; - case 0xC8: // INY - this.Y = this.Increment(this.Y); - break; - - case 0x48: // PHA - this.Push(this.A); - this.ClearTFlag(); - break; - case 0x08: // PHP - this.Push(this.P); - this.ClearTFlag(); - break; - case 0xDA: // PHX - this.Push(this.X); - this.ClearTFlag(); - break; - case 0x5A: // PHY - this.Push(this.Y); - this.ClearTFlag(); - break; - - case 0x68: // PLA - this.A = this.Pull(); - this.SetNZFlag(this.A); - this.ClearTFlag(); - break; - case 0x28: // PLP - this.P = this.Pull(); - break; - case 0xFA: // PLX - this.X = this.Pull(); - this.SetNZFlag(this.X); - this.ClearTFlag(); - break; - case 0x7A: // PLY - this.Y = this.Pull(); - this.SetNZFlag(this.Y); - this.ClearTFlag(); - break; - - case 0x07: // RMB0 - this.RMBi(0); - break; - case 0x17: // RMB1 - this.RMBi(1); - break; - case 0x27: // RMB2 - this.RMBi(2); - break; - case 0x37: // RMB3 - this.RMBi(3); - break; - case 0x47: // RMB4 - this.RMBi(4); - break; - case 0x57: // RMB5 - this.RMBi(5); - break; - case 0x67: // RMB6 - this.RMBi(6); - break; - case 0x77: // RMB7 - this.RMBi(7); - break; - - case 0x87: // SMB0 - this.SMBi(0); - break; - case 0x97: // SMB1 - this.SMBi(1); - break; - case 0xA7: // SMB2 - this.SMBi(2); - break; - case 0xB7: // SMB3 - this.SMBi(3); - break; - case 0xC7: // SMB4 - this.SMBi(4); - break; - case 0xD7: // SMB5 - this.SMBi(5); - break; - case 0xE7: // SMB6 - this.SMBi(6); - break; - case 0xF7: // SMB7 - this.SMBi(7); - break; - - case 0x22: // SAX - tmp = this.A; - this.A = this.X; - this.X = tmp; - this.ClearTFlag(); - break; - case 0x42: // SAY - tmp = this.A; - this.A = this.Y; - this.Y = tmp; - this.ClearTFlag(); - break; - case 0x02: // SXY - tmp = this.X; - this.X = this.Y; - this.Y = tmp; - this.ClearTFlag(); - break; - - case 0xAA: // TAX - this.X = this.A; - this.SetNZFlag(this.X); - this.ClearTFlag(); - break; - case 0xA8: // TAY - this.Y = this.A; - this.SetNZFlag(this.Y); - this.ClearTFlag(); - break; - case 0xBA: // TSX - this.X = this.S; - this.SetNZFlag(this.X); - this.ClearTFlag(); - break; - case 0x8A: // TXA - this.A = this.X; - this.SetNZFlag(this.A); - this.ClearTFlag(); - break; - case 0x9A: // TXS - this.S = this.X; - this.ClearTFlag(); - break; - case 0x98: // TYA - this.A = this.Y; - this.SetNZFlag(this.A); - this.ClearTFlag(); - break; - - case 0x89: // BIT IMM - this.BIT(this.PC + 1); - break; - case 0x24: // BIT ZP - this.BIT(this.ZP()); - break; - case 0x34: // BIT ZP, X - this.BIT(this.ZP_X()); - break; - case 0x2C: // BIT ABS - this.BIT(this.ABS()); - break; - case 0x3C: // BIT ABS, X - this.BIT(this.ABS_X()); - break; - - case 0x83: // TST IMM ZP - this.TST(this.PC + 1, 0x2000 | this.Get(this.PC + 2)); - break; - case 0xA3: // TST IMM ZP, X - this.TST(this.PC + 1, 0x2000 | ((this.Get(this.PC + 2) + this.X) & 0xFF)); - break; - case 0x93: // TST IMM ABS - this.TST(this.PC + 1, this.Get16(this.PC + 2)); - break; - case 0xB3: // TST IMM ABS, X - this.TST(this.PC + 1, (this.Get16(this.PC + 2) + this.X) & 0xFFFF); - break; - - case 0x14: // TRB ZP - this.TRB(this.ZP()) - break; - case 0x1C: // TRB ABS - this.TRB(this.ABS()) - break; - - case 0x04: // TSB ZP - this.TSB(this.ZP()) - break; - case 0x0C: // TSB ABS - this.TSB(this.ABS()) - break; - - case 0xA9: // LDA IMM - this.A = this.Load(this.PC + 1); - break; - case 0xA5: // LDA ZP - this.A = this.Load(this.ZP()); - break; - case 0xB5: // LDA ZP, X - this.A = this.Load(this.ZP_X()); - break; - case 0xB2: // LDA (IND) - this.A = this.Load(this.IND()); - break; - case 0xA1: // LDA (IND, X) - this.A = this.Load(this.IND_X()); - break; - case 0xB1: // LDA (IND), Y - this.A = this.Load(this.IND_Y()); - break; - case 0xAD: // LDA ABS - this.A = this.Load(this.ABS()); - break; - case 0xBD: // LDA ABS, X - this.A = this.Load(this.ABS_X()); - break; - case 0xB9: // LDA ABS, Y - this.A = this.Load(this.ABS_Y()); - break; - case 0xA2: // LDX IMM - this.X = this.Load(this.PC + 1); - break; - case 0xA6: // LDX ZP - this.X = this.Load(this.ZP()); - break; - case 0xB6: // LDX ZP, Y - this.X = this.Load(this.ZP_Y()); - break; - case 0xAE: // LDX ABS - this.X = this.Load(this.ABS()); - break; - case 0xBE: // LDX ABS, Y - this.X = this.Load(this.ABS_Y()); - break; - case 0xA0: // LDY IMM - this.Y = this.Load(this.PC + 1); - break; - case 0xA4: // LDY ZP - this.Y = this.Load(this.ZP()); - break; - case 0xB4: // LDY ZP, X - this.Y = this.Load(this.ZP_X()); - break; - case 0xAC: // LDY ABS - this.Y = this.Load(this.ABS()); - break; - case 0xBC: // LDY ABS, X - this.Y = this.Load(this.ABS_X()); - break; - - case 0x85: // STA ZP - this.Store(this.ZP(), this.A); - break; - case 0x95: // STA ZP, X - this.Store(this.ZP_X(), this.A); - break; - case 0x92: // STA (IND) - this.Store(this.IND(), this.A); - break; - case 0x81: // STA (IND, X) - this.Store(this.IND_X(), this.A); - break; - case 0x91: // STA (IND), Y - this.Store(this.IND_Y(), this.A); - break; - case 0x8D: // STA ABS - this.Store(this.ABS(), this.A); - break; - case 0x9D: // STA ABS, X - this.Store(this.ABS_X(), this.A); - break; - case 0x99: // STA ABS, Y - this.Store(this.ABS_Y(), this.A); - break; - case 0x86: // STX ZP - this.Store(this.ZP(), this.X); - break; - case 0x96: // STX ZP, Y - this.Store(this.ZP_Y(), this.X); - break; - case 0x8E: // STX ABS - this.Store(this.ABS(), this.X); - break; - case 0x84: // STY ZP - this.Store(this.ZP(), this.Y); - break; - case 0x94: // STY ZP, X - this.Store(this.ZP_X(), this.Y); - break; - case 0x8C: // STY ABS - this.Store(this.ABS(), this.Y); - break; - case 0x64: // STZ ZP - this.Store(this.ZP(), 0x00); - break; - case 0x74: // STZ ZP, X - this.Store(this.ZP_X(), 0x00); - break; - case 0x9C: // STZ ABS - this.Store(this.ABS(), 0x00); - break; - case 0x9E: // STZ ABS, X - this.Store(this.ABS_X(), 0x00); - break; - - case 0xEA: // NOP - this.ClearTFlag(); - break; - - case 0x03: // ST0 - this.SetVDCRegister(this.Get(this.PC + 1), this.VDCSelect); - this.ClearTFlag(); - break; - case 0x13: // ST1 - this.SetVDCLow(this.Get(this.PC + 1), this.VDCSelect); - this.ClearTFlag(); - break; - case 0x23: // ST2 - this.SetVDCHigh(this.Get(this.PC + 1), this.VDCSelect); - this.ClearTFlag(); - break; - - case 0x53: // TAMi - data = this.Get(this.PC + 1); - bit = 0x01; - if(data == 0x00) - data = this.MPRSelect; - else - this.MPRSelect = data; - for(i=0; i<8; i++) - if((data & (bit << i)) != 0x00) - this.MPR[i] = this.A << 13; - break; - case 0x43: // TMAi - data = this.Get(this.PC + 1); - bit = 0x01; - if(data == 0x00) - data = this.MPRSelect; - else - this.MPRSelect = data; - for(i=0; i<8; i++) - if((data & (bit << i)) != 0x00) - this.A = this.MPR[i] >>> 13; - break; - - case 0xF3: // TAI - if(this.TransferLen == 0) { - this.TransferSrc = this.Get16(this.PC + 1); - this.TransferDist = this.Get16(this.PC + 3); - this.TransferLen = this.Get16(this.PC + 5); - this.TransferAlt = 1; - this.ProgressClock = 17; - } - - this.Set(this.TransferDist, this.Get(this.TransferSrc)); - this.TransferSrc = (this.TransferSrc + this.TransferAlt) & 0xFFFF; - this.TransferDist = (this.TransferDist + 1) & 0xFFFF; - this.TransferLen = (this.TransferLen - 1) & 0xFFFF; - this.TransferAlt = this.TransferAlt == 1 ? -1 : 1; - this.ProgressClock += 6; - - if(this.TransferLen == 0) { - this.ClearTFlag(); - this.PC += 7; - } - break; - case 0xC3: // TDD - if(this.TransferLen == 0) { - this.TransferSrc = this.Get16(this.PC + 1); - this.TransferDist = this.Get16(this.PC + 3); - this.TransferLen = this.Get16(this.PC + 5); - this.ProgressClock = 17; - } - - this.Set(this.TransferDist, this.Get(this.TransferSrc)); - this.TransferSrc = (this.TransferSrc - 1) & 0xFFFF; - this.TransferDist = (this.TransferDist - 1) & 0xFFFF; - this.TransferLen = (this.TransferLen - 1) & 0xFFFF; - this.ProgressClock += 6; - - if(this.TransferLen == 0) { - this.ClearTFlag(); - this.PC += 7; - } - break; - case 0xE3: // TIA - if(this.TransferLen == 0) { - this.TransferSrc = this.Get16(this.PC + 1); - this.TransferDist = this.Get16(this.PC + 3); - this.TransferLen = this.Get16(this.PC + 5); - this.TransferAlt = 1; - this.ProgressClock = 17; - } - - this.Set(this.TransferDist, this.Get(this.TransferSrc)); - this.TransferSrc = (this.TransferSrc + 1) & 0xFFFF; - this.TransferDist = (this.TransferDist + this.TransferAlt) & 0xFFFF; - this.TransferLen = (this.TransferLen - 1) & 0xFFFF; - this.TransferAlt = this.TransferAlt == 1 ? -1 : 1; - this.ProgressClock += 6; - - if(this.TransferLen == 0) { - this.ClearTFlag(); - this.PC += 7; - } - break; - case 0x73: // TII - if(this.TransferLen == 0) { - this.TransferSrc = this.Get16(this.PC + 1); - this.TransferDist = this.Get16(this.PC + 3); - this.TransferLen = this.Get16(this.PC + 5); - this.ProgressClock = 17; - } - - this.Set(this.TransferDist, this.Get(this.TransferSrc)); - this.TransferSrc = (this.TransferSrc + 1) & 0xFFFF; - this.TransferDist = (this.TransferDist + 1) & 0xFFFF; - this.TransferLen = (this.TransferLen - 1) & 0xFFFF; - this.ProgressClock += 6; - - if(this.TransferLen == 0) { - this.ClearTFlag(); - this.PC += 7; - } - - break; - case 0xD3: // TIN - if(this.TransferLen == 0) { - this.TransferSrc = this.Get16(this.PC + 1); - this.TransferDist = this.Get16(this.PC + 3); - this.TransferLen = this.Get16(this.PC + 5); - this.ProgressClock = 17; - } - - this.Set(this.TransferDist, this.Get(this.TransferSrc)); - this.TransferSrc = (this.TransferSrc + 1) & 0xFFFF; - this.TransferLen = (this.TransferLen - 1) & 0xFFFF; - this.ProgressClock += 6; - - if(this.TransferLen == 0) { - this.ClearTFlag(); - this.PC += 7; - } - break; - - case 0xD4: // CSH - this.ClearTFlag(); - this.CPUBaseClock = this.BaseClock7; - break; - case 0x54: // CSL - this.ClearTFlag(); - this.CPUBaseClock = this.BaseClock1; - break; - default: - this.ClearTFlag();//NOP - break; - } - this.PC += this.OpBytes[op]; - this.ProgressClock = (this.ProgressClock + this.OpCycles[op]) * this.CPUBaseClock; - } - - Adder(address, neg) { - let data0; - let data1 = this.Get(address); - - if(!neg && (this.P & this.TFlag) == this.TFlag) { - this.ProgressClock = 3; - data0 = this.Get(0x2000 | this.X); - } else - data0 = this.A; - - if(neg) - data1 = ~data1 & 0xFF; - - let carry = this.P & 0x01; - let tmp = data0 + data1 + carry; - - if((this.P & this.DFlag) == 0x00) { - if((((~data0 & ~data1 & tmp) | (data0 & data1 & ~tmp)) & 0x80) == 0x80) - this.SetVFlag(); - else - this.ClearVFlag(); - } else { - this.ProgressClock += 1; - if(neg) { - if((tmp & 0x0F) > 0x09) - tmp -= 0x06; - if((tmp & 0xF0) > 0x90) - tmp -= 0x60; - } else { - if(((data0 & 0x0F) + (data1 & 0x0F) + carry) > 0x09) - tmp += 0x06; - if((tmp & 0x1F0) > 0x90) - tmp += 0x60; - } - } - - if(tmp > 0xFF) - this.SetCFlag(); - else - this.ClearCFlag(); - - tmp &= 0xFF; - this.SetNZFlag(tmp); - - if(!neg && (this.P & this.TFlag) == this.TFlag) - this.Set(0x2000 | this.X, tmp); - else - this.A = tmp; - - this.ClearTFlag(); - } - - - ADC(address) { - this.Adder(address, false); - } - - - SBC(address) { - this.Adder(address, true); - } - - - AND(address) { - let data0; - let data1 = this.Get(address); - - if((this.P & this.TFlag) == 0x00) { - data0 = this.A; - } else { - this.ProgressClock = 3; - data0 = this.Get(0x2000 | this.X); - } - - let tmp = data0 & data1; - this.SetNZFlag(tmp); - - if((this.P & this.TFlag) == 0x00) - this.A = tmp; - else - this.Set(0x2000 | this.X, tmp); - - this.ClearTFlag(); - } - - - EOR(address) { - let data0; - let data1 = this.Get(address); - - if((this.P & this.TFlag) == 0x00) { - data0 = this.A; - } else { - this.ProgressClock = 3; - data0 = this.Get(0x2000 | this.X); - } - - let tmp = data0 ^ data1; - this.SetNZFlag(tmp); - - if((this.P & this.TFlag) == 0x00) - this.A = tmp; - else - this.Set(0x2000 | this.X, tmp); - - this.ClearTFlag(); - } - - - ORA(address) { - let data0; - let data1 = this.Get(address); - - if((this.P & this.TFlag) == 0x00) { - data0 = this.A; - } else { - this.ProgressClock = 3; - data0 = this.Get(0x2000 | this.X); - } - - let tmp = data0 | data1; - this.SetNZFlag(tmp); - - if((this.P & this.TFlag) == 0x00) - this.A = tmp; - else - this.Set(0x2000 | this.X, tmp); - - this.ClearTFlag(); - } - - - ASL(data) { - data <<= 1; - if(data > 0xFF) - this.SetCFlag(); - else - this.ClearCFlag(); + constructor() { + /* ***************** */ + /* **** Setting **** */ + /* ***************** */ + this.SuperGrafx = false; + this.CountryTypePCE = 0x40; + this.CountryTypeTG16 = 0x00; + this.CountryType = this.CountryTypePCE; + this.GamePadButton6 = false; + this.MultiTap = false; + + /* ******************* */ + /* **** Construct **** */ + /* ******************* */ + this.EtcConstruct(); + this.CPUConstruct(); + this.StorageConstruct(); + this.VCEConstruct(); + this.VPCConstruct(); + this.VDCConstruct(); + this.SoundConstruct(); + this.PSGConstruct(); + this.TimerConstruct(); + this.JoystickConstruct(); + } + + + /* ************* */ + /* **** ETC **** */ + /* ************* */ + EtcConstruct() { + this.TimerID = null; + this.MainCanvas = null; + this.Ctx = null; + this.ImageData = null; + } + + + UpdateAnimationFrame() { + this.TimerID = window.requestAnimationFrame(this.UpdateAnimationFrame.bind(this)); + this.Run(); + } + + + CancelAnimationFrame() { + window.cancelAnimationFrame(this.TimerID); + this.TimerID = null; + } + + + Pause() { + if (this.TimerID != null) { + this.JoystickEventRelease(); + this.CancelAnimationFrame(); + } + } + + + Start() { + if (this.TimerID == null) { + this.JoystickEventInit(); + this.UpdateAnimationFrame(); + } + } + + + Run() { + this.CheckGamePad(); + this.DrawFlag = false; + while (!this.DrawFlag) { + this.CPURun(); + this.VDCRun(); + this.TimerRun(); + this.PSGRun(); + } + } + + + Reset() { + this.StorageReset(); + this.Mapper.Init(); + this.CPUInit(); + this.VCEInit(); + this.VPCInit(); + this.VDCInit(); + this.TimerInit(); + this.JoystickInit(); + this.PSGInit(); + this.CPUReset(); + } + + + Init() { + this.StorageInit(); + this.CPUInit(); + this.VCEInit(); + this.VPCInit(); + this.VDCInit(); + this.TimerInit(); + this.JoystickInit(); + this.PSGInit(); + } + + + SetCanvas(canvas: HTMLCanvasElement) { + this.MainCanvas = canvas; + if (!this.MainCanvas.getContext) + return false; + + this.Ctx = this.MainCanvas.getContext("2d"); + this.ImageData = this.Ctx.createImageData(this.MainCanvas.width, this.MainCanvas.height); // this.ScreenWidthMAX, this.ScreenHeightMAX); + for (let i = 0; i < this.MainCanvas.width * this.MainCanvas.height * 4; i += 4) { + this.ImageData.data[i] = 0; + this.ImageData.data[i + 1] = 0; + this.ImageData.data[i + 2] = 0; + this.ImageData.data[i + 3] = 255; + } + this.Ctx.putImageData(this.ImageData, 0, 0); + + return true; + } + + /* ************* */ + /* **** CPU **** */ + /* ************* */ + CPUConstruct() { + this.OpCycles = [ + 8, 7, 3, 4, 6, 4, 6, 7, 3, 2, 2, 2, 7, 5, 7, 6,// 0x00 + 2, 7, 7, 4, 6, 4, 6, 7, 2, 5, 2, 2, 7, 5, 7, 6,// 0x10 + 7, 7, 3, 4, 4, 4, 6, 7, 3, 2, 2, 2, 5, 5, 7, 6,// 0x20 + 2, 7, 7, 2, 4, 4, 6, 7, 2, 5, 2, 2, 5, 5, 7, 6,// 0x30 + 7, 7, 3, 4, 8, 4, 6, 7, 3, 2, 2, 2, 4, 5, 7, 6,// 0x40 + 2, 7, 7, 5, 2, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,// 0x50 + 7, 7, 2, 2, 4, 4, 6, 7, 3, 2, 2, 2, 7, 5, 7, 6,// 0x60 + 2, 7, 7, 0, 4, 4, 6, 7, 2, 5, 3, 2, 7, 5, 7, 6,// 0x70 + 4, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,// 0x80 + 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,// 0x90 + 2, 7, 2, 7, 4, 4, 4, 7, 2, 2, 2, 2, 5, 5, 5, 6,// 0xA0 + 2, 7, 7, 8, 4, 4, 4, 7, 2, 5, 2, 2, 5, 5, 5, 6,// 0xB0 + 2, 7, 2, 0, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,// 0xC0 + 2, 7, 7, 0, 2, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6,// 0xD0 + 2, 7, 2, 0, 4, 4, 6, 7, 2, 2, 2, 2, 5, 5, 7, 6,// 0xE0 + 2, 7, 7, 0, 2, 4, 6, 7, 2, 5, 3, 2, 2, 5, 7, 6];//0xF0 + + this.OpBytes = [ + 0, 2, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 0,// 0x00 + 0, 2, 2, 2, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 0,// 0x10 + 0, 2, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 0,// 0x20 + 0, 2, 2, 1, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 0,// 0x30 + 0, 2, 1, 2, 0, 2, 2, 2, 1, 2, 1, 1, 0, 3, 3, 0,// 0x40 + 0, 2, 2, 2, 1, 2, 2, 2, 1, 3, 1, 1, 1, 3, 3, 0,// 0x50 + 0, 2, 1, 1, 2, 2, 2, 2, 1, 2, 1, 1, 0, 3, 3, 0,// 0x60 + 0, 2, 2, 0, 2, 2, 2, 2, 1, 3, 1, 1, 0, 3, 3, 0,// 0x70 + 0, 2, 1, 3, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 0,// 0x80 + 0, 2, 2, 4, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 0,// 0x90 + 2, 2, 2, 3, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 0,// 0xA0 + 0, 2, 2, 4, 2, 2, 2, 2, 1, 3, 1, 1, 3, 3, 3, 0,// 0xB0 + 2, 2, 1, 0, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 0,// 0xC0 + 0, 2, 2, 0, 1, 2, 2, 2, 1, 3, 1, 1, 1, 3, 3, 0,// 0xD0 + 2, 2, 1, 0, 2, 2, 2, 2, 1, 2, 1, 1, 3, 3, 3, 0,// 0xE0 + 0, 2, 2, 0, 1, 2, 2, 2, 1, 3, 1, 1, 1, 3, 3, 0];//0xF0 + + this.A = 0; + this.X = 0; + this.Y = 0; + this.PC = 0; + this.S = 0; + this.P = 0; + + this.NZCacheTable = new Uint8Array(0x100); + this.NZCacheTable = this.NZCacheTable.map((d, i) => { return i & 0x80; }); + this.NZCacheTable[0x00] = 0x02; + + this.NFlag = 0x80; + this.VFlag = 0x40; + this.TFlag = 0x20; + this.BFlag = 0x10; + this.DFlag = 0x08; + this.IFlag = 0x04; + this.ZFlag = 0x02; + this.CFlag = 0x01; + + this.TIQFlag = 0x04; + this.IRQ1Flag = 0x02; + this.IRQ2Flag = 0x01; + + this.ProgressClock = 0; + this.CPUBaseClock = 0; + + this.BaseClock1 = 12; + this.BaseClock3 = 6; + this.BaseClock5 = 4; + this.BaseClock7 = 3; + this.BaseClock10 = 2; + + this.TransferSrc = 0; + this.TransferDist = 0; + this.TransferLen = 0; + this.TransferAlt = 0; + } + + + CPUReset() { + this.TransferSrc = 0; + this.TransferDist = 0; + this.TransferLen = 0; + this.TransferAlt = 0; + + this.CPUBaseClock = this.BaseClock1; + + this.SetIFlag(); + this.PC = this.Get16(0xFFFE); + } + + + CPUInit() { + this.A = 0; + this.X = 0; + this.Y = 0; + this.PC = 0; + this.S = 0; + this.P = 0x00; + + this.ProgressClock = 0; + this.CPUBaseClock = this.BaseClock1; + + this.TransferSrc = 0; + this.TransferDist = 0; + this.TransferLen = 0; + this.TransferAlt = 0; + + this.LastInt = 0x00; + } + + + CPURun() { + this.ProgressClock = 0; + + let tmp = this.LastInt; + this.LastInt = (this.P & this.IFlag) == 0x00 ? this.GetIntStatus() : 0x00; + + if (tmp != 0x00 && this.TransferLen == 0) { + this.LastInt = 0x00; + + if ((tmp & this.TIQFlag) == this.TIQFlag) {//TIQ + this.Push(this.PCH()); + this.Push(this.PCL()); + this.Push(this.P); + this.P = 0x04; + this.PC = this.Get16(0xFFFA); + } else if ((tmp & this.IRQ1Flag) == this.IRQ1Flag) {//IRQ1 + this.Push(this.PCH()); + this.Push(this.PCL()); + this.Push(this.P); + this.P = 0x04; + this.PC = this.Get16(0xFFF8); + } else if ((tmp & this.IRQ2Flag) == this.IRQ2Flag) {//IRQ2 + this.Push(this.PCH()); + this.Push(this.PCL()); + this.Push(this.P); + this.SetIFlag(); + this.PC = this.Get16(0xFFF6); + } + this.ProgressClock = 8 * this.CPUBaseClock; + } else + this.OpExec(); + } + + + OpExec() { + let address; + let tmp; + let data; + let bit; + let i; + + let op = this.Get(this.PC); + + switch (op) { + case 0x69: // ADC IMM + this.ADC(this.PC + 1); + break; + case 0x65: // ADC ZP + this.ADC(this.ZP()); + break; + case 0x75: // ADC ZP, X + this.ADC(this.ZP_X()); + break; + case 0x72: // ADC (IND) + this.ADC(this.IND()); + break; + case 0x61: // ADC (IND, X) + this.ADC(this.IND_X()); + break; + case 0x71: // ADC (IND), Y + this.ADC(this.IND_Y()); + break; + case 0x6D: // ADC ABS + this.ADC(this.ABS()); + break; + case 0x7D: // ADC ABS, X + this.ADC(this.ABS_X()); + break; + case 0x79: // ADC ABS, Y + this.ADC(this.ABS_Y()); + break; + + case 0xE9: // SBC IMM + this.SBC(this.PC + 1); + break; + case 0xE5: // SBC ZP + this.SBC(this.ZP()); + break; + case 0xF5: // SBC ZP, X + this.SBC(this.ZP_X()); + break; + case 0xF2: // SBC (IND) + this.SBC(this.IND()); + break; + case 0xE1: // SBC (IND, X) + this.SBC(this.IND_X()); + break; + case 0xF1: // SBC (IND), Y + this.SBC(this.IND_Y()); + break; + case 0xED: // SBC ABS + this.SBC(this.ABS()); + break; + case 0xFD: // SBC ABS, X + this.SBC(this.ABS_X()); + break; + case 0xF9: // SBC ABS, Y + this.SBC(this.ABS_Y()); + break; + + case 0x29: // AND IMM + this.AND(this.PC + 1); + break; + case 0x25: // AND ZP + this.AND(this.ZP()); + break; + case 0x35: // AND ZP, X + this.AND(this.ZP_X()); + break; + case 0x32: // AND (IND) + this.AND(this.IND()); + break; + case 0x21: // AND (IND, X) + this.AND(this.IND_X()); + break; + case 0x31: // AND (IND), Y + this.AND(this.IND_Y()); + break; + case 0x2D: // AND ABS + this.AND(this.ABS()); + break; + case 0x3D: // AND ABS, X + this.AND(this.ABS_X()); + break; + case 0x39: // AND ABS, Y + this.AND(this.ABS_Y()); + break; + + case 0x49: // EOR IMM + this.EOR(this.PC + 1); + break; + case 0x45: // EOR ZP + this.EOR(this.ZP()); + break; + case 0x55: // EOR ZP, X + this.EOR(this.ZP_X()); + break; + case 0x52: // EOR (IND) + this.EOR(this.IND()); + break; + case 0x41: // EOR (IND, X) + this.EOR(this.IND_X()); + break; + case 0x51: // EOR (IND), Y + this.EOR(this.IND_Y()); + break; + case 0x4D: // EOR ABS + this.EOR(this.ABS()); + break; + case 0x5D: // EOR ABS, X + this.EOR(this.ABS_X()); + break; + case 0x59: // EOR ABS, Y + this.EOR(this.ABS_Y()); + break; + + case 0x09: // ORA IMM + this.ORA(this.PC + 1); + break; + case 0x05: // ORA ZP + this.ORA(this.ZP()); + break; + case 0x15: // ORA ZP, X + this.ORA(this.ZP_X()); + break; + case 0x12: // ORA (IND) + this.ORA(this.IND()); + break; + case 0x01: // ORA (IND, X) + this.ORA(this.IND_X()); + break; + case 0x11: // ORA (IND), Y + this.ORA(this.IND_Y()); + break; + case 0x0D: // ORA ABS + this.ORA(this.ABS()); + break; + case 0x1D: // ORA ABS, X + this.ORA(this.ABS_X()); + break; + case 0x19: // ORA ABS, Y + this.ORA(this.ABS_Y()); + break; + + case 0x06: // ASL ZP + address = this.ZP(); + this.Set(address, this.ASL(this.Get(address))); + break; + case 0x16: // ASL ZP, X + address = this.ZP_X(); + this.Set(address, this.ASL(this.Get(address))); + break; + case 0x0E: // ASL ABS + address = this.ABS(); + this.Set(address, this.ASL(this.Get(address))); + break; + case 0x1E: // ASL ABS, X + address = this.ABS_X(); + this.Set(address, this.ASL(this.Get(address))); + break; + case 0x0A: // ASL A + this.A = this.ASL(this.A); + break; + + case 0x46: // LSR ZP + address = this.ZP(); + this.Set(address, this.LSR(this.Get(address))); + break; + case 0x56: // LSR ZP, X + address = this.ZP_X(); + this.Set(address, this.LSR(this.Get(address))); + break; + case 0x4E: // LSR ABS + address = this.ABS(); + this.Set(address, this.LSR(this.Get(address))); + break; + case 0x5E: // LSR ABS, X + address = this.ABS_X(); + this.Set(address, this.LSR(this.Get(address))); + break; + case 0x4A: // LSR A + this.A = this.LSR(this.A); + break; + + case 0x26: // ROL ZP + address = this.ZP(); + this.Set(address, this.ROL(this.Get(address))); + break; + case 0x36: // ROL ZP, X + address = this.ZP_X(); + this.Set(address, this.ROL(this.Get(address))); + break; + case 0x2E: // ROL ABS + address = this.ABS(); + this.Set(address, this.ROL(this.Get(address))); + break; + case 0x3E: // ROL ABS, X + address = this.ABS_X(); + this.Set(address, this.ROL(this.Get(address))); + break; + case 0x2A: // ROL A + this.A = this.ROL(this.A); + break; + + case 0x66: // ROR ZP + address = this.ZP(); + this.Set(address, this.ROR(this.Get(address))); + break; + case 0x76: // ROR ZP, X + address = this.ZP_X(); + this.Set(address, this.ROR(this.Get(address))); + break; + case 0x6E: // ROR ABS + address = this.ABS(); + this.Set(address, this.ROR(this.Get(address))); + break; + case 0x7E: // ROR ABS, X + address = this.ABS_X(); + this.Set(address, this.ROR(this.Get(address))); + break; + case 0x6A: // ROR A + this.A = this.ROR(this.A); + break; + + case 0x0F: // BBR0 + this.BBRi(0); + break; + case 0x1F: // BBR1 + this.BBRi(1); + break; + case 0x2F: // BBR2 + this.BBRi(2); + break; + case 0x3F: // BBR3 + this.BBRi(3); + break; + case 0x4F: // BBR4 + this.BBRi(4); + break; + case 0x5F: // BBR5 + this.BBRi(5); + break; + case 0x6F: // BBR6 + this.BBRi(6); + break; + case 0x7F: // BBR7 + this.BBRi(7); + break; + + case 0x8F: // BBS0 + this.BBSi(0); + break; + case 0x9F: // BBS1 + this.BBSi(1); + break; + case 0xAF: // BBS2 + this.BBSi(2); + break; + case 0xBF: // BBS3 + this.BBSi(3); + break; + case 0xCF: // BBS4 + this.BBSi(4); + break; + case 0xDF: // BBS5 + this.BBSi(5); + break; + case 0xEF: // BBS6 + this.BBSi(6); + break; + case 0xFF: // BBS7 + this.BBSi(7); + break; + + case 0x90: // BCC + this.Branch((this.P & this.CFlag) == 0x00, 1); + break; + case 0xB0: // BCS + this.Branch((this.P & this.CFlag) == this.CFlag, 1); + break; + case 0xD0: // BNE + this.Branch((this.P & this.ZFlag) == 0x00, 1); + break; + case 0xF0: // BEQ + this.Branch((this.P & this.ZFlag) == this.ZFlag, 1); + break; + case 0x10: // BPL + this.Branch((this.P & this.NFlag) == 0x00, 1); + break; + case 0x30: // BMI + this.Branch((this.P & this.NFlag) == this.NFlag, 1); + break; + case 0x50: // BVC + this.Branch((this.P & this.VFlag) == 0x00, 1); + break; + case 0x70: // BVS + this.Branch((this.P & this.VFlag) == this.VFlag, 1); + break; + case 0x80: // BRA + this.Branch(true, 1); + break; + + case 0x44: // BSR + this.PC++; + this.Push(this.PCH()); + this.Push(this.PCL()); + this.Branch(true, 0); + break; + case 0x20: // JSR ABS + tmp = this.ABS(); + this.PC += 2; + this.Push(this.PCH()); + this.Push(this.PCL()); + this.PC = tmp; + this.ClearTFlag(); + break; + + case 0x40: // RTI + this.P = this.Pull(); + this.toPCL(this.Pull()); + this.toPCH(this.Pull()); + break; + case 0x60: // RTS + this.ClearTFlag(); + this.toPCL(this.Pull()); + this.toPCH(this.Pull()); + this.PC++; + break; + + case 0x4C: // JMP ABS + this.PC = this.ABS(); + this.ClearTFlag(); + break; + case 0x6C: // JMP (ABS) + this.PC = this.ABS_IND(); + this.ClearTFlag(); + break; + case 0x7C: // JMP (ABS, X) + this.PC = this.ABS_X_IND(); + this.ClearTFlag(); + break; + + case 0x00: // BRK + this.PC += 2; + this.Push(this.PCH()); + this.Push(this.PCL()); + this.SetBFlag(); + this.Push(this.P); + this.ClearDFlag(); + this.ClearTFlag(); + this.SetIFlag(); + this.PC = this.Get16(0xFFF6); + break; + + case 0x62: // CLA + this.A = 0x00; + this.ClearTFlag(); + break; + case 0x82: // CLX + this.X = 0x00; + this.ClearTFlag(); + break; + case 0xC2: // CLY + this.Y = 0x00; + this.ClearTFlag(); + break; + + case 0x18: // CLC + this.ClearCFlag(); + this.ClearTFlag(); + break; + case 0xD8: // CLD + this.ClearDFlag(); + this.ClearTFlag(); + break; + case 0x58: // CLI + this.ClearIFlag(); + this.ClearTFlag(); + break; + case 0xB8: // CLV + this.ClearVFlag(); + this.ClearTFlag(); + break; + + case 0x38: // SEC + this.SetCFlag(); + this.ClearTFlag(); + break; + case 0xF8: // SED + this.SetDFlag(); + this.ClearTFlag(); + break; + case 0x78: // SEI + this.SetIFlag(); + this.ClearTFlag(); + break; + case 0xF4: // SET + this.SetTFlag(); + break; + + case 0xC9: // CMP IMM + this.Compare(this.A, this.PC + 1); + break; + case 0xC5: // CMP ZP + this.Compare(this.A, this.ZP()); + break; + case 0xD5: // CMP ZP, X + this.Compare(this.A, this.ZP_X()); + break; + case 0xD2: // CMP (IND) + this.Compare(this.A, this.IND()); + break; + case 0xC1: // CMP (IND, X) + this.Compare(this.A, this.IND_X()); + break; + case 0xD1: // CMP (IND), Y + this.Compare(this.A, this.IND_Y()); + break; + case 0xCD: // CMP ABS + this.Compare(this.A, this.ABS()); + break; + case 0xDD: // CMP ABS, X + this.Compare(this.A, this.ABS_X()); + break; + case 0xD9: // CMP ABS, Y + this.Compare(this.A, this.ABS_Y()); + break; + case 0xE0: // CPX IMM + this.Compare(this.X, this.PC + 1); + break; + case 0xE4: // CPX ZP + this.Compare(this.X, this.ZP()); + break; + case 0xEC: // CPX ABS + this.Compare(this.X, this.ABS()); + break; + case 0xC0: // CPY IMM + this.Compare(this.Y, this.PC + 1); + break; + case 0xC4: // CPY ZP + this.Compare(this.Y, this.ZP()); + break; + case 0xCC: // CPY ABS + this.Compare(this.Y, this.ABS()); + break; + + case 0xC6: // DEC ZP + address = this.ZP(); + this.Set(address, this.Decrement(this.Get(address))); + break; + case 0xD6: // DEC ZP, X + address = this.ZP_X(); + this.Set(address, this.Decrement(this.Get(address))); + break; + case 0xCE: // DEC ABS + address = this.ABS(); + this.Set(address, this.Decrement(this.Get(address))); + break; + case 0xDE: // DEC ABS, X + address = this.ABS_X(); + this.Set(address, this.Decrement(this.Get(address))); + break; + case 0x3A: // DEC A + this.A = this.Decrement(this.A); + break; + case 0xCA: // DEX + this.X = this.Decrement(this.X); + break; + case 0x88: // DEY + this.Y = this.Decrement(this.Y); + break; + + case 0xE6: // INC ZP + address = this.ZP(); + this.Set(address, this.Increment(this.Get(address))); + break; + case 0xF6: // INC ZP, X + address = this.ZP_X(); + this.Set(address, this.Increment(this.Get(address))); + break; + case 0xEE: // INC ABS + address = this.ABS(); + this.Set(address, this.Increment(this.Get(address))); + break; + case 0xFE: // INC ABS, X + address = this.ABS_X(); + this.Set(address, this.Increment(this.Get(address))); + break; + case 0x1A: // INC A + this.A = this.Increment(this.A); + break; + case 0xE8: // INX + this.X = this.Increment(this.X); + break; + case 0xC8: // INY + this.Y = this.Increment(this.Y); + break; + + case 0x48: // PHA + this.Push(this.A); + this.ClearTFlag(); + break; + case 0x08: // PHP + this.Push(this.P); + this.ClearTFlag(); + break; + case 0xDA: // PHX + this.Push(this.X); + this.ClearTFlag(); + break; + case 0x5A: // PHY + this.Push(this.Y); + this.ClearTFlag(); + break; + + case 0x68: // PLA + this.A = this.Pull(); + this.SetNZFlag(this.A); + this.ClearTFlag(); + break; + case 0x28: // PLP + this.P = this.Pull(); + break; + case 0xFA: // PLX + this.X = this.Pull(); + this.SetNZFlag(this.X); + this.ClearTFlag(); + break; + case 0x7A: // PLY + this.Y = this.Pull(); + this.SetNZFlag(this.Y); + this.ClearTFlag(); + break; + + case 0x07: // RMB0 + this.RMBi(0); + break; + case 0x17: // RMB1 + this.RMBi(1); + break; + case 0x27: // RMB2 + this.RMBi(2); + break; + case 0x37: // RMB3 + this.RMBi(3); + break; + case 0x47: // RMB4 + this.RMBi(4); + break; + case 0x57: // RMB5 + this.RMBi(5); + break; + case 0x67: // RMB6 + this.RMBi(6); + break; + case 0x77: // RMB7 + this.RMBi(7); + break; + + case 0x87: // SMB0 + this.SMBi(0); + break; + case 0x97: // SMB1 + this.SMBi(1); + break; + case 0xA7: // SMB2 + this.SMBi(2); + break; + case 0xB7: // SMB3 + this.SMBi(3); + break; + case 0xC7: // SMB4 + this.SMBi(4); + break; + case 0xD7: // SMB5 + this.SMBi(5); + break; + case 0xE7: // SMB6 + this.SMBi(6); + break; + case 0xF7: // SMB7 + this.SMBi(7); + break; + + case 0x22: // SAX + tmp = this.A; + this.A = this.X; + this.X = tmp; + this.ClearTFlag(); + break; + case 0x42: // SAY + tmp = this.A; + this.A = this.Y; + this.Y = tmp; + this.ClearTFlag(); + break; + case 0x02: // SXY + tmp = this.X; + this.X = this.Y; + this.Y = tmp; + this.ClearTFlag(); + break; + + case 0xAA: // TAX + this.X = this.A; + this.SetNZFlag(this.X); + this.ClearTFlag(); + break; + case 0xA8: // TAY + this.Y = this.A; + this.SetNZFlag(this.Y); + this.ClearTFlag(); + break; + case 0xBA: // TSX + this.X = this.S; + this.SetNZFlag(this.X); + this.ClearTFlag(); + break; + case 0x8A: // TXA + this.A = this.X; + this.SetNZFlag(this.A); + this.ClearTFlag(); + break; + case 0x9A: // TXS + this.S = this.X; + this.ClearTFlag(); + break; + case 0x98: // TYA + this.A = this.Y; + this.SetNZFlag(this.A); + this.ClearTFlag(); + break; + + case 0x89: // BIT IMM + this.BIT(this.PC + 1); + break; + case 0x24: // BIT ZP + this.BIT(this.ZP()); + break; + case 0x34: // BIT ZP, X + this.BIT(this.ZP_X()); + break; + case 0x2C: // BIT ABS + this.BIT(this.ABS()); + break; + case 0x3C: // BIT ABS, X + this.BIT(this.ABS_X()); + break; + + case 0x83: // TST IMM ZP + this.TST(this.PC + 1, 0x2000 | this.Get(this.PC + 2)); + break; + case 0xA3: // TST IMM ZP, X + this.TST(this.PC + 1, 0x2000 | ((this.Get(this.PC + 2) + this.X) & 0xFF)); + break; + case 0x93: // TST IMM ABS + this.TST(this.PC + 1, this.Get16(this.PC + 2)); + break; + case 0xB3: // TST IMM ABS, X + this.TST(this.PC + 1, (this.Get16(this.PC + 2) + this.X) & 0xFFFF); + break; + + case 0x14: // TRB ZP + this.TRB(this.ZP()) + break; + case 0x1C: // TRB ABS + this.TRB(this.ABS()) + break; + + case 0x04: // TSB ZP + this.TSB(this.ZP()) + break; + case 0x0C: // TSB ABS + this.TSB(this.ABS()) + break; + + case 0xA9: // LDA IMM + this.A = this.Load(this.PC + 1); + break; + case 0xA5: // LDA ZP + this.A = this.Load(this.ZP()); + break; + case 0xB5: // LDA ZP, X + this.A = this.Load(this.ZP_X()); + break; + case 0xB2: // LDA (IND) + this.A = this.Load(this.IND()); + break; + case 0xA1: // LDA (IND, X) + this.A = this.Load(this.IND_X()); + break; + case 0xB1: // LDA (IND), Y + this.A = this.Load(this.IND_Y()); + break; + case 0xAD: // LDA ABS + this.A = this.Load(this.ABS()); + break; + case 0xBD: // LDA ABS, X + this.A = this.Load(this.ABS_X()); + break; + case 0xB9: // LDA ABS, Y + this.A = this.Load(this.ABS_Y()); + break; + case 0xA2: // LDX IMM + this.X = this.Load(this.PC + 1); + break; + case 0xA6: // LDX ZP + this.X = this.Load(this.ZP()); + break; + case 0xB6: // LDX ZP, Y + this.X = this.Load(this.ZP_Y()); + break; + case 0xAE: // LDX ABS + this.X = this.Load(this.ABS()); + break; + case 0xBE: // LDX ABS, Y + this.X = this.Load(this.ABS_Y()); + break; + case 0xA0: // LDY IMM + this.Y = this.Load(this.PC + 1); + break; + case 0xA4: // LDY ZP + this.Y = this.Load(this.ZP()); + break; + case 0xB4: // LDY ZP, X + this.Y = this.Load(this.ZP_X()); + break; + case 0xAC: // LDY ABS + this.Y = this.Load(this.ABS()); + break; + case 0xBC: // LDY ABS, X + this.Y = this.Load(this.ABS_X()); + break; + + case 0x85: // STA ZP + this.Store(this.ZP(), this.A); + break; + case 0x95: // STA ZP, X + this.Store(this.ZP_X(), this.A); + break; + case 0x92: // STA (IND) + this.Store(this.IND(), this.A); + break; + case 0x81: // STA (IND, X) + this.Store(this.IND_X(), this.A); + break; + case 0x91: // STA (IND), Y + this.Store(this.IND_Y(), this.A); + break; + case 0x8D: // STA ABS + this.Store(this.ABS(), this.A); + break; + case 0x9D: // STA ABS, X + this.Store(this.ABS_X(), this.A); + break; + case 0x99: // STA ABS, Y + this.Store(this.ABS_Y(), this.A); + break; + case 0x86: // STX ZP + this.Store(this.ZP(), this.X); + break; + case 0x96: // STX ZP, Y + this.Store(this.ZP_Y(), this.X); + break; + case 0x8E: // STX ABS + this.Store(this.ABS(), this.X); + break; + case 0x84: // STY ZP + this.Store(this.ZP(), this.Y); + break; + case 0x94: // STY ZP, X + this.Store(this.ZP_X(), this.Y); + break; + case 0x8C: // STY ABS + this.Store(this.ABS(), this.Y); + break; + case 0x64: // STZ ZP + this.Store(this.ZP(), 0x00); + break; + case 0x74: // STZ ZP, X + this.Store(this.ZP_X(), 0x00); + break; + case 0x9C: // STZ ABS + this.Store(this.ABS(), 0x00); + break; + case 0x9E: // STZ ABS, X + this.Store(this.ABS_X(), 0x00); + break; + + case 0xEA: // NOP + this.ClearTFlag(); + break; + + case 0x03: // ST0 + this.SetVDCRegister(this.Get(this.PC + 1), this.VDCSelect); + this.ClearTFlag(); + break; + case 0x13: // ST1 + this.SetVDCLow(this.Get(this.PC + 1), this.VDCSelect); + this.ClearTFlag(); + break; + case 0x23: // ST2 + this.SetVDCHigh(this.Get(this.PC + 1), this.VDCSelect); + this.ClearTFlag(); + break; + + case 0x53: // TAMi + data = this.Get(this.PC + 1); + bit = 0x01; + if (data == 0x00) + data = this.MPRSelect; + else + this.MPRSelect = data; + for (i = 0; i < 8; i++) + if ((data & (bit << i)) != 0x00) + this.MPR[i] = this.A << 13; + break; + case 0x43: // TMAi + data = this.Get(this.PC + 1); + bit = 0x01; + if (data == 0x00) + data = this.MPRSelect; + else + this.MPRSelect = data; + for (i = 0; i < 8; i++) + if ((data & (bit << i)) != 0x00) + this.A = this.MPR[i] >>> 13; + break; + + case 0xF3: // TAI + if (this.TransferLen == 0) { + this.TransferSrc = this.Get16(this.PC + 1); + this.TransferDist = this.Get16(this.PC + 3); + this.TransferLen = this.Get16(this.PC + 5); + this.TransferAlt = 1; + this.ProgressClock = 17; + } + + this.Set(this.TransferDist, this.Get(this.TransferSrc)); + this.TransferSrc = (this.TransferSrc + this.TransferAlt) & 0xFFFF; + this.TransferDist = (this.TransferDist + 1) & 0xFFFF; + this.TransferLen = (this.TransferLen - 1) & 0xFFFF; + this.TransferAlt = this.TransferAlt == 1 ? -1 : 1; + this.ProgressClock += 6; + + if (this.TransferLen == 0) { + this.ClearTFlag(); + this.PC += 7; + } + break; + case 0xC3: // TDD + if (this.TransferLen == 0) { + this.TransferSrc = this.Get16(this.PC + 1); + this.TransferDist = this.Get16(this.PC + 3); + this.TransferLen = this.Get16(this.PC + 5); + this.ProgressClock = 17; + } + + this.Set(this.TransferDist, this.Get(this.TransferSrc)); + this.TransferSrc = (this.TransferSrc - 1) & 0xFFFF; + this.TransferDist = (this.TransferDist - 1) & 0xFFFF; + this.TransferLen = (this.TransferLen - 1) & 0xFFFF; + this.ProgressClock += 6; + + if (this.TransferLen == 0) { + this.ClearTFlag(); + this.PC += 7; + } + break; + case 0xE3: // TIA + if (this.TransferLen == 0) { + this.TransferSrc = this.Get16(this.PC + 1); + this.TransferDist = this.Get16(this.PC + 3); + this.TransferLen = this.Get16(this.PC + 5); + this.TransferAlt = 1; + this.ProgressClock = 17; + } + + this.Set(this.TransferDist, this.Get(this.TransferSrc)); + this.TransferSrc = (this.TransferSrc + 1) & 0xFFFF; + this.TransferDist = (this.TransferDist + this.TransferAlt) & 0xFFFF; + this.TransferLen = (this.TransferLen - 1) & 0xFFFF; + this.TransferAlt = this.TransferAlt == 1 ? -1 : 1; + this.ProgressClock += 6; + + if (this.TransferLen == 0) { + this.ClearTFlag(); + this.PC += 7; + } + break; + case 0x73: // TII + if (this.TransferLen == 0) { + this.TransferSrc = this.Get16(this.PC + 1); + this.TransferDist = this.Get16(this.PC + 3); + this.TransferLen = this.Get16(this.PC + 5); + this.ProgressClock = 17; + } + + this.Set(this.TransferDist, this.Get(this.TransferSrc)); + this.TransferSrc = (this.TransferSrc + 1) & 0xFFFF; + this.TransferDist = (this.TransferDist + 1) & 0xFFFF; + this.TransferLen = (this.TransferLen - 1) & 0xFFFF; + this.ProgressClock += 6; + + if (this.TransferLen == 0) { + this.ClearTFlag(); + this.PC += 7; + } + + break; + case 0xD3: // TIN + if (this.TransferLen == 0) { + this.TransferSrc = this.Get16(this.PC + 1); + this.TransferDist = this.Get16(this.PC + 3); + this.TransferLen = this.Get16(this.PC + 5); + this.ProgressClock = 17; + } + + this.Set(this.TransferDist, this.Get(this.TransferSrc)); + this.TransferSrc = (this.TransferSrc + 1) & 0xFFFF; + this.TransferLen = (this.TransferLen - 1) & 0xFFFF; + this.ProgressClock += 6; + + if (this.TransferLen == 0) { + this.ClearTFlag(); + this.PC += 7; + } + break; + + case 0xD4: // CSH + this.ClearTFlag(); + this.CPUBaseClock = this.BaseClock7; + break; + case 0x54: // CSL + this.ClearTFlag(); + this.CPUBaseClock = this.BaseClock1; + break; + default: + this.ClearTFlag();//NOP + break; + } + this.PC += this.OpBytes[op]; + this.ProgressClock = (this.ProgressClock + this.OpCycles[op]) * this.CPUBaseClock; + } + + Adder(address, neg) { + let data0; + let data1 = this.Get(address); + + if (!neg && (this.P & this.TFlag) == this.TFlag) { + this.ProgressClock = 3; + data0 = this.Get(0x2000 | this.X); + } else + data0 = this.A; + + if (neg) + data1 = ~data1 & 0xFF; + + let carry = this.P & 0x01; + let tmp = data0 + data1 + carry; + + if ((this.P & this.DFlag) == 0x00) { + if ((((~data0 & ~data1 & tmp) | (data0 & data1 & ~tmp)) & 0x80) == 0x80) + this.SetVFlag(); + else + this.ClearVFlag(); + } else { + this.ProgressClock += 1; + if (neg) { + if ((tmp & 0x0F) > 0x09) + tmp -= 0x06; + if ((tmp & 0xF0) > 0x90) + tmp -= 0x60; + } else { + if (((data0 & 0x0F) + (data1 & 0x0F) + carry) > 0x09) + tmp += 0x06; + if ((tmp & 0x1F0) > 0x90) + tmp += 0x60; + } + } + + if (tmp > 0xFF) + this.SetCFlag(); + else + this.ClearCFlag(); + + tmp &= 0xFF; + this.SetNZFlag(tmp); + + if (!neg && (this.P & this.TFlag) == this.TFlag) + this.Set(0x2000 | this.X, tmp); + else + this.A = tmp; + + this.ClearTFlag(); + } + + + ADC(address) { + this.Adder(address, false); + } + + + SBC(address) { + this.Adder(address, true); + } + + + AND(address) { + let data0; + let data1 = this.Get(address); + + if ((this.P & this.TFlag) == 0x00) { + data0 = this.A; + } else { + this.ProgressClock = 3; + data0 = this.Get(0x2000 | this.X); + } + + let tmp = data0 & data1; + this.SetNZFlag(tmp); + + if ((this.P & this.TFlag) == 0x00) + this.A = tmp; + else + this.Set(0x2000 | this.X, tmp); + + this.ClearTFlag(); + } + + + EOR(address) { + let data0; + let data1 = this.Get(address); + + if ((this.P & this.TFlag) == 0x00) { + data0 = this.A; + } else { + this.ProgressClock = 3; + data0 = this.Get(0x2000 | this.X); + } + + let tmp = data0 ^ data1; + this.SetNZFlag(tmp); + + if ((this.P & this.TFlag) == 0x00) + this.A = tmp; + else + this.Set(0x2000 | this.X, tmp); + + this.ClearTFlag(); + } + + + ORA(address) { + let data0; + let data1 = this.Get(address); + + if ((this.P & this.TFlag) == 0x00) { + data0 = this.A; + } else { + this.ProgressClock = 3; + data0 = this.Get(0x2000 | this.X); + } + + let tmp = data0 | data1; + this.SetNZFlag(tmp); + + if ((this.P & this.TFlag) == 0x00) + this.A = tmp; + else + this.Set(0x2000 | this.X, tmp); + + this.ClearTFlag(); + } + + + ASL(data) { + data <<= 1; + if (data > 0xFF) + this.SetCFlag(); + else + this.ClearCFlag(); - data &= 0xFF; - this.SetNZFlag(data); - this.ClearTFlag(); - return data; - } + data &= 0xFF; + this.SetNZFlag(data); + this.ClearTFlag(); + return data; + } - LSR(data) { - if((data & 0x01) == 0x01) - this.SetCFlag(); - else - this.ClearCFlag(); + LSR(data) { + if ((data & 0x01) == 0x01) + this.SetCFlag(); + else + this.ClearCFlag(); - data >>= 1; - this.SetNZFlag(data); - this.ClearTFlag(); - return data; - } + data >>= 1; + this.SetNZFlag(data); + this.ClearTFlag(); + return data; + } - - ROL(data) { - data = (data << 1) | (this.P & 0x01); - if(data > 0xFF) - this.SetCFlag(); - else - this.ClearCFlag(); - - data &= 0xFF; - this.SetNZFlag(data); - this.ClearTFlag(); - return data; - } + + ROL(data) { + data = (data << 1) | (this.P & 0x01); + if (data > 0xFF) + this.SetCFlag(); + else + this.ClearCFlag(); + + data &= 0xFF; + this.SetNZFlag(data); + this.ClearTFlag(); + return data; + } - ROR(data) { - let tmp = this.P & this.CFlag; - if((data & 0x01) == 0x01) - this.SetCFlag(); - else - this.ClearCFlag(); + ROR(data) { + let tmp = this.P & this.CFlag; + if ((data & 0x01) == 0x01) + this.SetCFlag(); + else + this.ClearCFlag(); - data = (data >> 1) | (tmp << 7); - this.SetNZFlag(data); - this.ClearTFlag(); - return data; - } + data = (data >> 1) | (tmp << 7); + this.SetNZFlag(data); + this.ClearTFlag(); + return data; + } - - BBRi(bit) { - let tmp = this.Get(this.ZP()); - tmp = (tmp >> bit) & 0x01; - this.Branch(tmp == 0, 2); - } - - - BBSi(bit) { - let tmp = this.Get(this.ZP()); - tmp = (tmp >> bit) & 0x01; - this.Branch(tmp == 1, 2); - } - - - Branch(status, adr) { - this.ClearTFlag(); - if(status) { - let tmp = this.Get(this.PC + adr); - if(tmp >= 0x80) - tmp |= 0xFF00; - this.PC = (this.PC + adr + 1 + tmp) & 0xFFFF; - this.ProgressClock = 2; - } else - this.PC += adr + 1; - } - - - Compare(data0, data1) { - data0 -= this.Get(data1); - if(data0 < 0) - this.ClearCFlag(); - else - this.SetCFlag(); - - this.ClearTFlag(); - this.SetNZFlag(data0 & 0xFF); - } + + BBRi(bit) { + let tmp = this.Get(this.ZP()); + tmp = (tmp >> bit) & 0x01; + this.Branch(tmp == 0, 2); + } + + + BBSi(bit) { + let tmp = this.Get(this.ZP()); + tmp = (tmp >> bit) & 0x01; + this.Branch(tmp == 1, 2); + } + + + Branch(status, adr) { + this.ClearTFlag(); + if (status) { + let tmp = this.Get(this.PC + adr); + if (tmp >= 0x80) + tmp |= 0xFF00; + this.PC = (this.PC + adr + 1 + tmp) & 0xFFFF; + this.ProgressClock = 2; + } else + this.PC += adr + 1; + } + + + Compare(data0, data1) { + data0 -= this.Get(data1); + if (data0 < 0) + this.ClearCFlag(); + else + this.SetCFlag(); + + this.ClearTFlag(); + this.SetNZFlag(data0 & 0xFF); + } - Decrement(data) { - data = (data - 1) & 0xFF; - this.SetNZFlag(data); - this.ClearTFlag(); - return data; - } + Decrement(data) { + data = (data - 1) & 0xFF; + this.SetNZFlag(data); + this.ClearTFlag(); + return data; + } - Increment(data) { - data = (data + 1) & 0xFF; - this.SetNZFlag(data); - this.ClearTFlag(); - return data; - } + Increment(data) { + data = (data + 1) & 0xFF; + this.SetNZFlag(data); + this.ClearTFlag(); + return data; + } - Push(data) { - this.Set(0x2100 | this.S, data); - this.S = (this.S - 1) & 0xFF; - } + Push(data) { + this.Set(0x2100 | this.S, data); + this.S = (this.S - 1) & 0xFF; + } - Pull() { - this.S = (this.S + 1) & 0xFF; - return this.Get(0x2100 | this.S); - } + Pull() { + this.S = (this.S + 1) & 0xFF; + return this.Get(0x2100 | this.S); + } - RMBi(bit) { - let address = this.ZP(); - this.Set(address, this.Get(address) & ~(0x01 << bit)); - this.ClearTFlag(); - } + RMBi(bit) { + let address = this.ZP(); + this.Set(address, this.Get(address) & ~(0x01 << bit)); + this.ClearTFlag(); + } - SMBi(bit) { - let address = this.ZP(); - this.Set(address, this.Get(address) | (0x01 << bit)); - this.ClearTFlag(); - } + SMBi(bit) { + let address = this.ZP(); + this.Set(address, this.Get(address) | (0x01 << bit)); + this.ClearTFlag(); + } - BIT(address) { - let tmp = this.Get(address); - this.SetNZFlag(this.A & tmp); - this.P = (this.P & ~(this.NFlag | this.VFlag)) | (tmp & (this.NFlag | this.VFlag)); - this.ClearTFlag(); - } + BIT(address) { + let tmp = this.Get(address); + this.SetNZFlag(this.A & tmp); + this.P = (this.P & ~(this.NFlag | this.VFlag)) | (tmp & (this.NFlag | this.VFlag)); + this.ClearTFlag(); + } - TST(address0, address1) { - let tmp0 = this.Get(address0); - let tmp1 = this.Get(address1); - this.SetNZFlag(tmp0 & tmp1); - this.P = (this.P & ~(this.NFlag | this.VFlag)) | (tmp1 & (this.NFlag | this.VFlag)); - this.ClearTFlag(); - } + TST(address0, address1) { + let tmp0 = this.Get(address0); + let tmp1 = this.Get(address1); + this.SetNZFlag(tmp0 & tmp1); + this.P = (this.P & ~(this.NFlag | this.VFlag)) | (tmp1 & (this.NFlag | this.VFlag)); + this.ClearTFlag(); + } - TRB(address) { - let tmp = this.Get(address); - let res = ~this.A & tmp; - this.Set(address, res); - this.SetNZFlag(res); - this.P = (this.P & ~(this.NFlag | this.VFlag)) | (tmp & (this.NFlag | this.VFlag)); - this.ClearTFlag(); - } + TRB(address) { + let tmp = this.Get(address); + let res = ~this.A & tmp; + this.Set(address, res); + this.SetNZFlag(res); + this.P = (this.P & ~(this.NFlag | this.VFlag)) | (tmp & (this.NFlag | this.VFlag)); + this.ClearTFlag(); + } - TSB(address) { - let tmp = this.Get(address); - let res = this.A | tmp; - this.Set(address, res); - this.SetNZFlag(res); - this.P = (this.P & ~(this.NFlag | this.VFlag)) | (tmp & (this.NFlag | this.VFlag)); - this.ClearTFlag(); - } + TSB(address) { + let tmp = this.Get(address); + let res = this.A | tmp; + this.Set(address, res); + this.SetNZFlag(res); + this.P = (this.P & ~(this.NFlag | this.VFlag)) | (tmp & (this.NFlag | this.VFlag)); + this.ClearTFlag(); + } - Load(address) { - let data = this.Get(address); - this.SetNZFlag(data); - this.ClearTFlag(); - return data; - } + Load(address) { + let data = this.Get(address); + this.SetNZFlag(data); + this.ClearTFlag(); + return data; + } - Store(address, data) { - this.Set(address, data); - this.ClearTFlag(); - } + Store(address, data) { + this.Set(address, data); + this.ClearTFlag(); + } - ZP() { - return 0x2000 | this.Get(this.PC + 1); - } + ZP() { + return 0x2000 | this.Get(this.PC + 1); + } - ZP_X() { - return 0x2000 | ((this.Get(this.PC + 1) + this.X) & 0xFF); - } + ZP_X() { + return 0x2000 | ((this.Get(this.PC + 1) + this.X) & 0xFF); + } - ZP_Y() { - return 0x2000 | ((this.Get(this.PC + 1) + this.Y) & 0xFF); - } + ZP_Y() { + return 0x2000 | ((this.Get(this.PC + 1) + this.Y) & 0xFF); + } - IND() { - return this.Get16(0x2000 | this.Get(this.PC + 1)); - } + IND() { + return this.Get16(0x2000 | this.Get(this.PC + 1)); + } - IND_X() { - return this.Get16(0x2000 | ((this.Get(this.PC + 1) + this.X) & 0xFF)); - } + IND_X() { + return this.Get16(0x2000 | ((this.Get(this.PC + 1) + this.X) & 0xFF)); + } - IND_Y() { - return (this.Get16(0x2000 | this.Get(this.PC + 1)) + this.Y) & 0xFFFF; - } + IND_Y() { + return (this.Get16(0x2000 | this.Get(this.PC + 1)) + this.Y) & 0xFFFF; + } - ABS() { - return this.Get16(this.PC + 1); - } + ABS() { + return this.Get16(this.PC + 1); + } - ABS_X() { - return (this.Get16(this.PC + 1) + this.X) & 0xFFFF; - } + ABS_X() { + return (this.Get16(this.PC + 1) + this.X) & 0xFFFF; + } - ABS_Y() { - return (this.Get16(this.PC + 1) + this.Y) & 0xFFFF; - } + ABS_Y() { + return (this.Get16(this.PC + 1) + this.Y) & 0xFFFF; + } - ABS_IND() { - return this.Get16(this.Get16(this.PC + 1)); - } + ABS_IND() { + return this.Get16(this.Get16(this.PC + 1)); + } - ABS_X_IND() { - return this.Get16((this.Get16(this.PC + 1) + this.X) & 0xFFFF); - } + ABS_X_IND() { + return this.Get16((this.Get16(this.PC + 1) + this.X) & 0xFFFF); + } - SetNZFlag(data) { // Set N Z Flags - this.P = (this.P & ~(this.NFlag | this.ZFlag)) | this.NZCacheTable[data]; - } + SetNZFlag(data) { // Set N Z Flags + this.P = (this.P & ~(this.NFlag | this.ZFlag)) | this.NZCacheTable[data]; + } - SetVFlag() { // Set V Flag - this.P |= this.VFlag; - } + SetVFlag() { // Set V Flag + this.P |= this.VFlag; + } - ClearVFlag() { // Clear V Flag - this.P &= ~this.VFlag; - } + ClearVFlag() { // Clear V Flag + this.P &= ~this.VFlag; + } - SetTFlag() { // Set T Flag - this.P |= this.TFlag; - } + SetTFlag() { // Set T Flag + this.P |= this.TFlag; + } - ClearTFlag() { // Clear T Flag - this.P &= ~this.TFlag; - } + ClearTFlag() { // Clear T Flag + this.P &= ~this.TFlag; + } - SetBFlag() { // Set B Flag - this.P |= this.BFlag; - } + SetBFlag() { // Set B Flag + this.P |= this.BFlag; + } - ClearBFlag() { // Clear B Flag - this.P &= ~this.BFlag; - } + ClearBFlag() { // Clear B Flag + this.P &= ~this.BFlag; + } - SetDFlag() { // Set D Flag - this.P |= this.DFlag; - } + SetDFlag() { // Set D Flag + this.P |= this.DFlag; + } - ClearDFlag() { // Clear D Flag - this.P &= ~this.DFlag; - } + ClearDFlag() { // Clear D Flag + this.P &= ~this.DFlag; + } - SetIFlag() { // Set I Flag - this.P |= this.IFlag; - } + SetIFlag() { // Set I Flag + this.P |= this.IFlag; + } - ClearIFlag() { // Clear I Flag - this.P &= ~this.IFlag; - } + ClearIFlag() { // Clear I Flag + this.P &= ~this.IFlag; + } - SetCFlag() { // Set C Flag - this.P |= this.CFlag; - } + SetCFlag() { // Set C Flag + this.P |= this.CFlag; + } - ClearCFlag() { // Clear C Flag - this.P &= ~this.CFlag; - } + ClearCFlag() { // Clear C Flag + this.P &= ~this.CFlag; + } - PCH() { - return this.PC >> 8; - } + PCH() { + return this.PC >> 8; + } - PCL() { - return this.PC & 0x00FF; - } + PCL() { + return this.PC & 0x00FF; + } - toPCH(data) { - this.PC = (this.PC & 0x00FF) | (data << 8); - } + toPCH(data) { + this.PC = (this.PC & 0x00FF) | (data << 8); + } - toPCL(data) { - this.PC = (this.PC & 0xFF00) | data; - } + toPCL(data) { + this.PC = (this.PC & 0xFF00) | data; + } - /* ***************** */ - /* **** Storage **** */ - /* ***************** */ - StorageConstruct() { - this.MPR = new Array(8); - this.MPRSelect = 0; - this.RAM = new Array(0x8000); - this.RAMMask = 0x1FFF; - this.BRAM = new Array(0x2000).fill(0x00); - this.BRAMUse = false; + /* ***************** */ + /* **** Storage **** */ + /* ***************** */ + StorageConstruct() { + this.MPR = new Array(8); + this.MPRSelect = 0; + this.RAM = new Uint8Array(0x8000); + this.RAMMask = 0x1FFF; + this.BRAM = new Uint8Array(0x2000).fill(0x00); + this.BRAMUse = false; - this.INTIRQ2 = 0x00; - this.IntDisableRegister = 0; + this.INTIRQ2 = 0x00; + this.IntDisableRegister = 0; - this.Mapper = null; + this.Mapper = null; - this.Mapper0 = class extends this.MapperBase { + this.Mapper0 = class extends this.MapperBase { Address: number; - constructor(rom, core) { - super(rom, core); + constructor(rom, core) { + super(rom, core); - let tmp = this.ROM.length - 1; - this.Address = 0x80000; - while(this.Address > 0x0000) { - if((this.Address & tmp) != 0x0000) - break; - this.Address >>>= 1; - } - } + let tmp = this.ROM.length - 1; + this.Address = 0x80000; + while (this.Address > 0x0000) { + if ((this.Address & tmp) != 0x0000) + break; + this.Address >>>= 1; + } + } - Read(address) { - if(address >= this.ROM.length) - return this.ROM[(address & (this.Address - 1)) | this.Address]; - else - return this.ROM[address]; - } - }; + Read(address) { + if (address >= this.ROM.length) + return this.ROM[(address & (this.Address - 1)) | this.Address]; + else + return this.ROM[address]; + } + }; - this.Mapper1 = class extends this.MapperBase { + this.Mapper1 = class extends this.MapperBase { ROM: any; Address: number; - constructor(rom, core) { - super(rom, core); - this.Address = 0; - } + constructor(rom, core) { + super(rom, core); + this.Address = 0; + } - Init() { - this.Address = 0; - } + Init() { + this.Address = 0; + } - Read(address) { - if(address < 0x80000) - return this.ROM[address]; - else - return this.ROM[this.Address | (address & 0x7FFFF)]; - } + Read(address) { + if (address < 0x80000) + return this.ROM[address]; + else + return this.ROM[this.Address | (address & 0x7FFFF)]; + } - Write(address, data) { - this.Address = ((address & 0x000F) + 1) << 19; - } - }; + Write(address, data) { + this.Address = ((address & 0x000F) + 1) << 19; + } + }; - this.Mapper2 = class extends this.MapperBase { + this.Mapper2 = class extends this.MapperBase { ROM: any; - constructor(rom, core) { - super(rom, core); - this.ROM = rom.concat(new Array(0x80000).fill(0x00)); - } + constructor(rom, core) { + super(rom, core); + this.ROM = rom; + } - Read(address) { - return this.ROM[address]; - } + Read(address) { + return this.ROM[address] || 0; + } - Write(address, data) { - if(address >= 0x80000) - this.ROM[address] = data; - } - }; - } + Write(address, data) { + if (address >= 0x80000) + this.ROM[address] = data; + } + }; + } - GetIntStatus() { - return ~this.IntDisableRegister & this.GetIntReqest(); - } + GetIntStatus() { + return ~this.IntDisableRegister & this.GetIntReqest(); + } - GetIntDisable() { - return this.IntDisableRegister; - } - - - SetIntDisable(data) { - this.IntDisableRegister = data; - this.TimerAcknowledge(); - } - - - GetIntReqest() { - return (((this.VDC[0].VDCStatus | this.VDC[1].VDCStatus) & 0x3F) != 0x00 ? this.IRQ1Flag : 0x00) | this.INTIRQ2 | this.INTTIQ; - } - - - SetIntReqest(data) { - this.TimerAcknowledge(); - } - - - SetROM(rom) { - this.Init(); - let tmp = rom.slice(rom.length % 8192); - //if(tmp[0x001FFF] < 0xE0) - // tmp = tmp.map((d) => {return this.ReverseBit[d];}); - this.Mapper = new this.Mapper0(tmp, this); - this.CPUReset(); - } - - - StorageInit() { - this.RAM.fill(0x00); - this.RAMMask = this.SuperGrafx ? 0x7FFF : 0x1FFF; - this.StorageReset(); - } - - - StorageReset() { - this.IntDisableRegister = 0x00;//IntInit - - for(let i=0; i<7; i++) - this.MPR[i] = 0xFF << 13; - this.MPR[7] = 0x00; - - this.MPRSelect = 0x01; - } - - - Get16(address) { - return (this.Get(address + 1) << 8) | this.Get(address); - } - - - Get(address) { - address = this.MPR[address >> 13] | (address & 0x1FFF); - - if(address < 0x100000)// ROM - return this.Mapper.Read(address); - - if(address < 0x1EE000)// NOT USE - return 0xFF; - - if(address < 0x1F0000) {// BRAM - if(this.BRAMUse) - return this.BRAM[address & 0x1FFF]; - else - return 0xFF; - } - - if(address < 0x1F8000)// RAM - return this.RAM[address & this.RAMMask]; - - if(address < 0x1FE000)// NOT USE - return 0xFF; - - if(address < 0x1FE400) {// VDC - if(this.SuperGrafx) { - let tmp = address & 0x00001F; - if(tmp < 0x00008) { - switch(address & 0x000003) {// VDC#1 - case 0x00: - return this.GetVDCStatus(0); - case 0x01: - return 0x00; - case 0x02: - return this.GetVDCLow(0); - case 0x03: - return this.GetVDCHigh(0); - } - } else if(tmp < 0x00010) {// VPC - return this.GetVPC(tmp & 0x000007); - } else if(tmp < 0x00018) {// VDC#2 - switch(address & 0x000003) { - case 0x00: - return this.GetVDCStatus(1); - case 0x01: - return 0x00; - case 0x02: - return this.GetVDCLow(1); - case 0x03: - return this.GetVDCHigh(1); - } - } else { - return 0xFF; - } - } else { - switch(address & 0x000003) {// VDC#1 - case 0x00: - return this.GetVDCStatus(0); - case 0x01: - return 0x00; - case 0x02: - return this.GetVDCLow(0); - case 0x03: - return this.GetVDCHigh(0); - } - } - } - - if(address < 0x1FE800) {// VCE - switch(address & 0x000007) { - case 0x04: - return this.GetVCEDataLow(); - case 0x05: - return this.GetVCEDataHigh(); - default: - return 0x00; - - } - } - - if(address < 0x1FEC00)// PSG - return this.GetPSG(address & 0x00000F); - - if(address < 0x1FF000)// TIMER - return this.ReadTimerCounter(); - - if(address < 0x1FF400)// IO - return this.GetJoystick(); - - if(address < 0x1FF800) {// INT Register - switch(address & 0x000003) { - case 0x02: - return this.GetIntDisable(); - case 0x03: - return this.GetIntReqest(); - default: - return 0x00; - } - } - - return 0xFF;//EXT - } - - - Set(address, data) { - address = this.MPR[address >> 13] | (address & 0x1FFF); - - if(address < 0x100000) {// ROM - this.Mapper.Write(address, data); - return; - } - - if(address < 0x1EE000)// NOT USE - return; - - if(address < 0x1F0000) {// BRAM - if(this.BRAMUse) - this.BRAM[address & 0x1FFF] = data; - return; - } - - if(address < 0x1F8000) {// RAM - this.RAM[address & this.RAMMask] = data; - return; - } - - if(address < 0x1FE000)// NOT USE - return; - - if(address < 0x1FE400) {// VDC - if(this.SuperGrafx) { - let tmp = address & 0x00001F; - if(tmp < 0x00008) { - switch(address & 0x000003) {// VDC#1 - case 0x00: - this.SetVDCRegister(data, 0); - break; - case 0x02: - this.SetVDCLow(data, 0); - break; - case 0x03: - this.SetVDCHigh(data, 0); - break; - } - } else if(tmp < 0x00010) {// VPC - this.SetVPC(tmp & 0x000007, data); - } else if(tmp < 0x00018) {// VDC#2 - switch(address & 0x000003) { - case 0x00: - this.SetVDCRegister(data, 1); - break; - case 0x02: - this.SetVDCLow(data, 1); - break; - case 0x03: - this.SetVDCHigh(data, 1); - break; - } - } - } else { - switch(address & 0x000003) {// VDC#1 - case 0x00: - this.SetVDCRegister(data, 0); - break; - case 0x01: - break; - case 0x02: - this.SetVDCLow(data, 0); - break; - case 0x03: - this.SetVDCHigh(data, 0); - break; - } - } - return; - } - - if(address < 0x1FE800) {// VCE - switch(address & 0x000007) { - case 0x00: - this.SetVCEControl(data); - break; - case 0x02: - this.SetVCEAddressLow(data); - break; - case 0x03: - this.SetVCEAddressHigh(data); - break; - case 0x04: - this.SetVCEDataLow(data); - break; - case 0x05: - this.SetVCEDataHigh(data); - break; - } - return; - } - - if(address < 0x1FEC00) {// PSG - this.SetPSG(address & 0x00000F, data); - return; - } - - if(address < 0x1FF000) {// TIMER - switch(address & 0x000001) { - case 0x00: - this.WirteTimerReload(data); - break; - case 0x01: - this.WirteTimerControl(data); - break; - } - return; - } - - if(address < 0x1FF400) {// IO - this.SetJoystick(data); - return; - } - - if(address < 0x1FF800) {// INT Register - switch(address & 0x000003) { - case 0x02: - this.SetIntDisable(data); - break; - case 0x03: - this.SetIntReqest(data); - break; - } - return; - } - } - - - /* ************* */ - /* **** VCE **** */ - /* ************* */ - VCEConstruct() { - this.Palette = new Array(512); - this.PaletteData = new Array(512); - this.MonoPaletteData = new Array(512); - - this.VCEBaseClock = 0; - this.VCEControl = 0; - this.VCEAddress = 0; - this.VCEData = 0; - } - - - VCEInit() { - this.Palette.fill(0x0000); - for(let i=0; i<512; i++) { - this.PaletteData[i] = {r:0, g:0, b:0}; - this.MonoPaletteData[i] = {r:0, g:0, b:0}; - } - - this.VCEBaseClock = this.BaseClock5; - this.VCEControl = 0x00; - this.VCEAddress = 0x00; - this.VCEData = 0x00; - } - - - SetVCEControl(data) { - this.VCEControl = data; - - switch(data & 0x03) { - case 0x00: - this.VCEBaseClock = this.BaseClock5; - break; - case 0x01: - this.VCEBaseClock = this.BaseClock7; - break; - case 0x02: - case 0x03: - this.VCEBaseClock = this.BaseClock10; - break; - } - } - - - SetVCEAddressLow(data) { - this.VCEAddress = (this.VCEAddress & 0xFF00) | data; - } - - - SetVCEAddressHigh(data) { - this.VCEAddress = ((this.VCEAddress & 0x00FF) | (data << 8)) & 0x01FF; - } - - - GetVCEDataLow() { - return this.Palette[this.VCEAddress] & 0x00FF; - } - - - GetVCEDataHigh() { - let tmp = (this.Palette[this.VCEAddress] & 0xFF00) >> 8; - this.VCEAddress = (this.VCEAddress + 1) & 0x01FF; - return tmp; - } - - - SetVCEDataLow(data) { - this.Palette[this.VCEAddress] = (this.Palette[this.VCEAddress] & 0xFF00) | data; - this.ToPalettes(); - } - - - SetVCEDataHigh(data) { - this.Palette[this.VCEAddress] = (this.Palette[this.VCEAddress] & 0x00FF) | (data << 8); - this.ToPalettes(); - this.VCEAddress = (this.VCEAddress + 1) & 0x01FF; - } - - - ToPalettes() { - let color = this.Palette[this.VCEAddress]; - let tmp = this.PaletteData[this.VCEAddress]; - tmp.r = ((color >> 3) & 0x07) * 36; - tmp.g = ((color >> 6) & 0x07) * 36; - tmp.b = (color & 0x07) * 36; - - let mono = tmp.r * 0.299 + tmp.g * 0.587 + tmp.b * 0.114; - this.MonoPaletteData[this.VCEAddress].r = mono; - this.MonoPaletteData[this.VCEAddress].g = mono; - this.MonoPaletteData[this.VCEAddress].b = mono; - } - - - /* ************* */ - /* **** VPC **** */ - /* ************* */ - VPCConstruct() { - this.VPCRegister = new Array(8); - this.VDCSelect = 0; - this.VPCWindow1 = 0; - this.VPCWindow2 = 0; - this.VPCPriority = new Array(4); - } - - - VPCInit() { - this.VPCRegister.fill(0x00); - this.VPCRegister[0] = 0x11; - this.VPCRegister[1] = 0x11; - this.VPCRegister[7] = 0xFF; - - this.VDCSelect = 0; - this.VPCWindow1 = 0; - this.VPCWindow2 = 0; - this.VPCPriority.fill(0x01); - } - - - SetVPC(no, data) { - if(no == 0x07) - return; - - this.VPCRegister[no] = data; - if(no == 0x06) - this.VDCSelect = data & 0x01; - - if(no == 0x02 || no == 0x03) { - this.VPCWindow1 = (this.VPCRegister[0x02] | ((this.VPCRegister[0x03] & 0x03) << 8)) - 64; - if(this.VPCWindow1 < 0) - this.VPCWindow1 = 1024; - } - - if(no == 0x04 || no == 0x05) { - this.VPCWindow2 = (this.VPCRegister[0x04] | ((this.VPCRegister[0x05] & 0x03) << 8)) - 64; - if(this.VPCWindow2 < 0) - this.VPCWindow2 = -1; - } - - if(no == 0x00) { - this.VPCPriority[2] = this.VPCRegister[0x00] >> 4; - this.VPCPriority[3] = this.VPCRegister[0x00] & 0x0F; - } - - if(no == 0x01) { - this.VPCPriority[0] = this.VPCRegister[0x01] >> 4; - this.VPCPriority[1] = this.VPCRegister[0x01] & 0x0F; - } - } - - - GetVPC(no) { - return this.VPCRegister[no]; - } - - - /* ************* */ - /* **** VDC **** */ - /* ************* */ - VDCConstruct() { - this.DrawFlag = false; - this.VDCPutLineProgressClock = 0; - this.VDCPutLine = 0; - this.VDC = new Array(2); - - this.VDCLineClock = 1368; - - this.ScreenSize = []; - this.ScreenSize[this.BaseClock5] = 342; - this.ScreenSize[this.BaseClock7] = 456; - this.ScreenSize[this.BaseClock10] = 684; - - this.PutScreenSize = []; - this.PutScreenSize[this.BaseClock5] = 320; - this.PutScreenSize[this.BaseClock7] = 428; - this.PutScreenSize[this.BaseClock10] = 640; - - this.ScreenHeightMAX = 262; - this.ScreenWidthMAX = 684; - - this.VScreenWidthArray = []; - this.VScreenWidthArray[0x00] = 32; - this.VScreenWidthArray[0x10] = 64; - this.VScreenWidthArray[0x20] = 128; - this.VScreenWidthArray[0x30] = 128; - - this.ReverseBit = new Array(0x100).fill(0x00); - this.ReverseBit = this.ReverseBit.map((d, i) => { return ((i & 0x80) >> 7) | ((i & 0x40) >> 5) | - ((i & 0x20) >> 3) | ((i & 0x10) >> 1) | - ((i & 0x08) << 1) | ((i & 0x04) << 3) | - ((i & 0x02) << 5) | ((i & 0x01) << 7); }); - - this.ReverseBit16 = new Array(0x10000).fill(0x00); - this.ReverseBit16 = this.ReverseBit16.map((d, i) => { return (this.ReverseBit[i & 0x00FF] << 8) | this.ReverseBit[(i & 0xFF00) >> 8]; }); - - this.ReverseBit256 = new Array(0x100).fill(0x00); - this.ReverseBit256 = this.ReverseBit256.map((d, i) => { let b = this.ReverseBit[i]; - return ((b & 0x80) << (28 - 7)) | - ((b & 0x40) << (24 - 6)) | - ((b & 0x20) << (20 - 5)) | - ((b & 0x10) << (16 - 4)) | - ((b & 0x08) << (12 - 3)) | - ((b & 0x04) << ( 8 - 2)) | - ((b & 0x02) << ( 4 - 1)) | - ((b & 0x01) << ( 0 - 0)); }); - - this.SPAddressMask = []; - this.SPAddressMask[16] = []; - this.SPAddressMask[32] = []; - this.SPAddressMask[16][16] = 0x07FE; - this.SPAddressMask[16][32] = 0x07FE & 0x07FA; - this.SPAddressMask[16][64] = 0x07FE & 0x07F2; - this.SPAddressMask[32][16] = 0x07FC; - this.SPAddressMask[32][32] = 0x07FC & 0x07FA; - this.SPAddressMask[32][64] = 0x07FC & 0x07F2; - } - - - MakeSpriteLine(vdcno) { - let vdcc = this.VDC[vdcno]; - - let sp = vdcc.SPLine; - for(let i=0; i> 8) + 16; - height = height > 32 ? 64 : height; - - if(line < y || line > (y + height - 1)) - continue; - - let x = (satb[s + 1] & 0x3FF) - 32; - let width = ((attribute & 0x0100) >> 4) + 16; - if((x + width) <= 0) - continue; - - let spy = line - y; - if((attribute & 0x8000) == 0x8000) - spy = (height - 1) - spy; - - let index = ((satb[s + 2] & this.SPAddressMask[width][height]) << 5) | (((spy & 0x30) << 3) | (spy & 0x0F)); - - let data0; - let data1; - let data2; - let data3; - if((attribute & 0x0800) == 0x0000) { - data0 = revbit16[vram[index]]; - data1 = revbit16[vram[index + 16]]; - data2 = revbit16[vram[index + 32]]; - data3 = revbit16[vram[index + 48]]; - if(width == 32) { - data0 |= revbit16[vram[(index | 0x0040)]] << 16; - data1 |= revbit16[vram[(index | 0x0040) + 16]] << 16; - data2 |= revbit16[vram[(index | 0x0040) + 32]] << 16; - data3 |= revbit16[vram[(index | 0x0040) + 48]] << 16; - } - } else { - data0 = vram[index]; - data1 = vram[index + 16]; - data2 = vram[index + 32]; - data3 = vram[index + 48]; - if(width == 32) { - data0 = (data0 << 16) | vram[(index | 0x0040)]; - data1 = (data1 << 16) | vram[(index | 0x0040) + 16]; - data2 = (data2 << 16) | vram[(index | 0x0040) + 32]; - data3 = (data3 << 16) | vram[(index | 0x0040) + 48]; - } - } - - let palette = ((attribute & 0x000F) << 4) | 0x0100; - let priority = attribute & 0x0080; - - let j = 0; - if(x < 0) { - j -= x; - x = 0; - } - - for(; j>> j) & 0x0001) - | (((data1 >>> j) << 1) & 0x0002) - | (((data2 >>> j) << 2) & 0x0004) - | (((data3 >>> j) << 3) & 0x0008); - if(dot != 0x00) { - spx.data = dot; - spx.palette = palette; - spx.priority = priority; - } - } - - if(spx.no == 255) - spx.no = i; - - if(i != 0 && spx.no == 0) - vdcc.VDCStatus |= vdcc.VDCRegister[0x05] & 0x0001;//SetSpriteCollisionINT - - if(++dotcount == 256) { - vdcc.VDCStatus |= vdcc.VDCRegister[0x05] & 0x0002;//SetSpriteOverINT - if(vdcc.SpriteLimit) - return; - } - } - } - } - - - MakeBGLine(vdcno) { - let vdcc = this.VDC[vdcno]; - - let sp = vdcc.SPLine; - let bg = vdcc.BGLine; - let sw = vdcc.ScreenWidth; - let leftblank = ((vdcc.HDS + vdcc.HSW) << 3) + vdcc.DrawBGIndex; - - if((vdcc.VDCRegister[0x05] & 0x0080) == 0x0080) { - let WidthMask = vdcc.VScreenWidth - 1; - - let x = vdcc.VDCRegister[0x07]; - let index_x = (x >> 3) & WidthMask; - x = (x & 0x07) << 2; - - let y = vdcc.DrawBGLine; - let index_y = ((y >> 3) & (vdcc.VScreenHeight - 1)) * vdcc.VScreenWidth; - y = y & 0x07; - - let vram = vdcc.VRAM; - let bgx = 0; - let revbit = this.ReverseBit256; - - while(bgx < sw) { - let tmp = vram[index_x + index_y]; - let address = ((tmp & 0x0FFF) << 4) + y; - let palette = (tmp & 0xF000) >> 8; - - let data0 = vram[address]; - let data1 = vram[address + 8]; - let data = (revbit[ data0 & 0x00FF ] ) | - (revbit[(data0 & 0xFF00) >> 8] << 1) | - (revbit[ data1 & 0x00FF ] << 2) | - (revbit[(data1 & 0xFF00) >> 8] << 3); - - for(; x<32 && bgx>> x) & 0x0F; - let spbgx = sp[bgx]; - bg[bgx + leftblank] = spbgx.data != 0x00 && (dot == 0x00 || spbgx.priority == 0x0080) ? - spbgx.data | spbgx.palette : dot | (dot == 0x00 ? 0x00 : palette); - } - - x = 0; - index_x = (index_x + 1) & WidthMask; - } - } else { - for(let i=0; i 0) {//VRAMtoSATB - vdcc.VRAMtoSATBCount -= this.ProgressClock; - if(vdcc.VRAMtoSATBCount <= 0) - vdcc.VDCStatus = (vdcc.VDCStatus & 0xBF) | ((vdcc.VDCRegister[0x0F] & 0x0001) << 3);//VRAMtoSATB INT - } - - if(vdcc.VRAMtoVRAMCount > 0) {//VRAMtoVRAM - vdcc.VRAMtoVRAMCount -= this.ProgressClock; - if(vdcc.VRAMtoVRAMCount <= 0) - vdcc.VDCStatus = (vdcc.VDCStatus & 0xBF) | ((vdcc.VDCRegister[0x0F] & 0x0002) << 3);//VRAMtoVRAM INT - } - } - - - VDCProcess(vdcno) { - let vdcc = this.VDC[vdcno]; - - vdcc.VDCProgressClock -= this.VDCLineClock; - - vdcc.DrawBGIndex = 0; - vdcc.BGLine.fill(0x100); - - for(let i=0; i 261) - vline -= 261; - if(vdcc.DrawBGYLine == vline) { - vdcc.VDCStatus |= (vdcc.VDCRegister[0x05] & 0x0008) << 2;//SetVSync INT - if(vdcc.VRAMtoSATBStartFlag) {//VRAMtoSATB - for(let i=0, addr=vdcc.VDCRegister[0x13]; i<256; i++, addr++) - vdcc.SATB[i] = vdcc.VRAM[addr]; - vdcc.VRAMtoSATBCount = 256 * this.VCEBaseClock; - vdcc.VDCStatus |= 0x40; - vdcc.VRAMtoSATBStartFlag = (vdcc.VDCRegister[0x0F] & 0x0010) == 0x0010; - } - } - - vdcc.RasterCount++; - if(vdcc.DrawBGYLine == (vdcc.VDS + vdcc.VSW - 1)) - vdcc.RasterCount = 64; - - if(vdcc.RasterCount == vdcc.VDCRegister[0x06] && (vdcc.VDCStatus & 0x20) == 0x00) - vdcc.VDCStatus |= vdcc.VDCRegister[0x05] & 0x0004;//SetRaster INT - - vdcc.DrawBGIndex += vdcc.DrawLineWidth; - } - } - - - VDCRun() { - this.VDCProcessDMA(0); - this.VDC[0].VDCProgressClock += this.ProgressClock; - - if(this.SuperGrafx) { - this.VDCProcessDMA(1); - this.VDC[1].VDCProgressClock += this.ProgressClock; - } - - while(this.VDC[0].VDCProgressClock >= this.VDCLineClock) { - this.VDCProcess(0); - if(this.SuperGrafx) - this.VDCProcess(1); - } - - this.VDCPutLineProgressClock += this.ProgressClock; - if(this.VDCPutLineProgressClock >= this.VDCLineClock) { - this.VDCPutLineProgressClock -= this.VDCLineClock; - this.VDCPutLine++; - - if(this.VDCPutLine == this.ScreenHeightMAX) { - this.VDCPutLine = 0; - this.GetScreenSize(0); - this.VDC[0].DrawBGYLine = 0; - if(this.SuperGrafx) { - this.GetScreenSize(1); - this.VDC[1].DrawBGYLine = 0; - } - this.DrawFlag = true; - this.Ctx.putImageData(this.ImageData, 0, 0); - } - - let palettes = (this.VCEControl & 0x80) == 0x00 ? this.PaletteData : this.MonoPaletteData; - - let data = this.ImageData.data; - let imageIndex = this.VDCPutLine * this.ScreenWidthMAX * 4; - let black = palettes[0x100]; - - let sw = this.ScreenSize[this.VCEBaseClock]; - let bgl0 = this.VDC[0].BGLine; - - if(this.SuperGrafx) {//VPC - let window1 = this.VPCWindow1; - let window2 = this.VPCWindow2; - let priority = this.VPCPriority; - - let bgl1 = this.VDC[1].BGLine; - for(let bgx=0; bgx < sw; bgx++, imageIndex+=4) { - let wflag = 0x00; - if(bgx >= window1) - wflag |= 0x01; - if(bgx <= window2) - wflag |= 0x02; - - let bg0 = bgl0[bgx]; - let bg1 = bgl1[bgx]; - - let color; - switch(priority[wflag]) { - case 0x04 | 0x03: - if(bg0 > 0x100 || bg1 > 0x100) - color = palettes[bg0 > 0x100 ? bg0 : bg1]; - else - color = palettes[(bg0 & 0x0FF) != 0x000 ? bg0 : bg1]; - - break; - case 0x08 | 0x03: - if(bg0 < 0x100 && bg0 != 0x000) - color = palettes[bg0]; - else - color = palettes[(bg1 & 0x0FF) != 0x000 ? bg1 : bg0]; - break; - case 0x00 | 0x03: - case 0x0C | 0x03: - color = palettes[(bg0 & 0x0FF) != 0x000 ? bg0 : bg1]; - break; - case 0x00 | 0x01: - case 0x04 | 0x01: - case 0x08 | 0x01: - case 0x0C | 0x01: - color = palettes[bg0]; - break; - case 0x00 | 0x02: - case 0x04 | 0x02: - case 0x08 | 0x02: - case 0x0C | 0x02: - color = palettes[bg1]; - break; - default: - color = black; - break; - } - data[imageIndex] = color.r; - data[imageIndex + 1] = color.g; - data[imageIndex + 2] = color.b; - } - } else { - for(let bgx=0; bgx < sw; bgx++, imageIndex+=4) { - let color = palettes[bgl0[bgx]]; - data[imageIndex] = color.r; - data[imageIndex + 1] = color.g; - data[imageIndex + 2] = color.b; - } - } - } - } - - - GetScreenSize(vdcno) { - let vdcc = this.VDC[vdcno]; - let r = vdcc.VDCRegister; - - vdcc.VScreenWidth = this.VScreenWidthArray[r[0x09] & 0x0030]; - - vdcc.VScreenHeight = (r[0x09] & 0x0040) == 0x0000 ? 32 : 64; - vdcc.VScreenHeightMask = vdcc.VScreenHeight * 8 - 1; - vdcc.ScreenWidth = ((r[0x0B] & 0x007F) + 1) * 8; - - if(vdcc.ScreenWidth > this.ScreenWidthMAX) - vdcc.ScreenWidth = this.ScreenWidthMAX; - - vdcc.HDS = (r[0x0A] & 0x7F00) >> 8; - vdcc.HSW = r[0x0A] & 0x001F; - - vdcc.HDE = (r[0x0B] & 0x7F00) >> 8; - vdcc.HDW = r[0x0B] & 0x007F; - - vdcc.VDS = ((r[0x0C] & 0xFF00) >> 8); - vdcc.VSW = r[0x0C] & 0x001F; - - vdcc.VDW = r[0x0D] & 0x01FF; - - vdcc.VCR = r[0x0E] & 0x00FF; - - vdcc.ScreenSize = this.ScreenSize[this.VCEBaseClock]; - if(this.MainCanvas.width != vdcc.ScreenSize) { - //this.MainCanvas.style.width = (this.PutScreenSize[this.VCEBaseClock] * 2) + 'px'; - this.MainCanvas.width = this.PutScreenSize[this.VCEBaseClock]; - } - - vdcc.DrawLineWidth = (vdcc.HDS + vdcc.HSW + vdcc.HDE + vdcc.HDW + 1) << 3; - if(vdcc.DrawLineWidth <= this.ScreenSize[this.BaseClock5]) - vdcc.DrawLineWidth = this.ScreenSize[this.BaseClock5]; - else if(vdcc.DrawLineWidth <= this.ScreenSize[this.BaseClock7]) - vdcc.DrawLineWidth = this.ScreenSize[this.BaseClock7]; - else vdcc.DrawLineWidth = this.ScreenSize[this.BaseClock10]; - - vdcc.VDCBurst = (r[0x05] & 0x00C0) == 0x0000 ? true : false; - } - - - VDCInit() { - this.VDCPutLineProgressClock = 0; - this.VDCPutLine = 0; - this.DrawFlag = false; - - for(let vdcno=0; vdcno<2; vdcno++) { - this.VDC[vdcno] = { - VDCRegister: new Array(20).fill(0x0000), - VRAM: new Array(0x10000).fill(0x0000), - SATB: new Array(256).fill(0x0000), - VDCBurst: false, - SpriteLimit: false, - - SPLine: new Array(this.ScreenWidthMAX), - BGLine: new Array(this.ScreenWidthMAX).fill(0x00), - - VDCStatus: 0x00, - VDCRegisterSelect: 0x00, - WriteVRAMData: 0x0000, - - VRAMtoSATBStartFlag: false, - VRAMtoSATBCount: 0, - VRAMtoVRAMCount: 0, - - RasterCount: 64, - VDCProgressClock: 0, - DrawBGYLine: 0, - DrawBGLine: 0, - - VScreenWidth: 0, - VScreenHeight: 0, - VScreenHeightMask: 0, - ScreenWidth: 0, - ScreenSize: 0, - DrawLineWidth: 0, - DrawBGIndex: 0, - - HDS: 0, - HSW: 0, - HDE: 0, - HDW: 0, - VDS: 0, - VSW: 0, - VDW: 0, - VCR: 0}; - - for(let i=0; i 0; l--) { - vram[d] = vram[s]; - s = (s + si) & 0xFFFF; - d = (d + di) & 0xFFFF; - } - return; - } - - if(vdcc.VDCRegisterSelect == 0x13)//VRAMtoSATB - vdcc.VRAMtoSATBStartFlag = true; - } - - - GetVRAMIncrement(vdcno) { - switch(this.VDC[vdcno].VDCRegister[0x05] & 0x1800) { - case 0x0000: - return 1; - case 0x0800: - return 32; - case 0x1000: - return 64; - case 0x1800: - return 128; - } - } - - - GetVDCStatus(vdcno) { - let tmp = this.VDC[vdcno].VDCStatus; - this.VDC[vdcno].VDCStatus &= 0x40; - return tmp; - } - - - GetVDCLow(vdcno) { - return this.VDC[vdcno].VDCRegister[this.VDC[vdcno].VDCRegisterSelect] & 0x00FF; - } - - - GetVDCHigh(vdcno) { - let vdcc = this.VDC[vdcno]; - - if(vdcc.VDCRegisterSelect == 0x02 || vdcc.VDCRegisterSelect == 0x03) { - let tmp = (vdcc.VDCRegister[0x02] & 0xFF00) >> 8; - vdcc.VDCRegister[0x02] = vdcc.VRAM[vdcc.VDCRegister[0x01]]; - vdcc.VDCRegister[0x03] = vdcc.VDCRegister[0x02]; - vdcc.VDCRegister[0x01] = (vdcc.VDCRegister[0x01] + this.GetVRAMIncrement(vdcno)) & 0xFFFF; - return tmp; - } - - return (vdcc.VDCRegister[vdcc.VDCRegisterSelect] & 0xFF00) >> 8; - } - - - /* *************** */ - /* **** Sound **** */ - /* *************** */ - SoundConstruct() { - this.WaveDataArray = []; - this.WaveClockCounter = 0; - this.WaveVolume = 1.0; - - this.WebAudioCtx = null; - this.WebAudioJsNode = null; - this.WebAudioGainNode = null; - this.WebAudioBufferSize = 2048; - - this.PSGClock = 3579545; - } - - - WebAudioFunction(e) { - let output = []; - let data = []; - - for(let i=0; i<2; i++) { - output[i] = e.outputBuffer.getChannelData(i); - data[i] = new Float32Array(this.WebAudioBufferSize); - if(this.WaveDataArray[i].length < this.WebAudioBufferSize) { - data[i].fill(0.0); - } else { - for(let j=0; j this.WebAudioBufferSize * 2) - this.WaveDataArray[i] = this.WaveDataArray[i].slice(this.WebAudioBufferSize); - } - output[i].set(data[i]); - } - } - - SoundInit() { - this.WaveClockCounter = 0; - this.WaveDataArray = []; - this.WaveDataArray[0] = []; - this.WaveDataArray[1] = []; - - if(typeof AudioContext !== "undefined" && this.WebAudioCtx == null) { + GetIntDisable() { + return this.IntDisableRegister; + } + + + SetIntDisable(data) { + this.IntDisableRegister = data; + this.TimerAcknowledge(); + } + + + GetIntReqest() { + return (((this.VDC[0].VDCStatus | this.VDC[1].VDCStatus) & 0x3F) != 0x00 ? this.IRQ1Flag : 0x00) | this.INTIRQ2 | this.INTTIQ; + } + + + SetIntReqest(data) { + this.TimerAcknowledge(); + } + + + SetROM(rom) { + this.Init(); + let tmp = rom.slice(rom.length % 8192); + //if(tmp[0x001FFF] < 0xE0) + // tmp = tmp.map((d) => {return this.ReverseBit[d];}); + this.Mapper = new this.Mapper0(tmp, this); + this.CPUReset(); + } + + + StorageInit() { + this.RAM.fill(0x00); + this.RAMMask = this.SuperGrafx ? 0x7FFF : 0x1FFF; + this.StorageReset(); + } + + + StorageReset() { + this.IntDisableRegister = 0x00;//IntInit + + for (let i = 0; i < 7; i++) + this.MPR[i] = 0xFF << 13; + this.MPR[7] = 0x00; + + this.MPRSelect = 0x01; + } + + + Get16(address) { + return (this.Get(address + 1) << 8) | this.Get(address); + } + + + Get(address) { + address = this.MPR[address >> 13] | (address & 0x1FFF); + + if (address < 0x100000)// ROM + return this.Mapper.Read(address); + + if (address < 0x1EE000)// NOT USE + return 0xFF; + + if (address < 0x1F0000) {// BRAM + if (this.BRAMUse) + return this.BRAM[address & 0x1FFF]; + else + return 0xFF; + } + + if (address < 0x1F8000)// RAM + return this.RAM[address & this.RAMMask]; + + if (address < 0x1FE000)// NOT USE + return 0xFF; + + if (address < 0x1FE400) {// VDC + if (this.SuperGrafx) { + let tmp = address & 0x00001F; + if (tmp < 0x00008) { + switch (address & 0x000003) {// VDC#1 + case 0x00: + return this.GetVDCStatus(0); + case 0x01: + return 0x00; + case 0x02: + return this.GetVDCLow(0); + case 0x03: + return this.GetVDCHigh(0); + } + } else if (tmp < 0x00010) {// VPC + return this.GetVPC(tmp & 0x000007); + } else if (tmp < 0x00018) {// VDC#2 + switch (address & 0x000003) { + case 0x00: + return this.GetVDCStatus(1); + case 0x01: + return 0x00; + case 0x02: + return this.GetVDCLow(1); + case 0x03: + return this.GetVDCHigh(1); + } + } else { + return 0xFF; + } + } else { + switch (address & 0x000003) {// VDC#1 + case 0x00: + return this.GetVDCStatus(0); + case 0x01: + return 0x00; + case 0x02: + return this.GetVDCLow(0); + case 0x03: + return this.GetVDCHigh(0); + } + } + } + + if (address < 0x1FE800) {// VCE + switch (address & 0x000007) { + case 0x04: + return this.GetVCEDataLow(); + case 0x05: + return this.GetVCEDataHigh(); + default: + return 0x00; + + } + } + + if (address < 0x1FEC00)// PSG + return this.GetPSG(address & 0x00000F); + + if (address < 0x1FF000)// TIMER + return this.ReadTimerCounter(); + + if (address < 0x1FF400)// IO + return this.GetJoystick(); + + if (address < 0x1FF800) {// INT Register + switch (address & 0x000003) { + case 0x02: + return this.GetIntDisable(); + case 0x03: + return this.GetIntReqest(); + default: + return 0x00; + } + } + + return 0xFF;//EXT + } + + + Set(address, data) { + address = this.MPR[address >> 13] | (address & 0x1FFF); + + if (address < 0x100000) {// ROM + this.Mapper.Write(address, data); + return; + } + + if (address < 0x1EE000)// NOT USE + return; + + if (address < 0x1F0000) {// BRAM + if (this.BRAMUse) + this.BRAM[address & 0x1FFF] = data; + return; + } + + if (address < 0x1F8000) {// RAM + this.RAM[address & this.RAMMask] = data; + return; + } + + if (address < 0x1FE000)// NOT USE + return; + + if (address < 0x1FE400) {// VDC + if (this.SuperGrafx) { + let tmp = address & 0x00001F; + if (tmp < 0x00008) { + switch (address & 0x000003) {// VDC#1 + case 0x00: + this.SetVDCRegister(data, 0); + break; + case 0x02: + this.SetVDCLow(data, 0); + break; + case 0x03: + this.SetVDCHigh(data, 0); + break; + } + } else if (tmp < 0x00010) {// VPC + this.SetVPC(tmp & 0x000007, data); + } else if (tmp < 0x00018) {// VDC#2 + switch (address & 0x000003) { + case 0x00: + this.SetVDCRegister(data, 1); + break; + case 0x02: + this.SetVDCLow(data, 1); + break; + case 0x03: + this.SetVDCHigh(data, 1); + break; + } + } + } else { + switch (address & 0x000003) {// VDC#1 + case 0x00: + this.SetVDCRegister(data, 0); + break; + case 0x01: + break; + case 0x02: + this.SetVDCLow(data, 0); + break; + case 0x03: + this.SetVDCHigh(data, 0); + break; + } + } + return; + } + + if (address < 0x1FE800) {// VCE + switch (address & 0x000007) { + case 0x00: + this.SetVCEControl(data); + break; + case 0x02: + this.SetVCEAddressLow(data); + break; + case 0x03: + this.SetVCEAddressHigh(data); + break; + case 0x04: + this.SetVCEDataLow(data); + break; + case 0x05: + this.SetVCEDataHigh(data); + break; + } + return; + } + + if (address < 0x1FEC00) {// PSG + this.SetPSG(address & 0x00000F, data); + return; + } + + if (address < 0x1FF000) {// TIMER + switch (address & 0x000001) { + case 0x00: + this.WirteTimerReload(data); + break; + case 0x01: + this.WirteTimerControl(data); + break; + } + return; + } + + if (address < 0x1FF400) {// IO + this.SetJoystick(data); + return; + } + + if (address < 0x1FF800) {// INT Register + switch (address & 0x000003) { + case 0x02: + this.SetIntDisable(data); + break; + case 0x03: + this.SetIntReqest(data); + break; + } + return; + } + } + + + /* ************* */ + /* **** VCE **** */ + /* ************* */ + VCEConstruct() { + this.Palette = new Array(512); + this.PaletteData = new Array(512); + this.MonoPaletteData = new Array(512); + + this.VCEBaseClock = 0; + this.VCEControl = 0; + this.VCEAddress = 0; + this.VCEData = 0; + } + + + VCEInit() { + this.Palette.fill(0x0000); + for (let i = 0; i < 512; i++) { + this.PaletteData[i] = { r: 0, g: 0, b: 0 }; + this.MonoPaletteData[i] = { r: 0, g: 0, b: 0 }; + } + + this.VCEBaseClock = this.BaseClock5; + this.VCEControl = 0x00; + this.VCEAddress = 0x00; + this.VCEData = 0x00; + } + + + SetVCEControl(data) { + this.VCEControl = data; + + switch (data & 0x03) { + case 0x00: + this.VCEBaseClock = this.BaseClock5; + break; + case 0x01: + this.VCEBaseClock = this.BaseClock7; + break; + case 0x02: + case 0x03: + this.VCEBaseClock = this.BaseClock10; + break; + } + } + + + SetVCEAddressLow(data) { + this.VCEAddress = (this.VCEAddress & 0xFF00) | data; + } + + + SetVCEAddressHigh(data) { + this.VCEAddress = ((this.VCEAddress & 0x00FF) | (data << 8)) & 0x01FF; + } + + + GetVCEDataLow() { + return this.Palette[this.VCEAddress] & 0x00FF; + } + + + GetVCEDataHigh() { + let tmp = (this.Palette[this.VCEAddress] & 0xFF00) >> 8; + this.VCEAddress = (this.VCEAddress + 1) & 0x01FF; + return tmp; + } + + + SetVCEDataLow(data) { + this.Palette[this.VCEAddress] = (this.Palette[this.VCEAddress] & 0xFF00) | data; + this.ToPalettes(); + } + + + SetVCEDataHigh(data) { + this.Palette[this.VCEAddress] = (this.Palette[this.VCEAddress] & 0x00FF) | (data << 8); + this.ToPalettes(); + this.VCEAddress = (this.VCEAddress + 1) & 0x01FF; + } + + + ToPalettes() { + let color = this.Palette[this.VCEAddress]; + let tmp = this.PaletteData[this.VCEAddress]; + tmp.r = ((color >> 3) & 0x07) * 36; + tmp.g = ((color >> 6) & 0x07) * 36; + tmp.b = (color & 0x07) * 36; + + let mono = tmp.r * 0.299 + tmp.g * 0.587 + tmp.b * 0.114; + this.MonoPaletteData[this.VCEAddress].r = mono; + this.MonoPaletteData[this.VCEAddress].g = mono; + this.MonoPaletteData[this.VCEAddress].b = mono; + } + + + /* ************* */ + /* **** VPC **** */ + /* ************* */ + VPCConstruct() { + this.VPCRegister = new Uint8Array(8); + this.VDCSelect = 0; + this.VPCWindow1 = 0; + this.VPCWindow2 = 0; + this.VPCPriority = new Uint8Array(4); + } + + + VPCInit() { + this.VPCRegister.fill(0x00); + this.VPCRegister[0] = 0x11; + this.VPCRegister[1] = 0x11; + this.VPCRegister[7] = 0xFF; + + this.VDCSelect = 0; + this.VPCWindow1 = 0; + this.VPCWindow2 = 0; + this.VPCPriority.fill(0x01); + } + + + SetVPC(no, data) { + if (no == 0x07) + return; + + this.VPCRegister[no] = data; + if (no == 0x06) + this.VDCSelect = data & 0x01; + + if (no == 0x02 || no == 0x03) { + this.VPCWindow1 = (this.VPCRegister[0x02] | ((this.VPCRegister[0x03] & 0x03) << 8)) - 64; + if (this.VPCWindow1 < 0) + this.VPCWindow1 = 1024; + } + + if (no == 0x04 || no == 0x05) { + this.VPCWindow2 = (this.VPCRegister[0x04] | ((this.VPCRegister[0x05] & 0x03) << 8)) - 64; + if (this.VPCWindow2 < 0) + this.VPCWindow2 = -1; + } + + if (no == 0x00) { + this.VPCPriority[2] = this.VPCRegister[0x00] >> 4; + this.VPCPriority[3] = this.VPCRegister[0x00] & 0x0F; + } + + if (no == 0x01) { + this.VPCPriority[0] = this.VPCRegister[0x01] >> 4; + this.VPCPriority[1] = this.VPCRegister[0x01] & 0x0F; + } + } + + + GetVPC(no) { + return this.VPCRegister[no]; + } + + + /* ************* */ + /* **** VDC **** */ + /* ************* */ + VDCConstruct() { + this.DrawFlag = false; + this.VDCPutLineProgressClock = 0; + this.VDCPutLine = 0; + this.VDC = new Array(2); + + this.VDCLineClock = 1368; + + this.ScreenSize = []; + this.ScreenSize[this.BaseClock5] = 342; + this.ScreenSize[this.BaseClock7] = 456; + this.ScreenSize[this.BaseClock10] = 684; + + this.PutScreenSize = []; + this.PutScreenSize[this.BaseClock5] = 320; + this.PutScreenSize[this.BaseClock7] = 428; + this.PutScreenSize[this.BaseClock10] = 640; + + this.ScreenHeightMAX = 262; + this.ScreenWidthMAX = 684; + + this.VScreenWidthArray = []; + this.VScreenWidthArray[0x00] = 32; + this.VScreenWidthArray[0x10] = 64; + this.VScreenWidthArray[0x20] = 128; + this.VScreenWidthArray[0x30] = 128; + + this.ReverseBit = new Uint8Array(0x100); + this.ReverseBit = this.ReverseBit.map((d, i) => { + return ((i & 0x80) >> 7) | ((i & 0x40) >> 5) | + ((i & 0x20) >> 3) | ((i & 0x10) >> 1) | + ((i & 0x08) << 1) | ((i & 0x04) << 3) | + ((i & 0x02) << 5) | ((i & 0x01) << 7); + }); + + this.ReverseBit16 = new Uint16Array(0x10000).fill(0x00); + this.ReverseBit16 = this.ReverseBit16.map((d, i) => { return (this.ReverseBit[i & 0x00FF] << 8) | this.ReverseBit[(i & 0xFF00) >> 8]; }); + + this.ReverseBit256 = new Uint32Array(0x100).fill(0x00); + this.ReverseBit256 = this.ReverseBit256.map((d, i) => { + let b = this.ReverseBit[i]; + return ((b & 0x80) << (28 - 7)) | + ((b & 0x40) << (24 - 6)) | + ((b & 0x20) << (20 - 5)) | + ((b & 0x10) << (16 - 4)) | + ((b & 0x08) << (12 - 3)) | + ((b & 0x04) << (8 - 2)) | + ((b & 0x02) << (4 - 1)) | + ((b & 0x01) << (0 - 0)); + }); + + this.SPAddressMask = []; + this.SPAddressMask[16] = []; + this.SPAddressMask[32] = []; + this.SPAddressMask[16][16] = 0x07FE; + this.SPAddressMask[16][32] = 0x07FE & 0x07FA; + this.SPAddressMask[16][64] = 0x07FE & 0x07F2; + this.SPAddressMask[32][16] = 0x07FC; + this.SPAddressMask[32][32] = 0x07FC & 0x07FA; + this.SPAddressMask[32][64] = 0x07FC & 0x07F2; + } + + + MakeSpriteLine(vdcno) { + let vdcc = this.VDC[vdcno]; + + let sp = vdcc.SPLine; + for (let i = 0; i < vdcc.ScreenWidth; i++) { + let spi = sp[i]; + spi.data = 0x00; + spi.palette = 0x000; + spi.no = 255; + spi.priority = 0x00; + } + + if ((vdcc.VDCRegister[0x05] & 0x0040) == 0x0000) + return; + + let dotcount = 0; + let line = vdcc.DrawBGYLine - (vdcc.VDS + vdcc.VSW) + 64; + + let vram = vdcc.VRAM; + let satb = vdcc.SATB; + let revbit16 = this.ReverseBit16; + for (let i = 0, s = 0; i < 64; i++, s += 4) { + let y = satb[s] & 0x3FF; + let attribute = satb[s + 3]; + + let height = ((attribute & 0x3000) >> 8) + 16; + height = height > 32 ? 64 : height; + + if (line < y || line > (y + height - 1)) + continue; + + let x = (satb[s + 1] & 0x3FF) - 32; + let width = ((attribute & 0x0100) >> 4) + 16; + if ((x + width) <= 0) + continue; + + let spy = line - y; + if ((attribute & 0x8000) == 0x8000) + spy = (height - 1) - spy; + + let index = ((satb[s + 2] & this.SPAddressMask[width][height]) << 5) | (((spy & 0x30) << 3) | (spy & 0x0F)); + + let data0; + let data1; + let data2; + let data3; + if ((attribute & 0x0800) == 0x0000) { + data0 = revbit16[vram[index]]; + data1 = revbit16[vram[index + 16]]; + data2 = revbit16[vram[index + 32]]; + data3 = revbit16[vram[index + 48]]; + if (width == 32) { + data0 |= revbit16[vram[(index | 0x0040)]] << 16; + data1 |= revbit16[vram[(index | 0x0040) + 16]] << 16; + data2 |= revbit16[vram[(index | 0x0040) + 32]] << 16; + data3 |= revbit16[vram[(index | 0x0040) + 48]] << 16; + } + } else { + data0 = vram[index]; + data1 = vram[index + 16]; + data2 = vram[index + 32]; + data3 = vram[index + 48]; + if (width == 32) { + data0 = (data0 << 16) | vram[(index | 0x0040)]; + data1 = (data1 << 16) | vram[(index | 0x0040) + 16]; + data2 = (data2 << 16) | vram[(index | 0x0040) + 32]; + data3 = (data3 << 16) | vram[(index | 0x0040) + 48]; + } + } + + let palette = ((attribute & 0x000F) << 4) | 0x0100; + let priority = attribute & 0x0080; + + let j = 0; + if (x < 0) { + j -= x; + x = 0; + } + + for (; j < width && x < vdcc.ScreenWidth; j++, x++) { + let spx = sp[x]; + if (spx.data == 0x00) { + let dot = ((data0 >>> j) & 0x0001) + | (((data1 >>> j) << 1) & 0x0002) + | (((data2 >>> j) << 2) & 0x0004) + | (((data3 >>> j) << 3) & 0x0008); + if (dot != 0x00) { + spx.data = dot; + spx.palette = palette; + spx.priority = priority; + } + } + + if (spx.no == 255) + spx.no = i; + + if (i != 0 && spx.no == 0) + vdcc.VDCStatus |= vdcc.VDCRegister[0x05] & 0x0001;//SetSpriteCollisionINT + + if (++dotcount == 256) { + vdcc.VDCStatus |= vdcc.VDCRegister[0x05] & 0x0002;//SetSpriteOverINT + if (vdcc.SpriteLimit) + return; + } + } + } + } + + + MakeBGLine(vdcno) { + let vdcc = this.VDC[vdcno]; + + let sp = vdcc.SPLine; + let bg = vdcc.BGLine; + let sw = vdcc.ScreenWidth; + let leftblank = ((vdcc.HDS + vdcc.HSW) << 3) + vdcc.DrawBGIndex; + + if ((vdcc.VDCRegister[0x05] & 0x0080) == 0x0080) { + let WidthMask = vdcc.VScreenWidth - 1; + + let x = vdcc.VDCRegister[0x07]; + let index_x = (x >> 3) & WidthMask; + x = (x & 0x07) << 2; + + let y = vdcc.DrawBGLine; + let index_y = ((y >> 3) & (vdcc.VScreenHeight - 1)) * vdcc.VScreenWidth; + y = y & 0x07; + + let vram = vdcc.VRAM; + let bgx = 0; + let revbit = this.ReverseBit256; + + while (bgx < sw) { + let tmp = vram[index_x + index_y]; + let address = ((tmp & 0x0FFF) << 4) + y; + let palette = (tmp & 0xF000) >> 8; + + let data0 = vram[address]; + let data1 = vram[address + 8]; + let data = (revbit[data0 & 0x00FF]) | + (revbit[(data0 & 0xFF00) >> 8] << 1) | + (revbit[data1 & 0x00FF] << 2) | + (revbit[(data1 & 0xFF00) >> 8] << 3); + + for (; x < 32 && bgx < sw; x += 4, bgx++) { + let dot = (data >>> x) & 0x0F; + let spbgx = sp[bgx]; + bg[bgx + leftblank] = spbgx.data != 0x00 && (dot == 0x00 || spbgx.priority == 0x0080) ? + spbgx.data | spbgx.palette : dot | (dot == 0x00 ? 0x00 : palette); + } + + x = 0; + index_x = (index_x + 1) & WidthMask; + } + } else { + for (let i = 0; i < sw; i++) + bg[i + leftblank] = sp[i].data | sp[i].palette; + } + } + + + MakeBGColorLineVDC(vdcno) { + this.VDC[vdcno].BGLine.fill(0x100); + } + + + VDCProcessDMA(vdcno) { + let vdcc = this.VDC[vdcno]; + + if (vdcc.VRAMtoSATBCount > 0) {//VRAMtoSATB + vdcc.VRAMtoSATBCount -= this.ProgressClock; + if (vdcc.VRAMtoSATBCount <= 0) + vdcc.VDCStatus = (vdcc.VDCStatus & 0xBF) | ((vdcc.VDCRegister[0x0F] & 0x0001) << 3);//VRAMtoSATB INT + } + + if (vdcc.VRAMtoVRAMCount > 0) {//VRAMtoVRAM + vdcc.VRAMtoVRAMCount -= this.ProgressClock; + if (vdcc.VRAMtoVRAMCount <= 0) + vdcc.VDCStatus = (vdcc.VDCStatus & 0xBF) | ((vdcc.VDCRegister[0x0F] & 0x0002) << 3);//VRAMtoVRAM INT + } + } + + + VDCProcess(vdcno) { + let vdcc = this.VDC[vdcno]; + + vdcc.VDCProgressClock -= this.VDCLineClock; + + vdcc.DrawBGIndex = 0; + vdcc.BGLine.fill(0x100); + + for (let i = 0; i < vdcc.ScreenSize; i += vdcc.DrawLineWidth) { + vdcc.DrawBGYLine++; + + if (vdcc.DrawBGYLine == this.ScreenHeightMAX) + vdcc.DrawBGYLine = 0; + + if (vdcc.DrawBGYLine < (vdcc.VDS + vdcc.VSW)) {//OVER SCAN + this.MakeBGColorLineVDC(vdcno); + } else if (vdcc.DrawBGYLine <= (vdcc.VDS + vdcc.VSW + vdcc.VDW)) {//ACTIVE DISPLAY + vdcc.DrawBGLine = (vdcc.DrawBGYLine == (vdcc.VDS + vdcc.VSW) ? vdcc.VDCRegister[0x08] : (vdcc.DrawBGLine + 1)) & vdcc.VScreenHeightMask; + if (!vdcc.VDCBurst) { + this.MakeSpriteLine(vdcno); + this.MakeBGLine(vdcno); + } else + this.MakeBGColorLineVDC(vdcno); + } else {//OVER SCAN + this.MakeBGColorLineVDC(vdcno); + } + + let vline = vdcc.VDS + vdcc.VSW + vdcc.VDW + 1; + if (vline > 261) + vline -= 261; + if (vdcc.DrawBGYLine == vline) { + vdcc.VDCStatus |= (vdcc.VDCRegister[0x05] & 0x0008) << 2;//SetVSync INT + if (vdcc.VRAMtoSATBStartFlag) {//VRAMtoSATB + for (let i = 0, addr = vdcc.VDCRegister[0x13]; i < 256; i++, addr++) + vdcc.SATB[i] = vdcc.VRAM[addr]; + vdcc.VRAMtoSATBCount = 256 * this.VCEBaseClock; + vdcc.VDCStatus |= 0x40; + vdcc.VRAMtoSATBStartFlag = (vdcc.VDCRegister[0x0F] & 0x0010) == 0x0010; + } + } + + vdcc.RasterCount++; + if (vdcc.DrawBGYLine == (vdcc.VDS + vdcc.VSW - 1)) + vdcc.RasterCount = 64; + + if (vdcc.RasterCount == vdcc.VDCRegister[0x06] && (vdcc.VDCStatus & 0x20) == 0x00) + vdcc.VDCStatus |= vdcc.VDCRegister[0x05] & 0x0004;//SetRaster INT + + vdcc.DrawBGIndex += vdcc.DrawLineWidth; + } + } + + + VDCRun() { + this.VDCProcessDMA(0); + this.VDC[0].VDCProgressClock += this.ProgressClock; + + if (this.SuperGrafx) { + this.VDCProcessDMA(1); + this.VDC[1].VDCProgressClock += this.ProgressClock; + } + + while (this.VDC[0].VDCProgressClock >= this.VDCLineClock) { + this.VDCProcess(0); + if (this.SuperGrafx) + this.VDCProcess(1); + } + + this.VDCPutLineProgressClock += this.ProgressClock; + if (this.VDCPutLineProgressClock >= this.VDCLineClock) { + this.VDCPutLineProgressClock -= this.VDCLineClock; + this.VDCPutLine++; + + if (this.VDCPutLine == this.ScreenHeightMAX) { + this.VDCPutLine = 0; + this.GetScreenSize(0); + this.VDC[0].DrawBGYLine = 0; + if (this.SuperGrafx) { + this.GetScreenSize(1); + this.VDC[1].DrawBGYLine = 0; + } + this.DrawFlag = true; + this.Ctx.putImageData(this.ImageData, 0, 0); + } + + let palettes = (this.VCEControl & 0x80) == 0x00 ? this.PaletteData : this.MonoPaletteData; + + let data = this.ImageData.data; + let imageIndex = this.VDCPutLine * this.ScreenWidthMAX * 4; + let black = palettes[0x100]; + + let sw = this.ScreenSize[this.VCEBaseClock]; + let bgl0 = this.VDC[0].BGLine; + + if (this.SuperGrafx) {//VPC + let window1 = this.VPCWindow1; + let window2 = this.VPCWindow2; + let priority = this.VPCPriority; + + let bgl1 = this.VDC[1].BGLine; + for (let bgx = 0; bgx < sw; bgx++, imageIndex += 4) { + let wflag = 0x00; + if (bgx >= window1) + wflag |= 0x01; + if (bgx <= window2) + wflag |= 0x02; + + let bg0 = bgl0[bgx]; + let bg1 = bgl1[bgx]; + + let color; + switch (priority[wflag]) { + case 0x04 | 0x03: + if (bg0 > 0x100 || bg1 > 0x100) + color = palettes[bg0 > 0x100 ? bg0 : bg1]; + else + color = palettes[(bg0 & 0x0FF) != 0x000 ? bg0 : bg1]; + + break; + case 0x08 | 0x03: + if (bg0 < 0x100 && bg0 != 0x000) + color = palettes[bg0]; + else + color = palettes[(bg1 & 0x0FF) != 0x000 ? bg1 : bg0]; + break; + case 0x00 | 0x03: + case 0x0C | 0x03: + color = palettes[(bg0 & 0x0FF) != 0x000 ? bg0 : bg1]; + break; + case 0x00 | 0x01: + case 0x04 | 0x01: + case 0x08 | 0x01: + case 0x0C | 0x01: + color = palettes[bg0]; + break; + case 0x00 | 0x02: + case 0x04 | 0x02: + case 0x08 | 0x02: + case 0x0C | 0x02: + color = palettes[bg1]; + break; + default: + color = black; + break; + } + data[imageIndex] = color.r; + data[imageIndex + 1] = color.g; + data[imageIndex + 2] = color.b; + } + } else { + for (let bgx = 0; bgx < sw; bgx++, imageIndex += 4) { + let color = palettes[bgl0[bgx]]; + data[imageIndex] = color.r; + data[imageIndex + 1] = color.g; + data[imageIndex + 2] = color.b; + } + } + } + } + + + GetScreenSize(vdcno) { + let vdcc = this.VDC[vdcno]; + let r = vdcc.VDCRegister; + + vdcc.VScreenWidth = this.VScreenWidthArray[r[0x09] & 0x0030]; + + vdcc.VScreenHeight = (r[0x09] & 0x0040) == 0x0000 ? 32 : 64; + vdcc.VScreenHeightMask = vdcc.VScreenHeight * 8 - 1; + vdcc.ScreenWidth = ((r[0x0B] & 0x007F) + 1) * 8; + + if (vdcc.ScreenWidth > this.ScreenWidthMAX) + vdcc.ScreenWidth = this.ScreenWidthMAX; + + vdcc.HDS = (r[0x0A] & 0x7F00) >> 8; + vdcc.HSW = r[0x0A] & 0x001F; + + vdcc.HDE = (r[0x0B] & 0x7F00) >> 8; + vdcc.HDW = r[0x0B] & 0x007F; + + vdcc.VDS = ((r[0x0C] & 0xFF00) >> 8); + vdcc.VSW = r[0x0C] & 0x001F; + + vdcc.VDW = r[0x0D] & 0x01FF; + + vdcc.VCR = r[0x0E] & 0x00FF; + + vdcc.ScreenSize = this.ScreenSize[this.VCEBaseClock]; + if (this.MainCanvas.width != vdcc.ScreenSize) { + //this.MainCanvas.style.width = (this.PutScreenSize[this.VCEBaseClock] * 2) + 'px'; + this.MainCanvas.width = this.PutScreenSize[this.VCEBaseClock]; + } + + vdcc.DrawLineWidth = (vdcc.HDS + vdcc.HSW + vdcc.HDE + vdcc.HDW + 1) << 3; + if (vdcc.DrawLineWidth <= this.ScreenSize[this.BaseClock5]) + vdcc.DrawLineWidth = this.ScreenSize[this.BaseClock5]; + else if (vdcc.DrawLineWidth <= this.ScreenSize[this.BaseClock7]) + vdcc.DrawLineWidth = this.ScreenSize[this.BaseClock7]; + else vdcc.DrawLineWidth = this.ScreenSize[this.BaseClock10]; + + vdcc.VDCBurst = (r[0x05] & 0x00C0) == 0x0000 ? true : false; + } + + + VDCInit() { + this.VDCPutLineProgressClock = 0; + this.VDCPutLine = 0; + this.DrawFlag = false; + + for (let vdcno = 0; vdcno < 2; vdcno++) { + this.VDC[vdcno] = { + VDCRegister: new Uint16Array(20).fill(0x0000), + VRAM: new Uint16Array(0x10000).fill(0x0000), + SATB: new Uint16Array(256).fill(0x0000), + VDCBurst: false, + SpriteLimit: false, + + SPLine: new Array(this.ScreenWidthMAX), + BGLine: new Array(this.ScreenWidthMAX).fill(0x00), + + VDCStatus: 0x00, + VDCRegisterSelect: 0x00, + WriteVRAMData: 0x0000, + + VRAMtoSATBStartFlag: false, + VRAMtoSATBCount: 0, + VRAMtoVRAMCount: 0, + + RasterCount: 64, + VDCProgressClock: 0, + DrawBGYLine: 0, + DrawBGLine: 0, + + VScreenWidth: 0, + VScreenHeight: 0, + VScreenHeightMask: 0, + ScreenWidth: 0, + ScreenSize: 0, + DrawLineWidth: 0, + DrawBGIndex: 0, + + HDS: 0, + HSW: 0, + HDE: 0, + HDW: 0, + VDS: 0, + VSW: 0, + VDW: 0, + VCR: 0 + }; + + for (let i = 0; i < this.VDC[vdcno].SPLine.length; i++) + this.VDC[vdcno].SPLine[i] = { data: 0x00, no: 255, priority: 0x00 }; + + this.VDC[vdcno].VDCRegister[0x09] = 0x0010; + this.VDC[vdcno].VDCRegister[0x0A] = 0x0202; + this.VDC[vdcno].VDCRegister[0x0B] = 0x031F; + this.VDC[vdcno].VDCRegister[0x0C] = 0x0F02; + this.VDC[vdcno].VDCRegister[0x0D] = 0x00EF; + this.VDC[vdcno].VDCRegister[0x0E] = 0x0003; + } + + this.GetScreenSize(0); + this.GetScreenSize(1); + } + + + SetVDCRegister(data, vdcno) { + this.VDC[vdcno].VDCRegisterSelect = data & 0x1F; + } + + + SetVDCLow(data, vdcno) { + let vdcc = this.VDC[vdcno]; + + if (vdcc.VDCRegisterSelect == 0x02) + vdcc.WriteVRAMData = data; + else + vdcc.VDCRegister[vdcc.VDCRegisterSelect] = (vdcc.VDCRegister[vdcc.VDCRegisterSelect] & 0xFF00) | data; + + if (vdcc.VDCRegisterSelect == 0x01) { + vdcc.VDCRegister[0x02] = vdcc.VRAM[vdcc.VDCRegister[0x01]]; + return; + } + + if (vdcc.VDCRegisterSelect == 0x08) { + vdcc.DrawBGLine = vdcc.VDCRegister[0x08]; + return; + } + + if (vdcc.VDCRegisterSelect == 0x0F) + vdcc.VRAMtoSATBStartFlag = (vdcc.VDCRegister[0x0F] & 0x10) == 0x10; + } + + + SetVDCHigh(data, vdcno) { + let vdcc = this.VDC[vdcno]; + + if (vdcc.VDCRegisterSelect == 0x02) { + vdcc.VRAM[vdcc.VDCRegister[0x00]] = vdcc.WriteVRAMData | (data << 8); + vdcc.VDCRegister[0x00] = (vdcc.VDCRegister[0x00] + this.GetVRAMIncrement(vdcno)) & 0xFFFF; + return; + } + + vdcc.VDCRegister[vdcc.VDCRegisterSelect] = (vdcc.VDCRegister[vdcc.VDCRegisterSelect] & 0x00FF) | (data << 8); + + if (vdcc.VDCRegisterSelect == 0x01) { + vdcc.VDCRegister[0x02] = vdcc.VRAM[vdcc.VDCRegister[0x01]]; + vdcc.VDCRegister[0x03] = vdcc.VDCRegister[0x02]; + vdcc.VDCRegister[0x01] = (vdcc.VDCRegister[0x01] + this.GetVRAMIncrement(vdcno)) & 0xFFFF; + return; + } + + if (vdcc.VDCRegisterSelect == 0x08) { + vdcc.DrawBGLine = vdcc.VDCRegister[0x08]; + return; + } + + if (vdcc.VDCRegisterSelect == 0x12) {//VRAMtoVRAM + let si = (vdcc.VDCRegister[0x0F] & 0x0004) == 0x0000 ? 1 : -1; + let di = (vdcc.VDCRegister[0x0F] & 0x0008) == 0x0000 ? 1 : -1; + + let s = vdcc.VDCRegister[0x10]; + let d = vdcc.VDCRegister[0x11]; + let l = vdcc.VDCRegister[0x12] + 1; + + vdcc.VRAMtoVRAMCount = l * this.VCEBaseClock; + vdcc.VDCStatus |= 0x40; + + let vram = vdcc.VRAM; + for (; l > 0; l--) { + vram[d] = vram[s]; + s = (s + si) & 0xFFFF; + d = (d + di) & 0xFFFF; + } + return; + } + + if (vdcc.VDCRegisterSelect == 0x13)//VRAMtoSATB + vdcc.VRAMtoSATBStartFlag = true; + } + + + GetVRAMIncrement(vdcno) { + switch (this.VDC[vdcno].VDCRegister[0x05] & 0x1800) { + case 0x0000: + return 1; + case 0x0800: + return 32; + case 0x1000: + return 64; + case 0x1800: + return 128; + } + } + + + GetVDCStatus(vdcno) { + let tmp = this.VDC[vdcno].VDCStatus; + this.VDC[vdcno].VDCStatus &= 0x40; + return tmp; + } + + + GetVDCLow(vdcno) { + return this.VDC[vdcno].VDCRegister[this.VDC[vdcno].VDCRegisterSelect] & 0x00FF; + } + + + GetVDCHigh(vdcno) { + let vdcc = this.VDC[vdcno]; + + if (vdcc.VDCRegisterSelect == 0x02 || vdcc.VDCRegisterSelect == 0x03) { + let tmp = (vdcc.VDCRegister[0x02] & 0xFF00) >> 8; + vdcc.VDCRegister[0x02] = vdcc.VRAM[vdcc.VDCRegister[0x01]]; + vdcc.VDCRegister[0x03] = vdcc.VDCRegister[0x02]; + vdcc.VDCRegister[0x01] = (vdcc.VDCRegister[0x01] + this.GetVRAMIncrement(vdcno)) & 0xFFFF; + return tmp; + } + + return (vdcc.VDCRegister[vdcc.VDCRegisterSelect] & 0xFF00) >> 8; + } + + + /* *************** */ + /* **** Sound **** */ + /* *************** */ + SoundConstruct() { + this.WaveDataArray = []; + this.WaveClockCounter = 0; + this.WaveVolume = 1.0; + + this.WebAudioCtx = null; + this.WebAudioJsNode = null; + this.WebAudioGainNode = null; + this.WebAudioBufferSize = 2048; + + this.PSGClock = 3579545; + } + + + WebAudioFunction(e) { + let output = []; + let data = []; + + for (let i = 0; i < 2; i++) { + output[i] = e.outputBuffer.getChannelData(i); + data[i] = new Float32Array(this.WebAudioBufferSize); + if (this.WaveDataArray[i].length < this.WebAudioBufferSize) { + data[i].fill(0.0); + } else { + for (let j = 0; j < data[i].length; j++) + data[i][j] = this.WaveDataArray[i].shift() / ((32 * 16 * 32) * 8 * 16); + if (this.WaveDataArray[i].length > this.WebAudioBufferSize * 2) + this.WaveDataArray[i] = this.WaveDataArray[i].slice(this.WebAudioBufferSize); + } + output[i].set(data[i]); + } + } + + SoundInit() { + this.WaveClockCounter = 0; + this.WaveDataArray = []; + this.WaveDataArray[0] = []; + this.WaveDataArray[1] = []; + + if (typeof AudioContext !== "undefined" && this.WebAudioCtx == null) { this.CreateAudioContext(); - } - } + } + } CreateAudioContext() { this.WebAudioCtx = new window.AudioContext(); @@ -3109,716 +3129,718 @@ class PCE { this.WebAudioGainNode.connect(this.WebAudioCtx.destination); } - SoundSet() { - let waveoutleft; - let waveoutright; - let ch; - - let i; - let j; - let out; - - this.WaveClockCounter += this.WebAudioCtx.sampleRate; - if(this.WaveClockCounter >= this.PSGClock) { - this.WaveClockCounter -= this.PSGClock; - - waveoutleft = 0; - waveoutright = 0; - for(j=0; j<6; j++) { - if(j != 1 || !this.WaveLfoOn) { - ch = this.PSGChannel[j]; - - if(j < 4 || !ch.noiseon) - out = ch.keyon ? (ch.dda ? ch.R[6] & 0x1F : ch.wave[ch.index]) : 0; - else - out = (ch.noise & 0x0001) == 0x0001 ? 0x0F : 0; - - waveoutleft += out * ch.leftvol; - waveoutright += out * ch.rightvol; - } - } - this.WaveDataArray[0].push(waveoutleft * this.WaveVolumeLeft); - this.WaveDataArray[1].push(waveoutright * this.WaveVolumeRight); - this.WebAudioGainNode.gain.value = this.WaveVolume; - } - } - - - /* ************* */ - /* **** PSG **** */ - /* ************* */ - PSGConstruct() { - this.PSGChannel = new Array(6); - this.PSGBaseClock = this.BaseClock3; - - this.PSGProgressClock = 0; - - this.WaveVolumeLeft = 0; - this.WaveVolumeRight = 0; - - this.WaveLfoOn = false; - this.WaveLfoControl = 0; - this.WaveLfoFreqency = 0; - } - - - PSGInit() { - this.SoundInit(); - - for(let i=0; i 0) { - i--; - j = 0; - - if(this.WaveLfoOn) { - ch0 = this.PSGChannel[0]; - ch1 = this.PSGChannel[1]; - if(ch0.keyon) { - if(ch0.count == 0) { - ch0.index = (ch0.index + 1) & 0x1F; - freqtmp = 0; - if(this.WaveLfoControl != 0x00) { - freqtmp = ch1.wave[ch1.index]; - freqtmp = freqtmp > 0x0F ? freqtmp - 0x20 : freqtmp & 0x0F; - freqtmp <<= 4 * (this.WaveLfoControl - 1); - } - freqtmp = ch0.freq + freqtmp; - if(freqtmp < 0) - freqtmp = 0; - ch0.count = freqtmp; - } else - ch0.count--; - - if(ch1.count == 0) { - ch1.index = (ch1.index + 1) & 0x1F; - ch1.count = ch1.freq * this.WaveLfoFreqency; - } else - ch1.count--; - } - j = 2; - } - - for(; j<6; j++) { - ch = this.PSGChannel[j]; - if(j < 4 || !ch.noiseon) { - if(ch.keyon && !ch.dda) { - if(ch.count == 0) { - ch.index = (ch.index + 1) & 0x1F; - ch.count = ch.freq; - } else - ch.count--; - } - } else { - if(ch.keyon && !ch.dda) { - if(ch.count == 0) { - ch.index = (ch.index + 1) & 0x1F; - if(ch.index == 0) - ch.noise = (ch.noise >> 1) | (((ch.noise << 12) ^ (ch.noise << 15)) & 0x8000); - ch.count = ch.noisefreq; - } else - ch.count--; - } - } - } - this.SoundSet(); - } - } - - - SetPSG(r, data) { - if(r == 0) { - this.PSGChannel[0].R[0] = data & 0x07; - return; - } - - if(this.PSGChannel[0].R[0] > 5) - return; - - let ch = this.PSGChannel[this.PSGChannel[0].R[0]]; - ch.R[r] = data; - - switch(r) { - case 1: - this.PSGChannel[0].R[1] = data; - this.WaveVolumeLeft = (data & 0xF0) >> 4; - this.WaveVolumeRight = data & 0x0F; - return; - - case 2: - case 3: - ch.freq = ((ch.R[3] << 8) | ch.R[2]) & 0x0FFF; - return; - - case 4: - ch.keyon = (data & 0x80) == 0x80 ? true : false; - ch.dda = (data & 0x40) == 0x40 ? true : false; - if((data & 0x40) == 0x40) - ch.index = 0; - ch.vol = data & 0x1F; - case 5: - let vol = ch.R[4] & 0x1F; - ch.leftvol = ((ch.R[5] & 0xF0) >> 4) * vol; - ch.rightvol = (ch.R[5] & 0x0F) * vol; - return; - - case 6: - if(!ch.dda) { - ch.wave[ch.index] = data & 0x1F; - ch.index = (ch.index + 1) & 0x1F; - } - return; - - case 7: - ch.noiseon = (data & 0x80) == 0x80 ? true : false; - ch.noisefreq = (data & 0x1F) ^ 0x1F; - return; - - case 8: - this.PSGChannel[0].R[8] = data; - this.WaveLfoFreqency = data; - return; - - case 9: - this.PSGChannel[0].R[9] = data; - this.WaveLfoOn = (data & 0x80) == 0x80 ? true : false; - this.WaveLfoControl = data & 0x03; - return; - } - } - - - GetPSG(r) { - if(r > 9) - return 0xFF; - if(r == 0 || r == 1 || r == 8 || r == 9) - return this.PSGChannel[0].R[r]; - if(this.PSGChannel[0].R[0] > 5) - return 0xFF; - return this.PSGChannel[this.PSGChannel[0].R[0]].R[r]; - } - - - /* *************** */ - /* **** TIMER **** */ - /* *************** */ - TimerConstruct() { - this.TimerBaseClock = this.BaseClock7; - this.TimerReload = 0; - this.TimerFlag = false; - this.TimerCounter = 0; - this.TimerPrescaler = 0; - this.INTTIQ = 0; - } - - - TimerInit() { - this.TimerReload = 0x00; - this.TimerFlag = false; - this.TimerCounter = 0x00; - this.TimerPrescaler = 0; - this.INTTIQ = 0x00; - } - - - ReadTimerCounter() { - return this.TimerCounter; - } - - - TimerAcknowledge() { - this.INTTIQ = 0x00; - } - - - WirteTimerReload(data) { - this.TimerReload = data & 0x7F; - } - - - WirteTimerControl(data) { - if(!this.TimerFlag && (data & 0x01) == 0x01) { - this.TimerCounter = this.TimerReload; - this.TimerPrescaler = 0; - } - - this.TimerFlag = (data & 0x01) == 0x01 ? true : false; - } - - - TimerRun() { - if(this.TimerFlag) { - this.TimerPrescaler += this.ProgressClock; - while(this.TimerPrescaler >= (1024 * this.TimerBaseClock)) { - this.TimerPrescaler -= 1024 * this.TimerBaseClock; - this.TimerCounter--; - if(this.TimerCounter < 0) { - this.TimerCounter = this.TimerReload; - this.INTTIQ = this.TIQFlag; - } - } - } - } - - - /* ****************** */ - /* **** Joystick **** */ - /* ****************** */ - JoystickConstruct() { - this.JoystickSEL = 0; - this.JoystickCLR = 0; - this.KeyUpFunction = null; - this.KeyDownFunction = null; - - this.Keybord = new Array(5).fill([]); - this.Keybord = this.Keybord.map((d) => { return new Array(4); }); - - this.GamePad = new Array(5).fill([]); - this.GamePad = this.Keybord.map((d) => { return new Array(4); }); - - this.GamePadSelect = 0x00; - this.GamePadButtonSelect = 0x00; - this.GamePadBuffer = 0x00; - - this.GamePadData = []; - this.GamePadData["STANDARD PAD"] = [ - [[{type:"B", index:1}],// SHOT1 - [{type:"B", index:0}],// SHOT2 - [{type:"B", index:8}],// SELECT - [{type:"B", index:9}, {type:"B", index:2}],// RUN - [{type:"B", index:12}],// UP - [{type:"B", index:13}],// DOWN - [{type:"B", index:14}],// LEFT - [{type:"B", index:15}]],// RIGHT - - [[{type:"B", index:1}],// SHOT1 - [{type:"B", index:0}],// SHOT2 - [{type:"B", index:8}],// SELECT - [{type:"B", index:9}],// RUN - [{type:"B", index:12}],// UP - [{type:"B", index:13}],// DOWN - [{type:"B", index:14}],// LEFT - [{type:"B", index:15}],// RIGHT - [{type:"B", index:7}],// SHOT3 - [{type:"B", index:5}],// SHOT4 - [{type:"B", index:2}],// SHOT5 - [{type:"B", index:3}]]];// SHOT6 - - this.GamePadData["HORI PAD 3 TURBO (Vendor: 0f0d Product: 0009)"] = [// Chrome - [[{type:"B", index:2}],// SHOT1 - [{type:"B", index:1}],// SHOT2 - [{type:"B", index:8}],// SELECT - [{type:"B", index:9}, {type:"B", index:0}],// RUN - [{type:"P", index:9}],// UP (POV) - [{type:"N", index:0}],// DOWN (POV) - [{type:"N", index:0}],// LEFT (POV) - [{type:"N", index:0}]],// RIGHT (POV) - - [[{type:"B", index:2}],// SHOT1 - [{type:"B", index:1}],// SHOT2 - [{type:"B", index:8}],// SELECT - [{type:"B", index:9}],// RUN - [{type:"P", index:9}],// UP (POV) - [{type:"N", index:0}],// DOWN (POV) - [{type:"N", index:0}],// LEFT (POV) - [{type:"N", index:0}],// RIGHT (POV) - [{type:"B", index:7}],// SHOT3 - [{type:"B", index:5}],// SHOT4 - [{type:"B", index:0}],// SHOT5 - [{type:"B", index:3}]]];// SHOT6 - - this.GamePadData["0f0d-0009-HORI PAD 3 TURBO"] = this.GamePadData["HORI PAD 3 TURBO (Vendor: 0f0d Product: 0009)"];// Firefox - this.GamePadData["UNKNOWN PAD"] = this.GamePadData["HORI PAD 3 TURBO (Vendor: 0f0d Product: 0009)"]; - - this.GamePadKeyData = [{index:0, data:0x01}, {index:0, data:0x02}, - {index:0, data:0x04}, {index:0, data:0x08}, - {index:1, data:0x01}, {index:1, data:0x04}, - {index:1, data:0x08}, {index:1, data:0x02}, - {index:2, data:0x01}, {index:2, data:0x02}, - {index:2, data:0x04}, {index:2, data:0x08}]; - - this.GamePadPovData = [0x01, 0x01|0x02, 0x02, 0x02|0x04, 0x04, 0x04|0x08, 0x08, 0x01|0x08]; - } - - - JoystickInit() { - this.JoystickSEL = 0; - this.JoystickCLR = 0; - - for(let i=0; i= this.PSGClock) { + this.WaveClockCounter -= this.PSGClock; + + waveoutleft = 0; + waveoutright = 0; + for (j = 0; j < 6; j++) { + if (j != 1 || !this.WaveLfoOn) { + ch = this.PSGChannel[j]; + + if (j < 4 || !ch.noiseon) + out = ch.keyon ? (ch.dda ? ch.R[6] & 0x1F : ch.wave[ch.index]) : 0; + else + out = (ch.noise & 0x0001) == 0x0001 ? 0x0F : 0; + + waveoutleft += out * ch.leftvol; + waveoutright += out * ch.rightvol; + } + } + this.WaveDataArray[0].push(waveoutleft * this.WaveVolumeLeft); + this.WaveDataArray[1].push(waveoutright * this.WaveVolumeRight); + this.WebAudioGainNode.gain.value = this.WaveVolume; + } + } + + + /* ************* */ + /* **** PSG **** */ + /* ************* */ + PSGConstruct() { + this.PSGChannel = new Array(6); + this.PSGBaseClock = this.BaseClock3; + + this.PSGProgressClock = 0; + + this.WaveVolumeLeft = 0; + this.WaveVolumeRight = 0; + + this.WaveLfoOn = false; + this.WaveLfoControl = 0; + this.WaveLfoFreqency = 0; + } + + + PSGInit() { + this.SoundInit(); + + for (let i = 0; i < this.PSGChannel.length; i++) + this.PSGChannel[i] = { + R: new Array(10).fill(0), + keyon: false, + dda: false, + freq: 0, + count: 0, + vol: 0, + leftvol: 0, + rightvol: 0, + noiseon: false, + noisefreq: 0, + noise: 0x8000, + noisestate: 0, + index: 0, + wave: new Uint8Array(32) + }; + } + + + PSGRun() { + if (this.WebAudioCtx == null) + return; + + let ch; + let i; + let j; + let ch0; + let ch1; + let freqtmp; + + this.PSGProgressClock += this.ProgressClock; + i = (this.PSGProgressClock / this.PSGBaseClock) | 0; + this.PSGProgressClock %= this.PSGBaseClock; + + while (i > 0) { + i--; + j = 0; + + if (this.WaveLfoOn) { + ch0 = this.PSGChannel[0]; + ch1 = this.PSGChannel[1]; + if (ch0.keyon) { + if (ch0.count == 0) { + ch0.index = (ch0.index + 1) & 0x1F; + freqtmp = 0; + if (this.WaveLfoControl != 0x00) { + freqtmp = ch1.wave[ch1.index]; + freqtmp = freqtmp > 0x0F ? freqtmp - 0x20 : freqtmp & 0x0F; + freqtmp <<= 4 * (this.WaveLfoControl - 1); + } + freqtmp = ch0.freq + freqtmp; + if (freqtmp < 0) + freqtmp = 0; + ch0.count = freqtmp; + } else + ch0.count--; + + if (ch1.count == 0) { + ch1.index = (ch1.index + 1) & 0x1F; + ch1.count = ch1.freq * this.WaveLfoFreqency; + } else + ch1.count--; + } + j = 2; + } + + for (; j < 6; j++) { + ch = this.PSGChannel[j]; + if (j < 4 || !ch.noiseon) { + if (ch.keyon && !ch.dda) { + if (ch.count == 0) { + ch.index = (ch.index + 1) & 0x1F; + ch.count = ch.freq; + } else + ch.count--; + } + } else { + if (ch.keyon && !ch.dda) { + if (ch.count == 0) { + ch.index = (ch.index + 1) & 0x1F; + if (ch.index == 0) + ch.noise = (ch.noise >> 1) | (((ch.noise << 12) ^ (ch.noise << 15)) & 0x8000); + ch.count = ch.noisefreq; + } else + ch.count--; + } + } + } + this.SoundSet(); + } + } + + + SetPSG(r, data) { + if (r == 0) { + this.PSGChannel[0].R[0] = data & 0x07; + return; + } + + if (this.PSGChannel[0].R[0] > 5) + return; + + let ch = this.PSGChannel[this.PSGChannel[0].R[0]]; + ch.R[r] = data; + + switch (r) { + case 1: + this.PSGChannel[0].R[1] = data; + this.WaveVolumeLeft = (data & 0xF0) >> 4; + this.WaveVolumeRight = data & 0x0F; + return; + + case 2: + case 3: + ch.freq = ((ch.R[3] << 8) | ch.R[2]) & 0x0FFF; + return; + + case 4: + ch.keyon = (data & 0x80) == 0x80 ? true : false; + ch.dda = (data & 0x40) == 0x40 ? true : false; + if ((data & 0x40) == 0x40) + ch.index = 0; + ch.vol = data & 0x1F; + case 5: + let vol = ch.R[4] & 0x1F; + ch.leftvol = ((ch.R[5] & 0xF0) >> 4) * vol; + ch.rightvol = (ch.R[5] & 0x0F) * vol; + return; + + case 6: + if (!ch.dda) { + ch.wave[ch.index] = data & 0x1F; + ch.index = (ch.index + 1) & 0x1F; + } + return; + + case 7: + ch.noiseon = (data & 0x80) == 0x80 ? true : false; + ch.noisefreq = (data & 0x1F) ^ 0x1F; + return; + + case 8: + this.PSGChannel[0].R[8] = data; + this.WaveLfoFreqency = data; + return; + + case 9: + this.PSGChannel[0].R[9] = data; + this.WaveLfoOn = (data & 0x80) == 0x80 ? true : false; + this.WaveLfoControl = data & 0x03; + return; + } + } + + + GetPSG(r) { + if (r > 9) + return 0xFF; + if (r == 0 || r == 1 || r == 8 || r == 9) + return this.PSGChannel[0].R[r]; + if (this.PSGChannel[0].R[0] > 5) + return 0xFF; + return this.PSGChannel[this.PSGChannel[0].R[0]].R[r]; + } + + + /* *************** */ + /* **** TIMER **** */ + /* *************** */ + TimerConstruct() { + this.TimerBaseClock = this.BaseClock7; + this.TimerReload = 0; + this.TimerFlag = false; + this.TimerCounter = 0; + this.TimerPrescaler = 0; + this.INTTIQ = 0; + } + + + TimerInit() { + this.TimerReload = 0x00; + this.TimerFlag = false; + this.TimerCounter = 0x00; + this.TimerPrescaler = 0; + this.INTTIQ = 0x00; + } + + + ReadTimerCounter() { + return this.TimerCounter; + } + + + TimerAcknowledge() { + this.INTTIQ = 0x00; + } + + + WirteTimerReload(data) { + this.TimerReload = data & 0x7F; + } + + + WirteTimerControl(data) { + if (!this.TimerFlag && (data & 0x01) == 0x01) { + this.TimerCounter = this.TimerReload; + this.TimerPrescaler = 0; + } + + this.TimerFlag = (data & 0x01) == 0x01 ? true : false; + } + + + TimerRun() { + if (this.TimerFlag) { + this.TimerPrescaler += this.ProgressClock; + while (this.TimerPrescaler >= (1024 * this.TimerBaseClock)) { + this.TimerPrescaler -= 1024 * this.TimerBaseClock; + this.TimerCounter--; + if (this.TimerCounter < 0) { + this.TimerCounter = this.TimerReload; + this.INTTIQ = this.TIQFlag; + } + } + } + } + + + /* ****************** */ + /* **** Joystick **** */ + /* ****************** */ + JoystickConstruct() { + this.JoystickSEL = 0; + this.JoystickCLR = 0; + this.KeyUpFunction = null; + this.KeyDownFunction = null; + + this.Keybord = new Array(5).fill([]); + this.Keybord = this.Keybord.map((d) => { return new Array(4); }); + + this.GamePad = new Array(5).fill([]); + this.GamePad = this.Keybord.map((d) => { return new Array(4); }); + + this.GamePadSelect = 0x00; + this.GamePadButtonSelect = 0x00; + this.GamePadBuffer = 0x00; + + this.GamePadData = []; + this.GamePadData["STANDARD PAD"] = [ + [[{ type: "B", index: 1 }],// SHOT1 + [{ type: "B", index: 0 }],// SHOT2 + [{ type: "B", index: 8 }],// SELECT + [{ type: "B", index: 9 }, { type: "B", index: 2 }],// RUN + [{ type: "B", index: 12 }],// UP + [{ type: "B", index: 13 }],// DOWN + [{ type: "B", index: 14 }],// LEFT + [{ type: "B", index: 15 }]],// RIGHT + + [[{ type: "B", index: 1 }],// SHOT1 + [{ type: "B", index: 0 }],// SHOT2 + [{ type: "B", index: 8 }],// SELECT + [{ type: "B", index: 9 }],// RUN + [{ type: "B", index: 12 }],// UP + [{ type: "B", index: 13 }],// DOWN + [{ type: "B", index: 14 }],// LEFT + [{ type: "B", index: 15 }],// RIGHT + [{ type: "B", index: 7 }],// SHOT3 + [{ type: "B", index: 5 }],// SHOT4 + [{ type: "B", index: 2 }],// SHOT5 + [{ type: "B", index: 3 }]]];// SHOT6 + + this.GamePadData["HORI PAD 3 TURBO (Vendor: 0f0d Product: 0009)"] = [// Chrome + [[{ type: "B", index: 2 }],// SHOT1 + [{ type: "B", index: 1 }],// SHOT2 + [{ type: "B", index: 8 }],// SELECT + [{ type: "B", index: 9 }, { type: "B", index: 0 }],// RUN + [{ type: "P", index: 9 }],// UP (POV) + [{ type: "N", index: 0 }],// DOWN (POV) + [{ type: "N", index: 0 }],// LEFT (POV) + [{ type: "N", index: 0 }]],// RIGHT (POV) + + [[{ type: "B", index: 2 }],// SHOT1 + [{ type: "B", index: 1 }],// SHOT2 + [{ type: "B", index: 8 }],// SELECT + [{ type: "B", index: 9 }],// RUN + [{ type: "P", index: 9 }],// UP (POV) + [{ type: "N", index: 0 }],// DOWN (POV) + [{ type: "N", index: 0 }],// LEFT (POV) + [{ type: "N", index: 0 }],// RIGHT (POV) + [{ type: "B", index: 7 }],// SHOT3 + [{ type: "B", index: 5 }],// SHOT4 + [{ type: "B", index: 0 }],// SHOT5 + [{ type: "B", index: 3 }]]];// SHOT6 + + this.GamePadData["0f0d-0009-HORI PAD 3 TURBO"] = this.GamePadData["HORI PAD 3 TURBO (Vendor: 0f0d Product: 0009)"];// Firefox + this.GamePadData["UNKNOWN PAD"] = this.GamePadData["HORI PAD 3 TURBO (Vendor: 0f0d Product: 0009)"]; + + this.GamePadKeyData = [{ index: 0, data: 0x01 }, { index: 0, data: 0x02 }, + { index: 0, data: 0x04 }, { index: 0, data: 0x08 }, + { index: 1, data: 0x01 }, { index: 1, data: 0x04 }, + { index: 1, data: 0x08 }, { index: 1, data: 0x02 }, + { index: 2, data: 0x01 }, { index: 2, data: 0x02 }, + { index: 2, data: 0x04 }, { index: 2, data: 0x08 }]; + + this.GamePadPovData = [0x01, 0x01 | 0x02, 0x02, 0x02 | 0x04, 0x04, 0x04 | 0x08, 0x08, 0x01 | 0x08]; + } + + + JoystickInit() { + this.JoystickSEL = 0; + this.JoystickCLR = 0; + + for (let i = 0; i < this.Keybord.length; i++) { + this.Keybord[i][0] = 0xBF; + this.Keybord[i][1] = 0xBF; + this.Keybord[i][2] = 0xBF; + this.Keybord[i][3] = 0xB0; + } - this.GamePadSelect = 0; - this.GamePadButtonSelect = 0x00; - this.GamePadBuffer = 0x00; - } + this.GamePadSelect = 0; + this.GamePadButtonSelect = 0x00; + this.GamePadBuffer = 0x00; + } - SetJoystick(data) { - let sel = data & 0x01; - let clr = (data & 0x02) >> 1; + SetJoystick(data) { + let sel = data & 0x01; + let clr = (data & 0x02) >> 1; - if((this.JoystickSEL == 1 && this.JoystickCLR == 0) && (sel == 1 && clr == 1)) { - this.JoystickSEL = 0; - this.JoystickCLR = 0; - this.GamePadSelect = 0; - if(this.GamePadButton6) - this.GamePadButtonSelect = this.GamePadButtonSelect ^ 0x02; - this.GamePadBuffer = 0xB0 | this.CountryType; - return; - } + if ((this.JoystickSEL == 1 && this.JoystickCLR == 0) && (sel == 1 && clr == 1)) { + this.JoystickSEL = 0; + this.JoystickCLR = 0; + this.GamePadSelect = 0; + if (this.GamePadButton6) + this.GamePadButtonSelect = this.GamePadButtonSelect ^ 0x02; + this.GamePadBuffer = 0xB0 | this.CountryType; + return; + } - if((this.JoystickSEL == 0 && this.JoystickCLR == 0) && (sel == 1 && clr == 0)) - this.GamePadSelect++; + if ((this.JoystickSEL == 0 && this.JoystickCLR == 0) && (sel == 1 && clr == 0)) + this.GamePadSelect++; - this.JoystickSEL = sel; - this.JoystickCLR = clr; + this.JoystickSEL = sel; + this.JoystickCLR = clr; - let no = this.MultiTap ? this.GamePadSelect - 1 : 0; - if(no < 5) { - let tmp = this.GamePadButtonSelect | this.JoystickSEL; - this.GamePadBuffer = (this.Keybord[no][tmp] & this.GamePad[no][tmp]) | this.CountryType; - } else - this.GamePadBuffer = 0xB0 | this.CountryType; - } + let no = this.MultiTap ? this.GamePadSelect - 1 : 0; + if (no < 5) { + let tmp = this.GamePadButtonSelect | this.JoystickSEL; + this.GamePadBuffer = (this.Keybord[no][tmp] & this.GamePad[no][tmp]) | this.CountryType; + } else + this.GamePadBuffer = 0xB0 | this.CountryType; + } - GetJoystick() { - return this.GamePadBuffer; - } + GetJoystick() { + return this.GamePadBuffer; + } - UnsetButtonRUN(no) { - this.Keybord[no][0] |= 0x08; - } + UnsetButtonRUN(no) { + this.Keybord[no][0] |= 0x08; + } - UnsetButtonSELECT(no) { - this.Keybord[no][0] |= 0x04; - } + UnsetButtonSELECT(no) { + this.Keybord[no][0] |= 0x04; + } - UnsetButtonSHOT2(no) { - this.Keybord[no][0] |= 0x02; - } + UnsetButtonSHOT2(no) { + this.Keybord[no][0] |= 0x02; + } - UnsetButtonSHOT1(no) { - this.Keybord[no][0] |= 0x01; - } + UnsetButtonSHOT1(no) { + this.Keybord[no][0] |= 0x01; + } - UnsetButtonLEFT(no) { - this.Keybord[no][1] |= 0x08; - } + UnsetButtonLEFT(no) { + this.Keybord[no][1] |= 0x08; + } - UnsetButtonDOWN(no) { - this.Keybord[no][1] |= 0x04; - } + UnsetButtonDOWN(no) { + this.Keybord[no][1] |= 0x04; + } - UnsetButtonRIGHT(no) { - this.Keybord[no][1] |= 0x02; - } + UnsetButtonRIGHT(no) { + this.Keybord[no][1] |= 0x02; + } - UnsetButtonUP(no) { - this.Keybord[no][1] |= 0x01; - } + UnsetButtonUP(no) { + this.Keybord[no][1] |= 0x01; + } - UnsetButtonSHOT6(no) { - this.Keybord[no][2] |= 0x08; - } + UnsetButtonSHOT6(no) { + this.Keybord[no][2] |= 0x08; + } - UnsetButtonSHOT5(no) { - this.Keybord[no][2] |= 0x04; - } + UnsetButtonSHOT5(no) { + this.Keybord[no][2] |= 0x04; + } - UnsetButtonSHOT4(no) { - this.Keybord[no][2] |= 0x02; - } + UnsetButtonSHOT4(no) { + this.Keybord[no][2] |= 0x02; + } - UnsetButtonSHOT3(no) { - this.Keybord[no][2] |= 0x01; - } + UnsetButtonSHOT3(no) { + this.Keybord[no][2] |= 0x01; + } - SetButtonRUN(no) { - this.Keybord[no][0] &= ~0x08; - } + SetButtonRUN(no) { + this.Keybord[no][0] &= ~0x08; + } - SetButtonSELECT(no) { - this.Keybord[no][0] &= ~0x04; - } + SetButtonSELECT(no) { + this.Keybord[no][0] &= ~0x04; + } - SetButtonSHOT2(no) { - this.Keybord[no][0] &= ~0x02; - } + SetButtonSHOT2(no) { + this.Keybord[no][0] &= ~0x02; + } - SetButtonSHOT1(no) { - this.Keybord[no][0] &= ~0x01; - } + SetButtonSHOT1(no) { + this.Keybord[no][0] &= ~0x01; + } - SetButtonLEFT(no) { - this.Keybord[no][1] &= ~0x08; - } + SetButtonLEFT(no) { + this.Keybord[no][1] &= ~0x08; + } - SetButtonDOWN(no) { - this.Keybord[no][1] &= ~0x04; - } + SetButtonDOWN(no) { + this.Keybord[no][1] &= ~0x04; + } - SetButtonRIGHT(no) { - this.Keybord[no][1] &= ~0x02; - } + SetButtonRIGHT(no) { + this.Keybord[no][1] &= ~0x02; + } - SetButtonUP(no) { - this.Keybord[no][1] &= ~0x01; - } + SetButtonUP(no) { + this.Keybord[no][1] &= ~0x01; + } - SetButtonSHOT6(no) { - this.Keybord[no][2] &= ~0x08; - } + SetButtonSHOT6(no) { + this.Keybord[no][2] &= ~0x08; + } - SetButtonSHOT5(no) { - this.Keybord[no][2] &= ~0x04; - } + SetButtonSHOT5(no) { + this.Keybord[no][2] &= ~0x04; + } - SetButtonSHOT4(no) { - this.Keybord[no][2] &= ~0x02; - } + SetButtonSHOT4(no) { + this.Keybord[no][2] &= ~0x02; + } - SetButtonSHOT3(no) { - this.Keybord[no][2] &= ~0x01; - } + SetButtonSHOT3(no) { + this.Keybord[no][2] &= ~0x01; + } - CheckKeyUpFunction(evt) { - switch (evt.keyCode){ - case Keys['START'].c:// RUN 'S' - this.UnsetButtonRUN(0); - break; - case Keys['SELECT'].c:// SELECT 'A' - this.UnsetButtonSELECT(0); - break; - case Keys['A'].c:// SHOT2 'Z' - case Keys['GP_A'].c:// SHOT2 'Z' - this.UnsetButtonSHOT2(0); - break; - case Keys['B'].c:// SHOT1 'X' - case Keys['GP_B'].c:// SHOT1 'X' - this.UnsetButtonSHOT1(0); - break; - - case 86:// SHOT2 'V' - this.UnsetButtonSHOT2(0); - break; - case 66:// SHOT1 'B' - this.UnsetButtonSHOT1(0); - break; - - case 37:// LEFT - this.UnsetButtonLEFT(0); - break; - case 39:// RIGHT - this.UnsetButtonRIGHT(0); - break; - case 40:// DOWN - this.UnsetButtonDOWN(0); - break; - case 38:// UP - this.UnsetButtonUP(0); - break; - - case 71:// SHOT6 'G' - this.UnsetButtonSHOT6(0); - break; - case 70:// SHOT5 'F' - this.UnsetButtonSHOT5(0); - break; - case 68:// SHOT4 'D' - this.UnsetButtonSHOT4(0); - break; - case 67:// SHOT3 'C' - this.UnsetButtonSHOT3(0); - break; - } - //evt.preventDefault(); - } - - - CheckKeyDownFunction(evt) { - switch (evt.keyCode){ - case Keys['START'].c:// RUN 'S' - this.SetButtonRUN(0); - break; + CheckKeyUpFunction(evt) { + switch (evt.keyCode) { + case Keys['START'].c:// RUN 'S' + this.UnsetButtonRUN(0); + break; case Keys['SELECT'].c:// SELECT 'A' - this.SetButtonSELECT(0); - break; + this.UnsetButtonSELECT(0); + break; + case Keys['A'].c:// SHOT2 'Z' + case Keys['GP_A'].c:// SHOT2 'Z' + this.UnsetButtonSHOT2(0); + break; + case Keys['B'].c:// SHOT1 'X' + case Keys['GP_B'].c:// SHOT1 'X' + this.UnsetButtonSHOT1(0); + break; + + case 86:// SHOT2 'V' + this.UnsetButtonSHOT2(0); + break; + case 66:// SHOT1 'B' + this.UnsetButtonSHOT1(0); + break; + + case 37:// LEFT + this.UnsetButtonLEFT(0); + break; + case 39:// RIGHT + this.UnsetButtonRIGHT(0); + break; + case 40:// DOWN + this.UnsetButtonDOWN(0); + break; + case 38:// UP + this.UnsetButtonUP(0); + break; + + case 71:// SHOT6 'G' + this.UnsetButtonSHOT6(0); + break; + case 70:// SHOT5 'F' + this.UnsetButtonSHOT5(0); + break; + case 68:// SHOT4 'D' + this.UnsetButtonSHOT4(0); + break; + case 67:// SHOT3 'C' + this.UnsetButtonSHOT3(0); + break; + } + //evt.preventDefault(); + } + + + CheckKeyDownFunction(evt) { + switch (evt.keyCode) { + case Keys['START'].c:// RUN 'S' + this.SetButtonRUN(0); + break; + case Keys['SELECT'].c:// SELECT 'A' + this.SetButtonSELECT(0); + break; case Keys['A'].c:// SHOT2 'Z' case Keys['GP_A'].c:// SHOT2 'Z' this.SetButtonSHOT2(0); - break; - case Keys['B'].c:// SHOT2 'Z' - case Keys['GP_B'].c:// SHOT2 'Z' - this.SetButtonSHOT1(0); - break; + break; + case Keys['B'].c:// SHOT2 'Z' + case Keys['GP_B'].c:// SHOT2 'Z' + this.SetButtonSHOT1(0); + break; - case 86:// SHOT2 'V' - this.SetButtonSHOT2(0); - break; - case 66:// SHOT1 'B' - this.SetButtonSHOT1(0); - break; + case 86:// SHOT2 'V' + this.SetButtonSHOT2(0); + break; + case 66:// SHOT1 'B' + this.SetButtonSHOT1(0); + break; - case 37:// LEFT - this.SetButtonLEFT(0); - break; - case 39:// RIGHT - this.SetButtonRIGHT(0); - break; - case 40:// DOWN - this.SetButtonDOWN(0); - break; - case 38:// UP - this.SetButtonUP(0); - break; + case 37:// LEFT + this.SetButtonLEFT(0); + break; + case 39:// RIGHT + this.SetButtonRIGHT(0); + break; + case 40:// DOWN + this.SetButtonDOWN(0); + break; + case 38:// UP + this.SetButtonUP(0); + break; - case 71:// SHOT6 'G' - this.SetButtonSHOT6(0); - break; - case 70:// SHOT5 'F' - this.SetButtonSHOT5(0); - break; - case 68:// SHOT4 'D' - this.SetButtonSHOT4(0); - break; - case 67:// SHOT3 'C' - this.SetButtonSHOT3(0); - break; - } - //evt.preventDefault(); - } + case 71:// SHOT6 'G' + this.SetButtonSHOT6(0); + break; + case 70:// SHOT5 'F' + this.SetButtonSHOT5(0); + break; + case 68:// SHOT4 'D' + this.SetButtonSHOT4(0); + break; + case 67:// SHOT3 'C' + this.SetButtonSHOT3(0); + break; + } + //evt.preventDefault(); + } - JoystickEventInit() { - this.KeyUpFunction = this.CheckKeyUpFunction.bind(this); - this.KeyDownFunction = this.CheckKeyDownFunction.bind(this); - this.MainCanvas.addEventListener("keyup", this.KeyUpFunction, true); - this.MainCanvas.addEventListener("keydown", this.KeyDownFunction, true); - } + JoystickEventInit() { + this.KeyUpFunction = this.CheckKeyUpFunction.bind(this); + this.KeyDownFunction = this.CheckKeyDownFunction.bind(this); + this.MainCanvas.addEventListener("keyup", this.KeyUpFunction, true); + this.MainCanvas.addEventListener("keydown", this.KeyDownFunction, true); + } - JoystickEventRelease() { - this.MainCanvas.removeEventListener("keyup", this.KeyUpFunction, true); - this.MainCanvas.removeEventListener("keydown", this.KeyDownFunction, true); - } + JoystickEventRelease() { + this.MainCanvas.removeEventListener("keyup", this.KeyUpFunction, true); + this.MainCanvas.removeEventListener("keydown", this.KeyDownFunction, true); + } - CheckGamePad() { - for(let i=0; i 0.5) - this.GamePad[i][this.GamePadKeyData[tmp].index] &= ~this.GamePadKeyData[tmp].data; - break; - case "AB": - if(pad.axes[val1.index] > -0.75) - this.GamePad[i][this.GamePadKeyData[tmp].index] &= ~this.GamePadKeyData[tmp].data; - break; - case "P": - let povtmp = ((pad.axes[val1.index] + 1) * 7 / 2 + 0.5) | 0; - this.GamePad[i][1] &= ~(povtmp <= 7 ? this.GamePadPovData[povtmp] : 0x00); - break; - } - } - tmp++; - } - } - } - } + let tmp = 0; + for (const val0 of paddata) { + for (const val1 of val0) { + switch (val1.type) { + case "B": + if (pad.buttons[val1.index].pressed) + this.GamePad[i][this.GamePadKeyData[tmp].index] &= ~this.GamePadKeyData[tmp].data; + break; + case "A-": + if (pad.axes[val1.index] < -0.5) + this.GamePad[i][this.GamePadKeyData[tmp].index] &= ~this.GamePadKeyData[tmp].data; + break; + case "A+": + if (pad.axes[val1.index] > 0.5) + this.GamePad[i][this.GamePadKeyData[tmp].index] &= ~this.GamePadKeyData[tmp].data; + break; + case "AB": + if (pad.axes[val1.index] > -0.75) + this.GamePad[i][this.GamePadKeyData[tmp].index] &= ~this.GamePadKeyData[tmp].data; + break; + case "P": + let povtmp = ((pad.axes[val1.index] + 1) * 7 / 2 + 0.5) | 0; + this.GamePad[i][1] &= ~(povtmp <= 7 ? this.GamePadPovData[povtmp] : 0x00); + break; + } + } + tmp++; + } + } + } + } } diff --git a/src/worker/tools/cc65.ts b/src/worker/tools/cc65.ts index a04af488..460aa5fd 100644 --- a/src/worker/tools/cc65.ts +++ b/src/worker/tools/cc65.ts @@ -186,6 +186,14 @@ export function linkLD65(step: BuildStep): BuildStepResult { var aout = FS.readFile("main", { encoding: 'binary' }); var mapout = FS.readFile("main.map", { encoding: 'utf8' }); var viceout = FS.readFile("main.vice", { encoding: 'utf8' }); + // correct binary for PCEngine + if (step.platform == 'pce' && aout.length > 0x2000) { + // move 8 KB from end to front + let newrom = new Uint8Array(aout.length); + newrom.set(aout.slice(aout.length - 0x2000), 0); + newrom.set(aout.slice(0, aout.length - 0x2000), 0x2000); + aout = newrom; + } //var dbgout = FS.readFile("main.dbg", {encoding:'utf8'}); putWorkFile("main", aout); putWorkFile("main.map", mapout); diff --git a/src/worker/workermain.ts b/src/worker/workermain.ts index 3e4f6e49..eb7b2bff 100644 --- a/src/worker/workermain.ts +++ b/src/worker/workermain.ts @@ -398,7 +398,7 @@ var PLATFORM_PARAMS = { arch: 'huc6280', define: ['__PCE__'], cfgfile: 'pce.cfg', - libargs: ['pce.lib'], + libargs: ['pce.lib', '-D', '__CARTSIZE__=0x8000'], }, };