return to Choose a Color Scheme: Dark
Print Mode

Learn Assembly for the Greatest Classic Processors:  Z80 - 6502 - 68000
Visit to get my games and their source code! | Support me on patreon

Learn Multi platform 68000 Assembly Programming... By Magic!

Platform Specific Lessons

Introduction to the Platform Specific Series...
In this series of tutorials we're going to cover how to do simple common tasks on multiple 68000 systems... 

The lessons will cover how to do each task (where possible) on all the systems and create functions that can be called in a common way, so we will create a 'common library' of functions you can use in your own programs to write platform independent 68000 code...

You should know 68000 already, If you don't please go through the Basic 68000 Assembly Lessons first!

Each lesson will have a matching Video tutorial, and if you just want the code, you can skip knowing how it works, and just download the code!

Enough talk, let's start creating code, and put those 68000 machines to work!

Lesson P1 - Bitmap Functions on the X68000

The x68000 has a built in dedicated graphics card, it's memory is accessed through the normal addressable range, but there are some quirks!

In this lesson we'll learn how to set up the graphics screen, print text from a 1bpp font, and draw a bitmap to the screen!
Setting up the screen on the X68000
The X68000 sceen is a bit odd, it typically works at 256x256 or 512x512 - which is square (and causes a problem for many VGA monitors), it can also do a 512x256 mode (which I believe is tecnically running at 512x512)...

To set up the screen we want  need to write the correct byte data to the memory mapped registers - a chart of the correct working values is shown below, and you probably don't want to alter these if they work for you!

High Resolution Low Resolution
RegNum 768x512 512x512 512x256 256x256 512x512 512x256 256x256 Register Purpose
E80000 $89 $5B $5B $2B $4B $4B $25  R00 Horizontal total
E80002 $0E $09 $09 $04 $03 $03 $01  R01 Horizontal synchronization end position timing
E80004 $1C $11 $11 $06 $04 $05 $00  R02 Horizontal display start position
E80006 $7C $51 $51 $26 $45 $45 $20  R03 Horizontal display end position
E80008 $237 $237 $237 $237 $103 $103 $103  R04 Vertical total
E8000A $05 $05 $05 $05 $02 $02 $02  R05 Vertical synchronization end position timing
E8000C $28 $28 $28 $28 $10 $10 $10  R06 Vertical display start position
E8000E $228 $228 $228 $228 $100 $100 $100  R07 Vertical display end position
E80010 $1B $1B $1B $1B $44 $44 $24  R08 External synchronization horizontal adjust: Horizontal position tuning 

$05 $01 $00  R20 Memory mode/Display mode control

$00 $00 $00  R0 (Screen mode initialization) - Detail

$3E4 $3E4 $3E4  R1 (Priority control) - Priority

$81 $81 $81  R2 (Special priority/screen display) - Screen On
$FF $FF $FF $FF $FF $25  Sprite H Total
$15 $15 $0A $09 $09 $04  Sprite H Disp
$28 $28 $28 $10 $10 $10  Sprite V Disp
$15 $11 $10 $05 $01 $00  Sprite Res %---FVVHH

We're going to define a 'screenInit' routine which will turn on the graphics screen -
we can choose the resolution we want by defining a symbol, such as Res256x256

These Tutorials are using a 16 color mode (as it's most common on retro systems)

We need to set up the CRT parameters which will define how the screen image is formed - we also need to define the registers which will configure the screen layout.

Note: we're not doing anything with the sprite registers at this time - at the time of writing, hardware sprites are not used in these tutorials, though theyy may be added later!

if you want more info on the registers, please see the GamesX website, or the (Japanese) X68000 technical data book 

The X68000 is capable of multiple color depths and multiple layers of paralax,
In these tutorials we're only going to use one 16 color layer - the reason for this is that we're going to do the same on a wide variety of 68000 systems (and even the same tasks on z80 and 6502 systems) and the vast majority of these systems support 16 color, but few support 256 colors.

Drawing Bitmap Graphics on the X68000
The X68000 screen is memory maps to the hardware, but it's slightly odd compared to other systems...

Each screen pixel uses two bytes of memory WHATEVER the screen mode! - so whether you're using 4bpp or 8bpp, you're still going to use
Address Purpose
$c00000 Graphics Vram – Page 0
$c80000 Graphics Vram – Page 1
$d00000 Graphics Vram – Page 2
$d80000 Graphics Vram – Page 3
We're going to use the A6 register to write data to the screen - we'll use a 'GetScreenPos' command to convert an X,Y pos (in D1,D2)

We're using Graphics Screen 0 - which starts at $C00000...

Each X pixel takes 2 bytes - so we do a ROL to shift X left 1 bit

Each Y line is 1024 bytes, so we do 8+2 ROL's to shift Y left 10 bits... we can't do ROL #10, the command doesn't support it
We have a GetNextLine command to move down a line as well...

Using the bitmap routine
We can show a bitmap sprite to the screen, buy using the GetScreenPos command to set the correct memory position in A6

We're going to read in a sprite in 'Packed format' where both nibbles of the byte is used - we'll need to split these up and write them in separate words to the screen memory

We need to use GetNextLine to move down after each complete line.

Bonus!... waiting for VSync to slow down a game
VSync on the X68000 is possible via the MFP (MC68901)... we can test bit 4 to see if the screen is in Vsync... by waiting for Vsync to start and end, we can make sure a new vsync starts before we continue processing...

This was used in the Grime 68000 game
This Vsync routine was used in Grime 68000 to slow down the game, but it's not perfect, on a 100mhz x68 it's much faster than a 1st gen machine... but this is the best the author has managed to do so far!

PrintChar - using out Bitmap font to print characters
Our 'PrintChar' routine will show an Ascii character in D0 to the screen...

Essentially we're using the same code as above, but now we're using Cursor_X and Cursor_Y as 'character position' for calculating the screen postion

When it comes to actually plotting to the screen, we're popping of a bit of the font lines, and moving it to 'color 15' of the byte, before drawing it to the screen.

Once we've drawn the character to the screen, we increase the X position - and see if we've reached the width of the screen, if we have then we run the NewLine command to wrap to the next line.
You'll need to define Cursor_X and Cursor_Y in ram somewhere... also not there's some simple LOCATE and CLS commands not shown here, download the sources.z7 if you want to see them!

Lesson P2 - Bitmap Functions on the Atari ST

The Atari ST has a ram based screen - we can just allocate some memory, and write data to it to get it on screen...
The layout is a bit odd - it's split into bitplaines in 16 pixel Words... lets see what that means!
Screen Layout
Lets take a look at how bitmap data is stored on the Atari ST...

The screen is 16 color - which means we need 4 bits for each color...
These colors are stored in 'Bitplanes' - this means each byte defines one of the color bits for 8 pixels.

On the Atari ST pixel data is stored in words... 16 pixels worth of data for a single bitpalne are stored in a Word... the next word will be the next bitplane for the same 16 pixels... and so on for all 3 bitplanes...

After all 4 bitplanes for the first 16 pixels, the next 16 pixels will start...

The screen is 320 pixels wide, so each line is 160 bytes across... and Line 1 is 160 bytes after Line 0 in the memory.

Hardware Registers
The Atari ST uses memory mapped registers to control the screen...
These registers are defined from $FF8200-$FF8260.... Note that because the 68000 uses a 24 bit address bus, the byte is usused - you may see in some documentation addresses like $FF8200 shown as $FFFF8200... these are the same address.

We need to define an area of our memory for screen use... we use $FF8200-$FF8202 to define it but only the bottom byte of each word address ... the screen will take 32000 bytes of data, however we can only specify the top 16 bits of the 24 bit address... this means the bottom byte of the screen address must be Zero - eg : $????00

The Atari ST has 3 screen modes - we'll be using mode 0 in these tutorials, which give 16 colors at 320x200... we set the screen mode by writing to $FF8260

We can also set colors with addresses $FF8240-$FF825F - one word defines each color.

Address Mode Bits Purpose Details
FF8200 RW -------- HHHHHHHH  Video Base H Need 32256 bytes per screen
FF8202 EW -------- MMMMMMMM  Video Base M Can’t specify L byte
FF8240 RW -----RRR -GGG-BBB  Palette Color 0
FF8242 RW -----RRR -GGG-BBB  Palette Color 1
FF8244 RW -----RRR -GGG-BBB  Palette Color 2
FF8246 RW -----RRR -GGG-BBB  Palette Color 3
FF8248 RW -----RRR -GGG-BBB  Palette Color 4
FF824A RW -----RRR -GGG-BBB  Palette Color 5
FF824C RW -----RRR -GGG-BBB  Palette Color 6
FF824E RW -----RRR -GGG-BBB  Palette Color 7
FF8250 RW -----RRR -GGG-BBB  Palette Color 8
FF8252 RW -----RRR -GGG-BBB  Palette Color 9
FF8254 RW -----RRR -GGG-BBB  Palette Color 10
FF8256 RW -----RRR -GGG-BBB  Palette Color 11
FF8258 RW -----RRR -GGG-BBB  Palette Color 12
FF825A RW -----RRR -GGG-BBB  Palette Color 13
FF825C RW -----RRR -GGG-BBB  Palette Color 14
FF825E RW -----RRR -GGG-BBB  Palette Color 15
FF8260 RW ------SS  Screen Mode 00=320x200 @4bpp
01=640x200 @2bpp
11=640x400 @1bpp

Setting up the screen
We need to define some ram for the screen...

we're going to define a 'BSS' section in our code...

Data in this section does not exist in the compiled file... but any data areas in it  will be allocated by the operating system ... they will ALLWAYS be initialized to ZERO, so we can only use DS to define areas, not DC

Because we need the bottom byte of the screen start to zero, we're going to allocate 256 bytes more than we need.

We'll start by changing the screen resolution by writing $00 to $FF8260

Now we need to use the address of the ram we defined in the BSS section... however we need to zero align it - as we can't set the Low byte of the screen address

Lets assume the screen_mem symbol has the address $00123456...
Our aligned screen will be $00123500... we'll store this in 'ScreenBase' ... but when we store this into $FF8200 - we need the two bytes to be in the low bytes of the words... so we shift it... converting $00120035

Finally, we'll define some basic colors to start us off

Calculating a screen position with GetScreenPos
We're going to define our GetScreenPos function we'll take an Xpos (in bytes) in D1, and a Ypos (in lines)  in D2

We'll have to calculate an offset to our screen base... as the 4 bitplanes of16 pixels (2x4 bytes) are grouped together, for every 16 pixels, we move 8 byte...  we do this by ignoring the bottom bit of the Xpos, and doing 2 bit shifts

but we need to move along one, to the middle of the word if the selected screen byte is odd... we do this by adding the bottom bit of the XPos

Each line of the screen has 160 bytes... so we multiply the Ypos by 160, and add this to the screen position...

This gives us the resulting position to write our byte data to

If we want to move down a line, we can just add 160 to our current position to do it.

Waiting for VBlank
We may need to wait for VBlank to delay our games and make them run at even speed...

We can use function $25 of Trap 14 (Xbios) to wait for the vblank.
Alternatively we can use the Vblank counter at address $462 - this is a counter that's updated by the firmware every time vblank occurs.

Ideally, we'd rather go direct to the hardware and detect VBLANK rather than using the firmware, but the author of these tutorials is too stupid to figure it out!... if you know how, please give him a clue - and tell him how it works!
Showing a Bitmap to the screen
We're going to define our bitmap with all 4 bitplanes in concecutive bytes (this is the same format we'll use for the amiga)

This means we'll have to write all the bytes to the 4 bitplanes - and we'll have to move in an odd pattern:

We'll write 4 bytes (offset to point to the bitplane)  - move 1 byte , then write another 4 bytes (also offset to point to the bitplane),
Finally we'll move another 7 bytes... this will move to the start of the next word... and we'll repeat the procedure again!

We could use Atari ST native format, but there are advantages to storing the data byte aligned, and converting it to word alignment.
The reason we're doing this is it allow us to write to any byte aligned X position - whereas if we used native Atari ST screen foramt we'd have to be word aligned.

Lesson P3 - using the FIX layer to draw bitmaps on the NeoGeo

The NeoGeo is not a bitmapped screen - so we can't set pixels in memory ... and unlike other consoles, the NeoGeo's backgrounds are made up of 16x16 Sprites not an 8x8 Tilemap...

However the NeoGeo does have an 8x8 FIX layer - which is deigned for onscreen text and other such stuff - and to get us started, we can use it to do our Chibiko Bitmap!
What is the Fix Layer
Most Console systems will have 2 types of graphics layer... a 'Tile Map' which is a grid of predefined 'tiles'... these are usually 8x8 in size... on a 16 bit system, usually multiple layers of tilemaps exist to define parallax...

On top of this we would add sprites to make our player character and other such things...

But the NeoGeo HAS NO TILEMAP!
So how does the NeoGeo work with no Tilemap?

Well... sprites on the NeoGeo are 16 pixels wide, and can be up to 512 pixels tall - but they can be combined!... and because the NeoGeo is capable of a whopping 380 tiles, we can combine 20 of them together to 'simulate' a tilemap!... this is how background graphics are drawn on the Neogeo!

On top of this are our 'normal' sprites - enemies, player characters and such...

There is one final layer, the 'Fix Layer'... this is made up of 16 color 8x8 tiles, in a simple grid... it's designed to do onscreen text and the like... but I used it in GrimeZ80 to do all the game graphics... so if your needs are simple, and you want 8x8 block graphics, it can be used for the job...

but don't worry, we'll learn about sprites later

Grime 68000 used the FIX map for all it's graphics... but we should have probably used Sprites...

Sprites are 16x16 - but the NeoGeo has Hardware scaling, so we could scale them down to 8x8 - We'll learn all about Sprites in a later lesson!

Mysteries of The Fix Layer!
The Neogeo screen has a resolution of 320x224, and each tile is 8x8 - giving an effective screen size of 40x28...

The actual tilemap is 40x32... the top and bottom two lines are not show (Shown in red on the chart to the right)

However, because of the CRT layout - it is likely that the left and rightmost 1 column will not be visible (Shown in orange to the right)... this gives a visible screen of 38x28

The Fix Layer is positioned in VRAM at &7000 (each position contains 1 word / 2 bytes)- each Tile is defined by 16 bits in the following format:

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

Where P is the Palette number, and T is the Tile number

The fixmap appears at $7000 in Vram... tile data for the Fixmap are in ROM

Each address contains a WORD...

Write a word to $3C0000 to select VRAM Address
Write a word to $3C0002 to Send data to VRAM

Tiles in memory are ordered in COLUMNS... so in memory (X,Y) co-ordinate (0,1) comes after (0,0) ($7000)... and (1,0) comes 32 words  ($7020) after (0,0)

For example - to set tile (0,2) to tile 256 in palette 1 (note this is in the "May be offscreen" area, but should appear on an emulator)

    Move.W  #$7002,d1        ;Address - Tile 2
    Move.W  #$1100,d0        ;PTTT    - Palette and tile
    Move.w d1,$3C0000       ;set address in vdp
    Move.w d0,$3C0002       ;set tile data in vdp

Start End Words Zone Description
$7000 $74FF 4096
Fix map
Fix Layer tiles are in an odd format!

Each tile is 8x8 at 4bpp ... so 32 bytes per tile...
The two nibbles of each byte represent 2 pixels , but they are BACKWARDS... so the 1st (High) nibble is the 2nd pixel color, and the 2nd nibble (Low) is the 1st pixel color

The bytes are stored in Columns, then rows... and the columns are out of order too! .. Visible pixels ABCDEFGH are stored in Ram in order FEHGBADC

The 8 bytes of each column are in normal top->bottom format... so at least that:s something!
My AkuSprite editor (used in these tutorials) has support to export images in the correct "FIX" format for the NeoGeo
The FIX and SPRITE formats are different on the NeoGeo which is VERY ANNOYING!

You can use AkuSprite Editor to create valid files - and remember, it's open source, so if it doesn't do the job well enough, you can use the source to make something better!

Defining our ROMS via MAME XML
We need to define our FIX rom data in the NEOGeo.XML... we'll split the fix data into 3 files...
NAME specifies the filename
OFFSET specifies the memory position in the 'ROM' of the Neogeo
SIZE is technically the size of the file - but mame doesn't seem to check if it's correct (Warning: it does with sprites!)
CRC / SHA1 - these are hashes of the rom - if they are incorrect MAME will complain

we're defining 3 files
     202-s1.s1 - This is the NEOGEO firmware fonts, we'll leave them alone
     FONT.FIX  - This is the ChibiAkumas font used by these tutorials, you'll need this for the PrintChar routines to work
     RawNEO.FIX - this is the bitmap data we're going to use today to show 'Chibiko' onscreen!

If we want to create a 'proper' rom file, we'll need to calculate the correct Hashes, but it's quicker to skip it, and the game will run, so it's OK for our testing

Getting our bitmap to the screen
We're going to put our 'Chibiko' character on the screen, the sprite is 48x48, so it's made up of 6x6 FIX tiles...

We'll set the correct positions of the fix tilemap to the parts of the bitmap.
We're going to use a function called FillAreaWithTiles... this will take a start XY position, a Width and Height, and a start Tilenumber... it will fill the entire area with consecutive tiles Left->Right, Top->bottom

Note... the NeoGeo works the opposite way: Columns first, then Rows

We're allocating tiles 0-255 for our font, so we're using tile 256 for our Chibiko Bitmap
When we call our FillAreaWithTiles function, we'll need to convert the X,Y co-ordinate into a memory

The first 2048 tiles ($800) are used by the firmware - we're also going to use Palette 1 - so we add $1800 to the tile number to get the data we write into VRAM

We then need to calculate the offset in the FIX map for the tile we want to change... the fixmap is organized in Column/Row order (Going down then Across)...
We do this by adding X*32+Y to the start address of the fixmap ($7000)

We shift the Xpos left 5 times with ROL.L #5 - multiplying X by 32...

Because the top 2 lines of the NeoGeo screen are not viewable, we add 2 to the Ypos

To set the Tile, we write the address we want to change to $3C0000.... and the TileNumber/Palette to $3C0002

We repeat the procedure for each of the tiles we want to draw to the screen.

Lesson P4 - Bitmap Functions on the Sinclair QL

The QL's graphics are visually very different to the other 16 bits (if you count the QL as 16 bit!!)

It uses a fixed palette, of 8 primaries (RGBCMYWb) in mode 8, or 4 in mode 4 (bRGW)

Screen Layout
The Screen is memory mapped from $20000-$28000, it is also possible to have a second page at $28000-30000, but this will render the OS unusable, as it's fixed variables are in that memory

Lines are in a linear format, with each line 128 bytes below the last... two concecutive bytes make up 4 pixels in  8 color, or 8 pixels in 4 color mode.

There are two possible screen modes, configured by bit 3 of port $18063

setting a 0 give 4 colors at 512x256 with Black,Red,Green and White
setting a 1 give 8 colors at 256x256 with Black,  R, G B, C, M, Y and White

There is no palette - the colors are fixed... it is not possible to have 'brightness levels' - colors are on or off.

My AkuSprite Editor can export 4 or 8 color bitmaps, however it does not support Flashing mode.
8 Color Mode
  4 Color Mode  
Address   Purpose Details
$18063 Screen Mode S---C-O-
O=On (doesn't actually work!)
C=Colordepth S=Screenpage
$20000 Screen 1 Screen Ram
$28000 Screen 2 /
system (systemvars*)
$2847C System stack pointer*
$28E00 Base of Common Heap*
$2BC00 Free area*
$30000 Running
Free area

4 Color mode:
F E D C B A 9 8 7 6 5 4 3 2 1 0
G7 G6 G5 G4 G3 G2 G1 G0 R7 R6 R5 R4 R3 R2 R1 R0

8 Color mode: (F is flashing)
F E D C B A 9 8 7 6 5 4 3 2 1 0
G3 F3 G2 F2 G1 F1 G0 F0 R3 B3 R2 B2 R1 B1 R0 B0

Flashing in 8 color mode
Flashing only works in 8 color mode -it's a HARDWARE flash, and does not use th interrupts or firmware.

A flashing bit of 1 will toggle flashing ON or OFF... flashing always starts as OFF at the start of a line

When a Flashing bit 1 is set - all subsequent pixels will flash between their normal defined color and the color of the pixel with the flashing bit set.

F= Flashing bit of 1

Many Emulators don't bother to emulate FLASHing... QLAY2 doesn't do it, and Q-Emulator doesn't seem to do it right except in full screen mode... The latest versions of Zesarux DO seem to do it well though...

That said, Falshing mode is pretty dumb anyway, so you're not missing anything important if your emulator doesn't support it!

Selecting Screen Mode
When we want to change screen mode, we just set bit of $18063 according to the mode we want...
a 1 will set 8 color mode... a 0 will ser 4 color mode!

Calculating Screen position
When we want to calculate the memory location of an X,Y position, it's pretty easy.

using an X position in 4/8 pixel blocks, and Y in lines we can use following

Each 8 pixels uses 2 bytes, so we bit shift the X pos in D1 by one bit.

Each line uses 128 bytes, so we bit shift the Y pos in D2 by 7 bits.

Then we add $200000 - the offset to the start ofthe screen.
When we want to use this, we just need to copy the bytes from our source (created by AkuSprite) to the screen,

After each line we use GetNextLine to move down the screen to start drawing the next line...

Because 4 color mode has twice as many pixels per byte, we need to alter our line total in D1 depending on if we're in 4 color mode or not. 
This routine will show a simple bitmap...

We also have 'PrintChar' routines, these use a 1bpp font, and show letters from a common font (used on all the systems)

The Sinclair QL's screen is pretty limited for a 16 bit machine, but remember... it's an 68008 - which has an 8-bit data bus, so technically it's and 8 bit machine... this means it's much slower than an Amiga or similar... and you'll have to optimize yout code more to keep the games fast.

The reduced graphics were probably and unavoidable sacrifice considering the price-point and early release of the machine.

We can use Vsync to slow down our game... by waiting for Vsync, we can wait for the next screen redraw

If we want to test for Vsync (the start of screen redraw) we need to use Port $18021... bit 3 will go high (1) when Vsync starts... we need to write a 1 to that same bit at the same port to clear the Vsync event...

Therefore, in effect we can write 255 to port $18021, then read from $18021 until it's nonzero to get the Vsync event.

 7   6   5   4   3   2   1   0 
 $18021 Read  B M R X F T  I  G  B=Baud state, M=Microdrive inactive, R=Rtc state, X=eXternal Interrupt, F=Frame vsync, T=Transmit interrupt, I=IPC Interface interrupt G=Gap interrupt (microdrive)
 $18021 Write  R F M X F T  I  G  R=tRansmit mask, F=interFace mask, M=gap Mask,X=reset eXternal Interrupt,F=reset Frame vsync, T=reset Transmit interrupt, I=reset IPC Interface interrupt G=reset Gap interrupt

Lesson P5 - Bitmap Functions on the Genesis

The Genesis is a Tile - Sprite based system... this means we can't just plot data to the screen... we need to define our bitmap data as tiles in vram, then set those tiles as visible onscreen...

Lets give it a go!

Setting up our screen
We need to initilize our screen, to do this we need to set some VDP settings... these start with $8nvv - where n is the register number and vv is the value for the register... we'll load these from the table VDPSettings
We'll be using the values shown for our tutorials...

you can change the values if you wish, but if you change things like the name table positions, the tutorials will not work correctly unless you also alter the code that draws characters and tiles to the screen
We're going to set up a simple palette to get us started...

Basically, each color in the palette has two bytes defining it's RGB value, but we're not going to go into more detail at this stage, as we'll be covering it in more detail later.
We've now done the basics... so we'll start the screen display, then convert our 2 bit font to tiles in the tile definitions.
Setting Reg 16 to 01 defines a tilemap of 64x32 - we could define one that's 32x32 or 64x64, but as our visible screen is 40x28 so 64x32 seems a good choice!

If you change it, or the memory address of Scroll A, then you're going to have to change the rest of the code in todays example!

Defining Tile patterns
When we want to write data to the VDP, we just write the data value to address $C00000 (vdp_data).... but first we need to select the VDP destination address using $C00004 (vdp_ctrl)

We'll need to select addresses from $0000-$C000 to define our tiles and each tile takes 32 bytes.

Unfortunately, because the VDP address select is designed to be backwards compatible with the SMS, the bytes we have to send to select the port are a little odd!... Effectively the top two bits of the address are moved to the bottom two, and the top two bits are set to %01...

you can see some how various sample VDP addresses convert to address select commands in the table to the right.
Memory Address
$0000 $40000000
$1000 $50000000
$2000 $60000000
$3000 $70000000
$4000 $40000001
$5000 $50000001
$6000 $60000001
$7000 $70000001
$8000 $40000002
$9000 $50000002
$A000 $60000002
$B000 $70000002
$C000 $40000003
$D000 $50000003
$E000 $60000003
$F000 $70000003
$FFFF $7FFF0003
Vram Address Possible Use
$0000 Pattern definitions
$C000 Scroll A – Tilemap
$D800 Sprite Attrib table
$E000 Scroll B – Tilemap
$F000 Window Map
$FC00 Hscroll Table
Selecting VDP memory is really confusing... but don't worry, we're going to create a little function that will do all the work for us!

The reason it's so confusing is the Genesis was designed to be backwards compatible with the Master system... that's why the genesis  uses a Z80 for it's sound chip - it can be used as the main CPU for SMS support!

To simplify sending data to the VDP we'll create a command called 'PrepareVram'

This will calculate the correct address to write to within the VDP
When we want to define tiles, we'll just copy the tile data into the VDP...

We'll define the start of the tile definitions in A0, the destination in vram in D2, and the bytecount in D1
When we want to transfer our tile definitions to VRAM, we can just call this 'Define Tiles' command.
Of course, you'll need to convert a bitmap into the correct format for the VDP... but you can do this with my AkuSprite editor!

It's free and open source, and you'll find it in the sources.7z
AkuSprite editor supports all the systems covered by these tutorials... and It'll be extended to cover any systems added in the future.

It's only a basic program, but you can load bitmaps in via the clipboard so you can use a more advanced eitor like Krita to do the hard work

Getting our tiles on the screen
We've now got our 'Chibiko' bitmap in vram as patterns, but we need to get it on screen... the bitmap is 48x48 pixels... meaning it's made up of 6x6 (36) tiles...

To show our bitmap on the screen we need to set the tiles in the positions we want to the correct pattern numbers for our bitmap!
We're going to define a command called 'FillAreaWithTiles'

We'll pass it a Start XY position, a width and height, and a start tilenumber (256 - the first 128 are used by our font)

The command will calculate and set the tiles to get our bitmap onscreen!
We've defined our tile map as 64 tiles wide, and 32 tiles tall... each tile definition takes 2 bytes... this means each row of the tile map is 128 bytes...

Therefore, to calculate our memory address within VRAM, we use the formula $C000+(Y*128)+(X*2)
F E D C B A 9 8
7 6 5 4 3 2 1 0

T=Tille number  H=Hflip  V=vflip  P=palette number  
=Layer (in front of /behind sprites)
We're going to merge our calculation of the byte position in VRAM and our 'PrepareVram' command to save CPU power,

For each line, we'll calculate the starting address of the line and send the VRAM select command to the VDP

We'll then start writing our tile numbers to VRAM... The VRAM address automatically increments after each write, so we don't need to recalculate until we've completed the whole line, but we do need to increment our tile number in D4

After each line we recalculate the memory position for the row below,

We continue this procedure until the the bitmap is drawn to the screen!

Of course this is just a simple example... but you can use it to create something better... Take a look at Grime 68000 if you want to see a more advanced example!

We've only looked at Tiles so far, but don't worry, we'll look at sprites later!
We can use Vblank as a way of slowing down our game... Vblank occurs when the screen restarts drawing, so happens 60 times a second (50 on PAL systems)

We can detect Vblank using bit 3 of data read from the Control port, we just read in a byte and test it, if the bit is 1 we're in VBlank.

We can wait until Vblank starts, and ends to ensure our game isn't running faster than 50fps.

Lesson P6 - Bitmap Functions on the Amiga

The Amiga is essentially a 'bitmap' based system, we allocate an area of memory to be our screen data, and we can write data into that area to get our pixels on the screen,

However there are some complexities to getting things working, so lets learn how to make it behave!


The Amiga screen is essentially a bit-planed bitmap within 'Chip Ram' (the built in memory of the Amiga - not upgrade memory)... we can write bytes to this ram, and they will immediately appear on the screen - but first we need to set the screen up!

Graphics on the amiga are controlled by the 'Chip Registers' a set of memory mapped registers which control the screen... in theory we could access these directly... but in practice we need to use the "Copper" graphics CO Processor...

We give this a set of commands defining the screens location and shape in ram!

Bitplanes and colors
The Amiga works in 'Bitplanes'... this is where each byte of data for the screen contains a single bit of 8 pixels - called a bitplane...  4 of these bitplanes combined will allow us 16 colors...

The Amiga 500 supports up to 6 bitplanes, We can optionally configure these bitplanes into 2 layers in parallax...

The Amiga can use up to 32 colors in a single layer (5 bitplanes) ... or have two 3 bitplane layers with 8 colors each (odd numbered bitplanes will be layer 1, even numbers will be layer 2)

In these tutorials we'll be defining one 320x200 layer of 16 colors (4 bitplanes)... this is because it will give good 'compatibility' with the Atari ST, and the other systems we're covering in these tutorials.
8 pixels we want to set:

Bitplanes compared to nibbles

Copper list commands
We're going to need to use a copperlist to set up our screen...  Copperlist commands can set a chip register, or wait for a particular screen position

Word 1
Word 2

F E D C B A 9 8  
7 6 5 4 3 2 1 0    
F E D C B A 9 8  
7 6 5 4 3 2 1 0     Command Details
0 0 0 0 0 0 0 n
n n n n n n n 0
D D D D D D D D Change setting n= address to Change ($DFFnnn) D=new data for address
H H H H H H H 1
v v v v v v v v
h h h h h h h 1 wait for pos V=Vops H=Hpos v=Vpos Compare enable h=hpos compare enable

The copperlist should end with an infinite wait '#$fffffffe'

Setting up Chip Ram
We need our screen and the 'Copperlist' for the co-processor  to be contained within the 'Chip Ram'

To ensure this we need to define a 'ChipRAM' section  - the Assembler / Linker will create an executable file, and the operating system will ensure this area of the program is in the correct

We're also going to use the command 'CNOP 0,4'... this zero pads the area to a 32 bit boundary - needed for the screen data

Now we have some memory, we can start setting up the screen!

'Chip Ram' in the Amiga is the basic ram of the machine (not add on upgrades)... we need it to do tasks like Graphics and Sound FX...

Our main code probably isn't running in Chip ram, so we can't 'tag' our screen buffer in there - we have to declare proper section, so the Assembler will build the correct executable and the OS will give us our memory

Setting up our screen
The first stage of setting up our screen is calling the os, and opening the graphics library ...

we'll use this to turn on the screen, but we'll do all the other screen config by directly manipulating the hardware registers!

You can see the different libraries the Amiga has here ... and the full contents of the Graphics library here

We're going do the basics of defining the screen size, bitplanes and position.

we need to use the chip registers to do this (see here for the full list)

We're going to set up our 320x200 16 color (4 bitplane) layer,

Next we'll set up the screen position

Finally we want to start the DMA control to handle the screen...

we're now going to set up our copperlist that will define the screen memory and colors!

Setting up our copperlist

We need to define our copperlist, the Coprocessor will use it to draw each frame of our screen.

As mentioned before, the copperlist commands are made up of two words per command,

The first word (2 bytes)  is a register number... for example $00e2 is $DFF0E2

The second word (2 bytes)  is the new value for the command.

First we'll define the memory location of the 4 bitplanes that make up our screen - they'll be 8000 bytes apart (40x200)

Then we'll define our starting color palette... we'll also remember the memory position of the palette definitions, as we can use it later to change our colors.

The last commands is a command to wait forever ($fffffffe) ... the list will automatically restart when the next screen redraw starts.

When we've defined our copperlist, we load the address of the copperlist into the pointer of the Chip Ram - our screen is finally set up!

The example here is just creating a single plane, you could have more colors, or more planes with a more advanced set up, but that's beyond the scope of these tutorials - but feel free to play around if you want!

Getting our bitmap data to the screen
Our  screen is split into 4 bitplanes, and as the screen is 320 pixels wide (40 bytes) and the screen is 200 lines tall, then each bitplane will be 8000 pixels apart.

Of course, if we want to set the color of a pixel, we'll have to set all these bitplanes, and we'll see that in our code
Offset from Screen_Mem Bitplane Number
Bitplane 1
Bitplane 2
Bitplane 3
Bitplane 4
We can see this mimicked in our bitmap copying code...

The byte data of the bitmap are in bitplane format (exported by my AkuSprite Editor)

4 consecutive bytes bytes are copied to each bitplane.

We use the GetScreenPos to calculate the correct memory position from a X,Y position (where X is in Bytes, and Y is in lines)

We also use GetNextLine to move down a line at the end of each line of our bitmap
The bitmap will be shown to the screen at the position we specified!

Want to convert a bitmap for use on the Amiga? The Free & open source AkuSprite Editor can do it for you!

It's included in the sources.7z, so go get it if you want!

Calculating screen co-ordinates
Setting up the screen was hard, but  Calculating a screen position is easy.. all we need to do is multiply our Ypos  by 40 (the width of the screen) and add X , and the base of the screen.

Moving down a line is also easy, we just add 40 to the current position!
Of course, calling a routine to move down a line is a pretty lousy to do things if you're just doing an Amiga game, you should just put that ADDA straight in the loop!

The reason we do the call is we're supporting lots of machines with the common drawing code... THEN it makes sense!

Testing for Vblank VBlank

If we want to slow our game down, a good way is to wait for Vblank (The start of screen redraw)

this will cap our game to 60/50 hz, and keep our game speed under control

We can test for Vblank on the Amiga by testing $DFF004 (VposR)

Learn Assembly for the Greatest Classic Processors:  Z80 - 6502 - 68000
Visit to get my games and their source code! | Support me on patreon