Saturday, May 31, 2014

NES Trivia Postmortem

For my Blazing Games June game I am releasing my NES Trivia game even though I have not yet quite got to it in the blog. See the what went wrong section for the reason for this. Needless to say, here is the postmortem.

What Went Right

The string library that was developed for general purpose use worked really well. Especially when the macros were used. Lots of the display-related code is very easy to understand thanks to the use of the PrintStringAt macro. While the StrNCmp function was never used in the game, it will be used in the sequel so the code was not wasted, just slightly premature.

Mixed Blessings

The whole reason for this game was to actually create a simple game fairly early in the series. As it turned out, there was a lot more foundation work that I had to write about before I could get to the meat and have a real game. Even at this point there are things that could be improved. The biggest being randomness. Right after that (before that for many people) is sound. Filling up the extra ROM space with questions and touching up the display finish off my list.

What Went Wrong

This was not the game I was planning on releasing for June. I was going to hold off releasing the game until we actually started creating the game in this blog. Unfortunately, the game I was hoping to release for June simply was too large for the amount of time I had available (and my Dad going into the hospital for a hernia operation didn't help). Using this game as filler material was my only option. Sadly the game I was developing is going to be delayed by at least a month as there is a big RPG Maker contest in June. While I suspect there are people who are far more knowledgable about RPG Maker that will probably win, there are real prizes for this challenge and I did want to try out the tool so this will be my June project. If the resulting game got enough interest, and especially if it won money, I would probably shift my focus to developing a full version of that game.

Friday, May 23, 2014

String Theory

While I do have an interest in theoretical physics, this column is not about that. When it comes to programming, strings are taken for granted. Pretty much every language comes with a comprehensive string library. In modern-day programming, it really is not necessary to write a string library. After all, most string libraries are really well written so there is nothing to be gained from writing your own.

When it comes to early game consoles, however, writing your own library may make sense. Early consoles don't have that much memory so you only want functionality that is actually required. It is certainly possible to find general purpose 6502 string libraries, but basic strings are simple enough that it is fairly easy to write a few routines for dealing with them.

Ultimately strings are simply arrays of characters. The type of characters is based on the platform. For the NES, we use bytes that indicate which pattern table character to display. This does not have to correspond to ASCII, but my pattern tables tend to at least partially incorporate the ASCII character set. For modern string libraries unicode may be used,quite possibly using UTF-8 formatting. There are numerous ways of implementing strings. The three most common methods are fixed length, Pascal-style and C-style strings.

Fixed length strings have a set length with any unused characters being spaces or null characters. This technique is often used with databases to help ensure that every row of the database table is the same length as that makes manipulating the database much more efficient. As the length of the string is known, no additional information about the string is needed, though if you are going to be frequently comparing strings you may want to keep a hash-value. The downside to this method of representing strings is that every string must be at least the length of the longest allowed string so this method is not memory efficient.

Many dialects of the Pascal language represent strings by having the first byte be the length of the string followed by the array of characters. This length variable didn't need to be a byte so later versions of this method would use 16 or 32-bit integers for the length. Variable-length strings were more efficient, and dealing with the length is simple enough but as nice as Pascal was as a programming language, the C language and it's numerous variants would dominate programming and C had a different method of handling strings.

C-style strings, also known as null-terminating strings, simply continue until a 0 is reached. The lack of an explicit length has resulted in buffer-overflow bugs that still haunt us today. The idea here is that if a string is larger than the size allocated for the string, copying the string will result in data beyond the allocated size of the string being overwritten. This can result in data corruption or worse. If you are writing in C, strncpy should always be used in place of strcpy.

As memory is at a premium, the choice of string format for my home-brew projects really comes down to a choice between C strings and Pascal strings. As C strings are more common, that is the format that will be used. String copy, compare, concatenation and some printing functions should be sufficient for our needs.

Friday, May 16, 2014

6502 Pointers

Pointers are one of those programming subjects that tend to confuse people yet once understood is really fairly simple. If you have been following my NES series of articles, the following code is probably easy to understand:

        LDY #0
CopySpriteData:
        LDA SpriteData,Y
        STA $200,Y
        INY
        BEQ CopySpriteData
        RTS

SpriteData:
        ; 256 bytes of sprite data go here

This code simply copies 256 bytes of data from SpriteData to the second page of 6502 memory. The fact that when a byte overflows it wraps around and becomes 0 again is used to terminate the loop. This code seems easy enough. The LDA instruction is using the address SpriteData is at, then adding the Y register to that value to come up with the memory address to grab the byte being copied from. Likewise, the STA is using the memory address $200 and adding the Y register to it to find the address to store the byte.

Pointers work pretty much the same way but instead of directly using an address, the address is stored in a pair of zero page addresses. Why would you want to do this? By having pointers to addresses instead of hard-coding the address you can create general-purpose functions. The caller would simply fill in the pointer with the address the function is suppose to use then call the function. The 6502 expects addresses to be written in a low to high format meaning the low-order byte is followed by the high-order byte. This is known as little-endian format. For NES developers this can be confusing as the PPU uses high/low (big-endian) for specifying addresses. To demonstrate pointers, here is a simple MemCpy function.

MemCpy:
        LDY #0
MemCpy_loop:
        LDA [SOURCE_PTR],Y
        STA [DEST_PTR],Y
        INY
        CPY COPY_LENGTH
        BNE MemCpy_loop
        RTS

The Y register is zeroed out before the loop. The byte at the address pointed to in SOURCE_PTR offset by  Y is loaded into the accumulator. This value is then stored at the address pointed to by DEST_PTR offset by Y.  The Y offset is increased and the loop continues until Y is equal to the value in COPY_LENGTH.

This works, but the amount of effort required to set up the zero-page pointer variables requires more instructions than the actual function. A more complex function, such as a MemCpy function that supported 16-bit copy-lengths would be worth doing. Likewise, when you are dealing with addresses that you may not know beforehand, such as will be the case with the general-purpose prompt routines we will be developing, using pointers to data is incredibly handy.

The use of pointers is something that will be used quite a bit as we progress. Our Trivia game will be needing strings and some type of way of selecting a choice so that is what we will be focusing on next.

Saturday, May 10, 2014

NES Hello Sprites 2

NES programs will often clone sprite memory in RAM to allow for DMA transfers. DMA, which stands for Direct Memory Access, is a rapid way of transferring blocks of memory to hardware. When a DMA transfer happens, the processor is temporarily halted while the memory is rapidly copied into PPU memory. While this still takes time, it is much faster than manually copying sprites. If you have a large number of sprites, it is far better to use DMA than to manually copy sprites.

Another convenience that the NES provides programmers is a VBlank Non-Maskable Interrupt (NMI). Interrupts cause the processor to stop what it is doing and immediately start running the subroutine pointed to by the interrupt vector. There are two types of interrupts. Your regular interrupts, or IRQs, can be disabled by the SEI instruction and enabled by the CLI instruction. NMIs are not affected by those instructions so will always occur. The PPU control register, however, does allow the VBlank to be disabled.

The advantage of using interrupts is that you do not have to worry about polling for the VBlank so you can process other game logic while the PPU is drawing the screen without having to worry about missing this important period. In this second sprite demo, all of our logic will be done in the interrupt handler, though this certainly does not have to be the case and in later projects we will be developing a state machine to handle complex processing.

The code for the second version of our sprite demo is very similar to the original version with only a few changes needed to support interrupts and DMA. Instead of copying the sprite data directly to the PPUs sprite memory, it is copied to a page of RAM. VBlank interrupts are enabled just before the radically changed main loop as follows:

LDA #%10000000 ; enable NMI
STA $2000

MainGameLoop:
NOP ; Right now we do nothing in the main loop.
JMP MainGameLoop

Yes, absolutely nothing is done in the main loop. Instead all work is done in the Interrupt. While the NOP instruction is not necessary, I have heard urban legends about loops causing hardware to catch fire. I find this highly suspect but spreading the loop over an extra instruction does give me an excuse to use my favorite 6502 instruction. The real logic happens in the Non-maskable interrupt routine. Though thanks to DMA hardware this is much simpler than the manual method of transferring sprite information.

NMI:
LDA #2
STA $4014
JSR MoveSprites
RTI

As you can see, DMA is very simple to use. You just store the page of memory you want to transfer to the PPU into $4014. The move sprites function is almost identical except it stores sprite positions to RAM instead of writing directly to the PPUs sprite memory which has the added benefit of being more compatible with emulators (always a benefit for home-brew games).

Thursday, May 1, 2014

Maze 3D postmortem

While there was not enough interest in Coffee Quest 2600 to warrant developing it, I really wanted to see if my rendering technique really would work on the 2600 with the limitations the system has. This game is the result and proves that CQ2600 could be done. I would love to develop a proper 2600 RPG though it is doubtful this will happen. Still, here is the postmortem for my 2600 3D maze game.

What Went Right

Stella was the code name for the 2600 console and is also then name of an open source 2600 emulator. If you ever decide to develop a home-brew 2600 game, this is an awesome emulator to use during development. The built in debugger is simply wonderful to use. Not only does it have your break-points and stepping through code capabilities, but you also see where the cathode ray is when stepping through the code. As some of the hardest programming/debugging involves the timing of the cathode ray, this is a wonderful feature. Other handy features include actually seeing what the TIA registers hold and smart disassembly.  The disassembler appears to track exactly which parts of the ROM are used for instructions and what parts are used for play-field and sprite data showing graphical representation of the data. This debugger made getting the game working much easier!

Mixed Blessings

The game required reworking the display that was used in my Coffee Quest 2600 game. While a lot of the logic used in that game was usable, there was a fairly large amount of code that needed to be reworked. The decision to have a top bar with a compass in the centre was a direct result of playing Coffee Quest 2600 as I found that it was way too easy to get disoriented while playing the game. The compass at least makes it possible to know which direction you are heading in. I was also going to have coordinates displayed on the bar, but the amount of time and effort to add this was too high so this feature was left out of the game.

What Went Wrong

"Racing the Beam" is a phrase used to describe programming the 2600. This is sort of correct as the entire program revolves around the timing of the display. However, especially when you are doing more complex things such as asymmetrical play-fields, you are not trying to keep ahead of the beam but need to wait for the beam to get ahead of you. With asymmetrical play-fields, you set up the play-field registers for the first half of the display but can only set up the registers for the second half of the display only after the beam has drawn the register you are changing otherwise what is being drawn is incorrect. This results in ugly code where some of the logic that should be done at the end of the block has to be done in the middle of the block. This is so that the beam can draw the play-register that needs to be changed.

This was a very interesting challenge as such tight constraints in memory and timing are rarely issues with modern day programs. With so little time to get things done, seemingly simple things such as shifting mask registers takes too long and has to be replaced with small look-up tables. Yet look-up tables take up precious memory so it is an interesting balancing act.