├── .gitattributes ├── .gitignore ├── .gitmodules ├── LICENSE ├── Makefile ├── README.md ├── docs ├── README.md ├── favicon.ico ├── files │ ├── CPU-i.html │ ├── CPU_DataStructures-i.html │ ├── CPU_Def-i.html │ ├── CPU_Math-i.html │ ├── CPU_Memory-i.html │ ├── CPU_PPU-i.html │ ├── CPU_Runtime-i.html │ ├── CPU_SMP-i.html │ ├── Configurations │ │ ├── Map-cfg.html │ │ └── libSFX-cfg.html │ ├── Docs │ │ └── Make-txt.html │ ├── Packages │ │ ├── LZ4 │ │ │ └── LZ4-i.html │ │ └── Mouse │ │ │ └── Mouse-i.html │ ├── SMP_ADSR-i.html │ ├── SMP_Def-i.html │ ├── SMP_Util-i.html │ └── libSFX-i.html ├── index.html └── styles │ └── main.css ├── examples ├── Hello-Mode7 │ ├── Data │ │ ├── Music.spc │ │ └── SNES-Mode7.png │ ├── Hello-Mode7.s │ └── Makefile ├── Hello │ ├── Data │ │ ├── Music.spc │ │ └── SNES.png │ ├── Hello.s │ └── Makefile ├── MSU-1 │ ├── .gitignore │ ├── MSU1.s │ ├── Makefile │ └── SMP │ │ └── SMP.s700 ├── Mode7-Transform │ ├── Data │ │ ├── Background.png │ │ └── Music.spc │ ├── Makefile │ ├── Math.i │ ├── Mode7-Transform.s │ ├── Sin.py │ └── libSFX.cfg ├── Mouse │ ├── Data │ │ ├── Music.spc │ │ ├── SNES.png │ │ └── Sprites.png │ ├── Makefile │ ├── Mouse.s │ ├── OAM.i │ └── libSFX.cfg ├── SMP-Test │ ├── Makefile │ ├── Map.cfg │ ├── Normal.s700 │ ├── SMP-Nop │ │ └── Test.s700 │ ├── SMP-Play │ │ ├── Data │ │ │ ├── Sample1.wav │ │ │ └── Sample2.wav │ │ ├── Directory.s700 │ │ ├── Play.s700 │ │ └── SMP-Map.cfg │ ├── SMP-Test.s │ └── libSFX.cfg ├── SixteenMegaPower │ ├── Makefile │ ├── Map.cfg │ ├── SixteenMegaPower.s │ ├── Subfolders │ │ └── With │ │ │ └── Code.s │ └── libSFX.cfg ├── Template-Mode21 │ ├── Makefile │ ├── Map.cfg │ ├── Template-Mode21.s │ └── libSFX.cfg ├── Template │ ├── Makefile │ └── Template.s └── X-GSU │ ├── Makefile │ ├── Map.cfg │ ├── SuperFX.s │ ├── SuperFX.sgs │ └── libSFX.cfg ├── extras ├── Ideas.md ├── NaturalDocs │ ├── bin │ │ ├── Config │ │ │ ├── Languages.txt │ │ │ └── Topics.txt │ │ ├── License.txt │ │ ├── Modules │ │ │ └── NaturalDocs │ │ │ │ ├── BinaryFile.pm │ │ │ │ ├── Builder.pm │ │ │ │ ├── Builder │ │ │ │ ├── Base.pm │ │ │ │ ├── FramedHTML.pm │ │ │ │ ├── HTML.pm │ │ │ │ └── HTMLBase.pm │ │ │ │ ├── ClassHierarchy.pm │ │ │ │ ├── ClassHierarchy │ │ │ │ ├── Class.pm │ │ │ │ └── File.pm │ │ │ │ ├── ConfigFile.pm │ │ │ │ ├── Constants.pm │ │ │ │ ├── DefineMembers.pm │ │ │ │ ├── Error.pm │ │ │ │ ├── File.pm │ │ │ │ ├── ImageReferenceTable.pm │ │ │ │ ├── ImageReferenceTable │ │ │ │ ├── Reference.pm │ │ │ │ └── String.pm │ │ │ │ ├── Languages.pm │ │ │ │ ├── Languages │ │ │ │ ├── ActionScript.pm │ │ │ │ ├── Ada.pm │ │ │ │ ├── Advanced.pm │ │ │ │ ├── Advanced │ │ │ │ │ ├── Scope.pm │ │ │ │ │ └── ScopeChange.pm │ │ │ │ ├── Base.pm │ │ │ │ ├── CSharp.pm │ │ │ │ ├── PLSQL.pm │ │ │ │ ├── Pascal.pm │ │ │ │ ├── Perl.pm │ │ │ │ ├── Prototype.pm │ │ │ │ ├── Prototype │ │ │ │ │ └── Parameter.pm │ │ │ │ ├── Simple.pm │ │ │ │ └── Tcl.pm │ │ │ │ ├── LineReader.pm │ │ │ │ ├── Menu.pm │ │ │ │ ├── Menu │ │ │ │ └── Entry.pm │ │ │ │ ├── NDMarkup.pm │ │ │ │ ├── Parser.pm │ │ │ │ ├── Parser │ │ │ │ ├── JavaDoc.pm │ │ │ │ ├── Native.pm │ │ │ │ └── ParsedTopic.pm │ │ │ │ ├── Project.pm │ │ │ │ ├── Project │ │ │ │ ├── ImageFile.pm │ │ │ │ └── SourceFile.pm │ │ │ │ ├── ReferenceString.pm │ │ │ │ ├── Settings.pm │ │ │ │ ├── Settings │ │ │ │ └── BuildTarget.pm │ │ │ │ ├── SourceDB.pm │ │ │ │ ├── SourceDB │ │ │ │ ├── Extension.pm │ │ │ │ ├── File.pm │ │ │ │ ├── Item.pm │ │ │ │ ├── ItemDefinition.pm │ │ │ │ └── WatchedFileDefinitions.pm │ │ │ │ ├── StatusMessage.pm │ │ │ │ ├── SymbolString.pm │ │ │ │ ├── SymbolTable.pm │ │ │ │ ├── SymbolTable │ │ │ │ ├── File.pm │ │ │ │ ├── IndexElement.pm │ │ │ │ ├── Reference.pm │ │ │ │ ├── ReferenceTarget.pm │ │ │ │ ├── Symbol.pm │ │ │ │ └── SymbolDefinition.pm │ │ │ │ ├── Topics.pm │ │ │ │ ├── Topics │ │ │ │ └── Type.pm │ │ │ │ └── Version.pm │ │ └── NaturalDocs │ └── config │ │ ├── Languages.txt │ │ ├── Menu.txt │ │ ├── README.md │ │ ├── Topics.txt │ │ ├── favicon.ico │ │ ├── libsfx.css │ │ ├── libsfx.scss │ │ └── readme ├── SublimeText │ ├── README.md │ ├── ca65-65816.sublime-settings │ ├── ca65-65816.tmLanguage │ ├── ca65-gsu.sublime-settings │ ├── ca65-gsu.tmLanguage │ ├── ca65-spc700.sublime-settings │ └── ca65-spc700.tmLanguage └── VisualStudioCode │ ├── README.md │ ├── ca65-65816 │ ├── .vscode │ │ └── launch.json │ ├── README.md │ ├── language-configuration.json │ ├── package.json │ └── syntaxes │ │ └── ca65-65816.tmLanguage │ ├── ca65-gsu │ ├── .vscode │ │ └── launch.json │ ├── README.md │ ├── language-configuration.json │ ├── package.json │ └── syntaxes │ │ └── ca65-gsu.tmLanguage │ └── ca65-spc700 │ ├── .vscode │ └── launch.json │ ├── README.md │ ├── language-configuration.json │ ├── package.json │ └── syntaxes │ └── ca65-spc700.tmLanguage ├── include ├── CPU.i ├── CPU │ ├── Header.s │ ├── Library.s │ ├── Runtime.s │ └── SMP.s ├── CPU_DSP.i ├── CPU_DataStructures.i ├── CPU_Def.i ├── CPU_GSU.i ├── CPU_MSU.i ├── CPU_Math.i ├── CPU_Memory.i ├── CPU_PPU.i ├── CPU_Runtime.i ├── CPU_SMP.i ├── Configurations │ ├── Map.cfg │ ├── Map_Mode20_1mbit.cfg │ ├── Map_Mode20_1mbit_GSU.cfg │ ├── Map_Mode20_2mbit.cfg │ ├── Map_Mode21_1mbit.cfg │ ├── Map_Mode21_2mbit.cfg │ ├── SMP-Map.cfg │ └── libSFX.cfg ├── Docs │ └── Make.txt ├── GSU_Assembler.i ├── Packages │ ├── LZ4 │ │ ├── LZ4.i │ │ ├── LZ4.s │ │ └── config │ └── Mouse │ │ ├── Mouse.i │ │ ├── Mouse.s │ │ └── config ├── SMP │ └── System.s700 ├── SMP_ADSR.i ├── SMP_Assembler.i ├── SMP_Def.i ├── SMP_Util.i ├── libSFX.defaults.i ├── libSFX.defines.i └── libSFX.i ├── libSFX.make ├── tests ├── Mode20 │ ├── Data │ │ ├── Graphics.palette │ │ ├── Graphics.tilemap.lz4 │ │ ├── Graphics.tiles.lz4 │ │ ├── Music.spc │ │ ├── Repetetive.bin │ │ └── TheEyesHaveIt.txt │ ├── Makefile │ └── Tests.s ├── Mode21 │ ├── Data │ │ ├── Graphics.palette │ │ ├── Graphics.tilemap.lz4 │ │ ├── Graphics.tiles.lz4 │ │ ├── Music.spc │ │ ├── Repetetive.bin │ │ └── TheEyesHaveIt.txt │ ├── Makefile │ ├── Map.cfg │ ├── Tests.s │ └── libSFX.cfg └── README.md └── tools └── make_breakpoints /.gitattributes: -------------------------------------------------------------------------------- 1 | *.i linguist-language=asm 2 | *.s linguist-language=asm 3 | *.s700 linguist-language=asm 4 | *.sgs linguist-language=asm 5 | extras/** linguist-vendored 6 | extras/** linguist-documentation 7 | tools/** linguist-vendored 8 | tools/** linguist-documentation 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/.o 2 | **/.build 3 | **/.build_libsfx 4 | examples/**/*.sfc 5 | examples/**/*.sym 6 | examples/**/*.cpu.sym 7 | examples/**/*.smp.sym 8 | examples/**/*.dmap 9 | examples/**/*.dnfo 10 | examples/**/*.srm 11 | examples/**/*.bin 12 | tests/**/*.sfc 13 | tests/**/*.sym 14 | tests/**/*.dsym 15 | tests/**/*.dmap 16 | tests/**/*.srm 17 | extras/NaturalDocs/config/Data 18 | dsp1b.bin 19 | examples/X-WIP 20 | *.psd 21 | *.swp 22 | *.dnfo 23 | **/_build_* 24 | **/*.palette 25 | **/*.tiles 26 | **/*.map 27 | **/*.m7d 28 | **/*.brr 29 | **/*.lz4 30 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tools/cc65"] 2 | path = tools/cc65 3 | url = https://github.com/cc65/cc65.git 4 | [submodule "tools/superfamicheck"] 5 | path = tools/superfamicheck 6 | url = https://github.com/Optiroc/SuperFamicheck 7 | [submodule "tools/brrtools"] 8 | path = tools/brrtools 9 | url = https://github.com/Optiroc/BRRtools.git 10 | [submodule "tools/lz4"] 11 | path = tools/lz4 12 | url = https://github.com/lz4/lz4.git 13 | [submodule "tools/superfamiconv"] 14 | path = tools/superfamiconv 15 | url = https://github.com/Optiroc/SuperFamiconv.git 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 David Lindecrantz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean submodules docs 2 | 3 | default: cc65 superfamiconv superfamicheck brrtools lz4 4 | 5 | all: clean default 6 | 7 | cc65: submodules 8 | @$(MAKE) -C tools/cc65 bin -j4 9 | 10 | superfamiconv: submodules 11 | @$(MAKE) -C tools/superfamiconv -j4 12 | 13 | superfamicheck: submodules 14 | @$(MAKE) -C tools/superfamicheck 15 | 16 | brrtools: submodules 17 | @$(MAKE) -C tools/brrtools 18 | 19 | lz4: submodules 20 | @$(MAKE) lz4 -C tools/lz4/programs -j4 21 | 22 | submodules: 23 | git submodule update --init --recursive 24 | 25 | docs: 26 | @rm -frd docs 27 | @mkdir -pv docs 28 | sassc extras/NaturalDocs/config/libsfx.scss extras/NaturalDocs/config/libsfx.css 29 | extras/NaturalDocs/bin/NaturalDocs -r -i include -o HTML docs -p extras/NaturalDocs/config -s libsfx -t 2 30 | @rm -frd ./docs/index && rm -frd ./docs/search && rm -frd ./docs/javascript 31 | @cp ./extras/NaturalDocs/config/readme ./docs/README.md 32 | @cp ./extras/NaturalDocs/config/favicon.ico ./docs/favicon.ico 33 | 34 | clean: 35 | @$(MAKE) clean -C tools/cc65 36 | @$(MAKE) clean -C tools/superfamiconv 37 | @$(MAKE) clean -C tools/superfamicheck 38 | @$(MAKE) clean -C tools/brrtools 39 | @$(MAKE) clean -C tools/lz4/programs 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libSFX 2 | A Super Nintendo assembler development framework featuring: 3 | 4 | * Basic system runtime for initialization and interrupt handling 5 | * 65816 register size tracking macros to minimize rep/sep instructions (and mental overhead) 6 | * Full set of memcpy/memset routines for efficiently transferring data to different parts of the system 7 | * Some useful data structures with allocation and accessor macros (FIFO and FILO are currently implemented) 8 | * S-SMP communication and SPC playing routines. 9 | * LZ4 decompression 10 | * Mouse driver 11 | * Graphics conversion via [SuperFamiconv](https://github.com/Optiroc/SuperFamiconv) 12 | * BRR audio encoding using [BRRtools](https://github.com/Optiroc/BRRtools) 13 | * ROM image validation via [SuperFamicheck](https://github.com/Optiroc/SuperFamicheck) 14 | * Sublime Text [syntax definitions](./extras/SublimeText) 15 | 16 | Documentation available at [optiroc.github.io/libSFX](https://optiroc.github.io/libSFX). 17 | 18 | libSFX is developed by David Lindecrantz and distributed under the terms of the [MIT license](./LICENSE). 19 | 20 | 21 | ## dependencies 22 | A C/C++ toolchain, make, git and a decent command line interface. 23 | 24 | Unix-like (Mac, Linux, etc.) systems should be ready to go out of the box. If you're running Windows the best option is to install [Cygwin](https://cygwin.com/install.html) and make sure you include the `git` and `mingw64` toolchain (`mingw64-x86_64-binutils`, `mingw64-x86_64-gcc-core` and `mingw64-x86_64-gcc-g++`) packages. 25 | 26 | 27 | ## building 28 | First you need to build the bundled tools, which are included as git submodules. Simply run `make` from the libSFX root path to initialize the submodules and build the tools. 29 | 30 | Now the toolchain is in place and you should be able to run `make` from any of the example directories to assemble the source files and link a Super Nintendo ROM image (*.sfc). 31 | 32 | 33 | ## setting up a project 34 | For the most basic setup, copy `examples/Template` to a location of your liking. Then edit `Makefile` and make sure that `libsfx_dir` points to the libSFX root directory. 35 | 36 | For project customization – for example extending the ROM size, adding SRAM or special code segments, or changing the default stack and scratchpad sizes – the build script looks for two files in the project directory; `libSFX.cfg` and `Map.cfg`. If these aren't found (like in the Template project), the defaults inside `$(libsfx_dir)/include/Configurations` are used. 37 | 38 | To override the defaults, simply copy these two files into your project directory and edit them to your liking. In [include/Configurations](./include/Configurations/) there's a few additional Map.cfg examples. You may also check out the [example](./examples/SixteenMegaPower) [projects](./examples/SuperFX) to see how a project can be customized. 39 | 40 | 41 | ## acknowledgments 42 | libSFX includes the following code and snippets: 43 | 44 | * SPC-700 assembler for ca65 and S-SMP transfer routines by [Blargg](http://blargg.8bitalley.com) 45 | * GSU assembler for ca65 by [ARM9](https://github.com/ARM9/casfx) 46 | * ca65 define/undefine macros by [Movax12](http://forums.nesdev.com/memberlist.php?mode=viewprofile&u=4680) 47 | 48 | 49 | ## resources 50 | * [fullsnes](http://problemkaputt.de/fullsnes.htm) - comprehensive SNES reference 51 | * [ca65 users guide](https://cc65.github.io/doc/ca65.html) 52 | * [SNESdev forum](http://forums.nesdev.com/viewforum.php?f=12) 53 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | libSFX documentation: [optiroc.github.io/libSFX](http://optiroc.github.io/libSFX) 2 | 3 | Generated with [NaturalDocs](http://www.naturaldocs.org) 4 | -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Optiroc/libSFX/35440f9274f6b6d609ae0b3f51721b03a6b27892/docs/favicon.ico -------------------------------------------------------------------------------- /docs/files/CPU_Math-i.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |CPU_Math.i | |
Macros | |
mulu | Unsigned multiplication (S-CPU MMIO) |
divu | Unsigned division (S-CPU MMIO) |
muls | Signed multiplication (S-PPU MMIO) |
Unsigned multiplication (S-CPU MMIO)
If :out: parameter is omitted, get result in RDMPYL/H (uint16) after 5 cycles
:in: n1 Multiplicand (uint8) a/x/y Requires RW a8 or i8 12 | constant Uses a, sets RW a8 13 | :in: n2 Multiplier (uint8) a/x/y Requires RW a8 or i8 14 | constant Uses a, sets RW a8 15 | :out?: ret Product (uint16) a/x/y Sets RW a16 or i16
lda #$88 16 | mulu a,$7f, x ;Returns x = #$4378
Unsigned division (S-CPU MMIO)
If :out: parameters are omitted, get quotient in RDDIVL (uint16) and remainder in RDMPYL (uint16) after 13 cycles
:in: n1 Dividend (uint16) a/x/y Requires RW a16 or i16 19 | constant Uses x, sets RW i16 20 | :in: n2 Divisor (uint8) a/x/y Requires RW a8 or i8 21 | constant Uses a, sets RW a8 22 | :out?: ret Quotient (uint16) a/x/y Sets RW a16 or i16 23 | :out?: retr Remainder (uint16) a/x/y Sets RW a16 or i16
Signed multiplication (S-PPU MMIO)
Not available during Mode 7 rendering If :out: parameter is omitted, result available in MPYL/M/H (sint24) immediately
:in: n1 Multiplicand (sint16) x/y Uses a, sets RW a8 26 | constant Uses a, sets RW a8 27 | :in: n2 Multiplier (sint8) a Requires RW a8 28 | constant Uses a, sets RW a8 29 | :out?: ret Product (sint24) ax/ay Sets RW a8i16
Map.cfg is the configuration file passed to the ld65 linker.
It consists of two main parts∶
In include/Configurations there are several template configuration files for different ROM sizes and memory layouts.
For full documentation of ld65 and its configuration refer to the official documentation.
Optional package adding SNES SFM1 Mouse support
To link mouse support in a project, simply add Mouse to libsfx_packages in the project makefile.
# Use packages 8 | libsfx_packages := Mouse
The mouse package adds mouse polling to the regular automatic joypad polling. By default the driver will look for a mouse in port 1. This is configurable with the SFX_MOUSE variable∶
SFX_MOUSE = MOUSE1 | MOUSE2
Mouse read-out data is stored in MOUSE_data structs with the following members∶
.struct MOUSE_data 9 | status .byte 10 | sensitivity .byte 11 | buttons_cont .byte 12 | buttons_trig .byte 13 | delta_x .byte 14 | delta_y .byte 15 | cursor_x .word 16 | cursor_y .word 17 | .endstruct 18 | 19 | Possible status values: 20 | .define MOUSE_status_nc $00 ;Mouse not connected 21 | .define MOUSE_status_ok $01 ;Mouse connected and working 22 | .define MOUSE_status_error $80 ;Hardware error 23 | 24 | Button presses are stored in the follwing bits of buttons_cont/buttons_trig: 25 | Bit 26 | 7 Right button 27 | 6 Left button
The driver updates all members during each VBlank interval at zero page locations SFX_mouse1 and SFX_mouse2. The data can be addressed like this∶
;Load cursor vertical position 28 | lda z:SFX_mouse1+MOUSE_data::cursor_y
The ‘sensitivity’ member is used to set the mouse acceleration curve.
;Set normal mouse sensitivty 29 | lda #MOUSE_sensitivity_normal 30 | sta SFX_mouse1+MOUSE_data::sensitivity 31 | 32 | ;Possible values 33 | .define MOUSE_sensitivity_slow 0 34 | .define MOUSE_sensitivity_normal 1 35 | .define MOUSE_sensitivity_fast 2
All other members are read-only.
If no mouse is detected and SFX_JOY is set for the port, the driver automatically falls back to joypad input. D-pad input is then mapped to delta and cursor, and the A/X buttons is mapped to the left/right buttons.
The driver can optionally be “hugged” by special strings that – I suppose – some emulators rely on to automatically enable mouse input. Real hardware (and consequently, real emulators) doesn’t care.
SFX_MOUSE_STRINGS = ENABLE
SMP_Util.i | |
Macros | |
DSP_get | Get DSP register |
DSP_set | Set DSP register |
SMP_exit | Return to IPL (clears timers, zeropage) |
libSFX is a Super Nintendo assembler development framework. It aims to add as little magic and abstraction to the programming as possible while removing the tedium of boilerplate and mandatory micro management of configuration files.
By leveraging the ca65 assembler and several macro packs it can create object code for∶
Using (and optionally extending) the included makefiles and configurations it’s a relative breeze to get SNES code up and running!
Anatomy libSFX consists of a small runtime that mainly initializes the system and handles hardware interrupts (which can be redirected in software). The real rice of the library are the macros included and documented here.
Packages There are also opt-in packages, adding a bit more to the object code size, for non-core features like input peripherals and data decompression. These are documented in the “Packages” section.
Tools The ca65 toolchain and a couple of support tools are included as submodules in the libSFX/tools directory. These are the only tools used by the libSFX.make makefile, making libSFX pretty much self contained. Running make from the repository root will sync the submodules and build the tools.
SFX 🤷️ Why is it called libSFX? That sounds like a library of sound effects. Well, yes it does. However, “SFX” was also how Nintendo refered to the SNES/SFC in the very early developer documentation. It was through photocopied binders of those documents – with severe generation loss! – I first learned about the innards of the Super Nintendo, and I have lovingly cultivated a habit of using SFX to prefix and suffix my SNES code over the years.
Get started Clone, fork or download the repository at github.com/Optiroc/libSFX and dive into the Make documentation.
libSFX is developed by David Lindecrantz and distributed under the terms of the MIT license.