`

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 P51 - Sound on the Atari 800 / 5200 (ChibiSound Pro)
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.

This will work on either Atari system, as only the pokey address changes!

A52_V1_ChibiSoundPro.asm

ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.


The new driver is a big improvement on the old one but doesn't really deserve the PRO suffix!

It's a parody of the early 'Soundblaster Pro' sound cards, which could only do 8 bit digital sound, so weren't really of 'pro spec' either!

Pokey Sound

The Pokey is at memory mapped port $D200 on A800 and  $E800 on A5200

Group Name Description Address A80 Address A52 Bits Meaning
POKEY AUDF1 Audio frequency 1 control $D200 $E800 FFFFFFFF F=Frequency (0=highest tone)
POKEY AUDC1 Audio channel 1 control $D201 $E801 NNNNVVVV N=Noise (0=noise / 10=Square wave)
V=Volume
(15=loudest)
POKEY AUDF2 Audio frequency 2 control $D202 $E802 FFFFFFFF F=Frequency (0=highest tone)
POKEY AUDC2 Audio channel 2 control $D203 $E803 NNNNVVVV N=Noise (0=noise / 10=Square wave)
V=Volume
(15=loudest)
POKEY AUDF3 Audio frequency 3 control $D204 $E804 FFFFFFFF F=Frequency (0=highest tone)
POKEY AUDC3 Audio channel 3 control $D205 $E805 NNNNVVVV N=Noise (0=noise / 10=Square wave)
V=Volume
(15=loudest)
POKEY AUDF4 Audio frequency 4 control $D206 $E806 FFFFFFFF F=Frequency (0=highest tone)
POKEY AUDC4 Audio channel 4 control $D207 $E807 NNNNVVVV N=Noise (0=noise / 10=Square wave)
V=Volume
(15=loudest)
POKEY AUDCTL general audio control $D208 $E808 N1234HHS N=Noise bit depth 1234=Channel Clocks HH=highpass filters S=main clockspeed

We have a whopping 4 channels! that's beats the AY's channels by 1.

Unfortunately the range of octaves is a little more limited, but it's still pretty good!

The Chibisound Pro driver

Before we start using the Pokey, we need to set up AUDCTL, we do this by writing a zero to port $D208/$E808, to set up the hardware to a known state.

We have a symbol set up called POKEY - this will point to $D200 or $E800 depending on the system we're building for.

We want to select the correct address offset for the channel (0-3) we want to set.
First we set the frequency, ChibiSound PRO is designed to use 16 bits, but the pokey only uses an 8 bit frequency.

We store the frequency to the first channel register
Next we need to select an 'instrument'

If noise is on, we set the top 4 bits to %0000----, if not we make a square wave with %1010----

Noise is one if bit 7 of L is one
We need to get the 4 bit volume... we take the top 4 bits of H and shift them into the correct position.

We then OR in the 4 bits for the 'instrument' , and store the result to the second channel register.

That's all we need to do!
We have a lookup table to define the notes of the octave, we can calculate sharps or flats by taking two tones, and dividing them by two.





Lesson P52 - Sound on the SuperNintendo (ChibiSound Pro)
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.


SNS_V1_ChibiSoundPro.asm

ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.


While we're writing a new Sound driver for the 65816 processor, we'll still use the same SPC700 driver from the original ChibiSound - You can find it HERE

That driver does the work of setting the registers on the SPC700 hardware, so we can do almost everything from the easier 65816 CPU!


The SPC700 Registers

Address Register Description Bits Meaning
c0 VOL (L) Left Volume -VVVVVVV Volume
c1 VOL (R) Right Volume -VVVVVVV Volume
c2 P (L) Pitch L PPPPPPPP Pitch
c3 P (H) Pitch H --PPPPPP Pitch
c4 SRCN Source number (references the source directory) SSSSSSSS Source
c5 ADSR (1) If bit7 is set, ADSR is enabled. If cleared GAIN is used. EDDDAAAA Enable, Dr, Ar
c6 ADSR (2) These two registers control the ADSR envelope. LLLRRRRR sL,sR
c7 GAIN This register provides function for software envelopes. GGGGGGGG G=Envelope bits
c8 -ENVX (auto updated) Readable current Envelope Value 0VVVVVVV Value
c9 -OUTX (auto updated) Readable current Waveform Value SVVVVVVV Signed Value
0C MVOL (L) Main Volume Left -VVVVVVV Volume
1C MVOL (R) Main Volume Right -VVVVVVV Volume
2C EVOL (L) Echo Volume Left -VVVVVVV Volume
3C EVOL (R) Echo Volume Right -VVVVVVV Volume
4C KON Key On CCCCCCCC Channel
5C KOF Key Off CCCCCCCC Channel
6C FLG DSP Flags. (used for MUTE,ECHO,RESET,NOISE CLOCK) RMENNNNN Reset (0=off) Mute (0=off) Echo (1=0ff) N=Noise clock
7C -ENDX (auto updated) read to see if channel done CCCCCCCC Channel
0D EFB Echo Feedback SFFFFFFF Signed Feedback
2D PMON Pitch modulation CCCCCCC- Channel (1-7)
3D NON Noise enable CCCCCCCC Channel (0=off)
4D EON Echo enable CCCCCCCC Channel (0=off)
5D DIR Offset of source directory (DIR*100h = memory offset) OOOOOOOO Offset $oo00
6D ESA Echo buffer start offset (ESA*100h = memory offset) OOOOOOOO Offset $oo00
7D EDL Echo delay, 4-bits, higher values require more memory. ----EEEE Echo delay
fF COEF 8-tap FIR Filter coefficients SCCCCCCC Signed Coeficcient
c = Channel 0-7� f = filter coefficient 0-7

The Chibisound Pro driver

Our chibisound driver uses a single sound sample, we'll need to define it's ADPCM wave.
We also need to define some bytes of ram, to record the state of the 'noise'

We also define two channel lookups, one is to select the 'base register' of a channels parameters,

the other is to set/clear the 'bit' relating to that channel (for KON/KOFF etc)
We have some functions to help us control the registers.

ProcessSoundCommandX_OR will turn on the bit for channel Y in reg A
ProcessSoundCommandX_XOR will turn off the bit for channel Y in reg A
as these registers contain bits for all channels, both of these use the cache at ChannelBuffer

ProcessSoundCommandXofchannel will deal with the channel registers $_0-$_9 , looking up the top nibble via the channel number in Y

Lets do some INIT!

We need to set up all the registers before the hardware will work for us well.

Many things like Echo and Moduclation we just set to zero, but others like master volume, and the source address of our samples we need to set to the correct values for our sounds to play.
we also need to INIT the channels.

we're only using one sample, and all these settings are the same all the time, so we'll set them all here.

If they weren't we'd want to set them for each note.
First we clear any previous key off commands with reg $5C

Next we load the channel number from z_L into Y... we can support up to 8 channels
Next we check the volume level in z_H

If it's zero we run the silence routine, by setting Key Off for this channel
We check the top bit of z_L ... this defines if noise is on or off

If noise is ON we need to shift our frequency (z_D) and volume (z_H)


we turn on the nose with reg $3D
we set the noise frequency with reg $6C
If noise is off, we clear noise with register $3D

we then load in our volume from z_H
We only need a 7 bit volume, we then set both L/R channels to the new volume
We set the 14 bit pitch of our channel with reg $03/2

We need to convert the 16 bit value in z_DE, but depending on our sample we may need to alter the amount of shifts we do, to get a good frequency range.
OK, we're ready to play our channel, so we set KEY ON for that channel!


We've only really used the SPC700 to simulate an AY sound chip here!
    
This is a bit of a waste of it's capabilities, but then again, the SPC700 is a bit of a pain, so we're even!!




Lesson P53 - Sound on the Apple II
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.

The Apple II only has beeper sound, so we'll have a challenge to play any music!


AP2_V1_ChibiSoundPro.asm

ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.

Beeper sound!

The Apple II has a simple 'Beeper', when we read from $C030 , this will cause a sound 'blip'. by waiting for a short time before doing this again, we can make a tone.

The length of the wait will define the frequency, but playing continuous sound will use basically all our cpu power!

The Chibisound Pro driver

We'll need a few variables for our code.
Our hardware can only play one sound at a time, but our music player expects 3 channels, so we'll 'cache' the requested channels, and only play the loudest at a given time.

We also need a random data source, we'll use NoisePos as an offset for this
Finally we need to be able to configure the length of sounds that are played each iteration, ToneLength will define this (Default 16)
Before we use ChibiSoundPro we need to use the INIT routine.

This will clear the cache data, and set the default sound length to 16.
If we want a shorter sound (for example, if we're playing sound during interrupts) we can override this with chibisoundpro_setbeeperlength
When we want to set the sound a channel should play, we use chibisoundpro_set

this will set the virtual channels entry in the cache, for playing later.

Each channel uses 4 bytes
As we have no hardware maintaining the tone, We need to 'replay' the sound every tick.

First we scan the ChannelCache for the loudest of the virtual channels - this is the one we'll play this tick!
We check the volume - we can't actually change volume on this hardware, so if the channel isn't very loud we treat it as silent.

In this case, we just pause for a while, to ensure any music plays at a consistent rate.


Next we need to deal with the noise - this is enabled by bit 7 of L
We transfer this to X - if X=0 noise will be off, if any bit in it was set, it will be on.

We need some 'random' byte data for our noise source - we actually use our program code!... but we use Y as the offset within this for the next psuedo-random data.
Now we use the 16 bit pitch setting

We convert this to a 10 bit 'pitch' - which is effectively the length of our delay loop.

We bitshift it as required into DE, which will be our 16 bit loop counters.
It's time to actually make our tone!

We are going to 'blip' $C030 to make the sound, but if we want the sound to be noisy, sometimes we wont!

We use X register ANDed with our random data to define if this sound will be noisy or not!
We need to do our loops.

We need to delay a bit before the next sound blip - longer delays means lower pitch.

We also need to decide how 'long' we want to play this sound, we use the length count in H to do this, and we subtract the high byte of our pitch. This is so that whether the pitch of the tone is high or low, the length it plays will be roughly consistent.
We have a lookup table to define the notes of the octave, we can calculate sharps or flats by taking two tones, and dividing them by two.




Lesson P54 - Sound on the Atari Lynx
Lets take another look at sound! We'll write a new multi-platform sound driver, which will give us control over the hardware, and allow us to write a music player which will work in a common way on all systems.

We'll use the Lynx 4 channels to make some music!


LNX_V1_ChibiSoundPro.asm

ChibiSound PRO!

ChibiSound is the sound driver that handles the particularities of a system, there is typically one driver per system, though the CPC and MSX drivers are essentially identical except for the AY register setting routines.

The original 'ChibiSound' gave us one channel, one Volume bit, six pitch bits, and the ability to turn noise on. Pitches were not matched across systems, so sound 32 won't sound the same on all systems.

The updated 'ChibiSound Pro' gives us all the channels provided by the hardware, 8 volume bits, 16 pitch bits, and the ability to turn noise on. Pitches were not matched across systems, however the 'ChibiOctave' lookup table provides values which ARE matched across all systems.

ChibiSound PRO is essentially a reduced subset of AY functionality, and was designed on the Z80 - it's 'PRO' suffix is a parody of the 'SoundBlaster PRO' - which could only do 8 bit sound so wasn't up to professional standards! (neither is ChibiSound PRO)

ChibiSound PRO provides a standard interface to the underlying hardware, it allows the following features to be set for each channel on the underlying hardware:

Function
Zero page entry
Notes:
Channel Number (bit 0-6)
Noise On/Off (bit 7)
H Multiple channels can be supported, but on single channel systems only Channel 0 will be sure to play.
If possible Channel 0 will be a center channel, Channels 1+ may be left/right

Noise bit turns the noise effect on (1) or off (0) - this can be set on any channel, if the underlying hardware only supports one noise channel, this will be resolved by the driver.
Volume L Set volume of the channel (0-255). Higher numbers are louder. O is off
Pitch DE Set the pitch of the channel (0-65535). Higher numbers are higher pitch.
Using DE does not standardize the resulting pitch - however a 'Lookup table' of notes 'ChibiOctave' provides a standardized way of getting the correct DE value to get a pitch correct note on the platform.
Chibisound PRO does not offer features like Envelope, LFE etc, as providing consistent functionality across different platforms would not be realistic.

Atari Lynx sound.

There are a variety of memory mapped ports we'll need to use to control the sound

From To Name Description Bits Meaning
FD20 FD20
Audio Channel 0 � 2�s compliment Volume control
0-127
FD21 FD21
Audio Channel 0 � Shift register feedback enable
eg %00010000
FD22 FD22
Audio Channel 0 � Audio Output Value (Raw Data)

Eg $80
FD23 FD23
Audio Channel 0 �Lower 8 bits of shift register
Eg 0
FD24 FD24
Audio Channel 0 � Audio Timer Backup Value
eg 0-63
FD25 FD25
Audio Channel 0 � Audio Control Bits
FTIRCKKK eg %00011110
FD26 FD26
Audio Channel 0 � Audio Counter

FD27 FD27
Audio Channel 0 �Other Audio Bits
Eg 0
FD28 FD2F
Audio Channel 1 � Same as Channel 0


FD30 FD37
Audio Channel 2 � Same as Channel 0

FD38 FD3F
Audio Channel 3 � Same as Channel 0

FD40 FD40 ATTENREG0 LLLLRRRR � Audio Attenuation

FD41 FD41 ATTENREG1 LLLLRRRR � Audio Attenuation

FD42 FD42 ATTENREG2 LLLLRRRR � Audio Attenuation

FD43 FD43 ATTENREG3 LLLLRRRR � Audio Attenuation

FD44 FD44 MPAN Stereo attenuation selection

FD50 FD50 MSTEREO Stereo disable LLLLRRRR 0=all on 255=all off


The Chibisound Pro driver

Before we use ChibiSoundPro we need to use the INIT routine.

First we set the channels to on.

Then we configure the defaults for each of the 4 channels (8 bytes apart)
Whatever sound we're making we don't change these settings again.
When we want to set the sound a channel should play, we use chibisoundpro_set

We are supporting up to 4 channels, and each channel has 8 byte data ports from $FD20/28/30/38
First we set the volume, the Lynx uses a 7 bit volume
Next we set the frequency.

We only use 7 of the bits from out top byte of the DE pair
The final thing we need to do is set the shift register feedback.

A value of $01 will make a good clean tone
A value of $F0 will make a noise sound

Once we've done this, the channel setup is complete and the sound will play.
We have a lookup table to define the notes of the octave, we can calculate sharps or flats by taking two tones, and dividing them by two.




Lesson P55 - Multiplatform Software tilemap on the BBC (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 BBC

BBC_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.
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 BBC we use a 256 byte lookup table, to 'pre-calculate the flipping of the 4 pixels in a Mode 1 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)

The BBC version is limited to Y movements of 8 pixel 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 16

The tile on the BBC uses 16 bytes, in 2 vertical 'strips'

we use Y as the offset for both the source tile, and VRAM destination

We repeat until the strip is drawn

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)

We work from right to left on the screen





Lesson P56 - Multiplatform Software tilemap on the Atari 800 or 5200 (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.


A52_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.
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 Atari 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)

The screen is 40 bytes wide, so we multiply the Y-line by 40.

The screen base is $2060, but our tilemap is only 32 bytes wide, so we center it 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 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.

we use z_HLs as the offset for  the source tile, and Y as the VRAM destination.

We add #40 to the Ypos to move down a line.

We repeat until the strip is drawn

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 P57 - Multiplatform Software tilemap on the Apple II
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 Apple II .


AP2_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.

On the Apple 2 the tiles are 7x8 pixels, giving a screen of 32x24 visible tiles.
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 Apple II we use a 256 byte lookup table, to 'pre-calculate the flipping of the pixels

The first bit in a byte is the color attribute - this is not flipped.
The remaining bits are the bitmap data, their order is reversed
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)

The Screen layout is split in 3 parts according to Y line
The bits of the Yline number are split and multiplied in the following format:
%AABBBCCC - AA*$0028  BBB*$0080  CCC*$0400
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 16
we use z_HLs as the offset for  the source tile, and Y as the VRAM destination.

We add #4 to the High byte of the Vram Destination to move down a line

We repeat 8 times until the strip is drawn

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 P58 - Multiplatform Software tilemap on the PC Engine
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 PC Engine .


PCE_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, and simulates X-flip by precalculating flipped tiles.
Before we can use the tiles, we need to transfer the tile patterns from cartridge ROM to VRAM.

We use DefineTilesCombo 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


The subroutine is executed twice, once with the normal patterns (to address $1000) and once Xflipped (to address $1000+$4000)

DoSourcePatternByte handles the X-flip as required.

DoSourcePatternByte loads the source data in and INCs Y (the offset to the source data)

IYL in the zero page defines if we're using X-flip or not... if we are the bits in the byte are flipped.

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 destination in z_H and z_L, from an X,Y source in z_B , z_C in logical units (pairs of pixels)

The Tilemap base is memory address $0000 in VRAM - but we skip the first two lines (64 bytes)

The formula is effectively:
Vram  Dest= (Ypos in Tiles * 32) + Xpos in Tiles
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 (to skip over the tilemap at VRAM $0000)
DoStripRev has essentially the same function, however we add $400 to the tile number, effectively skipping to the flipped tiles at memory address $4000+





Lesson P59 - Multiplatform Software tilemap on the NES / Famicom
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 NES.


NES_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. The Nes cannot Xflip tiles, and is limited to only 256 tiles for the background, so to flip our sprites, we'll use the hardware sprites (which can X flip) to draw the flipped character.
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

Caches and Interrupts

We can't write to Tilemap VRAM or sprite RAM outside of Vblank.
To work around this we'll write our changes to two caches.

We'll transfer the sprites via DMA each Vblank
We send around 1/4 of the Tile cache to Vram each vblank - there isn't time to copy more.
At the start of our vblank we stream as many tiles as we can to Vram ($B0 worth!)
After transferring the tiles we reset the scroll position (it changes when we write to Vram!)

we check if we've gone over the end of the cache, and reset if we have.
We use video register  $4014 to start a DMA which will transfer our Sprite Cache to the sprite ram in the video chip.

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)

The formula is effectively:
Dest= Cache Base + (Ypos in Tiles * 32) + Xpos in Tiles

This is used for the Tilemap, but X-flipped hardware sprites use the the pixel co-ordinate in B,C
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 E to the tile number.

These are written into the tile cache at HL
DoStripRev uses the hardware sprites. VDPNextSprite is used to keep track of the next free sprite.

we write the co-ordinates (in pixels) and pattern number, and set the Xflip attribute (%01000000)

We increase the X position by 4 logical units (8 pixels) after each tile to position the next sprite.

We also write a zero tile to HL to clear the tilemap under the sprite, to give the same effect as the unflipped tiles.


We need to zero the hardware sprite count before each draw, and redraw the sprites each time.

As our character goes offscreen the number of hardware sprites needed may change, to remove the unneeded ones, we clear all sprites which were unused during the draw.

Hardware sprites are more powerful, but there are very few of them!

On the NES we have only 64, and we used 40 of them for a single character... if the cpu controlled character wasn't drawn with the tilemap, we'd have run out!