Skip to content

Releases: pubby/nesfab

NESFab 1.8

19 Sep 05:01

Choose a tag to compare

This version contains several important bug fixes and a few new features. Please review the list of breaking changes. This release was a little rushed, so issues may arise.

9/22: hotfixes were done. Please download the hotfixed files.

NROM128 support

NESFab can now create 16KB NROM files.

I added this in case anyone wants to participate in the Game Genie Mini Jam.

Anonymous labels

asm fn and fn now accept anonymous labels.

Syntax:

label+amount
label-amount

Where +amount is a number referring to upcoming anonymous labels, and -amount is a number referring to previous anonymous labels.

Example:

label
    jmp label-1 // Jump to the previous label
    jmp label+1 // Jump to the next label 
    jmp label+2 // Jumps 2 labels ahead 
label
    nop
label

Arg-less [] and {}

The [] and {} operator can now be used without an index. In such cases, the index is treated as 0.

Example:

my_array[] = 10 // Equivalent to my_array[0] = 10

Index types: I and II.

There are two new types, I and II. These represent indexes into globally-defined arrays.

Syntax:

I.array
II.array

Where array is the name of a globally-defined array.

Values of I and II store indexes, just like U or UU. However, they also behave like pointers in that you can dereference them using [] or {}.

Example:

vars
    UU[10] some_array // Define a global array

fn example()
    I.some_array my_index = 5 // Create an index value pointing to the [5] position.
    my_index[] = 10           // Equivalent to some_array[5] = 10

Index types reduce the typing involved when working with arrays, but also come with some extra safety.

Feel free to ask in the Discord if you're confused by these.

Stronger type safety on [] and {} (breaking change)

The [] and {} operators now require their index to match type U and UU respectively. Before, implicit conversions were allowed, meaning {} could also accept U and Bool.

Weaker type safety on hardware writes

Hardware writes using the {}() syntax now cast the argument to U in more situations. This allows one to write S values, for example, without an explicit cast.

push / pop optional index argument

For Vec types, you can now push and pop into specific indexes, instead of only the last element.

Syntax:

push(vec, value, index)
pop(vec, index)

+inherit modifier

Adding the +inherit modifier to a struct field allows the owning struct to copy some of its behavior. Specifically, the parent struct will implicitly cast to the inherited field, and the inherited field's own fields will be accessible.

Example:

Struct Bar
    U member
struct Foo
    Bar bar : +inherit

fn example()
    Foo foo = Foo()
    Bar bar = foo // Implicit cast
    foo.member = 10 // Access Bar members

palette.fab rename: fade_out -> fade_out_custom (breaking change)

The fade_out / fade_in functions were intended to make it easy to define your own fade functions. The problem was, they took up the best names for these functions! Thus, they have been renamed.

lib/metasprite/metasprite.fab

I've added some extra functions to this library file, including ones that use U positions instead of SS.

lib/step_counter.fab

This tiny library file implements a common pattern: counting the number of times NMI was waited on. This is similar to checking nmi_counter, but does not increment on lag frames.

lib/uvec.fab

This library file contains ct functions for manipulating U{} values.

NESFab 1.7

13 Aug 02:16

Choose a tag to compare

This version contains several important bug fixes and a couple optimizations.

Named chrrom regions (breaking change)

You can now give names to chrrom blocks, allowing you to access their labels:

chrrom foo
    label bar
        file(fmt, "data.png")

Accessing the label returns the CHRROM address:

UU addr = UU(foo.bar)

The chrrom syntax now requires that the offset field be placed inside parenthesis. This is a breaking change.

chrrom (100)    // Before the parentheses weren't necessary.
chrrom foo(200) // You can also include names.

SRAM compiler options

You now have more ways to customize SRAM allocation, using the --sram-alloc and --sram-size options.

__multiply

The runtime's multiply function is now exported as the __multiply keyword. This allows you to perform multiplication in asm fn assembly code.

Better Rainbow mapper support

lib/mapper/rainbow.fab has received numerous improvements, and may continue to evolve over the coming months.

Warning: Upcoming MapFab change

I'm going to be replacing object name functionality in MapFab, likely by the next release. The object name field will be used to invoke additional macros, rather than defining ct Int values.

NESFab 1.6 Mac Snapshot

16 Mar 16:30

Choose a tag to compare

This snapshot was requested by @vtbassmatt for the purposes of Mac Homebrew.

See: https://github.com/pubby/nesfab/releases/tag/v1.6 for the actual release.

NESFab 1.6

15 Mar 07:57

Choose a tag to compare

This update contains mostly bug fixes, with a few features.

Better comparisons

The == and != operator now work on most types, including structs and arrays.

+static_fixed

This modifier behaves like +static, but only for mappers with a fixed bank.

push and pop in asm fn.

These two assembly statements push the current bank onto the stack, or pop it. They're most useful for writing +static code.

lib/math/bit.fab

This file contains some useful bit operations, such as calculating the popcount.

NESFab 1.5

30 Jul 14:02

Choose a tag to compare

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

25 Apr 21:43

Choose a tag to compare

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

09 Dec 03:47

Choose a tag to compare

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

22 Oct 14:20

Choose a tag to compare

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

18 Sep 03:55

Choose a tag to compare

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

29 Aug 01:15

Choose a tag to compare

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 game
  • examples/scrolling_8_way/ shows how to achieve 8-way scrolling
  • examples/rope/ shows some interesting rope physics
  • examples/billiards/ shows bouncing ball physics

Patreon

https://patreon.com/Pubby434