Skip to content

Instantly share code, notes, and snippets.

@hikari-no-yume
Last active November 19, 2016 21:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hikari-no-yume/fe099f8ac3effb1f426f555bc3b971e1 to your computer and use it in GitHub Desktop.
Save hikari-no-yume/fe099f8ac3effb1f426f555bc3b971e1 to your computer and use it in GitHub Desktop.
Minimal Famicom assembly example using cc65 which (in PAL mode only, apparently?) flips the screen colour every 256 frames
PPUMASK = $2001
PPUSTATUS = $2002
; The iNES header which makes this into an actual “rom”
.segment "INESHDR"
.byt "NES", $1A ; magic number!
.byt 1 ; program ROM size in multiples of 16384
.byt 1 ; character ROM size in multiples of 8192
.byt 0, 0 ; flags including mapper (which in this case is 0 for NROM)
.byt 2 ; program ROM size in multiples of 8192
.byt 1 ; PAL flag
; Interrupt addresses
.segment "VECTORS"
.addr nmi, reset, irq
; Self-explanatory :p
.segment "CODE"
.proc reset
; Init code time! I'll admit this is very much “cargo cult”.
; Following some of http://wiki.nesdev.com/w/index.php/Init_code
sei ; ignore IRQs (why?)
cld ; disable decimal mode (which is redundant actually)
ldx #$40
stx $4017 ; disable APU frame IRQ (…so we don't get interrupted?)
ldx #$ff
txs ; set up stack
stx $2000 ; disable NMI
stx $2001 ; disable rendering
stx $4010 ; disable DMC IRQs
; We want to use the PPU, so we can draw stuff! Let's wait for it.
; http://wiki.nesdev.com/w/index.php/PPU_power_up_state#Best_practice
bit PPUSTATUS ; clears the VBL flag if it was set at reset time
vwait1:
bit PPUSTATUS
bpl vwait1 ; at this point, about 27384 cycles have passed
vwait2:
bit PPUSTATUS
bpl vwait2 ; at this point, about 57165 cycles have passed
; video works now! let's do an effect or something
lda #$00 ; initial value of toggle
sta $0100
lda #%11111000 ; set PPU state to something less silly
sta PPUMASK
forever:
jmp forever
.endproc
.proc nmi
lda $0100
tay
bne skip
lda PPUMASK ; flip emphasise RGB bits
eor #%1110000
sta PPUMASK
skip:
iny
sty $0100
rti
.endproc
.proc irq
rti
.endproc
game.nes: game.o
ld65 -C nrom128.x game.o -o game.nes
game.o: game.s
ca65 game.s -o game.o
clean:
rm *.o *.nes
# Taken from http://bin.smwcentral.net/u/1780/ex.zip
MEMORY {
ZP: start = $10, size = $f0, type = rw;
# use first $10 zeropage locations as locals
HEADER: start = $7f00, size = $0010, type = ro, file = %O, fill = yes, fillval = $00;
RAM: start = $0300, size = $0500, type = rw;
PRG0: start = $C000, size = $4000, type = ro, file = %O, fill = yes, fillval = $FF;
CHR0: start = $0000, size = $2000;
}
SEGMENTS {
INESHDR: load = HEADER, type = ro, align = $10;
ZEROPAGE: load = ZP, type = zp;
BSS: load = RAM, type = bss, define = yes, align = $100;
CODE: load = PRG0, type = ro, align = $100;
RODATA: load = PRG0, type = ro, align = $100;
DMC: load = PRG0, type = ro, align = $40, optional = yes;
VECTORS: load = PRG0, type = ro, start = $FFFA;
CHR: load = CHR0, type = ro;
}
FILES {
%O: format = bin;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment