Friday, October 7, 2016

NESDev - Sprites

I'm really overdue for this post.

Week 4 of the Nerdy Nights tutorial covered the NES color palettes as well as a brief introduction to sprites.  Week 5 followed up with more elaboration on sprites and introducing controls.  It was a fair amount of information to take in and understand,and seeing as how I started the lesson 2 weeks ago, I may be scrambling together it all back together again.

For now, I'll just go off the notes I had taken at the time...


Sprites/PPU Review

  • Sprites - non-static graphics that are separate from the background.
    • made up of 8x8 tiles of pixels
    • PPU can hold up to 64 sprites
  • Sprite DMA - "Direct Memory Access"
    • This is apparently a method for transfer sprites into memory, and the way it works is described as "a block of RAM is copied from CPU memory to the PPU sprite memory". 
    • Typically uses addresses $0200-$02FF 
    • I'll be coming back to this one...

Let's break down the code... "sprites.asm"


We left off discussing how the color palette gets loaded into the NES PPU.  Following this in the code structure of sprites.asm is the loading and placement of a single sprite.  The way sprites are loaded in to the PPU is brokem down into 4 specific bytes of data:
  1. Y-Position
  2. Tile number - referencing the pattern table position
  3. Attributes - color and display info
  4. X-Position
The x and y position seems to work on a grid, similar to below:

-- INSERT GRID HERE --


The tile number is in reference to the placement of tiles within the .chr file.  Using FCEUX SP, we can see those values quite clearly:



Lastly, the attributes are adjusted in a similar fashion to the PPUCTRL register discussed previously.  The program sends a string of 8 buts to the last register reserved for this sprite.  Those bits are organized as such (from Nerdy Nights):

  76543210
  |||   ||
  |||   ++- Color Palette of sprite.  Choose which set of 4 from the 16 colors to use
  |||
  ||+------ Priority (0: in front of background; 1: behind background)
  |+------- Flip sprite horizontally
  +-------- Flip sprite vertically

There are essentially 4 steps to loading a sprite into the PPU.  The code snippet included in this weeks tutorial paints this quite simply using 1 byte to center the sprite (#$80), and 1 byte to determine which sprite to place and how it will look (#$00):

  LDA #$80
  STA $0200        ;put sprite 0 in center ($80) of screen vertically
  STA $0203        ;put sprite 0 in center ($80) of screen horizontally
  LDA #$00
  STA $0201        ;tile number = 0
  STA $0202        ;color palette = 0, no flipping

  LDA #%10000000   ; enable NMI, sprites from Pattern Table 0 (PPUCNTRL)
  STA $2000

  LDA #010000   ; no intensify (black background), enable sprites (PPUMASK)
  STA $2001

Notice where the data is being loaded.  As mentioned previously, the Sprite DMA typically uses addresses $0200 - $02FF.  Each sprite that is loaded will use 4 adresses to cover the 4 bytes of data we have mentioned here, hence why this particular sprite is loaded into registers $0200 - $0203.

It is worth noting that this code snippet also loads to PPUCTRL and PPUMASK (last 4 lines).  The comments should speak to themselves as to what the values are controlling.  However, I am finding it useful to keep a reference sheet on hand.

Multiple Sprites

In the following week's lesson, bunnyboy goes into the process of placing multiple sprites into the PPU.  There isn't too much to this, we can apply the same logic used when we loaded color palette data previously.  Storing those 4 values into a .db directive helps keep everything organized:

sprites:
     ;vert tile attr horiz
  .db $80, $32, $00, $80   ;sprite 0
  .db $80, $33, $00, $88   ;sprite 1
  .db $88, $34, $00, $80   ;sprite 2
  .db $88, $35, $00, $88   ;sprite 3

Using the X index, we can apply these bytes of data into the appropriate addresses within $0200-$02FF using a simple loop.


LoadSprites:
  LDX #$00              ; start at 0
LoadSpritesLoop:
  LDA sprites, x        ; load data from address (sprites + x)
  STA $0200, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadSpritesLoop   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
                        ; if compare was equal to 16, continue down

I've given up on formatting.

This logic should be fairly easy to follow, but just in case, I'll break it down:
  1. Load #$00 into Index X.  As we will be using this register to keep count as we load each individual byte of sprite data, we may as well be starting at 0.
  2. Load the first byte from the sprites .db directive.  As we are starting at 0, value 0 is loaded into Accumulator A ($80, in this case).
  3. Store the loaded byte into $0200.  The reference to accumulator X will result in a step up to the next register once the loop completes and starts again.
  4. Increment X.  This adds #$01 to the number currently stored in index X.  This allows us to step up to the next byte of data in the sprite directory and the next PPU address to store the data in.
  5. Compare X to #$10 and branch back to loop start if they are not equal.  This compares the current index count to the decimal number 16, which is the number of bytes we have stored in the sprite directory.  If we have hit this number, then we have loaded all of our sprites and can move on in the code.

For the next post I will be going into the use on controllers and how they control the movement of these sprites.  I will probably be referring a lot to the information covered in this post.

Cheers,
-JWest

Yes, I have a lot of holes to fill in this post.

Thursday, September 29, 2016

NESDev - Hardware Implementation

I'm taking a small break from the Nerdy Nights tutorials and looking ahead to the hardware implementation of this project.  It has been my understanding that in order for me to write my own code onto a cartridge's ROM chip, I would need to get my hands on an EPROM programmer.  Thankfully, the University I study at happened to have one:


I spent a few hours with my professor teaching ourselves how it worked using a GAL chip to create some basic logic gates.  Fortunately, even as outdated as this programmer is, there was still software available for it online for Windows XP (at the verrrry bottom of the download list).  It took some effort before we were able to get the programmer into a working state.


 Thankfully, my research brought me to a a great "how-to" article on the ROM programming process by The Poor Student Hobbyist.  It looks as though the process of actually programming ROM chips and adding them to the cartridge PCB will be quite simple; the trick will be determining what size EPROM chips I will need for my CHR and PRG files.  It looks as though 128k and 32k size chips were popular for most NES cartridges at the time (source).  Which one I will need will naturally depend on the size of my game.  Either way, most of the EPROM chips used in these cartridges are compatible with this programmer, so I should not face any issues with equipment.

However, the concept of mappers are coming up again.  It might be time to write about them, either in an edit to this post or the next one.

Back to programming.

-JWest


Wednesday, September 21, 2016

NESDev - Dev Environment

This will be a little side post to talk about my current set up for working on this project.

Currently, I have 3 machines I plan on using:
  • Home Desktop
    • Running Windows 10, I use this machine for mostly gaming, browsing, and homework assignments.  
    • As the software required to complete the Nerdy Nights tutorial is intended for windows usage, I have had no issues running them on this machine (dated as it may be).
  • Macook Pro
    • The laptop I carry everywhere.  It is currently running on El Capitan (10.11.3) and is primarily used for browsing, blogging, photography, and programming.
    • Making the NESASM assembler work proved to take a little more effort to get running on the Macbook, but it is do-able.  I am having trouble with FCEUX, however.  If I get it working I will add an update, but I may wind up getting stuck with NEStopia...  I will add a footnote to the bottom of this post to share how I installed the software.
  • Acer Netbook
    • This little machine can not run anything above Windows XP.  I figured I would keep it as a backup to use the software in case I had issues with working on the macbook or the desktop.
As I am obviously looking to make my work as portable as possible, I am exploring the best method for storing files.  Currently I am just sticking to dropbox for any of the Nerdy Nights sample code, ans it will allow me to make sure that the software is working in a similar fashion across all platforms.  When I actually start building my own game, I am fairly certain it will be kept on github.

I pulled NESASM from the from cesarparent's repo.