Work slowly continues on the development of an IDE (integrated development environment) for programming games for the NES.
I finished laying out the Universal NES Game Engine and have converted it to 6502 Assembly Code below. I will be building my own compiler in the IDE, so there may be some non-traditional formatting.
I finished laying out the Universal NES Game Engine and have converted it to 6502 Assembly Code below. I will be building my own compiler in the IDE, so there may be some non-traditional formatting.
Attachment:
Code:
--------------------------------------------------------------------
HEADER:
--------------------------------------------------------------------
.inesprg 1 ; 1x 16KB PRG code
.ineschr 1 ; 1x 8KB CHR data
.inesmap 0 ; mapper 0 = NROM, no bank swapping
.inesmir 1 ; background mirroring
--------------------------------------------------------------------
VARIABLES:
--------------------------------------------------------------------
VAR.Scene
VAR.Scene.Next
VAR.Frame
VAR.GameState
// 0 = Initialize
// 1 = Construct
// 2 = Update
// 3 = Deconstruct
TBL.GameState
// LBL.GameState.Initialize - 1
// LBL.GameState.Construct - 1
// LBL.GameState.Update - 1
// LBL.GameState.Deconstruct - 1
VAR.NMIState
// 0 = DisableRendering
// 1 = LoadPaletes
// 2 = EnableRendering
// 3 = Wait
// 4 = Normal
TBL.NMIState
// LBL.NMI.DisableRendering - 1
// LBL.NMI.LoadPalettes - 1
// LBL.NMI.EnableRendering - 1
// LBL.NMI.Wait - 1
// LBL.NMI.Normal - 1
TBL.Scene.Initialize
// LBL.Scene0.Initialize - 1
// LBL.Scene1.Initialize - 1
// LBL.Scene2.Initialize - 1
// ...
// LBL.SceneN.Initialize - 1
TBL.Scene.Update
// LBL.Scene0.Update - 1
// LBL.Scene1.Update - 1
// LBL.Scene2.Update - 1
// ...
// LBL.SceneN.Update - 1
TBL.Scene.Deconstruct
// LBL.Scene0.Deconstruct - 1
// LBL.Scene1.Deconstruct - 1
// LBL.Scene2.Deconstruct - 1
// ...
// LBL.SceneN.Deconstruct - 1
PTR.Background
PTR.Background.Palette
PTR.Sprites
PTR.Sprites.Palette
BUF.Sprites ($0200 - $02FF)
//+------+----------+--------------------------------------+
// Byte | Bits | Description |
//+------+----------+--------------------------------------+
//| 0 | YYYYYYYY | Y Coordinate - 1. Consider the coor- |
//| | | dinate the upper-left corner of the |
//| | | sprite itself. |
//| 1 | IIIIIIII | Tile Index # |
//| 2 | vhp000cc | Attributes |
//| | | v = Vertical Flip (1=Flip) |
//| | | h = Horizontal Flip (1=Flip) |
//| | | p = Background Priority |
//| | | 0 = In front |
//| | | 1 = Behind |
//| | | c = Upper two (2) bits of colour |
//| 3 | XXXXXXXX | X Coordinate (upper-left corner) |
//+------+----------+--------------------------------------+
VAR.PPUStack.Size ($0100)
BUF.PPUStack.High ($0101 - $0185)
BUF.PPUStack.Low ($0186 - $01A0)
BUF.PPUStack.Value ($01A1 - $01FF)
// Buffer Allows for space for 85 PPU changes
// VBlank may only allow 64
VAR.PPUStack.High.Temp
VAR.PPUStack.Low.Temp
VAR.PPUStack.Value.Temp
VAR.Controller1
VAR.Controller2
VAR.Controller1.Old
VAR.Controller2.Old
VAR.Controller1.Pressed
VAR.Controller2.Pressed
VAR.Controller1.Released
VAR.Controller2.Released
--------------------------------------------------------------------
CODE: Main Loop
--------------------------------------------------------------------
.bank 0
.org $8000
RESET:
SEI ; disable IRQs
CLD ; disable decimal mode
LDX #$40
STX $4017 ; disable APU frame IRQ
LDX #$00
STX $4010 ; disable DMC IRQs
STA $2001 ; disable rendering
STA VAR.Controller1.Old
STA VAR.Controller2.Old
LDA VAR.NMIState.Wait
STA VAR.NMIState
BIT $2002
JSR LBL.VBlankWait
JSR LBL.ClearRAM
JSR LBL.VBlankWait
LDA #$00 ; Start Game at Scene 0
STA VAR.Scene
LDA VAR.GameState.Initialize
STA VAR.GameState
LBL.Main
JSR LBL.GameState.Launcher
JMP LBL.Main
--------------------------------------------------------------------
CODE: Main Subroutines
--------------------------------------------------------------------
LBL.ClearRAM
LDA #$00
STA $0000, x
STA $0100, x
STA $0200, x
STA $0300, x
STA $0400, x
STA $0500, x
STA $0600, x
STA $0700, x
INX
BNE LBL.ClearRAM
RTS
--------------------------------------------------------------------
LBL.VBlankWait:
BIT $2002
BPL LBL.VBlankWait
RTS
--------------------------------------------------------------------
LBL.GameState.Launcher:
LDA VAR.GameState
ASL
TAX
LDA TBL.GameState + 1, x
PHA
LDA TBL.GameState, x
PHA
RTS
--------------------------------------------------------------------
LBL.GameState.Initialize
JSR LBL.Scene.Initialize.Launcher
LDA GameState.Construct
STA GameState
RTS
--------------------------------------------------------------------
LBL.Scene.Initialize.Launcher
LDA VAR.Scene
ASL
TAX
LDA TBL.Scene.Initialize + 1, x
PHA
LDA TBL.Scene.Initialize, x
PHA
RTS
--------------------------------------------------------------------
LBL.GameState.Construct
LDA NMI.State.DisableRendering
STA NMI.State
JSR LBL.WaitForNMIChange
JSR LBL.LoadBackground
JSR LBL.LoadSprites
LDA NMI.State.LoadPalettes
STA NMI.State
JSR LBL.WaitForNMIChange
LDA NMI.State.EnableRendering
STA NMI.State
JSR LBL.WaitForNMIChange
LDA #$00
STA VAR.Frame
LDA NMI.State.Normal
STA NMI.State
LDA GameState.Update
STA GameState
LDA #$00
STA VAR.Controller1.Old
LDA #$00
STA VAR.Controller2.Old
RTS
--------------------------------------------------------------------
LBL.WaitForNMIChange
LDA NMI.State
CMP NMI.State
BNE LBL.WaitForNMIChange
RTS
--------------------------------------------------------------------
LBL.GameState.Update
JSR LBL.WaitForNMIChange
JSR LBL.ReadControllers
JSR LBL.Scene.Update.Launcher
LDA VAR.Scene
CMP VAR.Scene.Next
BNE LBL.GameState.Update.Transition
RTS
LBL.GameState.Update.Transition
LDA VAR.GameState.Deconstruct
STA VAR.GameState
RTS
--------------------------------------------------------------------
LBL.GameState.Deconstruct
JSR LBL.Scene.Deconstruct.Launcher
LDA VAR.Scene.Next
STA VAR.Scene
LDA VAR.GameState.Initialize
STA VAR.GameState
RTS
--------------------------------------------------------------------
LBL.ReadControllers
LDA #$01
STA $4016
LDA #$00
STA $4016
LDX #$08
// bit: 7 6 5 4 3 2 1 0
// button: A B select start up down left right
LDA VAR.Controller1;
STA VAR.Controller1.Old;
LDA VAR.Controller2;
STA VAR.Controller2.Old;
LBL.ReadController1.Loop
LDA $4016
LSR A
ROL VAR.Controller1
DEX
BNE LBL.ReadController.Loop
LBL.ReadController2.Loop
LDA $4017
LSR A
ROL VAR.Controller2
DEX
BNE LBL.ReadController2.Loop
LDA VAR.Controller1
EOR #$FF
AND VAR.Controller1.Old
STA VAR.Controller1.Released
LDA VAR.Controller1.Old
EOR #$FF
AND VAR.Controller1
STA VAR.Controller1.Pressed
LDA VAR.Controller2
EOR #$FF
AND VAR.Controller2.Old
STA VAR.Controller2.Released
LDA VAR.Controller2.Old
EOR #$FF
AND VAR.Controller2
STA VAR.Controller2.Pressed
RTS
--------------------------------------------------------------------
LBL.LoadBackground
LDA #$20;
STA $2006
LDY #$00;
STY $2006
LDX #$04
LBL.LoadBackground.Loop
LDA PTR.Background, y
STA $2007
INY
BNE LBL.LoadBackground.Loop
DEX
INC PTR.Background + 1
BNE LBL.LoadBackground.Loop
RTS
--------------------------------------------------------------------
LBL.LoadSprites:
LDX PTR.Sprites
LBL.LoadSprites.Loop:
LDA PTR.Sprites, X
STA BUF.Sprites, X
DEX
BNE LBL.LoadSprites.Loop
RTS
--------------------------------------------------------------------
LBL.PushPPUStack:
INC VAR.PPUStack.Size
LDX VAR.PPUStack.Size
LDA VAR.PPUStack.High
STA BUF.PPUStack.High, x
LDA VAR.PPUStack.Low
STA BUF.PPUStack.Low, x
LDA VAR.PPUStack.Value
STA BUF.PPUStack.Value, x
RTS
--------------------------------------------------------------------
CODE: NMI
--------------------------------------------------------------------
LBL.NMI
JSR LBL.SaveRegisters
JSR LBL.NMIState.Launcher
JSR LBL.RestoreRegisters
RTI
--------------------------------------------------------------------
CODE: NMI Subroutines
--------------------------------------------------------------------
LBL_NMI_SaveRegisters:
PHA
TXA
PHA
TYA
PHA
RTS
--------------------------------------------------------------------
LBL_NMI_RestoreRegisters:
PLA
TAY
PLA
TAX
PLA
RTS
--------------------------------------------------------------------
LBL.NMIState.Launcher:
LDA VAR.NMIState
ASL
TAX
LDA TBL.NMIState + 1, x
PHA
LDA TBL.NMIState, x
PHA
RTS
--------------------------------------------------------------------
LBL.NMI.DisableRendering
LDA #$00 ;Disable Rendering
STA $2001 ;Disable Rendering
LDA VAR.NMIState.Wait
STA VAR.NMIState
RTS
--------------------------------------------------------------------
LBL.NMI.LoadPalettes
LDA $2002 ; reset High/Low Bit in PPU
LDA #$3F
STA $2006
LDA #$00
STA $2006
LDX #$00
LBL.NMI.LoadPalettes.BackgroundLoop:
LDA PTR.Background.Palettes, x
STA $2007
INX
CPX #$10
BNE LBL.NMI.LoadPalettes.BackgroundLoop
LDX #$00
LBL.NMI.LoadPalettes.SpriteLoop:
LDA PTR.Sprite.Palettes, x
STA $2007
INX
CPX #$10
BNE LBL.NMI.LoadPalettes.SpriteLoop
LDA VAR.NMIState.Wait
STA VAR.NMIState
RTS
--------------------------------------------------------------------
LBL.NMI.EnableRendering
LDA #%00011110
STA $2001
LDA VAR.NMIState.Wait
STA VAR.NMIState
RTS
--------------------------------------------------------------------
LBL.NMI.Wait
RTS
--------------------------------------------------------------------
LBL.NMI.Normal
JSR LBL.CopySprites
JSR LBL.BurnStack
INC VAR.Frame
RTS
--------------------------------------------------------------------
LBL.CopySprites
LDA HIGH(BUF.Sprite)
STA $4014
RTS
--------------------------------------------------------------------
LBL.BurnStack
LDA $2002
LDX VAR.PPUStack.Size
LBL.BurnStack.Loop:
LDA VAR.PPUStack.High,x
STA $2006
LDA VAR.PPUStack.Low,x
STA $2006
LDA VAR.PPUStack.Value,x
STA $2007
DEX
BNE LBL.BurnStack.Loop
RTS
HEADER:
--------------------------------------------------------------------
.inesprg 1 ; 1x 16KB PRG code
.ineschr 1 ; 1x 8KB CHR data
.inesmap 0 ; mapper 0 = NROM, no bank swapping
.inesmir 1 ; background mirroring
--------------------------------------------------------------------
VARIABLES:
--------------------------------------------------------------------
VAR.Scene
VAR.Scene.Next
VAR.Frame
VAR.GameState
// 0 = Initialize
// 1 = Construct
// 2 = Update
// 3 = Deconstruct
TBL.GameState
// LBL.GameState.Initialize - 1
// LBL.GameState.Construct - 1
// LBL.GameState.Update - 1
// LBL.GameState.Deconstruct - 1
VAR.NMIState
// 0 = DisableRendering
// 1 = LoadPaletes
// 2 = EnableRendering
// 3 = Wait
// 4 = Normal
TBL.NMIState
// LBL.NMI.DisableRendering - 1
// LBL.NMI.LoadPalettes - 1
// LBL.NMI.EnableRendering - 1
// LBL.NMI.Wait - 1
// LBL.NMI.Normal - 1
TBL.Scene.Initialize
// LBL.Scene0.Initialize - 1
// LBL.Scene1.Initialize - 1
// LBL.Scene2.Initialize - 1
// ...
// LBL.SceneN.Initialize - 1
TBL.Scene.Update
// LBL.Scene0.Update - 1
// LBL.Scene1.Update - 1
// LBL.Scene2.Update - 1
// ...
// LBL.SceneN.Update - 1
TBL.Scene.Deconstruct
// LBL.Scene0.Deconstruct - 1
// LBL.Scene1.Deconstruct - 1
// LBL.Scene2.Deconstruct - 1
// ...
// LBL.SceneN.Deconstruct - 1
PTR.Background
PTR.Background.Palette
PTR.Sprites
PTR.Sprites.Palette
BUF.Sprites ($0200 - $02FF)
//+------+----------+--------------------------------------+
// Byte | Bits | Description |
//+------+----------+--------------------------------------+
//| 0 | YYYYYYYY | Y Coordinate - 1. Consider the coor- |
//| | | dinate the upper-left corner of the |
//| | | sprite itself. |
//| 1 | IIIIIIII | Tile Index # |
//| 2 | vhp000cc | Attributes |
//| | | v = Vertical Flip (1=Flip) |
//| | | h = Horizontal Flip (1=Flip) |
//| | | p = Background Priority |
//| | | 0 = In front |
//| | | 1 = Behind |
//| | | c = Upper two (2) bits of colour |
//| 3 | XXXXXXXX | X Coordinate (upper-left corner) |
//+------+----------+--------------------------------------+
VAR.PPUStack.Size ($0100)
BUF.PPUStack.High ($0101 - $0185)
BUF.PPUStack.Low ($0186 - $01A0)
BUF.PPUStack.Value ($01A1 - $01FF)
// Buffer Allows for space for 85 PPU changes
// VBlank may only allow 64
VAR.PPUStack.High.Temp
VAR.PPUStack.Low.Temp
VAR.PPUStack.Value.Temp
VAR.Controller1
VAR.Controller2
VAR.Controller1.Old
VAR.Controller2.Old
VAR.Controller1.Pressed
VAR.Controller2.Pressed
VAR.Controller1.Released
VAR.Controller2.Released
--------------------------------------------------------------------
CODE: Main Loop
--------------------------------------------------------------------
.bank 0
.org $8000
RESET:
SEI ; disable IRQs
CLD ; disable decimal mode
LDX #$40
STX $4017 ; disable APU frame IRQ
LDX #$00
STX $4010 ; disable DMC IRQs
STA $2001 ; disable rendering
STA VAR.Controller1.Old
STA VAR.Controller2.Old
LDA VAR.NMIState.Wait
STA VAR.NMIState
BIT $2002
JSR LBL.VBlankWait
JSR LBL.ClearRAM
JSR LBL.VBlankWait
LDA #$00 ; Start Game at Scene 0
STA VAR.Scene
LDA VAR.GameState.Initialize
STA VAR.GameState
LBL.Main
JSR LBL.GameState.Launcher
JMP LBL.Main
--------------------------------------------------------------------
CODE: Main Subroutines
--------------------------------------------------------------------
LBL.ClearRAM
LDA #$00
STA $0000, x
STA $0100, x
STA $0200, x
STA $0300, x
STA $0400, x
STA $0500, x
STA $0600, x
STA $0700, x
INX
BNE LBL.ClearRAM
RTS
--------------------------------------------------------------------
LBL.VBlankWait:
BIT $2002
BPL LBL.VBlankWait
RTS
--------------------------------------------------------------------
LBL.GameState.Launcher:
LDA VAR.GameState
ASL
TAX
LDA TBL.GameState + 1, x
PHA
LDA TBL.GameState, x
PHA
RTS
--------------------------------------------------------------------
LBL.GameState.Initialize
JSR LBL.Scene.Initialize.Launcher
LDA GameState.Construct
STA GameState
RTS
--------------------------------------------------------------------
LBL.Scene.Initialize.Launcher
LDA VAR.Scene
ASL
TAX
LDA TBL.Scene.Initialize + 1, x
PHA
LDA TBL.Scene.Initialize, x
PHA
RTS
--------------------------------------------------------------------
LBL.GameState.Construct
LDA NMI.State.DisableRendering
STA NMI.State
JSR LBL.WaitForNMIChange
JSR LBL.LoadBackground
JSR LBL.LoadSprites
LDA NMI.State.LoadPalettes
STA NMI.State
JSR LBL.WaitForNMIChange
LDA NMI.State.EnableRendering
STA NMI.State
JSR LBL.WaitForNMIChange
LDA #$00
STA VAR.Frame
LDA NMI.State.Normal
STA NMI.State
LDA GameState.Update
STA GameState
LDA #$00
STA VAR.Controller1.Old
LDA #$00
STA VAR.Controller2.Old
RTS
--------------------------------------------------------------------
LBL.WaitForNMIChange
LDA NMI.State
CMP NMI.State
BNE LBL.WaitForNMIChange
RTS
--------------------------------------------------------------------
LBL.GameState.Update
JSR LBL.WaitForNMIChange
JSR LBL.ReadControllers
JSR LBL.Scene.Update.Launcher
LDA VAR.Scene
CMP VAR.Scene.Next
BNE LBL.GameState.Update.Transition
RTS
LBL.GameState.Update.Transition
LDA VAR.GameState.Deconstruct
STA VAR.GameState
RTS
--------------------------------------------------------------------
LBL.GameState.Deconstruct
JSR LBL.Scene.Deconstruct.Launcher
LDA VAR.Scene.Next
STA VAR.Scene
LDA VAR.GameState.Initialize
STA VAR.GameState
RTS
--------------------------------------------------------------------
LBL.ReadControllers
LDA #$01
STA $4016
LDA #$00
STA $4016
LDX #$08
// bit: 7 6 5 4 3 2 1 0
// button: A B select start up down left right
LDA VAR.Controller1;
STA VAR.Controller1.Old;
LDA VAR.Controller2;
STA VAR.Controller2.Old;
LBL.ReadController1.Loop
LDA $4016
LSR A
ROL VAR.Controller1
DEX
BNE LBL.ReadController.Loop
LBL.ReadController2.Loop
LDA $4017
LSR A
ROL VAR.Controller2
DEX
BNE LBL.ReadController2.Loop
LDA VAR.Controller1
EOR #$FF
AND VAR.Controller1.Old
STA VAR.Controller1.Released
LDA VAR.Controller1.Old
EOR #$FF
AND VAR.Controller1
STA VAR.Controller1.Pressed
LDA VAR.Controller2
EOR #$FF
AND VAR.Controller2.Old
STA VAR.Controller2.Released
LDA VAR.Controller2.Old
EOR #$FF
AND VAR.Controller2
STA VAR.Controller2.Pressed
RTS
--------------------------------------------------------------------
LBL.LoadBackground
LDA #$20;
STA $2006
LDY #$00;
STY $2006
LDX #$04
LBL.LoadBackground.Loop
LDA PTR.Background, y
STA $2007
INY
BNE LBL.LoadBackground.Loop
DEX
INC PTR.Background + 1
BNE LBL.LoadBackground.Loop
RTS
--------------------------------------------------------------------
LBL.LoadSprites:
LDX PTR.Sprites
LBL.LoadSprites.Loop:
LDA PTR.Sprites, X
STA BUF.Sprites, X
DEX
BNE LBL.LoadSprites.Loop
RTS
--------------------------------------------------------------------
LBL.PushPPUStack:
INC VAR.PPUStack.Size
LDX VAR.PPUStack.Size
LDA VAR.PPUStack.High
STA BUF.PPUStack.High, x
LDA VAR.PPUStack.Low
STA BUF.PPUStack.Low, x
LDA VAR.PPUStack.Value
STA BUF.PPUStack.Value, x
RTS
--------------------------------------------------------------------
CODE: NMI
--------------------------------------------------------------------
LBL.NMI
JSR LBL.SaveRegisters
JSR LBL.NMIState.Launcher
JSR LBL.RestoreRegisters
RTI
--------------------------------------------------------------------
CODE: NMI Subroutines
--------------------------------------------------------------------
LBL_NMI_SaveRegisters:
PHA
TXA
PHA
TYA
PHA
RTS
--------------------------------------------------------------------
LBL_NMI_RestoreRegisters:
PLA
TAY
PLA
TAX
PLA
RTS
--------------------------------------------------------------------
LBL.NMIState.Launcher:
LDA VAR.NMIState
ASL
TAX
LDA TBL.NMIState + 1, x
PHA
LDA TBL.NMIState, x
PHA
RTS
--------------------------------------------------------------------
LBL.NMI.DisableRendering
LDA #$00 ;Disable Rendering
STA $2001 ;Disable Rendering
LDA VAR.NMIState.Wait
STA VAR.NMIState
RTS
--------------------------------------------------------------------
LBL.NMI.LoadPalettes
LDA $2002 ; reset High/Low Bit in PPU
LDA #$3F
STA $2006
LDA #$00
STA $2006
LDX #$00
LBL.NMI.LoadPalettes.BackgroundLoop:
LDA PTR.Background.Palettes, x
STA $2007
INX
CPX #$10
BNE LBL.NMI.LoadPalettes.BackgroundLoop
LDX #$00
LBL.NMI.LoadPalettes.SpriteLoop:
LDA PTR.Sprite.Palettes, x
STA $2007
INX
CPX #$10
BNE LBL.NMI.LoadPalettes.SpriteLoop
LDA VAR.NMIState.Wait
STA VAR.NMIState
RTS
--------------------------------------------------------------------
LBL.NMI.EnableRendering
LDA #%00011110
STA $2001
LDA VAR.NMIState.Wait
STA VAR.NMIState
RTS
--------------------------------------------------------------------
LBL.NMI.Wait
RTS
--------------------------------------------------------------------
LBL.NMI.Normal
JSR LBL.CopySprites
JSR LBL.BurnStack
INC VAR.Frame
RTS
--------------------------------------------------------------------
LBL.CopySprites
LDA HIGH(BUF.Sprite)
STA $4014
RTS
--------------------------------------------------------------------
LBL.BurnStack
LDA $2002
LDX VAR.PPUStack.Size
LBL.BurnStack.Loop:
LDA VAR.PPUStack.High,x
STA $2006
LDA VAR.PPUStack.Low,x
STA $2006
LDA VAR.PPUStack.Value,x
STA $2007
DEX
BNE LBL.BurnStack.Loop
RTS