`



Learn Multi platform 6502 Assembly Programming... For Monsters!

Platform Specific Lessons


Platform Specific Series - Now we know the basics, lets look at the details of the platforms we're covering!
    Lesson P1 - Bitmap Functions on the BBC

Lesson P2 - Bitmap Functions on the Atari 800 / 5200

Lesson P3 - Bitmap Functions on the Apple II

Lesson P4 - Bitmap Functions on the Atari Lynx

Lesson P5 - Bitmap Functions on the PC Engine (TurboGrafx-16)

Lesson P6 - Bitmap Functions on the NES / Famicom

Lesson P7 - Bitmap Functions on the SNES / Super Famicom

Lesson P8 - Bitmap Functions on the VIC-20

Lesson P9 - Bitmap Functions on the C64

Lesson P10 - Joystick Reading on the BBC

Lesson P11 - Joystick Reading on the Atari 800 / 5200

Lesson P12 - Joystick Reading on the Apple II

Lesson P13 - Joystick Reading on the Atari Lynx

Lesson P14 - Joystick Reading on the PC Engine (TurboGrafx-16)

Lesson P15 - Joystick Reading on the NES / Famicom and SNES

Lesson P16 - Joystick Reading on the VIC-20

Lesson P17 - Palette definitions on the BBC

Lesson P18 - Palette definitions on the Atari 800 / 5200

Lesson P19 - Palette definitions on the Atari Lynx

Lesson P20 - Palette definitions on the PC Engine (TurboGrafx-16)

Lesson P21 - Palette Definitions on the NES

Lesson P22 - Palette Definitions on the SNES / Super Famicom

Lesson P22 (z80) - Sound with the SN76489 on the BBC Micro

Lesson P23 - Sound on the Atari 800 / 5200

Lesson P23 (Z80) - Sound with the 'Beeper' on the Apple II

Lesson P24 - Sound on the Atari Lynx

Lesson P25 - Sound on the PC Engine (TurboGrafx-16)

Lesson P26 - Sound on the NES / Famicom

Lesson P27 - Sound on the SNES / Super Famicom: the SPC700

Lesson P28 - Sound on the SNES / Super Famicom: Writing ChibiSound

Lesson P29 - Sound on the on the VIC-20

Lesson P30 - Sound on the C64

Lesson P31 - Hardware Sprites on the Atari 800 / 5200

Lesson P32 - Hardware sprites on the Atari Lynx

Lesson P33 - Hardware Sprites on the PC Engine (TurboGrafx-16)

Lesson P34 - Hardware Sprites on the NES / Famicom

Lesson P35 - Hardware Sprites on the SNES / Super Famicom

Lesson P36 - Hardware Sprites on the C64

Lesson P37 - Screen settings with the CRTC on the BBC Micro!

Lesson P38 - Character Block Graphics on the PET

Lesson P39 - Key reading on the PET

Lesson P40 - Sound on the PET

Lesson P41 - Multiple layers on the SNES

Lesson P42 - Color maths on the Super Nintendo

Lesson P43 - Splitscreen scrolling and Sprite 0 Hit on the NES!

Lesson P44 - The NES Zapper!



Lesson P60 - Multiplatform Software tilemap on the Commodore 64 (Mintile)
We've written a minimal multiplatform Tile/Sprite routine in the Mintile series, Now, lets take a look at the platform specific code to quickly draw tiles to the screen on the Commodore 64.


c64_MinTile.asm



MinTile is a multiplatform 'engine' which allows us to define our game code in a common way, and let the platform specific code handle the platform specific work!... it was used to write 'ChibiFighter' on the Z80.

For more details on Mintile, see the Mintile series here...

Tile Drawing Routines

Our example shows an onscreen tilemap and two software 'sprites'.
Mintile supports scrolling and X-Flip (but not Y-flip)
The 'sprites' are actually miniature tile maps, this is to reduce the amount of platform specific code.
these are all created via the DoStrip platform specific routine, which we'll look at here.

In 4 color mode the tiles are 4x8 pixels, giving a screen of 32x24 visible tiles.

We don't use the full screen width on the C64 - this is to make porting games from the other 256x192 screen systems easier.
The MinTile shared routine provides calculation and tilemap planning, however we need to do the actual job of 'Drawing' in the platform code.

The code can horizontally flip tiles, on the C64 we use a 256 byte lookup table, to 'pre-calculate the flipping of the 4 pixels in a 4 color byte, or 8 pixels in a 2 color byte
The LUT needs to be byte aligned, so &8100 or &FE00 would be fine, but &FE01 would not!
We have a 'GetScreenPos' function , which calculates the VRAM destination for the sprite objects.
It calculates a VRAM destination in z_H and z_L, from an X,Y source in z_B,Z_c in logical units (pairs of pixels)

For speed and convenience, we limit our Y co-ordinates to whole tiles.

The screen is 40 bytes wide, and bytes are consecutive in ram within an 8 pixel tall block, so we multiply the Y-line by 40*8.

The screen base is $6000, and as our tilemap is only 32 bytes wide, we center it by adding $20 - skipping 4 blocks
DoStrip will draw one horizontal strip of tiles.
The job is defined by the following zero page entries

z_HL = VRAM Dest
z_BCs = Tilemap
z_DEs = Pattern data
z_IYL = TileMap Width

X=0 throughout the function

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)

If using the tile cache we zero the tiles after they are drawn.

We calculate the address of the source pattern data by multiplying the tile number by 8
We need to transfer the 8 bytes of the tile.

as all the vertical bytes in a tile are in consecutive VRAM addresses, We use Y as the offset for the pattern source and VRAM destination

We transfer all 8 bytes, then Increment our Tilemap source, and move to the next horizontal tile by adding 8 to the VRAM destination.


DoStripRev has essentially the same function, however it horizontally flips the pattern data via the lookup table.

We're using z_BC to point to our lookup table, by loading z_c with the data we want to Xflip, we can read back the flipped byte from (z_bc)





Lesson P61 - Multiplatform Software tilemap on the Atari Lynx (Mintile)
We've written a minimal multiplatform Tile/Sprite routine in the Mintile series, Now, lets take a look at the platform specific code to quickly draw tiles to the screen on the Atari Lynx.


LNX_MinTile.asm



MinTile is a multiplatform 'engine' which allows us to define our game code in a common way, and let the platform specific code handle the platform specific work!... it was used to write 'ChibiFighter' on the Z80.

For more details on Mintile, see the Mintile series here...

On the Lynx due to the small screen size we'll use tiles of 6x6.

This is rather irregular compared to our normal 8x8, however it's a reasonable trade off between our typical 8x8, and a tiny 4x4

Tile Drawing Routines

Our example shows an onscreen tilemap and two software 'sprites'.
Mintile supports scrolling and X-Flip (but not Y-flip)
The 'sprites' are actually miniature tile maps, this is to reduce the amount of platform specific code.
these are all created via the DoStrip platform specific routine, which we'll look at here.

On the Atari Lynx we're using 6x6 tiles giving a screen size of 26x17 tiles with a 2 pixel border on the left and right of the screen
The MinTile shared routine provides calculation and tilemap planning, however we need to do the actual job of 'Drawing' in the platform code.

The code can horizontally flip tiles, on the Lynx we use a 256 byte lookup table, to 'pre-calculate the flipping of the 2 pixels in a 16 color byte
The LUT needs to be byte aligned, so &8100 or &FE00 would be fine, but &FE01 would not!
We have a 'GetScreenPos' function , which calculates the VRAM destination for the sprite objects.
It calculates a VRAM destination in z_H and z_L, from an X,Y source in z_B,Z_c in logical units (pairs of pixels)

Mintile is designed for tiles of 4x4... As we're using an irregular tile size of 6x6 one tile is still 4x4 logical units - so one Logical unit is 1.5 pixels on the Lynx!

we multiply our Ypos by 1.5, and multiply this by 80 bytes (80 bytes per line)

The screen base is memory address $C000
The screen has a 1 byte border around the 26x17 visible tilemap, so we add 1 to compensate.
DoStrip will draw one horizontal strip of tiles.
The job is defined by the following zero page entries

z_HL = VRAM Dest
z_BCs = Tilemap
z_DEs = Pattern data
z_IYL = TileMap Width

X=0 throughout the function

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)
If using the tile cache we zero the tiles after they are drawn.

We calculate the address of the source pattern data by multiplying the tile number by 18 (As that's how many bytes a 6x6 pixel tile uses)
We need to transfer 3 bytes per line, for 6 lines

we add 80 bytes to the VRAM destination after each line.


Once the tile is done we move to the next tile position in BC, and move across the screen 1 tile by adding 3 to HL



DoStripRev has essentially the same function, however it horizontally flips the pattern data via the lookup table.

We're using z_BC to point to our lookup table, by loading z_c with the data we want to Xflip, we can read back the flipped byte from (z_bc)







Lesson P62 - Multiplatform Software tilemap on the Vic 20
We've written a minimal multiplatform Tile/Sprite routine in the Mintile series, Now, lets take a look at the platform specific code to quickly draw tiles to the screen on the Vic 20


VIC_MinTile.asm


MinTile is a multiplatform 'engine' which allows us to define our game code in a common way, and let the platform specific code handle the platform specific work!... it was used to write 'ChibiFighter' on the Z80.

For more details on Mintile, see the Mintile series here...

The VIC 20 doesn't have 'real' bitmap graphics, it uses character blocks!

We'll export our character with Akusprite Editor, and create a 'translation table' to flip the blocks to do the best we can on this system.

Tile Drawing Routines

Our example shows an onscreen tilemap and two software 'sprites'.
Mintile supports scrolling and X-Flip (but not Y-flip)
The 'sprites' are actually miniature tile maps, this is to reduce the amount of platform specific code.
these are all created via the DoStrip platform specific routine, which we'll look at here.

On the VIC Each tile is a single character block
Mintile sets the graphics blocks, but does not currently use colors.

here we fill the entire screen with a solid color
We have a 'GetScreenPos' function , which calculates the VRAM destination for the sprite objects.
It calculates a VRAM destination in z_H and z_L, from an X,Y source in z_B,Z_c in logical units (pairs of pixels)

each logical unit is 2 pixels, so a tile is 4x4 logical units (LU)

on the VIC, each line has 22 characters, so we multiply our Yline by 22.

Our screen base is $1E00
DoStrip will draw one horizontal strip of tiles.
The job is defined by the following zero page entries

z_HL = VRAM Dest
z_BCs = Tilemap
z_DEs = Pattern data
z_IYL = TileMap Width

X=0 throughout the function

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)
If using the tile cache we zero the tiles after they are drawn.

We add z_E to the character number, this is an offset to our 'patterns'
To 'X-flip' the graphic, we have a lookup table of conversions for flipped equivalent characters.

The last entry in the LUT is a 0


DoStripRev has essentially the same function, however it horizontally flips the pattern data via the lookup table.

We're using z_DEs to point to our lookup table, we check each pair of entries in the table, if either matches our source pattern, the other is the flipped equivalent.

If nothing matches, we just write the original character to the screen as is.






Lesson P63 - Multiplatform Software tilemap on the PET
We've written a minimal multiplatform Tile/Sprite routine in the Mintile series, Now, lets take a look at the platform specific code to quickly draw tiles to the screen on the Commodore PET


PET_MinTile.asm


MinTile is a multiplatform 'engine' which allows us to define our game code in a common way, and let the platform specific code handle the platform specific work!... it was used to write 'ChibiFighter' on the Z80.

For more details on Mintile, see the Mintile series here...

The PET doesn't have 'real' bitmap graphics, it uses character blocks!

We'll export our character with Akusprite Editor, and create a 'translation table' to flip the blocks to do the best we can on this system.

Tile Drawing Routines

Our example shows an onscreen tilemap and two software 'sprites'.
Mintile supports scrolling and X-Flip (but not Y-flip)
The 'sprites' are actually miniature tile maps, this is to reduce the amount of platform specific code.
these are all created via the DoStrip platform specific routine, which we'll look at here.

On the PET Each tile is a single character block
We have a 'GetScreenPos' function , which calculates the VRAM destination for the sprite objects.
It calculates a VRAM destination in z_H and z_L, from an X,Y source in z_B,Z_c in logical units (pairs of pixels)

each logical unit is 2 pixels, so a tile is 4x4 logical units (LU)

on the PET, each line has 40 characters, so we multiply our Yline by 40.
Our screen base is $8000.

Our virtual screen is 32x24 tiles, so we center the screen by adding 4
DoStrip will draw one horizontal strip of tiles.
The job is defined by the following zero page entries

z_HL = VRAM Dest
z_BCs = Tilemap
z_DEs = Pattern data
z_IYL = TileMap Width

X=0 throughout the function

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)
If using the tile cache we zero the tiles after they are drawn.

We add z_E to the character number, this is an offset to our 'patterns'
To 'X-flip' the graphic, we have a lookup table of conversions for flipped equivalent characters.

The last entry in the LUT is a 0


DoStripRev has essentially the same function, however it horizontally flips the pattern data via the lookup table.

We're using z_DEs to point to our lookup table, we check each pair of entries in the table, if either matches our source pattern, the other is the flipped equivalent.

If nothing matches, we just write the original character to the screen as is.






Lesson P64 - Multiplatform Software tilemap on the SNES
We've written a minimal multiplatform Tile/Sprite routine in the Mintile series, Now, lets take a look at the platform specific code to quickly draw tiles to the screen on the SNES.


SNS_MinTile.asm



MinTile is a multiplatform 'engine' which allows us to define our game code in a common way, and let the platform specific code handle the platform specific work!... it was used to write 'ChibiFighter' on the Z80.

For more details on Mintile, see the Mintile series here...

Tile INIT

Our example shows an onscreen tilemap and two software 'sprites'.
Mintile supports scrolling and X-Flip (but not Y-flip)
The 'sprites' are actually miniature tile maps, this is to reduce the amount of platform specific code.
these are all created via the DoStrip platform specific routine, which we'll look at here.

The drawn tilemap is 32x24 in size.
Before we can use the tiles, we need to transfer the tile patterns from cartridge ROM to VRAM.

We use DefineTiles to send the data.
DefineTiles transfers the source data (in bitplanes) to VRAM

We use three 16 bit pairs defined in the zero page

BC is the total Bytes
DE is the Destination Ram
HL is the Source Bytes

We select a VRAM address with port $2116-7

We write the bytes of data to port $2118-9

Caches and Interrupts

We can't write to Tilemap VRAM outside of Vblank.

We define a screen buffer of $800 bytes to cache the contents of the tilemap, and transfer the cache during vblank
During VBLANK We use a DMA to transfer all the bytes of the buffer from RAM to VRAM
We define the address of our interrupt handler in the footer at address $FFC0

Tile Drawing Routines

The MinTile shared routine provides calculation and tilemap planning, however we need to do the actual job of 'Drawing' in the platform code.

We have a 'GetScreenPos' function , which calculates the VRAM destination for the sprite objects.
It calculates a VRAM cache destination in z_H and z_L, from an X,Y source in z_B , z_C in logical units (pairs of pixels) - Each tile is effectively 4 logical units.

Each tile uses 2 bytes of VRAM in the tilemap

The formula is effectively:
Dest= Cache Base + (Ypos in Tiles * 64) + Xpos in Tiles *32
DoStrip will draw one horizontal strip of tiles.

The job is defined by the following zero page entries

z_HL = VRAM Dest
z_BCs = Tilemap
z_DEs = Pattern data
z_IYL = TileMap Width

X=0 throughout the function

The tilemap will either be the TileCache (for the background) or a mini tilemap (for sprites)
If using the tile cache we zero the tiles after they are drawn.

We select our tile number, adding the DE to the tile number. These are written into the tile cache at HL

The two tile definition bytes are in the format %TTTTTTTT %VHLPPPTT
where T=tile number V=vflip H=hflip L=layer (in front of sprites) P=palette

DoStripRev is virtually identical!

We just set the Xflip flag, and walk through the tilemap from right to left.





Lesson P65 - Interrupt Driven Music on the BBC (ChibiTracks)
Lets upgrade our previous example with sound via ChibiTracks, we'll hook into the firmware interrupt handlers to play some music


BBC_MinTile_WithSound.asm



The firmware ROM is in the high are of the address space where the interrupt vectors are ($FFFA-$FFFF) so we'll have to 'chain onto' the firmware handler.

Interrupt Vectors

The standard 6502 interrupt vectors from $FFFA+ are ROM, however these jump to vectors in low memory addresses (Jumps to the address at...)

IRQ and BRK interrupts back up A at address $00FC.

NMI is different, it causes a jump to address $0D00 - the firmware puts an RTI command here during reset.

Vector Address 
Remaps to
Function  
Registers stored
by Firmware
$FFFE-$FFFF Vector at $0202-$0203  
BRK STA $FC
$FFFE-$FFFF
Vector at $0204-$0205 IRQ1 (Primary IRQ)
STA $FC
$FFFE-$FFFF Vector at $0206-$0207 IRQ2 (Unrecognised IRQ)
STA $FC
$FFFA-$FFFB
Jumps to $0D00 NMI

We need to clear the interrupt, we can do this by writing #255 to $FE4D

The Interrupt Handler

To hook into the firmware interrupt handler we need to patch the address of our interrupt handler to address $0204

We use CLI to turn on interrupts
First we need to check what caused the interrupt - we do this with the register at $FE4D

If bit 1=one then this is our VBLANK, and we need to update the sound.
otherwise we just restore A from $00FC (the firmware backed it up)

We also need to clear the interrupt, we do this by writing $255 to FE4D

ChibiTracks uses the Zeropage entries z_hl,z_bc,z_de and z_ix,as well as X,Y and A

ChibiTracks
To use ChibiTracks, we need to include the modules of the music player,

We also need the platform specific "Chibisound Pro" sound driver.

We need to have a ChiBiTracks music file to play.
We have two options 'Allow Speed change' allows us to change the speed of our song. This is useful to keep the song playing the same speed on 50hz and 60hz screens. NOTE: Whether this will work effectively depends on if the speed was pre-multiplied on export (faster playback, but stops this function working)

AllowRelocation allows the binary to be loaded at any memory address, not just the one 'compiled' into the binary at export time - while disabling this will save a little speed/memory it's recommended you keep this enabled!
We need to allocate up to 128 bytes of memory for ChibiSoundPro, and ChibiTracks player.

We define pointers to the ChibiTracks variables within this ram.
Before we play anything we need to init the ChibiSoundPro Driver.

To start our song, we set SongBase to point to the music file we want to play, and call StartSong - we do this any time we want the music to change
All that's left is to execute the PLAY routine to update the playing music.





Lesson P66 - Interrupt Driven Music on the PC-Engine (ChibiTracks)
Lets upgrade our previous example with sound via ChibiTracks, we'll use the VBlank interrupt handlers to play some music


PCE_MinTile_WithSound.asm



The Interrupt Handler

We need to define a pointer to our Interrupt handler at address $FFF8-9 in the logical address space (Visible to the CPU).

This handles IRQ1 - which is triggered by Vblank.
We need to set the video hardware to generate Vblank, by setting bit 3 of video reg 5
First we need to check what caused the interrupt - we do this with the register at $1403

If bit 1=one then this is our VBLANK, and we need to update the sound.
Otherwise we just clear whatever the interrupt was , by writing 255 to $1403

the Video interrupt can't be cleared like that, to clear the VBLANK we read from the VDC status at address $0100

ChibiTracks uses the Zeropage entries z_hl,z_bc,z_de and z_ix,as well as X,Y and A

ChibiTracks
To use ChibiTracks, we need to include the modules of the music player,

We also need the platform specific "Chibisound Pro" sound driver.

We need to have a ChiBiTracks music file to play.
We have two options 'Allow Speed change' allows us to change the speed of our song. This is useful to keep the song playing the same speed on 50hz and 60hz screens. NOTE: Whether this will work effectively depends on if the speed was pre-multiplied on export (faster playback, but stops this function working)

AllowRelocation allows the binary to be loaded at any memory address, not just the one 'compiled' into the binary at export time - while disabling this will save a little speed/memory it's recommended you keep this enabled!
We need to allocate up to 128 bytes of memory for ChibiSoundPro, and ChibiTracks player.

We define pointers to the ChibiTracks variables within this ram.
Before we play anything we need to init the ChibiSoundPro Driver.

To start our song, we set SongBase to point to the music file we want to play, and call StartSong - we do this any time we want the music to change

Here we've slowed down the song a little, it was designed to play on 50 hz systems, not the 60hz of the PC Engine.
All that's left is to execute the PLAY routine to update the playing music.






Lesson P67 - Interrupt Driven Music on the Commodore Pet (ChibiTracks)
Lets upgrade our previous example with sound via ChibiTracks, we'll use the VBlank interrupt handlers to play some music


PET_MinTile_WithSound.asm




The Address of the interrupt vector in ram differs depending on the ROM version!

Here, in the code we're using the original ROM address $0219, but the later ones use $0090


Interrupt vectors

The standard 6502 interrupt vectors from $FFFA+ are ROM, however these jump to vectors in low memory addresses. IRQ and BRK interrupts push A,X and Y onto the stack in that order.

Immediately after the pushes, the interrupt handler at the addresses below are executed.

Note: The vector addresses were different on the first generation 2001-8 machine.

2001-8 Others

From To From To Function Registers Pushed
$0219
$021A $0090 $0091 IRQ A X Y
$021B $021C $0092 $0093 BRK A X Y
None None $0094 #0095 NMI

The Interrupt Handler - Using Vblank!

We need to load the address of Interrupt handler into address $0219-A

This handles various interrupts, including the Timer and Vblank!
We don't actually need to do anything to enable the Vblank interrupt, but if we want to be certain it's on, we can do so by setting bit 0 of $E813
First we need to check what caused the interrupt - we do this by reading at $E812

The ROM interrupt handler pushed A,X and Y ... but we've taken over control, so we need to pop these in the correct order after we're done.

NOTE: We also clear the timer interrupt, by writing 255 to $E84D - we don't actually need to do this if we're using the Vblank interrupt, but we'll use it in our second example next!


ChibiTracks uses the Zeropage entries z_hl,z_bc,z_de and z_ix,as well as X,Y and A

The Interrupt Handler - Using the timer!
First we want to disable the VBLANK interrupt, we do this by setting bit 0 to zero of $E813

Next we set the 16 bit speed value - $4000 is about the right speed, a lower number will speed up the music.

We need to enable only the timer interrupt, interrupts are controlled by $E84E. The top bit 7 defines the action (1=enable 0=disable).. bits 0-6 apply that action to the interrupts.

so writing %01111111 to $E84E disables all interrupts
writing %11000000 enables the interrupt controlled by bit 6 - the timer interrupts

We're not quite done though, to run the timer we need to set bit 6 of $E84B
The same address and interrupt is executed by the timer interrupt.

This time we actually want to clear the interrupts, we do this by writing 255 to $E84D

Each 1 bit in the value written clears a different interrupt - writing 255 clears them all!


ChibiTracks
To use ChibiTracks, we need to include the modules of the music player,

We also need the platform specific "Chibisound Pro" sound driver.

We need to have a ChiBiTracks music file to play.
We have two options 'Allow Speed change' allows us to change the speed of our song. This is useful to keep the song playing the same speed on 50hz and 60hz screens. NOTE: Whether this will work effectively depends on if the speed was pre-multiplied on export (faster playback, but stops this function working)

AllowRelocation allows the binary to be loaded at any memory address, not just the one 'compiled' into the binary at export time - while disabling this will save a little speed/memory it's recommended you keep this enabled!
We need to allocate up to 128 bytes of memory for ChibiSoundPro, and ChibiTracks player.

We define pointers to the ChibiTracks variables within this ram.
Before we play anything we need to init the ChibiSoundPro Driver.

To start our song, we set SongBase to point to the music file we want to play, and call StartSong - we do this any time we want the music to change

Here we've slowed down the song a little, it was designed to play on 50 hz systems, not the 60hz of the PC Engine.


All that's left is to execute the PLAY routine to update the playing music.
If we're using the TimerA to time our song, we need to ensure we keep int enabled.

Making sound also requires writes to $E84B, so we have to patch in to set bit 6 if we want the timer to work.





Lesson P68 - Interrupt Driven Music on the SNES (ChibiTracks)
Lets upgrade our previous example with sound via ChibiTracks, we'll use the VBlank interrupt handlers to play some music


SNS_MinTile_WithSound.asm



The SNES has two interrupt vectors... which occurs depends on if the CPU is in 6502 mode or 65816 mode!

In these tutorials we use the CPU as a 6502, so it's that one which we need to use.

Interrupt vectors
The SNES has a block of vectors at the FFE0-FFFF range of memory - There are two sets, depending on what mode the processor is in.
The interrupt we are interested in is the NMI - and we'll be using the 6502 mode vresion at $FFFC-$FFFD

Address Bytes Category Purpose Example
$FFE0 2 65816 Mode
$0000
$FFE2 2 65816 Mode
$0000
$FFE4 2 65816 Mode COP Vector $0000
$FFE6 2 65816 Mode Brk Vector $0000
$FFE8 2 65816 Mode Abort Vector (Unused) $0000
$FFEA 2 65816 Mode NMI Vector (V-blank) $0000
$FFEC 2 65816 Mode Reset Vector (Unused) $0000
$FFEE 2 65816 Mode IRQ Vector (H/V/External) $0000
$FFF0 2 6502 Mode
$0000
$FFF2 2 6502 Mode
$0000
$FFF4 2 6502 Mode COP Vector $0000
$FFF6 2 6502 Mode BRK Vector (unused) $0000
$FFF8 2 6502 Mode Abort Vector (Unused) $0000
$FFFA 2 6502 Mode NMI Vector (V-blank) $0000
$FFFC 2 6502 Mode Reset Vector (6502 Mode) $8000
$FFFE 2 6502 Mode IRQ/BRK Vector $0000

The Interrupt Handler - Using Vblank!

We're going to define an interrupt handler called 'CustomNmihandler'

We need to put this at address $FFFA-FFFB in the cartridge footer.


for clarity we've defined CustomNmihandler65816 - but this isn't actually used by todays example.

We turn on the VBLANK NMI with bit 7 of port $4200

This causes the video hardware to cause interrupts which will execute our interrupt handler
Our graphics routines need to do some work during VBLANK.

As VBLANK time is limited, we do them before our music tasks.

We transfer the screen buffer using a DMA transfer.



Now the graphics jobs are done we update our music!

ChibiTracks uses the Zeropage entries z_hl,z_bc,z_de and z_ix,as well as X,Y and A
Just to confirm it's the 6502 version running, we've created a dummy 65816 interrupt handler which does nothing.

This isn't actually executed during our example.

ChibiTracks
To use ChibiTracks, we need to include the modules of the music player,

We also need the platform specific "Chibisound Pro" sound driver.

We need to have a ChiBiTracks music file to play.
We have two options 'Allow Speed change' allows us to change the speed of our song. This is useful to keep the song playing the same speed on 50hz and 60hz screens. NOTE: Whether this will work effectively depends on if the speed was pre-multiplied on export (faster playback, but stops this function working)

AllowRelocation allows the binary to be loaded at any memory address, not just the one 'compiled' into the binary at export time - while disabling this will save a little speed/memory it's recommended you keep this enabled!
We need to allocate up to 128 bytes of memory for ChibiSoundPro, and ChibiTracks player.

We define pointers to the ChibiTracks variables within this ram.
Before we play anything we need to init the ChibiSoundPro Driver.

To start our song, we set SongBase to point to the music file we want to play, and call StartSong - we do this any time we want the music to change

Here we've slowed down the song a little, it was designed to play on 50 hz systems, not the 60hz of the PC Engine.
All that's left is to execute the PLAY routine to update the playing music.



Lesson P69 - Interrupt Driven Music on the NES (ChibiTracks)
Lets upgrade our previous example with sound via ChibiTracks, we'll use the VBlank interrupt handlers to play some music


NES_MinTile_withsound.asm



The SNES has two interrupt vectors... which occurs depends on if the CPU is in 6502 mode or 65816 mode!

In these tutorials we use the CPU as a 6502, so it's that one which we need to use.

The Interrupt Handler - Using Vblank!

We're going to define an interrupt handler called 'Nmihandler'

We need to put this at address $FFFA-FFFB in the cartridge footer.
We turn on the VBLANK NMI with bit 7 of port $2000

This causes the video hardware to cause interrupts which will execute our interrupt handler
Our graphics routines need to do some work during VBLANK.

We need to transfer tile updates to Vram, and this must be done during vblank.

As VBLANK time is limited, we do them before our music tasks, as it doesn't matter if our sound is updated while the screen is being drawn.




Now the graphics jobs are done we update our music!

ChibiTracks uses the Zeropage entries z_hl,z_bc,z_de and z_ix,as well as X,Y and A

ChibiTracks
To use ChibiTracks, we need to include the modules of the music player,

We also need the platform specific "Chibisound Pro" sound driver.

We need to have a ChiBiTracks music file to play.
We have two options 'Allow Speed change' allows us to change the speed of our song. This is useful to keep the song playing the same speed on 50hz and 60hz screens. NOTE: Whether this will work effectively depends on if the speed was pre-multiplied on export (faster playback, but stops this function working)

AllowRelocation allows the binary to be loaded at any memory address, not just the one 'compiled' into the binary at export time - while disabling this will save a little speed/memory it's recommended you keep this enabled!
We need to allocate up to 128 bytes of memory for ChibiSoundPro, and ChibiTracks player.

We define pointers to the ChibiTracks variables within this ram.
Before we play anything we need to init the ChibiSoundPro Driver.

To start our song, we set SongBase to point to the music file we want to play, and call StartSong - we do this any time we want the music to change

Here we've slowed down the song a little, it was designed to play on 50 hz systems, not the 60hz of the PC Engine.
All that's left is to execute the PLAY routine to update the playing music.




 

View Options
Default Dark
Simple (Hide this menu)
Print Mode (white background)

Top Menu
***Main Menu***
Youtube channel
Patreon
Introduction to Assembly (Basics for absolute beginners)
Amazon Affiliate Link
Forum
AkuSprite Editor
ChibiTracker
Dec/Bin/Hex/Oct/Ascii Table

Alt Tech
Archive.org
Bitchute
Odysee
Rumble
DailyMotion
Please note: I wlll upload more content to these alt platforms based on the views they bring in

Z80 Content
***Z80 Tutorial List***
Learn Z80 Assembly (2021)
Learn Z80 Assembly (old)
Hello World
Simple Samples
Advanced Series
Multiplatform Series
Platform Specific Series
ChibiAkumas Series
Grime Z80
Z80 Downloads
Z80 Cheatsheet
Sources.7z
DevTools kit
Z80 Platforms
Amstrad CPC
Elan Enterprise
Gameboy & Gameboy Color
Master System & GameGear
MSX & MSX2
Sam Coupe
TI-83
ZX Spectrum
Spectrum NEXT
Camputers Lynx

6502 Content
***6502 Tutorial List***
Learn 6502 Assembly
Advanced Series
Platform Specific Series
Hello World Series
Simple Samples
Grime 6502
6502 Downloads
6502 Cheatsheet
Sources.7z
DevTools kit
6502 Platforms
Apple IIe
Atari 800 and 5200
Atari Lynx
BBC Micro
Commodore 64
Commodore PET
Commander x16
Super Nintendo (SNES)
Nintendo NES / Famicom
PC Engine (Turbografx-16)
Vic 20

68000 Content
***68000 Tutorial List***
Learn 68000 Assembly
Hello World Series
Platform Specific Series
Simple Samples
Grime 68000
68000 Downloads
68000 Cheatsheet
Sources.7z
DevTools kit
68000 Platforms
Amiga 500
Atari ST
Neo Geo
Sega Genesis / Mega Drive
Sinclair QL
X68000 (Sharp x68k)

8086 Content
Learn 8086 Assembly
Platform Specific Series
Hello World Series
Simple Samples
8086 Downloads
8086 Cheatsheet
Sources.7z
DevTools kit
8086 Platforms
Wonderswan
MsDos

ARM Content
Learn ARM Assembly
Learn ARM Thumb Assembly
Platform Specific Series
Hello World
Simple Samples
ARM Downloads
ARM Cheatsheet
Sources.7z
DevTools kit
ARM Platforms
Gameboy Advance
Nintendo DS
Risc Os

Risc-V Content
Learn Risc-V Assembly
Risc-V Downloads
Risc-V Cheatsheet
Sources.7z
DevTools kit

MIPS Content
Learn Risc-V Assembly
Platform Specific Series
Hello World
Simple Samples
MIPS Downloads
MIPS Cheatsheet
Sources.7z
DevTools kit
MIPS Platforms
Playstation
N64

PDP-11 Content
Learn PDP-11 Assembly
Platform Specific Series
Simple Samples
PDP-11 Downloads
PDP-11 Cheatsheet
Sources.7z
DevTools kit
PDP-11 Platforms
PDP-11
UKNC

TMS9900 Content
Learn TMS9900 Assembly
Platform Specific Series
Hello World
TMS9900 Downloads
TMS9900 Cheatsheet
Sources.7z
DevTools kit
TMS9900 Platforms
Ti 99

6809 Content
Learn 6809 Assembly
Learn 6309 Assembly
Platform Specific Series
Hello World Series
Simple Samples
6809 Downloads
6809/6309 Cheatsheet
Sources.7z
DevTools kit
6809 Platforms
Dragon 32/Tandy Coco
Fujitsu FM7
TRS-80 Coco 3
Vectrex

65816 Content
Learn 65816 Assembly
Hello World
Simple Samples
65816 Downloads
65816 Cheatsheet
Sources.7z
DevTools kit
65816 Platforms
SNES

eZ80 Content
Learn eZ80 Assembly
Platform Specific Series
eZ80 Downloads
eZ80 Cheatsheet
Sources.7z
DevTools kit
eZ80 Platforms
Ti84 PCE

IBM370 Content
Learn IBM370 Assembly
Simple Samples
IBM370 Downloads
IBM370 Cheatsheet
Sources.7z
DevTools kit

Super-H Content
Learn SH2 Assembly
Hello World Series
Simple Samples
SH2 Downloads
SH2 Cheatsheet
Sources.7z
DevTools kit
SH2 Platforms
32x
Saturn

PowerPC Content
Learn PowerPC Assembly
Hello World Series
Simple Samples
PowerPC Downloads
PowerPC Cheatsheet
Sources.7z
DevTools kit
PowerPC Platforms
Gamecube

Work in Progress
ChibiAndroids

Misc bits
Ruby programming









Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!















































































































































































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!



































































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!



































































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!



































































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!


























































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!



































































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!



































































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!


























































































Buy my Assembly programming book
on Amazon in Print or Kindle!


Buy my Assembly programming book



Available worldwide!
Search 'ChibiAkumas' on
your local Amazon website!
Click here for more info!