Спасти для истории

Oct 28, 2011 00:42

http://www.bestdamnpodcastever.com/millerblog/?p=72
Текстик по странной, но интересующей меня теме. Источник недоступен - спас из вебархива. 


NES Programming: Getting Started

So the other day, I got the urge to do some retro-programming. What better platform, I thought to myself, than the Nintendo Entertainment System. Unfortunately, for the beginner, programming even a very simple ROM and running it in your favorite emulator can be challenging. So here now is my small guide to getting started.

Get the Compiler

In true retro-programming form, the NES cannot be practically programmed using a high level language like C. The system featured a Ricoh 2A03 CPU, a variant of the MOS 6502. As such, games must be written in the 6502’s assembler language. Once written, we have to compile the ASM to a binary iNES file which can be read by all popular NES emulators.

The compiler of choice for 6502 ASM, from what I gather, is the CA65 ASM compiler; part of the CC65 tool chain. Download the source distribution here. Build with GCC by opening a console, navigating to the cc65 folder, and run the following command:
make -f make/gcc.mak install

After this finishes, you should have the ASM compiler (ca65) and the linker (ld65) that we’ll need to build our ROMs.

At this point, I would recommend familiarizing yourself with the 6502 hardware and assembly language. Visit 6502.org for more information.

Creating a Simple Program

To jump right in here, let’s write a simple program:
; Displays a message on the screen. Demonstrates how to set up PPU

; and nametable

.segment "HEADER"

.byte "NES", 26, 2, 1

; CHR ROM data

.segment "CHARS"

.segment "VECTORS"

.word 0, 0, 0, nmi, reset, irq

.segment "STARTUP"

.segment "CODE"

; ===============================================

; NES Registers

; ===============================================

PPUCTRL = $2000 ; These two control the PPU in various ways

PPUMASK = $2001

PPUSTATUS = $2002 ; Can be read to get current PPU status

PPUSCROLL = $2005 ; Sets X/Y scrolling of background

PPUADDR = $2006 ; Sets VRAM address in PPU

PPUDATA = $2007 ; Writes data to current VRAM address

; ===============================================

; Entry point - jumped to when reset or powered up

; ===============================================

reset:

; Initialize NES hardware

ldx #$FF ; Reset stack pointer to $FF (255)

txs

sei ; Be sure the IRQ interrupt is disabled

lda #0

sta PPUCTRL ; Be sure NMI is off (stores zero from accumulator in PPUCTRL)

sta PPUMASK ; Be sure PPU rendering is off

; Give the PPU time to warm up

@wait1: bit PPUSTATUS ; Loop until top bit of PPUSTATUS is set

bpl @wait1

; Reading PPUSTATUS also clears top bit,

; so it's clear now

@wait2: bit PPUSTATUS ; Wait for bit to be set again

bpl @wait2

; Set first four palette entries

lda #$3F ; Set PPU address to palette RAM

sta PPUADDR

lda #0

sta PPUADDR

lda #$51 ; Set background to black

sta PPUDATA

;lda #$30 ; Set three foreground colors to white

lda #$FF

sta PPUDATA

sta PPUDATA

sta PPUDATA

; Wait for VBL before enabling display

bit PPUSTATUS

@wait3: bit PPUSTATUS

bpl @wait3

; Enable background display

lda #%00001000 ; Enable background

sta PPUMASK

lda #0 ; Scroll to top-left of nametable at $2000

sta PPUCTRL

sta PPUSCROLL

sta PPUSCROLL

; loop forever

forever:

jmp forever

; ===============================================

; Interrupt handlers

; ===============================================

irq:

rti

nmi:

rti

This program initializes the NES hardware and draws a blue background. To compile it, run ca65 and ld65 like this:
ca65 myprogram.asm

ld65 -t nes -o myprogram.nes myprogram.o

This should produce a ROM which you can run with an emulator. On my mac, I use Nestopia.

So what is all that?

For a better description of what this code actually does, I would hit up google, but I’ll try to explain the basics. I’m just getting started with this, so please, if this isn’t quite right, let me know.

First, let’s look at the structure of the ROM file. Each ROM starts with a header, denoted by the HEADER segment. The header tells the emulator what kind of ROM to expect. The first byte always are the characters “NES” followed by 26 (0×1A in hex). The next two bytes tell the emulator how many PRG-ROM blocks and CHR-ROM blocks to expect.

The next segment, called CHAR, can hold sprite data. After that in the VECTORS segment, we define several vectors which the program jumps to upon receiving an interrupt. We’ll define three (nmi, reset, and irq) but only use the reset vector which is our programs entry point.

Next, we give names to six of the NES’s eight memory-mapped registers. We’ll use these to manipulate the NES’s picture processing unit (PPU).

Finally, we get to the actual program. The first order of business is to initialize the NES hardware. We reset the stack pointer, turn off two interrupts and PPU rendering. Next, we wait for the PPU to warm up (that’s right - warm up). We initialize the palette next, wait for the VBL, and draw.

That’s enough to get started. Happy coding!

фигня, программирование

Previous post Next post
Up