Compare commits
2 Commits
master
...
3599e3dbf1
Author | SHA1 | Date | |
---|---|---|---|
|
3599e3dbf1 | ||
|
b35032f28d |
@ -4,7 +4,12 @@ This repo is a playground for messing around with SNES assembly.
|
||||
|
||||
It uses the [wla-dx](https://github.com/vhelin/wla-dx) assembler toolchain.
|
||||
|
||||
## Roms
|
||||
|
||||
* `simple-rom` - this is more or less following bazz's tutorial here: https://wiki.superfamicom.org/writing-your-first-snes-program
|
||||
|
||||
|
||||
# Resources
|
||||
|
||||
* https://wiki.superfamicom.org/
|
||||
* https://ersanio.gitbook.io/assembly-for-the-snes/
|
||||
|
263
common/InitSNES.asm
Normal file
263
common/InitSNES.asm
Normal file
@ -0,0 +1,263 @@
|
||||
;------------------------------------------------------------------------
|
||||
;- Written by: Neviksti
|
||||
;- If you use my code, please share your creations with me
|
||||
;- as I am always curious :)
|
||||
;------------------------------------------------------------------------
|
||||
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; InitSNES -- my "standard" initialization of SNES memory and registers
|
||||
;----------------------------------------------------------------------------
|
||||
.MACRO InitSNES
|
||||
sei ;disable interrupts
|
||||
clc ;switch to native mode
|
||||
xce
|
||||
|
||||
REP #$38 ; mem/A = 16 bit, X/Y = 16 bit
|
||||
;decimal mode off
|
||||
|
||||
LDX #$1FFF ;Setup the stack
|
||||
TXS ;Transfer Index X to Stack Pointer Register
|
||||
|
||||
;do the rest of the initialization in a routine
|
||||
JSL $008000
|
||||
|
||||
SEP #$20 ; mem/A = 8 bit
|
||||
.ENDM
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
|
||||
.BANK 0 SLOT 0
|
||||
.ORG 0
|
||||
.SECTION "InitializeSNESCode" FORCE
|
||||
|
||||
InitializeSNES:
|
||||
PHK ;set Data Bank = Program Bank
|
||||
PLB
|
||||
|
||||
LDA #$0000 ;set Direct Page = $0000
|
||||
TCD ;Transfer Accumulator to Direct Register
|
||||
|
||||
LDX $1FFD ;we clear all the mem at one point ...
|
||||
STX $4372 ;so save the return address in a place that won't get overwritten
|
||||
LDX $1FFF
|
||||
STX $4374
|
||||
|
||||
SEP #$20 ; mem/A = 8 bit
|
||||
REP #$10
|
||||
|
||||
LDA #$8F
|
||||
STA $2100 ;turn screen off for now, set brightness to normal
|
||||
|
||||
LDX #$2101
|
||||
_Loop00: ;regs $2101-$210C
|
||||
STZ $00,X ;set Sprite,Character,Tile sizes to lowest, and set addresses to $0000
|
||||
INX
|
||||
CPX #$210D
|
||||
BNE _Loop00
|
||||
|
||||
_Loop01: ;regs $210D-$2114
|
||||
STZ $00,X ;Set all BG scroll values to $0000
|
||||
STZ $00,X
|
||||
INX
|
||||
CPX #$2115
|
||||
BNE _Loop01
|
||||
|
||||
LDA #$80 ;reg $2115
|
||||
STA $2115 ; Initialize VRAM transfer mode to word-access, increment by 1
|
||||
|
||||
STZ $2116 ;regs $2117-$2117
|
||||
STZ $2117 ;VRAM address = $0000
|
||||
|
||||
;reg $2118-$2119
|
||||
;VRAM write register... don't need to initialize
|
||||
|
||||
STZ $211A ;clear Mode7 setting
|
||||
|
||||
LDX #$211B
|
||||
_Loop02: ;regs $211B-$2120
|
||||
STZ $00,X ;clear out the Mode7 matrix values
|
||||
STZ $00,X
|
||||
INX
|
||||
CPX #$2121
|
||||
BNE _Loop02
|
||||
|
||||
;reg $2121 - Color address, doesn't need initilaizing
|
||||
;reg $2122 - Color data, is initialized later
|
||||
|
||||
LDX #$2123
|
||||
_Loop03: ;regs $2123-$2133
|
||||
STZ $00,X ;turn off windows, main screens, sub screens, color addition,
|
||||
INX ;fixed color = $00, no super-impose (external synchronization),
|
||||
CPX #$2134 ;no interlaced mode, normal resolution
|
||||
BNE _Loop03
|
||||
|
||||
;regs $2134-$2136 - multiplication result, no initialization needed
|
||||
;reg $2137 - software H/V latch, no initialization needed
|
||||
;reg $2138 - Sprite data read, no initialization needed
|
||||
;regs $2139-$213A - VRAM data read, no initialization needed
|
||||
;reg $213B - Color RAM data read, no initialization needed
|
||||
;regs $213C-$213D - H/V latched data read, no initialization needed
|
||||
|
||||
STZ $213E ;reg $213E - might not be necesary, but selects PPU master/slave mode
|
||||
;reg $213F - PPU status flag, no initialization needed
|
||||
|
||||
;reg $2140-$2143 - APU communication regs, no initialization required
|
||||
|
||||
;reg $2180 - read/write WRAM register, no initialization required
|
||||
;reg $2181-$2183 - WRAM address, no initialization required
|
||||
|
||||
;reg $4016-$4017 - serial JoyPad read registers, no need to initialize
|
||||
|
||||
|
||||
STZ $4200 ;reg $4200 - disable timers, NMI,and auto-joyread
|
||||
|
||||
LDA #$FF
|
||||
STA $4201 ;reg $4201 - programmable I/O write port, initalize to allow reading at in-port
|
||||
|
||||
;regs $4202-$4203 - multiplication registers, no initialization required
|
||||
;regs $4204-$4206 - division registers, no initialization required
|
||||
|
||||
;regs $4207-$4208 - Horizontal-IRQ timer setting, since we disabled this, it is OK to not init
|
||||
;regs $4209-$420A - Vertical-IRQ timer setting, since we disabled this, it is OK to not init
|
||||
|
||||
STZ $420B ;reg $420B - turn off all general DMA channels
|
||||
STZ $420C ;reg $420C - turn off all H-MA channels
|
||||
|
||||
STZ $420D ;reg $420D - ROM access time to slow (2.68Mhz)
|
||||
|
||||
LDA $4210 ;reg $4210 - NMI status, reading resets
|
||||
|
||||
;reg $4211 - IRQ status, no need to initialize
|
||||
;reg $4212 - H/V blank and JoyRead status, no need to initialize
|
||||
;reg $4213 - programmable I/O inport, no need to initialize
|
||||
|
||||
;reg $4214-$4215 - divide results, no need to initialize
|
||||
;reg $4216-$4217 - multiplication or remainder results, no need to initialize
|
||||
|
||||
;regs $4218-$421f - JoyPad read registers, no need to initialize
|
||||
|
||||
;regs $4300-$437F
|
||||
;no need to intialize because DMA was disabled above
|
||||
;also, we're not sure what all of the registers do, so it is better to leave them at
|
||||
;their reset state value
|
||||
|
||||
JSR ClearVRAM ;Reset VRAM
|
||||
JSR ClearPalette ;Reset colors
|
||||
|
||||
;**** clear Sprite tables ********
|
||||
|
||||
STZ $2102 ;sprites initialized to be off the screen, palette 0, character 0
|
||||
STZ $2103
|
||||
LDX #$0080
|
||||
LDA #$F0
|
||||
_Loop08:
|
||||
STA $2104 ;set X = 240
|
||||
STA $2104 ;set Y = 240
|
||||
STZ $2104 ;set character = $00
|
||||
STZ $2104 ;set priority=0, no flips
|
||||
DEX
|
||||
BNE _Loop08
|
||||
|
||||
LDX #$0020
|
||||
_Loop09:
|
||||
STZ $2104 ;set size bit=0, x MSB = 0
|
||||
DEX
|
||||
BNE _Loop09
|
||||
|
||||
;**** clear WRAM ********
|
||||
|
||||
STZ $2181 ;set WRAM address to $000000
|
||||
STZ $2182
|
||||
STZ $2183
|
||||
|
||||
LDX #$8008
|
||||
STX $4300 ;Set DMA mode to fixed source, BYTE to $2180
|
||||
LDX #wram_fill_byte
|
||||
STX $4302 ;Set source offset
|
||||
LDA #:wram_fill_byte
|
||||
STA $4304 ;Set source bank
|
||||
LDX #$0000
|
||||
STX $4305 ;Set transfer size to 64k bytes
|
||||
LDA #$01
|
||||
STA $420B ;Initiate transfer
|
||||
|
||||
LDA #$01 ;now set the next 64k bytes
|
||||
STA $420B ;Initiate transfer
|
||||
|
||||
PHK ;make sure Data Bank = Program Bank
|
||||
PLB
|
||||
|
||||
CLI ;enable interrupts again
|
||||
|
||||
LDX $4372 ;get our return address...
|
||||
STX $1FFD
|
||||
LDA $4374
|
||||
STA $1FFF
|
||||
RTL
|
||||
|
||||
wram_fill_byte:
|
||||
.db $00
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; ClearVRAM -- Sets every byte of VRAM to zero
|
||||
; In: None
|
||||
; Out: None
|
||||
; Modifies: flags
|
||||
;----------------------------------------------------------------------------
|
||||
ClearVRAM:
|
||||
pha
|
||||
phx
|
||||
php
|
||||
|
||||
REP #$30 ; mem/A = 8 bit, X/Y = 16 bit
|
||||
SEP #$20
|
||||
|
||||
LDA #$80
|
||||
STA $2115 ;Set VRAM port to word access
|
||||
LDX #$1809
|
||||
STX $4300 ;Set DMA mode to fixed source, WORD to $2118/9
|
||||
LDX #$0000
|
||||
STX $2116 ;Set VRAM port address to $0000
|
||||
STX $0000 ;Set $00:0000 to $0000 (assumes scratchpad ram)
|
||||
STX $4302 ;Set source address to $xx:0000
|
||||
LDA #$00
|
||||
STA $4304 ;Set source bank to $00
|
||||
LDX #$FFFF
|
||||
STX $4305 ;Set transfer size to 64k-1 bytes
|
||||
LDA #$01
|
||||
STA $420B ;Initiate transfer
|
||||
|
||||
STZ $2119 ;clear the last byte of the VRAM
|
||||
|
||||
plp
|
||||
plx
|
||||
pla
|
||||
RTS
|
||||
|
||||
;----------------------------------------------------------------------------
|
||||
; ClearPalette -- Reset all palette colors to zero
|
||||
; In: None
|
||||
; Out: None
|
||||
; Modifies: flags
|
||||
;----------------------------------------------------------------------------
|
||||
ClearPalette:
|
||||
PHX
|
||||
PHP
|
||||
REP #$30 ; mem/A = 8 bit, X/Y = 16 bit
|
||||
SEP #$20
|
||||
|
||||
STZ $2121
|
||||
LDX #$0100
|
||||
ClearPaletteLoop:
|
||||
STZ $2122
|
||||
STZ $2122
|
||||
DEX
|
||||
BNE ClearPaletteLoop
|
||||
|
||||
PLP
|
||||
PLX
|
||||
RTS
|
||||
|
||||
.ENDS
|
||||
|
6
justfile
6
justfile
@ -1,6 +1,12 @@
|
||||
default:
|
||||
just --list
|
||||
|
||||
simple_rom:
|
||||
#!/usr/bin/env bash
|
||||
cd simple-rom
|
||||
wla-65816 -o simple_rom.obj simple_rom.asm
|
||||
wlalink simple_rom.link simple_rom.smc
|
||||
|
||||
greenspace_smc:
|
||||
just legacy/greenspace/greenspace_smc
|
||||
|
||||
|
61
simple-rom/header.inc
Normal file
61
simple-rom/header.inc
Normal file
@ -0,0 +1,61 @@
|
||||
;------------------------------ Header File ---------------------------------
|
||||
; This is basically a combo of MarctheMER's and Neviksti's header files
|
||||
; Perhaps reading their's will also help your understanding of the header,
|
||||
; but I believe this will be the simplest method of defining your header,
|
||||
; as Marc's doesn't provide a full explanation, and Neviksti's can be
|
||||
; a bit more difficult for beginners (using the WLA directives is easier).
|
||||
;----------------------------------------------------------------------------
|
||||
|
||||
;==LoRom== ; We'll get to HiRom some other time.
|
||||
.MEMORYMAP ; Begin describing the system architecture.
|
||||
SLOTSIZE $8000 ; The slot is $8000 bytes in size.
|
||||
DEFAULTSLOT 0 ; There's only 1 slot in SNES
|
||||
SLOT 0 $8000 ; Define's Slot 0's starting address.
|
||||
.ENDME ; End MemoryMap definition
|
||||
|
||||
.ROMBANKSIZE $8000 ; Every ROM bank is 32 KBytes in size
|
||||
.ROMBANKS 8 ; 2 Mbits - Tell WLA we want to use 8 ROM Banks
|
||||
|
||||
.SNESHEADER
|
||||
ID "SNES" ; 1-4 letter string, just leave it as "SNES"
|
||||
|
||||
NAME "Test SNES ROM desu " ; Program Title - can't be over 21 bytes,
|
||||
; "123456789012345678901" ; use spaces for unused bytes of the name.
|
||||
|
||||
SLOWROM
|
||||
LOROM
|
||||
|
||||
CARTRIDGETYPE $00 ; $00 = ROM only, see WLA documentation for others
|
||||
ROMSIZE $08 ; $08 = 2 Mbits, see WLA doc for more..
|
||||
SRAMSIZE $00 ; No SRAM see WLA doc for more..
|
||||
COUNTRY $01 ; $01 = U.S. $00 = Japan, that's all I know
|
||||
LICENSEECODE $00 ; Just use $00
|
||||
VERSION $00 ; $00 = 1.00, $01 = 1.01, etc.
|
||||
.ENDSNES
|
||||
|
||||
.SNESNATIVEVECTOR ; Define Native Mode interrupt vector table
|
||||
COP EmptyHandler
|
||||
BRK EmptyHandler
|
||||
ABORT EmptyHandler
|
||||
NMI EmptyHandler
|
||||
IRQ EmptyHandler
|
||||
.ENDNATIVEVECTOR
|
||||
|
||||
.SNESEMUVECTOR ; Define Emulation Mode interrupt vector table
|
||||
COP EmptyHandler
|
||||
ABORT EmptyHandler
|
||||
NMI EmptyHandler
|
||||
RESET Start
|
||||
IRQBRK EmptyHandler
|
||||
.ENDEMUVECTOR
|
||||
|
||||
.BANK 0 SLOT 0 ; Defines the ROM bank and the slot it is inserted in memory.
|
||||
.ORG 0 ; .ORG 0 is really $8000, because the slot starts at $8000
|
||||
.SECTION "EmptyVectors" SEMIFREE
|
||||
|
||||
EmptyHandler:
|
||||
rti
|
||||
.ENDS
|
||||
|
||||
.EMPTYFILL $00
|
||||
;---------------------------------- END -------------------------------------
|
28
simple-rom/simple_rom.asm
Normal file
28
simple-rom/simple_rom.asm
Normal file
@ -0,0 +1,28 @@
|
||||
;== Include memorymap, header info, and SNES initialization routines
|
||||
.INCLUDE "header.inc"
|
||||
.INCLUDE "../common/InitSNES.asm"
|
||||
|
||||
;========================
|
||||
; Start
|
||||
;========================
|
||||
|
||||
.BANK 0 SLOT 0
|
||||
.ORG 0
|
||||
.SECTION "MainCode"
|
||||
|
||||
Start:
|
||||
InitSNES ; invoke SNES init
|
||||
|
||||
stz $2121 ; set $2121 to zero, this sets palette color 0
|
||||
lda #%00010011 ; binary is more visual, but if you
|
||||
sta $2122 ; Colors are 2 bytes. Write first byte from A
|
||||
stz $2122 ; second byte is 0
|
||||
|
||||
lda #$0F ; = 00001111
|
||||
sta $2100 ; Turn on screen, full brightness
|
||||
|
||||
|
||||
forever:
|
||||
jmp forever
|
||||
|
||||
.ENDS
|
2
simple-rom/simple_rom.link
Normal file
2
simple-rom/simple_rom.link
Normal file
@ -0,0 +1,2 @@
|
||||
[objects]
|
||||
simple_rom.obj
|
Loading…
Reference in New Issue
Block a user