# Visual Basic > Games and Graphics Programming > Game Demos >  NES 6502 Programming Tutorial - Part 1: Getting Started

## Jacob Roman

Welcome to my NES 6502 programming tutorial! In this tutorial, I'm gonna teach you step by step on what tools you'll need, some basic 6502 opcodes to use, and the end result, having a basic structured NES program. This tutorial is going to kinda shorter than I intended to write it because I written some basic 6502 commands for you to learn in my Atari 2600 programming tutorial already right HERE.

To help get your skills improved in the world of 6502 programming, you can play around with them in these sites:
https://skilldrick.github.io/easy6502/
http://www.6502asm.com/

----------------------------------------------------------------------------------------------------------------------------

Ok. So by now, you should have a basic understanding of 6502 assembly, and hexadecimals, which is a lot easier than you think. The next thing you will need is a place to code in. Some people could use notepad and save the file as asm, but what I personally use is Notepad++.

----------------------------------------------------------------------------------------------------------------------------

Now after that you are going to need something to convert all that code to an NES file. So what you will need is NESASM3. Using it is so easy you can either drag the asm file into it, or make a batch file to compile it, which is better because it'll display the errors you made. Dragging the asm file into the NESASM3 will create 2 files; an .fns file which shows the addresses of your sub routines, and an .nes file. If there is an error in your code, only the .fns file will be created. However if you create a batch file (ex. compile.bat) using these commands:



```
NESASM3 mygame.asm
pause
```

it will output this:



```
F:\Jacobs Stuff\Programming\Projects\NES 6502\Projects\My Game>NESASM3 mygame.asm
NES Assembler (v3.1)

pass 1
pass 2

F:\Jacobs Stuff\Programming\Projects\NES 6502\Projects\My Game>pause
Press any key to continue . . .
```

Otherwise it'll show an error in you code at a specific line.

----------------------------------------------------------------------------------------------------------------------------

You will now need some emulators to test your NES programs on. And not just any NES emulator. NES emulator debuggers! FCEUXD SP seems to be the most accurate in emulation, while NO$NES has some really really good debugging tools.
FCEUXD SP
NO$NES

Unless you really REALLY wanna test it on actual hardware, there's also the PowerPak by RetroUSB which costs $135.00 assuming you own a Nintendo:
PowerPak


----------------------------------------------------------------------------------------------------------------------------

Ok. So now you can start coding, right? Well there is just one thing missing. You will need a graphics file as well. A CHR file to be exact, which contains all the graphic tiles and sprites. You can create your own using a CHR editor such as YYCHR, or you can download mario.chr so you can play around with Super Mario Bros. sprites and tiles. But we won't be placing sprites and tiles just yet. The mario.chr file will look something like this for you to work with:



Basically it consists of multiple 8x8 pixel tiles, each within it's own hexadecimal address. For example:



----------------------------------------------------------------------------------------------------------------------------

Now it's time to learn the memory map of the Nintendo Entertainment System. And this is important because you will be using these memory locations *a lot!*



However it's lacking a bit of information. So I'm going to clarify.

*CPU Memory Map*
$FFFA - $FFFF is where all of your interrupts are located such as NMI, RESET, and IRQ$8000 - $FFF9 is the PRG-ROM, which basically means it's where all of your programming data will be located in, 32K of it. Larger programs can perform bank switching to execute other code.$6000 - $7FFF even though it says SRAM, I personally call it WRAM because it's Work Ram.$4018 - $5FFF is the expansion ROM, which is for the expansion located on the bottom of the NES. These addresses are never used due to the fact that no expansion device was ever made for it!$4017   Controller 2 plus IRQ interrupts$4016   Controller 1$4015   APU Sound/Vertical Clock Signal Register$4014   Sprite DMA Register (Direct Memory Access)$4013   APU Delta Modulation Data Length Register$4012   APU Delta Modulation Address Register$4011   APU Delta Modulation D/A Register$4010   APU Delta Modulation Control Register$400F   APU Noise Frequency Register 2$400E   APU Noise Frequency Register 1$400D   Not Used$400C   APU Noise Control Register 1$400B   APU Triangle Frequency Register 2$400A   APU Triangle Frequency Register 1$4009   APU Triangle Control Register 2$4008   APU Triangle Control Register 1$4007   APU Pulse 2 Coarse Tune Register$4006   APU Pulse 2 Fine Tune Register$4005   APU Pulse 2 Ramp Control Register$4004   APU Pulse 2 Control Register$4003   APU Pulse 1 Coarse Tune (CT) Register$4002   APU Pulse 1 Fine Tune (FT) Register$4001   APU Pulse 1 Ramp Control Register$4000   APU Pulse 1 Control Register$2008 - $3FFF are mirrors of $2000-$2007 over and over again. Any data changed between $2000-$2007 will be copied in $2008-$3FFF and vice versa, hence the term "mirroring".$2007   VRAM I/O Register$2006   VRAM Address Register 2$2005   VRAM Address Register 1$2004   SPR-RAM I/O Register$2003   SPR-RAM Address Register$2002   PPU Status Register$2001   PPU Control Register 2$2000   PPU Control Register 1$0800 - $1FFF are mirrors of $0000-$07FF over and over again.$0300 - $07FF is RAM$0200 - $02FF is where your sprite data from your CHR file is stored. Note that more sprite data can be swapped using bank switching so you are not limited.$0100 - $01FF is the stack, and generally used for arrays I believe.$0000 - $00FF is known as the Zero Page. Generally, variables can be declared here.

----------------------------------------------------------------------------------------------------------------------------

Now that you know the memory map of the CPU (kinda  :Sick: ), you are going to need to know the memory map of the PPU as well, especially if you plan on changing the background:



To avoid confusion and having to spend hours explaining what they are, thank god for NES Wiki!
What is a Pattern Table?
What is a Name Table?
What is an Attribute Table?
How does the NES pallete work?
--------------------------------------------------------------------------------------------------------------------

If you made it this far, congratulations! Now I'm going to teach you how to code in 6502 assembly for the NES!

*Warning - The NESASM3 compiler is extremely picky on how you indent things. The code can look beautiful, but it'll fail to compile if indented wrong. For example, the dot commands such as .inesprg must always be indented with a couple spaces from the space bar. I don't remember but if you do not indent the dot commands, it will not compile your file correctly or not at all. The sub routines I generally don't indent, but the code inside I generally indent with 2 spaces, and not with a tab key due to the pickiness of the NESASM3 compiler.*

The first thing we need to do is set up the header using dot commands. And yes, they will need indented with 2 spaces. 



```
  .inesprg 1   ; 1x 16KB PRG code
  .ineschr 1   ; 1x  8KB CHR data
  .inesmap 0   ; mapper 0 = NROM, no bank swapping
  .inesmir 1   ; background mirroring
```

So lets go into detail here. Since our code will be small, we'll only need one 16k bank of program code for *.inesprg*, even though you can fit nearly 32k of program code, keyword, nearly. Don't forget that $FFFA-$FFFF is reserved for interrupts. And since our CHR file is only one 8k bank, we put a one for *.ineschr*.

Believe it or not, there are 256 mappers for the NES (kinda  :Sick: ), with most not used. But since were bare bones basic here, were gonna stick with mapper 0 for now in *.inesmap*. Heres a complete list of the mappers if you are curious with detail explanations: https://wiki.nesdev.com/w/index.php/Mapper

And as for mirroring in *.inesmir*, this will describe how the game will scroll the nametables.

0 - Horizontal Mirroring - Used in vertical scrolling games such as Commando, Ikari Warriors, 1942, etc.1 - Vertical Mirroring - Used in horizontal scrolling games such as Super Mario Bros, Contra, Ghost and Goblins, etc.2 - Single Screen - Used in simple games with no scrolling such as Tetris, Dr Mario, Donkey Kong, Pacman, etc.3 - Four Screen - Used in games that utilize all 4 nametable screens such as Gauntlet, Festers Quest, etc. 

For more information on mirroring, again, resort to NES Wiki. They are awesome:
https://wiki.nesdev.com/w/index.php/Mirroring

The next step is to setup our programming bank at address $C000 using dot commands again. Remember don't forget to 2 space indent:


```
  .bank 0
  .org $C000
```

I guess you could do it at $8000 if you wanted to as well, but for now, stick with $C000.

The next step is the RESET sub routine:


```
RESET:
	SEI          ; disable IRQs
	CLD          ; disable decimal mode
	LDX #$40	
	STX $4017    ; disable APU frame IRQ
	LDX #$FF	
	TXS          ; Set up stack
	INX          ; now X = 0
	STX $2000    ; disable NMI
	STX $2001    ; disable rendering
	STX $4010    ; disable DMC IRQs
```

Since the 6502 inside the NES is actually a 2A03 with no decimal commands, but rather instead, more sound outputs, decimal mode will need disabled where the line CLD is. Now we need two vblank waiting periods to occur, and clear memory in between:



```
vblankwait1:       ; First wait for vblank to make sure PPU is ready
	BIT $2002
	BPL vblankwait1

clrmem:
	LDA #$00
	STA $0000, x
	STA $0100, x
	STA $0200, x
	STA $0400, x
	STA $0500, x
	STA $0600, x
	STA $0700, x
	LDA #$FE
	STA $0300, x
	INX
	BNE clrmem
   
vblankwait2:      ; Second wait for vblank, PPU is ready after this
	BIT $2002
	BPL vblankwait2
```

The next step is to loop forever in between. Note that *this is NOT where the game loop is.*



```
Foreverloop:
	JMP Foreverloop     ;jump back to Forever, infinite loop
```

This loop is necessary so it can activate an NMI (non maskable interrupt) every frame, doing so 60 frames per second on NTSC NES's. When it does, then this will be where our game code will enly and do something. The NES will automatically clear the screen so you do not have to worry about trying to clear it with code. The end of all the game code will end at RTI (return from interrupt). But for now well keep it blank.



```
NMI:
	RTI
```

Now we are going to need the interrupt bank:



```
  .bank 1
  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the 
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
```

And last but not least some code to load external files:



```
  .bank 2
  .org $0000
  .incbin "mario.chr"   ;includes 8KB graphics file from SMB1
```

I don't know why the origin is $0000 and not $0200, but don't question it, it just works. Just make sure the CHR file is in the same directory as your asm file. Now after saving the complete code as an asm file, you only need to either drag the asm file into your NESASM3 or open your batch file you created to compile it (compile.bat), with the 2nd option being the preferred choice. If it passes, you should now have two new files both having the extention .nes and .fns. Open up your emulator, and load your new NES game. Vwola, you should see a grey background. This concludes our tutorial. Next time, I will teach you how to setup a color palette, and change the background color!  

Also to make it easier, the complete code will be shown below:



```
  .inesprg 1   ; 1x 16KB PRG code
  .ineschr 1   ; 1x  8KB CHR data
  .inesmap 0   ; mapper 0 = NROM, no bank swapping
  .inesmir 1   ; background mirroring
  
;;;;;;;;;;;;;;;

  .bank 0
  .org $C000 
RESET:
  SEI          ; disable IRQs
  CLD          ; disable decimal mode
  LDX #$40	
  STX $4017    ; disable APU frame IRQ
  LDX #$FF	
  TXS          ; Set up stack
  INX          ; now X = 0
  STX $2000    ; disable NMI
  STX $2001    ; disable rendering
  STX $4010    ; disable DMC IRQs

vblankwait1:       ; First wait for vblank to make sure PPU is ready
  BIT $2002
  BPL vblankwait1

clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem
   
vblankwait2:      ; Second wait for vblank, PPU is ready after this
  BIT $2002
  BPL vblankwait2

Foreverloop:
  JMP Foreverloop     ;jump back to Forever, infinite loop

NMI:
  RTI
 
;;;;;;;;;;;;;;  

  .bank 1
  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the 
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
  
;;;;;;;;;;;;;;  

  .bank 2
  .org $0000
  .incbin "mario.chr"   ;includes 8KB graphics file from SMB1
```

----------


## 8bitZedha

Hello man. First at all et me thank you for this great and useful tutorial. I'm a total noob in NES programming. I've finished the excersice, but i can't get the NESASM3 works. If i try to open it, only get a flicker of the screen an thats it. I don't understand how to make the 2 files. Surelly im doing something wrong. So I hope you can help me. Thanks again.

----------


## passel

You don't open it.
You open a cmd window, and you run it from there. It is a command line interface.

You could drag a file and drop it on the executable, and then you should see what you're seeing, i.e. a command windows flashes up briefly while the program is being assembled, and then goes away. If everything worked, you would have the output files in the directory. If it didn't, you don't know what happen.

That is why Jacob suggest using a batch file (.bat), with the contents as shown in the first code window of his post. Double clicking on the bat file, will automatically open a Cmd window to run the batch file, which will assemble your file, and then the "pause" will keep the window open so you can see the results.

Personally, when I use batch files or compile things from the command line, I just open a command window and work from it, rather than use Windows Explorer, but either will work.

----------


## Jacob Roman

Yup. BAT file man  :Stick Out Tongue:

----------


## tonia6970

If i have some nes rom game, then how Can i see its source code ?

----------


## Jacob Roman

> If i have some nes rom game, then how Can i see its source code ?


You have to understand what the contents of an NES rom is and how to code in 6502 assembly (all 56 opcodes and 13 address modes, not including illegal opcodes  :Eek Boom: ) and know the hexadecimal numbers of the instructions are to know the source code. The rom contains more than just code, but also the chr graphics file. When you read a rom, the first thing you will see is 'N' 'E' 'S' and the hexadecimal '1A'. The next value is how many PRGROM pages there are (the source code). The next value is how many CHRROM pages are there (the graphics). The value after that is known as the ROM_Control_Byte_1. The value after that is known as ROM_Control_Byte_2. Using this formula:



```
nes_rom.Mapper = (ROM_Control_Byte_1 >> 4) + (ROM_Control_Byte_2 & 0xf0);
```

it determines what mapper number the rom is. And there is lots of em. 256 available but actually less than that because some mapper numbers are unused or are death mappers. You can see it here: https://wiki.nesdev.com/w/index.php/Mapper

ROM_Control_Byte_1 also determines what kind of screen mirroring. Is it horizontal vertical, single screen, or four screen? And determines if there is a battery save or trainer is present. If there is one, its gonna determine where in the rom the source code is found. I'll show you a small clip of code from my C++ version of my NES emulator to show you what I mean:


C++ Code:
if (nes_rom.Trainer_Present)
{
    NES_File.seekg(16);
    NES_File.read((char *)Train, 0x200);
    NES_File.seekg(528);
    NES_File.read(reinterpret_cast<char *>(nes_rom.PRG_ROM.data()), nes_rom.PRG_ROM.size());
    NES_File.seekg((nes_rom.PRG_ROM_Pages * 0x4000) + 528);
    NES_File.read(reinterpret_cast<char *>(nes_rom.CHR_ROM.data()), nes_rom.CHR_ROM.size());
}
else
{
    NES_File.seekg(16);
    NES_File.read(reinterpret_cast<char *>(nes_rom.PRG_ROM.data()), nes_rom.PRG_ROM.size());
    NES_File.seekg((nes_rom.PRG_ROM_Pages * 0x4000) + 16);
    NES_File.read(reinterpret_cast<char *>(nes_rom.CHR_ROM.data()), nes_rom.CHR_ROM.size());
}

So nes_rom.PRG_ROM_Pages * 0x4000  plus the offset shows you where the source code to your rom is located as well as how many pages. So if there is one page, theres 0x4000 lines of code (16,384 in standard decimal format) times the number of pages. at either 16 or 528 depending if there is a trainer present. 

As for the code, have fun comparing each hexadecimal you come across with these  :big yellow: 


C++ Code:
//////////////////////
    // Constants:
    //////////////////////
    // ADC: 0x69; 0x65; 0x75; 0x6d; 0x7d; 0x79; 0x61; 0x71
    static const byte ADC_IMMEDIATE = 0x69;
    static const byte ADC_ZERO_PAGE = 0x65;
    static const byte ADC_ZERO_PAGE_X = 0x75;
    static const byte ADC_ABSOLUTE = 0x6d;
    static const byte ADC_ABSOLUTE_X = 0x7d;
    static const byte ADC_ABSOLUTE_Y = 0x79;
    static const byte ADC_INDIRECT_X = 0x61;
    static const byte ADC_INDIRECT_Y = 0x71;
     // AND: 0x29; 0x25; 0x35; 0x2d; 0x3d; 0x39; 0x21; 0x31
    static const byte AND_IMMEDIATE = 0x29;
    static const byte AND_ZERO_PAGE = 0x25;
    static const byte AND_ZERO_PAGE_X = 0x35;
    static const byte AND_ABSOLUTE = 0x2d;
    static const byte AND_ABSOLUTE_X = 0x3d;
    static const byte AND_ABSOLUTE_Y = 0x39;
    static const byte AND_INDIRECT_X = 0x21;
    static const byte AND_INDIRECT_Y = 0x31;
     // ASL: 0x0a; 0x06; 0x16; 0x0e; 0x1e
    static const byte ASL_ACCUMULATOR = 0x0a;
    static const byte ASL_ZERO_PAGE = 0x06;
    static const byte ASL_ZERO_PAGE_X = 0x16;
    static const byte ASL_ABSOLUTE = 0x0e;
    static const byte ASL_ABSOLUTE_X = 0x1e;
     // BCC: 0x90
    static const byte BCC_RELATIVE = 0x90;
     // BCS: 0xb0
    static const byte BCS_RELATIVE = 0xb0;
     // BEQ: 0xf0
    static const byte BEQ_RELATIVE = 0xf0;
     // BIT: 0x24; 0x2c
    static const byte BIT_ZERO_PAGE = 0x24;
    static const byte BIT_ABSOLUTE = 0x2c;
     // BMI: 0x30
    static const byte BMI_RELATIVE = 0x30;
     // BNE: 0xd0
    static const byte BNE_RELATIVE = 0xd0;
     // BPL: 0x10
    static const byte BPL_RELATIVE = 0x10;
     // BRK: 0x00
    static const byte BRK_IMPLIED = 0x00;
     // BVC: 0x50
    static const byte BVC_RELATIVE = 0x50;
     // BVS: 0x70
    static const byte BVS_RELATIVE = 0x70;
     // CLC: 0x18
    static const byte CLC_IMPLIED = 0x18;
     // CLD: 0xd8
    static const byte CLD_IMPLIED = 0xd8;
     // CLI: 0x58
    static const byte CLI_IMPLIED = 0x58;
     // CLV: 0xb8
    static const byte CLV_IMPLIED = 0xb8;
     // CMP: 0xc9; 0xc5; 0xd5; 0xcd; 0xdd; 0xd9; 0xc1; 0xd1
    static const byte CMP_IMMEDIATE = 0xc9;
    static const byte CMP_ZERO_PAGE = 0xc5;
    static const byte CMP_ZERO_PAGE_X = 0xd5;
    static const byte CMP_ABSOLUTE = 0xcd;
    static const byte CMP_ABSOLUTE_X = 0xdd;
    static const byte CMP_ABSOLUTE_Y = 0xd9;
    static const byte CMP_INDIRECT_X = 0xc1;
    static const byte CMP_INDIRECT_Y = 0xd1;
     // CPX: 0xe0; 0xe4; 0xec
    static const byte CPX_IMMEDIATE = 0xe0;
    static const byte CPX_ZERO_PAGE = 0xe4;
    static const byte CPX_ABSOLUTE = 0xec;
     // CPY: 0xc0; 0xc4; 0xcc
    static const byte CPY_IMMEDIATE = 0xc0;
    static const byte CPY_ZERO_PAGE = 0xc4;
    static const byte CPY_ABSOLUTE = 0xcc;
     // DEC: 0xc6; 0xd6; 0xce; 0xde
    static const byte DEC_ZERO_PAGE = 0xc6;
    static const byte DEC_ZERO_PAGE_X = 0xd6;
    static const byte DEC_ABSOLUTE = 0xce;
    static const byte DEC_ABSOLUTE_X = 0xde;
     // DEX: 0xca;
    static const byte DEX_IMPLIED = 0xca;
     // DEY: 0x88;
    static const byte DEY_IMPLIED = 0x88;
     // EOR: 0x49; 0x45; 0x55; 0x4d; 0x5d; 0x59; 0x41; 0x51
    static const byte EOR_IMMEDIATE = 0x49;
    static const byte EOR_ZERO_PAGE = 0x45;
    static const byte EOR_ZERO_PAGE_X = 0x55;
    static const byte EOR_ABSOLUTE = 0x4d;
    static const byte EOR_ABSOLUTE_X = 0x5d;
    static const byte EOR_ABSOLUTE_Y = 0x59;
    static const byte EOR_INDIRECT_X = 0x41;
    static const byte EOR_INDIRECT_Y = 0x51;
     // INC: 0xe6; 0xf6; 0xee; 0xfe
    static const byte INC_ZERO_PAGE = 0xe6;
    static const byte INC_ZERO_PAGE_X = 0xf6;
    static const byte INC_ABSOLUTE = 0xee;
    static const byte INC_ABSOLUTE_X = 0xfe;
     // INX: 0xe8
    static const byte INX_IMPLIED = 0xe8;
     // INY: 0xc8
    static const byte INY_IMPLIED = 0xc8;
     // JMP: 0x4c; 0x6c
    static const byte JMP_ABSOLUTE = 0x4c;
    static const byte JMP_INDIRECT = 0x6c;
     // JSR: 0x20
    static const byte JSR_ABSOLUTE = 0x20;
     // LDA: 0xa9; 0xa5; 0xb5; 0xad; 0xbd; 0xb9; 0xa1; 0xb1
    static const byte LDA_IMMEDIATE = 0xa9;
    static const byte LDA_ZERO_PAGE = 0xa5;
    static const byte LDA_ZERO_PAGE_X = 0xb5;
    static const byte LDA_ABSOLUTE = 0xad;
    static const byte LDA_ABSOLUTE_X = 0xbd;
    static const byte LDA_ABSOLUTE_Y = 0xb9;
    static const byte LDA_INDIRECT_X = 0xa1;
    static const byte LDA_INDIRECT_Y = 0xb1;
     // LDX: 0xa2; 0xa6; 0xb6; 0xae; 0xbe
    static const byte LDX_IMMEDIATE = 0xa2;
    static const byte LDX_ZERO_PAGE = 0xa6;
    static const byte LDX_ZERO_PAGE_Y = 0xb6;
    static const byte LDX_ABSOLUTE = 0xae;
    static const byte LDX_ABSOLUTE_Y = 0xbe;
     // LDY: 0xa0; 0xa4; 0xb4; 0xac; 0xbc
    static const byte LDY_IMMEDIATE = 0xa0;
    static const byte LDY_ZERO_PAGE = 0xa4;
    static const byte LDY_ZERO_PAGE_X = 0xb4;
    static const byte LDY_ABSOLUTE = 0xac;
    static const byte LDY_ABSOLUTE_X = 0xbc;
     // LSR: 0x4a; 0x46; 0x56; 0x4e; 0x5e
    static const byte LSR_ACCUMULATOR = 0x4a;
    static const byte LSR_ZERO_PAGE = 0x46;
    static const byte LSR_ZERO_PAGE_X = 0x56;
    static const byte LSR_ABSOLUTE = 0x4e;
    static const byte LSR_ABSOLUTE_X = 0x5e;
     // NOP: 0xea
    static const byte NOP_IMPLIED = 0xea;
     // ORA: 0x09; 0x05; 0x15; 0x0d; 0x1d; 0x19; 0x01; 0x11
    static const byte ORA_IMMEDIATE = 0x09;
    static const byte ORA_ZERO_PAGE = 0x05;
    static const byte ORA_ZERO_PAGE_X = 0x15;
    static const byte ORA_ABSOLUTE = 0x0d;
    static const byte ORA_ABSOLUTE_X = 0x1d;
    static const byte ORA_ABSOLUTE_Y = 0x19;
    static const byte ORA_INDIRECT_X = 0x01;
    static const byte ORA_INDIRECT_Y = 0x11;
     // PHA: 0x48
    static const byte PHA_IMPLIED = 0x48;
     // PHP: 0x08
    static const byte PHP_IMPLIED = 0x08;
     // PLA: 0x68
    static const byte PLA_IMPLIED = 0x68;
     // PLP: 0x28
    static const byte PLP_IMPLIED = 0x28;
     // ROL: 0x2a; 0x26; 0x36; 0x2e; 0x3e;
    static const byte ROL_ACCUMULATOR = 0x2a;
    static const byte ROL_ZERO_PAGE = 0x26;
    static const byte ROL_ZERO_PAGE_X = 0x36;
    static const byte ROL_ABSOLUTE = 0x2e;
    static const byte ROL_ABSOLUTE_X = 0x3e;
     // ROR: 0x6a; 0x66; 0x76; 0x6e; 0x7e;
    static const byte ROR_ACCUMULATOR = 0x6a;
    static const byte ROR_ZERO_PAGE = 0x66;
    static const byte ROR_ZERO_PAGE_X = 0x76;
    static const byte ROR_ABSOLUTE = 0x6e;
    static const byte ROR_ABSOLUTE_X = 0x7e;
     // RTI: 0x40
    static const byte RTI_IMPLIED = 0x40;
     // RTS: 0x60
    static const byte RTS_IMPLIED = 0x60;
     // SBC: 0xe9; 0xe5; 0xf5; 0xed; 0xfd; 0xf9; 0xe1; 0xf1
    static const byte SBC_IMMEDIATE = 0xe9;
    static const byte SBC_ZERO_PAGE = 0xe5;
    static const byte SBC_ZERO_PAGE_X = 0xf5;
    static const byte SBC_ABSOLUTE = 0xed;
    static const byte SBC_ABSOLUTE_X = 0xfd;
    static const byte SBC_ABSOLUTE_Y = 0xf9;
    static const byte SBC_INDIRECT_X = 0xe1;
    static const byte SBC_INDIRECT_Y = 0xf1;
     // SEC: 0x38
    static const byte SEC_IMPLIED = 0x38;
     // SED: 0xf8
    static const byte SED_IMPLIED = 0xf8;
     // SEI: 0x78
    static const byte SEI_IMPLIED = 0x78;
     // STA: 0x85; 0x95; 0x8d; 0x9d; 0x99; 0x81; 0x91
    static const byte STA_ZERO_PAGE = 0x85;
    static const byte STA_ZERO_PAGE_X = 0x95;
    static const byte STA_ABSOLUTE = 0x8d;
    static const byte STA_ABSOLUTE_X = 0x9d;
    static const byte STA_ABSOLUTE_Y = 0x99;
    static const byte STA_INDIRECT_X = 0x81;
    static const byte STA_INDIRECT_Y = 0x91;
     // STX: 0x86; 0x96; 0x8e
    static const byte STX_ZERO_PAGE = 0x86;
    static const byte STX_ZERO_PAGE_Y = 0x96;
    static const byte STX_ABSOLUTE = 0x8e;
     // STY: 0x84; 0x94; 0x8c
    static const byte STY_ZERO_PAGE = 0x84;
    static const byte STY_ZERO_PAGE_X = 0x94;
    static const byte STY_ABSOLUTE = 0x8c;
     // TAX: 0xaa
    static const byte TAX_IMPLIED = 0xaa;
     // TAY: 0xa8
    static const byte TAY_IMPLIED = 0xa8;
     // TSX: 0xba
    static const byte TSX_IMPLIED = 0xba;
     // TXA: 0x8a
    static const byte TXA_IMPLIED = 0x8a;
     // TXS: 0x9a
    static const byte TXS_IMPLIED = 0x9a;
     // TYA: 0x98
    static const byte TYA_IMPLIED = 0x98;

----------


## tonia6970

> You have to understand what the contents of an NES rom is and how to code in 6502 assembly (all 56 opcodes and 13 address modes, not including illegal opcodes ) and know the hexadecimal numbers of the instructions are to know the source code. The rom contains more than just code, but also the chr graphics file. When you read a rom, the first thing you will see is 'N' 'E' 'S' and the hexadecimal '1A'. The next value is how many PRGROM pages there are (the source code). The next value is how many CHRROM pages are there (the graphics). The value after that is known as the ROM_Control_Byte_1. The value after that is known as ROM_Control_Byte_2. Using this formula:
> 
> 
> 
> ```
> nes_rom.Mapper = (ROM_Control_Byte_1 >> 4) + (ROM_Control_Byte_2 & 0xf0);
> ```
> 
> it determines what mapper number the rom is. And there is lots of em. 256 available but actually less than that because some mapper numbers are unused or are death mappers. You can see it here: https://wiki.nesdev.com/w/index.php/Mapper
> ...


Thanks for the respond. I have some nes rom game which I try to convert it in Unity platform (C# programming language). I have created the half game but I should understand the logic of game for example every when the enemy fly or shoot etc... If I have the source code in some high level programming language like Python, C, C++, Java then if I read it then I could understand the logic of game so that to convert it to C# for Unity. Now it is in assembly which is not understable. If I sent you the source code, then can you undrstand the logic of game or does it exist some way to convert assembly to C or C++ (or to some other high level programming language) - I don't care if the converted file is perfect converted so that to be runnable because I care to see atleast in around how to be the source code & I will understand the logic of game.

----------


## Jacob Roman

I think it would be easier if you visualize what the game is doing and code it by hand. Getting the direct source code wont convert well to modern hardware because the code is working around the NES's hardware, which includes bank switching, something modern hardware doesn't have to do. Not to mention it would be redundant to convert every line of 6502 assembly one line at a time. Just saying.

----------


## tonia6970

> I think it would be easier if you visualize what the game is doing and code it by hand. Getting the direct source code wont convert well to modern hardware because the code is working around the NES's hardware, which includes bank switching, something modern hardware doesn't have to do. Not to mention it would be redundant to convert every line of 6502 assembly one line at a time. Just saying.


This is what I have done until now. I try to see and understand the behavior of each enemy and after to translate to C#. But at to point which I am now, the behavior in some points is some random and can't get accurate conclusion and for this reason I found the source code to view it but it was in assembly. I fantasize that all these tutorials which exists, and say for assembly to C or to C++, are fake ?
The nes game is the Galaxian.

----------


## Jacob Roman

You will most definitely run into problems during the conversion, which is why it is pointless. Collision is definitely one of them. The PPU chip in the NES already handles the collision using hardware one bit out of the 8 bits of the PPU Address register, if I remember correctly, or at least one of the PPU Addresses from $2000 to $2007, not including mirroring.

If it is collision you are after, then I can definitely help. Currently I been designing collision algorithms for primitives no matter how fast the object goes, even if it is a billion pixels a frame, it will register a collision. I don't wanna give too much away since it is my algorithms, but lets say it involves some vector math and the use of what is called signed distance. If, for example, a circle is on one side of the wall, the signed distance is positive, but once it is on the other side, it is negative. It involves getting the normal of the segment wall (the direction the wall is facing) with some dot products:



```
VECTOR2D normal = normal.Set_Normal(segment_vector);
float old_signed_distance = normal.Dot_Product(old_position) - (normal.Dot_Product(segment_origin));
float signed_distance = normal.Dot_Product(position) - (normal.Dot_Product(segment_origin));
```

I also use not just position but the old position of the circle. So pretend one frame of animation went by. If the old position of circle is on one side of the wall, and the new position of the circle is on the other side of the wall, and its invisible capsule (2 circles old position and new position plus the rectangle formed from the one frame movement) used instead of a ray pierced the segment in any way shape or form, a collision definitely took place, and I use some nifty trig to offset the new position with the circles radius to be against the wall. Its pretty neat actually. And I can do it with ellipses as well using vector spaces.

----------

