Welcome

Friday, August 29, 2025

SNasm

 Code Assemble !

Assembling your first application isn't quite as simple as it is on the C64 with Kick.

There are a couple of important assembler directives that must be used or what you assemble won't work at all.

The first is:

OPT ZXNEXT

This option will enable the extended Spectrum Next functions such as the NEXTREG command which is used to talk to the hardware registers of the machine.

ORG $C000

This option tells the assembler where to start the code addressing from, the address $C000 is a common place to start applications, especially for new devs who don't yet know the hardware. The 1st 16k is ROM, this can be paged out but not until the program has loaded and is running, the second 16k is, by default, used for the screen and user defined tiles, this depends upon the screen mode and can be moved. 

The top 32k is all yours!

Finally:

savenex "../bin/main.nex",StartAddress,StackStart

is required, this tells SNasm how to write out the file so that it can be executed on the next.

The filename is simply the path and name of the file to produce, to keep things tidy I like to drop this into a bin (or binary) directory which can then be passed to the emulator.

The StartAddress is the address of the first line of the program that will be run, usually this is the same as the ORG value set above but you can specify any memory address to start the code. One very important thing to note is that if you wish to start your code in a particular memory block make sure that the label is AFTER the ORG command not before it.

ie

    ORG $C000
StartAddress:
    ...

NOT

StartAddress:
    ORG $C000
   ...

doing the the latter will set the start code to end of the previous code block (or zero if its at the top of the code). Guess how I found that out.

Finally the Next needs to know where its stack is, unlike the 6502 the stack is not in a fixed memory page.

Firstly you need to allocate a block of memory for the stack, the size of the stack really depends on how and what the program does. If the program has a lot of recursion,  for example, more stack space is required. Usually I would suggest 256 byte as a reasonable value.

A simple and predictable way to define this is:

ds 255
StackStart:
db 0

Remember the stack grows backwards in memory so we define the label after the reserved space and the first element on the stack is zeroed.

Obviously you could just set a variable to an area of memory you expect to be free but I prefer to define it, it save tears later. 

It doesn't really matter where the stack is place although my preference is to put it at the end of any blocks of data rather than at the end of a block of code. This way if the stack grows beyond the reserved space it corrupts data rather than code, which is easier to trouble shoot, especially if it graphics data as it will be obvious something is overwriting. Corrupt code just does weird stuff that is not always obvious to diagnose. 

The Spectrum Next!

Spectrum Next 


Like many, many people I have backed the Kick Stater for the Spectrum Next and I'm planning on once again half finishing a bunch of projects that will never see light of day. That said it keeps me out of trouble so I thought I'd document a few of my adventures.

For my first steps I need to set up a development environment and as usual this will be on my Mac, though much of this will apply to Windows users too. In fact most of the tools I'm using here are .NET tools running under mono. Mono a Mac project that simply allow .NET application to run on a Mac. 

If you are using a Mac you will need to download  and install Mono Framework before starting. This is available free from https://www.mono-project.com/docs/getting-started/install/mac/

I've chosen to go with CSpect as my emulator, from what I've read in the forums and generally in the community this is a well regarded product and so far it's worked very well for me. It can be downloaded from https://mdf200.itch.io/cspect for free but personally I always give a few quid to the devs, these things don't write with themselves.

CSpect also includes a copy of SNasm which is my assembler of choice for this project. Both products have been developed by Mike Dailly who is not only a great dev but seem like a totally awesome guy too so thanks for your work Mike. It seems only fair to give Mike's web site a plug too so here it is https://lemmings.info

Ok now for the editor, Sublime text is my go to code editor, has been for years. But this is probably personal choice and if you want to use notepad++ or even worse VSCode it makes no difference.

Once you have downloaded all the components its time to install them, if you're using a Mac run the mono installer package and just take the defaults.

To simplify all the relative paths for building, covered later, I made a very simple file structure. Again this will make sense later.

spectrum
-CSpect
-gameName
  -bin
  -src
  -assets

These are all relative but their placement is important later on.

First job is to copy CSpect directory from download to the spectrum folder. There will be a version tagged onto the filename, remove the version number and just call the folder CSpect. This make the path names in build script much easer to troubleshoot later on.

The SNasm assembler is already in this folder.

Also under the spectrum folder create a sub directory for each new project.

The structure of folders in the project folders just help to keep files organised and isn't essential, I just get a bit anal about code being in the "right" place.

In the project folder create a text file named build.sh and give it execute permissions, for windows this would be build.bat and you won't need to set execute permission.

Use chmod +x build.sh to make the file executable.

Edit the build.sh file and paste the following:

#!/bin/bash
  echo
  echo "   Doing some assembling   "
  mono ../../CSpect/SNasm.exe -map ./main.s ../bin/main.dat
  echo "        Assemble done   "
  mono ../../CSPect/CSpect.exe -map=../projectName/bin/main.dat.map -zxnext -w5 -mmc=.i/ ../bin/main.nex

The echo statements are optional but it lets you see how things are progressing. This file can be copied to any project just edit the projectName in the last line.

I always use the main.s file as my core code file for all projects, just habit. if you start file is called something different just edit the file. Remember too that on the Mac case is important so just check that first if there are any issues.

For windows users remove the mono command at the start of the lines.

Unfortunately the mono command does not pass through any return codes from the applications so if the assemble fails there is no way to detect it and stop the script, the emulator just fires up and runs the last version of  program that did assemble.

There are also a number of additional parameters you can pass to emulator, there are detailed in the readme file in the CSpect directory. This basic command line seems to do the job for me.

Now all that's left to do is setup a hot key in the editor to assemble and run. Again this is editor dependant but for Sublime I created a new build system and named it SpectrumNext using the following settings.

{
"shell_cmd": "build.sh"
}

Now when you open the base directory of the project and him apple-b the program assembles and fires up the emulator.

Sunday, March 3, 2024

Setting up Mega65 Connect for LAN

The latest Mega65 Core (0.96) now supports remote access from the  M65Connect using Jtag and now ethernet. This guide will explain how to setup a Mac/PC to use the new LAN features.


The order of these steps is not necessarily important; its just the order I think makes most sense.

Note: You must have a full login to the mega65 file host website.

  • From the file host download the latest Core package
    • Using the instructions in the download install the core to the M65
    • Copy the files in the sdcard-files directory to the root of the M65 boot SD card
    • Reboot the M65
  •  Download and install the latest version of M65Connect from the file host
    • There are some permission issues with the MAC version of the  application, follow the instructions in the download section to resolve these
  • Connect the Mac/PC and the M65 to the network
  • The Mega65 uses IPV6 for communication with M65Connect, for Windows users go into the network configuration and ensure IPV6 is ticked, its been a while since I used windows and I'm not sure if IPV6 is enabled by default. A Link-Local address will automatically be assigned be assigned. For Mac users this should already be enabled.  Linux users may need to google, sorry.
  • Start M65Connect on the Mac/PC
    • In the bottom left of the window the status should read Not Connected to MEGA65
  • On the Mega65 press SHIFT £
    • The power light on the Mega65 will flash Green/Yellow
    • In the Bottom left of the M65Connect window the message should now read Connected to MEGA65 via LAN 
You should now be able to control the M65 from the Mac/PC, click the SD Card button in the M65Connect and you should be able to copy files too and from the MEGA65.

Trouble shooting:

  1. When you try to issue any commands to the M65 via M65Connect the M65 screens fills with random characters and crashes
    1. Likely cause is the ETHLOAD.M65 file has not been copied to the ROOT of the M65 boot drive
  2. M65Connect does not connect even though the M65 light is flashing
    1. Check and replace all ethernet cables, yes even if they are brand new
    2. The M65 has a 10/100 network interface, if you are using a switch ensure the port the M65 is connected to is not hard coded to gigabit or that the switch supports multiple port speeds
    3. If you are using a direct cable from the M65 to the Mac/PC you may need a cross over ethernet cable not a straight thought (normal) cable. 
    4. If the Mac/PC is using USB to Ethernet it may not support 10/100 speeds this is fine if its plugged into a switch but a direct connection to the M65 will not work
    5. If you are using a managed switch ensure that the Mac/PC and the M65 are in the same VLAN, even if your network is configured to use IPv6 routing it will not work because the M65 only supports link-local addressing 
I hope this helps.




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.

SNasm

 Code Assemble ! Assembling your first application isn't quite as simple as it is on the C64 with Kick. There are a couple of important ...