Category Archives: RetroComputing

Commodore SD2IEC

When using a SD2IEC and a 1541 floppy drive together it is possible to have a device id conflict. The SD2IEC defaults to device#8. The 1541 floppy drive defaults to device#8 as well.

To change the device id on the SD2IEC, power on the C64 but not the 1541. Then open a connection to the SD2IEC

OPEN 15,8,15

Then send a command to change the device controller ID.

PRINT#15,”U0>”+CHR$(9)

The SD2IEC should now be using ID 9. To test, load the directory.

LOAD”$”,9

Now power on the 1541 floppy drive. It should startup and work as device#8 as normal.

LOAD”$”,8

Commodore 1541 Floppy drive commands

Getting back in to playing with my old Commodore 64 and 1541 floppy drive. I had to relearn how to use the floppy drive. Just a simple task such as formatting a floppy disk took me a little while to find the commands. So to make it easier for myself I thought I would list a bunch of the commands that I would be using now in the future.

Format a disk (NEW)
OPEN 1,8,15,"N0:Diskname,ID": CLOSE 1
or
OPEN 1,8,15: PRINT#1,"N0:Diskname,ID": CLOSE 1
The disk name has a maximum of 16 chars and the ID requires 2 chars.

Initialize drive (INITIALIZE)
e.g. to detect a disk change
OPEN 1,8,15,"I0":CLOSE 1

Validate a disk (VALIDATE)
Checks and fixes the disk’s meta-data structures (directory, block availability map, etc.)
OPEN 1,8,15,"V0": CLOSE 1

Copy files (COPY)
OPEN 1,8,15,"C0:NewFile=OldFile": CLOSE 1

Copy disk (COPY)
OPEN 1,8,15,"C0=C1": CLOSE 1
Copy the whole disk on a double drive from drive 1 to drive 0.

Concatenate files (COMBINE)
OPEN 1,8,15,"C0:NewFile=OldFile1,OldFile2,...": CLOSE 1
The command string is limited to 40 chars in length!

Rename a file (RENAME)
OPEN 1,8,15,"R0:New_Name=Old_Name":CLOSE 1
The command string is limited to 40 chars in length!

Delete a file (SCRATCH)
OPEN 1,8,15,"S0:filename": CLOSE 1
Wildcards such as * (matches all the remaining chars) or ? (matches one char) are supported.For example: OPEN 1,8,15,"S0:*":CLOSE 1 all files of a disk will be deleted (“scratched”).With comma (,) more than one file or wildcard mask can be given and multiple matching files actually could be subject of the deletion.

Overwrite a file (REPLACE)
SAVE"@0:filename",8
or
OPEN 1,8,15,"@0:filename,S,W": CLOSE 1.
The REPLACE command is especially prone to triggering the above mentioned bug on the original 1541 (fixed in the 1541C and the 1541-II) – it may fail with some regularity and one could lose all data on a disk. Unless the user knows for certain that the drive in question will not be an original 1541, the better way is to first to use SCRATCH and after that the BASIC command SAVE.

Commander X16 BASIC Tiles

I continue to learn more about the Commander X16 retro platform and programming in BASIC. I want to make games for the platform, so I needed to come to grips with how VERA handles tiles.

Currently, I’m using VMWare Fusion on my Mac with a Windows 10 VM for doing my retro development. I’m using X16 emulator R38 ,NotePad++ ,Tiled ,HxD ,TexturePacker ,MOSpeed and Vera Graphics Converter.

I started with a few false starts, and then I found a tile tutorial on 8-bit coding, which started me off. However, I needed something more. I was struggling with several different things, workflow and debugging how to get the tile graphics into the system and look ok, how to edit tilemaps and get that data into the X16. What is happening in VERA memory? Argg, their program works why doesn’t mine. So, now I have worked some things out I decided I should share what I learnt. 

I started by finding a nice 256 colour tileset, and I created what I thought was a basic 64 x 64 tilemap in Tiled. I then spent time learning how to export data out of Tiled as BASIC DATA statements. At this point I realised maybe I had made a mistake, just the data statements for the graphics and map were almost 30k. Also, I wasn’t having much luck with displaying anything. I was getting graphic snow/static. I just couldn’t see into VERA to work out what was happening. I spent time looking at the emulator debugger documentation, and I just couldn’t see what I needed. I had a look at the debugger.c code out of curiosity and found CMD_DUMP_VERA='v'
This was it! This lets me view VERA memory. Start the X16 emulator with the -debug switch.
C:\x16emu_win-r38>x16emu.exe -bas TUTORIAL-TILES.BAS -debug
Then activate the debugger by pressing F12. Once in the debugger press v and type the memory address in VERA to view. Awesome. 

X16 Emulator started with -debug and viewing VERA memory at $4000.

I still wasn’t having much luck. I stumbled upon a forum post which reminded me about the VLOAD command. I hadn’t looked at it before since at the time the documentation just listed TODO. A good reminder that the X16 team were working faster on the code then the documentation. I had some problems using VLOAD with data that crossed from Bank 0 to Bank 1. So I just made sure my data fit in either Bank 0 or Bank 1. 

For this tutorial, I am trying something more significant than my initial successful program. In Tiled I created a 256 x 32 tiled map of 16×16 tiles. Giving a scroll area of 4096 x 512, suitable for a side scroller like Mario. With the X16 in 320×240 mode, this would provide close to 26 screens worth of map for a level. I created an elementary map. I then used Johan Kårlin tool for tiled, which let me export the map data. The map data takes up just over 16k. I used a subset of a graphic tileset from Open Game Art. I used what I thought was a small sample, which ended up being 416 tiles. I then used VERA Graphics Converter to turn the png file into 16×16 tiles at 4 bit per pixel and exported the binary data file, which was 53kb! Clearly, when I do create a game, I will have to make sure I only included used tiles.

Tiled – Clearly, I need to develop my level creation skills.

Looking at VERA and its registers and memory, we can see that VERA can handle two layers. By default, it uses layer 1 for text. I was thinking of using layer 1 for a HUD/score/user information etc. So we will enable layer 0 and put the tiles there. But how to handle that? VERA has 128kb of memory, and my tile graphics were going to take 52kb, and the map was going to take 16kb. 

AddressNameBit 7 – BIT 6 – bit 5 – Bit 4 – Bit 3 – Bit 2 – Bit 1 – Bit 0
$9F29DC_VIDEO (DCSEL=0)Current Field (Bit 7) Sprites Enable (Bit 6) Layer1 Enable (Bit 5) Layer0 Enable (Bit 4) Unused (Bit 3) Chroma Disable (Bit 2) Output Mode (Bit 1-0)
$9F2DL0_CONFIGMap Height (Bit 7-6) Map Width (Bit 5-4) T256C (Bit 3) Bitmap Mode (Bit 2) Color Depth (Bit 1-0)
$9F2EL0_MAPBASEMap Base Address Bits 16-9 (Bit 7-0)
$9F2FL0_TILEBASETile Base Address Bit 16-11 (Bit 7-2) Tile Height (Bit 1) Tile Width (Bit 0)
$9F30L0_HSCROLL_LH-Scroll Bits 7-0 (Bit 7-0)
$9F31L0_HSCROLL_HUnused (Bit 7-4) H-Scroll Bits 11-8 (Bit 3-0)
$9F32L0_VSCROLL_LV-Scroll Bits 7-0 (Bit 7-0)
$9F33L0_VSCROLL_HUnused (Bit 7-4) V-Scroll Bits 11-8 (Bit 3-0)
$9F34L1_CONFIGMap Height (Bit 7-6) Map Width (Bit 5-4) T256C (Bit 3) Bitmap Mode (Bit 2) Color Depth (Bit 1-0)
$9F35L1_MAPBASEMap Base Address Bits 16-9 (Bit 7-0)
$9F36L1_TILEBASETile Base Address Bit 16-11 (Bit 7-2) Tile Height (Bit 1) Tile Width (Bit 0)
$9F37L1_HSCROLL_LH-Scroll Bits 7-0 (Bit 7-0)
$9F38L1_HSCROLL_HUnused (Bit 7-4) H-Scroll Bits 11-8 (Bit 3-0)
$9F39L1_VSCROLL_LV-Scroll Bits 7-0 (Bit 7-0)
$9F3AL1_VSCROLL_HUnused (Bit 7-4) V-Scroll Bits 11-8 (Bit 3-0)
Subset of VERA Registers for Layer 0 and 1

I will start the structure of this program with a simple main program and a number of subroutines which perform tasks. The first task is setting up the SCREEN in 320×240 mode.

Now we will need to enable layer 0. Doing so is relatively straight forward. We simply poke the right bit of memory. Looking at the table above we can see to enable layer 0 we just need to set bit 4 of $9F29 to be 1. I like to use binary when POKEing value so I set exactly the right bits. I want both layer 0 and 1 and enabled and the default output mode. For this, I will POKE $9F29, %00110001.

Now we have to do several pokes to configure Layer 0 in VERA. $9F2D is fairly straight forward. We will ignore T256C and Bitmap mode. We only have two bits for height and two bits for width. A binary value needs to be set.

decimalBinaryHeight / Width
00032 tiles
10164 tiles
210128 tiles
311256 tiles
VERA Layer Height and Width options

The last two bits in $9F2D are color depth. This value changes how VERA expects the colour data to be encoded. 8-Bit Coding has a tutorial which goes into more depth.

Color Depth valueDescription
01 bpp
12 bpp
24 bpp
38 bpp
VERA Layer Color Depth options

The next register took a little bit for me to understand. $9F2E. Initial I had thought it just took a 16-bit address for VERA memory and remove the eight least significate bits. But that didn’t work. It wasn’t until I started to think a bit more. 16-bit address only allows 64k. VERA has 128k of memory. To cover all 128k of memory the binary range is 0 0000 0000 0000 0000 – 1 1111 1111 1111 1111. The 17-bit is selecting which 64k bank is being used, bank 0 or bank 1. So this register actually needs the high 8-bits from a 17bit address. I found the Windows Calculator very handy for this. The example here is setting the tilemap base at $4000 in VERA. $4000 in binary is 0100 0000 0000 0000. If I poke 0100 0000 into the VERA register, it will not work correctly. If I change it so it is a 17bit address 0 0100 0000 0000 0000 and then I take the high 8-bits, I poke in 0010 0000 VERA should work correctly.

Windows Calculator in Programmer mode.

Once I understood the addressing issue, I found working with $9F2F easier. Instead of having the high 8-bits of the tile graphic location, it takes the high 6-bits. The last two bits set the height and width of the tiles. The height and width can be 8 or 16 pixels. Giving us a total of four different tile sizes; 8×8, 8×16, 16×8, 16×16. The example here is setting the tile graphics base at $10000 in VERA with 16×16 tiles. The 17-bit address is 1 0000 0000 0000 0000. I take the high 6-bits from the address. The tiles will be 16 x 16, so the height and width bits will be both be 1. So I poke in the binary value 1000 00 11.

Binary valueTile height / width
08 pixels
116 pixels
VERA Tile dimensions

If we started the program with what we have done at the moment, we would not see anything. Only the default blue background, the white text of layer 1 will be visible. VERA handles color 0 as transparent. Color 0 is normally black. We will use the COLOR command to set the foreground color to white (1) and background color to black (0). Then we will clear the screen using CLS and PRINT some instructions. That will be the end of the first subroutine, so we can then RETURN to the main program.

So far the code looks like this;
100 GOSUB 10000: REM SETUP DISPLAY
110 END
10000 REM SETUP DISPLAY
10010 SCREEN $00: REM SETUP SCREEN MODE 320X240
10020 REM CONFIGURE LAYER 0 AND DISPLAY TILES
10030 POKE $9F29, %00110001: REM TURN ON LAYER 0,1 AND VGA OUTPUT
10040 POKE $9F2D, %00110010: REM MAP 32 X 256, T256C, BITMAP MODE, COLOR DEPTH
10050 POKE $9F2E, %00100000: REM MAP BASE AT $4000
10060 POKE $9F2F, %10000011: REM SET TILE BASE AT $10000 AND H=16 W=16
10070 REM CONFIGURE LAYER 1 AND DISPLAY INSTRUCTIONS
10080 COLOR 1,0
10090 CLS
10100 PRINT "MOVE VIEW USING WASD. Q TO QUIT"
10110 RETURN

Now I need to load the tilemap data and tile graphic data straight into VERAs memory. We will use the VLOAD command. Now currently there isn’t any documentation for this, and I think there might be a bug in it as well. The data loaded should either fit entirely in bank 0 or bank 1 of VERA. If I try and load a large block of data starting in bank 0 and expecting it to continue into bank 1, I have a problem. I will investigate further, but I think VLOAD works with this syntax;
VLOAD "filename",device,<VERA memory bank>, <VERA memory address>
For this example, I have two files. TILEMAP-256X32.BIN and TILE-GFX.BIN. I then use sub-routines to load each of the files into VERA. The tilemap base is at $4000 in bank 0, so the command should look like VLOAD "TILEMAP-256X32.BIN",0,$4000. The tile graphic data is at $10000, so address $0000 in bank 1. The command will look like VLOAD "TILE-GFX.BIN",1,$0000

So far the code looks like this;
100 GOSUB 10000: REM SETUP DISPLAY
110 GOSUB 20000: REM SETUP TILE MAP
120 GOSUB 30000: REM SETUP TILE GRAPHICS
130 END

10000 REM SETUP DISPLAY
10010 SCREEN $00: REM SETUP SCREEN MODE 320X240
10020 REM CONFIGURE LAYER 0 AND DISPLAY TILES
10030 POKE $9F29, %00110001: REM TURN ON LAYER 0,1 AND VGA OUTPUT
10040 POKE $9F2D, %00110010: REM MAP 32 X 256, T256C, BITMAP MODE, COLOR DEPTH
10050 POKE $9F2E, %00100000: REM MAP BASE AT $4000
10060 POKE $9F2F, %10000011: REM SET TILE BASE AT $10000 AND H=16 W=16
10070 REM CONFIGURE LAYER 1 AND DISPLAY INSTRUCTIONS
10080 COLOR 1,0
10090 CLS
10100 PRINT "MOVE VIEW USING WASD. Q TO QUIT"
10110 RETURN

20000 REM SETUP TILE MAP
20010 VLOAD "TILEMAP-256X32.BIN",8,0,$4000
20020 RETURN

30000 REM SETUP TILE GRAPHICS
30020 VLOAD "TILE-GFX.BIN",8,1,$0000
30030 RETURN

To see how it is going I copied the two data files and the BASIC file into the X16 emulator directory and ran;
C:\x16emu_win-r38>x16emu.exe -bas TUTORIAL-TILES.BAS -debug
To see how it appeared…. and success!

Success – Tilemap and graphic data loaded and displayed.

Now I want the program to take keyboard input and move the view around so we can explore the entire map. The maximum layer area that VERA can handle is 4096 pixels, starting at 0 and going to 4095. However, we can only poke up to a value of 255! 0 to 4095 is a 12-bit address, 0000 0000 0000 to 1111 1111 1111. When we look at the VERA registers, we see that the horizontal scroll is $9F30 for the low 8-bits and $9F31 for the high 4-bits. Unlike assembly, you just can’t grab the high, or low 8-bits using < or > and manipulate data as easily. (I would like to be wrong here so if you know otherwise please leave a comment). So we need to create a few variables to handle data. I’m going to make two variables to keep track of the tile horizontal and vertical location, TH and TV. Then to convert those numbers into values, these we can poke into VERA. I will create HL and HH for the horizontal low and high values. As well as a VL and VH variable for vertical low and high values. I will also create a variable to store the movement speed, MV.

I will create another subroutine to handle moving the screen view around the layer. Then I will GET the keyboard input and store it in variable K$. Inside the loop, it will check which key was pressed and call a subroutine to move the view either left/right/up/down. Then it will loop back to GET the keyboard input again.

So far the code looks like this;
100 GOSUB 10000: REM SETUP DISPLAY
110 GOSUB 20000: REM SETUP TILE MAP
120 GOSUB 30000: REM SETUP TILE GRAPHICS
130 GOSUB 1000: REM THE MAIN LOOP
140 END

1000 REM MAIN LOOP
1010 LET TH=0: TV=0: REM TILE HORIZONTAL AND VERTICAL LOCATION 0-4095
1020 LET HH=0: HL=0: VH=0: VL=0: REM HIGH AND LOW VALUES FOR HOR AND VER
1030 LET MV=2: REM SET DEFAULT MOVEMENT SPEED
1040 GET K$: REM READ IN KEYPRESSES
1050 IF K$="A" THEN GOSUB 1100: REM MOVE LEFT
1060 IF K$="D" THEN GOSUB 1200: REM MOVE RIGHT
1070 IF K$="W" THEN GOSUB 1300: REM MOVE UP
1080 IF K$="S" THEN GOSUB 1400: REM MOVE DOWN
1090 IF K$="Q" THEN RETURN: REM EXIT SUBROUTINE
1095 GOTO 1040: REM LOOP BACK TO GET KEYBOARD INPUT

We create a subroutine for each of the movements. The program will also check bounds. When moving left, we should not have a value of less than 0. When moving to the right, we have to adjust a little. The screen view is 320 pixels wide. We don’t want to move the screen view all the way to 4095; otherwise, the layer will wrap around, and we will be looking at layer pixels 0-319. So we limit the movement to 3776, which is layer width (4096) – screen view width (320). When moving up, we should not have a value of less than 0. When moving down, we have to adjust a little again. The screen view is 240 pixels high. We have a layer vertical size of 512, so we will limit movement to 272, which is layer height (512) – screen view height (240). We then call the subroutine for calculating the values which will be POKEd into VERA. Then call the subroutine for updating VERA.

1100 REM MOVE VIEW LEFT
1110 IF TH = 0 THEN RETURN
1120 TH=TH-MV
1130 GOSUB 1700: REM CALCULATE 8BIT
1140 GOSUB 1900: REM UPDATE SCROLL
1150 RETURN

1200 REM MOVE VIEW RIGHT
1210 IF TH = 3776 THEN RETURN: REM LAYER WIDTH - SCREEN VIEW WIDTH
1220 TH=TH+MV
1230 GOSUB 1700: REM CALCULATE 8BIT
1240 GOSUB 1900: REM UPDATE SCROLL
1250 RETURN

1300 REM MOVE UP
1310 IF TV = 0 THEN RETURN
1320 TV=TV-MV
1330 GOSUB 1800: REM CALCULATE 8BIT
1340 GOSUB 1900: REM UPDATE SCROLL
1350 RETURN

1400 REM MOVE DOWN
1410 IF TV = 272 THEN RETURN: REM 512-240
1420 TV=TV+MV
1430 GOSUB 1800: REM CALCULATE 8BIT
1440 GOSUB 1900: REM UPDATE SCROLL
1450 RETURN

Now we need to calculate the 8-bit values which will get POKEd into VERA. The X16 handles numbers in 8-bit chunks, 0-255. VERA allows scroll values from 0 to 4095, 0000 0000 0000 – 1111 1111 1111. VERA has $9F30 for the low 8 bits and $9F31 for the hight 4-bits. We think of this process as some basic division maths. The 4-bit high value is the horizontal location divided by 255, and the 8-bit low value is the remainder of that division. We have to so a few steps. I use the HH variable to store the horizontal high value, which is the INTeger result of TH (Tile Horizontal location) divided by 255. By using the INT function, we only get the quotient and no remainder (float value, decimal numbers) The HL variable stores the result of the TH – number of times 255 went into it, giving me an integer less than 255. We do the process again for the vertical. Once each of these sub-routines has completed return to the code which called them.

1700 REM CALCULATE HORITZONAL HIGH AND LOW VALUES TO POKE IN TO LAYER SCROLL
1710 HH = INT(TH / 255)
1720 HL = TH - (HH * 255)
1730 RETURN

1800 REM CALCULATE VERTICAL HIGH AND LOW VALUES TO POKE IN TO LAYER SCROLL
1810 VH = INT(TV / 255)
1820 VL = TV - (VH * 255)
1830 RETURN

Finally the subroutine for updating VERA. We just POKE the horizontal and vertical values into the VERA scroll registers for layer 0.

1900 REM UPDATE VERA FOR NEW LAYER SCROLL
1910 POKE $9F30,HL
1920 POKE $9F31,HH
1930 POKE $9F32,VL
1940 POKE $9F33,VH
1950 RETURN

With my BASIC code, I’ve tried to use as many comments as possible. I’m also using empty lines to help break up my code. I’m sure my code is not efficient or as fast as it could be. All the code, Tiled map file, binary and graphics are available from the Github repo.

So now the completed code looks like this;
100 GOSUB 10000: REM SETUP DISPLAY
110 GOSUB 20000: REM SETUP TILE MAP
120 GOSUB 30000: REM SETUP TILE GRAPHICS
130 GOSUB 1000: REM THE MAIN LOOP
140 END

1000 REM MAIN LOOP
1010 LET TH=0: TV=0: REM TILE HORIZONTAL AND VERTICAL LOCATION 0-4095
1020 LET HH=0: HL=0: VH=0: VL=0: REM HIGH AND LOW VALUES FOR HOR AND VER
1030 LET MV=2: REM SET DEFAULT MOVEMENT SPEED
1040 GET K$: REM READ IN KEYPRESSES
1050 IF K$="A" THEN GOSUB 1100: REM MOVE LEFT
1060 IF K$="D" THEN GOSUB 1200: REM MOVE RIGHT
1070 IF K$="W" THEN GOSUB 1300: REM MOVE UP
1080 IF K$="S" THEN GOSUB 1400: REM MOVE DOWN
1090 IF K$="Q" THEN RETURN: REM EXIT SUBROUTINE
1095 GOTO 1040: REM LOOP BACK TO GET KEYBOARD INPUT

1100 REM MOVE VIEW LEFT
1110 IF TH = 0 THEN RETURN
1120 TH=TH-MV
1130 GOSUB 1700: REM CALCULATE 8BIT
1140 GOSUB 1900: REM UPDATE SCROLL
1150 RETURN

1200 REM MOVE VIEW RIGHT
1210 IF TH = 3776 THEN RETURN: REM LAYER WIDTH - SCREEN VIEW WIDTH
1220 TH=TH+MV
1230 GOSUB 1700: REM CALCULATE 8BIT
1240 GOSUB 1900: REM UPDATE SCROLL
1250 RETURN

1300 REM MOVE UP
1310 IF TV = 0 THEN RETURN
1320 TV=TV-MV
1330 GOSUB 1800: REM CALCULATE 8BIT
1340 GOSUB 1900: REM UPDATE SCROLL
1350 RETURN

1400 REM MOVE DOWN
1410 IF TV = 272 THEN RETURN: REM 512-240
1420 TV=TV+MV
1430 GOSUB 1800: REM CALCULATE 8BIT
1440 GOSUB 1900: REM UPDATE SCROLL
1450 RETURN

1700 REM CALCULATE HORITZONAL HIGH AND LOW VALUES TO POKE IN TO LAYER SCROLL
1710 HH = INT(TH / 255)
1720 HL = TH - (HH * 255)
1730 RETURN

1800 REM CALCULATE VERTICAL HIGH AND LOW VALUES TO POKE IN TO LAYER SCROLL
1810 VH = INT(TV / 255)
1820 VL = TV - (VH * 255)
1830 RETURN

1900 REM UPDATE VERA FOR NEW LAYER SCROLL
1910 POKE $9F30,HL
1920 POKE $9F31,HH
1930 POKE $9F32,VL
1940 POKE $9F33,VH
1950 RETURN

10000 REM SETUP DISPLAY
10010 SCREEN $00: REM SETUP SCREEN MODE 320X240
10020 REM CONFIGURE LAYER 0 AND DISPLAY TILES
10030 POKE $9F29, %00110001: REM TURN ON LAYER 0,1 AND VGA OUTPUT
10040 POKE $9F2D, %00110010: REM MAP 32 X 256, T256C, BITMAP MODE, COLOR DEPTH
10050 POKE $9F2E, %00100000: REM MAP BASE AT $4000
10060 POKE $9F2F, %10000011: REM SET TILE BASE AT $10000 AND H=16 W=16
10070 REM CONFIGURE LAYER 1 AND DISPLAY INSTRUCTIONS
10080 COLOR 1,0
10090 CLS
10100 PRINT "MOVE VIEW USING WASD. Q TO QUIT"
10110 RETURN

20000 REM SETUP TILE MAP
20010 VLOAD "TILEMAP-256X32.BIN",8,0,$4000
20020 RETURN

30000 REM SETUP TILE GRAPHICS
30020 VLOAD "TILE-GFX.BIN",8,1,$0000
30030 RETURN

Combined with the data files, we get a nice little demo of X16 tiles and BASIC.

X16 – Tile demo in BASIC

Commander X16 BASIC from old Compute book code.

As a bit of challenge for myself, I am re-reading a few old Compute programming books for the Commodore 64 and converting them to run on the Commander X16. The book I’m currently working on is “Compute’s First Book of 64 Games” from 1983. Which is available on archive.org

Investment Simulation

5 PRINT"{CLR}"
10 CASH=100000:PGLD=499
15 POKE 53272,23:REM SHIFT TO LOWER CASE
20 PB=80
31 PRINT: PRINT"BUNDTFUND IS $"PB" PER SHARE.YOU HAVE "B"{4 SPACES}SHARES. -- $"PB*B
33 PRINT" GOLD IS{4 SPACES}$"GLS" OUNCES. -- $"GLD*PGLD
34 T=PB*B+GLD*PGLD
35 PRINT:PRINT" TOTAL INVESTMENTS -- $"T
36 PRINT:PRINT" YOU HAVE $"CASH" TO SPEND."
40 PRINT:PRINT" GRAND TOTAL":PRINT"(INVESTMENTS + CASH){4 SPACES}$"T+CASH
45 IFCK=1THEN500
50 PRINT:PRINT"1.BUY{2 SPACES}2.SELL{2 SPACES}3.DONE"
60 INPUTA:IFA=3THENCK=1:GOTO31
100 PRINT"WHICH?{3 SPACES}1.GOLD{4 SPACES}OR{4 SPACES}2.STOCK"
110 INPUTF
120 PRINT"HOW MANY (SHARES{3 SPACES} OR {3 SPACES} OUNCES)?"
130 INPUTN
140 IFF=1THEN160
150 PRINCE=PB*N:IFA=1THENCASH=CASH-PRICE:B=B+N:GOTO400
155 CASH=CASH+PRICE:GLD=GLD-N
160 PRICE=PGLD*N:IFA=1THENCASH=CASH-PRICE:GLD=GLD+N:GOTO400
170 CASH=CASH+PRICE:GLD=GLD-N
400 GOTO50
500 PRINT"PRESS ANY KEY TO CONT";
503 GET C$:IF C$=""THEN503
505 CK=0:PRINT:PRINT"{CLR}ONE MONTH LATER ...":FOR T=1TO700:NEXTT:PRINT
510 X=INT((RND(1)*100/10):Y=INT((RND(1)*200/10):Z=RND(1)
520 CH=CH+1:IFCH>4ANDCH<XTHENCH=0:GOTO600
525 IFCH=2GOTO600
530 IF Z>.5 THENPB=PB+X:PGLD=PGLD-Y:GOTO31
540 PB=PB-X:PGLD=PGLD+Y:GOTO31
600 PRINT"INTERNATIONAL UNREST...":PGLD=PGLD+2*Y:PB=PB-2*X:GOTO31
700 PRINT"MARKET RALLY ...{2 SPACES}":PGLD=PGLD-2*Y:PB=PB+3*X:GOTO31

While typing it all out I noticed bugs. Originally I thought I must be mistaken, but no. BuWhile typing it all out, I noticed bugs. Initially, I thought I must be mistaken, but no. Bugs like on line 33 with a variable called “GLS” instead of “GLD”. Then on line 150 with variables called “PRINCE” instead of “PRICE”. It also struck me that the formatting of the code could be more helpful. Finally, the number of GOTO creating a little pile of spaghetti code, which is one of the problems with BASIC.

So when I re-worked the code, I tried to create blocks of subroutines. Tried to remove all of the GOTOs. I also created little checks to make sure the player has enough money/gold/stock to do the function they want. I don’t think my code is more efficient than the original. I do, however, think it is easier to read and follows a more modern design. My code is available on Github.

1 REM COMPUTES FIRST BOOK OF 64 GAMES 
2 REM INVESTMENT SIMULATION
3 REM ORIGINAL BY RICHARD MANSFIELD
4 REM UPDATED BY JUSTIN BALDOCK
6 REM CASH = PLAYERS CASH : 
7 REM PB = PRICE OF 8BIT FUND : REM PGLD = PRICE OF GOLD
8 REM B = NUMBER OF 8BIT SHARES PLAYER HAS : REM GLD = NUMBER OF GOLD OUNCES PLAYER HAS
9 REM T = TOTAL VALUE OF PLAYER : REM CP = CAN PURCHASE
10 CASH=100000:PGLD=400
20 PB=80
29 PRINT CHR$(147) : REM CLEAR SCREEN
30 PRINT : REM SPACING
31 PRINT " 8-BIT FUND IS $"PB" PER SHARE. YOU HAVE "B" SHARES. -- $"PB*B
33 PRINT " GOLD IS $"PGLD" PER OUNCE. YOU HAVE "GLD" OUNCES. -- $"GLD*PGLD
34 T=(PB*B)+(GLD*PGLD)
35 PRINT:PRINT" TOTAL INVESTMENTS -- $"T
36 PRINT:PRINT" YOU HAVE $"CASH" TO SPEND."
40 PRINT:PRINT" GRAND TOTAL":PRINT"(INVESTMENTS + CASH)    $"T+CASH
50 PRINT:PRINT"1.BUY   2.SELL  3.DONE  4.QUIT"
60 INPUT A:IF A=3 THEN GOTO 4000 : REM GOTO THE MARKET SIMULATOR
70 IF A=4 THEN END
100 PRINT "WHICH?   1.GOLD    OR    2.STOCK"
110 INPUT F
120 PRINT "HOW MANY (SHARES   OR   OUNCES)?"
130 INPUT N
140 IF A=1 THEN IF F=1 THEN GOSUB 5600
145 IF A=1 THEN IF F=2 THEN GOSUB 5400
150 IF A=2 THEN IF F=1 THEN GOSUB 5200
155 IF A=2 THEN IF F=2 THEN GOSUB 5000
160 PRINT" PRESS ANY KEY TO CONTINUE."
170 GET C$: IF C$="" THEN GOTO 170 : REM WAIT FOR THE USER TO PRESS ANY KEY
180 GOTO 29 : REM RESTART THE MAIN LOOP
4000 REM
4001 REM THE MARKET SIMULATION
4010 PRINT:PRINT" ONE MONTH LATER...  "
4020 PRINT"                    ..."
4030 X=INT((RND(1)*100)/10):Y=INT((RND(1)*200)/10):Z=RND(1)
4040 CH=CH+1:IF CH>4 AND CH<X THEN CH=0: GOSUB 4400
4050 IF CH=2 THEN GOSUB 4500
4060 IF Z> .5 THEN GOSUB 4700
4070 IF Z<=.5 THEN GOSUB 4600
4080 PRINT:PRINT " THE MARKET MOVES..."
4090 PRINT:PRINT "                    ... PRESS ANY KEY TO CONTINUE."
4100 GET C$: IF C$="" GOTO 4100
4110 GOTO 29 : REM RETURN TO OUR MAIN LOOP
4120 END : REM THIS CODE SHOULD NEVER RUN
4400 REM
4401 REM METHOD INTERNATIONAL UNREST
4410 PRINT:PRINT" INTERNATIONAL UNREST...  "
4420 PGLD=PGLD+2*Y:PB=PB-2*X
4430 RETURN
4500 REM
4501 REM METHOD MARKET RALLY
4510 PRINT:PRINT" MARKET RALLIES ...  "
4520 PGLD=PGLD-2*Y:PB=PB+3*X
4530 RETURN
4600 REM
4601 REM METHOD GOLD UP, STOCK DOWN
4610 PB=PB-X:PGLD=PGLD+Y
4620 RETURN
4700 REM
4701 REM METHOD GOLD DOWN, STOCK UP
4710 PB=PB+X:PGLD=PGLD-Y
4720 RETURN
5000 REM
5001 REM SELL SHARES, PASS (N)UMBER OF SHARES TO SELL
5010 GOSUB 6000
5020 IF CP = 0 THEN PRINT" NOT ENOUGH SHARES TO SELL.":RETURN
5030 PRICE = PB*N : REM CAL PRICE
5040 CASH = CASH+PRICE : REM UPDATE CASH
5050 B = B-N : REM UPDATE STOCK OWNED
5060 PRINT " STOCK SOLD."
5070 RETURN
5200 REM
5201 REM METHOD SELL GOLD, PASS (N)UMBER OF GOLD TO SELL
5210 GOSUB 6100
5220 IF CP = 0 THEN PRINT" NOT ENOUGH GOLD TO SELL.":RETURN
5230 PRICE = PGLD*N : REM CAL PRICE
5240 CASH = CASH+PRICE : REM UDPATE CASH
5250 GLD = GLD-N :  REM UPDATE GOLD OWNED
5260 PRINT " GOLD SOLD."
5270 RETURN
5400 REM
5401 REM METHOD BUY SHARES, PASS (N)UMBER OF SHARES TO BUY
5410 PRICE = PB*N : REM CAL PRICE
5420 GOSUB 5800 : REM CHECK TO SEE IF PLAYER HAS ENOUGH MONEY
5430 IF CP = 0 THEN PRINT" NOT ENOUGH CASH TO PURCHASE SHARES":RETURN
5440 CASH = CASH-PRICE : REM UPDATE CASH
5450 B = B+N : REM UPDATE STOCK OWNED
5460 PRINT " STOCK PURCHASED."
5470 RETURN
5600 REM
5601 REM METHOD BUY GOLD, PASS (N)UMBER OF GOLD TO BUY
5610 PRICE = PGLD*N : REM CAL PRICE
5620 GOSUB 5800 : REM CHECK TO SEE IF PLAYER HAS ENOUGH MONEY
5630 IF CP = 0 THEN PRINT" NOT ENOUGH CASH TO PURCHASE GOLD":RETURN
5640 CASH = CASH-PRICE : REM UPDATE CASH
5650 GLD = GLD+N : REM UPDATE GOLD OWNED
5660 PRINT " GOLD PURCHASED."
5670 RETURN
5800 REM
5801 REM METHOD CHECK IF PLAYER HAS ENOUGH CASH
5810 IF CASH>=PRICE THEN CP=1
5820 IF CASH<PRICE THEN CP=0
5830 RETURN
6000 REM
6001 REM METHOD CHECK IF PLAYER HAS ENOUGH STOCK, PASS (N)UMBER OF STOCK TO SELL
6010 IF B>=N THEN CP=1
6020 IF B<N THEN CP=0
6030 RETURN
6100 REM
6101 REM METHOD CHECK IF PLAYER HAS ENOUGH GOLD, PASS (N)UMBER OF GOLD TO SELL
6110 IF GLD>=N THEN CP=1
6120 IF GLD<N THEN CP=0
6130 RETURN

I’ve started to update the next BASIC game, Ping-Pong. I’ve included the original C64 code listing again. At a first glance the code appears fairly good.

100 SCR=1024:COL=55296:POKE 53281,0
110 WALL=160:REM WALL CHARACTER, SOLID SQUARE.TRY {SPACE}OTHER CHARACTERS.
120 LN=40
130 GOSUB 260:REM DRAW BORDER
140 LOC=SCR+LN*10+LN/2:CLOC=COL+LN*10/2:REM SCREEN AND COLOR LOCATION
150 VECTR=LN:REM ALSO TRY -1,+1,LN-1,LN+1,ETC
160 BLANK=32
170 FIGURE=81:REM "BALL"CHARACTER.
180 IF PEEK(LOC+VECTR)<>WALL THEN 200
190 VECTR=-VECTR:REM REVERSE DIRECTION
200 POKE LOC,BLANK:REM ERASE OLD BALL
210 LOC=LOC+VECTR:CLOC=CLOC+VECTR:REM CALCULATE NEW POSITION
220 POKELOC+54272,1:POKELOC,81:REM PLACE BALL
230 GOTO180
240 END
250 REM BORDER SUBROUTINE
260 PRINT CHR$(147) : REM CLEAR SCREEN
270 FOR I=0 TO LN-1:POKE SCR+I,WALL:POKE COL+I,2:NEXTI:REM TOP
280 FOR I=0 TO LN-1:POKE SCR+LN*24+I,WALL:POKECOL+LN*24+I,2:NEXT I:REM BOTTOM
290 FOR I=0 TO 24: POKESCR+I*LN,WALL:POKECOL+I*LN,2:NEXT I:REM LEFT
300 FOR I=0 TO 24:POKE SCR+LN-1+I*LN,WALL:POKECOL+LN-1+I*LN,2:NEXTI:REM RIGHT
310 RETURN

Commander X16 Adventures in BASIC

Going over some old Commodore 64 books and re-typing up the old programs and adjusting them for the X16.

Bouncing Ball
Its good to experiment. To change the speed that the ball moves at change the value 50 on line 50 and line 100 to another value. The lower the value tm the faster the ball will move.

10 rem bouncing ball
20 print "{clr/home}"
25 for x = 1 to 10 : print "{crsr/down}:next
30 for bl = 0 to 78
40 print " {shift q}{crsr/left}";
50 for tm = 1 to 50
60 next tm
70 next bl
75 rem move ball right to left
80 for bl = 78 to 0 step -1
90 print " {crsr/left}{crsr/left}{shift q}{crsr/left}";
100 for tm = 1 to 50
110 next tm
120 next bl
130 goto 20

Classic maze
The maze program which can be converted in to the classic one liner which gives the unique maze on the Commodore 64. It runs and look pretty much identical on the X16.

10 print "{clr/home}"
20 print chr$(205.5+rnd(1));
30 goto
10 print chr$(205.5+rnd(1));:goto10

Lets make the maze a little bit more colourful. We are creating a random number between 0 and 1. We then use chr$ to send a control sequence to change the colour either yellow or cyan and then print use chr$ to print either a / or \.

10 let rn = int(0.5+rnd(1))
20 print chr$(158+rn);chr$(205+rn);
30 goto 10

Commander X16 – VRAM Allocation Guide

The code used for 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.

Finally I managed to get sprites working on the X16. A guide will follow soon. One of the issues I had was figuring out where I could put my sprites in VERA’s VRAM.

I spent a good while reading the VERA Programmer’s Reference. The Internal address space table was a good place to start.

Address rangeDescription
$00000 – $1FFFF Video RAM
$F0000 – $F001F Display composer registers
$F1000 – $F11FF Palette
$F2000 – $F200F Layer 0 registers
$F3000 – $F300F Layer 1 registers
$F4000 – $F400F Sprite registers
$F5000 – $F53FF Sprite attributes
$F6000 – $F6xxx Audio
$F7000 – $F7001 SPI
$F8000 – $F8003 UART
VERA Internal Address Space

Video RAM is used by VERA to hold the image that is displayed. There are a number of different modes and they use different parts of Video RAM. By default the X16 uses 80×60 characters. 80×60 text character has 4800 characters so 4800 bytes. Each character will need 1 byte for colour data, so another 4800 bytes. A total of 9600 bytes. Converting 9600 decimal to hex is $2580. However I found that wasn’t the case.

X16 in 80×60 Mode with sprite data loaded to $2580

When using 40×30 character mode should only use 1200 for character data and 1200 for colour data. So 2400 bytes, so from $960.

X16 in 40×30 Mode with sprite data loaded to $960

So I tried using 320×200 256 colour mode. I put the sprite up at $10000 things looked interesting as well.

X16 in 320×200 256 colour with sprite data loaded to $10000. You can see the “mouse” pointer spread across the first row pixels.

I clearly didn’t understand how VERA was working. I found an interesting video CX 16 VERA VRAM Allocation Guide Mk2 by Oziphanto. However it didn’t help me with understanding what I was doing wrong. So I watched Hardware Sprites on the Commander X16 by ChibiAkumas. Which while interesting also didn’t explain to me which parts of VRAM I could use.

So decided to work it out with trial and error. I found for 40×30 mode that I can use from $1e00-$1ffff for sprite data. In 80×60 mode I can use from $3c00-$1ffff for sprite data. In 320×200 mode I could use from $0000 to $ffff. I could not use from $10000 to $1ffff.

After I posted the initial version of this document SlithyMatt on the forums pointed out to me how VERA actually does 80×60 and 40×30 modes. 80×60 is achieved by switching to 640×480 and using tile maps for each character. To get 80×60 VERA uses 128 x 64 tiles. 40×30 is done by switching to 320×240 and using 64×32 tiles.

With this new understanding, how much VRAM does 80×60 use? 128x64x2 gives us 16384 bytes, 16k, $4000. I’m sure now I had been over writing tile data with my sprite and if I had scrolled I would have seen it. When we view the X16 screen we are only seeing a portion of the total. The image below shows what is happening with the tile map and the viewable area.

128 x 64 tile map with the screen viewable area of 80×60 characters

How much VRAM does the 40×30 screen mode use? Well it turns out it uses the same amount. The image below shows what is happening with the tile map and the viewable area. The same tile map is being used. You can place your sprite data at $4000 and you should be ok.

128 x 64 tile map with the screen viewable area of 40×30 characters.

In the Programmers reference guide in the Video programming there is a note that the kernal loads the PETSCII character sets in to VRAM at $0f800. So there a small amount of space we should not overwrite if we want to use text.

In theory I should be able to use space after the display composer registers, f0020 to f0fff. I should also be able to use the space after each of the Layer registers. f2010 to f2fff and f3010 to f3fff. Each of those pockets should hold 3k each.

The end result is that for each game you will have to work out which space works for you based on which graphic mode are in and which features you need to allocate VRAM to.

As I was about to post this article I saw that Emmanuel had posted a link to this youtube video Explore Video Memory from the Commander X16 in ASMFun. This appeared to answer my questions. I had tried a much earlier version of ASMFun and I have to say the latest version with the VERA VRAM allocation is super useful on Windows 10.

If other people have ideas on how VRAM is being used or if I am wrong about something please comment so that I can fix up this guide.

Thanks to SlithyMatt from the forum.

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.

Diving back into electronics

As a teenager I had started to study electronics but I never finished my diploma because I got a job, started working and just never looked back.

I recently was looking in to the Amiga scene again. The last time I dipped my toes in was over 10 years ago. I found a thriving community of people modding / recreating / having a good time.

I decided I wanted to get back in to it.

I have access to the Lydia online learning catalogue so I decided to brush up on my electronics skills and start learning some new ones. CPLD/FPGAs have become cheap and are making custom boards for old Amigas easier then ever to make.

The last week has seen me study;

I am hopefull this will give me a good starting foundation to start making some contribution to this community.