`

chibiakumas.com



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 P80 - MaxTile software tilemap on the Atari5200
Lets take a look at the advanced 'Maxtile' tilemap on the Atari 5200 , it supports Xflip,Yflip, Fastfill and more!

A52_V1_MaxTile_Normal.asm


MaxTile Definitions

Using the 4 color screen, unlike the other systems, the tiles are only 4x8 (not 8x8)... this gives a 'virtual screen' resolution of 128x192 pixels (the screen is actually 160 pixels wide)
Maxtile Caches draws to the screen in 3 thirds to reduce flicker.
We use some spare memory for the 3 draw caches (each 256 bytes)

we also use 256 bytes for the 'Xflip lookup table'


The VRAM base of the screen is $2060 - we center the virtual screen by adding 4

Here is the Tile pattern data

The tiles are 8x8 in 2 color mode, or 4x8 in 4 color mode - either way each tile is 8 bytes.


'Fill tiles' are a special case, they fill a tile with 2 bytes (saving time and memory)
We'll calculate an Xflip LUT

We swap the pixels in each byte, storing the flipped equivalent in the LUT
This saves memory compared to storing alternative patterns.

There are two versions

Yflip does not require a lookup table, we instead move UP VRAM instead of DOWN as we draw the pattern!
When we want to draw a sprite object to the screen, we need to calculate the VRAM destination.

MaxTile uses X,Y co-ordinates in 'Logical Units' (Pairs of pixels) - this is passed in z_BC, and the Vram destination is returned in z_HL

The screen base is at address $2060 (plus 4 to center the virtual screen).

Each screen Y line is 40 bytes wide, so we multiply the Y line by 40 via bitshifts, effectively adding Y*32 and Y*8 to get Y*40

We also add the X position in bytes!


Tile Drawing!

The calling routine that exexutes DrawTile will set X and Y to zero, so we can rely on this being the case at the start of the routine... however we need to ensure that X and Y still contain zero by the end of our routine

The DrawTile Routine is called by the shared code, This shared code will backup and restore the stack pointer and load the first byte of the 16 bit tile number into A

The low bit is shifted out (the update bit)... we need to reset it to 0 anyway!

The following zero page entries  are loaded:
z_BCs = Tilemap
z_DEs = Tile Bitmap Pattern data
z_HL = VRAM Destination

To optimize things, the tile drawing works as a 'binary tree', deciding the kind of tile drawing routine to use

The Platform specific draw routine DrawTile starts by ckecking Bit 1 (now Bit 0)
This is the 'Program' flag - If this is 0, then this is the simplest unflipped tile, otherwise we switch to the advanced routine.

If we're drawing a basic tile, we shift a 0 back into A, and write it back, that clears the Update flag, as we will draw the tile now.
We're going to draw a basic unflipped tile

We need to load the second byte of the tilenumber.

Max tile was designed to multiply the tilenumber by 16, by using the top 12 bits of the two byte tile value, but we need to multiply by 8, so we bitshift the value, dividing it by two


We add this to z_DE (the pattern data)

This gives us the source address - which we load into z_HL
We need to write 1 byte for each line,

after each line we add 40 to the VRAM destination to move down to the next line - we do this by tweaking the Y register, except the last line, where we would need Y to equal 280 ($118) which is impossible, so we INC z_H, and set Y to 24 ($18)

We upldate the source in z_HLs by INCing zero page entry z_Ls

We repeat for each 8 lines of our tile.
If the Program bit was 1, then either we need to flip, or run some 'custom code'

Next we check the XY bits, if both are 0 this is not a flip (Transparent, Filled, Double etc)

If either bit (or both) is 1, then this is some kind of flip, so we calculate the pattern source address, and move it into the z_HLs
If the Y flip bit is 0 we must be X flipping!

We load each source pattern byte from z_HSs, then Xflip it via the Lookup table (in z_BC)

We then write these to the screen in the same way as the unflipped data.

We move down the screen using the Y register in the same way as before.
If the Y flip bit was set we now check if the X flip bit is also set.

If it's not we're just Yflipping!

To flip vertically we write the source pattern data normally, but we read it backwards from the source pattern, by adding 7 to z_HLs to move to the last line.
if the X bit was set as well as Y we need to XY flip.

We do this with a combination of both 'tricks'

We use the LUT to X flip, and draw to the screen Bottom to Top to Y flip!

MaxTile Custom Draw Types

Bits 1,2,3... XYP=%001 defines a custom program

When a custom program is being used Bits 4,5 define the program type (rather than part of the low tile number)

%00=Filled Tile
%01=Double height tile
%10=unused
%11=Transparent tile/empty tile

The remaining two bits 6,7 act as the High part of the tile number %------NN nnnnnnnn
A double height tile uses only 4 lines of a pattern, so we multiply the pattern number by 4 (half our 8 byte tile)

We then draw each line of the pattern twice to the screen.
The fill tile is the simplest!

We use 2 bytes from the pattern data, and fill each line with one of the two

We use z_E for one line, then z_D for one line - this allows us to make a nice 'checkerboard' patterned fill, or alternate lines in different colors.

As so little data is read, This routine is the fastest, so should be used for as much as possible of our tilemap!
The final type is the Transparent tile.

if the Tilenumber=255 then this tile is completely transparent, and no data will be drawn
Our transparency is a crude '0 byte' transparency.

Basically, any byte equal to 0 is not drawn to the screen, others are drawn normally.

We use the same pattern data as usual, but as we read in each byte, we only draw it to the screen if it isn't zero..




Lesson P81 - MaxTile software tilemap on the C64
Lets take a look at the advanced 'Maxtile' tilemap on the C64 , it supports Xflip,Yflip, Fastfill and more!

C64_V1_MaxTile_Normal.asm


MaxTile Definitions

Using the 4 color screen, unlike the other systems, the tiles are only 4x8 (not 8x8)...

this gives a 'virtual screen' resolution of 128x192 pixels (the screen is actually 160 pixels wide)

MaxTile also supports 2 color mode for 8x8 tiles and a screen of 256x192
Maxtile Caches draws to the screen in 3 thirds to reduce flicker.
We use some spare memory for the 3 draw caches (each 256 bytes)

we also use 256 bytes for the 'Xflip lookup table'


The VRAM base of the screen is $6000 - we center the virtual screen by adding $20 ($6020 total)

Here is the Tile pattern data

The tiles are 8x8 in 2 color mode, or 4x8 in 4 color mode - either way each tile is 8 bytes.


'Fill tiles' are a special case, they fill a tile with 2 bytes (saving time and memory)
We'll calculate an Xflip LUT

We swap the pixels in each byte, storing the flipped equivalent in the LUT
This saves memory compared to storing alternative patterns.

There are two versions

Yflip does not require a lookup table, we instead move UP VRAM instead of DOWN as we draw the pattern!
When we want to draw a sprite object to the screen, we need to calculate the VRAM destination.

MaxTile uses X,Y co-ordinates in 'Logical Units' (Pairs of pixels) - this is passed in z_BC, and the Vram destination is returned in z_HL

The screen base is at address $2000 (plus $20 to center the virtual screen).

On the C64 blocks of 8 consecutive bytes move down the screen, the 9th byte jumps back up, and is 1 block across from the first byte.


Considering our destination with X in bytes and Y in lines, by splitting the bits of X and Y, we could consider the calculation to be:
Vram Address= (%XXXXXXXX * 8) + (%YYYYY--- * 40) + %-----YYY + $2000







Tile Drawing!

The calling routine that exexutes DrawTile will set X and Y to zero, so we can rely on this being the case at the start of the routine... however we need to ensure that X and Y still contain zero by the end of our routine

The DrawTile Routine is called by the shared code, This shared code will backup and restore the stack pointer and load the first byte of the 16 bit tile number into A

The low bit is shifted out (the update bit)... we need to reset it to 0 anyway!

The following zero page entries  are loaded:
z_BCs = Tilemap
z_DEs = Tile Bitmap Pattern data
z_HL = VRAM Destination

To optimize things, the tile drawing works as a 'binary tree', deciding the kind of tile drawing routine to use

The Platform specific draw routine DrawTile starts by ckecking Bit 1 (now Bit 0)
This is the 'Program' flag - If this is 0, then this is the simplest unflipped tile, otherwise we switch to the advanced routine.

If we're drawing a basic tile, we shift a 0 back into A, and write it back, that clears the Update flag, as we will draw the tile now.
We're going to draw a basic unflipped tile

We need to load the second byte of the tilenumber.

Max tile was designed to multiply the tilenumber by 16, by using the top 12 bits of the two byte tile value, but we need to multiply by 8, so we bitshift the value, dividing it by two


We add this to z_DE (the pattern data)

This gives us the source address - which we load into z_HL
We need to write 1 byte for each line,

To make things easy, this code requires our tile to be vertically aligned to an 8 line boundary.

as the 8 lines are consecutive bytes in Vram, we just write 8 consecutive bytes from our pattern to VRAM

If the Program bit was 1, then either we need to flip, or run some 'custom code'

Next we check the XY bits, if both are 0 this is not a flip (Transparent, Filled, Double etc)

If either bit (or both) is 1, then this is some kind of flip, so we calculate the pattern source address, and move it into the z_HLs
If the Y flip bit is 0 we must be X flipping!

We load each source pattern byte from z_HSs, then Xflip it via the Lookup table (in z_BC)

We then write these to the screen in the same way as the unflipped data.

We move down the screen using the Y register in the same way as before.
If the Y flip bit was set we now check if the X flip bit is also set.

If it's not we're just Yflipping!

To flip vertically we write the source pattern data normally, but we read it backwards from the source pattern, by adding 7 to z_HLs to move to the last line.
if the X bit was set as well as Y we need to XY flip.

We do this with a combination of both 'tricks'

We use the LUT to X flip, and draw to the screen Bottom to Top to Y flip!

MaxTile Custom Draw Types

Bits 1,2,3... XYP=%001 defines a custom program

When a custom program is being used Bits 4,5 define the program type (rather than part of the low tile number)

%00=Filled Tile
%01=Double height tile
%10=unused
%11=Transparent tile/empty tile

The remaining two bits 6,7 act as the High part of the tile number %------NN nnnnnnnn
A double height tile uses only 4 lines of a pattern, so we multiply the pattern number by 4 (half our 8 byte tile)

We then draw each line of the pattern twice to the screen.
The fill tile is the simplest!

We use 2 bytes from the pattern data, and fill each line with one of the two

We use z_E for one line, then z_D for one line - this allows us to make a nice 'checkerboard' patterned fill, or alternate lines in different colors.

As so little data is read, This routine is the fastest, so should be used for as much as possible of our tilemap!
The final type is the Transparent tile.

if the Tilenumber=255 then this tile is completely transparent, and no data will be drawn
Our transparency is a crude '0 byte' transparency.

Basically, any byte equal to 0 is not drawn to the screen, others are drawn normally.

We use the same pattern data as usual, but as we read in each byte, we only draw it to the screen if it isn't zero..



Lesson P82 - MaxTile software tilemap on the PC Engine
Lets take a look at the advanced 'Maxtile' tilemap on the PC engine , it supports Xflip,Yflip, Fastfill and more!

Source patterns can be 4 or 16 color.

PCE_V1_MaxTile_Normal.asm


MaxTile Definitions

On the PC engine, we use the hardware tilemap to draw the Maxtile Tilemap.

The Double height and flipped tiles are 'preconverted' and stored in VRAM.

This version uses the tilemap for the 'simulated sprites' - there is an alternative version which uses hardware sprites
Maxtile Caches draws to the screen in 3 thirds to reduce flicker.
We use some spare memory for the 3 draw caches (each 256 bytes)

The VRAM base of the Tilemap is $6000 - we center the virtual screen by adding $20 ($6020 total)


FourColorPatterns if defined will switch to 4 color mode.



Tilemap Definitions
As with everything else on the PC engine Vram... each tile definition takes one memory address, which contains 2 bytes...

The top 4 bits pppp define a 16 color palette number from 0-15...
The remaining 12 bits nnnn nnnnnnnn define the tile number -

as stated, the first 64-256 probably can't be used because they overlap the tilemap... no's 2048-4095 CANNOT be used, as the memory these would use would be 64k-128k... and this memory is not installed in the PC Engine.
ppppnnnn nnnnnnnn

Tile definitions
Tile definitions use 4 bitplanes for 16 colors, and tile definitions are 8x8 - so 32 bytes ... Data is transferred in Words, and rather strangely we send bitplane 1+2 of lines, one at a time... then we do the same for bitplanes 3 and 4

Byte 1 Byte 2
First 16 bytes 00111100
01111111
01100011
01100011
01111111
01100011
01100011
00000000
00222200
02222222
02200022
02200022
02222222
02200022
02200022
00000000
Second 16 bytes 00333300
03333333
03300033
03300033
03333333
03300033
03300033
00000000
00444400
04444444
04400044
04400044
04444444
04400044
04400044
00000000


Sending tiles to VRAM

Here is the Tile pattern data

We use 4 bytes per tile for the solid fill tiles - these are always 16 color.

For the Tile patterns, we either use 2 bitplanes (4 color - 16 bytes per tile) or all 4 (16 color - 32 bytes per tile)

These are the unflipped tiles only, we flip and double-height them in software as required.
We send our data with DefineTilesCombo and DefineFills

DefineTilesCombo will do the Xflip,Yflip,XYflip and doubleheight conversion for us!

If using 4 color data, we use z_ixh and z_ixl to define the static color setting for bitplanes 2/3 (0/1 are loaded from the pattern data)

Our solid fills are the simplest, we use the same 2 lines for each of our bytes

We select the VRAM destination with 'ST0 #0'... writing the destination address to $102/3

we then select 'Data write' with 'ST0 #2' and sends our lines of data to $102/3...
we send all 8 lines of bitplane 0/1... then all 8 bitplanes of 2/3


We need to process the same data, but convert it to all the different versions we require.
We need to shift our 'tile destination' adding the offset in YX to the one in the zeropage DE pair

DE is a memory address, but YX is a tile number, so we multiply by 16 before adding (16 words = 32 bytes)

We then select the VRAM Destination and prepare to write our tiles.
We'll need to X flip data in many case - we can do this by swapping all the bits in the bytes we read.

We have a function to do this conversion...

This means we can use the same code for our Normal+Xflip

we have an alternate one for Yflip+XYFlip - which reads the source pattern data bottom to top.
our DefineTilesX routine does our Normal (unflipped) and X flipped tiles.

We transfer all the lines of our patterns to $102/3

If we're using 4 colors, than after 16 bytes (bitplanes 0/1) we transfer 8 lines of empty data for bitplanes 2/3 from z_IXH/z_IXL
For Y flip (also XY flip) we work from the last line of our source data (bytes 14/15) backwards to our first (Bytes 0/1)

Because of the Vram layout we do two bitplanes at a time...

for 4 color patterns we write ixh/l to bitplanes 2/3 after we do 0/1
The double height tile code is a bit of a pain.

Each tile needs 8 bytes (4 lines) of bitplane 0/1 and 8 bytes (4 lines) of bitplane 1/2

We have two routines to build a double height tile. One for the first half of the tile, and another to do the second


DoDoubleLines will transfer 4 lines from our pattern

DoDoubleEmptyLine will be used by 4 color patterns.


Tile Drawing!

The calling routine that exexutes DrawTile will set X and Y to zero, so we can rely on this being the case at the start of the routine... however we need to ensure that X and Y still contain zero by the end of our routine

When we want to draw a sprite object to the screen, we need to calculate the VRAM destination.

MaxTile uses X,Y co-ordinates in 'Logical Units' (Pairs of pixels) - this is passed in z_BC, and the Vram destination is returned in z_HL

The tilemap base is $6000 - to centre our virtual screen we move two strips down
The DrawTile Routine is called by the shared code, This shared code will backup and restore the stack pointer and load the first byte of the 16 bit tile number into A

The low bit is shifted out (the update bit)... we need to reset it to 0 anyway!

The following zero page entries  are loaded:
z_BCs = Tilemap
z_DEs = Tile Bitmap Pattern data
z_HL = VRAM Destination

To optimize things, the tile drawing works as a 'binary tree', deciding the kind of tile drawing routine to use

The Platform specific draw routine DrawTile starts by ckecking Bit 1 (now Bit 0)
This is the 'Program' flag - If this is 0, then this is the simplest unflipped tile, otherwise we switch to the advanced routine.

If we're drawing a basic tile, we shift a 0 back into A, and write it back, that clears the Update flag, as we will draw the tile now.
We're going to draw a basic unflipped tile

We need to load the second byte of the tilenumber.

Maxtile was designed for 16 bytes per tile, but we just want to write the tile number, so we shift to the right, effectively dividing by 16

We add our tile base in DEs, and write into the tilemap
If the Program bit was 1, then either we need to flip, or run some 'custom code'

Next we check the XY bits, if both are 0 this is not a flip (Transparent, Filled, Double etc)

If either bit (or both) is 1, then this is some kind of flip, so we calculate the tile number, and move it into the z_HLs
We check our X and Y flip bits, and switch to the pre-flipped tiles accordingly.

We then draw our tile onscreen in the same way as before.

MaxTile Custom Draw Types

Bits 1,2,3... XYP=%001 defines a custom program

When a custom program is being used Bits 4,5 define the program type (rather than part of the low tile number)

%00=Filled Tile
%01=Double height tile
%10=unused
%11=Transparent tile/empty tile

The remaining two bits 6,7 act as the High part of the tile number %------NN nnnnnnnn

The first type is the Transparent tile.

if the Tilenumber=255 then this tile is completely transparent, and no data will be drawn

Ideally others should be partially transparent, but we can't do that on the PC engine tilemap, so we just draw the tile as usual.

A double height or fill tile simply use the alternate tile patterns.

FillTiles do not add the z_DE tile pattern base - as their patterns are separate from the rest.




Lesson P83 - MaxTile software tilemap on the PC Engine - Hardware Sprites
Lets use Hardware sprites to allow our characters to move more smoothly around the screen.

PCE_MaxTile_Mid_Hsprite.asm
PCE_V1_MaxTile_Hsprite.asm


MaxTile Definitions

Here' we're using Hardware sprites to move our characters around the screen.

Note that PC-engine hardware sprites are 16x16 minimum, but we're treating them as 8x8 to allow Maxtile to work the same as on other systems.

This means 3/4 of the sprite pattern is empty - which isn't very efficient! - as we use up all the hardware sprites, part of our characters will disappear.


We transfer the data to the sprite pattern only as it appears onscreen - more like a bitmap system than the previous tile system.


Our code supports 4 or 16 color patterns. Although our sprites use a different format, we use the same source pattern data and convert it in realtime.
Our tilemap is drawn using the previous code,

We need some new variables, a counter for the hardware sprite number, and an Xshift and Yshift to move the sprite as we flip it (to compensate for the fact we're only using the top left part of the sprite)



Sprite Definitions
The basic sprite size is 16x16, though larger sprites can be created by tilling them, for up to 32x64.... only neighboring sprites can be tilled.

Sprites are NOT in the same format as the tilemap, they are 16x16 with 4 bitplanes, but each plane is sent separately

 For Example lets look at a sprite, where all pixels are color 0 or color 15!

First 16 writes
(Bitplane 1)
1110000000000111
1000000100000001
1000000100000001
0000000100000000
0000000100000000
0000000100000000
0000000100000000
0000000111111100
0011111110000000
0000000010000000
0000000010000000
0000000010000000
0000000010000000
1000000010000001
1000000010000001
1110000000000111
Second 16 writes
(Bitplane 2)
2220000000000222
2000000200000002
2000000200000002
0000000200000000
0000000200000000
0000000200000000
0000000200000000
0000000222222200
0022222220000000
0000000020000000
0000000020000000
0000000020000000
0000000020000000
2000000020000002
2000000020000002
2220000000000222
Third 16 writes
(Bitplane 3)
3330000000000333
3000000300000003
3000000300000003
0000000300000000
0000000300000000
0000000300000000
0000000300000000
0000000333333300
0033333330000000
0000000030000000
0000000030000000
0000000030000000
0000000030000000
3000000030000003
3000000030000003
3330000000000333
Fourth 16 writes
(Bitplane 4)
4440000000000444
4000000400000004
4000000400000004
0000000400000000
0000000400000000
0000000400000000
0000000400000000
0000000444444400
0044444440000000
0000000040000000
0000000040000000
0000000040000000
0000000040000000
4000000040000004
4000000040000004
4440000000000444

Sprites are stored in regular VRAM... the sprite definitions are stored in special ram which we CANNOT ACCESS...however we can allocate a bank of 256 addresses (each containing one word) called SATB, and then get the hardware to copy that ram to the special ram... it's suggested you use $7F00 for that purpose.

To start the copy we just write the address to control reg $13

SATB - Sprite attribute table buffer
The Sprite table allows for up to 64 sprites... each one has 4 words of data - making 256 words in total... the format is as follows

Address  F  E  D  C  B  A  9  8
 7  6  5  4  3  2  1  0 Notes
1 - - - - - - Y Y
Y Y Y Y Y Y Y Y Y=Ypos (64 is first visible line)
2 - - - - - - X X
X X X X X X X X X=Xpos (32 is first visible line)
3 - - - - - A A A
A A A A A A A A A=Address (Top 10 bits $trueaddress>>5 )
4 YF - YS YS XF - - XS
F - - - P P P P YF=Yflip XF=Xflip YS=Ysize (16/32/64) XS=Xsize (16/32)
F=Foreground (infront of tilemap) P=Palette


Tile Drawing!

The calling routine that exexutes DrawTile will set X and Y to zero, so we can rely on this being the case at the start of the routine... however we need to ensure that X and Y still contain zero by the end of our routine

Here is our tile pattern data,

We'll convert it as the sprites appear onscreen to the correct format.
When we want to draw a sprite object to the screen, we usually need to calculate the VRAM destination.

In this case though, we need an XY co-ordinate, but we need to shift them into H L to maintain compatibility
The DrawTile Routine is called by the shared code, This shared code will backup and restore the stack pointer and load the first byte of the 16 bit tile number into A

The low bit is shifted out (the update bit)... we need to reset it to 0 anyway!

The following zero page entries  are loaded:
z_BCs = Tilemap
z_DEs = Tile Bitmap Pattern data
z_HL = VRAM Destination

To optimize things, the tile drawing works as a 'binary tree', deciding the kind of tile drawing routine to use

The Platform specific draw routine DrawTile starts by ckecking Bit 1 (now Bit 0)
This is the 'Program' flag - If this is 0, then this is the simplest unflipped tile, otherwise we switch to the advanced routine.

If we're drawing a basic tile, we shift a 0 back into A, and write it back, that clears the Update flag, as we will draw the tile now.

Before we start our draw, we clear XShift/YShift... because we're only using the top left corner of our sprite, we must shift the drawpos when Xflipping or Y-flipping

We're going to draw a basic unflipped tile

We need to load the second byte of the tilenumber.

Maxtile was designed for 16 bytes per tile, so we shift to multiply by 1 for our tile number.

We add our tile base in DEs, and write into the tilemap
We check there's actually any hardware sprites left! (64 total)

if we've got some free, we use 'SpritePrep' to select the VRAM destination.

'TransferSpriteTileBlockx2' will send 2 of the bitplanes - we run this twice.
This is to ensure we can use the same pattern data as the Tiles, which sent bitplanes in pairs.

If we're only using 4 colors we send empty data for the unused 2 bitplanes.
SpritePrep will set up sprite A (in the accumulator)

First we set up the X/Y pos from z_hl

We set up the pattern Address (based on the sprite number)

Next we set up the attributes

Finally we select the pattern VRAM - as we'll send the pattern data next.
TransferSpriteTileBlockx2 will send the pattern data to VRAM

Due to the sprite layout, we need to send one byte from our source, and one empty byte.
Then we send 16 empty bytes.

First we send the even bytes from our source, then we send the odd ones - this is to 'convert' the source data for the sprite format.
If the Program bit was 1, then either we need to flip, or run some 'custom code'

Next we check the XY bits, if both are 0 this is not a flip (Transparent, Filled, Double etc)

If either bit (or both) is 1, then this is some kind of flip, so we calculate the tile number, and move it into the z_HLs


We load the bitmap address and we use the same draw code as before.

BUT we need to set the X/Y flip attribute in A before calling DrawTileBasicH.


Our sprites are 16x16, but we're pretending they are 8x8, so we need to load an X-Y position shift to keep the 8x8 block in the correct position as we flip

MaxTile Custom Draw Types

Bits 1,2,3... XYP=%001 defines a custom program

When a custom program is being used Bits 4,5 define the program type (rather than part of the low tile number)

%00=Filled Tile
%01=Double height tile
%10=unused
%11=Transparent tile/empty tile

The remaining two bits 6,7 act as the High part of the tile number %------NN nnnnnnnn


The first type is the Transparent tile.

if the Tilenumber=255 then this tile is completely transparent, and no data will be drawn
In all other cases, since all our sprites are transparent, we just use the normal draw routine.
A Fill Tile sends the same 4 source bytes for all 8 lines of each of the bitplanes

This is 16 color - even if the regular patterns are 4 color
A double height tile uses half the pattern data

First we calculate the source tile, by multiplying the 'whole tile number' by 32 (or 16 for 4 color tiles)

we then look at the least significant bit - this is the 'half tile shift' and move down 4 lines (8 bytes = 4*2 bitplanes) if we need the 'odd half' of the tile.

We then transfer the data in a similar way as before, but we send each source line twice.
Once we've drawn the hardware sprites to the screen we need to remove the un-needed ones,

learUnusedHsprites will remove any unused sprites from the screen, setting all their attributes to zero.

It also transfers the VRAM STAB sprite table to the actual sprite hardware, showing the sprites in the process.




Lesson P84 - MaxTile software tilemap on the Super Nintendo
Lets take a look at the advanced 'Maxtile' tilemap on the Super Nintendo , it supports Xflip,Yflip, Fastfill and more!

Source patterns can be 4 or 16 color.

SNS_V1_MaxTile_Normal.asm


MaxTile Definitions

On the SNES, we use the hardware tilemap to draw the Maxtile Tilemap.

The SNES tilemap can perform X and Y flip for us.
The Double height tiles are 'preconverted' and stored in VRAM.

This version uses the tilemap for the 'simulated sprites' - there is an alternative version which uses hardware sprites
Maxtile Caches draws to the screen in 3 thirds to reduce flicker.
We use some spare memory for the 3 draw caches (each 256 bytes)

The VRAM base of the Tilemap is 2 lines down from SnesScreenBuffer (to center the virtual screen)


FourColorPatterns if defined will switch to 4 color mode.


Note we use $0001 as the first pattern number .... $0000 has a special meaning to maxtile and will cause a malfunction if used as the first pattern

Tile Definitions
Tile definitions use 4 bitplanes for 16 colors, and tile definitions are 8x8 - so 32 bytes ... Data is transferred in Words, and rather strangely we send bitplane 1+2 of lines, one at a time... then we do the same for bitplanes 3 and 4

Byte 1 Byte 2
First 16 bytes 00111100
01111111
01100011
01100011
01111111
01100011
01100011
00000000
00222200
02222222
02200022
02200022
02222222
02200022
02200022
00000000
Second 16 bytes 00333300
03333333
03300033
03300033
03333333
03300033
03300033
00000000
00444400
04444444
04400044
04400044
04444444
04400044
04400044
00000000

Tilemap Data
The Tilemap will typically start from address $0000, each entry contains two bytes

 F   E   D   C   B   A   9   8    
 7   6   5   4   3   2   1   0    

V H L P P P T T
T T T T T T T T
V=vflip H=hflip L=layer (in front of sprites) P=palette T=tile number

Sending tiles to VRAM

Here is the Tile pattern data

We use 4 bytes per tile for the solid fill tiles - these are always 16 color.

For the Tile patterns, we either use 2 bitplanes (4 color - 16 bytes per tile) or all 4 (16 color - 32 bytes per tile)

These are the unflipped tiles only. 

The SNES can flip tiles for us, and we convert them and store alternate patterns in VRAM for doubleheight
We don't write directly into VRAM, we write to an $800 byte buffer called 'SnesScreenBuffer'

This will be transferred to VRAM during the NMI via a DMA.


The DMA, once set up, automatically shifts all the data from normal memory to VRAM - all in the time the vblank occurs
We send our data with DefineTiles, DefineDoubleTiles and DefineFills

These transfer (and convert) the source pattern data into 16 color patterns in VRAM

if using 4 color source patterns, IXH and IXL in the zeropage define the two extra bitplanes not defined in the pattern data.
Our solid fills are the simplest, we use the same 2 lines for each of our bytes

We select the VRAM destination with 'ST0 #0'... writing the destination address to $102/3

we then select 'Data write' with 'ST0 #2' and sends our lines of data to $102/3...
we send all 8 lines of bitplane 0/1... then all 8 bitplanes of 2/3


DefineTiles handles our regular tiles, we send all the bytes 'AS IS' to VRAM.

EXCEPT if we're using 4 colors!
In that case, after we've sent all 16 bytes of our tile, we need to send 16 'dummy bytes' to fill bitplanes 2/3 from IXH,IXL
The double height tile code is a bit of a pain.

Each tile needs 8 bytes (4 lines) of bitplane 0/1 and 8 bytes (4 lines) of bitplane 1/2

We run 'DefineTiles4Lines' to send 4 lines twice.
we add 8 bytes, to move to the other bitplanes of the same half - unless we're using 4 color patterns, in which case we send 'dummy data' from IXH/IXL

After each send we add 16/32 to move to the next tile

Tile Drawing!

The calling routine that exexutes DrawTile will set X and Y to zero, so we can rely on this being the case at the start of the routine... however we need to ensure that X and Y still contain zero by the end of our routine

When we want to draw a sprite object to the screen, we need to calculate the VRAM destination.

MaxTile uses X,Y co-ordinates in 'Logical Units' (Pairs of pixels) - this is passed in z_BC, and the Vram destination is returned in z_HL

The tilemap is 32 tiles wide, and each tile is 2 bytes.
The DrawTile Routine is called by the shared code, This shared code will backup and restore the stack pointer and load the first byte of the 16 bit tile number into A

The low bit is shifted out (the update bit)... we need to reset it to 0 anyway!

The following zero page entries  are loaded:
z_BCs = Tilemap
z_DEs = Tile Bitmap Pattern data
z_HL = VRAM Destination

To optimize things, the tile drawing works as a 'binary tree', deciding the kind of tile drawing routine to use

The Platform specific draw routine DrawTile starts by ckecking Bit 1 (now Bit 0)
This is the 'Program' flag - If this is 0, then this is the simplest unflipped tile, otherwise we switch to the advanced routine.

If we're drawing a basic tile, we shift a 0 back into A, and write it back, that clears the Update flag, as we will draw the tile now.
We're going to draw a basic unflipped tile

We need to load the second byte of the tilenumber.

Maxtile was designed for 16 bytes per tile, but we just want to write the tile number, so we shift to the right, effectively dividing by 16

We add our tile base in DEs, and write into the tilemap cache (SnesScreenBuffer) at address z_hl
If the Program bit was 1, then either we need to flip, or run some 'custom code'

Next we check the XY bits, if both are 0 this is not a flip (Transparent, Filled, Double etc)

If either bit (or both) is 1, then this is some kind of flip, so we calculate the tile number, and move it into the z_HLs
We check our X and Y flip bits, and switch the value we put in z_B accordingly - Bit 6 is Xflip, Bit 7 is Yflip

We then draw our tile onscreen in the same way as before.

MaxTile Custom Draw Types

Bits 1,2,3... XYP=%001 defines a custom program

When a custom program is being used Bits 4,5 define the program type (rather than part of the low tile number)

%00=Filled Tile
%01=Double height tile
%10=unused
%11=Transparent tile/empty tile

The remaining two bits 6,7 act as the High part of the tile number %------NN nnnnnnnn

The first type is the Transparent tile.

if the Tilenumber=255 then this tile is completely transparent, and no data will be drawn

Ideally others should be partially transparent, but we can't do that on the SNES tilemap, so we just draw the tile as usual.

A double height or fill tile simply use the alternate tile patterns.

FillTiles do not add the z_DE tile pattern base - as their patterns are separate from the rest.




Lesson P85 - MaxTile software tilemap on the SNES - Hardware Sprites
Lets use Hardware sprites to allow our characters to move more smoothly around the screen.

SNS_V1_MaxTile_Hsprite.asm


MaxTile Definitions

Here' we're using Hardware sprites to move our characters around the screen.

We're using 8x8 hardware sprites, using the same pattern data as the background tiles.

Our code supports 4 or 16 color patterns. Although our sprites use a different format, we use the same source pattern data and convert it in realtime.
We define various settings for our sprite drawing, most are the same as the prvious tilemap example

We define some new ram for the sprite data buffer SnesSpriteBuffer - it's transferred to VRAM during NMI via a DMA
Our pattern data is the same as before, but the sprites use patterns from address $4000+ , so we copy the patterns to this address for the sprites.
We need to transfer the sprite cache into VRAM during the NMI interrupt
We need to enable the 'sprite layer', and also turn on the interrupts

Sprite Definitions - Overview
Sprites use as special bank of 512 bytes of 'OAM' memory for their definitions... they also use standard VRAM for the pattern data.
In theory the Pattern data can be relocated... but in practice it's best to just assume it's at $4000 (address in 16 bit words)
Sprites can be various sizes - a 'default size' is set for all sprites... and certain selected sprites can be double size...
this is, however a bit tricky... lets say you have the default size as 8x8... and one double size 16,16 sprite
If we point this sprite 'double size' 16x16 sprite to pattern  'Tile 0',  the 4 8x8 chunks will be made up of tile numbers:
1 2
16 17

Lets look at this example of a 16x16 sprite in AkuSprite Editor... Akusprite editor is designed for 8x8 sprites, but we can export a 16x16 one in the following way

If we want to export this quickly, so we can use it as a single doublesize sprite, one option is to tick the 'FixedSize' tickbox, and set the size to 128,16

This will export the sprite correctly - of course there will be a lot of unused space in the exported file... so we would want to combine all our 16x16 together into a single image

Generally it would be easier to build up a 16x16 sprite from 4 8x8 sprites
Sprite Definitions - Ports Used
Address Name Purpose Bits Details
$2101 OBSEL OAM size (Sprite) SSSNNBBB S=size N=Bame addr B=Base addr
$2102 OAMADDL/L OAM address LLLLLLLL a=oam address L
$2103 OAMADDL/H OAM address R000000H R= priority Rotation / H=oam address MSB
$2104 OAMDATA OAM data ????????
$212C TM Main screen designation ---S4321 S=sprites 4-1=enable Bgx
$2138 OAMDATAREAD Read data from OAM


Sprite Definitions - OAM Data

The SNES has 128 hardware sprites.

Selecting a HL address is done by setting registers $2102 (L) and $2103 (H)

Each address below $0100 holds Two Bytes (The first table)...each address $0100 or above holds just one!... All data is written via the $2104 
Note, Sprites use Palettes from 128... so the color palette used is the value in CCC +128
Sprite data should only be written to Vram during Vsync.
Address Byte 1 Byte 2 Meaning SprNum
$0000 XXXXXXXX YYYYYYYY X=Xpos (bits 0-7) Y=Ypos 0
$0001 YXPPCCCT TTTTTTTT Y=yflip X=xflip P=priority compared to BG (C=palette +128) 0
$0002 XXXXXXXX YYYYYYYY X=Xpos (bits 0-7) Y=Ypos 1
$0003 YXPPCCCT TTTTTTTT Y=yflip X=xflip P=priority compared to BG (C=palette +128) 1
$00FE XXXXXXXX YYYYYYYY X=Xpos (bits 0-7) Y=Ypos 127
$00FF YXPPCCCT TTTTTTTT Y=yflip X=xflip P=priority compared to BG (C=palette +128) T= Tile Pattern number
127
$0100 SXSXSXSX (no 2nd byte) S=doubleSize sprite X=Xpos (bit 8) 0-3
$0101 SXSXSXSX (no 2nd byte) S=doubleSize sprite X=Xpos (bit 8) 4-6

$011F SXSXSXSX (no 2nd byte) S=doubleSize sprite X=Xpos (bit 8) 124-127


Tile Drawing!

The calling routine that exexutes DrawTile will set X and Y to zero, so we can rely on this being the case at the start of the routine... however we need to ensure that X and Y still contain zero by the end of our routine

When we want to draw a sprite object to the screen, we usually need to calculate the VRAM destination.

In this case though, we need an XY co-ordinate, but we need to shift them into H L to maintain compatibility
The DrawTile Routine is called by the shared code, This shared code will backup and restore the stack pointer and load the first byte of the 16 bit tile number into A

The low bit is shifted out (the update bit)... we need to reset it to 0 anyway!

The following zero page entries  are loaded:
z_BCs = Tilemap
z_DEs = Tile Bitmap Pattern data
z_HL = VRAM Destination

To optimize things, the tile drawing works as a 'binary tree', deciding the kind of tile drawing routine to use

The Platform specific draw routine DrawTile starts by ckecking Bit 1 (now Bit 0)
This is the 'Program' flag - If this is 0, then this is the simplest unflipped tile, otherwise we switch to the advanced routine.

If we're drawing a basic tile, we shift a 0 back into A, and write it back, that clears the Update flag, as we will draw the tile now.

Before we start our draw, we clear XShift/YShift... because we're only using the top left corner of our sprite, we must shift the drawpos when Xflipping or Y-flipping

We're going to draw a basic unflipped tile

We need to load the second byte of the tilenumber.

Maxtile was designed for 16 bytes per tile, so we shift to multiply by 1 for our tile number.

We add our tile base in DEs, and write into the tilemap

we use 'SetHardwareSprite' to set the sprite attributes
Set hardware sprite moves all the parameters of the sprite into the sprite VRAM cache.

The only tricky thing is the 2nd part, where 2 bits (X pos bit 9 + Sprite Doublesize bit) need to be shifted to the correct position

This is because the byte is shared between 4 different hardware sprites
If the Program bit was 1, then either we need to flip, or run some 'custom code'

Next we check the XY bits, if both are 0 this is not a flip (Transparent, Filled, Double etc)

If either bit (or both) is 1, then this is some kind of flip, so we calculate the tile number, and move it into the z_HLs


We load the bitmap address and we use the same draw code as before.

BUT we need to set the X/Y flip attribute in A before calling DrawTileBasicH.


Our sprites are 16x16, but we're pretending they are 8x8, so we need to load an X-Y position shift to keep the 8x8 block in the correct position as we flip

MaxTile Custom Draw Types

Bits 1,2,3... XYP=%001 defines a custom program

When a custom program is being used Bits 4,5 define the program type (rather than part of the low tile number)

%00=Filled Tile
%01=Double height tile
%10=unused
%11=Transparent tile/empty tile

The remaining two bits 6,7 act as the High part of the tile number %------NN nnnnnnnn


The first type is the Transparent tile.

if the Tilenumber=255 then this tile is completely transparent, and no data will be drawn
In all other cases, since all our sprites are transparent, we just use the normal draw routine.
A Fill Tile sends the same 4 source bytes for all 8 lines of each of the bitplanes

This is 16 color - even if the regular patterns are 4 color
A double height tile uses half the pattern data

We use the alternate stretched tiles.
Once we've drawn the hardware sprites to the screen we need to remove the un-needed ones,

ClearUnusedHsprites will remove any unused sprites from the screen, setting all their attributes to zero.




Lesson P86 - Mouse control C64 with the 1351 mouse
The C64 mouse (the 1351) can operate as a normal joystick, and be read in the typical way, however we can also read it as an analog device!

Lets learn how!

C64_HelloMouse.asm


The interrupt handler code from todays example is taken from the official mouse manual, see page 85+ from the Commodore_1351_Mouse_Users_Manual_1986_Commodore.pdf!

Mouse hardware ports

The X-Y movement is passed by the paddle ports, however these are a 'relative location' and will repeat as we keep moving the mouse, so must be compared to the previous value to produce a relative offset.

The left and right mouse buttons use Fire and Up of the Joystick.

Address Description  Normal Bits 
 Mouse Bits 
Meaning
$D419 Paddle X value (Mouse X move) xxxxxxxx xPPPPPPn x=dont care (ignored) / P=Mouse Pos MOD 64 / n=noise bit
$D41A Paddle Y value (Mouse Y move) yyyyyyyy xPPPPPPn x=dont care (ignored) / P=Mouse Pos MOD 64 / n=noise bit
$DC01 CIA1: Port B, keyboard matrix rows and joystick #1 ---FRLDU ---L---R Left / Right Mousebuttons

The mouse handler code (interrupt handler)

Here is our mouse example.
The top line shows the raw values from the ports.
The second line is the X-Y position of the sprite.

Our mouse controls the sprite, and the left and right mouse buttons change its color
We need some zero page bytes to store the last settings of the paddle values, so we can work out the difference.

We also define some pointers to the sprite's XY position to make moving it more easy/clear in our code
Our interrupt handler uses the routine movchk to calculate the relative shift of the X and Y pot

We load the current value in A , and the old value in Y and run the routine.

It returns the old value in A, and a 16 bit signed shift in XA - we only need an 8 bit shift for the Y axis, but we use all 16 bits for the X pos


We set the position of the first Hardware sprite...
The Xpos is set by bits 0-7 of $D000, and the most significant bit is bit 0 of $D010
The Ypos is set by bits 0-8 of $D001
MovChk subtracts the OldValue from the NewValue to create a signed offset for the axis.

The Pots give a value from $40-$C0, and the least significant bit is 'unreliable'
In our code, only the middle 6 bits are used... these are converted to a signed 16 bit value in XA (X is the High byte, A is the Low byte)

Preparing our example

We need to load the address of our interrupt handler into address $314-$315

This will be executed by the C64 ROM,

We also need to turn on interrupts, and clear the interrupt flag.
We're using one of the hardware sprites to show our cursor.

Here we initialize the sprites parameters, showing it to the screen.

We load a bitmap 'Cursor' into ram at address $2000 which we've set up to be the address containing Sprite 0's image
The main loop loads the raw values from the hardware ports and shows them to the screen.
It also loads in the sprite position and shows that to the screen.


The sprite position is set by the interrupt handler, but here we read the 'joystick port' and check the mouse buttons.

We tweak the color accordingly (in X) - and update the sprite color.




Lesson P87 - Fast Filled border on the BBC
To enhance bitmap versions of MaxTile, we may wish to have a Filled border of 4 pixels (to cover the partial tile draws)

Lets learn how on the BBC

BBC_V1_SpeedTile_ClearBorder.asm


Overview

Maxtile can only draw whole tiles, this means on systems with allowing partial movements the edges of the screen will show parts of unchanged tiles.

On systems allowing Half tile movement the area which is left 'dirty' will be 4 pixels
On systems allowing Quarter tile movement the area which is left 'dirty' will be 6 pixels

As it's calculations are done in pairs of Pixels, Maxtile cannot do more than Quarter tile movement
The simplest solution to this problem is just to cover up the mess!

We'll create a 4-6 pixel border around the screen, and cover up the partial tile draws.

We will design our code with the system in mind, and fill the areas required as fast as possible!

BBC Version

First we're going to fill the top and bottom of the screen

'ClearBorderTopBottom' will fill 4 lines - we use it for the top and the bottom of the screen.


we also run 'ClearBorder4', this clears a 4x4 block at the left of the screen - which will be missed by our main routine which does the vertical strips.


Because of the way the BBC screen works, where 8 consecutive bytes in memory go down the screen with the 9th 'jumping' back up to the top,

To fill our 4 pixel tall strip, there are 4 'filled' bytes followed by 4 skipped bytes

With these skipped lines, The top 4 lines of the screen use 512 bytes total
We're now going to clear the sides.

Because of the screen layout, and To save time, we can do the Left and right in one go.

We first do a 4x8 strip on the right of the screen, and then INC Y, and do a 4x8 strip on the left.

We repeat on the height of the screen.


BUT this leaves a 4x4 block at the start on the left... which is why we filled it before

It also leaves a 4x8 block on the right at the end... we'll do that next.
'ClearBorder4' fills a 4x4 block, we use it at the start and end to fill the 'missed bit'




Lesson P88 - NativeSprite on the PC Engine
Lets look at 'NativeSprite' on the PC-Engine. It allows us to use hardware sprites in a multiplatform way!

GameVM_Sprong.asm
PCE_V1_NativeSprite.asm


What Is NativeSprite?

Nativesprite allows us to use platform specific sprite capabilities, to form 'objects' (grids of sprites which can be used in the same way on all systems.

This allows us to write a multiplatform program, but gain the benefits of the hardware capabilities.

Nativesprite splits the job of drawing sprites into three parts.
Part 1 is multiplatform, it is a list of NativeSprite objects with X,Y co-ordinates (in logical units - Pairs of Pixels)

Our game can change the co-ordinates and sprite object pointers to change in-game graphics in a multiplatform way.
Part 2 is platform specific, and defines the sprite pattern grid,
This defines how the object is made up of hardware sprite patterns.
It also offers platform specific functions, like sprite scaling or palettes where available.

On systems where no Hardware sprites are available, XOR software sprites are used (made up of 8x8 tiles)... XOR is used because it means we don't need to worry about redrawing the background.




Part 3 is also platform specific.
This is the bitmap pattern data used to draw the sprite, in the format of the hardware sprites or screen memory.

PC Engine Sprite Definitions
The PC Engine has 64 hardware sprites. The basic sprite size is 16x16, though larger sprites can be created by tilling them, for up to 32x64.... only neighboring sprites can be tilled. Sprites use the second set of palettes, from 256-511

Sprites are NOT in the same format as the tilemap, they are 16x16 with 4 bitplanes, but each plane is sent separately

 For Example lets look at a sprite, where all pixels are color 0 or color 15!

First 16 writes
(Bitplane 1)
1110000000000111
1000000100000001
1000000100000001
0000000100000000
0000000100000000
0000000100000000
0000000100000000
0000000111111100
0011111110000000
0000000010000000
0000000010000000
0000000010000000
0000000010000000
1000000010000001
1000000010000001
1110000000000111
Second 16 writes
(Bitplane 2)
2220000000000222
2000000200000002
2000000200000002
0000000200000000
0000000200000000
0000000200000000
0000000200000000
0000000222222200
0022222220000000
0000000020000000
0000000020000000
0000000020000000
0000000020000000
2000000020000002
2000000020000002
2220000000000222
Third 16 writes
(Bitplane 3)
3330000000000333
3000000300000003
3000000300000003
0000000300000000
0000000300000000
0000000300000000
0000000300000000
0000000333333300
0033333330000000
0000000030000000
0000000030000000
0000000030000000
0000000030000000
3000000030000003
3000000030000003
3330000000000333
Fourth 16 writes
(Bitplane 4)
4440000000000444
4000000400000004
4000000400000004
0000000400000000
0000000400000000
0000000400000000
0000000400000000
0000000444444400
0044444440000000
0000000040000000
0000000040000000
0000000040000000
0000000040000000
4000000040000004
4000000040000004
4440000000000444

Sprites are stored in regular VRAM... the sprite definitions are stored in special ram which we CANNOT ACCESS...however we can allocate a bank of 256 addresses (each containing one word) called SATB, and then get the hardware to copy that ram to the special ram... it's suggested you use $7F00 for that purpose.

To start the copy we just write the address to control reg $13

SATB - Sprite attribute table buffer
The Sprite table allows for up to 64 sprites... each one has 4 words of data - making 256 words in total... the format is as follows
Address  F  E  D  C  B  A  9  8
 7  6  5  4  3  2  1  0 Notes
1 - - - - - - Y Y
Y Y Y Y Y Y Y Y Y=Ypos (64 is first visible line)
2 - - - - - - X X
X X X X X X X X X=Xpos (32 is first visible line)
3 - - - - - A A A
A A A A A A A A A=Address (Top 10 bits $trueaddress>>5 )
4 YF - YS YS XF - - XS
F - - - P P P P YF=Yflip XF=Xflip YS=Ysize (16/32/64) XS=Xsize (16/32)
F=Foreground (infront of tilemap) P=Palette (256+)


NativeSprite
NativeSpr_Init will prepare the system for drawing hardware sprites.

On the PC engine we first need to turn on hardware sprites with bit 6 of Video Register 5.



We now need to transfer the sprite patterns (16x16 pixels ... 128 bytes each) to VRAM. $2000 is a good address to transfer sprites into VRAM.



Sprites do not use the same palettes as the background tiles - they use the 'second set' of palettes 256-511,

We select palette address $0100 to begin configuring the sprite palettes.
NativeSpr_DrawArray draws the array of sprite objects defined in Part1

The Co-ordinates of the sprite (in pairs of pixels) and the pointer to the sprite object (part 2)

We use NativeSpr_DrawExtra to draw the sprite to the screen.
Here is the correct Object definition for the PC Engine

The Width and Height in patterns is defined in the first two bytes.

The next word is the 'Attributes' which define the hardware sprite size and palette. This is shared for the entire sprite object (PC Engine sprite word 4)

Each tile has a pattern Word, however it must be the correct format for the sprite parameters, which is the source address bitshifted right 5 bits (For Example $2000>>5)
NativeSpr_DrawOne will load in the parameters, The XY position for the draw, and the pointer to the sprite object definition
NativeSpr_DrawExtra will draw one more sprite using the next free Hardware Sprite Number



NativeSpr_Draw will draw object HL at position B,C using Hardware sprite number A onwards.

On the PC Engine the attribute defines the sprite patterns as 16x16, 32x32 or 64x64.

NativeSprite uses a shared attribute to define this size.


The 'Virtual screen' uses Logical Units (Pairs of Pixels). The logical screen is 128x96 and starts from co-ordinate 64,80. Offscreen sprites are not drawn and do not use a hardware sprite number


The Sprite attribute buffer is in VRAM at address $7F00 - there are 4 bytes per sprite.

We convert and transfer the Ypos and Xpos, we then transfer the sprite pattern address (shifted >>5)

We then transfer the shared attribute.



This buffer at $7F00 does not update the sprites, we need to initiate a transfer with Video Register $13 (VRAM-SATB Block Transfer Source)

Hardware sprites stay on screen until they are removed. If we reduced the size or number the objects drawn to the screen, we will need to remove any hardware sprites that are no longer needed.


NativeSpr_ClearUnused will hide the sprites which are no longer needed, and is automatically executed after the NativeSprite array is drawn.


NativeSpr_HideAll will remove all the hardware sprites from the screen, and should be used for things like title screens. It should also be used before redrawing the background with XOR sprites.


NativeSpr_Hide will remove a single hardware sprite by number.

On the PC Engine we zero all the attributes, moving the sprite offscreen.





Lesson P89 - NativeSprite on the C64

Lets look at 'NativeSprite' on the C64. It allows us to use hardware sprites in a multiplatform way!

GameVM_Sprong.asm
C64_V1_NativeSprite.asm


What Is NativeSprite?

Nativesprite allows us to use platform specific sprite capabilities, to form 'objects' (grids of sprites which can be used in the same way on all systems.

This allows us to write a multiplatform program, but gain the benefits of the hardware capabilities.

Nativesprite splits the job of drawing sprites into three parts.
Part 1 is multiplatform, it is a list of NativeSprite objects with X,Y co-ordinates (in logical units - Pairs of Pixels)

Our game can change the co-ordinates and sprite object pointers to change in-game graphics in a multiplatform way.
Part 2 is platform specific, and defines the sprite pattern grid,
This defines how the object is made up of hardware sprite patterns.
It also offers platform specific functions, like sprite scaling or palettes where available.

On the C64, we define a shared 'Attribute byte' which allows selection of Double Height, or DoubleWidth sprite patterns for this object

We then define a Pattern byte, and ColorByte for each pattern. in this example the sprite patterns are $40, due to the fact the sprite patterns are stored at address $5000


Part 3 is also platform specific.
This is the bitmap pattern data used to draw the sprite, in the format of the hardware sprites or screen memory.

C64 Sprites

The Sprite pointers for the bitmap data are a single byte... multiplying the sprite pointer by 64 will give the address of the sprite *within the 16k bank of Vram* (so must be in the range $0000-$3FFF)...
$1000-$2000 and $9000-$A000 are seen by the VIC as character ROM, so sprites cannot be in this area!

We can move our screen base to something more convenient... so for example with a screen base of $4000 (Screen ram at $6000)- our sprites can be at $5000

$D018
Memory setup register.
$DD00
Vic 2 bank
(Bottom 2 bits)
Screen Base
Sprite Patterns
Sprite Pointers
%00011000
(Screen base $2000 / Colors at $400)
%------10
(Bank $4000-7FFF)
$6000
($4000+$2000)
$5000 (one option)
$4000+?
$47F8
($4000+$7F8)

Sprites are 21 vertical lines and 63 bytes each. With one unused byte this makes a 64 byte pattern size.
In 1bpp (2 color) mode this makes sprites 24x21.
In 2bpp (4 color) mode they are 12x21.

In both modes, Color 0 is Transparent
In 2bpp mode color 1,2 are read from $D025/6 and color 3 is the sprite color.

The Top Left first visible co-ordinate is (24,50)

Address Purpose Bits Meaning
ScreenBase+
$07F8-$07FF
Sprite pointers
(default - will change if screen moved)
 SSSSSSSS  s*64=memory address
$D000 Sprite #0 X-coordinate XXXXXXXX (only bits #0-#7).
$D001 Sprite #0 Y-coordinate YYYYYYYY
$D002 Sprite #1 X-coordinate XXXXXXXX (only bits #0-#7).
$D003 Sprite #1 Y-coordinate YYYYYYYY
... ... ... ...
$D00E Sprite #7 X-coordinate XXXXXXXX (only bits #0-#7).
$D00F Sprite #7 Y-coordinate YYYYYYYY
$D010 Sprite #0-#7 X-coordinates 76543210 (bit #8)
$D015 Sprite enable register 76543210 1=on
$D017 Sprite double height register 76543210
$D01B Sprite priority register 76543210
$D01C Sprite multicolor mode register 76543210 0=2 color 1=4color
$D01D Sprite double width register 76543210
$D01E Sprite-sprite collision register 76543210
$D01F Sprite-background collision reg 76543210
$D025 Sprite extra color #1 ----CCCC
$D026 Sprite extra color #2 ----CCCC
$D027 Sprite #0 color ----CCCC
$D028 Sprite #1 color ----CCCC
...
... ...
$D02E Sprite #7 color ----CCCC

NativeSprite
NativeSpr_Init will prepare the system for drawing hardware sprites.

On the C64, we need to load the sprite patterns to the correct memory range, With the screen memory layout used by this example, we load to address $5000

If we use the Multicolor '4 color sprites' two shared colors are defined, which are used by all sprites. These are defined by $D025 and $D026.
 
NativeSpr_DrawArray draws the array of sprite objects defined in Part1

The Co-ordinates of the sprite (in pairs of pixels) and the pointer to the sprite object (part 2)

We use NativeSpr_DrawExtra to draw the sprite to the screen.
Here is the correct Object definition for the C64

The Width and Height in patterns is defined in the first two bytes.

On the C64, we define a shared 'Attribute byte' which allows selection of Double Height, or DoubleWidth sprite patterns for this object

We then define a Pattern byte, and ColorByte for each pattern. in this example the sprite patterns are $40, due to the fact the sprite patterns are stored at address $5000
NativeSpr_DrawOne will load in the parameters, The XY position for the draw, and the pointer to the sprite object definition
NativeSpr_DrawExtra will draw one more sprite using the next free Hardware Sprite Number



NativeSpr_Draw will draw object HL at position B,C using Hardware sprite number A onwards.

First we take the Ypos and Xpos and convert these to sprite screen coordinates.

Next we load the Object Width and Height, and shared Attributes.

The Attributes are used to calculate the 'size' of the patterns in pixels, which are loaded in from NativeSpr_Sizes
We transfer all the atributes for each sprite pattern in the object to a different hardware sprite.
C64SpriteConvertToMask is used to convert the '1 bit per hardware sprite' attributes
Hardware sprites stay on screen until they are removed. If we reduced the size or number the objects drawn to the screen, we will need to remove any hardware sprites that are no longer needed.


NativeSpr_ClearUnused will hide the sprites which are no longer needed, and is automatically executed after the NativeSprite array is drawn.


NativeSpr_HideAll will remove all the hardware sprites from the screen, and should be used for things like title screens. It should also be used before redrawing the background with XOR sprites.


NativeSpr_Hide will remove a single hardware sprite by number.

On the C64, we set the X,Y pos both to zero



 

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

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

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
Psion 3a
PC9821

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

My Patreon backers
Thanks to all my supporters who allow this site to keep going:

Ack, Adolfo Perez Alvarez
Alejandro Gil Cal
Alejandro Pérez
Barry White, Brett Owen
burnout_x1, Chris Lidyard
CPU, damarty, Dave Snowdon
David L. Martin
Dimitris Topouzis
Ervin Pajor
Fábio Domingos, Ferro0xid
FNQMatt, ishotjr
James Whitwell
Juergen Pichler, Justin
Leo Comerford, m00n
MacTORG Steen, Marco Leal
Mark Trombly
Markus Podszuk (Brainslave)
Matt Kasdorf (KnightFire66)
Mikebloke, MrDave6309
Neil Moore, pagetable.com
penryu, Peter Beständig
Robin Elvin, robsoft
Roland Rząsa, schmosef
SethSR, ske286, squid64
Str33tz, SUPERDIVORCE
Trevor Briscoe
Voyager_Sput
William Torres



Images/Links are those provided by my supporters and should not be assumed to represent the values of this sites author










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!
















































































































































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!