Learn Multi platform 6502 Assembly Programming... For Monsters!
Super Simple Series
In this series we'll take a look at a variety of basic tasks that you may need to look at when you're starting out with programming these classic systems...
In each case the source-code will be a single file with no Includes to make things easy if you're using a different assembler (though some may include a binary.)
Supervisor mode on XM7
On WinX68kHighSpeed we can access hardware registers in USER mode,
but emulator XM6 is more strict. We will need to enter 'Supervisor mode'... we do this with DOSCALL function _SUPER ($FF20)... Thanks to viewer 'Mugsy' for this info |
![]() |
Starting our program
First we need to turn on our screen - we need to send a variety of
settings to hardware registers. Here we're setting up a 256x256 screen mode - if you want to see the full range of settings see here |
![]() |
Next we need to set up our palette... we need 4 colors, defined by
$E82000+ Each color is defined by 5 bits. We're now set up... so we can work on drawing our sprite! |
![]() |
Drawing an 8x8 sprite
Drawing a larger bitmap
We've used bitmap
graphics here to draw our 'sprite'... it's easier for a beginner
getting started to just work with bitmaps. if you want to use actual hardware sprites take a look here |
![]() |
![]() |
Lesson
S2 - Simple Bitmap Drawing on the Atari ST Let's look at the basics on the Atari, Lets learn how to draw a simple bitmap onto the screen... effectively a software sprite. |
![]() |
![]() AST_Bitmap.asm
|
![]() |
Starting our program
Drawing an 8x8 sprite
Drawing a larger bitmap
![]() |
If we preferred we could
write in words, which would be faster, but less flexible for
different widths most systems work in 8 pixel bitplanes - not the Atari ST's 16 pixels - so we've written this code to work with the format used by other systems. |
Starting our program
Drawing an 8x8 sprite
Drawing a larger bitmap
The Copperlist
is quite complex, but it's needed to do everything with the amiga
screen... Unfortunately the 'Chibiko' mascot isn't in the right colors, but we can fix that... see here |
![]() |
![]() |
Lesson
S4 - Simple
Bitmap Drawing on the
Sinclair QL Lets take a look at the Sinclair QL - we'll use 8 color mode to draw a simple smiley, and our mascot |
![]() |
![]() SQL_Bitmap.asm
|
![]() |
Drawing an 8x8 sprite
Drawing a larger sprite
![]() |
We've looked at
8 color mode here... but the QL also supports a higher resolution
4 color mode. But I won't tell you about it!... What you really want to? well... ok - see this lesson here! |
This tutorial
will extend the 'Hello World' Episode... We're not going to cover
the code that is the same as that episode.. If you've not seen the Hello World episode, see it here. |
![]() |
Drawing a single 8x8 tile
Drawing a larger image
This tutorial
assumes you've watched the 'Hello World' Episode, and adds to that
lesson.. Not watched it yet? Don't worry, there's still hope for you... just check it out after you read through this episode - ok? |
![]() |
Drawing a single 8x8 tile
Drawing a larger image
![]() |
This example used the FIX map, Want to use sprites? Check out this tutorial! |
The Code
If you want to
use more joystick buttons, take a look at this tutorial Here...
the x68k can use MSX type or Genesis type joypads! |
![]() |
![]() |
Lesson
S8 - Simple Joystick Reading on the Atari ST Lets extend our Atari Example, and use traps and vectors to read in the Joystick |
![]() |
![]() AST_Joystick.asm
|
![]() |
The Code
![]() |
Want more
details on the Joystick of the Atari ST? Check out This tutorial here |
The Code
This example
builds on the Hello World and bitmap examples... See Hello world here. |
![]() |
The Code
The Sinclair QL does
have joystick ports... but they emulate cursor keys!... so we
don't need to do anything special to use the plug in Joysticks
(although they are super rare!) |
![]() |
![]() |
Lesson
S11 - Joypad Reading on
the Sega Genesis Lets extend the previous bitmap example, and learn how to move an 8x8 smiley tile around the screen. |
![]() |
![]() GEN_Joystick.asm
|
![]() |
The Code
Joystick Reading
![]() |
The weird layout and
splitting of the buttons is to maintain compatibility with the old
Master System controllers... The genesis has basically an entire master system built in, with sound chip... Z80 and backwards compatible video. |
The Code
Joystick Reading
Don't forget!...
The Fixmap bitmap data for the smiley is never transferred to VRAM
- it's all in ROM, and is defined by the MAME XML. |
![]() |
Logical Units and clipping
To allow us to crop our sprites, we'll need to move our sprite
around 'logical space' - only a portion of this will be the visible
screen. We'll use this to crop the sprite. |
![]() |
We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit) The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side. |
![]() |
We need to crop any offscreen part to
get to the first visible pixel of the sprite. After each line We also need to crop the unused pixels to the next visible pixel |
![]() |
The X68000 actually
allows for easy per pixel movement, so our Logical units of 2x2
pixels will be a little less smooth than is possible. The main reason we're using this constant logical unit definition is to allow easy porting of code between platforms. |
![]() |
Our Sprite Routine
Before we draw our sprite we need to crop it with "DoCrop" registers D1,D4 is the X,Y co-ordinate in logical units registers D3,D6 is the Width,Height in logical units register A6 is the address of the source bitmap data. If there is nothing onscreen, 'DoCrop' will return the Carry set. |
![]() |
GetVDPScreenPos will calculate the VRAM destination into A2 We then transfer bytes from A6 to A2 to move the VRAM destination down one line we add 1024 after each line we update the source bitmap, adding the transferred bytes, and any bytes that need to be skipped at the end of a line (SpriteHClip) |
![]() |
GetVDPScreenPos will calculate the VRAM destination A2 from X,Y
pos (D1,D4) The formula is $C00000 + Ypos *1024 + Xpos |
![]() |
Logical Cropping
Our cropping routine will work out the X,Y pos in bytes, and width
and height + any skipped pixels from the source data registers D1,D4 is the X,Y co-ordinate in logical units registers D3,D6 is the Width,Height in logical units register A6 is the address of the source bitmap data. First we zero D2,D5 - they are used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line |
![]() |
Ok... lets crop the top of the sprite... First we remove the ypos of the first visible pixel from the draw ypos (D4)... if the result is greater than zero, then nothing is off the screen at the top. if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite (D6), if the amount to crop is not less than the height then the sprite is completely offscreen. Anything else is the number of lines we need to remove from the top, we store this in D5 and set the new 'draw position' to Ypos (D4) =0 |
![]() |
Next we do the same for the bottom, We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop |
![]() |
We've calculated the top (d5) and bottom (d2) crop... we now use these to calculate the new height of the sprite (D6). | ![]() |
We then skip over any bytes in the source (A6) based on the number
of lines we need to remove from the top. |
![]() |
now we do the same for the X axis First we remove the xpos of the first visible pixel from the draw Xpos (D1) ... if the result is greater than zero, then nothing is off the screen at the left. if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite (D3), if the amount to crop is not less than the width then the sprite is completely offscreen. Anything else is the number of lines we need to remove from the left, we store this in D5 and set the new 'draw position' to Xpos (D1) =0 |
![]() |
Next we do the same for the right, We add the width (D3) to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop from the right (d2) |
![]() |
We've calculated the left and right crop... we now use these to
calculate the new width of the sprite (D3). We then skip over any bytes in the source (A6) based on the number of bytes we need to remove from the left (D5). |
![]() |
We've finished cropping our sprite!... but we need to convert our
co-ordinates from logical units (pairs of pixels) to a tile count -
effectively muultiplying Xpos,Ypos and Height by 2. We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return. |
![]() |
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return | ![]() |
Logical Units and clipping
To allow us to crop our sprites, we'll need to move our sprite
around 'logical space' - only a portion of this will be the visible
screen. We'll use this to crop the sprite. |
![]() |
We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit) The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side. |
![]() |
We need to crop any offscreen part to
get to the first visible pixel of the sprite. After each line We also need to crop the unused pixels to the next visible pixel |
![]() |
The blitting code
works in 16 bit words, so chunks of the sprite disappear when we
get to the edge of the screen. If we want to fix this, we need to define a wider screen with an 'offscreen' area of at least 1 word on the left and right. |
![]() |
Our Sprite Routine
Before we can use the blitter, we need to enable the Blitter DMA with $DFF096 | ![]() |
Before we draw our sprite we need to crop it with "DoCrop" registers D1,D4 is the X,Y co-ordinate in logical units registers D3,D6 is the Width,Height in logical units register A6 is the address of the source bitmap data. If there is nothing onscreen, 'DoCrop' will return the Carry set. |
![]() |
First we need to ensure the last blit finished... we do this with
WaitForBlit! Then we convert our X,Ypos from Logical units to horizontal words, and vertical lines. We then Use GetScreenPos to calculate the VRAM destination position. |
![]() |
There are a lot of settings we need to set up for the drawing of our sprite via BLIT we can only work in 16 bit words, but we can bit shift the bits of the sprite to allow for smooth movement between 2 byte blocks. We XOR the sprite with the current screen contents, we use the function $5A = !AC+A!C to do this... where A is the sprite, and C is the current screen contents. |
![]() |
GetVDPScreenPos will calculate the VRAM destination A2 from X,Y
pos (D1,D4) We have So our formula is Addr = ScreenMem + (Ypos * 40 * 4) + Xpos |
![]() |
Logical Cropping
Our cropping routine will work out the X,Y pos in bytes, and width
and height + any skipped pixels from the source data registers D1,D4 is the X,Y co-ordinate in logical units registers D3,D6 is the Width,Height in logical units register A6 is the address of the source bitmap data. First we zero D2,D5 - they are used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line |
![]() |
Ok... lets crop the top of the sprite... First we remove the ypos of the first visible pixel from the draw ypos (D4)... if the result is greater than zero, then nothing is off the screen at the top. if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite (D6), if the amount to crop is not less than the height then the sprite is completely offscreen. Anything else is the number of lines we need to remove from the top, we store this in D5 and set the new 'draw position' to Ypos (D4) =0 |
![]() |
Next we do the same for the bottom, We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop |
![]() |
We've calculated the top (d5) and bottom (d2) crop... we now use these to calculate the new height of the sprite (D6). | ![]() |
We then skip over any bytes in the source (A6) based on the number
of lines we need to remove from the top. |
![]() |
now we do the same for the X axis First we remove the xpos of the first visible pixel from the draw Xpos (D1) ... if the result is greater than zero, then nothing is off the screen at the left. if the result is less than zero we need to crop... we convert the negative to a positive and compare to the width of our sprite (D3), if the amount to crop is not less than the width then the sprite is completely offscreen. Anything else is the number of lines we need to remove from the left, we store this in D5 and set the new 'draw position' to Xpos (D1) =0 |
![]() |
Next we do the same for the right, We add the width (D3) to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop from the right (d2) |
![]() |
We've calculated the left and right crop... we now use these to
calculate the new width of the sprite (D3). We then skip over any bytes in the source (A6) based on the number of bytes we need to remove from the left (D5). |
![]() |
We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return. | ![]() |
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return | ![]() |
![]() |
Lesson
S15 - Simple Sprite Clipping on the Atari ST Lets extend our Atari Example, and add sprite clipping so the sprite can go partially offscreen. |
![]() |
AST_BitmapClipping.asm
|
![]() |
Logical Units and clipping
To allow us to crop our sprites, we'll need to move our sprite
around 'logical space' - only a portion of this will be the visible
screen. We'll use this to crop the sprite. |
![]() |
We're designing our code for screens of 256x192 - and we'll use 'Logical Co-ordinates' which define a visible screen of 192x96 (2 pixels per logical unit) The visible logical screen is in the center of the logical space area to allow the sprite to be 'partially offscreen' on any side. |
![]() |
We need to crop any offscreen part to
get to the first visible pixel of the sprite. After each line We also need to crop the unused pixels to the next visible pixel |
![]() |
Our sample code does
not bitshift the bits of the sprite, this means we can only move
horizontally in 8 pixel blocks... This means jerky horizontal movement, but pixel shifting all the blocks would be quite slow. |
![]() |
Our Sprite Routine
Before we draw our sprite we need to crop it with "DoCrop" registers D1,D4 is the X,Y co-ordinate in logical units registers D3,D6 is the Width,Height in logical units register A6 is the address of the source bitmap data. If there is nothing onscreen, 'DoCrop' will return the Carry set. |
![]() |
We need to fix up our co-ordinates. Our routine works horizontally in 8 pixel blocks, and we need to reduce our width (in D3) by one for DBRA We vconvert the Xpos to byte blocks (8 pixels) We need to convert our height (D6) and Ypos (D4) from logical units to lines We then use GetScreenPos to get the VRAM destionation (in register A2) |
![]() |
Our Sprite routine transfers 4 bytes of our source sprite to the 4 bitplanes. We XOR (eor) the source data with the screen data, this inverts the screen data, and allows us to remove the sprite by drawing it a second time. The 4 bitplanes are in 4 consecutive words in VRAM, so after 2 bytes we need to skip the next 6 bytes. We repeat until the sprite is done. |
![]() |
GetVDPScreenPos will calculate the VRAM destination A2 from X,Y
pos (D1,D4) We have each 320 pixel line is 160 bytes, but we have to cope with the fact that pairs of bytes are grouped together, but the bitplanes of those pairs are in 8 consecutive bytes in vram. |
![]() |
Logical Cropping
Our cropping routine will work out the X,Y pos in bytes, and width
and height + any skipped pixels from the source data registers D1,D4 is the X,Y co-ordinate in logical units registers D3,D6 is the Width,Height in logical units register A6 is the address of the source bitmap data. First we zero D2,D5 - they are used for temp values, and spritehclip which is used for the horizontally skipped bytes after each line |
![]() |
Ok... lets crop the top of the sprite... First we remove the ypos of the first visible pixel from the draw ypos (D4)... if the result is greater than zero, then nothing is off the screen at the top. if the result is less than zero we need to crop... we convert the negative to a positive and compare to the height of our sprite (D6), if the amount to crop is not less than the height then the sprite is completely offscreen. Anything else is the number of lines we need to remove from the top, we store this in D5 and set the new 'draw position' to Ypos (D4) =0 |
![]() |
Next we do the same for the bottom, We add the height to the Ypos, and subtract the height of the logical screen, if it's over the screen height (greater than zero) we need to crop again - the result is the amount to crop |
![]() |
We've calculated the top (d5) and bottom (d2) crop... we now use these to calculate the new height of the sprite (D6). | ![]() |
We then skip over any bytes in the source (A6) based on the number
of lines we need to remove from the top. |
![]() |
now we do the same for the X axis First we remove the xpos of the first visible pixel from the draw Xpos (D1) ... if the result is greater than zero, then nothing is off the screen at the left. if the result is less than zero we need to crop... we add 4 to round up the amount to crop. Anything else is the number of lines we need to remove from the left, we store this in D5 and set the new 'draw position' to Xpos (D1) =0 |
![]() |
Next we do the same for the right, We add the width (D3) to the Xpos, and subtract the width of the logical screen, if it's over the screen width (greater than zero) we need to crop again - the result is the amount to crop from the right (d2) |
![]() |
We've calculated the left and right crop... we now use these to
calculate the new width of the sprite (D3). We then skip over any bytes in the source (A6) based on the number of bytes we need to remove from the left (D5). |
![]() |
We clear the carry to tell the calling routine we cropped the sprite successfully (it needs drawing) and return. | ![]() |
If the sprite is completely offscreen, there's no point trying to draw, so we set the carry and return | ![]() |