diff --git a/presets/nes/ex1.asm b/presets/nes/ex1.asm index 5c534140..93b82b30 100644 --- a/presets/nes/ex1.asm +++ b/presets/nes/ex1.asm @@ -1,3 +1,4 @@ + ;;;;; CONSTANTS @@ -18,31 +19,33 @@ DMC_FREQ equ $4010 org $0 ScrollPos byte ; used during NMI +Rand byte ;;;;; CARTRIDGE FILE HEADER +NES_MAP_HORIZ equ 0 +NES_MAP_VERT equ 1 +NES_MAP_QUAD equ 8 + + MAC NES_HEADER processor 6502 seg Header org $7FF0 - -NES_MAPPER equ 0 ;mapper number -NES_PRG_BANKS equ 2 ;number of 16K PRG banks, change to 2 for NROM256 -NES_CHR_BANKS equ 1 ;number of 8K CHR banks (0 = RAM) -NES_MIRRORING equ 1 ;0 horizontal, 1 vertical, 8 four screen - - .byte $4e,$45,$53,$1a ; header - .byte NES_PRG_BANKS - .byte NES_CHR_BANKS - .byte NES_MIRRORING|(NES_MAPPER<<4) - .byte NES_MAPPER&$f0 - .byte 0,0,0,0,0,0,0,0 ; reserved, set to zero - -;;;;; CODE - +.NES_MAPPER SET {1} ;mapper number +.NES_PRG_BANKS SET {2} ;number of 16K PRG banks, change to 2 for NROM256 +.NES_CHR_BANKS SET {3} ;number of 8K CHR banks (0 = RAM) +.NES_MIRRORING SET {4} ;0 horizontal, 1 vertical, 8 four screen + byte $4e,$45,$53,$1a ; header + byte .NES_PRG_BANKS + byte .NES_CHR_BANKS + byte .NES_MIRRORING|(.NES_MAPPER<<4) + byte .NES_MAPPER&$f0 + byte 0,0,0,0,0,0,0,0 ; reserved, set to zero seg Code org $8000 -start: -_exit: + ENDM + + MAC NES_INIT sei ;disable IRQs cld ;decimal mode not supported ldx #$ff @@ -51,22 +54,18 @@ _exit: stx PPU_MASK ;disable rendering stx DMC_FREQ ;disable DMC interrupts stx PPU_CTRL ;disable NMI interrupts - jsr WaitSyncSafe ;wait for VSYNC -; clear RAM -- not a subroutine because we clear the stack too - lda #0 - tax -.clearRAM - sta $0,x - sta $100,x - ; skip $200-$2FF, used for OAM display list - sta $300,x - sta $400,x - sta $500,x - sta $600,x - sta $700,x - inx - bne .clearRAM -; end of clear RAM routine + bit PPU_STATUS ;clear VBL flag + ENDM + + NES_HEADER 0,2,1,1 ; mapper 0, 2 PRGs, 1 CHR, vertical + +start: +_exit: + NES_INIT ; set up stack pointer, turn off PPU + jsr WaitSync + jsr WaitSync + jsr ClearRAM + jsr WaitSync ;wait for VSYNC jsr SetPalette ;set colors jsr FillVRAM ;set PPU RAM jsr WaitSync ;wait for VSYNC (and PPU warmup) @@ -84,7 +83,27 @@ _exit: ;;;;; SUBROUTINES +ClearRAM: subroutine + lda #0 + tax +.clearRAM + sta $0,x + cpx #$fe ; don't clear last 2 bytes of stack + bcs .skipStack + sta $100,x +.skipStack + ; skip $200-$2FF, used for OAM display list + sta $300,x + sta $400,x + sta $500,x + sta $600,x + sta $700,x + inx + bne .clearRAM + rts + ; set palette colors + SetPalette: subroutine ldy #$0 lda #$3f @@ -108,7 +127,7 @@ FillVRAM: subroutine ldy #$10 .loop: sta PPU_DATA - adc #1 + adc #7 inx bne .loop dey @@ -116,8 +135,6 @@ FillVRAM: subroutine rts ; wait for VSYNC to start -WaitSyncSafe: subroutine - bit PPU_STATUS WaitSync: bit PPU_STATUS bpl WaitSync diff --git a/src/baseplatform.ts b/src/baseplatform.ts index 8fb987e0..28d3e0a8 100644 --- a/src/baseplatform.ts +++ b/src/baseplatform.ts @@ -255,25 +255,28 @@ function cpuStateToLongString_6502(c) : string { + " Y " + hex(c.Y) + " " + "SP " + hex(c.SP) + "\n"; } +var OPMETA_6502 = { + cycletime: [ + 7, 6, 0, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 6, 6, 0, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 6, 6, 0, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 6, 6, 0, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 0, 6, 0, 6, 3, 3, 3, 3, 2, 0, 2, 0, 4, 4, 4, 4, 2, 6, 0, 0, 4, 4, 4, 4, 2, 5, 2, 0, 0, 5, 0, 0, 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 0, 4, 4, 4, 4, 2, 5, 0, 5, 4, 4, 4, 4, 2, 4, 2, 0, 4, 4, 4, 4, 2, 6, 0, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 3, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 2, 6, 0, 8, 3, 3, 5, 5, 2, 2, 2, 0, 4, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7 + ], + extracycles: [ + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1 + ], + insnlengths: [ + 1, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 3, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 1, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 1, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 0, 2, 0, 2, 2, 2, 2, 2, 1, 0, 1, 0, 3, 3, 3, 3, 2, 2, 0, 0, 2, 2, 2, 3, 1, 3, 1, 0, 0, 3, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 0, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 1, 0, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 0, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3 + ], + validinsns: [ + 1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 0, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 3, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 0, 2, 0, 0, 2, 2, 2, 0, 1, 0, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 0, 3, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0 + ], +} + function getOpcodeMetadata_6502(opcode, address) { - var cycletime = [ - 7, 6, 0, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 6, 6, 0, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 6, 6, 0, 8, 3, 3, 5, 5, 3, 2, 2, 2, 3, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 6, 6, 0, 8, 3, 3, 5, 5, 4, 2, 2, 2, 5, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 0, 6, 0, 6, 3, 3, 3, 3, 2, 0, 2, 0, 4, 4, 4, 4, 2, 6, 0, 0, 4, 4, 4, 4, 2, 5, 2, 0, 0, 5, 0, 0, 2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 0, 4, 4, 4, 4, 2, 5, 0, 5, 4, 4, 4, 4, 2, 4, 2, 0, 4, 4, 4, 4, 2, 6, 0, 8, 3, 3, 5, 5, 2, 2, 2, 2, 4, 4, 3, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7, 2, 6, 0, 8, 3, 3, 5, 5, 2, 2, 2, 0, 4, 4, 6, 6, 2, 5, 0, 8, 4, 4, 6, 6, 2, 4, 0, 7, 4, 4, 7, 7 - ]; - var extracycles = [ - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1 - ]; - var insnlengths = [ - 1, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 3, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 1, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 1, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 0, 2, 0, 2, 2, 2, 2, 2, 1, 0, 1, 0, 3, 3, 3, 3, 2, 2, 0, 0, 2, 2, 2, 3, 1, 3, 1, 0, 0, 3, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1, 0, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 1, 0, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 2, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1, 0, 3, 3, 3, 3, 2, 2, 0, 2, 2, 2, 2, 2, 1, 3, 0, 3, 3, 3, 3, 3 - ]; - var validinsns = [ - 1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 0, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 3, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 1, 2, 0, 0, 0, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 0, 2, 0, 0, 2, 2, 2, 0, 1, 0, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 0, 3, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 3, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 1, 0, 3, 3, 3, 0, 2, 2, 0, 0, 0, 2, 2, 0, 1, 3, 0, 0, 0, 3, 3, 0 - ]; // TODO: more intelligent maximum cycles return { opcode:opcode, - minCycles:cycletime[opcode], - maxCycles:cycletime[opcode] + extracycles[opcode], - insnlength:insnlengths[opcode] + minCycles:OPMETA_6502.cycletime[opcode], + maxCycles:OPMETA_6502.cycletime[opcode] + OPMETA_6502.extracycles[opcode], + insnlength:OPMETA_6502.insnlengths[opcode] }; } diff --git a/src/platform/nes.js b/src/platform/nes.js index 49dd5bbd..43994521 100644 --- a/src/platform/nes.js +++ b/src/platform/nes.js @@ -83,9 +83,10 @@ var JSNESPlatform = function(mainElement) { //onBatteryRamWrite }); nes.stop = function() { - self.pause();// TODO - console.log(nes.cpu.toJSON()); // TODO - throw ("CPU STOPPED"); + // TODO: trigger breakpoint + self.pause(); + console.log(nes.cpu.toJSON()); + throw ("CPU STOPPED @ PC $" + hex(nes.cpu.REG_PC)); }; // insert debug hook nes.cpu._emulate = nes.cpu.emulate; @@ -199,8 +200,7 @@ var JSNESPlatform = function(mainElement) { ]; for (var i=0; i { var div = document.createElement("div"); @@ -211,7 +211,8 @@ export class SourceEditor implements ProjectView { this.clearCurrentLine(); if (line>0) { addCurrentMarker(line-1); - this.editor.setSelection({line:line,ch:0}, {line:line-1,ch:0}, {scroll:true}); + if (moveCursor) + this.editor.setSelection({line:line,ch:0}, {line:line-1,ch:0}, {scroll:true}); this.currentDebugLine = line; } } @@ -224,14 +225,14 @@ export class SourceEditor implements ProjectView { } } - refreshDebugState() { + refreshDebugState(moveCursor:boolean) { this.clearCurrentLine(); var state = lastDebugState; if (state && state.c) { var PC = state.c.PC; var line = this.sourcefile.findLineForOffset(PC); if (line >= 0) { - this.setCurrentLine(line); + this.setCurrentLine(line, moveCursor); // TODO: switch to disasm? } } @@ -246,9 +247,9 @@ export class SourceEditor implements ProjectView { } } - refresh() { + refresh(moveCursor: boolean) { this.refreshListing(); - this.refreshDebugState(); + this.refreshDebugState(moveCursor); } getLine(line : number) { @@ -368,7 +369,7 @@ export class DisassemblerView implements ProjectView { } // TODO: too many globals - refresh() { + refresh(moveCursor: boolean) { var state = lastDebugState || platform.saveState(); var pc = state.c ? state.c.PC : 0; var curline = 0; @@ -407,8 +408,10 @@ export class DisassemblerView implements ProjectView { } var text = disassemble(pc-96, pc) + disassemble(pc, pc+96); this.disasmview.setValue(text); - this.disasmview.setCursor(selline, 0); - jumpToLine(this.disasmview, selline); + if (moveCursor) { + this.disasmview.setCursor(selline, 0); + jumpToLine(this.disasmview, selline); + } } getCursorPC() : number { @@ -434,7 +437,7 @@ export class ListingView extends DisassemblerView implements ProjectView { this.assemblyfile = assemblyfile; } - refresh() { + refresh(moveCursor: boolean) { var state = lastDebugState || platform.saveState(); var pc = state.c ? state.c.PC : 0; var asmtext = this.assemblyfile.text; @@ -447,7 +450,7 @@ export class ListingView extends DisassemblerView implements ProjectView { var findPC = platform.getDebugCallback() ? pc : -1; if (findPC >= 0) { var lineno = this.assemblyfile.findLineForOffset(findPC); - if (lineno) { + if (lineno && moveCursor) { // set cursor while debugging if (platform.getDebugCallback()) disasmview.setCursor(lineno-1, 0); diff --git a/src/windows.ts b/src/windows.ts index 0efb48e0..027635c5 100644 --- a/src/windows.ts +++ b/src/windows.ts @@ -45,7 +45,7 @@ export class ProjectWindows { this.activediv = div; this.activewnd = wnd; $(div).show(); - this.refresh(); + this.refresh(true); this.refreshErrors(); } this.activeid = id; @@ -56,9 +56,9 @@ export class ProjectWindows { this.id2window[id] = window; } - refresh() { + refresh(moveCursor:boolean) { if (this.activewnd && this.activewnd.refresh) - this.activewnd.refresh(); + this.activewnd.refresh(moveCursor); } tick() {