Releases: pubby/nesfab
NESFab 1.5
This update is primarily for bug fixes and optimization tweaks, but contains a few new things.
Clang Support
NESFab seemingly compiles under the clang++ compiler now, meaning it might be possible to compile natively on Mac.
Flash Saves
I've improved support for saving to flash memory, adding a +sector
modifier to align data to sectors, and a --sector-size
compiler option.
See examples/flash_save
to see an example.
NESFab 1.4
This update includes bug fixes and a few features.
MMC5 Support
The mmc5
mapper is now supported, with some initial library code at /lib/mapper/mmc5.fab
. NESFab can take advantage of MMC5's multiplication hardware when compiling with --unsafe-bank-switch
. The NESFab implementation of MMC5 expects 32K banking to always be used.
See examples/mmc5
to see an example.
Rainbow Mapper Support
The rainbow
mapper is now supported, with some initial library code at /lib/mapper/rainbow.fab
. The NESFab implementation of Rainbow expects 32K banking to always be used.
See examples/rainbow
and examples/wifi
to see an example.
Expansion Audio
The PUF music driver now implements expansion audio for MMC5 and Rainbow (modified VRC6).
charmap
offsets
You can now include an offset incharmap
definitions, which defines the value of the first element:
charmap foo("abc", 8)
: stows /strings
Here, a
will have a value of 8
.
Logging Library
Miau's Lua logging code was adapted into lib/logging
, which provides printf support in emulators like FCEUX and Mesen.
For better support, the language now reserves address $00
for debugging, and addresses $100-$107
can be used for additional information.
NESFab 1.3
This update contains a few features and a few bug fixes.
Legal-only Instructions
Building the compiler with make ISA=legal
results in a NESFab executable that only generates legal instructions. As illegal instructions have better performance, the default implementation will remain as-is.
Because this is the first release to support this feature, I've included a nesfab_legal.exe
in the Windows release. I haven't decided if future releases will do the same.
Conditional byte blocks
You can now use if
and else
inside byte blocks, so long as the condition can be checked at compile time. This enables data to be included / excluded based on compile-time knowledge.
asm fn foo() U
: employs
default
if SOME_CONSTANT == 1
lda #10
else
lda #32
sta &return
rts
The current implementation cannot handle labels inside of conditionals, so watch out for that caveat.
PUF Audio Update
More speeds
A common complaint was that PUF music had to be speed 4 or slower. This update removes that restriction, allowing any speed from 1 to 30, albeit with reduced performance for speeds 1 to 3.
Changeable speeds
You can now use puf.set_speed
to change the speed of a song while it is playing. This can be used to hasten the music when gameplay gets tense.
Controller Update
Controller reading has received a small update to support more than 2 players.
--controllers
compiler flag
You can now set the --controllers
option, used to mark the maximum number of controllers used. This exports a __controllers
option in the language, which library code (or your code) can reference.
The default controller reading in lib/nes.fab
checks the __controllers
option to determine its implementation. For 1 player, it only reads the first controller. For 2 players, it reads both. For 3 and 4 players, it checks for the presence of the NES Four Score adapter. No higher player count is supported yet.
See examples/4_player
to see the Four Score used.
Famicom Controller Support
As mentioned, the default controller code can handle the Four Score adapter. Unfortunately, the Japanese Famicom supports many more styles of adapters, which complicates things.
The new file lib/famicom.fab
contains a controller reading implementation which handles all of these adapters, including the Four Score. It was based on code written by Miau, shared on the forums. Currently, this implementation does not handle the DPCM error, so the DMC channel should not be used.
SNES Mouse Support
The library file lib/mouse.fab
implements SNES mouse support.
Currently, this implementation does not handle the DPCM error, so the DMC channel should not be used.
See examples/mouse
to see the SNES Mouse used.
CNROM change
Previously, CNROM was changing banks by writing to an address directly, e.g. {$8000}(my_bank)
. As this method cannot handle bus conflicts, CNROM was changed to use the state
keyword, e.g. state(my_bank)
.
NESFab 1.2
Overview
Primarily bug fixes, with a few features.
-unroll
and +unloop
You can now disable loop unrolling using the -unroll
modifier:
for U i = 0; i < 10; i += 1
: -unroll
{PPUDATA}(0)
You can now force loops to be fully unrolled using the +unloop
modifier:
for U i = 0; i < 10; i += 1
: +unloop
{PPUDATA}(0)
These modifiers are hints. They work most of the time, but there may be a few rare cases where they are ignored.
Donut CHR compression
NESFab now supports Donut compression, which is perhaps the best form of CHR compression. See lib/decompress/donut.fab
for the decompressor.
Macro-based geometry.fab
There's now a generic version of lib/math/geometry.fab
called lib/math/geometry.macrofab
, which lets you change the types and prefixes. The original file remains, for those who prefer simplicity.
NESFab 1.1
Overview
This version contains several prominent bug fixes, and a few small features:
Metasprite library reorganization and animation.fab
I've moved lib/metasprite.fab
into its own folder: lib/metasprite/metasprite.fab
.
This folder also contains a new library file, animation.fab
, which contains code for animating metasprites.
To see this file used in an example, check out examples/animation
.
Paired hardware writes (and reads)
Using the following syntax, you can now execute two hardware writes consecutively:
{foo_addr, bar_addr}(foo_value, bar_data)
This syntax ensures that the hardware writes will occur as close together as possible, without any execution happening in-between.
Why is this necessary?
First, it's helpful when writing scrolling code to minimize PPU glitches. With this syntax, there's less concern of timing windows.
More importantly though, it's important when interfacing mappers like MMC3, which require two writes to interface.
Consider the code below which doesn't use this feature:
{$8000}(0)
{$8001}(calc_bank())
NESFab may decide to call the function calc_bank
between the the two hardware writes. If this occurs, the first write will be clobbered as calling a function writes to $8000
too.
With a paired write, the problem is avoided, as calc_bank
must occur before both of the two writes:
{$8000, $8001}(0, calc_bank())
--ctags
Option
The --ctags
option can be used to generate a ctags file. When loaded into a text editor, the ctags file can be used to quickly navigate to definitions.
To use ctags in VSCode, install the following extension: https://marketplace.visualstudio.com/items?itemName=jtanx.ctagsx
--ram-init
, --sram-init
, --vram-init
Options
These new compiler flags cause memory to be zero'd out on boot. Although not recommended (it's better to zero-init using code), I've gotten a few requests for these so I've decided to add them.
NESFab 1.0
Overview
This is a milestone. If you're an optimist, you can think of NESFab as going from beta to gold. If you're a pessimist, you can think of it as going from alpha to beta. Either way, 1.0 is a major version bump.
There's a decent amount of bugfixes in this release, along with a few features.
Breaking change: Library reorganization
I've moved various files in thelib/
folder to sub-folders such as lib/math/
and lib/audio/
. Also, I've renamed a few files and functions (such as base10
-> base_10
to better match NESFab's naming scheme. My apologies for this, but the 1.0 release seemed like a good time to make these changes.
file
Expressions
Previously, the file
keyword could only be used in byte blocks. Now, it can be used as an expression to produce values of type U{}
.
Function pointers
I've added experimental support for function pointers, but this support is somewhat gimped. Function pointers require functions to be partitioned into sets, and function pointers can only be called from a single thread of execution. Also, for the time being, asm
support doesn't exist for function pointers. But there is some support in 1.0
.
To see this feature being used, check out examples/fn_ptr/
.
--multicart
compiler option
The --multicart action53
compiler flag can be used to ensure compatibility with the Action 53 multicart mapper. This is intended to be used for the yearly NESDev competition.
JSON mapfab imports
The mapfab
keyword can now import .JSON files exported by MapFab.
32x32 Meta-meta-tiles
The mapfab
keyword now supports the mmt_32
target, which generates 32x32 metametatiles.
To see this feature being used, check out examples/meta_meta_tiles/
.
More examples
examples/platformer/
shows the basics of a platforming gameexamples/scrolling_8_way/
shows how to achieve 8-way scrollingexamples/rope/
shows some interesting rope physicsexamples/billiards/
shows bouncing ball physics
Patreon
NESFab 0.9
Overview
This release is a mix of bug fixes, features, and performance enhancements.
MapFab support and the mapfab
keyword
MapFab is a new level editor designed to be used with NESFab. Its data files can be imported into NESFab using the new mapfab
keyword:
mapfab(raw, "project.mapfab", "chr", "palette", "metatiles", "level")
This keyword invokes user-defined macros for each definition in the .mapfab
file, allowing one to customize how the data is formatted in the game.
The new example examples/mapfab
illustrates how this works.
chrrom
offsets
You can now have multiple chrrom
definitions. An integer following the chrrom
keyword specifies what offset the data will go.
chrrom $1000
(...)
chrrom $0000
(...)
VEC types
VECs are resizeable arrays that only exist at compile time. Their syntax is similar to regular arrays (TEAs), but their length is not part of their type signature:
ct Int{} my_vec = Int{}(1,2,3,4,5) // Type{} syntax means VEC
The purpose of VECs is that they let you write compile-time functions that generate or resize arrays. Two new keywords: push
and pop
were added to facilitate this.
ct fn foo(Int{} in) Int{}
Int{} out = Int{}()
for U i = 0; i < len(in); i += 1
push(out, in{i})
push(out, in{i})
return out
Unlike other types arrays, VECs can be multi-dimensional.
Patreon
I've set up a Patreon to help development:
NESFab 0.8
Overview
This release is a mix of bug fixes, features, and performance enhancements.
Mapper addition: MMC3 and UNROM
Experimentally, MMC3 and UNROM are now supported. These mappers involve a fixed bank, which requires the use of the +static
modifier.
Language addition: read
and write
The keywords read
and write
allow data of arbitrary types to be read/written using pointers.
Language addition: nesfab-dir
The --nesfab-dir
option is used to specify the directory of the NESFab installation. This should be used instead of specifying lib
files using complicated relative paths.
nesfab-dir = ../../
input = lib/nes.fab
input = lib/palette.fab
Likewise, the NESFAB
environment variable can be used to set --nesfab-dir
globally.
Language addition: sloppy
The --sloppy
compiler flag, and +sloppy
/ -sloppy
modifiers can be used to speed up compilation times at the cost of optimization.
Language addition: SRAM
NESFab now supports mappers with 8KiB of additional cartridge RAM (SRAM), which can be enabled using the option --sram
. Variables can be forced to use SRAM using the modifiers +sram
and -sram
.
Language addition: Private identifiers
Global identifiers prefixed with _
are now private to the file they're in.
fn foo() // not private
fn _bar() // private
Breaking language change: PP
and PPP
pointers.
CC
and CCC
pointers now point to ROM data only. To point to either ROM data, or RAM data, new PP
and PPP
types were introduced.
Breaking library change: pbz.fab
and rlz.fab
The decompression functions in these files were changed to return a pointer to the end of their data.
PBZ decompression interface was redesigned to better match the rest of the library. This will break existing code.
NESFab 0.7
Overview
Several important bugfixes in this release. Many thanks to the bug reporters!
Library addition: trig.fab
This file contains routines for a few functions from trigonometry - the ones useful for game dev.
To see this file being used, check out "examples/trig".
NESFab 0.6
Overview
A large number of bug fixes, and a few new optimizations.
Language change to groups
In previous versions of NESFab, each group was either a vars
group, a data
group, or an omni data
group. In 0.6 however, groups can be any combination of these.
For example, the following code is now valid:
vars /my_group
// ...
data /my_group
// ...
To implement this change, changes were made to the stows
and employs
modifiers.
stows
now puts strings in a regulardata
block. To put them in anomni data
block, usestows omni
.employs
works as it always does, but one can useemploys vars
oremploys data
to employ only those specific blocks of each group.
Library addition: base10.fab
This file contains routines for converting between numbers and a base-10 representation. It is useful if you want to display numbers on the screen.
To see this file being used, check out "examples/counter".
Library addition: palette.fab
This file extends the palette code from "lib/nes.fab", specifically adding routines to fade in and out. In the future, more effects may be added.
To see this file being used, check out "examples/fade".