├── do.sh ├── .gitignore ├── asm ├── remap │ ├── sram.asm │ ├── sprite_memory.asm │ ├── dma.asm │ ├── map16.asm │ └── dp.asm ├── engine │ ├── mmc.asm │ ├── snes_init.asm │ ├── snes_irq_zsnes.asm │ ├── snes_irq.asm │ └── snes_nmi.asm ├── boost │ ├── map16.asm │ ├── circle.asm │ ├── level_loading.asm │ ├── maxtile │ │ ├── get_slot.asm │ │ └── finish_write.asm │ ├── lz2.asm │ ├── level_mode.asm │ ├── lzx.asm │ ├── lz3.asm │ ├── overworld.asm │ ├── sprite_load.asm │ ├── sprites.asm │ └── oam.asm ├── 8mb.asm ├── 6mb.asm ├── more_sprites │ ├── sprite_tables.asm │ ├── NoMoreSpriteTileLimits.asm │ └── inc_max_sprites.asm └── sa1.asm ├── package.sh ├── docs ├── notable-changes.md ├── known-issues.md ├── W-RAM.md ├── Sprite-Remap.md ├── I-RAM.md ├── remap.asm ├── BW-RAM.md └── memory-map-summary.md ├── quick guide.txt ├── style.css ├── changes.txt └── README.md /do.sh: -------------------------------------------------------------------------------- 1 | rm smw.smc; cp smw_base.smc smw.smc && asar asm/sa1.asm smw.smc 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.smc 2 | *.sfc 3 | *.srm 4 | *.bsz 5 | *.bst 6 | *.zs* 7 | other/* 8 | target/* 9 | *.html 10 | *.sym 11 | -------------------------------------------------------------------------------- /asm/remap/sram.asm: -------------------------------------------------------------------------------- 1 | @includefrom sa1.asm 2 | ; Remap SRAM to $41:C000-$41:C7FF. 3 | 4 | if read1($009B58+3) == $70 5 | 6 | ORG $009B58 7 | STA $41C000,x 8 | STA $41C1AD,x 9 | ORG $009BE1 10 | STA $41C000,x 11 | ORG $009BFD 12 | STA $41C000,x 13 | ORG $009CFF 14 | LDA $41C000,x 15 | ORG $009D05 16 | STA $41C000,x 17 | ORG $009D14 18 | LDA $41C000,x 19 | ORG $009D66 20 | LDA $41C08C,x 21 | ORG $009DC6 22 | LDA $41C08D,x 23 | ORG $009DD1 24 | LDA $41C000,x 25 | 26 | endif -------------------------------------------------------------------------------- /package.sh: -------------------------------------------------------------------------------- 1 | rm -rf ./target 2 | mkdir target 3 | cp -r ./asm/. ./target 4 | cp -r ./docs ./target/docs 5 | cp ./README.md ./target/ 6 | cp ./changes.txt ./target/ 7 | cp ./style.css ./target/docs 8 | cp "./quick guide.txt" ./target/ 9 | 10 | markhtml () { 11 | github-markdown "$1" "-t \$BASENAME" -s "$2style.css" > "${1%.*}.html" 12 | rm "$1" 13 | } 14 | 15 | folderhtml () { 16 | for i in *.md; do 17 | [ -f "$i" ] || break 18 | markhtml $i $1 19 | done 20 | 21 | sed -i -- 's/.md/.html/g' *.html 22 | } 23 | 24 | cd ./target 25 | folderhtml "docs/" 26 | cd ./docs 27 | folderhtml "" 28 | -------------------------------------------------------------------------------- /asm/engine/mmc.asm: -------------------------------------------------------------------------------- 1 | ;===============================================; 2 | ; Super MMC Routines ; 3 | ;===============================================; 4 | 5 | mmc_rom_reset: 6 | BIT $318E ; Set overflow if the ROM is swapped. 7 | .direct: 8 | LDX #$03 ; For each Super MMC register 9 | ; 10 | - LDA.l bank_switch,x ; \ Load bank switch value and set 11 | BVC + ; | the correct value to the 12 | EOR #$04 ; | bank switch register. 13 | + STA $2220,x ; / 14 | ; 15 | DEX ; \ Loop though each register. 16 | BPL - ; / 17 | ; 18 | RTL ; Return 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /asm/boost/map16.asm: -------------------------------------------------------------------------------- 1 | @includefrom sa1.asm 2 | 3 | pushpc 4 | ORG $0586DD 5 | BEQ + 6 | ORG $0586E9 7 | + 8 | 9 | ORG $0586DF 10 | JML KeepLoading 11 | 12 | ORG $0585FF 13 | JSL CallSA1 14 | RTS 15 | pullpc 16 | 17 | CallSA1: 18 | SEP #$20 19 | LDA.B #SA1Code 20 | STA $3180 21 | LDA.B #SA1Code>>8 22 | STA $3181 23 | LDA.B #SA1Code>>16 24 | STA $3182 25 | JSR $1E80 26 | RTL 27 | 28 | KeepLoading: 29 | SEP #$30 30 | LDY #$00 31 | LDA [$65],Y 32 | JML $058605 33 | 34 | SA1Code: 35 | PHB 36 | LDY #$00 37 | PHY 38 | PLB 39 | LDA [$65],Y 40 | 41 | PHK 42 | PEA.w .Return-1 43 | PEA.w $058125-1 44 | JML $058605 45 | .Return PLB 46 | RTL 47 | -------------------------------------------------------------------------------- /asm/8mb.asm: -------------------------------------------------------------------------------- 1 | sa1rom 2 | 3 | org $8A60 ; Change bank switch 4 | db $04,$05,$06,$07 5 | 6 | 7 | norom ; pc address mode 8 | 9 | org $7FFFFF 10 | db $00 ; expand ROM to 8MB 11 | 12 | org $407FB8 13 | db "S","T","A","R" 14 | dw $003F 15 | dw $FFC0 16 | 17 | org $407FC0 ; copy header 18 | dd read4($7FC0) 19 | dd read4($7FC4) 20 | dd read4($7FC8) 21 | dd read4($7FCC) 22 | dd read4($7FD0) 23 | dd read4($7FD4) 24 | dd read4($7FD8) 25 | dd read4($7FDC) 26 | dd read4($7FE0) 27 | dd read4($7FE4) 28 | dd read4($7FE8) 29 | dd read4($7FEC) 30 | dd read4($7FF0) 31 | dd read4($7FF4) 32 | dd read4($7FF8) 33 | dd read4($7FFC) 34 | 35 | org $7FD7 36 | db $0D ; 33Mbit~64Mbit 37 | org $407FD7 38 | db $0D ; 33MBit~64Mbit 39 | 40 | -------------------------------------------------------------------------------- /docs/notable-changes.md: -------------------------------------------------------------------------------- 1 | # Notable Changes 2 | 3 | The SA-1 Pack heavily modifies the SMW engine to use and explore the SA-1 system features. 4 | When patched, there is many notable changes in the game, mostly related to performance and loading times. 5 | 6 | ## Eliminated slowdown spots 7 | * Yoshi's Island 2 8 | * Yoshi's Island 4 9 | * Donut Plains 4 10 | * Forest of the Illusion 2 11 | * Sunken Ghost Ship 12 | * Bowser's Castle -- Front/Back Door 13 | * more? 14 | 15 | ## Faster loading 16 | * Levels will load faster than the normal. 17 | * Nintendo Presents screen runs much faster because of the Mario and other animations being compressed much faster. 18 | 19 | ## Graphical enhancements 20 | * Windowing effects won't slowdown. 21 | * Circle-in effect on title screen runs much more smoother. 22 | * Circle-out effect after beating a level runs much more smoother. 23 | * The spotlight sprite will run at full speed (60 FPS) instead of quarter speed (15 FPS). 24 | -------------------------------------------------------------------------------- /asm/remap/sprite_memory.asm: -------------------------------------------------------------------------------- 1 | 2 | macro remap_memory() 3 | !ptr #= $070000|read2(!count*2+$05EC00) 4 | 5 | !spr_bit #= read1(!ptr) 6 | !spr_mask = !spr_bit&$E0 7 | !spr_mem = !spr_bit&$1F 8 | 9 | !level_mode #= read1(read3(!count*3+$05E000)+1)&$1F 10 | 11 | ; Sprite memory $12 and $10 is used on bosses battles and cannot be changed due of hardcoded-specific code. 12 | ; Sprite memory $0A is used on wigglers and cannot be changed to avoid memory corruption. 13 | 14 | if !spr_mem != $12 && !spr_mem != $10 && !spr_mem != $0A && !level_mode != $10 && !level_mode != $0B && !level_mode != $09 && !count != 0 && !count != $0100 15 | org !ptr 16 | db !spr_mask|$08 17 | ; else 18 | ; print "Skipping level ",hex(!count)," with memory ",hex(!spr_mem) 19 | endif 20 | 21 | !count #= !count+1 22 | endmacro 23 | 24 | ; Change all sprite memory to $08 only if it's a clean ROM. 25 | if read1($0DA691+2) != $7E 26 | !count = 0 27 | rep 512 : %remap_memory() 28 | endif 29 | -------------------------------------------------------------------------------- /asm/6mb.asm: -------------------------------------------------------------------------------- 1 | !ZSNES = 1 ; choose 1 for ZSNES support (eats 128 KB) or 0 to not (eats 64 bytes) 2 | 3 | sa1rom 4 | 5 | org $8A60 ; Change bank switch 6 | db $04,$05,$06,$07 7 | 8 | 9 | norom ; pc address mode 10 | 11 | org $5FFFFF 12 | db $00 ; expand ROM to 6MB 13 | 14 | if !ZSNES == 0 15 | org $407FB8 16 | db "S","T","A","R" 17 | dw $003F 18 | dw $FFC0 19 | else 20 | org $400000 21 | fillbyte $55 : fill $010000 22 | org $410000 23 | fillbyte $55 : fill $010000 24 | 25 | org $400000 26 | db "S","T","A","R" 27 | dw $FFF7 28 | dw $0008 29 | org $410000 30 | db "S","T","A","R" 31 | dw $FFF7 32 | dw $0008 33 | org $410000 34 | endif 35 | 36 | org $407FC0 ; copy header 37 | dd read4($7FC0) 38 | dd read4($7FC4) 39 | dd read4($7FC8) 40 | dd read4($7FCC) 41 | dd read4($7FD0) 42 | dd read4($7FD4) 43 | dd read4($7FD8) 44 | dd read4($7FDC) 45 | dd read4($7FE0) 46 | dd read4($7FE4) 47 | dd read4($7FE8) 48 | dd read4($7FEC) 49 | dd read4($7FF0) 50 | dd read4($7FF4) 51 | dd read4($7FF8) 52 | dd read4($7FFC) 53 | 54 | org $7FD7 55 | db $0D ; 33Mbit~64Mbit 56 | org $407FD7 57 | db $0D ; 33MBit~64Mbit 58 | 59 | -------------------------------------------------------------------------------- /asm/boost/circle.asm: -------------------------------------------------------------------------------- 1 | @includefrom sa1.asm 2 | ; This patch optimizes the SMW's circle routine. 3 | namespace Circle 4 | pushpc 5 | 6 | org $00CA88 7 | JSL SwitchCPU 8 | RTS 9 | 10 | org $00CC14 11 | CLV ; 12 | PHY ; 13 | LDA #$01 ; 14 | STA $2250 ; 15 | LDA $01 ; 16 | BPL + ; 17 | LSR ; 18 | SEP #$40 ; 19 | + STA $2252 ; 20 | STZ $2251 ; 21 | LDA $7433 ; 22 | STA $2253 ; 23 | STZ $2254 ; 24 | NOP ; 25 | REP #$20 ; 26 | LDA $2306 ; 27 | BVS + ; 28 | LSR ; 29 | + TAY ; 30 | SEP #$20 ; 31 | STZ $2250 ; 32 | LDA $7433 ; 33 | STA $2251 ; 34 | STZ $2252 ; 35 | LDA ($06),y ; 36 | STA $2253 ; 37 | STZ $2254 ; 38 | JML Jump 39 | Back: LDA $2307 ; 40 | STA $02 ; 41 | PLY ; 42 | RTS ; 43 | warnpc $00CC5C ; 44 | 45 | pullpc 46 | 47 | Jump: 48 | NOP ; 49 | LDA $2307 ; 50 | STA $03 ; 51 | LDA ($04),y ; 52 | STA $2253 ; 53 | STZ $2254 ; 54 | NOP ; 55 | JML Back ; 56 | 57 | SwitchCPU: 58 | STA $3100 59 | TSC 60 | XBA 61 | CMP #$37 62 | BEQ SA1 63 | LDA.b #SA1 64 | STA $3180 65 | LDA.b #SA1>>8 66 | STA $3181 67 | LDA.b #SA1>>16 68 | STA $3182 69 | JSR $1E80 70 | RTL 71 | 72 | SA1: PHP 73 | PHB 74 | LDA #$00 75 | PHA 76 | PLB 77 | LDA $3100 78 | REP #$30 79 | AND #$00FF 80 | PHK 81 | PEA.w .jslrtsreturn-1 82 | PEA.w $0084CF-1 83 | JML $00CA8D 84 | .jslrtsreturn 85 | PLB 86 | PLP 87 | RTL 88 | 89 | 90 | 91 | namespace off 92 | -------------------------------------------------------------------------------- /asm/boost/level_loading.asm: -------------------------------------------------------------------------------- 1 | ; This sub-patch gives a boost on level loading at general. 2 | ; DO NOT USE THIS PATCH! 3 | @includefrom sa1.asm 4 | 5 | 6 | pushpc 7 | 8 | org $96D5 9 | JSL MarioStartGameMode 10 | RTS 11 | org $9749 12 | RTS 13 | RTS 14 | RTS 15 | org $009702 16 | INC $0100 17 | RTS 18 | 19 | pullpc 20 | 21 | MarioStartGameMode: 22 | STZ $4200 23 | LDA.B #.SA1Code 24 | STA $3180 25 | LDA.B #.SA1Code>>8 26 | STA $3181 27 | LDA.B #.SA1Code>>16 28 | STA $3182 29 | JSR $1E80 30 | LDA $3100 31 | BNE .Phrase2 32 | LDA #$81 33 | STA $4200 34 | RTL 35 | .Phrase2 36 | LDA.B #.MultiThread_SA1 37 | STA $3180 38 | LDA.B #.MultiThread_SA1>>8 39 | STA $3181 40 | LDA.B #.MultiThread_SA1>>16 41 | STA $3182 42 | LDA #$80 43 | STA $2200 44 | JSR .MultiThread_SNES 45 | JSR $1E85 46 | PHK 47 | PEA.w .jslrtsreturn4-1 48 | PEA.w $0084CF-1 49 | JML $009712 50 | .jslrtsreturn4 51 | LDA #$81 52 | STA $4200 53 | RTL 54 | 55 | .SA1Code: 56 | PHB 57 | STZ $15 58 | STZ $16 59 | STZ $17 60 | STZ $18 61 | STZ $0100 62 | LDA #$00 63 | PHA 64 | PLB 65 | PHK 66 | PEA.w .jslrtsreturn-1 67 | PEA.w $0084CF-1 68 | JML $0096DB 69 | .jslrtsreturn 70 | PLB 71 | RTL 72 | 73 | ; Warning: Watch out possible RAM collision 74 | 75 | .MultiThread_SNES: 76 | PHK 77 | PEA.w .jslrtsreturn1-1 78 | PEA.w $0084CF-1 79 | JML $008134 80 | .jslrtsreturn1 81 | RTS 82 | 83 | .MultiThread_SA1: 84 | PHB 85 | LDA #$00 86 | PHA 87 | PLB 88 | PHK 89 | PEA.w .jslrtsreturn2-1 90 | PEA.w $0084CF-1 91 | JML $00A635 92 | .jslrtsreturn2 93 | LDA #$20 94 | STA $5E 95 | PHK 96 | PEA.w .jslrtsreturn3-1 97 | PEA.w $0084CF-1 98 | JML $00A796 99 | .jslrtsreturn3 100 | INC $1404 101 | PLB 102 | RTL 103 | 104 | -------------------------------------------------------------------------------- /asm/boost/maxtile/get_slot.asm: -------------------------------------------------------------------------------- 1 | 2 | ; Allocate and get OAM pointer from MaxTile. 3 | ; Difference between get_oam_slot_general is: 4 | ; > Amount of slots is passed via "A" 5 | ; > No 16-bit AXY required. 6 | ; > Slot is also copied to $0C ($3100) and $0E ($3102). 7 | 8 | call_oam_get_slot_sprite: 9 | PHP 10 | REP #$30 11 | AND #$00FF 12 | TAY 13 | LDA #$0003 14 | JSL call_oam_get_slot_general 15 | BCS .ok 16 | PLP 17 | CLC 18 | RTL 19 | 20 | .ok 21 | LDA $3100 22 | STA $0C 23 | LDA $3102 24 | STA $0E 25 | PLP 26 | SEC 27 | RTL 28 | 29 | ; Allocate and get OAM pointer from MaxTile 30 | ; The routine automatically adjusts internal MaxTile pointers for you. 31 | ; 32 | ; Input params: 33 | ; > AXY 16-bit 34 | ; > Y = how many slots to be allocated (min: #$0001 - 1 slot, max: #$0080 - 128 slots) 35 | ; > A = priority (0: highest, 3: lowest) 36 | ; 37 | ; Output params: 38 | ; > Carry set if the OAM allocation was success, carry clear otherwise. 39 | ; > $3100-$3101 will contain the pointer to the OAM general buffer. 40 | ; > $3102-$3103 will contain the pointer to the OAM attribute buffer. 41 | ; > The pointer returned is intended to be incremented, just like normal OAM drawing routines. 42 | ; > $3100-$3103 will be used by FinishOAMWrite routine version MaxTile. 43 | 44 | call_oam_get_slot_general: 45 | STY $3102 46 | 47 | ASL #4 48 | TAY 49 | 50 | LDA $3102 51 | ASL #2 52 | STA $3100 53 | 54 | LDA !maxtile_mirror_max+0,y 55 | SEC 56 | SBC $3100 57 | 58 | CMP !maxtile_mirror_max+8,y 59 | BCC .no_slot 60 | 61 | STA !maxtile_mirror_max+0,y 62 | 63 | ;add 4 64 | ADC #$0003 65 | STA $3100 66 | 67 | LDA !maxtile_mirror_max+2,y 68 | SEC 69 | SBC $3102 70 | STA !maxtile_mirror_max+2,y 71 | INC 72 | STA $3102 73 | 74 | SEC 75 | .no_slot 76 | RTL 77 | -------------------------------------------------------------------------------- /quick guide.txt: -------------------------------------------------------------------------------- 1 | This is a quick guide to you get working fast with the SA-1 Pack. 2 | It's pretty simple really, but the readme may be a little confusing at start, so I created this file specially for 3 | who is starting to work with SA-1 Pack. 4 | 5 | Requirements: 6 | - Asar 1.50 or newer; and 7 | - Lunar Magic 2.20 or newer. 8 | 9 | Guide: 10 | 1. Grab a CLEAN UNMODIFIED ROM. If your ROM is not clean, there's a 99.99% chance that this guide will fail. 11 | 2. Place asar.exe and your ROM on same folder as you extracted SA-1 Pack. 12 | 3. Double click asar.exe 13 | 4. Type sa1.asm on "Enter patch name" and press enter. 14 | 5. Type your ROM name on "Enter ROM name" and press enter. Your ROM should be patched with SA-1. 15 | 6. Open your ROM with Lunar Magic and save any level. 16 | 17 | That's all. Your ROM should be ready to be on "SA-1 adventure"! 18 | 19 | If you want to use any external resource (tool, sprite, block, patch, etc.), please note that they need to be 20 | remapped to they work with SA-1. Fortunately, the SA-1 Pack is been on SMW Central for a considerable amount 21 | of time, so a fairly good amount of resources already works. 22 | 23 | If you still use Romi's Sprite Tool, you will need this special version of Sprite Tool to insert sprites on 24 | SA-1 Pack: https://bin.smwcentral.net/u/8251/st140.zip 25 | 26 | PIXI and GIEPY has native SA-1 Pack compatibility. 27 | 28 | Aside from the Sprite Tool, any other resource on the site will work on SA-1 Pack fine if the "sa-1" tag is 29 | present in the submission. It means the submission is either hybrid (supports both SA-1 and regular ROMs) or 30 | they require SA-1 to work. So these work for you. 31 | 32 | Most of the Sprites and Blocks however can be converted automatically with a tool called "SA-1 Convert". 33 | Please take a look in the Tools Section on SMW Central if you're interested. It can be useful if the resource 34 | you're looking for is not compatible with SA-1. 35 | round or merging the patches to SMW Central. 36 | 37 | You don't need to worry about music (.txt/.bnk/.brr) files, they will work with SA-1 normally. 38 | The only thing you have to worry is if the tool to insert them (Addmusic) is compatible. 39 | 40 | GPS has native SA-1 support since version 1.20. 41 | UberASM Tool as well. 42 | 43 | AddmusicK works natively with SA-1, so if you're using it, you don't have to worry about music. 44 | -------------------------------------------------------------------------------- /asm/boost/lz2.asm: -------------------------------------------------------------------------------- 1 | @includefrom sa1.asm 2 | ; LC_LZ2 3 | 4 | .case_e0_or_end 5 | LDA $8D 6 | CMP #$1F 7 | BEQ .end 8 | 9 | AND #$03 10 | STA $8E 11 | EOR $8D 12 | ASL 13 | ASL 14 | ASL 15 | XBA 16 | %ReadByte() 17 | STA $8D 18 | XBA 19 | BRA .type 20 | 21 | .case_80_or_else 22 | BMI .case_e0_or_end 23 | 24 | %ReadByte() 25 | XBA 26 | %ReadByte() 27 | 28 | STX.b $00+!S 29 | REP #$21 30 | ADC $00 31 | TAX 32 | LDA $8D 33 | SEP #$20 34 | 35 | BIT.b $0C+!S 36 | BMI + 37 | JMP.w $000C+!S 38 | 39 | + LDA $02 40 | CMP #$40 41 | BNE + 42 | 43 | LDA $8D 44 | MVN $40,$40 45 | BRA .back2 46 | 47 | + LDA $8D 48 | MVN $41,$41 49 | 50 | .back2 51 | LDX.b $00+!S 52 | 53 | .main 54 | %ReadByte() 55 | STA $8D 56 | STZ $8E 57 | AND #$E0 58 | TRB $8D 59 | 60 | .type 61 | ASL 62 | BCS .case_80_or_else 63 | BMI .case_40_or_60_J 64 | ASL 65 | BMI .case_20 66 | 67 | .case_00 68 | REP #$20 69 | LDA $8D 70 | STX $8D 71 | 72 | - SEP #$20 73 | BIT.b $06+!S 74 | BMI + 75 | JMP.w $0006+!S 76 | 77 | + REP #$20 78 | PEI ($02+!S) 79 | PEI ($00) 80 | STZ $00 81 | SEP #$20 82 | INC 83 | STA $02+!S 84 | XBA 85 | INC 86 | STA $03+!S 87 | PHB 88 | LDA $8C 89 | PHA 90 | PLB 91 | -- LDA $0000,x 92 | STA [$00],y 93 | INX 94 | INY 95 | DEC $02+!S 96 | BNE -- 97 | DEC $03+!S 98 | BNE -- 99 | PLB 100 | REP #$20 101 | PLA 102 | STA $00 103 | PLA 104 | STA $02+!S 105 | SEP #$20 106 | .back 107 | CPX $8D 108 | BCS .main 109 | 110 | INC $8C 111 | INC $08+!S 112 | CPX #$0000 113 | BEQ ++ 114 | 115 | DEX 116 | STX.b $00+!S 117 | REP #$21 118 | LDX $02+!S ;#$8000 or #$0000 119 | STX $8D 120 | TYA 121 | SBC.b $00+!S 122 | TAY 123 | LDA.b $00+!S 124 | BRA - 125 | 126 | ++ LDX $02+!S ;#$8000 or #$0000 127 | BRA .main 128 | .case_40_or_60_J 129 | BRA .case_40_or_60 130 | 131 | .case_20 132 | %ReadByte() 133 | STX.b $00+!S 134 | PHA 135 | PHA 136 | REP #$20 137 | 138 | .case_20_main 139 | LDA $8D 140 | INC 141 | LSR 142 | TAX 143 | PLA 144 | 145 | - STA $0000,Y 146 | INY 147 | INY 148 | DEX 149 | BNE - 150 | 151 | SEP #$20 152 | BCC + 153 | STA $0000,Y 154 | INY 155 | + LDX.b $00+!S 156 | JMP .main 157 | 158 | .case_40_or_60 159 | ASL 160 | BMI .case_60 161 | %ReadByte() 162 | XBA 163 | %ReadByte() 164 | 165 | XBA 166 | STX.b $00+!S 167 | REP #$20 168 | PHA 169 | ;Replace BRA .case_20_main the code itself 170 | LDA $8D 171 | INC 172 | LSR 173 | TAX 174 | PLA 175 | - STA $0000,Y 176 | INY 177 | INY 178 | DEX 179 | BNE - 180 | SEP #$20 181 | BCC + 182 | STA $0000,Y 183 | INY 184 | + LDX.b $00+!S 185 | JMP .main 186 | 187 | .case_60 188 | %ReadByte() 189 | STX.b $00+!S 190 | LDX $8D 191 | - STA $0000,Y 192 | INC 193 | INY 194 | DEX 195 | BPL - 196 | LDX.b $00+!S 197 | JMP .main -------------------------------------------------------------------------------- /asm/boost/level_mode.asm: -------------------------------------------------------------------------------- 1 | @includefrom sa1.asm 2 | namespace level_mode 3 | pushpc 4 | org $00A2E6 5 | JSL optimize 6 | 7 | org $05CBFF 8 | JML score_stuff 9 | 10 | org $00E2BD 11 | JML optimize_00E2BD 12 | 13 | org $00C47E 14 | JSL optimize_00C47E 15 | RTS 16 | 17 | org $00C593 18 | JSL mario_animation 19 | RTS 20 | 21 | org $00C0FB 22 | JSL stripe_help 23 | pullpc 24 | 25 | stripe_help: 26 | LDA $5B 27 | STA $00 28 | TSC 29 | AND #$FF00 30 | CMP #$3700 31 | BEQ .sa1 32 | RTL 33 | .sa1 34 | SEP #$20 35 | LDA.b #.snes 36 | STA $0183 37 | LDA.b #.snes>>8 38 | STA $0184 39 | LDA.b #.snes>>16 40 | STA $0185 41 | LDA #$D0 42 | STA $2209 43 | STX $3100 44 | STY $3102 45 | - LDA $018A 46 | BEQ - 47 | STZ $018A 48 | LDX $3100 49 | LDY $3102 50 | PLA 51 | PLA 52 | PLA 53 | REP #$20 54 | JML $00C1AB 55 | .snes 56 | LDA #$00 57 | PHA 58 | PLB 59 | REP #$30 60 | LDX $3100 61 | LDY $3102 62 | PHK 63 | PEA.w .jslrtsreturn-1 64 | PEA.w $0084CF-1 65 | JML $00C0FF 66 | .jslrtsreturn 67 | STX $3100 68 | STY $3102 69 | SEP #$30 70 | RTL 71 | 72 | ; make sure all stuff from there are executed. 73 | mario_animation: 74 | TSC 75 | XBA 76 | CMP #$37 77 | BNE .call 78 | LDA #$00 79 | .go PEA.w $84CF-1 80 | PHA 81 | PEA.w $C595+4-1 82 | LDA $71 83 | JML $0086DF 84 | 85 | .call LDA.b #.sa1 86 | STA $3180 87 | LDA.b #.sa1>>8 88 | STA $3181 89 | LDA.b #.sa1>>16 90 | STA $3182 91 | JSR $1E80 92 | RTL 93 | 94 | .sa1 LDA #$00 95 | PHA 96 | PLB 97 | BRA .go 98 | 99 | optimize_00E2BD: 100 | PHB 101 | LDA #$00 102 | PHA 103 | PLB 104 | TSC 105 | XBA 106 | CMP #$37 107 | BEQ .skip 108 | LDA.b #.sa1 109 | STA $3180 110 | LDA.b #.sa1>>8 111 | STA $3181 112 | LDA.b #.sa1>>16 113 | STA $3182 114 | JSR $1E80 115 | PLB 116 | RTL 117 | .sa1 118 | PHB 119 | LDA #$00 120 | PHA 121 | PLB 122 | .skip 123 | LDA $78 124 | JML $00E2C2 125 | 126 | optimize_00C47E: 127 | LDA.b #.sa1 128 | STA $3180 129 | LDA.b #.sa1>>8 130 | STA $3181 131 | LDA.b #.sa1>>16 132 | STA $3182 133 | JSR $1E80 134 | RTL 135 | .sa1 136 | LDA #$00 137 | PHA 138 | PLB 139 | STZ $78 140 | LDA $73CB 141 | PEA.w $0084CF-1 142 | JML $00C483 143 | 144 | score_stuff: 145 | PHB 146 | LDA #$05 147 | PHA 148 | PLB 149 | 150 | TSC 151 | XBA 152 | CMP #$37 153 | BEQ .sa1 154 | .snes 155 | PHK 156 | PEA.w .jslrtsreturn-1 157 | PEA.w $058125-1 158 | JML $05CC07 159 | .jslrtsreturn 160 | PLB 161 | RTL 162 | .sa1 163 | LDA.b #.sa1_snes 164 | STA $0183 165 | LDA.b #.sa1_snes>>8 166 | STA $0184 167 | LDA.b #.sa1_snes>>16 168 | STA $0185 169 | LDA #$D0 170 | STA $2209 171 | - LDA $018A 172 | BEQ - 173 | STZ $018A 174 | PLB 175 | RTL 176 | .sa1_snes 177 | PHB 178 | LDA #$05 179 | PHA 180 | PLB 181 | BRA .snes 182 | 183 | optimize: 184 | LDA #$B1 185 | STA $3180 186 | LDA #$8A 187 | STA $3181 188 | LDA #$02 189 | STA $3182 190 | JSR $1E80 191 | RTL 192 | 193 | namespace off -------------------------------------------------------------------------------- /asm/boost/maxtile/finish_write.asm: -------------------------------------------------------------------------------- 1 | !a1 = $00 2 | !a2 = $01 3 | !a3 = $02 4 | !a4 = $03 5 | !a5 = $04 6 | !a6 = $05 7 | !a7 = $06 8 | !a8 = $07 9 | !a9 = $08 10 | !a10 = $09 11 | !a11 = $0A 12 | !a12 = $0B 13 | 14 | !a15 = $0E 15 | 16 | !RAM_SpriteYHi = $3258 17 | !RAM_SpriteXHi = $326E 18 | !RAM_ScreenBndryXLo = $1A 19 | !RAM_ScreenBndryYLo = $1C 20 | !RAM_SpriteYLo = $3216 21 | !RAM_SpriteXLo = $322C 22 | !RAM_SprProcessIndex = $75E9 23 | 24 | call_finish_oam_write: 25 | 26 | ; Finish OAM Write that uses MaxTile API 27 | ; Requires pointers to be at $3100 and $3102. 28 | 29 | FinishOAMWrite: 30 | PHB 31 | PHK 32 | PLB 33 | JSR FinishOAMWriteRt 34 | PLB 35 | RTL 36 | 37 | FinishOAMWriteRt: 38 | STY !a12 39 | STA !a9 40 | LDA !RAM_SpriteYLo,X 41 | STA !a1 42 | SEC 43 | SBC !RAM_ScreenBndryYLo 44 | STA !a7 45 | LDA !RAM_SpriteYHi,X 46 | STA !a2 47 | LDA !RAM_SpriteXLo,X 48 | STA !a3 49 | SEC 50 | SBC !RAM_ScreenBndryXLo 51 | STA !a8 52 | LDA !RAM_SpriteXHi,X 53 | STA !a4 54 | 55 | REP #$10 56 | LDY $3102 57 | STY !a15 58 | LDY $3100 59 | 60 | LDA #$40 61 | PHA 62 | PLB 63 | 64 | CODE_01B7DE: 65 | ; Slot given by MaxTile 66 | LDX !a15 67 | LDA !a12 68 | BPL CODE_01B7F0 69 | LDA $0000,x 70 | AND #$02 71 | STA $0000,x 72 | BRA CODE_01B7F3 73 | 74 | CODE_01B7F0: 75 | STA $0000,x 76 | 77 | CODE_01B7F3: 78 | LDX #$0000 79 | LDA $0000,y 80 | SEC 81 | SBC !a8 82 | BPL CODE_01B7FE 83 | DEX 84 | CODE_01B7FE: 85 | CLC 86 | ADC !a3 87 | STA !a5 88 | TXA 89 | ADC !a4 90 | STA !a6 91 | JSR CODE_01B844 92 | BCC CODE_01B819 93 | LDX !a15 94 | LDA $0000,x 95 | ORA #$01 96 | STA $0000,x 97 | CODE_01B819: 98 | LDX #$0000 99 | LDA $0001,y 100 | SEC 101 | SBC !a7 102 | BPL CODE_01B824 103 | DEX 104 | CODE_01B824: 105 | CLC 106 | ADC !a1 107 | STA !a10 108 | TXA 109 | ADC !a2 110 | STA !a11 111 | JSR CODE_01C9BF 112 | BCC CODE_01B838 113 | LDA #$F0 114 | STA $0001,y 115 | CODE_01B838: 116 | INY 117 | INY 118 | INY 119 | INY 120 | ; It's safe to increment in 8-bit. 121 | INC !a15 122 | DEC !a9 123 | BPL CODE_01B7DE 124 | 125 | SEP #$10 126 | PHK 127 | PLB 128 | 129 | LDX !RAM_SprProcessIndex 130 | RTS 131 | 132 | CODE_01B844: 133 | REP #$20 134 | LDA !a5 135 | SEC 136 | SBC !RAM_ScreenBndryXLo 137 | CMP #$0100 138 | SEP #$20 139 | RTS 140 | 141 | CODE_01C9BF: 142 | REP #$20 143 | LDA !a10 144 | PHA 145 | CLC 146 | ADC #$0010 147 | STA !a10 148 | SEC 149 | SBC !RAM_ScreenBndryYLo 150 | CMP #$0100 151 | PLA 152 | STA !a10 153 | SEP #$20 154 | Return01C9D5: 155 | RTS 156 | -------------------------------------------------------------------------------- /docs/known-issues.md: -------------------------------------------------------------------------------- 1 | # Known Issues 2 | 3 | Developed since 2012, one of the biggest SA-1 Pack challenges is to deal with potential emulation issues, because of the chip complexity and the so little known, accurate information about the SA-1 system. 4 | 5 | Along that, there is always some issues that is from the SA-1 Pack itself and needs to be corrected. This document will attempt to list some potential issues the patch will present on emulators as well on real consoles. 6 | 7 | For consistency, only issues from latest version of each emulator will be listed, with rare exceptions. 8 | 9 | (!): Issues caused by an incorrect behavior of the SA-1 Pack, not from emulator/console. 10 | 11 | ## sd2snes 12 | * (!) The console has some slight PPU scanline glitch below status bar during mode 7 bosses. 13 | * The SA-1 CPU has some speed inconsistencies. The CPU runs slight slower (~9.63 MHz) during ROM access and runs faster than normal on I-RAM access (~13.76 MHz). 14 | 15 | ## Real SA-1 cart 16 | * (!) The console has some slight PPU scanline glitch below status bar during mode 7 bosses. 17 | 18 | ## bsnes 19 | bsnes refers to the SNES emulation part of higan. 20 | * On the older versions of bsnes (0.7x, probably 0.8x as well), variable length bit processing does not get affected by the Super MMC registers, making impossible to access the last 4 MB of the ROM though the SA-1 ROM bit stream feature. Although fixed on the newer versions, people unfortunately still uses older versions of the emulator and can be affected by this bug. 21 | * 256 kB BW-RAM is not supported unless if the user writes an explicit custom mapper (BML/XML mapper). 22 | 23 | ## Snes9x 24 | * Since version 1.56, the SA-1 CPU is 12% faster than the nominal 10.74 MHz clock. It's clocked at ~12.01 MHz instead. 25 | * SA-1 CPU is affected by the W-RAM refreshes. 26 | * SA-1 CPU is wrongly paused during SNES DMA. 27 | * SA-1 CPU is wrongly paused during H-DMA. 28 | * Virtual Bitmap BW-RAM area (`$60-$6F`) can only access the first 64 kB of the BW-RAM. 29 | * Virtual BW-RAM mapping (`$6000-$7FFF`) can only map the first 64 kB of the BW-RAM. 30 | * For SA-1 ROMs larger than 4 MB, Snes9x may wrongly swap the upper 4 MB with the lower 4 MB. 31 | * Does not lock W-RAM accesses. 32 | * Does not support 256 kB BW-RAM. 33 | * Probably... more coming. 34 | 35 | ## ZSNES 36 | * The SA-1 CPU is 42% slower than the nominal 10.74 MHz clock. It's clocked at ~6.18 MHz instead. 37 | * Random crashes and freezes are often common, with an unknown reason for that. 38 | * It's not possible to execute code on I-RAM nor BW-RAM. Applies to both SA-1 CPU and SNES CPU. To workaround, code must be placed and executed on the W-RAM. 39 | * There is no Character Conversion support, with the exception from the one that Super Mario RPG uses. 40 | * Has partial SA-1 IRQ support. Often SA-1 IRQs conflicts with PPU and H-/V-IRQs. 41 | * Can drop frames out of sudden depending of the code executed on the SNES CPU. 42 | * Does not lock access to any of the SNES registers. SA-1 can even DMA to the VRAM. 43 | * Does not generate IRQ after SA-1 DMA execution. 44 | * Does not support 256 kB BW-RAM. 45 | * Does not support 8 MB ROMs. 46 | * The first 128 kB on the last 2 megabytes on 6 MB ROMs is unusable because ZSNES uses it as an actual memory and for other tables. 47 | * The H-Blank flag from bit 6 of $4212 does not work correctly. 48 | * And more coming. -------------------------------------------------------------------------------- /asm/more_sprites/sprite_tables.asm: -------------------------------------------------------------------------------- 1 | @includefrom sa1.asm 2 | !sa1 = 2 ; Set to 0 if you are not using SA-1, 1 if you are using normal (old) SA-1 Pack and 2 if you are using SA-1 with more sprites enabled (1.10+) 3 | 4 | macro define_sprite_table(name, addr, addr_sa1, addr_more_sprites) 5 | if !sa1 == 0 6 | ! = 7 | elsif !sa1 == 1 8 | ! = 9 | else 10 | ! = 11 | endif 12 | endmacro 13 | 14 | %define_sprite_table(sprite_num, $9E, $9E, $3200) 15 | %define_sprite_table(sprite_speed_y, $AA, $AA, $9E) 16 | %define_sprite_table(sprite_speed_x, $B6, $B6, $B6) 17 | %define_sprite_table(sprite_misc_c2, $C2, $C2, $D8) 18 | %define_sprite_table(sprite_y_low, $D8, $D8, $3216) 19 | %define_sprite_table(sprite_x_low, $E4, $E4, $322C) 20 | %define_sprite_table(sprite_status, $14C8, $74C8, $3242) 21 | %define_sprite_table(sprite_y_high, $14D4, $74D4, $3258) 22 | %define_sprite_table(sprite_x_high, $14E0, $74E0, $326E) 23 | %define_sprite_table(sprite_speed_y_frac, $14EC, $74EC, $74C8) 24 | %define_sprite_table(sprite_speed_x_frac, $14F8, $74F8, $74DE) 25 | %define_sprite_table(sprite_misc_1504, $1504, $7504, $74F4) 26 | %define_sprite_table(sprite_misc_1510, $1510, $7510, $750A) 27 | %define_sprite_table(sprite_misc_151c, $151C, $751C, $3284) 28 | %define_sprite_table(sprite_misc_1528, $1528, $7528, $329A) 29 | %define_sprite_table(sprite_misc_1534, $1534, $7534, $32B0) 30 | %define_sprite_table(sprite_misc_1540, $1540, $7540, $32C6) 31 | %define_sprite_table(sprite_misc_154c, $154C, $754C, $32DC) 32 | %define_sprite_table(sprite_misc_1558, $1558, $7558, $32F2) 33 | %define_sprite_table(sprite_misc_1564, $1564, $7564, $3308) 34 | %define_sprite_table(sprite_misc_1570, $1570, $7570, $331E) 35 | %define_sprite_table(sprite_misc_157c, $157C, $757C, $3334) 36 | %define_sprite_table(sprite_blocked_status, $1588, $7588, $334A) 37 | %define_sprite_table(sprite_misc_1594, $1594, $7594, $3360) 38 | %define_sprite_table(sprite_off_screen_horz, $15A0, $75A0, $3376) 39 | %define_sprite_table(sprite_misc_15ac, $15AC, $75AC, $338C) 40 | %define_sprite_table(sprite_slope, $15B8, $75B8, $7520) 41 | %define_sprite_table(sprite_off_screen, $15C4, $75C4, $7536) 42 | %define_sprite_table(sprite_being_eaten, $15D0, $75D0, $754C) 43 | %define_sprite_table(sprite_obj_interact, $15DC, $75DC, $7562) 44 | %define_sprite_table(sprite_oam_index, $15EA, $75EA, $33A2) 45 | %define_sprite_table(sprite_oam_properties, $15F6, $75F6, $33B8) 46 | %define_sprite_table(sprite_misc_1602, $1602, $7602, $33CE) 47 | %define_sprite_table(sprite_misc_160e, $160E, $760E, $33E4) 48 | %define_sprite_table(sprite_index_in_level, $161A, $761A, $7578) 49 | %define_sprite_table(sprite_misc_1626, $1626, $7626, $758E) 50 | %define_sprite_table(sprite_behind_scenery, $1632, $7632, $75A4) 51 | %define_sprite_table(sprite_misc_163e, $163E, $763E, $33FA) 52 | %define_sprite_table(sprite_in_water, $164A, $764A, $75BA) 53 | %define_sprite_table(sprite_tweaker_1656, $1656, $7656, $75D0) 54 | %define_sprite_table(sprite_tweaker_1662, $1662, $7662, $75EA) 55 | %define_sprite_table(sprite_tweaker_166e, $166E, $766E, $7600) 56 | %define_sprite_table(sprite_tweaker_167a, $167A, $767A, $7616) 57 | %define_sprite_table(sprite_tweaker_1686, $1686, $7686, $762C) 58 | %define_sprite_table(sprite_off_screen_vert, $186C, $786C, $7642) 59 | %define_sprite_table(sprite_misc_187b, $187B, $787B, $3410) 60 | %define_sprite_table(sprite_tweaker_190f, $190F, $790F, $7658) 61 | %define_sprite_table(sprite_misc_1fd6, $1FD6, $7FD6, $766E) 62 | %define_sprite_table(sprite_cape_disable_time, $1FE2, $7FE2, $7FD6) -------------------------------------------------------------------------------- /docs/W-RAM.md: -------------------------------------------------------------------------------- 1 | W-RAM 2 | ===== 3 | 4 | W-RAM (work RAM) is the SNES onboard memory. 128 kB (131072 bytes) big, it's clocked at 2.68 MHz and can be accessed though addresses`$7E:0000-$7F:FFFF`, as well on addresses`$0000-$1FFF`though banks`$00-$3F`/`$80-$BF`and though ports`$2180-$2183`on the address bus B. The SA-1 CPU can't access the W-RAM. 5 | 6 | SA-1 Pack moves most of the W-RAM addresses to either I-RAM or BW-RAM to make the contents accessible and faster for the SA-1 system. Because of that, a good portion of the W-RAM is either left unused or modified for another cause which does not involve SA-1 CPU access. 7 | 8 | ### Code Memory 9 | The patch places some routines on the W-RAM for several reasons, but the most important of them is to allow that SA-1 CPU will always access the ROM memory at 10.74 MHz when the SNES CPU is idle or busy doing a process that does not need ROM access. 10 | 11 | ### W-RAM Memory Map 12 | Only modified W-RAM addresses are displayed on this document. For checking other SMW addresses, look for the SMW Central RAM map. 13 | 14 | #### Bank $7E 15 | Start | End | Description 16 | :-----:|:-----:|------------- 17 | `$0000`|`$000F`| Scratch Memory. Some codes does not use the I-RAM at all for certain reasons, such as for executing code on the memory. FuSoYa's SA-1 version of LC_LZ2 and LC_LZ3 implementation are examples of that. The reason of that is ZSNES. See [Known Issues](known-issues.md) to understand why. 18 | `$0010`|`$0FFF`| Empty. Not cleared. 19 | `$1000`|`$1E7F`| Empty. Not cleared. **Reserved by SA-1 Pack for future expansion.** 20 | `$1D00`|`-`| **IRQ-as-NMI system (`x------e`)**
  • Bit 0 (e): When set, the V-Blank routine is moved to an IRQ and NMI is disabled.
  • Bit 7 (x): When set, the next IRQ will be the V-Blank routine. Used internally when`e`is set.
21 | `$1D01`|`-`| Which scanline should the V-Blank run when`$1D00`is set. 22 | `$1D02`|`-`| Custom IRQ handler flag. If set, all IRQs, with exception of IRQ-as-NMI handler will run on the pointer located at`$1D04-$1D06`instead of running on the regular SMW IRQ handelr. 23 | `$1D03`|`-`| Copy of the register`$2224`. When setting`$2224`, make sure to set this address as well. This address is used to restore the`$2224`register value after an IRQ is executed. 24 | `$1D04`|`$1D06`| Custom IRQ handler pointer. All IRQs will jump to this pointer when`$1D02`is set. 25 | `$1D07`|`-`| Reserved for future use. 26 | `$1D08`|`$1DFF`| This is where the IRQ controller is uploaded at game reset and is responsible for controlling all S-CPU IRQs received. Calling`$1D08`activates the IRQ-as-NMI system on the next IRQ call, if enabled. 27 | `$1E00`|`$1E7F`| Empty. Not cleared. **Reserved by SA-1 Pack for future expansion.** 28 | `$1E80`|`$1E8D`| SA-1 Execute Pointer. When called, the routine will invoke the SA-1 CPU to run a certain code and wait until the execution is finished. 29 | `$1E8E`|`$1E95`| The game main loop. It waits for a NMI and then resumes executing. 30 | `$1E96`|`$1EA6`| The wait for H-Blank routine. Waits until h-blank starts. When the emulator is ZSNES, this routine is replaced with a special version. 31 | `$1EA7`|`$1EFF`| Empty. Not cleared. **Reserved by SA-1 Pack for future expansion.** 32 | `$1F00`|`$1FFF`| Reserved for the SNES CPU stack. 33 | `$2000`|`$C7FF`| Untouched by SA-1 Pack. 34 | `$C800`|`$FFFF`| Empty. Not cleared. **Reserved by SA-1 Pack for future expansion.** 35 | 36 | #### Bank $7F 37 | Start | End | Description 38 | :-----:|:-----:|------------- 39 | `$0000`|`$9A7A`| Untouched by SA-1 Pack. 40 | `$9A7B`|`$9C7A`| Empty. Not cleared. 41 | `$9C7B`|`$C7FF`| Untouched by SA-1 Pack. 42 | `$C800`|`$FFFF`| Empty. Not cleared. **Reserved by SA-1 Pack for future expansion.** -------------------------------------------------------------------------------- /asm/boost/lzx.asm: -------------------------------------------------------------------------------- 1 | @includefrom sa1.asm 2 | 3 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 4 | ; LC_LZ2/LC_LZ3 Optimization Patch v1.2 5 | ; SA-1 Version. 6 | ; 7 | ; By: 8 | ; - Ersanio 9 | ; - edit1754 10 | ; - 33953YoShI 11 | ; - Min 12 | ; - smkdan 13 | ; 14 | ; In addition to being much faster than the original 15 | ; this one also stores the decompressed size to $8D, 16 | ; which may be useful in patches that upload ExGFX files 17 | ; 18 | ; NEW in v1.1: 19 | ; - rearranged some branches so they branch in the less-likely case rather than 20 | ; the more-likely case (Ex: BEQ .end rather than BEQ .notEnd) 21 | ; - rewrote the MVN $7E7E / MVN $7F7F portion of code because it destroyed 22 | ; the ability to decompress to SRAM. 23 | ; 24 | ; NEW in v1.2 25 | ; - should have no issues with interrupts. 26 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 27 | 28 | !S = $9E ; 0x10 bytes in $30XX that aren't touched during interrupts (NMI or IRQ) 29 | 30 | if read1($0FFFEB) == 2 31 | !LZ3 = 1 32 | else 33 | !LZ3 = 0 34 | 35 | pushpc 36 | ORG $0FFFEB 37 | db $01 38 | pullpc 39 | endif 40 | 41 | macro ReadByte() 42 | STX $8A 43 | LDA [$8A] 44 | INX 45 | BNE + 46 | LDX.b $02+!S ;can be #$8000 or #$0000 47 | INC $8C 48 | INC $08+!S 49 | + 50 | endmacro 51 | 52 | pushpc 53 | org $00B8E3 54 | JSL CodeStart ;was JML before 55 | RTS 56 | pullpc 57 | 58 | CodeStart: 59 | PHB 60 | PHK 61 | PLB 62 | SEP #$20 63 | REP #$10 64 | 65 | LDX.W #Decompress 66 | STX $3180 67 | LDA.B #Decompress>>16 68 | STA $3182 69 | JSR $1E80 70 | 71 | BIT $3100 72 | BMI .RAM_DMA 73 | 74 | PLB 75 | SEP #$30 76 | RTL 77 | 78 | .RAM_DMA 79 | LDX #$8000 80 | STX $4300 81 | LDX $00 82 | STX $2181 83 | LDA $02 84 | STA $2183 85 | LDX #$0000 86 | STX $4302 87 | LDA #$41 88 | STA $4304 89 | LDX $8D 90 | STX $4305 91 | LDA #$01 92 | - STA $420B 93 | LDX $4305 94 | BNE - 95 | 96 | PLB 97 | SEP #$30 98 | RTL 99 | 100 | Decompress: 101 | PEI ($00+!S) 102 | PEI ($02+!S) 103 | PEI ($04+!S) 104 | PEI ($06+!S) ;mvn, byte1 105 | PEI ($08+!S) ;byte 2, jmp 106 | PEI ($0A+!S) ;jmp addr 107 | PEI ($0C+!S) ;mvn, byte1 108 | PEI ($0E+!S) ;byte 2, jmp 109 | PEI ($10+!S) ;jmp addr 110 | PEI ($8A) 111 | 112 | LDA #$80 113 | STA.b $03+!S 114 | STZ.b $02+!S 115 | 116 | LDA $8C 117 | CMP #$C0 118 | BCC + 119 | STZ.b $03+!S 120 | + 121 | LDA #$00 122 | PHA 123 | 124 | LDA $02 125 | CMP #$7E 126 | BEQ .RAM_DMA 127 | CMP #$7F 128 | BNE .Continue 129 | .RAM_DMA 130 | PLA 131 | 132 | PEI ($00) 133 | LDA $02 134 | PHA 135 | 136 | LDA #$41 137 | STZ $00 138 | STZ $01 139 | STA $02 140 | 141 | LDA #$FF 142 | PHA 143 | .Continue 144 | PHB 145 | REP #$10 146 | 147 | LDA #$54 148 | BIT $318E 149 | BPL + 150 | LDA #$FF 151 | + STA.b $06+!S 152 | STA.b $0C+!S 153 | LDA #$4C 154 | STA.b $09+!S 155 | STA.b $0F+!S 156 | LDX.w #.back 157 | STX.b $0A+!S 158 | LDX.w #.back2 159 | STX.b $10+!S 160 | LDA.b $8C 161 | STA.b $08+!S 162 | LDA $02 163 | STA.b $07+!S 164 | STA.b $0D+!S 165 | STA.b $0E+!S 166 | PHA 167 | PLB 168 | 169 | LDY $00 ; dest_low 170 | LDX $8A ; src_low 171 | STZ $8A 172 | STZ $8B 173 | JMP .main 174 | .done 175 | REP #$20 176 | TYA 177 | SEC 178 | SBC $00 179 | STA $8D ; size!!! 180 | SEP #$20 181 | PLB 182 | 183 | PLA 184 | STA $0100 185 | BPL + 186 | PLA 187 | STA $02 188 | PLX 189 | STX $00 190 | 191 | + PLX : STX $8A 192 | PLX : STX.b $10+!S 193 | PLX : STX.b $0E+!S 194 | PLX : STX.b $0C+!S 195 | PLX : STX.b $0A+!S 196 | PLX : STX.b $08+!S 197 | PLX : STX.b $06+!S 198 | PLX : STX.b $04+!S 199 | PLX : STX.b $02+!S 200 | PLX : STX.b $00+!S 201 | SEP #$30 202 | RTL 203 | .end JMP .done 204 | 205 | if !LZ3 == 0 206 | incsrc lz2.asm 207 | else 208 | incsrc lz3.asm 209 | endif 210 | 211 | -------------------------------------------------------------------------------- /docs/Sprite-Remap.md: -------------------------------------------------------------------------------- 1 | # Arujus's More Sprites Patch Remap 2 | 3 | > The main task of the patch is to remap three sprite tables that were previously on the direct page off of the direct page, namely the sprite number table, the X position low byte table and the Y position low byte table. The main idea for doing this is to store three pointers on the direct page that point to the appropriate indices into these tables and then replace accesses to the old sprite tables indexed by x with indirect accesses to one of the pointers on the direct page, which will point to the correct address into the new sprite table. 4 | 5 | Arujus's words extracted from `more_sprites.asm`. The main challenge of the sprite expansion patch wasn't to remap the sprite tables to I-RAM, nor expand them, but move three tables in particular from direct page addressing to absolute addressing without having to reallocate half of the game code. With the remapping done, it was fairly trivial to expand the direct page addressing sprite tables to 22 bytes long with the extra space freed from the other direct page tables. 6 | 7 | ## 'More Sprites' Special DP Addresses 8 | These addresses are updated as soon as a sprite starts executing and are workarounds for when it's not possible to change a 2-byte to 3-byte opcode to accommodate`$3200+x`,`$3216+x`and`$322C+x`. 9 | 10 | DP | Size | Description 11 | :----:|:-------:|------------- 12 | `$87` | 1 byte | Holds the current sprite number. Used when a sprite can't load `$B4` indirectly, for example when it wants to load it on the X/Y register instead of the accumulator A. 13 | `$B4` | 2 bytes | Points to`$3200`+ current sprite slot, which holds the current sprite number. 14 | `$CC` | 2 bytes | Points to`$3216`+ current sprite slot, which holds the current sprite Y position low byte. 15 | `$EE` | 2 bytes | Points to`$322C`+ current sprite slot, which holds the current sprite X position low byte. 16 | 17 | ## Sprite Tables Memory Map 18 | Below is the memory map of all sprite tables. Each table is now 22 bytes long, compared to the original SMW which was 12 bytes long. 19 | 20 | ### Direct Page I-RAM Addresses 21 | Start | End | Description 22 | :-----:|:-----:|------------- 23 | `$309E`|`$30B3`| SMW's `$7E:00AA` 24 | `$30B6`|`$30CB`| SMW's `$7E:00B6` 25 | `$30D8`|`$30ED`| SMW's `$7E:00C2` 26 | 27 | ### Absolute I-RAM Addresses 28 | Start | End | Description 29 | :-----:|:-----:|------------- 30 | `$3200`|`$3215`| SMW's `$7E:009E` *(used to be Direct Page)* 31 | `$3216`|`$322B`| SMW's `$7E:00D8` *(used to be Direct Page)* 32 | `$322C`|`$3241`| SMW's `$7E:00E4` *(used to be Direct Page)* 33 | `$3242`|`$3257`| SMW's `$7E:14C8` 34 | `$3258`|`$326D`| SMW's `$7E:14D4` 35 | `$326E`|`$3283`| SMW's `$7E:14E0` 36 | `$3284`|`$3299`| SMW's `$7E:151C` 37 | `$329A`|`$32AF`| SMW's `$7E:1528` 38 | `$32B0`|`$32C5`| SMW's `$7E:1534` 39 | `$32C6`|`$32DB`| SMW's `$7E:1540` 40 | `$32DC`|`$32F1`| SMW's `$7E:154C` 41 | `$32F2`|`$3307`| SMW's `$7E:1558` 42 | `$3308`|`$331D`| SMW's `$7E:1564` 43 | `$331E`|`$3333`| SMW's `$7E:1570` 44 | `$3334`|`$3349`| SMW's `$7E:157C` 45 | `$334A`|`$335F`| SMW's `$7E:1588` 46 | `$3360`|`$3375`| SMW's `$7E:1594` 47 | `$3376`|`$338B`| SMW's `$7E:15A0` 48 | `$338C`|`$33A1`| SMW's `$7E:15AC` 49 | `$33A2`|`$33B7`| SMW's `$7E:15EA` 50 | `$33B8`|`$33CD`| SMW's `$7E:15F6` 51 | `$33CE`|`$33E3`| SMW's `$7E:1602` 52 | `$33E4`|`$33F9`| SMW's `$7E:160E` 53 | `$33FA`|`$340F`| SMW's `$7E:163E` 54 | `$3410`|`$3425`| SMW's `$7E:187B` 55 | 56 | ### Absolute BW-RAM Addresses 57 | Start | End | Description 58 | :-----:|:-----:|------------- 59 | `$74C8`|`$74DD`| SMW's `$7E:14EC` 60 | `$74DE`|`$74F3`| SMW's `$7E:14F8` 61 | `$74F4`|`$7509`| SMW's `$7E:1504` 62 | `$750A`|`$751F`| SMW's `$7E:1510` 63 | `$7520`|`$7535`| SMW's `$7E:15B8` 64 | `$7536`|`$754B`| SMW's `$7E:15C4` 65 | `$754C`|`$7561`| SMW's `$7E:15D0` 66 | `$7562`|`$7577`| SMW's `$7E:15DC` 67 | `$7578`|`$758D`| SMW's `$7E:161A` 68 | `$758E`|`$75A3`| SMW's `$7E:1626` 69 | `$75A4`|`$75B9`| SMW's `$7E:1632` 70 | `$7658`|`$766D`| SMW's `$7E:190F` 71 | `$766E`|`$7683`| SMW's `$7E:1FD6` 72 | `$7FD6`|`$7FEB`| SMW's `$7E:1FE2` 73 | `$75BA`|`$75CF`| SMW's `$7E:164A` 74 | `$75D0`|`$75E5`| SMW's `$7E:1656` 75 | `$75EA`|`$75FF`| SMW's `$7E:1662` 76 | `$7600`|`$7615`| SMW's `$7E:166E` 77 | `$7616`|`$762B`| SMW's `$7E:167A` 78 | `$762C`|`$7641`| SMW's `$7E:1686` 79 | `$7642`|`$7657`| SMW's `$7E:186C` 80 | -------------------------------------------------------------------------------- /asm/more_sprites/NoMoreSpriteTileLimits.asm: -------------------------------------------------------------------------------- 1 | @includefrom sa1.asm 2 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 3 | ;; No More Sprite Tile Limits v2.0.0 4 | ;; coded by edit1754, macro'd by MathOnNapkins, 5 | ;; improved by Arujus and optimized by VitorVilela. 6 | ;; 7 | ;; This is a mockup edition that uses the MaxTile API to clean up the slots, 8 | ;; with the consequence of slots no longer being searched but instead hardcoded. 9 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 10 | 11 | header 12 | sa1rom 13 | 14 | org $0180D2 15 | 16 | sprite_oam_hook: 17 | BRA .skip ; skip the NOP's 18 | NOP ; \ 19 | NOP ; | use NOP 20 | NOP ; | to take 21 | NOP ; | up space 22 | NOP ; | to overwrite 23 | NOP ; | old code 24 | NOP ; | 25 | NOP ; | 26 | NOP ; | 27 | NOP ; | 28 | NOP ; | 29 | NOP ; | 30 | NOP ; / 31 | .skip 32 | autoclean JSL pick_oam_slot 33 | 34 | ; Don't want climbing net door setting it's own OAM index 35 | org $01BB33 36 | JSL net_door_fix 37 | NOP 38 | 39 | org $01BBFD 40 | LDY $0F 41 | 42 | ; This table contains OAM indices for cluster sprites. Set them to use the highest 43 | ; indices so as not to conflict with ordinary sprites. 44 | org $02FF50 45 | db $E0,$E4,$E8,$EC,$F0,$F4,$F8,$FC 46 | db $B0,$B4,$B8,$BC,$D0,$D4,$D8,$DC 47 | db $C0,$C4,$C8,$CC 48 | 49 | ; Lakitu should not use a hard-coded OAM index for the fishing line 50 | org $02E6EC 51 | JSL fishing_line_fix 52 | NOP 53 | 54 | ; I'm pretty sure that $140F was meant to be used a flag indicating that Reznor is 55 | ; on screen but SMW has a bug where it increments every frame in which Reznor is 56 | ; present instead of just once, which means it can wrap around to zero for one 57 | ; frame. This can cause tiles to disappear among other problems for this patch so it 58 | ; is best to fix the bug and set $140F to a fixed value so that it's always non-zero 59 | ; during a Reznor fight. 60 | org $039890 61 | STA $740F 62 | 63 | ; Powerups sometimes use their own hard-coded OAM index, we don't want this so fix it. 64 | ;org $01C61F 65 | ;BRA SkipStuff 66 | ;rep 21 : NOP 67 | ;SkipStuff: 68 | 69 | ;Vitor Vilela: this screws up Roy/Morton/Ludwig, undo that. The hard-coded OAM index 70 | ; is only for their case anyways. 71 | org $01C61F 72 | LDA.w $740F 73 | BNE + 74 | LDA.w $6D9B 75 | CMP.b #$C1 76 | BEQ + 77 | BIT.w $6D9B 78 | BVC + 79 | LDA.b #$D8 80 | STA.w $33A2,X 81 | TAY 82 | + 83 | 84 | ; The hammer brother graphics routine is called by the hammer brother's platform. 85 | ; The OAM index for the hammer brother might not be set correctly so hijack here 86 | ; to set it. 87 | org $02DB82 88 | JSL hammer_bro_fix 89 | NOP 90 | NOP 91 | 92 | freecode 93 | 94 | hammer_bro_fix: 95 | LDA !sprite_x_high,x 96 | STA !sprite_x_high,y 97 | 98 | ; Add #$10 because the platform wrote 4 tiles (#$10 bytes) to OAM. 99 | LDA !sprite_oam_index,x 100 | CLC 101 | ADC #$10 102 | STA !sprite_oam_index,y 103 | RTL 104 | 105 | fishing_line_fix: 106 | LDA !sprite_oam_index,x 107 | CLC 108 | ADC #$08 109 | STA !sprite_oam_index,x 110 | RTL 111 | 112 | net_door_fix: 113 | LDA !sprite_oam_index,x 114 | LSR 115 | LSR 116 | STA $0F 117 | 118 | LDA !sprite_oam_index,x 119 | RTL 120 | 121 | pick_oam_slot: 122 | ; It's not necessary to get an index if the sprite doesn't exist. 123 | LDA !sprite_status,x 124 | BEQ .return 125 | 126 | LDA !sprite_num,x 127 | CMP #$35 128 | BEQ .yoshi 129 | 130 | LDA #$38 131 | STA !sprite_oam_index,x 132 | JML call_nmstl_mockup_flush 133 | 134 | .yoshi 135 | ; Yoshi will get a hardcoded slot because the game likes 136 | ; redrawing him multiple times. 137 | LDA #$28 138 | STA !sprite_oam_index,x 139 | JML call_nmstl_mockup_flush 140 | 141 | .return 142 | RTL 143 | 144 | -------------------------------------------------------------------------------- /asm/boost/lz3.asm: -------------------------------------------------------------------------------- 1 | @includefrom sa1.asm 2 | ; LC_LZ3 from Lunar Magic 3 | 4 | .case_c0 5 | %ReadByte() 6 | CMP #$00 7 | BPL + 8 | STY.b $00+!S 9 | REP #$21 10 | AND #$007F 11 | EOR #$FFFF 12 | ADC.b $00+!S 13 | BRA .lzcopy110 14 | + XBA 15 | %ReadByte() 16 | REP #$21 17 | ADC $00 18 | 19 | .lzcopy110 20 | STX.b $00+!S 21 | INC $8D 22 | TAX 23 | SEP #$20 24 | - LDA $0000,x 25 | STA $0000,y 26 | INY 27 | DEX 28 | DEC $8D 29 | BNE - 30 | DEC $8E 31 | BPL - 32 | JMP .back2 33 | 34 | .case_e0_or_else 35 | ASL 36 | BPL .case_c0 37 | LDA $8D 38 | CMP #$1F 39 | BEQ .end 40 | AND #$03 41 | STA $8E 42 | EOR $8D 43 | ASL 44 | ASL 45 | ASL 46 | XBA 47 | %ReadByte() 48 | STA $8D 49 | XBA 50 | JMP .type 51 | 52 | .case_80_or_else 53 | BMI .case_e0_or_else 54 | ASL 55 | BMI .case_a0 56 | 57 | %ReadByte() 58 | CMP #$00 59 | BPL + 60 | STY.b $00+!S 61 | REP #$21 62 | AND #$007F 63 | EOR #$FFFF 64 | ADC.b $00+!S 65 | BRA .lzcopy 66 | + XBA 67 | %ReadByte() 68 | REP #$21 69 | ADC $00 70 | 71 | .lzcopy 72 | STX.b $00+!S 73 | TAX 74 | LDA $8D 75 | SEP #$20 76 | 77 | BIT.b $0C+!S 78 | BMI + 79 | JMP.w $000C+!S 80 | 81 | + LDA $02 82 | CMP #$40 83 | BEQ + 84 | 85 | LDA $8D 86 | MVN $41,$41 87 | BRA .back2 88 | 89 | + LDA $8D 90 | MVN $40,$40 91 | BRA .back2 92 | 93 | .case_a0 94 | %ReadByte() 95 | CMP #$00 96 | BPL + 97 | STY.b $00+!S 98 | REP #$21 99 | AND #$007F 100 | EOR #$FFFF 101 | ADC.b $00+!S 102 | BRA .lzcopy101 103 | + XBA 104 | %ReadByte() 105 | REP #$21 106 | ADC $00 107 | 108 | .lzcopy101 109 | STX.b $00+!S 110 | TAX 111 | LDA.w #$0000 112 | ASL.b $8D 113 | SEP #$20 114 | -- LSR.b $8D 115 | - LDA $0000,x 116 | STZ.b $04+!S 117 | ASL 118 | ROR.b $04+!S 119 | ASL 120 | ROR.b $04+!S 121 | ASL 122 | ROR.b $04+!S 123 | ASL 124 | ROR.b $04+!S 125 | ASL 126 | ROR.b $04+!S 127 | ASL 128 | ROR.b $04+!S 129 | ASL 130 | ROR.b $04+!S 131 | ASL 132 | LDA.b $04+!S 133 | ROR 134 | STA $0000,y 135 | INY 136 | INX 137 | DEC $8D 138 | BPL - 139 | DEC $8E 140 | BPL -- 141 | 142 | .back2 143 | LDX.b $00+!S 144 | 145 | .main 146 | %ReadByte() 147 | STA $8D 148 | STZ $8E 149 | AND #$E0 150 | TRB $8D 151 | 152 | .type 153 | ASL 154 | BCS .case_80_or_else_J 155 | BMI .case_40_or_60_J 156 | ASL 157 | BMI .case_20 158 | 159 | .case_00 160 | REP #$20 161 | LDA $8D 162 | STX $8D 163 | 164 | - SEP #$20 165 | BIT.b $06+!S 166 | BMI + 167 | JMP.w $0006+!S 168 | 169 | + REP #$20 170 | PEI ($02+!S) 171 | PEI ($00) 172 | STZ $00 173 | SEP #$20 174 | INC 175 | STA.b $02+!S 176 | XBA 177 | INC 178 | STA.b $03+!S 179 | PHB 180 | LDA $8C 181 | PHA 182 | PLB 183 | -- LDA $0000,x 184 | STA [$00],y 185 | INX 186 | INY 187 | DEC.b $02+!S 188 | BNE -- 189 | DEC.b $03+!S 190 | BNE -- 191 | PLB 192 | REP #$20 193 | PLA 194 | STA $00 195 | PLA 196 | STA.b $02+!S 197 | SEP #$20 198 | .back 199 | CPX $8D 200 | BCS .main 201 | 202 | INC $8C 203 | INC $08+!S 204 | CPX #$0000 205 | BEQ + 206 | 207 | DEX 208 | STX.b $00+!S 209 | REP #$21 210 | LDX.b $02+!S ;#$8000 or #$0000 211 | STX $8D 212 | TYA 213 | SBC.b $00+!S 214 | TAY 215 | LDA.b $00+!S 216 | BRA - 217 | + 218 | LDX.b $02+!S ;#$8000 or #$0000 219 | BRA .main 220 | 221 | .case_80_or_else_J 222 | JMP .case_80_or_else 223 | 224 | .case_40_or_60_J 225 | JMP .case_40_or_60 226 | 227 | .case_20 228 | %ReadByte() 229 | STX.b $00+!S 230 | PHA 231 | PHA 232 | REP #$20 233 | 234 | .case_20_main 235 | LDA $8D 236 | INC 237 | LSR 238 | TAX 239 | PLA 240 | 241 | - STA $0000,Y 242 | INY 243 | INY 244 | DEX 245 | BNE - 246 | 247 | SEP #$20 248 | BCC + 249 | STA $0000,Y 250 | INY 251 | + LDX.b $00+!S 252 | JMP .main 253 | 254 | .case_40_or_60 255 | ASL 256 | BMI .case_60 257 | %ReadByte() 258 | XBA 259 | %ReadByte() 260 | 261 | XBA 262 | STX.b $00+!S 263 | REP #$20 264 | PHA 265 | ;Replace BRA .case_20_main the code itself 266 | LDA $8D 267 | INC 268 | LSR 269 | TAX 270 | PLA 271 | - STA $0000,Y 272 | INY 273 | INY 274 | DEX 275 | BNE - 276 | SEP #$20 277 | BCC + 278 | STA $0000,Y 279 | INY 280 | + LDX.b $00+!S 281 | JMP .main 282 | 283 | 284 | .case_60 285 | REP #$20 286 | 287 | .case_60_main 288 | LDA $8D 289 | BEQ .case_60_single 290 | INC 291 | LSR 292 | STX.b $00+!S 293 | TYX 294 | 295 | - STZ $0000,x 296 | INX 297 | INX 298 | DEC 299 | BNE - 300 | 301 | TXY 302 | LDX.b $00+!S 303 | BCS .case_60_single 304 | SEP #$20 305 | JMP .main 306 | 307 | .case_60_single 308 | SEP #$20 309 | STA $0000,y 310 | INY 311 | JMP .main 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | -------------------------------------------------------------------------------- /asm/engine/snes_init.asm: -------------------------------------------------------------------------------- 1 | ;===============================================; 2 | ; S-CPU Initialization System ; 3 | ;===============================================; 4 | 5 | macro init_block_ram_copy(label) 6 | LDA.w #