Category Archives: Assembly

Commander X16 Introduction to graphic put char function using assembly.

The Commander X16 has a nice graphic library to help you get started. At the time of writing the Programmers Reference Guide is still early in its development and I found it a little difficult. 

It took me several days to get the graph_put_char function to put anything on the screen so I thought I should write a guide to help others.

The code listed in this guide was created for the ca65 cross-compiler. I used Visual Studio Code as my text editor with git version control. For use on r36 of the X16 emulator.

Initially, I spent time reading the Graphics section of the Programmers Reference Guide. It all seemed straight forward but I wasn’t getting visual results. I kept on coming back to it and then posted for some help on the FB page and the forum. With a bit of help seeing working code I was able to figure it out.

Before we go much further I just want to show the X16 screen co-ordinate method. The top left-hand corner is 0,0. The odd point which caught me out is for text, the anchor point is the bottom left-hand corner. So if you position a character at y=0 the text will be off-screen.

X16 Screen co-ordinates and character anchor point

The below code is for configuring variables and setting everything up. I created a zero page variable which is going to point to the string variable that my function will then display to the screen. I have created a ‘kernal.inc’ file which has several system constants to make the code easier to read. I then created 3 string variables with some test string data.

;-----------------------------------------------------------------------------
.segment "ZEROPAGE"
; here is where you put any zero page variables.
; These are all items located in the $0000-$00ff memory space
; On the X-16 Users c can use $0000-$007F. Kernal and Basic zero page is $0080-$00FF
pointerToString = $22
pointerToStringLow = $22
pointerToStringHigh = $23
;-----------------------------------------------------------------------------
.segment "STARTUP" ; This segment contains the startup code which initializes the C software stack and the libraries
.include "kernal.inc"
;-----------------------------------------------------------------------------
.segment "DATA"
; here is where you put raw data / binary / sprites / text blobs / etc
; variables
; strings
textString1: .asciiz "this is string 1"
textString2: .asciiz "this is string 2"
textString3: .asciiz "this is string 3"

In the below code I create part of my main function. To make my code easier to read I created the kernal.inc file. This file has several constants declared. Eg SCREEN_MODE_320x200x256C = $80, or COLOUR_RED = $02. This hopefully makes my code easier to read. In my kernal.inc file I also added constants for all of the kernal functions. Instead of looking up the jump addresses each time I can use the kernal function names to call them. Eg SCREEN_SET_MODE = $FF5F. The first step in my main function was setting the screen mode to the 320×200 graphics mode. Eventually, all of the kernal graphics functions will respect the window clipping setting, currently, only 2 functions use it, graph_put_char and graph_clear. Looking at the documentation for GRAPH_SET_WINDOW we can see that r0 will be the origin x co-ordinate and r1 will be the origin y coordinate. I set them both to zero. I had been experiencing strange results and I think that was because of non-zero/high values in the r0H and r1H. So I now make sure to zero them fully. We also see that r2 will be the width and r3 will be the height of the clipping window. I set those to 319 and 199 respectfully. Then I jumped to the subroutine. Now I wanted to set the graphic function colours. GRAPH_SET_COLORS takes 3 parameters. .a is the stroke colour, .x is the fill colour and .y is the background colour. For this example, I am going to use red colour for the pen/stroke colour. 

;-----------------------------------------------------------------------------
.segment "CODE"
jmp main
.proc main
    ; set the screen mode using a kernal function
    lda #SCREEN_MODE_320x200x256C
    jsr SCREEN_SET_MODE; set the graphic window size
    ; set r0(start-x) and r1(start-y) to zero
    stz r0L ; STore Zero in to location
    stz r0H
    stz r1L
    stz r1H
    ; set r2 (width)
    lda #<319
    sta r2L
    lda #>319
    sta r2H
    ; set r3 (height)
    lda #<199
    sta r3L
    lda #>199
    sta r3H
    ; use the kernal function
    jsr GRAPH_SET_WINDOW
    ; set the graphic colours
    lda #COLOUR_RED
    ldx #COLOUR_PURPLE
    ldy #COLOUR_BLUE
    ; use the kernal function
    jsr GRAPH_SET_COLORS

The basic configuration has been done, now time to set which string we want to display and where. I created a local label @drawString1: to help me break up the main function and make it easier to read. Once again r0 and r1 will be our x and y starting co-ordinates. Then I needed to figure out how to be able to change which string will be displayed to screen. I had used pointers in C before so I thought it should be simple enough. And it is. I load the low address byte into .a and then store it in my pointer low variable. Then load the high address byte into .a and store it in my pointer high variable.

@drawString1:
    ; set start x/y position of text
    lda #7 ; 8 pixels for both x and y, remember we count from 0, 0-7
    sta r0L ; STore Accumulator to location
    sta r1L
    stz r1H ; STore Zero in to location
    stz r2H; point to the string
    lda #<textString1 ; get the low address byte from memory 
    sta pointerToStringLow ; 
    lda #>textString1 ; get the high address byte from memory
    sta pointerToStringHigh
    ; now call my function to display string
    jsr write_text

My write_text function is below. I wrote a short description so I know what it does. I’m slowly learning assembly and I’ve noticed a few times my registers values changing. I figured I would try and prevent my code from stomping on registers. In this code, we can see I’ve pushed the .y on to the stack. Once I’ve stored .y I reset it to 0 as I will use it as a counter. I then store it in variable r11. I create a local label @loop: and the code in here will be used to read in the string and exit the loop when all of the string has been read. Looking at GRAPH_PUT_CHAR documentation we can see that r0 and r1 are our x and y coordinates. We also see that .a is our single-byte character. I did have a problem for a while with only the first character being displayed. It was only when I used the debugger and watched all the registers that I noticed that .y when from being 00 to A0 and I knew that wasn’t right. So to me, it appears that GRAPH_PUT_CHAR changes the value of .y. So I put some extra code to load .y from r11, increase it, resave it to r11 then jump back to the start of the loop. Once the loop has finished I pull the original value of .y off the stack and return to the main function.

.proc write_text
    ; requires r0 and r1 set for x and y
    ; requires pointer be set to point to string to write to graphics
    ; will preserve .y
    phy ; PusH Y on to stack
    ; set counter
    ldy #0
    sty r11
@loop:
    ldy r11 
    lda (pointerToString),y ; go to pointed to memory address and read offset .y in to .a
    beq @end ; Branch if EQual, if zero flag is set then branch to @end
    jsr GRAPH_PUT_CHAR ; looks just graph_put_char stomps on y
    ; load the .y counter, increase it and store it
    ldy r11
    iny
    sty r11
    jmp @loop
@end:
    ply ; PuLl Y back off stack
    rts ; ReTurn from Subroutine
.endproc

I then finished off the main function with a little local label @loop: and jmp @loop to create an infinite loop.

@loop:
    jmp @loop
.endproc

To download the source files for this guide visit my Github repository.

I would encourage any feedback or comments to improve this guide.

Commander X16 Bank switching in Assembly and Intro to x16emu debug

Bank Switching in assembly

In the Commander X16 the memory range from $a000 to $bfff, 8k of ram, will be banked. This will allow the computer to access up to 2048k (2Mb)

I am planning on creating a game using assembly and loading all of the graphics/sprites/text in the initial load and then switch banks to access them. Looking at the forum I couldn’t find any posts about bank switching and very little on using the emulator debugger. So I decided to do a guide after I figured out something useful.

The code listed in this guide was created for the ca65 cross-compiler. I used Visual Studio Code as my text editor with git version control. For use on r36 of the X16 emulator.

I did some reading of the Commander X16 Programmers Reference guide and found the reference to banked memory. The manual did direct me to the I/O Programming section but it didn’t help me much. This listed $9F61 as the byte to adjust banking 0-255. The X16 will have a minimum of 512k so that is banks 0-63. Personally, I hope they just ship all of them with 2048k, banks 64-255. One less configuration option to make it easier for the programmers.

The below code is my initial config before my main loop. I have created the string which I am going to copy into the banks. I’ve declared VIA1 at $9F61. I’ve declared a few kernal functions that I will use. I’ve declared three variables and allocated memory locations for them. bank_selection will track which memory bank is currently selected. message_position will track which character in the string I am currently accessing. message_in_bank is the memory location I will write to. Then I initialised two of the variables. The bank_selection variable is set to 1 as it appears there is some code already in 00 $a000. (I found overwriting the contents of 00a000 did strange things and I didn’t sort it out until I had worked out how to use the debugger down below). The message_position variable is set to 0 for the first character.

;-----------------------------------------------------------------------------
.segment "DATA"
; here is where you put raw data / binary / sprites / text blobs / etc
message: .asciiz "this is a string which we will put in to the different banks of $a000"

;-----------------------------------------------------------------------------
.segment "CODE"

; constants
VIA1 = $9F61

; give kernal functions names
CHROUT = $ffd2 ; CHROUT outputs a character (C64 Kernal API)
CHRIN = $FFCF ; CHRIN read from default input

; variable locations
bank_selection = $0070
message_position = $0071
message_in_bank = $A000

; variables set
lda #1
sta bank_selection
; I am starting at bank 1 because it appears there is something written in bank 0 at $a000-$a041

lda #0
sta message_position

You may have noticed in the above code there is no basic launcher code. Previous to this project I had been setting my memory start location to $0801 and including a ‘basic loader’ string. $0c,$08,$0a…. etc and then my actual assembly code starting at $0810. For this project, I had been doing a sys2061 to start it while I was working on it. One time I accidentally typed run, and it ran! That wasn’t supposed to happen! I had a look at my prg in a hex editor. Sure enough, I saw 9E, 20, 32,30,36….. It appears that ca65 and its linker create a little basic loader.

The below code is my main loop. I am checking to see which bank is currently selected and if less then 20 we will run the code. If bank 20 is currently selected will we branch out to a function which will end the program. I then set the bank selection. I put the message position counter into register x. Then I put a character from the message, register x (register x is the offset in the message string) in to register a. I do a quick check to make sure the character is not null. If it is null then we have reached the end of the string and we branch out to a function which will change banks and reset counters. Then we store the current character into message_in_bank variable with the same offset. Then we increment the message_position so next time it will read the next character. Then we loop back to the beginning and go again.

;-----------------------------------------------------------------------------
.proc main
    lda bank_selection
    cmp #20 ;lets only do x banks
    bcs wait_user ; if it equals x then quit
    
    ; set RAM bank
    lda bank_selection
    sta VIA1

    ; get location of next character from our screen message
    ldx message_position
    lda message,x
    cmp #0 ; CoMPare accumulator with value 0 which is null terminator
    beq update_counter 
    ; output it to bank
    sta message_in_bank,x
    ; increase out message position
    inc message_position

    ; loop back to start
    jmp main
.endproc

The below code is my two support functions. update_counter resets the message_position variable back to 0 so the main loop will start to read from the first character again. I also increase the bank selection so I can write to the next memory bank. Then I jump back to the main loop. wait_user just prints out a single character to the screen then waits for the user to press return/enter then it ends.

.proc update_counter
    ; lets go back to the first character in message
    lda #0
    sta message_position
    ; increase the next bank
    inc bank_selection
    jmp main ; lets jmp back to the mail loop with updated counters
.endproc

.proc wait_user
    ; send a * out to the screen so we know its finish
    lda #42
    jsr CHROUT
    jsr	CHRIN ; Read input until Enter/Return is pressed
    rts ; Return to caller
.endproc

Intro to x16emu debug

When writing up this code I realised I wasn’t going to get any feedback if it was successful. I needed a way to see what was happening in memory. I was getting strange problems. In the past, I’ve had debuggers, breakpoints and been able to step each line of my code etc. I didn’t know how I was going to do that with X16emu. I did find a post on the forum by codewar65 which reminded me to read the actual documentation. In the x16emu readme.md there was a section on the debugger! I changed my visual studio code run task to include the “-debug” and started it up. Pressing F12 to break into the debugger.

x16emu -debug , Pressing F12 to start the debugger

Now to learn how to use it better! I started to use F10 to try and step ‘over’ routines and F11 to step over each instruction being executed. Happy! Then I wanted to see what was in memory. codewar65 had mentioned that page up and page down would let you browse memory. So I paged down to A000 and noticed it had FF:A000.

x16emu -debug, Showing $A000 bank FF.

I suspected that FF:A000 meant I was looking at bank FF. This proved frustrating until I was re-reading readme.md for x16emu. I could type m %x were %x was the address. Originally my code started at bank 00. I tried it m 00a000. There was some code there already, not the blank 00 00 00 I expected. Then I stepped each instruction and I would get strange results. So I quickly decided to avoid 00a000 and changed my starting bank to 1. Compiled, ran and moved to 01a000 and there it was, the string had been written to memory.

x16emu -debug. Showing $A000 bank 1.

I then looked at a few different banks. 02:A000, 03:A000… 13:A000 my string was in all of them. 14:A000 my string wasn’t which made sense. I had stopped the main loop when the bank was decimal 20 which is hex 14.

With the free plan on WordPress, I can’t upload text files or zip files. So I’ve turned it into a pdf for people who want all of the code in a single document to copy and paste from.

I would encourage any feedback or comments to improve this guide.

Setting up the Mac for Commander X16 Assembler development

I have been playing around with C64 assembly for a few months and when I discovered the Commander X16 project I wanted to play. I couldn’t find the tools easily on the Mac so I used my virtual Windows 10 machine.

The Commander X16 project is creating a modern 8-bit hobby computer similar to the Commodore 64. The emulator, ROM, programming guides, etc are available from Github.

Recently I worked out a way to do development on the Mac. I needed several tools. The X16 emulator is available for the Mac. Check out the latest GitHub release. Then I used Visual Studio code from Microsoft.

Then I needed the missing part of the puzzle. A 65C02 assembly compiler that could run on the Mac. The CC65 project includes the assembly tool ca65. The source can be downloaded from GitHub which I did. On the Mac for Git, I use SourceTree. I then got Apple’s Developer Xcode 10.1, I did not get the latest version because my main desktop is only running Mac OS 10.13. Regardless it is big, over 6GB to download and almost 13GB installed. Once Xcode was installed I was able to go into the src directory in the cc65 folder and run the make script which surprised me by working perfectly. 

Mac OS 10 terminal window building the cc65 suite of tools.

I recommend using a GIT tool and keeping an eye on cc65 because it appears to be getting a lot of updates mostly for the X16. So you may need to update your local source and re-make when there are updates.

Now I had the basic building blocks. Now time to configure Visual Studio Code. On the left hand go to the 4 squares icon for extensions. Then in the search bar at the top enter cc65. It should find the ‘ca65 Macro Assembler Language Support’ extension. Click on install.

Visual Studio Code – Finding and Installing cc65 extention

Now I needed to configure tasks to point to the location of my ca65 and x16emu. Go to the Terminal menu and select Configure Default Build Task.

Visual Studio Code – Configure Default Build Task from Terminal Menu.

The next window you can select the default ‘Create tasks.json file from template’

Visual Studio Code – Create tasks.json file from template

Then select ‘MSBuild Executes the build target’

Visual Studio Code – Selecting the MSBuild template.

You should then have default .vscode folder and tasks.json file

Visual Studio Code – Default tasks.json.

I then edited the tasks.json to the below. If you adjust the locations of your ca65 and your x16emu it should work for you too.
Note: You may notice a difference between the image above and the code below. When I initially wrote this post I had just switched to the cc65 suite of tools and I thought using ca65 was the correct command-line tool to create a prg. It isn’t, that created object code which then needs to be linked using ld65. However, it is possible to use cl65 to compile and link.

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "x16-build-ca65",
            "type": "shell",
            "command": "/users/justin/GITHUB/cc65/bin/cl65 --verbose -o build.prg --cpu 65c02 -t cx16 ${file}",
            "args": [
                // 
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "presentation": {
                "clear": true
            },
            "problemMatcher": "$msCompile"
        },
        {
            "label": "x16-run-prg",
            "type": "shell",
            "command": "/users/justin/Documents/Commander-X16/x16emu_mac-r36/x16emu -prg ${workspaceFolder}/build.prg ",
            "args": [
                // 
            ],
            "group": {
                "kind": "test",
                "isDefault": true
            },
            "presentation": {
                "clear": true
            },
            "problemMatcher": "$msCompile"
        }
    ]
}

Once you’ve typed up some assembly select the file, go up to the ‘Terminal’ menu and select ‘Run Build Task’

Visual Studio Code – Running build task against assembler file

Down in the lower part of the Visual Studio Code window you should see the build messages.

Visual Studio Code – Successfully building a X16 prg

Now you should have a build.prg file listed in your project. You can select this, go to the ‘Terminal’ menu and select ‘Run Task…’ You should then see a list of possible tasks to run. Hopefully, you noticed in the above JSON tasks listing above that I called the 2 tasks “x16-build-ca65” and “x16-run-prg”. If you select x16-run-prg it should run the build.prg you’ve just created. The x16 emulator should launch with your prg loaded.

Note: I did have a problem with running x16emu tasks were the path had a space character. Originally when running x16emu I had a path of “/users/justin/Documents/Commander X16/x16emu_mac-r36/x16emu” and it was reporting an error, file not found at “/users/justin/Documents/Commander” so I changed the directory to include the – character instead and it works.

Visual Studio Code – Successfully launching the X16emu with the created build.prg

I would encourage any feedback or comments to improve this guide.