Welcome

Monday, September 27, 2021

Installing the Mega 65 Kick Assembler tool chain on a Mac


This is an explanation of how I implemented Shallan50k's tool chain in a Mac environment. This has only been tested on MacOS version 11.5 but I have no reason to believe it won't work on other versions.

Install xemu

 

Get the latest version of xemu from:

 

https://github.lgb.hu/xemu/

 

Open the installer and drag the xmega65 icon to the applications folder.

 

Open the xemu65 application and configure any options required. See mega65.org for detailed instructions on how to set up the emulator

 

Virtual disk tools

 

To create and write to virtual floppy disks you will need the c1541 tool which is part of the VICE C64 emulator package.

 

Download the latest version of vice and install into the applications folder.

 

Vice can be found here:

https://vice-emu.sourceforge.io

 

Setting up Kick 


*Please not KickAssembler is a Java application so you must install Java onto your Mac, installing Java is beyond the scope of this document but Google is your friend.

 

To code for the Mega 65 you will need the current version of Jesper’s Kick Assembler for which supports 45gs02 (Thanks Jesper!)

 

The files can be found here:

 

https://gitlab.com/jespergravgaard/kickassembler65ce02/-/blob/master/release/KickAss65CE02-5.21.jar

 

 

Download the Jar file and copy to: /Applications/KickAssembler and rename it to KickAss.jar

 

*you don’t have to use this location but I like to keep all my Apps in the Application folder. If you chose to put it elsewhere then ensure you make changes to reflect this path later on

 

Creating a make file

 

In the same folder as the main.s file (or whatever the core source file is called) create a file, the filename is not relevant but convention says use make.sh

 

Copy the following into the make file:

 

echo Assembling Code

java -cp /Applications/KickAssembler/kickass.jar kickass.KickAssembler65CE02 main.s -odir ./bin -vicesymbols -showmem 

echo making Disk

/Applications/VICE/x64sc.app/Contents/MacOS/c1541 -format "disk,0" d81 "./bin/disk.d81"

echo copying program to disk

/Applications/VICE/x64sc.app/Contents/MacOS/c1541 -attach "./bin/disk.d81" 8  -write "./bin/main.prg" main

echo launch xemu

/Applications/xmega65.app/Contents/MacOS/xmega65 -besure  -prg "./bin/main.prg" &

 

And save the file.

 

From a command shell change directory to the source code folder where the make file is located and type:

 

chmod +x make.sh

 

This will allow the make file executable.

 

Setting up sublime

 

From the Sublime Text menu select preferences, then browse packages. This opens a finder window, copy the syntax file from https://github.com/smnjameson/M65_KickAsm_Macros into this folder.

 

From the View->Syntax menu select KickAssember (Mega65) option.

 

All 45gs02 code will now be highlighted correctly, to test this create a test.s file and enter a command such as ldz #$50 and ldy #$50 they should be both highlighted the same.

 

 

Go to Tools->Build System->New build system…

 

Replace the default text with

 

{

 

            "shell_cmd": "./make.sh"

}

 

Then save it as mega65.sublime.build

 

From Tools->Build System now tick the mega65 build option.

 

Apple-key b will now build and run the project.

 

Finally and big shout out Shallan50k and Jesper for all the work they put in to get the mega 65 development environment working. All I did as put a few Apple twists to get it working on Mac. 

Saturday, January 30, 2021

 Shallan50K Spiral Competition.

Shallan50K recently created a competition to reproduce the image below in the least number of bytes.


A few people have asked about the zero page auto run aspect of the program so I thought I'd drop in a paragraph to explain it.

In zero page there is a small routine called CHRGET which is used by the basic interpreter, this routine is located at $73. When basic starts up it uses this routine to read either from the command line or from the basic program. Any program put here will run instead when the machine boots.

The easiest thing to do would be to place the program here and just have it run, unfortunately basic also uses $8b to initialise its random routines which means that if the program is longer that 23 bytes corruption will occur!

To solve this problem the program is loaded into lower memory with the last line of code lined up with $73 so that when basic runs the last line of the program runs instead! The last line of code needs to be a branch command to jump to the beginning of the program. The start location of the code has to move as the code changes to ensure that the branch is always located at $73.

Hope that make sense.


My solution to the problem is below:



/*


Turtles all the way down

(c) AMK Enterprises 2021

All rights reserved 


*/


// for PC

.const directionTableHigh = $0114 // would you believe it this memory block is $00,$00,$ff,$ff

// just what i need for the table! Winner Winner turtle dinner


// for mac

//.const directionTableHigh = $017e // would you believe it this memory block is $00,$00,$ff,$ff

// just what i need for the table! Winner Winner turtle dinner


.const theCount = $16 // HA HA HAR

* = $42


Entry:

jsr $e544 // kernal cls


!outerLoop:


inx  

xaa #$03

tax


clc

.byte $b5, <stepz__ // lda stepz__,x 

adc theCount // HA HA HAR

tay


!loop:


/*


move the cursor to the next point


*/


clc


.byte $a5, <cursor // lda cursor

.byte $75, <directionTableLow // adc directionTableLow,x

.byte $85, <cursor // sta cursor


.byte $a5, (<cursor)+1 // lda cursor+1

adc directionTableHigh,x

.byte $85, (<cursor)+1 // sta cursor+1


/*


draw an inverse @


*/


lda #$80 // inverse @ code

sta cursor:$3fe // dirty dirty dirty self mod code


/*


decrease counter

and

loop

*/


dey 

bne !loop-


/*


reduce the length of the line


*/

.byte $c6,<theCount // dec theCount - HA HA HAR


/*


if line length isnt zero do it all again


*/


bne !outerLoop-


/*


stay a while

.....

  stay for ever

*/

beq  *


stepz__:

.byte 16,0,16,0


directionTableLow:   

.byte -1,-40,1,40


* = * "jump"

bne Entry


Thursday, March 19, 2020

Using BCD

Binary Coded Decimal (BCD)


Binary coded decimal is a way in which decimal values are represented as digits in hexadecimal. In gaming one of the primary uses for BCD is to display information to the player such as scores or other details on screen.

So how does BDC differ from normal hex?

$28 in hex would be 40 in decimal, to converting hex to decimal in 6502 is a  semi-complex coding exercise which is also quite expensive in terms of CPU usage especially if the values are many digits long.

With BCD the values in the $28 are read as their decimal values, so $28 is 28, making it much easier to display on screen as there is no conversion required.

BCD splits the byte in half, creating two 4 bits values so $28 is represented as 0010 1000. So a byte when using BCD can store a number between 0 and 99. For numbers greater than 99 additional bytes need to be used as they would be when storing a larger number.

BCD mode cannot be used all the time it must be turned on and off whenever calculations are required on the values.

To turn on BCD use the sed instruction and the cld instruction turns off BCD. This can be check in a debugger as it sets a bit in the status flag, 1 for on 0 for off.

Example 1:

sed          ; set BCD mode
lda #$19. ; set a to NINETEEN
clc
adc #$11 ; add ELEVEN

cld          ; turn off BCD mode

after the abovet code is run the accumulator contains the value $30. Normally the expected value would be $2a.

Example 2:

sed          ; set BCD Mode
lda #$19  ; set a to NINETEEN
sta temp   ; save to memory
inc temp   ; increase memory

cld           ; turn off BCD mode

in this example the memory address (temp) now contains the value $1A, not $20; some commands do not support BCD.

example 3

To add 150 (decimal) to a score, for example, the usual carry flag rules still apple

score:
        .word 5011

sed          ; set BCD mode
lda score  ; get the lower byte
clc
adc #$50 ; add the lower part of the score

sta score

lda score+1 ; get next. byte
adc #$01     ; previously the carry bit was set because 50+50 = 100 the 1st digit goes into the carry

sta score+1
cld          ; turn off BCD mode

      
The score will now be 0013, remember that in 6502 we store the numbers in little-endian format. 1150 + 150 = 1300.

This example can be continued for as many digits as required,

BCD is just a representation so if the values need to be compared or accessed for other reasons the BCD mode does not need to set, the values can simply be read and worked upon.

Example 4

To print the values to the screen the individual digits can be accessed and used.

number:
      .byte $21

lda number      ; get the number
; print the left digit 1st, to do this move the top 4 bits to the bottom 4 bits
lsr
lsr
lsr
lsr
clc
adc #digits                ; where digits is the value of the 0 in the character set
sta startOfScreen

lda number.     ; get number again
and #0f            ; mask out the top 4 bits
adc #digits
sta statrtOfScreen

The above example takes a single byte, isolates the two halves of it and prints two digits to the screen, note there was no need to use the sed command as the program just reads the digits as they already are.

The value for startOfScreen will depend upon where the program and placed the screen and will usually need an offset to make sure the information is printed in the correct place.

The value for digits is whichever character code the current character set starts the number characters from. The position in which the number characters are placed has no effect on how this works.

For values longer than one byte simply repeat the process for each byte of the number remembering to make sure it is printed in the correct order 

Monday, February 3, 2020

Setting up Hardware


Setting up the Hardware


According to the advertising at the time, the Commodore 64 had a huge 64k of memory, yet when the computer is booted it proudly announces that there is 38991 bytes free. So what happened to the other half of the memory?

For the computer to operate it needs an operating system, which in the case of the C64 is the Kernal, and yes its spelled with an 'a' not an 'e' that's just what Commodore called it. The Kernal provides very simple functions, such as loading to and from disks, reading the keyboard etc. all of which are critical to the computer working the way it should, but that takes memory. The C64 also has the BASIC computer interpreter built in again this uses memory.

When writing a game there is very little use for the Kernal and absolutely zero use for the BASIC interpreter, in fact usually the Kernal is only used to access files on the disk or tape which can easily be replaced by more efficient user code.

The C64 has 64k of RAM, at boot time the Kernal and BASIC ROMs are switched out with some of this RAM but it is possible to switch this ROM back out and enable the extra RAM.

Disabling the BASIC and Kernal routines also has the added benefit of freeing up the whole of zero page memory, (I will cover zero page in another post). For now, it is enough to say that this is a very good thing.

The initHardware function is the first subroutine to call when starting any game program.


initHardware: {

   //Disable CIA IRQ's to prevent crashes
lda #$7f
sta $dc0d
sta $dd0d

//bank out BASIC and Kernal
lda $01
and #%11111000
ora #%000101
sta $01


// set VIC to BANK 3
lda $dd00
and #11111100
sta $dd00

// set screen to char mem
lda #001100
sta $d018

rts
}

The first block of code disables the CIA interrupts, these interrupts trigger Kernal functions and since the Kernal is about to be removed they must be disabled to prevent the system crashing.

The second block makes the RAM at addresses $A000-$BFFF and $E000-$FFFF available, this would usually be the BASIC and Kernal respectively. It also makes the RAM at $D000-DFFF available, however, this memory is used by the VIC and SID chips and is write only. Any data stored in this area can be used by the VIC but if the memory is read by the program the ROM data is returned. I will return to this in depth in another article.

The third block of code tells the VIC chip which bank of memory to use, the VIC chip is only capable of seeing 16k of memory and all of the addresses used by the VIC are offset to the selected back. The bottom lower two bits specify which bank to use. In the example above the VIC bank is at the top of memory, out of the way. 

The bank options are:

, 0: Bank #3, $C000-$FFFF, 49152-65535.
%01, 1: Bank #2, $8000-$BFFF, 32768-49151.
%10, 2: Bank #1, $4000-$7FFF, 16384-32767.
%11, 3: Bank #0, $0000-$3FFF, 0-16383.

The final block sets the character set pointer and the start of the screen memory, in this example the screen starts at $0800 and the character set at $2000 both relative to VIC bank.

This means that in this example the screen starts at $C800. because we have set the VIC bank to 0 and the screen to $800 so the screen starts at $800 bytes from the start of the VIC bank.

Thursday, January 30, 2020

Sample Sprite Code


Sample Sprite Code


As I stated earlier on the interrupt and simple sprites post, I prefer to draw all my sprites in simple games as soon as the raster interrupt has triggered. This avoids any flicker and it also means that I can use a single routine to draw all the sprites, which makes the code simpler to debug as all the screen updates are in one place.

The first step is to setup a table in memory to hold all the values that will be needed to draw the sprites, I usually prefer to store these in zero page because of access speed though its not necessary.

The first thing to do is define the table:

spriteXLow:
    .fill 8,0
spriteXHigh:
    .fill 8,0
spriteY:
    .fill 8,0
spritePointer:
   .fill 8,0
spriteColour:
    .fill 8,0
spriteStatus:
    .fill 8,0

This code uses the Kick Assembler directive .fill which simply creates 8 bytes of zero's for each label. This can be replaced with .byte 0,0,0,0,0,0,0,0 or any similar commands supported by other assemblers.

One thing to note here is that the high byte for the X co-ordinate is stored as a byte not, as discussed previously, a shared byte. This is because whilst setting these variables it is easier and quicker to set the X coordinate as a 16bit number and let the sprite draw code take care of the VIC limitations.

Another advantage of using this table is the fact that it can be used to store the working information about every sprite, you do not need to keep separate variables for each sprite, they just live here.

I also use a a spriteStatus byte for each sprite which can be used to hold various in-game attributes for the sprite. In a later post I'll look at using this for setting individual sprite into double width, double height and mixing multi colour and hi res sprites, butfor now I'll keep the routine simple.

So lets look at an example:

Sprite 0 is 280 pixels across the screen and 100 pixels down the screen, it should be coloured red and use sprite 64.

To set the sprites attributes we store the relative attributes into the table, sprite 0 is the first column of the table so I'll load the values into the label + 0, the reason I use + 0 is to demonstrate that this is an entry into a table in column zero, an aid memoir so to speak (idea blatantly stolen from Shallan50k)

One reason I always use hex when writing assembler is that it makes 16bit numbers easier to split into bytes, which will help with the X co-ordinate.

The X co-ordinate is 280 which is hex is $0118 so the low byte is $18 and the hight byte is $01

lda #$18
sta spriteXLow + 0

lda #$01
sta spriteXHigh + 0

Now to set the Y, this is easier as there is only one byte. 100 in hex is $64

lda #$64
sta spriteY + 0

spritePointer is the sprite number which I covered in the previous post, this it just the sprite number.

lda #$40
sta spritePointer + 0

Where possible it is better to use a descriptive label when setting a value, the Kick Assembler has builtin constants for colours so I'll use one here.

lda #RED
sta spriteColour + 0

For the time being I will leave the status flag alone, I will expand on what can be done with status flags in a later post.

The values for the sprites can be updated anywhere in the game code.

The code to produce the sprites consist of two routines, the first one is only called once and set-up some VIC settings which don't, for now, need to be changed every time sprites are drawn.


.const spriteEnable      = $d015
 .const spriteMulticolour = $d01c
.const spriteDoubleWide  = $d01d
.const spriteDoubleHeight = $d017

initSprites:{




// enable sprites

lda #$ff
sta spriteEnable

// set all sprites to multi colour

lda #$00
sta spriteMulticolour

// set sprites to single height an width

lda #$00
sta spriteDoubleWide
sta spriteDoubleHeight

rts


}

The initSprite subroutine should be called at the beginning of the program and simply sets all sprite to hi res, normal size and enables them all. It's always a good idea to define all constants and use the labels in a program, it makes debugging so much easier. A typo in a label will be flagged by the assembler whereas a mistype in an address in hex will usually result in a bug.

Once the sprite information is loaded into the sprite table the drawSprites routine can be called once per raster frame and all the hardware sprites are drawn to the screen.

highBit:
.byte 0

bitSet:

.byte $01, $02, $04, $08, $10, $20, $40, $80

.const sprite0X = $d000

.const spriteColour0 = $d027
// The value of screenRam may change depending on which
// blocks of memory have been switched out
// refer to the memory bank section
.const screenRam = $c000
.const spriteBaseAddress = screenRam + $3f8


drawSprites:{




// clear the highBit

// This is a variable to consolidate all of the X high bits

lda #$00

sta highBit

// loop through all of the sprites

// using the X register an index

ldx #$07

nextSprite:


// As esplained previously the X and Y registers in the VIC chip

// are interlaced so for every sprite you need to double the
// offset to the VIC register
// to do that I'll use the Y register and double it

txa
asl
tay

// set X lower byte
// using the x register to index into the sprite table
// and the y index to point to the VIC
lda spriteXLow,x
sta sprite0X,y


// now set the pesky high hit

// rather than keep changing the VIC register for every sprite
// ive created a variable call highBit which gets updated every sprite
// but only written to the VIC at the end

lda spriteXHigh,x

beq dontSetBit

// The bitSet will be explained in detail below


lda bitSet,x

ora highBit
sta highBit

dontSetBit:



// set sprite colour

lda zeroPage.spriteColour,x
sta spriteColour0,x

// set Y co-ordinate : dont get the Y and the Y co-ordinate confused
// the Y register has nothing to do with the Y co-ordinate
lda zeroPage.spriteY,x
sta sprite0X + 1,y


// set this sprite colour

lda spriteColour, x
sta spriteColour0, x

// set this sprite colour

lda spritePointer, x
sta spriteBaseAddress, x


// and loop back to the top for hw next sprite

dex
bpl nextSprite

// now we can set the highBit for the X sprite as its a single byte for all sprites

// the A register will all ready hold the correct value
lda highBit
    sta spriteXMSB


}



Once the drawSprite routine has been called the values in the sprite table can be updated for the next frame without affecting the current on-screen sprites.

*The bitSet table:

The bitSet table contains 8 values, each value corresponds to a single bit, as below.

000001
000010
000100
001000
010000
100000
%01000000
%10000000

By indexing into this table it is possible to select a single bit and apply that to a register or another variable.

For example, to set the high bit for sprite 5 we need to set bit 5 in the MBS register, to do that we take the 6th element in the bitSet table (6th because we start counting at 0). The 6th element in the table is 100000 which when ORed with the MSB register turns on the bit for sprite 5 and only for sprite 5.


Tuesday, January 28, 2020

Simple Sprites

Simple Sprites


The hardware sprites available on the C64 are quite limited but if used well can be quite effective. Sprites are controlled but the VIC chip and by setting different registers in the VIC chip the sprites can be displayed and manipulated.

So what is a sprite? Well in simple terms its a graphical image which is 24 x 22 pixels in hi res mode and 12 x 22 pixels in multi colour mode. And yes 24 x 22 is high res, its all relative.

In hi res a sprite can be 2 colours and by two colours I mean one colour and transparent. In multi colour mode sprites have three colours and transparent but two of the colours are the same for all sprites and one can be unique to each sprite. Sounds limiting, yep it is.

Sprites can also be double width and double height but that doesn't mean there are more pixels to work with, the pixels are just double the width or height making the sprite look more chunky.

Due to a limitation in the amount of memory the VIC chip is able to address the location of all VIC data is set relative to VIC page, this is covered in the banking kernal and BASIC section. For the purpose of this section assume that kernal and BASIC are switched out and that the screen has been remapped to $C000. This is explained fully in the kernal section.

To control a sprite we must give the VIC certain information, this is done by setting values into the memory that can be read by the VIC chip.

The important values we need are:
  • X co-ordinate of the sprite
    • How far across the screen should the sprite be drawn, this point is the top left of the sprite graphic including any transparent pixels
  • Y co-ordinate of the sprite
    • How far down the screen should the sprite be drawn, this point is the top left of the sprite graphic including any transparent pixels
  • The sprites individual colour
    • Each sprite has one colour that can be set independently of all other sprites
  • Is the sprite double width
    • Simple toggle on or off
  • Is the sprite double heigh
    • Simple toggle on or off
  • Where is the graphic for the sprite
    • I'll go into greater detail on this below
  • Is the sprite enabled
    • Each sprite can be turned on or off individually


This doesn't, at first glance, look too complicated but its 1982 and the limitations of the chips and addressable memory are very restrictive. Back in the early days saving as much memory as possible wasn't just a good idea it was an absolute requirement.


So lets look at the X co-ordinate for the sprite. There are 320 visible pixels across the screen of but there is also the screen border. It is possible to place a sprite into the border but the only part that will be displayed is parts which over lap onto the viewable screen. The border is 24 pixels wide so the top left of the viewable screen starts at 24 not 0. There are then 320 pixels across the viewable screen so the last addressable pixel in the viewable area is 343. This is a problem. Its a problem because the memory location used to store the X co-ordinate is a single byte, values of 0 - 255, so we need to a second byte to hold hold the high value of X. As I mentioned above memory is was at a premium and as the max value X can't attain is 376 the developer realised that they didn't need a full byte they only needed on extra bit.


Theory bit to be completed..... Hayes needs the sample code





Negative Numbers

Negative numbers


Negative numbers are surprisingly complicated when working in assembler, firstly there is no minus sign inside the registers just 0s and 1s and when is a negative number actually a negative number? 

Well it comes down to context so lets look at some examples.

An 8bit register or memory location can hold numbers from 0 - 255 ($00 - $ff) and these numbers are all positive.

But let’s look at an example:

lda #0
sec
sbc #1

We set a = 0 and subtract 1 from it from it, so a now equals -1 but if you look at the value of a in a debugger you will see its set to $ff or 255! But also the negative is set, so does that mean 0 - 1 = -255?

Well no, when working with signed numbers computer use a system called 2's complement. With 2 complement we can represent numbers from -128 to +127. Bit 7 becomes a sign bit so numbers starting with a 1 are positive and numbers starting with a 0 are positive.

I don't want to go too deeply into this for the time being as its not really that relevant to games development on the platform, but if I get any feed back to suggest that this is a topic worth a deep dive I may reconsider. There is plenty of information on the internet on this subject and I really don't want to repeat what many other people have done already.



Installing the Mega 65 Kick Assembler tool chain on a Mac This is an explanation of how I implemented Shallan50k's tool chain in a Mac e...